summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYong He <yonghe@outlook.com>2025-05-15 12:51:29 -0700
committerGitHub <noreply@github.com>2025-05-15 12:51:29 -0700
commit0d6312f3be66f4bff9eec9606228db3edc309e2c (patch)
treea868e452e2d25a88f8a6cdee109a280edd11c0fb
parentd961f4438ef865028d289148d22e0fb5c0d8319a (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.cpp3
-rw-r--r--source/slang/slang-check-decl.cpp91
-rw-r--r--source/slang/slang-check-type.cpp12
-rw-r--r--source/slang/slang-diagnostic-defs.h7
-rw-r--r--source/slang/slang.cpp7
-rw-r--r--tests/bindings/binding-spv-storage-class.slang6
-rw-r--r--tests/compute/nonuniformres-as-function-parameter.slang2
-rw-r--r--tests/diagnostics/invalid-buffer.slang9
-rw-r--r--tests/diagnostics/register-bindings.slang3
-rw-r--r--tests/diagnostics/register-bindings.slang.expected9
-rw-r--r--tests/hlsl/invalid-semantic.slang56
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