diff options
| author | Gangzheng Tong <tonggangzheng@gmail.com> | 2025-05-30 17:16:59 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-05-31 00:16:59 +0000 |
| commit | da5cf478c6be06c9e6c20917a7d472cbdcb624e3 (patch) | |
| tree | 7be790c85547c86b92fff80fa9340c89d71a167e | |
| parent | 3ca27faa23a92124f26875a6f00bcfc3a1c6431e (diff) | |
Add check for the variable requirement (#6677)
* Add check for the variable requirement
This change adds the capability check for the variables requirement.
With this check, the shader
```
[require(cpp_cuda_glsl_hlsl_metal_spirv)]
Buffer<float> InputTyped;
[require(cpp_cuda_glsl_hlsl_metal_spirv)]
RWBuffer<float> OutputTyped;
```
will issue error if targeting to WSGL
e.g. `.\build\Debug\bin\slangc .\tests\wgsl_no_buffer.slang -o
wgsl_no_buffer.txt -target wgsl -entry Main -stage compute`
.\tests\wgsl_no_buffer.slang(2): error 36108: 'InputTyped' has dependencies that are not compatible on the required target 'wgsl'.
Buffer<float> InputTyped;
^~~~~~~~~~
.\tests\wgsl_no_buffer.slang(4): error 36108: 'OutputTyped' has dependencies that are not compatible on the required target 'wgsl'.
RWBuffer<float> OutputTyped;
^~~~~~~~~~~
Fixes #6304
* Add var capability tests
* Do capability checks for global var only
* Add inferredCapabilityRequirements to var capability check
* Add requirement to the intrinsic types Buffer/RWBuffer
* format code
* Update capabliity test
* use DefaultDataLayout as default data layout
* Use visitMemberExpr to check the capabilities
* Update the cap tests to match the error messages
* update test to use the ScalarDataLayout for hlsl target
* Update tests check condition to use error number only
* Add default push_constant data layout type
---------
Co-authored-by: slangbot <186143334+slangbot@users.noreply.github.com>
| -rw-r--r-- | source/slang/hlsl.meta.slang | 7 | ||||
| -rw-r--r-- | source/slang/slang-ast-builder.cpp | 6 | ||||
| -rw-r--r-- | source/slang/slang-ast-builder.h | 1 | ||||
| -rw-r--r-- | source/slang/slang-ast-type.h | 7 | ||||
| -rw-r--r-- | source/slang/slang-check-decl.cpp | 45 | ||||
| -rw-r--r-- | source/slang/slang-parser.cpp | 5 | ||||
| -rw-r--r-- | source/slang/slang-type-layout.cpp | 1 | ||||
| -rw-r--r-- | tests/bugs/gh-3429.slang | 3 | ||||
| -rw-r--r-- | tests/language-feature/capability/var-capability-incompatible.slang | 19 | ||||
| -rw-r--r-- | tests/language-feature/capability/var-capability-wgsl-2.slang | 15 | ||||
| -rw-r--r-- | tests/language-feature/capability/var-capability-wgsl.slang | 15 | ||||
| -rw-r--r-- | tests/language-feature/capability/var-implicit-capability-wgsl.slang | 14 |
12 files changed, 118 insertions, 20 deletions
diff --git a/source/slang/hlsl.meta.slang b/source/slang/hlsl.meta.slang index ad1a983dd..86cb84d6e 100644 --- a/source/slang/hlsl.meta.slang +++ b/source/slang/hlsl.meta.slang @@ -30,6 +30,12 @@ struct DefaultDataLayout : IBufferDataLayout {}; /// @category misc_types +__intrinsic_type($(kIROp_Std430BufferLayoutType)) +__magic_type(DefaultPushConstantDataLayoutType) +struct DefaultPushConstantDataLayout : IBufferDataLayout +{}; + +/// @category misc_types __intrinsic_type($(kIROp_Std140BufferLayoutType)) [require(spirv)] [require(glsl)] @@ -503,6 +509,7 @@ struct __ShapeCube : __ITextureShape /// @category misc_types __magic_type(TextureShapeBufferType) __intrinsic_type($(kIROp_TextureShapeBufferType)) +[require(cpp_cuda_glsl_hlsl_metal_spirv)] struct __ShapeBuffer : __ITextureShape { static const int flavor = $(SLANG_TEXTURE_BUFFER); diff --git a/source/slang/slang-ast-builder.cpp b/source/slang/slang-ast-builder.cpp index 893d5e6d7..d3e99ee4b 100644 --- a/source/slang/slang-ast-builder.cpp +++ b/source/slang/slang-ast-builder.cpp @@ -289,6 +289,12 @@ Type* ASTBuilder::getDefaultLayoutType() { return getSpecializedBuiltinType({}, "DefaultDataLayoutType"); } + +Type* ASTBuilder::getDefaultPushConstantLayoutType() +{ + return getSpecializedBuiltinType({}, "DefaultPushConstantDataLayoutType"); +} + Type* ASTBuilder::getStd140LayoutType() { return getSpecializedBuiltinType({}, "Std140DataLayoutType"); diff --git a/source/slang/slang-ast-builder.h b/source/slang/slang-ast-builder.h index a25fcea28..5990f90f1 100644 --- a/source/slang/slang-ast-builder.h +++ b/source/slang/slang-ast-builder.h @@ -486,6 +486,7 @@ public: Type* getSpecializedBuiltinType(ArrayView<Val*> genericArgs, const char* magicTypeName); Type* getDefaultLayoutType(); + Type* getDefaultPushConstantLayoutType(); Type* getStd140LayoutType(); Type* getStd430LayoutType(); Type* getScalarLayoutType(); diff --git a/source/slang/slang-ast-type.h b/source/slang/slang-ast-type.h index 1b82fc63a..2d1a592da 100644 --- a/source/slang/slang-ast-type.h +++ b/source/slang/slang-ast-type.h @@ -134,6 +134,13 @@ class DefaultDataLayoutType : public DataLayoutType }; FIDDLE() +class DefaultPushConstantDataLayoutType : public DataLayoutType +{ + FIDDLE(...) +}; + + +FIDDLE() class Std430DataLayoutType : public DataLayoutType { FIDDLE(...) diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index cc65edd2f..081ccbb0b 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -720,6 +720,13 @@ struct SemanticsDeclReferenceVisitor : public SemanticsDeclVisitorBase, // Pass down the callee location processDeclModifiers(expr->declRef.getDecl(), expr->loc); } + + void visitMemberExpr(MemberExpr* expr) + { + dispatchIfNotNull(expr->baseExpression); + visitDeclRefExpr(expr); + } + void visitStaticMemberExpr(StaticMemberExpr* expr) { dispatchIfNotNull(expr->declRef.declRefBase); @@ -2009,7 +2016,7 @@ void SemanticsDeclHeaderVisitor::checkPushConstantBufferType(VarDeclBase* varDec { varDecl->type.type = getConstantBufferType( cbufferType->getElementType(), - m_astBuilder->getStd430LayoutType()); + m_astBuilder->getDefaultPushConstantLayoutType()); } } else if (isGlobalShaderParameter(varDecl)) @@ -2017,8 +2024,9 @@ void SemanticsDeclHeaderVisitor::checkPushConstantBufferType(VarDeclBase* varDec // If this is a global variable with [vk::push_constant] attribute, // we need to make sure to wrap it in a `ConstantBuffer`. // - varDecl->type.type = - getConstantBufferType(varDecl->type, m_astBuilder->getStd430LayoutType()); + varDecl->type.type = getConstantBufferType( + varDecl->type, + m_astBuilder->getDefaultPushConstantLayoutType()); } } } @@ -13660,8 +13668,12 @@ CapabilitySet SemanticsDeclCapabilityVisitor::getDeclaredCapabilitySet(Decl* dec // For every existing target, we want to join their requirements together. // If the the parent defines additional targets, we want to add them to the disjunction set. // For example: - // [require(glsl)] struct Parent { [require(glsl, glsl_ext_1)] [require(spirv)] void - // foo(); } + // [require(glsl)] + // struct Parent { + // [require(glsl, glsl_ext_1)] + // [require(spirv)] + // void foo(); + // } // The requirement for `foo` should be glsl+glsl_ext_1 | spirv. // CapabilitySet declaredCaps; @@ -14197,19 +14209,18 @@ void SemanticsDeclCapabilityVisitor::diagnoseUndeclaredCapability( } } - //// The second scenario is when the callee is using a capability that is not provided by - /// the - /// requirement. / For example: / [require(hlsl,b,c)] / void caller() / { / - /// useD(); - ///// require capability (hlsl,d) / } / In this case we should report that useD() is - /// using a - /// capability that is not declared by caller. - //// - - //// If we reach here, we are case 2. + // The second scenario is when the callee is using a capability that is not provided by the + // requirement. For example: + // [require(hlsl,b,c)] + // void caller() + // { + // useD(); // requires capability (hlsl,d) + // } + // In this case we should report that useD() is using a capability that is not declared by + // caller. If we reach here, we are case 2. We will produce all failed atoms. This is important + // since provenance of multiple atoms can come from multiple referenced items in a function + // body. - // We will produce all failed atoms. This is important since provenance of multiple atoms - // can come from multiple referenced items in a function body. HashSet<Decl*> printedDecls; auto simplifiedFailedAtomsSet = failedAtomsInsideAvailableSet.newSetWithoutImpliedAtoms(); for (auto i : simplifiedFailedAtomsSet) diff --git a/source/slang/slang-parser.cpp b/source/slang/slang-parser.cpp index 9eb8c1391..439959827 100644 --- a/source/slang/slang-parser.cpp +++ b/source/slang/slang-parser.cpp @@ -4976,8 +4976,9 @@ static DeclBase* ParseDeclWithModifiers( }; if (AdvanceIf(parser, "buffer")) { - decl = as<Decl>( - parseGLSLShaderStorageBufferDecl(parser, getLayoutArg("Std430DataLayout"))); + decl = as<Decl>(parseGLSLShaderStorageBufferDecl( + parser, + getLayoutArg("DefaultDataLayout"))); break; } else if (auto mod = findPotentialGLSLInterfaceBlockModifier(parser, modifiers)) diff --git a/source/slang/slang-type-layout.cpp b/source/slang/slang-type-layout.cpp index 6ac3ba079..2c72b61de 100644 --- a/source/slang/slang-type-layout.cpp +++ b/source/slang/slang-type-layout.cpp @@ -1570,6 +1570,7 @@ LayoutRulesImpl* GLSLLayoutRulesFamilyImpl::getConstantBufferRules( case ASTNodeType::DefaultDataLayoutType: case ASTNodeType::Std140DataLayoutType: return &kStd140LayoutRulesImpl_; + case ASTNodeType::DefaultPushConstantDataLayoutType: case ASTNodeType::Std430DataLayoutType: return &kStd430LayoutRulesImpl_; case ASTNodeType::ScalarDataLayoutType: diff --git a/tests/bugs/gh-3429.slang b/tests/bugs/gh-3429.slang index c9b49e5f4..115ebdb06 100644 --- a/tests/bugs/gh-3429.slang +++ b/tests/bugs/gh-3429.slang @@ -14,7 +14,8 @@ struct PushConstants bool bufferHasOnlyOneElement; }; -[[vk::push_constant]] ConstantBuffer<PushConstants> gPushConstants; +[[vk::push_constant]] +ConstantBuffer<PushConstants> gPushConstants; float loadDataConditionTrue() { diff --git a/tests/language-feature/capability/var-capability-incompatible.slang b/tests/language-feature/capability/var-capability-incompatible.slang new file mode 100644 index 000000000..89378f6b3 --- /dev/null +++ b/tests/language-feature/capability/var-capability-incompatible.slang @@ -0,0 +1,19 @@ +//TEST:SIMPLE(filecheck=CHECK):-target spirv +[require(hlsl)] +struct MyType +{} + +//CHECK: ([[# @LINE+2]]): error 36107 +[numthreads(1,1,1)] +void f1() +{ + MyType t; // compile to spirv should result error here. +} + +ConstantBuffer<MyType> t2; +//CHECK: ([[# @LINE+2]]): error 36107 +[numthreads(1,1,1)] +void f2() // compile to spirv should result error here. +{ + ConstantBuffer<MyType> t3 = t2; +} diff --git a/tests/language-feature/capability/var-capability-wgsl-2.slang b/tests/language-feature/capability/var-capability-wgsl-2.slang new file mode 100644 index 000000000..4fb259ea6 --- /dev/null +++ b/tests/language-feature/capability/var-capability-wgsl-2.slang @@ -0,0 +1,15 @@ +//TEST:SIMPLE(filecheck=CHECK_IGNORE_CAPS): -target wgsl -entry Main -stage compute + +//CHECK_IGNORE_CAPS-NOT: error 36107 +[require(cpp_cuda_glsl_hlsl_metal_spirv)] +struct inputWrapper { + RWBuffer<float> InputTyped; +}; + +inputWrapper input; + +[numthreads(64, 1, 1)] +void Main(uint3 DTid : SV_DispatchThreadID) +{ + // We should not see an error here, because the inputWrapper is not referenced. +}
\ No newline at end of file diff --git a/tests/language-feature/capability/var-capability-wgsl.slang b/tests/language-feature/capability/var-capability-wgsl.slang new file mode 100644 index 000000000..2a67cc6e2 --- /dev/null +++ b/tests/language-feature/capability/var-capability-wgsl.slang @@ -0,0 +1,15 @@ +//TEST:SIMPLE(filecheck=CHECK): -target wgsl -entry Main -stage compute +//TEST:SIMPLE(filecheck=CHECK_IGNORE_CAPS): -target wgsl -entry Main -stage compute -ignore-capabilities + +[require(cpp_cuda_glsl_hlsl_metal_spirv)] +Buffer<float> InputTyped; +[require(cpp_cuda_glsl_hlsl_metal_spirv)] +RWBuffer<float> OutputTyped; + +//CHECK: ([[# @LINE+3]]): error 36107 +//CHECK_IGNORE_CAPS-NOT: error 36107 +[numthreads(64, 1, 1)] +void Main(uint3 DTid : SV_DispatchThreadID) +{ + OutputTyped[DTid.x] = InputTyped[DTid.x]; +}
\ No newline at end of file diff --git a/tests/language-feature/capability/var-implicit-capability-wgsl.slang b/tests/language-feature/capability/var-implicit-capability-wgsl.slang new file mode 100644 index 000000000..56aa4157d --- /dev/null +++ b/tests/language-feature/capability/var-implicit-capability-wgsl.slang @@ -0,0 +1,14 @@ +//TEST:SIMPLE(filecheck=CHECK): -target wgsl -entry Main -stage compute +//TEST:SIMPLE(filecheck=CHECK_IGNORE_CAPS): -target wgsl -entry Main -stage compute -ignore-capabilities + + +Buffer<float> InputTyped; +RWBuffer<float> OutputTyped; + +//CHECK: ([[# @LINE+3]]): error 36107 +//CHECK_IGNORE_CAPS-NOT: error 36107 +[numthreads(64, 1, 1)] +void Main(uint3 DTid : SV_DispatchThreadID) +{ + OutputTyped[DTid.x] = InputTyped[DTid.x]; +}
\ No newline at end of file |
