Implement support for arrays of constants.

Arrays of constants can be dynamically indexed, so they can't be
propagated by value and handled as literals like other constants.
Instead we store them in the constant register file.

Change-Id: Idcee033d694b20d047c70e2d13974e5a6dce127b
Reviewed-on: https://swiftshader-review.googlesource.com/15488
Tested-by: Nicolas Capens <nicolascapens@google.com>
Reviewed-by: Alexis Hétu <sugoi@google.com>
diff --git a/src/OpenGL/compiler/OutputASM.cpp b/src/OpenGL/compiler/OutputASM.cpp
index 3d196b2..ad79503 100644
--- a/src/OpenGL/compiler/OutputASM.cpp
+++ b/src/OpenGL/compiler/OutputASM.cpp
@@ -216,12 +216,12 @@
 
 	sw::PixelShader *Shader::getPixelShader() const
 	{
-		return 0;
+		return nullptr;
 	}
 
 	sw::VertexShader *Shader::getVertexShader() const
 	{
-		return 0;
+		return nullptr;
 	}
 
 	OutputASM::TextureFunction::TextureFunction(const TString& nodeName) : method(IMPLICIT), proj(false), offset(false)
@@ -306,9 +306,9 @@
 
 	OutputASM::OutputASM(TParseContext &context, Shader *shaderObject) : TIntermTraverser(true, true, true), shaderObject(shaderObject), mContext(context)
 	{
-		shader = 0;
-		pixelShader = 0;
-		vertexShader = 0;
+		shader = nullptr;
+		pixelShader = nullptr;
+		vertexShader = nullptr;
 
 		if(shaderObject)
 		{
@@ -317,9 +317,9 @@
 			vertexShader = shaderObject->getVertexShader();
 		}
 
-		functionArray.push_back(Function(0, "main(", 0, 0));
+		functionArray.push_back(Function(0, "main(", nullptr, nullptr));
 		currentFunction = 0;
-		outputQualifier = EvqOutput; // Set outputQualifier to any value other than EvqFragColor or EvqFragData
+		outputQualifier = EvqOutput;   // Initialize outputQualifier to any value other than EvqFragColor or EvqFragData
 	}
 
 	OutputASM::~OutputASM()
@@ -514,8 +514,19 @@
 			return false;
 		case EOpInitialize:
 			assert(visit == PreVisit);
-			right->traverse(this);
-			copy(left, right);
+			// Constant arrays go into the constant register file.
+			if(leftType.getQualifier() == EvqConstExpr && leftType.isArray() && leftType.getArraySize() > 1)
+			{
+				for(int i = 0; i < left->totalRegisterCount(); i++)
+				{
+					emit(sw::Shader::OPCODE_DEF, left, i, right, i);
+				}
+			}
+			else
+			{
+				right->traverse(this);
+				copy(left, right);
+			}
 			return false;
 		case EOpMatrixTimesScalarAssign:
 			assert(visit == PreVisit);
@@ -2544,7 +2555,15 @@
 
 		if(qualifier == EvqConstExpr && (!operand->getAsConstantUnion() || !operand->getAsConstantUnion()->getUnionArrayPointer()))
 		{
-			return sw::Shader::PARAMETER_TEMP;
+			// Constant arrays are in the constant register file.
+			if(operand->isArray() && operand->getArraySize() > 1)
+			{
+				return sw::Shader::PARAMETER_CONST;
+			}
+			else
+			{
+				return sw::Shader::PARAMETER_TEMP;
+			}
 		}
 
 		switch(qualifier)
diff --git a/src/OpenGL/compiler/ParseHelper.cpp b/src/OpenGL/compiler/ParseHelper.cpp
index 0be554f..01a01b3 100644
--- a/src/OpenGL/compiler/ParseHelper.cpp
+++ b/src/OpenGL/compiler/ParseHelper.cpp
@@ -1297,15 +1297,21 @@
 		}
 	}
 
-	if (!variable->isConstant()) {
+	// Constants which aren't indexable arrays get propagated by value
+	// and thus don't need to initialize the symbol.
+	if (variable->isConstant() && !(type.isArray() && type.getArraySize() > 1))
+	{
+		*intermNode = nullptr;
+	}
+	else
+	{
 		TIntermSymbol* intermSymbol = intermediate.addSymbol(variable->getUniqueId(), variable->getName(), variable->getType(), line);
 		*intermNode = createAssign(EOpInitialize, intermSymbol, initializer, line);
 		if(*intermNode == nullptr) {
 			assignError(line, "=", intermSymbol->getCompleteString(), initializer->getCompleteString());
 			return true;
 		}
-	} else
-		*intermNode = nullptr;
+	}
 
 	return false;
 }
diff --git a/src/OpenGL/compiler/glslang.y b/src/OpenGL/compiler/glslang.y
index c7e8f28..083745e 100644
--- a/src/OpenGL/compiler/glslang.y
+++ b/src/OpenGL/compiler/glslang.y
@@ -233,8 +233,9 @@
         // don't delete $1.string, it's used by error recovery, and the pool
         // pop will reclaim the memory
 
+        // Constants which aren't indexable arrays can be propagated by value.
         ConstantUnion *constArray = variable->getConstPointer();
-        if (constArray) {
+        if (constArray && variable->getType().getArraySize() <= 1) {
             TType t(variable->getType());
             $$ = context->intermediate.addConstantUnion(constArray, t, @1);
         } else
diff --git a/src/OpenGL/compiler/glslang_tab.cpp b/src/OpenGL/compiler/glslang_tab.cpp
index ea821d3..0101b0e 100644
--- a/src/OpenGL/compiler/glslang_tab.cpp
+++ b/src/OpenGL/compiler/glslang_tab.cpp
@@ -2373,8 +2373,9 @@
         // don't delete $1.string, it's used by error recovery, and the pool
         // pop will reclaim the memory
 
+        // Constants which aren't indexable arrays can be propagated by value.
         ConstantUnion *constArray = variable->getConstPointer();
-        if (constArray) {
+        if (constArray && variable->getType().getArraySize() <= 1) {
             TType t(variable->getType());
             (yyval.interm.intermTypedNode) = context->intermediate.addConstantUnion(constArray, t, (yylsp[0]));
         } else