OSDN Git Service

Handle constant expressions that have not been constant folded.
authorNicolas Capens <capn@google.com>
Sun, 10 Apr 2016 04:30:02 +0000 (00:30 -0400)
committerNicolas Capens <capn@google.com>
Mon, 11 Apr 2016 14:25:00 +0000 (14:25 +0000)
Change-Id: I7dd1e6db9a4cee64cb10fb27373d77038b2af63e
Reviewed-on: https://swiftshader-review.googlesource.com/5078
Tested-by: Nicolas Capens <capn@google.com>
Reviewed-by: Alexis Hétu <sugoi@google.com>
Reviewed-by: Nicolas Capens <capn@google.com>
src/OpenGL/compiler/Intermediate.cpp
src/OpenGL/compiler/OutputASM.cpp
src/OpenGL/compiler/ParseHelper.cpp
src/OpenGL/compiler/ParseHelper.h
src/OpenGL/compiler/SymbolTable.h
src/OpenGL/compiler/glslang.y
src/OpenGL/compiler/glslang_tab.cpp
src/OpenGL/compiler/intermediate.h

index 7692081..bc79a68 100644 (file)
@@ -1624,7 +1624,6 @@ TIntermTyped* TIntermConstantUnion::fold(TOperator op, TIntermTyped* constantNod
                 return tempNode;
 
             default:
-                infoSink.info.message(EPrefixInternalError, "Invalid operator for constant folding", getLine());
                 return 0;
         }
         tempNode = new TIntermConstantUnion(tempConstArray, returnType);
index 568fc8e..6fed93f 100644 (file)
@@ -2132,7 +2132,7 @@ namespace glsl
                        parameter.type = registerType(arg);\r
                        parameter.bufferIndex = argumentInfo.bufferIndex;\r
 \r
-                       if(arg->getQualifier() == EvqConstExpr)\r
+                       if(arg->getAsConstantUnion() && arg->getAsConstantUnion()->getUnionArrayPointer())\r
                        {\r
                                int component = componentCount(type, argumentInfo.clampedIndex);\r
                                ConstantUnion *constants = arg->getAsConstantUnion()->getUnionArrayPointer();\r
@@ -2459,6 +2459,11 @@ namespace glsl
                        outputQualifier = qualifier;\r
                }\r
 \r
+               if(qualifier == EvqConstExpr && (!operand->getAsConstantUnion() || !operand->getAsConstantUnion()->getUnionArrayPointer()))\r
+               {\r
+                       return sw::Shader::PARAMETER_TEMP;\r
+               }\r
+\r
                switch(qualifier)\r
                {\r
                case EvqTemporary:           return sw::Shader::PARAMETER_TEMP;\r
@@ -2510,7 +2515,7 @@ namespace glsl
                {\r
                case EvqTemporary:           return temporaryRegister(operand);\r
                case EvqGlobal:              return temporaryRegister(operand);\r
-               case EvqConstExpr:           UNREACHABLE(EvqConstExpr);\r
+               case EvqConstExpr:           return temporaryRegister(operand);   // Unevaluated constant expression\r
                case EvqAttribute:           return attributeRegister(operand);\r
                case EvqVaryingIn:           return varyingRegister(operand);\r
                case EvqVaryingOut:          return varyingRegister(operand);\r
index eb41738..d8efe5d 100644 (file)
@@ -228,7 +228,7 @@ void TParseContext::unaryOpError(const TSourceLoc &line, const char* op, TString
 void TParseContext::binaryOpError(const TSourceLoc &line, const char* op, TString left, TString right)
 {
     std::stringstream extraInfoStream;
-    extraInfoStream << "no operation '" << op << "' exists that takes a left-hand operand of type '" << left 
+    extraInfoStream << "no operation '" << op << "' exists that takes a left-hand operand of type '" << left
                     << "' and a right operand of type '" << right << "' (or there is no acceptable conversion)";
     std::string extraInfo = extraInfoStream.str();
     error(line, " wrong operand types ", op, extraInfo.c_str());
@@ -1191,11 +1191,12 @@ bool TParseContext::executeInitializer(const TSourceLoc& line, const TString& id
        ASSERT(intermNode != nullptr);
        TType type = TType(pType);
 
-       TVariable *variable = nullptr;
        if(type.isArray() && (type.getArraySize() == 0))
        {
                type.setArraySize(initializer->getArraySize());
        }
+
+       TVariable *variable = nullptr;
        if(!declareVariable(line, identifier, type, &variable))
        {
                return true;
@@ -1218,7 +1219,7 @@ bool TParseContext::executeInitializer(const TSourceLoc& line, const TString& id
     //
     // identifier must be of type constant, a global, or a temporary
     //
-    TQualifier qualifier = variable->getType().getQualifier();
+    TQualifier qualifier = type.getQualifier();
     if ((qualifier != EvqTemporary) && (qualifier != EvqGlobal) && (qualifier != EvqConstExpr)) {
         error(line, " cannot initialize this type of qualifier ", variable->getType().getQualifierString());
         return true;
@@ -1228,7 +1229,7 @@ bool TParseContext::executeInitializer(const TSourceLoc& line, const TString& id
     //
 
     if (qualifier == EvqConstExpr) {
-        if (qualifier != initializer->getType().getQualifier()) {
+        if (qualifier != initializer->getQualifier()) {
             std::stringstream extraInfoStream;
             extraInfoStream << "'" << variable->getType().getCompleteString() << "'";
             std::string extraInfo = extraInfoStream.str();
@@ -1236,12 +1237,14 @@ bool TParseContext::executeInitializer(const TSourceLoc& line, const TString& id
             variable->getType().setQualifier(EvqTemporary);
             return true;
         }
+
         if (type != initializer->getType()) {
             error(line, " non-matching types for const initializer ",
                 variable->getType().getQualifierString());
             variable->getType().setQualifier(EvqTemporary);
             return true;
         }
+
         if (initializer->getAsConstantUnion()) {
             variable->shareConstPointer(initializer->getAsConstantUnion()->getUnionArrayPointer());
         } else if (initializer->getAsSymbolNode()) {
@@ -1250,17 +1253,10 @@ bool TParseContext::executeInitializer(const TSourceLoc& line, const TString& id
 
             ConstantUnion* constArray = tVar->getConstPointer();
             variable->shareConstPointer(constArray);
-        } else {
-            std::stringstream extraInfoStream;
-            extraInfoStream << "'" << variable->getType().getCompleteString() << "'";
-            std::string extraInfo = extraInfoStream.str();
-            error(line, " cannot assign to", "=", extraInfo.c_str());
-            variable->getType().setQualifier(EvqTemporary);
-            return true;
         }
     }
 
-    if (qualifier != EvqConstExpr) {
+    if (!variable->isConstant()) {
         TIntermSymbol* intermSymbol = intermediate.addSymbol(variable->getUniqueId(), variable->getName(), variable->getType(), line);
         *intermNode = createAssign(EOpInitialize, intermSymbol, initializer, line);
         if(*intermNode == nullptr) {
@@ -1273,25 +1269,6 @@ bool TParseContext::executeInitializer(const TSourceLoc& line, const TString& id
     return false;
 }
 
-bool TParseContext::areAllChildConst(TIntermAggregate* aggrNode)
-{
-    ASSERT(aggrNode != NULL);
-    if (!aggrNode->isConstructor())
-        return false;
-
-    bool allConstant = true;
-
-    // check if all the child nodes are constants so that they can be inserted into
-    // the parent node
-    TIntermSequence &sequence = aggrNode->getSequence() ;
-    for (TIntermSequence::iterator p = sequence.begin(); p != sequence.end(); ++p) {
-        if (!(*p)->getAsTyped()->getAsConstantUnion())
-            return false;
-    }
-
-    return allConstant;
-}
-
 TPublicType TParseContext::addFullySpecifiedType(TQualifier qualifier, bool invariant, TLayoutQualifier layoutQualifier, const TPublicType &typeSpecifier)
 {
        TPublicType returnType = typeSpecifier;
@@ -1818,12 +1795,12 @@ TIntermAggregate *TParseContext::addFunctionDefinition(const TFunction &function
        aggregate->setName(function.getMangledName().c_str());
        aggregate->setType(function.getReturnType());
 
-       // store the pragma information for debug and optimize and other vendor specific\r
-       // information. This information can be queried from the parse tree\r
-       aggregate->setOptimize(pragma().optimize);\r
+       // store the pragma information for debug and optimize and other vendor specific
+       // information. This information can be queried from the parse tree
+       aggregate->setOptimize(pragma().optimize);
        aggregate->setDebug(pragma().debug);
 
-       if(functionBody && functionBody->getAsAggregate())\r
+       if(functionBody && functionBody->getAsAggregate())
                aggregate->setEndLine(functionBody->getAsAggregate()->getEndLine());
 
        symbolTable.pop();
@@ -2117,8 +2094,8 @@ TIntermTyped* TParseContext::addConstructor(TIntermNode* arguments, const TType*
     }
 
     // Turn the argument list itself into a constructor
-    TIntermTyped *constructor = intermediate.setAggregateOperator(aggregateArguments, op, line);
-    TIntermTyped *constConstructor = foldConstConstructor(constructor->getAsAggregate(), *type);
+    TIntermAggregate *constructor = intermediate.setAggregateOperator(aggregateArguments, op, line);
+    TIntermTyped *constConstructor = foldConstConstructor(constructor, *type);
     if(constConstructor)
     {
         return constConstructor;
@@ -2129,9 +2106,8 @@ TIntermTyped* TParseContext::addConstructor(TIntermNode* arguments, const TType*
 
 TIntermTyped* TParseContext::foldConstConstructor(TIntermAggregate* aggrNode, const TType& type)
 {
-    bool canBeFolded = areAllChildConst(aggrNode);
     aggrNode->setType(type);
-    if (canBeFolded) {
+    if (aggrNode->isConstantFoldable()) {
         bool returnVal = false;
         ConstantUnion* unionArray = new ConstantUnion[type.getObjectSize()];
         if (aggrNode->getSequence().size() == 1)  {
@@ -2153,7 +2129,7 @@ TIntermTyped* TParseContext::foldConstConstructor(TIntermAggregate* aggrNode, co
 // This function returns the tree representation for the vector field(s) being accessed from contant vector.
 // If only one component of vector is accessed (v.x or v[0] where v is a contant vector), then a contant node is
 // returned, else an aggregate node is returned (for v.xy). The input to this function could either be the symbol
-// node or it could be the intermediate tree representation of accessing fields in a constant structure or column of 
+// node or it could be the intermediate tree representation of accessing fields in a constant structure or column of
 // a constant matrix.
 //
 TIntermTyped* TParseContext::addConstVectorNode(TVectorFields& fields, TIntermTyped* node, const TSourceLoc &line)
@@ -2625,7 +2601,7 @@ TIntermTyped *TParseContext::addFieldSelectionExpression(TIntermTyped *baseExpre
                        recover();
                }
 
-               if(baseExpression->getType().getQualifier() == EvqConstExpr)
+               if(baseExpression->getAsConstantUnion())
                {
                        // constant folding for vector fields
                        indexedExpression = addConstVectorNode(fields, baseExpression, fieldLocation);
index b610339..d6b08b3 100644 (file)
@@ -143,7 +143,6 @@ public:
     void handlePragmaDirective(const TSourceLoc &line, const char* name, const char* value);
 
     bool containsSampler(TType& type);
-    bool areAllChildConst(TIntermAggregate* aggrNode);
     const TFunction* findFunction(const TSourceLoc &line, TFunction* pfnCall, bool *builtIn = 0);
     bool executeInitializer(const TSourceLoc &line, const TString &identifier, const TPublicType &pType,
                             TIntermTyped *initializer, TIntermNode **intermNode);
index 53b926f..153e814 100644 (file)
@@ -95,6 +95,7 @@ public:
     }
 
     ConstantUnion* getConstPointer() const { return unionArray; }
+       bool isConstant() const { return unionArray != nullptr; }
 
     void shareConstPointer( ConstantUnion *constArray)
     {
index f6b416e..3030144 100644 (file)
@@ -217,8 +217,8 @@ variable_identifier
         // don't delete $1.string, it's used by error recovery, and the pool
         // pop will reclaim the memory
 
-        if (variable->getType().getQualifier() == EvqConstExpr ) {
-            ConstantUnion* constArray = variable->getConstPointer();
+        ConstantUnion *constArray = variable->getConstPointer();
+        if (constArray) {
             TType t(variable->getType());
             $$ = context->intermediate.addConstantUnion(constArray, t, @1);
         } else
@@ -686,7 +686,7 @@ function_header
         TType type($1);
         function = new TFunction($2.string, type);
         $$ = function;
-        
+
         context->symbolTable.push();
     }
     ;
@@ -914,7 +914,7 @@ type_qualifier
     | interpolation_qualifier {
         context->error(@1, "interpolation qualifier requires a fragment 'in' or vertex 'out' storage qualifier", getQualifierString($1.qualifier));
         context->recover();
-        
+
         TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
         $$.setBasic(EbtVoid, qual, @1);
     }
index f5a0fae..2e23afe 100644 (file)
@@ -2365,8 +2365,8 @@ yyreduce:
         // don't delete $1.string, it's used by error recovery, and the pool
         // pop will reclaim the memory
 
-        if (variable->getType().getQualifier() == EvqConstExpr ) {
-            ConstantUnion* constArray = variable->getConstPointer();
+        ConstantUnion *constArray = variable->getConstPointer();
+        if (constArray) {
             TType t(variable->getType());
             (yyval.interm.intermTypedNode) = context->intermediate.addConstantUnion(constArray, t, (yylsp[0]));
         } else
index 8228787..337fe36 100644 (file)
@@ -8,7 +8,7 @@
 // Definition of the in-memory high-level intermediate representation
 // of shaders.  This is a tree that parser creates.
 //
-// Nodes in the tree are defined as a hierarchy of classes derived from 
+// Nodes in the tree are defined as a hierarchy of classes derived from
 // TIntermNode. Each is a node in a tree.  There is no preset branching factor;
 // each node can have it's own type of list of children.
 //
@@ -26,7 +26,7 @@
 enum TOperator {
     EOpNull,            // if in a node, should only mean a node is still being built
     EOpSequence,        // denotes a list of statements, or parameters, etc.
-    EOpFunctionCall,    
+    EOpFunctionCall,
     EOpFunction,        // For function definition
     EOpParameters,      // an aggregate listing the parameters to a function
 
@@ -306,7 +306,7 @@ public:
     TPrecision getPrecision() const { return type.getPrecision(); }
     int getNominalSize() const { return type.getNominalSize(); }
        int getSecondarySize() const { return type.getSecondarySize(); }
-    
+
        bool isInterfaceBlock() const { return type.isInterfaceBlock(); }
     bool isMatrix() const { return type.isMatrix(); }
     bool isArray()  const { return type.isArray(); }
@@ -400,14 +400,14 @@ public:
     // if symbol is initialized as symbol(sym), the memory comes from the poolallocator of sym. If sym comes from
     // per process globalpoolallocator, then it causes increased memory usage per compile
     // it is essential to use "symbol = sym" to assign to symbol
-    TIntermSymbol(int i, const TString& sym, const TType& t) : 
-            TIntermTyped(t), id(i)  { symbol = sym; } 
+    TIntermSymbol(int i, const TString& sym, const TType& t) :
+            TIntermTyped(t), id(i)  { symbol = sym; }
 
     int getId() const { return id; }
     const TString& getSymbol() const { return symbol; }
 
     void setId(int newId) { id = newId; }
-    
+
     virtual void traverse(TIntermTraverser*);
     virtual TIntermSymbol* getAsSymbolNode() { return this; }
 
@@ -418,10 +418,13 @@ protected:
 
 class TIntermConstantUnion : public TIntermTyped {
 public:
-    TIntermConstantUnion(ConstantUnion *unionPointer, const TType& t) : TIntermTyped(t), unionArrayPointer(unionPointer) { }
+    TIntermConstantUnion(ConstantUnion *unionPointer, const TType& t) : TIntermTyped(t), unionArrayPointer(unionPointer)
+       {
+               getTypePointer()->setQualifier(EvqConstExpr);
+       }
 
     ConstantUnion* getUnionArrayPointer() const { return unionArrayPointer; }
-    
+
     int getIConst(int index) const { return unionArrayPointer ? unionArrayPointer[index].getIConst() : 0; }
     int getUConst(int index) const { return unionArrayPointer ? unionArrayPointer[index].getUConst() : 0; }
     float getFConst(int index) const { return unionArrayPointer ? unionArrayPointer[index].getFConst() : 0.0f; }
@@ -452,7 +455,7 @@ public:
 
 protected:
     TIntermOperator(TOperator o) : TIntermTyped(TType(EbtFloat, EbpUndefined)), op(o) {}
-    TIntermOperator(TOperator o, TType& t) : TIntermTyped(t), op(o) {}   
+    TIntermOperator(TOperator o, TType& t) : TIntermTyped(t), op(o) {}
     TOperator op;
 };
 
@@ -489,7 +492,7 @@ public:
     virtual TIntermUnary* getAsUnaryNode() { return this; }
 
     void setOperand(TIntermTyped* o) { operand = o; }
-    TIntermTyped* getOperand() { return operand; }    
+    TIntermTyped* getOperand() { return operand; }
     bool promote(TInfoSink&);
 
 protected:
@@ -527,6 +530,19 @@ public:
     void setEndLine(const TSourceLoc& line) { endLine = line; }
     const TSourceLoc& getEndLine() const { return endLine; }
 
+       bool isConstantFoldable()
+       {
+               for(TIntermNode *node : sequence)
+               {
+                       if(!node->getAsConstantUnion() || !node->getAsConstantUnion()->getUnionArrayPointer())
+                       {
+                               return false;
+                       }
+               }
+
+               return true;
+       }
+
 protected:
     TIntermAggregate(const TIntermAggregate&); // disallow copy constructor
     TIntermAggregate& operator=(const TIntermAggregate&); // disallow assignment operator
@@ -617,7 +633,7 @@ enum Visit
 };
 
 //
-// For traversing the tree.  User should derive from this, 
+// For traversing the tree.  User should derive from this,
 // put their traversal specific data in it, and then pass
 // it to a Traverse method.
 //
@@ -628,7 +644,7 @@ class TIntermTraverser
 {
 public:
     POOL_ALLOCATOR_NEW_DELETE();
-    TIntermTraverser(bool preVisit = true, bool inVisit = false, bool postVisit = false, bool rightToLeft = false) : 
+    TIntermTraverser(bool preVisit = true, bool inVisit = false, bool postVisit = false, bool rightToLeft = false) :
             preVisit(preVisit),
             inVisit(inVisit),
             postVisit(postVisit),