HLSL: Fix #1432: Globally initialize local static variables.

This commit is contained in:
John Kessenich 2018-07-11 01:09:14 -06:00
parent 64315a8aed
commit cf6bd066b9
7 changed files with 257 additions and 12 deletions

View File

@ -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

20
Test/hlsl.staticFuncInit.frag Executable file
View File

@ -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);
}

View File

@ -1,3 +1,3 @@
// This header is generated by the make-revision script.
#define GLSLANG_PATCH_LEVEL 2797
#define GLSLANG_PATCH_LEVEL 2801

1
gtests/Hlsl.FromFile.cpp Normal file → Executable file
View File

@ -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"},

View File

@ -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?

View File

@ -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

View File

@ -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)
{
//