Merge pull request #978 from LoopDawg/global-const-init-fix
HLSL: support global const initializers from non-constant rvalues
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 0000000..659ad53
--- /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 0000000..d8f36c9
--- /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 d6fe367..ea90b62 100644
--- a/gtests/Hlsl.FromFile.cpp
+++ b/gtests/Hlsl.FromFile.cpp
@@ -137,6 +137,7 @@
{"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 95869e8..05c95d3 100755
--- a/hlsl/hlslGrammar.cpp
+++ b/hlsl/hlslGrammar.cpp
@@ -2553,8 +2553,19 @@
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 27dac88..50d88d2 100755
--- a/hlsl/hlslParseHelper.cpp
+++ b/hlsl/hlslParseHelper.cpp
@@ -7165,6 +7165,21 @@
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 @@
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) {