HLSL: Fix #1432: Globally initialize local static variables.
authorJohn Kessenich <cepheus@frii.com>
Wed, 11 Jul 2018 07:09:14 +0000 (01:09 -0600)
committerJohn Kessenich <cepheus@frii.com>
Wed, 11 Jul 2018 07:09:14 +0000 (01:09 -0600)
Test/baseResults/hlsl.staticFuncInit.frag.out [new file with mode: 0755]
Test/hlsl.staticFuncInit.frag [new file with mode: 0755]
glslang/Include/revision.h
gtests/Hlsl.FromFile.cpp [changed mode: 0644->0755]
hlsl/hlslGrammar.cpp
hlsl/hlslGrammar.h
hlsl/hlslParseHelper.cpp

diff --git a/Test/baseResults/hlsl.staticFuncInit.frag.out b/Test/baseResults/hlsl.staticFuncInit.frag.out
new file mode 100755 (executable)
index 0000000..d468cec
--- /dev/null
@@ -0,0 +1,218 @@
+hlsl.staticFuncInit.frag
+Shader version: 500
+gl_FragCoord origin is upper left
+0:12Sequence
+0:1  Sequence
+0:1    move second child to first child ( temp float)
+0:1      'x' ( global float)
+0:1      Constant:
+0:1        1.000000
+0:5  Sequence
+0:5    move second child to first child ( temp float)
+0:5      'x' ( global float)
+0:5      Constant:
+0:5        2.000000
+0:4  Function Definition: f1( ( temp float)
+0:4    Function Parameters: 
+0:?     Sequence
+0:6      add second child into first child ( temp float)
+0:6        'x' ( global float)
+0:6        Constant:
+0:6          10.000000
+0:7      Branch: Return with expression
+0:7        'x' ( global float)
+0:12  Sequence
+0:12    move second child to first child ( temp float)
+0:12      'x' ( global float)
+0:12      Constant:
+0:12        7.000000
+0:11  Function Definition: f2(f1; ( temp float)
+0:11    Function Parameters: 
+0:11      'p' ( in float)
+0:?     Sequence
+0:13      add second child into first child ( temp float)
+0:13        'x' ( global float)
+0:13        'p' ( in float)
+0:14      Branch: Return with expression
+0:14        'x' ( global float)
+0:18  Function Definition: @main( ( temp 4-component vector of float)
+0:18    Function Parameters: 
+0:?     Sequence
+0:19      Branch: Return with expression
+0:19        Construct vec4 ( temp 4-component vector of float)
+0:19          add ( temp float)
+0:19            add ( temp float)
+0:19              add ( temp float)
+0:19                add ( temp float)
+0:19                  'x' ( global float)
+0:19                  Function Call: f1( ( temp float)
+0:19                Function Call: f1( ( temp float)
+0:19              Function Call: f2(f1; ( temp float)
+0:19                Constant:
+0:19                  5.000000
+0:19            Function Call: f2(f1; ( temp float)
+0:19              'x' ( global float)
+0:18  Function Definition: main( ( temp void)
+0:18    Function Parameters: 
+0:?     Sequence
+0:18      move second child to first child ( temp 4-component vector of float)
+0:?         '@entryPointOutput' (layout( location=0) out 4-component vector of float)
+0:18        Function Call: @main( ( temp 4-component vector of float)
+0:?   Linker Objects
+0:?     'x' ( global float)
+0:?     '@entryPointOutput' (layout( location=0) out 4-component vector of float)
+
+
+Linked fragment stage:
+
+
+Shader version: 500
+gl_FragCoord origin is upper left
+0:12Sequence
+0:1  Sequence
+0:1    move second child to first child ( temp float)
+0:1      'x' ( global float)
+0:1      Constant:
+0:1        1.000000
+0:5  Sequence
+0:5    move second child to first child ( temp float)
+0:5      'x' ( global float)
+0:5      Constant:
+0:5        2.000000
+0:4  Function Definition: f1( ( temp float)
+0:4    Function Parameters: 
+0:?     Sequence
+0:6      add second child into first child ( temp float)
+0:6        'x' ( global float)
+0:6        Constant:
+0:6          10.000000
+0:7      Branch: Return with expression
+0:7        'x' ( global float)
+0:12  Sequence
+0:12    move second child to first child ( temp float)
+0:12      'x' ( global float)
+0:12      Constant:
+0:12        7.000000
+0:11  Function Definition: f2(f1; ( temp float)
+0:11    Function Parameters: 
+0:11      'p' ( in float)
+0:?     Sequence
+0:13      add second child into first child ( temp float)
+0:13        'x' ( global float)
+0:13        'p' ( in float)
+0:14      Branch: Return with expression
+0:14        'x' ( global float)
+0:18  Function Definition: @main( ( temp 4-component vector of float)
+0:18    Function Parameters: 
+0:?     Sequence
+0:19      Branch: Return with expression
+0:19        Construct vec4 ( temp 4-component vector of float)
+0:19          add ( temp float)
+0:19            add ( temp float)
+0:19              add ( temp float)
+0:19                add ( temp float)
+0:19                  'x' ( global float)
+0:19                  Function Call: f1( ( temp float)
+0:19                Function Call: f1( ( temp float)
+0:19              Function Call: f2(f1; ( temp float)
+0:19                Constant:
+0:19                  5.000000
+0:19            Function Call: f2(f1; ( temp float)
+0:19              'x' ( global float)
+0:18  Function Definition: main( ( temp void)
+0:18    Function Parameters: 
+0:?     Sequence
+0:18      move second child to first child ( temp 4-component vector of float)
+0:?         '@entryPointOutput' (layout( location=0) out 4-component vector of float)
+0:18        Function Call: @main( ( temp 4-component vector of float)
+0:?   Linker Objects
+0:?     'x' ( global float)
+0:?     '@entryPointOutput' (layout( location=0) out 4-component vector of float)
+
+// Module Version 10000
+// Generated by (magic number): 80007
+// Id's are bound by 57
+
+                              Capability Shader
+               1:             ExtInstImport  "GLSL.std.450"
+                              MemoryModel Logical GLSL450
+                              EntryPoint Fragment 4  "main" 55
+                              ExecutionMode 4 OriginUpperLeft
+                              Source HLSL 500
+                              Name 4  "main"
+                              Name 8  "f1("
+                              Name 13  "f2(f1;"
+                              Name 12  "p"
+                              Name 17  "@main("
+                              Name 20  "x"
+                              Name 22  "x"
+                              Name 24  "x"
+                              Name 44  "param"
+                              Name 47  "param"
+                              Name 55  "@entryPointOutput"
+                              Decorate 55(@entryPointOutput) Location 0
+               2:             TypeVoid
+               3:             TypeFunction 2
+               6:             TypeFloat 32
+               7:             TypeFunction 6(float)
+              10:             TypePointer Function 6(float)
+              11:             TypeFunction 6(float) 10(ptr)
+              15:             TypeVector 6(float) 4
+              16:             TypeFunction 15(fvec4)
+              19:             TypePointer Private 6(float)
+           20(x):     19(ptr) Variable Private
+              21:    6(float) Constant 1065353216
+           22(x):     19(ptr) Variable Private
+              23:    6(float) Constant 1073741824
+           24(x):     19(ptr) Variable Private
+              25:    6(float) Constant 1088421888
+              26:    6(float) Constant 1092616192
+              43:    6(float) Constant 1084227584
+              54:             TypePointer Output 15(fvec4)
+55(@entryPointOutput):     54(ptr) Variable Output
+         4(main):           2 Function None 3
+               5:             Label
+                              Store 20(x) 21
+                              Store 22(x) 23
+                              Store 24(x) 25
+              56:   15(fvec4) FunctionCall 17(@main()
+                              Store 55(@entryPointOutput) 56
+                              Return
+                              FunctionEnd
+          8(f1():    6(float) Function None 7
+               9:             Label
+              27:    6(float) Load 22(x)
+              28:    6(float) FAdd 27 26
+                              Store 22(x) 28
+              29:    6(float) Load 22(x)
+                              ReturnValue 29
+                              FunctionEnd
+      13(f2(f1;):    6(float) Function None 11
+           12(p):     10(ptr) FunctionParameter
+              14:             Label
+              32:    6(float) Load 12(p)
+              33:    6(float) Load 24(x)
+              34:    6(float) FAdd 33 32
+                              Store 24(x) 34
+              35:    6(float) Load 24(x)
+                              ReturnValue 35
+                              FunctionEnd
+      17(@main():   15(fvec4) Function None 16
+              18:             Label
+       44(param):     10(ptr) Variable Function
+       47(param):     10(ptr) Variable Function
+              38:    6(float) Load 20(x)
+              39:    6(float) FunctionCall 8(f1()
+              40:    6(float) FAdd 38 39
+              41:    6(float) FunctionCall 8(f1()
+              42:    6(float) FAdd 40 41
+                              Store 44(param) 43
+              45:    6(float) FunctionCall 13(f2(f1;) 44(param)
+              46:    6(float) FAdd 42 45
+              48:    6(float) Load 20(x)
+                              Store 47(param) 48
+              49:    6(float) FunctionCall 13(f2(f1;) 47(param)
+              50:    6(float) FAdd 46 49
+              51:   15(fvec4) CompositeConstruct 50 50 50 50
+                              ReturnValue 51
+                              FunctionEnd
diff --git a/Test/hlsl.staticFuncInit.frag b/Test/hlsl.staticFuncInit.frag
new file mode 100755 (executable)
index 0000000..f61c566
--- /dev/null
@@ -0,0 +1,20 @@
+static float x = 1.0;
+
+float f1()
+{
+    static float x = 2.0;
+    x += 10.0;
+    return x;
+}
+
+float f2(float p)
+{
+    static float x = 7.0;
+    x += p;
+    return x;
+}
+
+float4 main() : SV_TARGET
+{
+    return x + f1() + f1() + f2(5.0) + f2(x);
+}
index b8d443b..99c1d4f 100644 (file)
@@ -1,3 +1,3 @@
 // This header is generated by the make-revision script.
 
-#define GLSLANG_PATCH_LEVEL 2797
+#define GLSLANG_PATCH_LEVEL 2801
old mode 100644 (file)
new mode 100755 (executable)
index 861c098..635c7a8
@@ -318,6 +318,7 @@ INSTANTIATE_TEST_CASE_P(
         {"hlsl.self_cast.frag", "main"},
         {"hlsl.snorm.uav.comp", "main"},
         {"hlsl.staticMemberFunction.frag", "main"},
+        {"hlsl.staticFuncInit.frag", "main"},
         {"hlsl.store.rwbyteaddressbuffer.type.comp", "main"},
         {"hlsl.stringtoken.frag", "main"},
         {"hlsl.string.frag", "main"},
index cb05877..8788d65 100755 (executable)
@@ -126,8 +126,6 @@ bool HlslGrammar::acceptIdentifier(HlslToken& idToken)
 //
 bool HlslGrammar::acceptCompilationUnit()
 {
-    TIntermNode* unitNode = nullptr;
-
     if (! acceptDeclarationList(unitNode))
         return false;
 
@@ -324,7 +322,7 @@ bool HlslGrammar::acceptSamplerDeclarationDX9(TType& /*type*/)
 // node for all the initializers. Each function created is a top-level node to grow
 // into the passed-in nodeList.
 //
-// If 'nodeList' is passed in as non-null, it must an aggregate to extend for
+// If 'nodeList' is passed in as non-null, it must be an aggregate to extend for
 // each top-level node the declaration creates. Otherwise, if only one top-level
 // node in generated here, that is want is returned in nodeList.
 //
@@ -489,7 +487,7 @@ bool HlslGrammar::acceptDeclaration(TIntermNode*& nodeList)
                         // Declare the variable and add any initializer code to the AST.
                         // The top-level node is always made into an aggregate, as that's
                         // historically how the AST has been.
-                        initializers = intermediate.growAggregate(initializers,
+                        initializers = intermediate.growAggregate(initializers, 
                             parseContext.declareVariable(idToken.loc, *fullName, variableType, expressionNode),
                             idToken.loc);
                     }
@@ -506,11 +504,16 @@ bool HlslGrammar::acceptDeclaration(TIntermNode*& nodeList)
     if (initializers != nullptr)
         initializers->setOperator(EOpSequence);
 
-    // Add the initializers' aggregate to the nodeList we were handed.
-    if (nodeList)
-        nodeList = intermediate.growAggregate(nodeList, initializers);
-    else
-        nodeList = initializers;
+    // if we have a locally scoped static, it needs a globally scoped initializer
+    if (declaredType.getQualifier().storage == EvqGlobal && !parseContext.symbolTable.atGlobalLevel()) {
+        unitNode = intermediate.growAggregate(unitNode, initializers, idToken.loc);
+    } else {
+        // Add the initializers' aggregate to the nodeList we were handed.
+        if (nodeList)
+            nodeList = intermediate.growAggregate(nodeList, initializers);
+        else
+            nodeList = initializers;
+    }
 
     // SEMICOLON
     if (! acceptTokenClass(EHTokSemicolon)) {
@@ -651,7 +654,7 @@ bool HlslGrammar::acceptQualifier(TQualifier& qualifier)
     do {
         switch (peek()) {
         case EHTokStatic:
-            qualifier.storage = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+            qualifier.storage = EvqGlobal;
             break;
         case EHTokExtern:
             // TODO: no meaning in glslang?
index 046f795..323f3b1 100755 (executable)
@@ -52,7 +52,7 @@ namespace glslang {
     public:
         HlslGrammar(HlslScanContext& scanner, HlslParseContext& parseContext)
             : HlslTokenStream(scanner), parseContext(parseContext), intermediate(parseContext.intermediate),
-              typeIdentifiers(false) { }
+              typeIdentifiers(false), unitNode(nullptr) { }
         virtual ~HlslGrammar() { }
 
         bool parse();
@@ -133,6 +133,7 @@ namespace glslang {
         HlslParseContext& parseContext;  // state of parsing and helper functions for building the intermediate
         TIntermediate& intermediate;     // the final product, the intermediate representation, includes the AST
         bool typeIdentifiers;            // shader uses some types as identifiers
+        TIntermNode* unitNode;
     };
 
 } // end namespace glslang
index 76fdfab..9471f77 100755 (executable)
@@ -7866,6 +7866,8 @@ TVariable* HlslParseContext::declareNonArray(const TSourceLoc& loc, const TStrin
 // Returning nullptr just means there is no code to execute to handle the
 // initializer, which will, for example, be the case for constant initializers.
 //
+// Returns a subtree that accomplished the initialization.
+//
 TIntermNode* HlslParseContext::executeInitializer(const TSourceLoc& loc, TIntermTyped* initializer, TVariable* variable)
 {
     //