diff options
| author | Yong He <yonghe@outlook.com> | 2025-05-15 12:51:29 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-05-15 12:51:29 -0700 |
| commit | 0d6312f3be66f4bff9eec9606228db3edc309e2c (patch) | |
| tree | a868e452e2d25a88f8a6cdee109a280edd11c0fb | |
| parent | d961f4438ef865028d289148d22e0fb5c0d8319a (diff) | |
Add checking for hlsl register semantic. (#7118)
* Add checking for hlsl register semantic.
* Fix.
* Fix test.
* Fix switch error.
* Fix tests.
| -rw-r--r-- | source/slang/slang-ast-type.cpp | 3 | ||||
| -rw-r--r-- | source/slang/slang-check-decl.cpp | 91 | ||||
| -rw-r--r-- | source/slang/slang-check-type.cpp | 12 | ||||
| -rw-r--r-- | source/slang/slang-diagnostic-defs.h | 7 | ||||
| -rw-r--r-- | source/slang/slang.cpp | 7 | ||||
| -rw-r--r-- | tests/bindings/binding-spv-storage-class.slang | 6 | ||||
| -rw-r--r-- | tests/compute/nonuniformres-as-function-parameter.slang | 2 | ||||
| -rw-r--r-- | tests/diagnostics/invalid-buffer.slang | 9 | ||||
| -rw-r--r-- | tests/diagnostics/register-bindings.slang | 3 | ||||
| -rw-r--r-- | tests/diagnostics/register-bindings.slang.expected | 9 | ||||
| -rw-r--r-- | tests/hlsl/invalid-semantic.slang | 56 |
11 files changed, 188 insertions, 17 deletions
diff --git a/source/slang/slang-ast-type.cpp b/source/slang/slang-ast-type.cpp index ff4cc0d10..18f3f90bc 100644 --- a/source/slang/slang-ast-type.cpp +++ b/source/slang/slang-ast-type.cpp @@ -396,8 +396,7 @@ Type* TypeType::_createCanonicalTypeOverride() void GenericDeclRefType::_toTextOverride(StringBuilder& out) { - // TODO: what is appropriate here? - out << toSlice("<DeclRef<GenericDecl>>"); + out << getDeclRef(); } Type* GenericDeclRefType::_createCanonicalTypeOverride() diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index e7ce8721a..f340bd6fd 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -95,6 +95,8 @@ struct SemanticsDeclAttributesVisitor : public SemanticsDeclVisitorBase, void checkVarDeclCommon(VarDeclBase* varDecl); + void checkHLSLRegisterSemantic(VarDeclBase* varDecl, HLSLRegisterSemantic* registerSematnic); + void visitVarDecl(VarDecl* varDecl) { checkVarDeclCommon(varDecl); } // Synthesize the constructor declaration for a struct during header visit, as we @@ -12606,6 +12608,10 @@ void SemanticsDeclAttributesVisitor::checkVarDeclCommon(VarDeclBase* varDecl) { hasPushConstAttr = true; } + else if (auto registerSemantic = as<HLSLRegisterSemantic>(modifier)) + { + checkHLSLRegisterSemantic(varDecl, registerSemantic); + } } if (hasSpecConstAttr && hasPushConstAttr) { @@ -12623,6 +12629,91 @@ void SemanticsDeclAttributesVisitor::checkVarDeclCommon(VarDeclBase* varDecl) } } +void SemanticsDeclAttributesVisitor::checkHLSLRegisterSemantic( + VarDeclBase* varDecl, + HLSLRegisterSemantic* registerSemantic) +{ + auto registerName = registerSemantic->registerName.getContent(); + if (registerName.getLength() < 1) + { + getSink()->diagnose( + registerSemantic->registerName.getLoc(), + Diagnostics::invalidHLSLRegisterName, + registerSemantic->registerName); + return; + } + + // Check to make sure the HLSL semantic register name is consistent with the resource type. + + auto varType = getType(m_astBuilder, DeclRef<VarDeclBase>(varDecl)); + varType = unwrapModifiedType(unwrapArrayType(varType)); + bool isValid = true; + if (auto resType = as<ResourceType>(varType)) + { + switch (registerName[0]) + { + case 't': + if (resType->getAccess() != SLANG_RESOURCE_ACCESS_READ) + isValid = false; + break; + case 'u': + if (resType->getAccess() == SLANG_RESOURCE_ACCESS_READ) + isValid = false; + break; + case 's': + if (!resType->isCombined()) + isValid = false; + break; + default: + isValid = false; + break; + } + } + else if ( + as<HLSLByteAddressBufferType>(varType) || as<HLSLStructuredBufferType>(varType) || + as<RaytracingAccelerationStructureType>(varType)) + { + if (registerName[0] != 't') + { + isValid = false; + } + } + else if ( + as<HLSLRWByteAddressBufferType>(varType) || + as<HLSLRasterizerOrderedByteAddressBufferType>(varType) || + as<HLSLRWStructuredBufferType>(varType) || as<HLSLConsumeStructuredBufferType>(varType) || + as<HLSLAppendStructuredBufferType>(varType) || + as<HLSLRasterizerOrderedStructuredBufferType>(varType)) + { + if (registerName[0] != 'u') + { + isValid = false; + } + } + else if (as<SamplerStateType>(varType)) + { + if (registerName[0] != 's') + { + isValid = false; + } + } + else if (as<ConstantBufferType>(varType)) + { + if (registerName[0] != 'b') + { + isValid = false; + } + } + if (!isValid) + { + getSink()->diagnose( + registerSemantic->registerName.getLoc(), + Diagnostics::invalidHLSLRegisterNameForType, + registerName, + varType); + } +} + void SemanticsDeclAttributesVisitor::checkForwardDerivativeOfAttribute( FunctionDeclBase* funcDecl, ForwardDerivativeOfAttribute* attr) diff --git a/source/slang/slang-check-type.cpp b/source/slang/slang-check-type.cpp index d32903175..b5f5240a5 100644 --- a/source/slang/slang-check-type.cpp +++ b/source/slang/slang-check-type.cpp @@ -331,17 +331,27 @@ bool SemanticsVisitor::CoerceToProperTypeImpl( if (outProperType) args.add(ExtractGenericArgVal(valParam->initExpr)); } - else if (auto constraintParam = as<GenericTypeConstraintDecl>(member)) + } + + for (Decl* member : genericDeclRef.getDecl()->members) + { + if (auto constraintParam = as<GenericTypeConstraintDecl>(member)) { auto genericParam = as<DeclRefType>(constraintParam->sub.type)->getDeclRef(); if (!genericParam) return false; auto genericTypeParamDecl = as<GenericTypeParamDecl>(genericParam.getDecl()); if (!genericTypeParamDecl) + { + diagSink->diagnose(typeExp.exp, Diagnostics::genericTypeNeedsArgs, typeExp); return false; + } auto defaultType = CheckProperType(genericTypeParamDecl->initType); if (!defaultType) + { + diagSink->diagnose(typeExp.exp, Diagnostics::genericTypeNeedsArgs, typeExp); return false; + } auto witness = tryGetSubtypeWitness(defaultType, CheckProperType(constraintParam->sup)); if (!witness) diff --git a/source/slang/slang-diagnostic-defs.h b/source/slang/slang-diagnostic-defs.h index 808d867b6..6bedcfe3e 100644 --- a/source/slang/slang-diagnostic-defs.h +++ b/source/slang/slang-diagnostic-defs.h @@ -1366,6 +1366,13 @@ DIAGNOSTIC( Error, variableCannotBePushAndSpecializationConstant, "'$0' cannot be a push constant and a specialization constant at the same time") + +DIAGNOSTIC(31221, Error, invalidHLSLRegisterName, "invalid HLSL register name '$0'.") +DIAGNOSTIC( + 31222, + Error, + invalidHLSLRegisterNameForType, + "invalid HLSL register name '$0' for type '$1'.") // Enums DIAGNOSTIC(32000, Error, invalidEnumTagType, "invalid tag type for 'enum': '$0'") diff --git a/source/slang/slang.cpp b/source/slang/slang.cpp index c7f6c920c..7fc519c03 100644 --- a/source/slang/slang.cpp +++ b/source/slang/slang.cpp @@ -2784,7 +2784,12 @@ Type* ComponentType::getTypeFromString(String const& typeStr, DiagnosticSink* si SLANG_AST_BUILDER_RAII(linkage->getASTBuilder()); Expr* typeExpr = linkage->parseTermString(typeStr, scope); - type = checkProperType(linkage, TypeExp(typeExpr), sink); + SharedSemanticsContext sharedSemanticsContext(linkage, nullptr, sink); + SemanticsVisitor visitor(&sharedSemanticsContext); + type = visitor.TranslateTypeNode(typeExpr); + auto typeOut = visitor.tryCoerceToProperType(TypeExp(type)); + if (typeOut.type) + type = typeOut.type; if (type) { diff --git a/tests/bindings/binding-spv-storage-class.slang b/tests/bindings/binding-spv-storage-class.slang index bb0ad3af3..7337ad77a 100644 --- a/tests/bindings/binding-spv-storage-class.slang +++ b/tests/bindings/binding-spv-storage-class.slang @@ -17,11 +17,11 @@ layout(shaderRecordNV) ConstantBuffer<MyStruct> myStruct : register(b0, space1); ConstantBuffer<MyStruct> myStruct1 : register(b1, space1); // Storage buffer -RWStructuredBuffer<MyStruct> myStruct2 : register(b2, space1); +RWStructuredBuffer<MyStruct> myStruct2 : register(u2, space1); // UniformConstant -Texture2D<float> texture: register(b3, space1); -SamplerState sampler: register(b4, space1); +Texture2D<float> texture: register(t3, space1); +SamplerState sampler: register(s4, space1); [shader("anyhit")] void main(out float3 pos) diff --git a/tests/compute/nonuniformres-as-function-parameter.slang b/tests/compute/nonuniformres-as-function-parameter.slang index daffc848e..38fb2a478 100644 --- a/tests/compute/nonuniformres-as-function-parameter.slang +++ b/tests/compute/nonuniformres-as-function-parameter.slang @@ -2,7 +2,7 @@ //TEST:SIMPLE(filecheck=CHECK_GLSL_SPV):-target spirv -entry main -stage compute -emit-spirv-via-glsl //TEST:SIMPLE(filecheck=CHECK_GLSL):-target glsl -entry main -stage compute //TEST:SIMPLE(filecheck=CHECK_HLSL):-target hlsl -entry main -stage compute -RWStructuredBuffer<uint> globalBuffer[] : register(t0, space0); +RWStructuredBuffer<uint> globalBuffer[] : register(u0, space1); RWStructuredBuffer<uint3> outputBuffer; struct MyStruct diff --git a/tests/diagnostics/invalid-buffer.slang b/tests/diagnostics/invalid-buffer.slang new file mode 100644 index 000000000..53f4c5ff6 --- /dev/null +++ b/tests/diagnostics/invalid-buffer.slang @@ -0,0 +1,9 @@ +//TEST:SIMPLE(filecheck=CHECK): -target spirv + +// CHECK: ([[# @LINE+1]]): error 30400: generic type 'Buffer' used without argument +Buffer b; + +[numthreads(1,1,1)] +void computeMain() +{ +}
\ No newline at end of file diff --git a/tests/diagnostics/register-bindings.slang b/tests/diagnostics/register-bindings.slang index 5c78cb10b..bad1c9aa3 100644 --- a/tests/diagnostics/register-bindings.slang +++ b/tests/diagnostics/register-bindings.slang @@ -3,9 +3,6 @@ // Various bad forms for register bindings -// Not a valid register class: -Texture2D a : register(DOESNT_EXIST); - // No register index given: TextureCube b : register(t); diff --git a/tests/diagnostics/register-bindings.slang.expected b/tests/diagnostics/register-bindings.slang.expected index 74e9917d3..928cf7957 100644 --- a/tests/diagnostics/register-bindings.slang.expected +++ b/tests/diagnostics/register-bindings.slang.expected @@ -1,15 +1,12 @@ result code = -1 standard error = { -tests/diagnostics/register-bindings.slang(7): error 39007: unknown register class: 'DOESNT_EXIST' -Texture2D a : register(DOESNT_EXIST); - ^~~~~~~~~~~~ -tests/diagnostics/register-bindings.slang(10): error 39008: expected a register index after 't' +tests/diagnostics/register-bindings.slang(7): error 39008: expected a register index after 't' TextureCube b : register(t); ^ -tests/diagnostics/register-bindings.slang(13): error 39009: expected 'space', got 's' +tests/diagnostics/register-bindings.slang(10): error 39009: expected 'space', got 's' SamplerState c : register(s0, s1); ^~ -tests/diagnostics/register-bindings.slang(16): error 39010: expected a register space index after 'space' +tests/diagnostics/register-bindings.slang(13): error 39010: expected a register space index after 'space' SamplerState d : register(s2, space); ^~~~~ } diff --git a/tests/hlsl/invalid-semantic.slang b/tests/hlsl/invalid-semantic.slang new file mode 100644 index 000000000..69465f731 --- /dev/null +++ b/tests/hlsl/invalid-semantic.slang @@ -0,0 +1,56 @@ +//TEST:SIMPLE(filecheck=CHECK): -target spirv + +struct Test_t +{ + uint4 foo; +}; + +// CHECK: ([[# @LINE+1]]): error 31222: invalid HLSL register name +RWStructuredBuffer< Test_t > g_Test : register(t0, space1); + +// CHECK: ([[# @LINE+1]]): error 31222: invalid HLSL register name +ConstantBuffer< Test_t > g_Test2 : register(t1, space1); + +// CHECK: ([[# @LINE+1]]): error 31222: invalid HLSL register name +StructuredBuffer< Test_t > g_Test3 : register(u2, space1); + +// CHECK: ([[# @LINE+1]]): error 31222: invalid HLSL register name +ByteAddressBuffer g_Test4 : register(u3, space1); + +// CHECK: ([[# @LINE+1]]): error 31222: invalid HLSL register name +RWTexture2D g_Test5 : register(t4, space1); + +// CHECK: ([[# @LINE+1]]): error 31222: invalid HLSL register name +Texture2D g_Test6 : register(u5, space1); + +// CHECK: ([[# @LINE+1]]): error 31222: invalid HLSL register name +FeedbackTexture2D g_Test7 : register(t6, space1); + +// CHECK: ([[# @LINE+1]]): error 31222: invalid HLSL register name +AppendStructuredBuffer< Test_t > g_Test8 : register(t7, space1); + +// CHECK: ([[# @LINE+1]]): error 31222: invalid HLSL register name +ConsumeStructuredBuffer< Test_t > g_Test9 : register(t8, space1); + +// CHECK: ([[# @LINE+1]]): error 31222: invalid HLSL register name +RWByteAddressBuffer g_Test10 : register(t9, space1); + +// CHECK: ([[# @LINE+1]]): error 31222: invalid HLSL register name +RasterizerOrderedByteAddressBuffer g_Test11 : register(t10, space1); + +// CHECK: ([[# @LINE+1]]): error 31222: invalid HLSL register name +SamplerState g_Test12 : register(t11, space1); + +// CHECK: ([[# @LINE+1]]): error 31222: invalid HLSL register name +SamplerComparisonState g_Test13 : register(t12, space1); + +// CHECK: ([[# @LINE+1]]): error 31222: invalid HLSL register name +RaytracingAccelerationStructure g_Test14 : register(u13, space1); + +[numthreads(1,1,1)] +void computeMain() +{ + Test_t test; + test.foo = uint4( 0, 0, 0, 0 ); + g_Test[0] = test; +}
\ No newline at end of file |
