HLSL: Implement proper nesting of symbol-table scopes and identifier searching.
authorJohn Kessenich <cepheus@frii.com>
Thu, 9 Jun 2016 08:02:17 +0000 (02:02 -0600)
committerJohn Kessenich <cepheus@frii.com>
Thu, 9 Jun 2016 08:03:46 +0000 (02:03 -0600)
Test/baseResults/hlsl.scope.frag.out [new file with mode: 0755]
Test/hlsl.scope.frag [new file with mode: 0644]
gtests/Hlsl.FromFile.cpp
hlsl/hlslGrammar.cpp
hlsl/hlslGrammar.h
hlsl/hlslParseHelper.cpp
hlsl/hlslParseHelper.h
hlsl/hlslScanContext.cpp
hlsl/hlslScanContext.h

diff --git a/Test/baseResults/hlsl.scope.frag.out b/Test/baseResults/hlsl.scope.frag.out
new file mode 100755 (executable)
index 0000000..274477a
--- /dev/null
@@ -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
diff --git a/Test/hlsl.scope.frag b/Test/hlsl.scope.frag
new file mode 100644 (file)
index 0000000..0d8cc1a
--- /dev/null
@@ -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);
+}
index 4a127c1..fa3442c 100644 (file)
@@ -88,6 +88,7 @@ INSTANTIATE_TEST_CASE_P(
         {"hlsl.max.frag", "PixelShaderFunction"},
         {"hlsl.precedence.frag", "PixelShaderFunction"},
         {"hlsl.precedence2.frag", "PixelShaderFunction"},
+        {"hlsl.scope.frag", "PixelShaderFunction"},
         {"hlsl.sin.frag", "PixelShaderFunction"},
         {"hlsl.whileLoop.frag", "PixelShaderFunction"},
         {"hlsl.void.frag", "PixelShaderFunction"},
index b7cb842..9ea14da 100755 (executable)
@@ -209,9 +209,6 @@ void HlslGrammar::acceptQualifier(TQualifier& qualifier)
 // Otherwise, return false, and don't advance
 bool HlslGrammar::acceptType(TType& type)
 {
-    if (! token.isType)
-        return false;
-
     switch (peek()) {
     case EHTokVoid:
         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 */);
 
-    // This does a symbol table push
+    // This does a pushScope()
     node = parseContext.handleFunctionDefinition(token.loc, *functionDeclarator);
 
     // compound_statement
@@ -625,7 +622,7 @@ bool HlslGrammar::acceptFunctionDefinition(TFunction& function, TIntermNode*& no
         node = intermediate.growAggregate(node, functionBody);
         intermediate.setAggregateOperator(node, EOpFunction, functionDeclarator->getType(), token.loc);
         node->getAsAggregate()->setName(functionDeclarator->getMangledName().c_str());
-        parseContext.symbolTable.pop(nullptr);
+        parseContext.popScope();
 
         return true;
     }
@@ -882,7 +879,7 @@ bool HlslGrammar::acceptPostfixExpression(TIntermTyped*& node)
     } else if (acceptIdentifier(idToken)) {
         // identifier or function_call name
         if (! peekTokenClass(EHTokLeftParen)) {
-            node = parseContext.handleVariable(idToken.loc, idToken.symbol, token.string);
+            node = parseContext.handleVariable(idToken.loc, token.string);
         } else if (acceptFunctionCall(idToken, node)) {
             // function_call (nothing else to do yet)
         } else {
@@ -1072,17 +1069,17 @@ bool HlslGrammar::acceptCompoundStatement(TIntermNode*& retStatement)
 bool HlslGrammar::acceptScopedStatement(TIntermNode*& statement)
 {
     parseContext.pushScope();
-    bool result = acceptNestedStatement(statement);
+    bool result = acceptStatement(statement);
     parseContext.popScope();
 
     return result;
 }
 
-bool HlslGrammar::acceptNestedStatement(TIntermNode*& statement)
+bool HlslGrammar::acceptScopedCompoundStatement(TIntermNode*& statement)
 {
-    parseContext.nestStatement();
-    bool result = acceptStatement(statement);
-    parseContext.unnestStatement();
+    parseContext.pushScope();
+    bool result = acceptCompoundStatement(statement);
+    parseContext.popScope();
 
     return result;
 }
@@ -1111,7 +1108,7 @@ bool HlslGrammar::acceptStatement(TIntermNode*& statement)
     // attributed_statement
     switch (peek()) {
     case EHTokLeftBrace:
-        return acceptCompoundStatement(statement);
+        return acceptScopedCompoundStatement(statement);
 
     case EHTokIf:
         return acceptSelectionStatement(statement);
index 69535f3..ba92c92 100755 (executable)
@@ -77,6 +77,7 @@ namespace glslang {
         bool acceptCompoundStatement(TIntermNode*&);
         bool acceptStatement(TIntermNode*&);
         bool acceptScopedStatement(TIntermNode*&);
+        bool acceptScopedCompoundStatement(TIntermNode*&);
         bool acceptNestedStatement(TIntermNode*&);
         void acceptAttributes();
         bool acceptSelectionStatement(TIntermNode*&);
index 2cdaf0c..e5c1564 100755 (executable)
@@ -51,7 +51,7 @@ HlslParseContext::HlslParseContext(TSymbolTable& symbolTable, TIntermediate& int
                                    int version, EProfile profile, int spv, int vulkan, EShLanguage language, TInfoSink& infoSink,
                                    bool forwardCompatible, EShMessages 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),
     limits(resources.limits),
     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.
 //
-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;
 
     // 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
     //
-    symbolTable.push();
+    pushScope();
 
     //
     // Insert parameters into the symbol table.
@@ -747,7 +748,6 @@ TIntermAggregate* HlslParseContext::handleFunctionDefinition(const TSourceLoc& l
     }
     intermediate.setAggregateOperator(paramNodes, EOpParameters, TType(EbtVoid), loc);
     loopNestingLevel = 0;
-    statementNestingLevel = 0;
     controlFlowNestingLevel = 0;
     postMainReturn = false;
 
index 6f920d8..e1fbbf8 100755 (executable)
@@ -65,7 +65,7 @@ public:
     bool builtInName(const 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);
     void checkIndex(const TSourceLoc&, const TType&, int& index);
 
@@ -139,8 +139,6 @@ public:
 
     void updateImplicitArraySize(const TSourceLoc&, TIntermNode*, int index);
 
-    void nestStatement()   { ++statementNestingLevel; }
-    void unnestStatement() { --statementNestingLevel; }
     void nestLooping()     { ++loopNestingLevel; }
     void unnestLooping()   { --loopNestingLevel; }
     void pushScope()       { symbolTable.push(); }
@@ -163,7 +161,6 @@ protected:
     int loopNestingLevel;        // 0 if outside all loops
     int structNestingLevel;      // 0 if outside blocks and structures
     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<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
index 38e765a..dc470ff 100755 (executable)
@@ -314,11 +314,8 @@ void HlslScanContext::deleteKeywordMap()
 // Wrapper for tokenizeClass()"] =  to get everything inside the token.
 void HlslScanContext::tokenize(HlslToken& token)
 {
-    token.isType = false;
     EHlslTokenClass tokenClass = tokenizeClass(token);
     token.tokenClass = tokenClass;
-    if (token.isType)
-        afterType = true;
 }
 
 //
@@ -338,13 +335,13 @@ EHlslTokenClass HlslScanContext::tokenizeClass(HlslToken& token)
         loc = ppToken.loc;
         parserToken->loc = loc;
         switch (ppToken.token) {
-        case ';':  afterType = false;   return EHTokSemicolon;
-        case ',':  afterType = false;   return EHTokComma;
+        case ';':                       return EHTokSemicolon;
+        case ',':                       return EHTokComma;
         case ':':                       return EHTokColon;
-        case '=':  afterType = false;   return EHTokAssign;
-        case '(':  afterType = false;   return EHTokLeftParen;
-        case ')':  afterType = false;   return EHTokRightParen;
-        case '.':  field = true;        return EHTokDot;
+        case '=':                       return EHTokAssign;
+        case '(':                       return EHTokLeftParen;
+        case ')':                       return EHTokRightParen;
+        case '.':                       return EHTokDot;
         case '!':                       return EHTokBang;
         case '-':                       return EHTokDash;
         case '~':                       return EHTokTilde;
@@ -400,7 +397,6 @@ EHlslTokenClass HlslScanContext::tokenizeClass(HlslToken& token)
         case PpAtomIdentifier:
         {
             EHlslTokenClass token = tokenizeIdentifier();
-            field = false;
             return token;
         }
 
@@ -542,7 +538,6 @@ EHlslTokenClass HlslScanContext::tokenizeIdentifier()
     case EHTokDouble4x2:
     case EHTokDouble4x3:
     case EHTokDouble4x4:
-        parserToken->isType = true;
         return keyword;
 
     // texturing types
@@ -560,7 +555,6 @@ EHlslTokenClass HlslScanContext::tokenizeIdentifier()
     case EHTokTexture2darray:
     case EHTokTexture3d:
     case EHTokTextureCube:
-        parserToken->isType = true;
         return keyword;
 
     // variable, user type, ...
@@ -598,19 +592,6 @@ EHlslTokenClass HlslScanContext::tokenizeIdentifier()
 EHlslTokenClass HlslScanContext::identifierOrType()
 {
     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;
 }
index d761e3a..75c01a9 100755 (executable)
@@ -54,10 +54,9 @@ class TPpToken;
 // Everything needed to fully describe a token.
 //
 struct HlslToken {
-    HlslToken() : isType(false), string(nullptr), symbol(nullptr) { loc.init(); }
+    HlslToken() : string(nullptr) { loc.init(); }
     TSourceLoc loc;                // location of token in the source
     EHlslTokenClass tokenClass;    // what kind of token it is
-    bool isType;                   // true if the token represents a type
     union {                        // what data the token holds
         glslang::TString *string;  // for identifiers
         int i;                     // for literals
@@ -65,7 +64,6 @@ struct HlslToken {
         bool b;
         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 {
 public:
     HlslScanContext(TParseContextBase& parseContext, TPpContext& ppContext)
-        : parseContext(parseContext), ppContext(ppContext), afterType(false), field(false) { }
+        : parseContext(parseContext), ppContext(ppContext) { }
     virtual ~HlslScanContext() { }
 
     static void fillInKeywordMap();
@@ -97,8 +95,6 @@ protected:
 
     TParseContextBase& parseContext;
     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;
     TPpToken* ppToken;
     HlslToken* parserToken;