Handle constant expressions that have not been constant folded.

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>
diff --git a/src/OpenGL/compiler/ParseHelper.cpp b/src/OpenGL/compiler/ParseHelper.cpp
index eb41738..d8efe5d 100644
--- a/src/OpenGL/compiler/ParseHelper.cpp
+++ b/src/OpenGL/compiler/ParseHelper.cpp
@@ -228,7 +228,7 @@
 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 @@
 	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 @@
     //
     // 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 @@
     //
 
     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 @@
             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 @@
 
             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 @@
     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 @@
 	aggregate->setName(function.getMangledName().c_str());
 	aggregate->setType(function.getReturnType());
 
-	// 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);

+	// 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())

+	if(functionBody && functionBody->getAsAggregate())
 		aggregate->setEndLine(functionBody->getAsAggregate()->getEndLine());
 
 	symbolTable.pop();
@@ -2117,8 +2094,8 @@
     }
 
     // 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::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 @@
 // 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 @@
 			recover();
 		}
 
-		if(baseExpression->getType().getQualifier() == EvqConstExpr)
+		if(baseExpression->getAsConstantUnion())
 		{
 			// constant folding for vector fields
 			indexedExpression = addConstVectorNode(fields, baseExpression, fieldLocation);