diff --git a/Test/baseResults/hlsl.global-const-init.frag.out b/Test/baseResults/hlsl.global-const-init.frag.out new file mode 100644 index 00000000..659ad53d --- /dev/null +++ b/Test/baseResults/hlsl.global-const-init.frag.out @@ -0,0 +1,178 @@ +hlsl.global-const-init.frag +Shader version: 500 +gl_FragCoord origin is upper left +0:? Sequence +0:6 Sequence +0:6 move second child to first child ( temp 4-component vector of float) +0:6 'bar' ( global 4-component vector of float) +0:6 foo: direct index for structure (layout( row_major std140) uniform 4-component vector of float) +0:6 'anon@0' (layout( row_major std140) uniform block{layout( row_major std140) uniform 4-component vector of float foo}) +0:6 Constant: +0:6 0 (const uint) +0:8 Sequence +0:8 move second child to first child ( temp 2-element array of 2-component vector of float) +0:8 'a1' ( global 2-element array of 2-component vector of float) +0:8 Construct vec2 ( temp 2-element array of 2-component vector of float) +0:8 Constant: +0:8 1.000000 +0:8 2.000000 +0:8 Construct vec2 ( temp 2-component vector of float) +0:8 direct index ( temp float) +0:8 foo: direct index for structure (layout( row_major std140) uniform 4-component vector of float) +0:8 'anon@0' (layout( row_major std140) uniform block{layout( row_major std140) uniform 4-component vector of float foo}) +0:8 Constant: +0:8 0 (const uint) +0:8 Constant: +0:8 0 (const int) +0:8 Constant: +0:8 4.000000 +0:12 Function Definition: @main( ( temp 4-component vector of float) +0:12 Function Parameters: +0:? Sequence +0:13 Branch: Return with expression +0:13 'bar' ( global 4-component vector of float) +0:12 Function Definition: main( ( temp void) +0:12 Function Parameters: +0:? Sequence +0:12 move second child to first child ( temp 4-component vector of float) +0:? '@entryPointOutput' (layout( location=0) out 4-component vector of float) +0:12 Function Call: @main( ( temp 4-component vector of float) +0:? Linker Objects +0:? 'anon@0' (layout( row_major std140) uniform block{layout( row_major std140) uniform 4-component vector of float foo}) +0:? 'bar' ( global 4-component vector of float) +0:? 'a1' ( global 2-element array of 2-component vector of float) +0:? 'a2' ( const 2-element array of 2-component vector of float) +0:? 5.000000 +0:? 6.000000 +0:? 7.000000 +0:? 8.000000 +0:? '@entryPointOutput' (layout( location=0) out 4-component vector of float) + + +Linked fragment stage: + + +Shader version: 500 +gl_FragCoord origin is upper left +0:? Sequence +0:6 Sequence +0:6 move second child to first child ( temp 4-component vector of float) +0:6 'bar' ( global 4-component vector of float) +0:6 foo: direct index for structure (layout( row_major std140) uniform 4-component vector of float) +0:6 'anon@0' (layout( row_major std140) uniform block{layout( row_major std140) uniform 4-component vector of float foo}) +0:6 Constant: +0:6 0 (const uint) +0:8 Sequence +0:8 move second child to first child ( temp 2-element array of 2-component vector of float) +0:8 'a1' ( global 2-element array of 2-component vector of float) +0:8 Construct vec2 ( temp 2-element array of 2-component vector of float) +0:8 Constant: +0:8 1.000000 +0:8 2.000000 +0:8 Construct vec2 ( temp 2-component vector of float) +0:8 direct index ( temp float) +0:8 foo: direct index for structure (layout( row_major std140) uniform 4-component vector of float) +0:8 'anon@0' (layout( row_major std140) uniform block{layout( row_major std140) uniform 4-component vector of float foo}) +0:8 Constant: +0:8 0 (const uint) +0:8 Constant: +0:8 0 (const int) +0:8 Constant: +0:8 4.000000 +0:12 Function Definition: @main( ( temp 4-component vector of float) +0:12 Function Parameters: +0:? Sequence +0:13 Branch: Return with expression +0:13 'bar' ( global 4-component vector of float) +0:12 Function Definition: main( ( temp void) +0:12 Function Parameters: +0:? Sequence +0:12 move second child to first child ( temp 4-component vector of float) +0:? '@entryPointOutput' (layout( location=0) out 4-component vector of float) +0:12 Function Call: @main( ( temp 4-component vector of float) +0:? Linker Objects +0:? 'anon@0' (layout( row_major std140) uniform block{layout( row_major std140) uniform 4-component vector of float foo}) +0:? 'bar' ( global 4-component vector of float) +0:? 'a1' ( global 2-element array of 2-component vector of float) +0:? 'a2' ( const 2-element array of 2-component vector of float) +0:? 5.000000 +0:? 6.000000 +0:? 7.000000 +0:? 8.000000 +0:? '@entryPointOutput' (layout( location=0) out 4-component vector of float) + +// Module Version 10000 +// Generated by (magic number): 80001 +// Id's are bound by 50 + + Capability Shader + 1: ExtInstImport "GLSL.std.450" + MemoryModel Logical GLSL450 + EntryPoint Fragment 4 "main" 41 + ExecutionMode 4 OriginUpperLeft + Source HLSL 500 + Name 4 "main" + Name 9 "@main(" + Name 12 "bar" + Name 13 "CB" + MemberName 13(CB) 0 "foo" + Name 15 "" + Name 26 "a1" + Name 41 "@entryPointOutput" + MemberDecorate 13(CB) 0 Offset 0 + Decorate 13(CB) Block + Decorate 15 DescriptorSet 0 + Decorate 41(@entryPointOutput) Location 0 + 2: TypeVoid + 3: TypeFunction 2 + 6: TypeFloat 32 + 7: TypeVector 6(float) 4 + 8: TypeFunction 7(fvec4) + 11: TypePointer Private 7(fvec4) + 12(bar): 11(ptr) Variable Private + 13(CB): TypeStruct 7(fvec4) + 14: TypePointer Uniform 13(CB) + 15: 14(ptr) Variable Uniform + 16: TypeInt 32 1 + 17: 16(int) Constant 0 + 18: TypePointer Uniform 7(fvec4) + 21: TypeVector 6(float) 2 + 22: TypeInt 32 0 + 23: 22(int) Constant 2 + 24: TypeArray 21(fvec2) 23 + 25: TypePointer Private 24 + 26(a1): 25(ptr) Variable Private + 27: 6(float) Constant 1065353216 + 28: 6(float) Constant 1073741824 + 29: 21(fvec2) ConstantComposite 27 28 + 30: 22(int) Constant 0 + 31: TypePointer Uniform 6(float) + 34: 6(float) Constant 1082130432 + 40: TypePointer Output 7(fvec4) +41(@entryPointOutput): 40(ptr) Variable Output + 43: 6(float) Constant 1084227584 + 44: 6(float) Constant 1086324736 + 45: 21(fvec2) ConstantComposite 43 44 + 46: 6(float) Constant 1088421888 + 47: 6(float) Constant 1090519040 + 48: 21(fvec2) ConstantComposite 46 47 + 49: 24 ConstantComposite 45 48 + 4(main): 2 Function None 3 + 5: Label + 19: 18(ptr) AccessChain 15 17 + 20: 7(fvec4) Load 19 + Store 12(bar) 20 + 32: 31(ptr) AccessChain 15 17 30 + 33: 6(float) Load 32 + 35: 21(fvec2) CompositeConstruct 33 34 + 36: 24 CompositeConstruct 29 35 + Store 26(a1) 36 + 42: 7(fvec4) FunctionCall 9(@main() + Store 41(@entryPointOutput) 42 + Return + FunctionEnd + 9(@main(): 7(fvec4) Function None 8 + 10: Label + 37: 7(fvec4) Load 12(bar) + ReturnValue 37 + FunctionEnd diff --git a/Test/hlsl.global-const-init.frag b/Test/hlsl.global-const-init.frag new file mode 100644 index 00000000..d8f36c96 --- /dev/null +++ b/Test/hlsl.global-const-init.frag @@ -0,0 +1,14 @@ + +cbuffer CB { + float4 foo; +}; + +static const float4 bar = foo; // test const (in the immutable sense) initializer from non-const. + +static const float2 a1[2] = { { 1, 2 }, { foo.x, 4 } }; // not entirely constant +static const float2 a2[2] = { { 5, 6 }, { 7, 8 } }; // entirely constant + +float4 main() : SV_Target0 +{ + return bar; +} diff --git a/gtests/Hlsl.FromFile.cpp b/gtests/Hlsl.FromFile.cpp index d6fe367d..ea90b62e 100644 --- a/gtests/Hlsl.FromFile.cpp +++ b/gtests/Hlsl.FromFile.cpp @@ -137,6 +137,7 @@ INSTANTIATE_TEST_CASE_P( {"hlsl.getdimensions.rw.dx10.frag", "main"}, {"hlsl.getdimensions.dx10.vert", "main"}, {"hlsl.getsampleposition.dx10.frag", "main"}, + {"hlsl.global-const-init.frag", "main"}, {"hlsl.domain.1.tese", "main"}, {"hlsl.domain.2.tese", "main"}, {"hlsl.domain.3.tese", "main"}, diff --git a/hlsl/hlslGrammar.cpp b/hlsl/hlslGrammar.cpp index 95869e8d..05c95d36 100755 --- a/hlsl/hlslGrammar.cpp +++ b/hlsl/hlslGrammar.cpp @@ -2553,8 +2553,19 @@ bool HlslGrammar::acceptInitializer(TIntermTyped*& node) expected("assignment expression in initializer list"); return false; } + + const bool firstNode = (node == nullptr); + node = intermediate.growAggregate(node, expr, loc); + // If every sub-node in the list has qualifier EvqConst, the returned node becomes + // EvqConst. Otherwise, it becomes EvqTemporary. That doesn't happen with e.g. + // EvqIn or EvqPosition, since the collection isn't EvqPosition if all the members are. + if (firstNode && expr->getQualifier().storage == EvqConst) + node->getQualifier().storage = EvqConst; + else if (expr->getQualifier().storage != EvqConst) + node->getQualifier().storage = EvqTemporary; + // COMMA if (acceptTokenClass(EHTokComma)) { if (acceptTokenClass(EHTokRightBrace)) // allow trailing comma diff --git a/hlsl/hlslParseHelper.cpp b/hlsl/hlslParseHelper.cpp index 27dac886..50d88d2f 100755 --- a/hlsl/hlslParseHelper.cpp +++ b/hlsl/hlslParseHelper.cpp @@ -7165,6 +7165,21 @@ TIntermNode* HlslParseContext::declareVariable(const TSourceLoc& loc, const TStr if (voidErrorCheck(loc, identifier, type.getBasicType())) return nullptr; + // Global consts with initializers that are non-const act like EvqGlobal in HLSL. + // This test is implicitly recursive, because initializers propagate constness + // up the aggregate node tree during creation. E.g, for: + // { { 1, 2 }, { 3, 4 } } + // the initializer list is marked EvqConst at the top node, and remains so here. However: + // { 1, { myvar, 2 }, 3 } + // is not a const intializer, and still becomes EvqGlobal here. + + const bool nonConstInitializer = (initializer != nullptr && initializer->getQualifier().storage != EvqConst); + + if (type.getQualifier().storage == EvqConst && symbolTable.atGlobalLevel() && nonConstInitializer) { + // Force to global + type.getQualifier().storage = EvqGlobal; + } + // make const and initialization consistent fixConstInit(loc, identifier, type, initializer); @@ -7345,11 +7360,6 @@ TIntermNode* HlslParseContext::executeInitializer(const TSourceLoc& loc, TInterm variable->getWritableType().getQualifier().storage = EvqTemporary; return nullptr; } - if (qualifier == EvqConst && symbolTable.atGlobalLevel() && initializer->getType().getQualifier().storage != EvqConst) { - error(loc, "global const initializers must be constant", "=", "'%s'", variable->getType().getCompleteString().c_str()); - variable->getWritableType().getQualifier().storage = EvqTemporary; - return nullptr; - } // Const variables require a constant initializer if (qualifier == EvqConst) {