From cf6bd066b9c67d06b1bc944ed48d853017a1d836 Mon Sep 17 00:00:00 2001 From: John Kessenich Date: Wed, 11 Jul 2018 01:09:14 -0600 Subject: [PATCH] HLSL: Fix #1432: Globally initialize local static variables. --- Test/baseResults/hlsl.staticFuncInit.frag.out | 218 ++++++++++++++++++ Test/hlsl.staticFuncInit.frag | 20 ++ glslang/Include/revision.h | 2 +- gtests/Hlsl.FromFile.cpp | 1 + hlsl/hlslGrammar.cpp | 23 +- hlsl/hlslGrammar.h | 3 +- hlsl/hlslParseHelper.cpp | 2 + 7 files changed, 257 insertions(+), 12 deletions(-) create mode 100755 Test/baseResults/hlsl.staticFuncInit.frag.out create mode 100755 Test/hlsl.staticFuncInit.frag mode change 100644 => 100755 gtests/Hlsl.FromFile.cpp diff --git a/Test/baseResults/hlsl.staticFuncInit.frag.out b/Test/baseResults/hlsl.staticFuncInit.frag.out new file mode 100755 index 00000000..d468cec3 --- /dev/null +++ b/Test/baseResults/hlsl.staticFuncInit.frag.out @@ -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 index 00000000..f61c5661 --- /dev/null +++ b/Test/hlsl.staticFuncInit.frag @@ -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); +} diff --git a/glslang/Include/revision.h b/glslang/Include/revision.h index b8d443b2..99c1d4f3 100644 --- a/glslang/Include/revision.h +++ b/glslang/Include/revision.h @@ -1,3 +1,3 @@ // This header is generated by the make-revision script. -#define GLSLANG_PATCH_LEVEL 2797 +#define GLSLANG_PATCH_LEVEL 2801 diff --git a/gtests/Hlsl.FromFile.cpp b/gtests/Hlsl.FromFile.cpp old mode 100644 new mode 100755 index 861c0988..635c7a87 --- a/gtests/Hlsl.FromFile.cpp +++ b/gtests/Hlsl.FromFile.cpp @@ -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"}, diff --git a/hlsl/hlslGrammar.cpp b/hlsl/hlslGrammar.cpp index cb058779..8788d657 100755 --- a/hlsl/hlslGrammar.cpp +++ b/hlsl/hlslGrammar.cpp @@ -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? diff --git a/hlsl/hlslGrammar.h b/hlsl/hlslGrammar.h index 046f7957..323f3b13 100755 --- a/hlsl/hlslGrammar.h +++ b/hlsl/hlslGrammar.h @@ -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 diff --git a/hlsl/hlslParseHelper.cpp b/hlsl/hlslParseHelper.cpp index 76fdfabc..9471f774 100755 --- a/hlsl/hlslParseHelper.cpp +++ b/hlsl/hlslParseHelper.cpp @@ -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) { //