HLSL: Implement proper nesting of symbol-table scopes and identifier searching.

This commit is contained in:
John Kessenich 2016-06-09 02:02:17 -06:00
parent 71351de879
commit 077e052a8f
9 changed files with 204 additions and 51 deletions

View File

@ -0,0 +1,150 @@
hlsl.scope.frag
Shader version: 450
gl_FragCoord origin is upper left
0:? Sequence
0:31 Function Definition: PixelShaderFunction(vf4; (temp 4-component vector of float)
0:2 Function Parameters:
0:2 'input' (temp 4-component vector of float)
0:? Sequence
0:4 'x' (temp int)
0:? Sequence
0:7 'x' (temp float)
0:? Sequence
0:10 'x' (temp bool)
0:? Sequence
0:13 'x' (temp 3-component vector of float)
0:15 'x' (temp bool)
0:17 'x' (temp float)
0:19 'x' (temp int)
0:21 Test condition and select (temp void)
0:21 Condition
0:21 Compare Greater Than (temp bool)
0:21 'x' (temp int)
0:21 Constant:
0:21 0 (const int)
0:21 true case is null
0:24 Loop with condition tested first
0:24 Loop Condition
0:24 Compare Greater Than (temp bool)
0:24 'x' (temp int)
0:24 Constant:
0:24 0 (const int)
0:24 No loop body
0:27 Loop with condition not tested first
0:27 Loop Condition
0:29 Compare Greater Than (temp bool)
0:29 'x' (temp int)
0:29 Constant:
0:29 0 (const int)
0:27 No loop body
0:? Linker Objects
Linked fragment stage:
Shader version: 450
gl_FragCoord origin is upper left
0:? Sequence
0:31 Function Definition: PixelShaderFunction(vf4; (temp 4-component vector of float)
0:2 Function Parameters:
0:2 'input' (temp 4-component vector of float)
0:? Sequence
0:4 'x' (temp int)
0:? Sequence
0:7 'x' (temp float)
0:? Sequence
0:10 'x' (temp bool)
0:? Sequence
0:13 'x' (temp 3-component vector of float)
0:15 'x' (temp bool)
0:17 'x' (temp float)
0:19 'x' (temp int)
0:21 Test condition and select (temp void)
0:21 Condition
0:21 Compare Greater Than (temp bool)
0:21 'x' (temp int)
0:21 Constant:
0:21 0 (const int)
0:21 true case is null
0:24 Loop with condition tested first
0:24 Loop Condition
0:24 Compare Greater Than (temp bool)
0:24 'x' (temp int)
0:24 Constant:
0:24 0 (const int)
0:24 No loop body
0:27 Loop with condition not tested first
0:27 Loop Condition
0:29 Compare Greater Than (temp bool)
0:29 'x' (temp int)
0:29 Constant:
0:29 0 (const int)
0:27 No loop body
0:? Linker Objects
// Module Version 10000
// Generated by (magic number): 80001
// Id's are bound by 36
Capability Shader
1: ExtInstImport "GLSL.std.450"
MemoryModel Logical GLSL450
EntryPoint Fragment 4 "PixelShaderFunction"
ExecutionMode 4 OriginUpperLeft
Source HLSL 450
Name 4 "PixelShaderFunction"
Name 8 "x"
Name 11 "x"
Name 14 "x"
Name 17 "x"
2: TypeVoid
3: TypeFunction 2
6: TypeInt 32 1
7: TypePointer Function 6(int)
9: TypeFloat 32
10: TypePointer Function 9(float)
12: TypeBool
13: TypePointer Function 12(bool)
15: TypeVector 9(float) 3
16: TypePointer Function 15(fvec3)
19: 6(int) Constant 0
4(PixelShaderFunction): 2 Function None 3
5: Label
8(x): 7(ptr) Variable Function
11(x): 10(ptr) Variable Function
14(x): 13(ptr) Variable Function
17(x): 16(ptr) Variable Function
18: 6(int) Load 8(x)
20: 12(bool) SGreaterThan 18 19
SelectionMerge 22 None
BranchConditional 20 21 22
21: Label
Branch 22
22: Label
Branch 23
23: Label
LoopMerge 25 26 None
Branch 27
27: Label
28: 6(int) Load 8(x)
29: 12(bool) SGreaterThan 28 19
BranchConditional 29 24 25
24: Label
Branch 26
26: Label
Branch 23
25: Label
Branch 30
30: Label
LoopMerge 32 33 None
Branch 31
31: Label
Branch 33
33: Label
34: 6(int) Load 8(x)
35: 12(bool) SGreaterThan 34 19
BranchConditional 35 30 32
32: Label
Return
FunctionEnd

30
Test/hlsl.scope.frag Normal file
View File

@ -0,0 +1,30 @@
float4 PixelShaderFunction(float4 input) : COLOR0
{
int x;
x;
{
float x;
x;
{
bool x;
x;
{
float3 x;
x;
}
x;
}
x;
}
x;
if (x > 0)
bool x;
while (x > 0)
bool x;
do {
bool x;
} while (x > 0);
}

View File

@ -88,6 +88,7 @@ INSTANTIATE_TEST_CASE_P(
{"hlsl.max.frag", "PixelShaderFunction"}, {"hlsl.max.frag", "PixelShaderFunction"},
{"hlsl.precedence.frag", "PixelShaderFunction"}, {"hlsl.precedence.frag", "PixelShaderFunction"},
{"hlsl.precedence2.frag", "PixelShaderFunction"}, {"hlsl.precedence2.frag", "PixelShaderFunction"},
{"hlsl.scope.frag", "PixelShaderFunction"},
{"hlsl.sin.frag", "PixelShaderFunction"}, {"hlsl.sin.frag", "PixelShaderFunction"},
{"hlsl.whileLoop.frag", "PixelShaderFunction"}, {"hlsl.whileLoop.frag", "PixelShaderFunction"},
{"hlsl.void.frag", "PixelShaderFunction"}, {"hlsl.void.frag", "PixelShaderFunction"},

View File

@ -209,9 +209,6 @@ void HlslGrammar::acceptQualifier(TQualifier& qualifier)
// Otherwise, return false, and don't advance // Otherwise, return false, and don't advance
bool HlslGrammar::acceptType(TType& type) bool HlslGrammar::acceptType(TType& type)
{ {
if (! token.isType)
return false;
switch (peek()) { switch (peek()) {
case EHTokVoid: case EHTokVoid:
new(&type) TType(EbtVoid); new(&type) TType(EbtVoid);
@ -616,7 +613,7 @@ bool HlslGrammar::acceptFunctionDefinition(TFunction& function, TIntermNode*& no
{ {
TFunction* functionDeclarator = parseContext.handleFunctionDeclarator(token.loc, function, false /* not prototype */); TFunction* functionDeclarator = parseContext.handleFunctionDeclarator(token.loc, function, false /* not prototype */);
// This does a symbol table push // This does a pushScope()
node = parseContext.handleFunctionDefinition(token.loc, *functionDeclarator); node = parseContext.handleFunctionDefinition(token.loc, *functionDeclarator);
// compound_statement // compound_statement
@ -625,7 +622,7 @@ bool HlslGrammar::acceptFunctionDefinition(TFunction& function, TIntermNode*& no
node = intermediate.growAggregate(node, functionBody); node = intermediate.growAggregate(node, functionBody);
intermediate.setAggregateOperator(node, EOpFunction, functionDeclarator->getType(), token.loc); intermediate.setAggregateOperator(node, EOpFunction, functionDeclarator->getType(), token.loc);
node->getAsAggregate()->setName(functionDeclarator->getMangledName().c_str()); node->getAsAggregate()->setName(functionDeclarator->getMangledName().c_str());
parseContext.symbolTable.pop(nullptr); parseContext.popScope();
return true; return true;
} }
@ -882,7 +879,7 @@ bool HlslGrammar::acceptPostfixExpression(TIntermTyped*& node)
} else if (acceptIdentifier(idToken)) { } else if (acceptIdentifier(idToken)) {
// identifier or function_call name // identifier or function_call name
if (! peekTokenClass(EHTokLeftParen)) { if (! peekTokenClass(EHTokLeftParen)) {
node = parseContext.handleVariable(idToken.loc, idToken.symbol, token.string); node = parseContext.handleVariable(idToken.loc, token.string);
} else if (acceptFunctionCall(idToken, node)) { } else if (acceptFunctionCall(idToken, node)) {
// function_call (nothing else to do yet) // function_call (nothing else to do yet)
} else { } else {
@ -1072,17 +1069,17 @@ bool HlslGrammar::acceptCompoundStatement(TIntermNode*& retStatement)
bool HlslGrammar::acceptScopedStatement(TIntermNode*& statement) bool HlslGrammar::acceptScopedStatement(TIntermNode*& statement)
{ {
parseContext.pushScope(); parseContext.pushScope();
bool result = acceptNestedStatement(statement); bool result = acceptStatement(statement);
parseContext.popScope(); parseContext.popScope();
return result; return result;
} }
bool HlslGrammar::acceptNestedStatement(TIntermNode*& statement) bool HlslGrammar::acceptScopedCompoundStatement(TIntermNode*& statement)
{ {
parseContext.nestStatement(); parseContext.pushScope();
bool result = acceptStatement(statement); bool result = acceptCompoundStatement(statement);
parseContext.unnestStatement(); parseContext.popScope();
return result; return result;
} }
@ -1111,7 +1108,7 @@ bool HlslGrammar::acceptStatement(TIntermNode*& statement)
// attributed_statement // attributed_statement
switch (peek()) { switch (peek()) {
case EHTokLeftBrace: case EHTokLeftBrace:
return acceptCompoundStatement(statement); return acceptScopedCompoundStatement(statement);
case EHTokIf: case EHTokIf:
return acceptSelectionStatement(statement); return acceptSelectionStatement(statement);

View File

@ -77,6 +77,7 @@ namespace glslang {
bool acceptCompoundStatement(TIntermNode*&); bool acceptCompoundStatement(TIntermNode*&);
bool acceptStatement(TIntermNode*&); bool acceptStatement(TIntermNode*&);
bool acceptScopedStatement(TIntermNode*&); bool acceptScopedStatement(TIntermNode*&);
bool acceptScopedCompoundStatement(TIntermNode*&);
bool acceptNestedStatement(TIntermNode*&); bool acceptNestedStatement(TIntermNode*&);
void acceptAttributes(); void acceptAttributes();
bool acceptSelectionStatement(TIntermNode*&); bool acceptSelectionStatement(TIntermNode*&);

View File

@ -51,7 +51,7 @@ HlslParseContext::HlslParseContext(TSymbolTable& symbolTable, TIntermediate& int
int version, EProfile profile, int spv, int vulkan, EShLanguage language, TInfoSink& infoSink, int version, EProfile profile, int spv, int vulkan, EShLanguage language, TInfoSink& infoSink,
bool forwardCompatible, EShMessages messages) : bool forwardCompatible, EShMessages messages) :
TParseContextBase(symbolTable, interm, version, profile, spv, vulkan, language, infoSink, forwardCompatible, messages), TParseContextBase(symbolTable, interm, version, profile, spv, vulkan, language, infoSink, forwardCompatible, messages),
contextPragma(true, false), loopNestingLevel(0), structNestingLevel(0), controlFlowNestingLevel(0), statementNestingLevel(0), contextPragma(true, false), loopNestingLevel(0), structNestingLevel(0), controlFlowNestingLevel(0),
postMainReturn(false), postMainReturn(false),
limits(resources.limits), limits(resources.limits),
afterEOF(false) afterEOF(false)
@ -282,8 +282,9 @@ void C_DECL HlslParseContext::ppWarn(const TSourceLoc& loc, const char* szReason
// //
// Handle seeing a variable identifier in the grammar. // Handle seeing a variable identifier in the grammar.
// //
TIntermTyped* HlslParseContext::handleVariable(const TSourceLoc& loc, TSymbol* symbol, const TString* string) TIntermTyped* HlslParseContext::handleVariable(const TSourceLoc& loc, const TString* string)
{ {
TSymbol* symbol = symbolTable.find(*string);
TIntermTyped* node = nullptr; TIntermTyped* node = nullptr;
// Error check for requiring specific extensions present. // Error check for requiring specific extensions present.
@ -714,7 +715,7 @@ TIntermAggregate* HlslParseContext::handleFunctionDefinition(const TSourceLoc& l
// //
// New symbol table scope for body of function plus its arguments // New symbol table scope for body of function plus its arguments
// //
symbolTable.push(); pushScope();
// //
// Insert parameters into the symbol table. // Insert parameters into the symbol table.
@ -747,7 +748,6 @@ TIntermAggregate* HlslParseContext::handleFunctionDefinition(const TSourceLoc& l
} }
intermediate.setAggregateOperator(paramNodes, EOpParameters, TType(EbtVoid), loc); intermediate.setAggregateOperator(paramNodes, EOpParameters, TType(EbtVoid), loc);
loopNestingLevel = 0; loopNestingLevel = 0;
statementNestingLevel = 0;
controlFlowNestingLevel = 0; controlFlowNestingLevel = 0;
postMainReturn = false; postMainReturn = false;

View File

@ -65,7 +65,7 @@ public:
bool builtInName(const TString&); bool builtInName(const TString&);
void handlePragma(const TSourceLoc&, const TVector<TString>&); void handlePragma(const TSourceLoc&, const TVector<TString>&);
TIntermTyped* handleVariable(const TSourceLoc&, TSymbol* symbol, const TString* string); TIntermTyped* handleVariable(const TSourceLoc&, const TString* string);
TIntermTyped* handleBracketDereference(const TSourceLoc&, TIntermTyped* base, TIntermTyped* index); TIntermTyped* handleBracketDereference(const TSourceLoc&, TIntermTyped* base, TIntermTyped* index);
void checkIndex(const TSourceLoc&, const TType&, int& index); void checkIndex(const TSourceLoc&, const TType&, int& index);
@ -139,8 +139,6 @@ public:
void updateImplicitArraySize(const TSourceLoc&, TIntermNode*, int index); void updateImplicitArraySize(const TSourceLoc&, TIntermNode*, int index);
void nestStatement() { ++statementNestingLevel; }
void unnestStatement() { --statementNestingLevel; }
void nestLooping() { ++loopNestingLevel; } void nestLooping() { ++loopNestingLevel; }
void unnestLooping() { --loopNestingLevel; } void unnestLooping() { --loopNestingLevel; }
void pushScope() { symbolTable.push(); } void pushScope() { symbolTable.push(); }
@ -163,7 +161,6 @@ protected:
int loopNestingLevel; // 0 if outside all loops int loopNestingLevel; // 0 if outside all loops
int structNestingLevel; // 0 if outside blocks and structures int structNestingLevel; // 0 if outside blocks and structures
int controlFlowNestingLevel; // 0 if outside all flow control int controlFlowNestingLevel; // 0 if outside all flow control
int statementNestingLevel; // 0 if outside all flow control or compound statements
TList<TIntermSequence*> switchSequenceStack; // case, node, case, case, node, ...; ensure only one node between cases; stack of them for nesting TList<TIntermSequence*> switchSequenceStack; // case, node, case, case, node, ...; ensure only one node between cases; stack of them for nesting
TList<int> switchLevel; // the statementNestingLevel the current switch statement is at, which must match the level of its case statements TList<int> switchLevel; // the statementNestingLevel the current switch statement is at, which must match the level of its case statements
bool inEntrypoint; // if inside a function, true if the function is the entry point bool inEntrypoint; // if inside a function, true if the function is the entry point

View File

@ -314,11 +314,8 @@ void HlslScanContext::deleteKeywordMap()
// Wrapper for tokenizeClass()"] = to get everything inside the token. // Wrapper for tokenizeClass()"] = to get everything inside the token.
void HlslScanContext::tokenize(HlslToken& token) void HlslScanContext::tokenize(HlslToken& token)
{ {
token.isType = false;
EHlslTokenClass tokenClass = tokenizeClass(token); EHlslTokenClass tokenClass = tokenizeClass(token);
token.tokenClass = tokenClass; token.tokenClass = tokenClass;
if (token.isType)
afterType = true;
} }
// //
@ -338,13 +335,13 @@ EHlslTokenClass HlslScanContext::tokenizeClass(HlslToken& token)
loc = ppToken.loc; loc = ppToken.loc;
parserToken->loc = loc; parserToken->loc = loc;
switch (ppToken.token) { switch (ppToken.token) {
case ';': afterType = false; return EHTokSemicolon; case ';': return EHTokSemicolon;
case ',': afterType = false; return EHTokComma; case ',': return EHTokComma;
case ':': return EHTokColon; case ':': return EHTokColon;
case '=': afterType = false; return EHTokAssign; case '=': return EHTokAssign;
case '(': afterType = false; return EHTokLeftParen; case '(': return EHTokLeftParen;
case ')': afterType = false; return EHTokRightParen; case ')': return EHTokRightParen;
case '.': field = true; return EHTokDot; case '.': return EHTokDot;
case '!': return EHTokBang; case '!': return EHTokBang;
case '-': return EHTokDash; case '-': return EHTokDash;
case '~': return EHTokTilde; case '~': return EHTokTilde;
@ -400,7 +397,6 @@ EHlslTokenClass HlslScanContext::tokenizeClass(HlslToken& token)
case PpAtomIdentifier: case PpAtomIdentifier:
{ {
EHlslTokenClass token = tokenizeIdentifier(); EHlslTokenClass token = tokenizeIdentifier();
field = false;
return token; return token;
} }
@ -542,7 +538,6 @@ EHlslTokenClass HlslScanContext::tokenizeIdentifier()
case EHTokDouble4x2: case EHTokDouble4x2:
case EHTokDouble4x3: case EHTokDouble4x3:
case EHTokDouble4x4: case EHTokDouble4x4:
parserToken->isType = true;
return keyword; return keyword;
// texturing types // texturing types
@ -560,7 +555,6 @@ EHlslTokenClass HlslScanContext::tokenizeIdentifier()
case EHTokTexture2darray: case EHTokTexture2darray:
case EHTokTexture3d: case EHTokTexture3d:
case EHTokTextureCube: case EHTokTextureCube:
parserToken->isType = true;
return keyword; return keyword;
// variable, user type, ... // variable, user type, ...
@ -598,19 +592,6 @@ EHlslTokenClass HlslScanContext::tokenizeIdentifier()
EHlslTokenClass HlslScanContext::identifierOrType() EHlslTokenClass HlslScanContext::identifierOrType()
{ {
parserToken->string = NewPoolTString(tokenText); parserToken->string = NewPoolTString(tokenText);
if (field)
return EHTokIdentifier;
parserToken->symbol = parseContext.symbolTable.find(*parserToken->string);
if (afterType == false && parserToken->symbol) {
if (const TVariable* variable = parserToken->symbol->getAsVariable()) {
if (variable->isUserType()) {
afterType = true;
return EHTokTypeName;
}
}
}
return EHTokIdentifier; return EHTokIdentifier;
} }

View File

@ -54,10 +54,9 @@ class TPpToken;
// Everything needed to fully describe a token. // Everything needed to fully describe a token.
// //
struct HlslToken { struct HlslToken {
HlslToken() : isType(false), string(nullptr), symbol(nullptr) { loc.init(); } HlslToken() : string(nullptr) { loc.init(); }
TSourceLoc loc; // location of token in the source TSourceLoc loc; // location of token in the source
EHlslTokenClass tokenClass; // what kind of token it is EHlslTokenClass tokenClass; // what kind of token it is
bool isType; // true if the token represents a type
union { // what data the token holds union { // what data the token holds
glslang::TString *string; // for identifiers glslang::TString *string; // for identifiers
int i; // for literals int i; // for literals
@ -65,7 +64,6 @@ struct HlslToken {
bool b; bool b;
double d; double d;
}; };
glslang::TSymbol* symbol; // if a symbol table lookup was done already, this is the result
}; };
// //
@ -76,7 +74,7 @@ struct HlslToken {
class HlslScanContext { class HlslScanContext {
public: public:
HlslScanContext(TParseContextBase& parseContext, TPpContext& ppContext) HlslScanContext(TParseContextBase& parseContext, TPpContext& ppContext)
: parseContext(parseContext), ppContext(ppContext), afterType(false), field(false) { } : parseContext(parseContext), ppContext(ppContext) { }
virtual ~HlslScanContext() { } virtual ~HlslScanContext() { }
static void fillInKeywordMap(); static void fillInKeywordMap();
@ -97,8 +95,6 @@ protected:
TParseContextBase& parseContext; TParseContextBase& parseContext;
TPpContext& ppContext; TPpContext& ppContext;
bool afterType; // true if we've recognized a type, so can only be looking for an identifier
bool field; // true if we're on a field, right after a '.'
TSourceLoc loc; TSourceLoc loc;
TPpToken* ppToken; TPpToken* ppToken;
HlslToken* parserToken; HlslToken* parserToken;