Refactor lvalue() to return the root node.

This will enable reusing it to determine the root node of rvalues as
well. The only functional change is that struct indexing no longer
overrides the register type. This is of no effect here since lvalue
intermediates already inherited their type from the root node, but for
rvalues the intermediates are considered temporary registers, while
instead the root's type should be used.

Change-Id: I2dbd1b0f8886c3f111a2ed3ef7fe4e9a5b480085
Reviewed-on: https://swiftshader-review.googlesource.com/13930
Tested-by: Nicolas Capens <nicolascapens@google.com>
Reviewed-by: Alexis Hétu <sugoi@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
diff --git a/src/OpenGL/compiler/OutputASM.cpp b/src/OpenGL/compiler/OutputASM.cpp
index 56fde3d..d3a0184 100644
--- a/src/OpenGL/compiler/OutputASM.cpp
+++ b/src/OpenGL/compiler/OutputASM.cpp
@@ -614,7 +614,7 @@
 						if(left->totalRegisterCount() > 1)
 						{
 							sw::Shader::SourceParameter relativeRegister;
-							argument(relativeRegister, right);
+							source(relativeRegister, right);
 
 							mov->src[0].rel.type = relativeRegister.type;
 							mov->src[0].rel.index = relativeRegister.index;
@@ -1887,9 +1887,7 @@
 
 		if(dst)
 		{
-			instruction->dst.type = registerType(dst);
-			instruction->dst.index = registerIndex(dst) + dstIndex;
-			instruction->dst.mask = writeMask(dst);
+			destination(instruction->dst, dst, dstIndex);
 		}
 
 		if(src0)
@@ -1898,11 +1896,11 @@
 			instruction->dst.partialPrecision = src && (src->getPrecision() <= EbpLow);
 		}
 
-		argument(instruction->src[0], src0, index0);
-		argument(instruction->src[1], src1, index1);
-		argument(instruction->src[2], src2, index2);
-		argument(instruction->src[3], src3, index3);
-		argument(instruction->src[4], src4, index4);
+		source(instruction->src[0], src0, index0);
+		source(instruction->src[1], src1, index1);
+		source(instruction->src[2], src2, index2);
+		source(instruction->src[3], src3, index3);
+		source(instruction->src[4], src4, index4);
 
 		shader->append(instruction);
 
@@ -2176,7 +2174,7 @@
 		return argumentInfo;
 	}
 
-	void OutputASM::argument(sw::Shader::SourceParameter &parameter, TIntermNode *argument, int index)
+	void OutputASM::source(sw::Shader::SourceParameter &parameter, TIntermNode *argument, int index)
 	{
 		if(argument)
 		{
@@ -2286,6 +2284,13 @@
 		}
 	}
 
+	void OutputASM::destination(sw::Shader::DestinationParameter &parameter, TIntermTyped *arg, int index)
+	{
+		parameter.type = registerType(arg);
+		parameter.index = registerIndex(arg) + index;
+		parameter.mask = writeMask(arg);
+	}
+
 	void OutputASM::copy(TIntermTyped *dst, TIntermNode *src, int offset)
 	{
 		for(int index = 0; index < dst->totalRegisterCount(); index++)
@@ -2328,8 +2333,8 @@
 			insert->src[0].type = insert->dst.type;
 			insert->src[0].index = insert->dst.index;
 			insert->src[0].rel = insert->dst.rel;
-			argument(insert->src[1], src);
-			argument(insert->src[2], binary->getRight());
+			source(insert->src[1], src);
+			source(insert->src[2], binary->getRight());
 
 			shader->append(insert);
 		}
@@ -2340,7 +2345,7 @@
 			Temporary address(this);
 			int swizzle = lvalue(mov1->dst, address, dst);
 
-			argument(mov1->src[0], src);
+			source(mov1->src[0], src);
 			mov1->src[0].swizzle = swizzleSwizzle(mov1->src[0].swizzle, swizzle);
 
 			shader->append(mov1);
@@ -2353,7 +2358,7 @@
 				mov->dst.index += offset;
 				mov->dst.mask = writeMask(dst, offset);
 
-				argument(mov->src[0], src, offset);
+				source(mov->src[0], src, offset);
 
 				shader->append(mov);
 			}
@@ -2362,6 +2367,20 @@
 
 	int OutputASM::lvalue(sw::Shader::DestinationParameter &dst, Temporary &address, TIntermTyped *node)
 	{
+		TIntermTyped *root = nullptr;
+		unsigned int offset = 0;
+		unsigned char mask = 0xF;
+		int swizzle = lvalue(root, offset, dst.rel, mask, address, node);
+
+		dst.type = registerType(root);
+		dst.index = registerIndex(root) + offset;
+		dst.mask = mask;
+
+		return swizzle;
+	}
+
+	int OutputASM::lvalue(TIntermTyped *&root, unsigned int &offset, sw::Shader::Relative &rel, unsigned char &mask, Temporary &address, TIntermTyped *node)
+	{
 		TIntermTyped *result = node;
 		TIntermBinary *binary = node->getAsBinaryNode();
 		TIntermSymbol *symbol = node->getAsSymbolNode();
@@ -2371,7 +2390,7 @@
 			TIntermTyped *left = binary->getLeft();
 			TIntermTyped *right = binary->getRight();
 
-			int leftSwizzle = lvalue(dst, address, left);   // Resolve the l-value of the left side
+			int leftSwizzle = lvalue(root, offset, rel, mask, address, left);   // Resolve the l-value of the left side
 
 			switch(binary->getOp())
 			{
@@ -2381,22 +2400,22 @@
 
 					if(left->isRegister())
 					{
-						int leftMask = dst.mask;
+						int leftMask = mask;
 
-						dst.mask = 1;
-						while((leftMask & dst.mask) == 0)
+						mask = 1;
+						while((leftMask & mask) == 0)
 						{
-							dst.mask = dst.mask << 1;
+							mask = mask << 1;
 						}
 
 						int element = swizzleElement(leftSwizzle, rightIndex);
-						dst.mask = 1 << element;
+						mask = 1 << element;
 
 						return element;
 					}
 					else if(left->isArray() || left->isMatrix())
 					{
-						dst.index += rightIndex * result->totalRegisterCount();
+						offset += rightIndex * result->totalRegisterCount();
 						return 0xE4;
 					}
 					else UNREACHABLE(0);
@@ -2414,42 +2433,42 @@
 					{
 						int scale = result->totalRegisterCount();
 
-						if(dst.rel.type == sw::Shader::PARAMETER_VOID)   // Use the index register as the relative address directly
+						if(rel.type == sw::Shader::PARAMETER_VOID)   // Use the index register as the relative address directly
 						{
 							if(left->totalRegisterCount() > 1)
 							{
 								sw::Shader::SourceParameter relativeRegister;
-								argument(relativeRegister, right);
+								source(relativeRegister, right);
 
-								dst.rel.index = relativeRegister.index;
-								dst.rel.type = relativeRegister.type;
-								dst.rel.scale = scale;
-								dst.rel.deterministic = !(vertexShader && left->getQualifier() == EvqUniform);
+								rel.index = relativeRegister.index;
+								rel.type = relativeRegister.type;
+								rel.scale = scale;
+								rel.deterministic = !(vertexShader && left->getQualifier() == EvqUniform);
 							}
 						}
-						else if(dst.rel.index != registerIndex(&address))   // Move the previous index register to the address register
+						else if(rel.index != registerIndex(&address))   // Move the previous index register to the address register
 						{
 							if(scale == 1)
 							{
-								Constant oldScale((int)dst.rel.scale);
+								Constant oldScale((int)rel.scale);
 								Instruction *mad = emit(sw::Shader::OPCODE_IMAD, &address, &address, &oldScale, right);
-								mad->src[0].index = dst.rel.index;
-								mad->src[0].type = dst.rel.type;
+								mad->src[0].index = rel.index;
+								mad->src[0].type = rel.type;
 							}
 							else
 							{
-								Constant oldScale((int)dst.rel.scale);
+								Constant oldScale((int)rel.scale);
 								Instruction *mul = emit(sw::Shader::OPCODE_IMUL, &address, &address, &oldScale);
-								mul->src[0].index = dst.rel.index;
-								mul->src[0].type = dst.rel.type;
+								mul->src[0].index = rel.index;
+								mul->src[0].type = rel.type;
 
 								Constant newScale(scale);
 								emit(sw::Shader::OPCODE_IMAD, &address, right, &newScale, &address);
 							}
 
-							dst.rel.type = sw::Shader::PARAMETER_TEMP;
-							dst.rel.index = registerIndex(&address);
-							dst.rel.scale = 1;
+							rel.type = sw::Shader::PARAMETER_TEMP;
+							rel.index = registerIndex(&address);
+							rel.scale = 1;
 						}
 						else   // Just add the new index to the address register
 						{
@@ -2481,9 +2500,8 @@
 						fieldOffset += fields[i]->type()->totalRegisterCount();
 					}
 
-					dst.type = registerType(left);
-					dst.index += fieldOffset;
-					dst.mask = writeMask(result);
+					offset += fieldOffset;
+					mask = writeMask(result);
 
 					return 0xE4;
 				}
@@ -2492,7 +2510,7 @@
 				{
 					ASSERT(left->isRegister());
 
-					int leftMask = dst.mask;
+					int leftMask = mask;
 
 					int swizzle = 0;
 					int rightMask = 0;
@@ -2508,7 +2526,7 @@
 						swizzle = swizzle | swizzleElement(leftSwizzle, i) << (element * 2);
 					}
 
-					dst.mask = leftMask & rightMask;
+					mask = leftMask & rightMask;
 
 					return swizzle;
 				}
@@ -2520,9 +2538,20 @@
 		}
 		else if(symbol)
 		{
-			dst.type = registerType(symbol);
-			dst.index = registerIndex(symbol);
-			dst.mask = writeMask(symbol);
+			root = symbol;
+			offset = 0;
+			mask = writeMask(symbol);
+
+			return 0xE4;
+		}
+		else
+		{
+			node->traverse(this);
+
+			root = node;
+			offset = 0;
+			mask = writeMask(node);
+
 			return 0xE4;
 		}
 
@@ -2537,10 +2566,10 @@
 		}
 
 		const TQualifier qualifier = operand->getQualifier();
-		if((EvqFragColor == qualifier) || (EvqFragData == qualifier))
+		if((qualifier == EvqFragColor) || (qualifier == EvqFragData))
 		{
-			if(((EvqFragData == qualifier) && (EvqFragColor == outputQualifier)) ||
-			   ((EvqFragColor == qualifier) && (EvqFragData == outputQualifier)))
+			if(((qualifier == EvqFragData) && (outputQualifier == EvqFragColor)) ||
+			   ((qualifier == EvqFragColor) && (outputQualifier == EvqFragData)))
 			{
 				mContext.error(operand->getLine(), "static assignment to both gl_FragData and gl_FragColor", "");
 			}
diff --git a/src/OpenGL/compiler/OutputASM.h b/src/OpenGL/compiler/OutputASM.h
index f59380e..2d04e38 100644
--- a/src/OpenGL/compiler/OutputASM.h
+++ b/src/OpenGL/compiler/OutputASM.h
@@ -251,14 +251,14 @@
 		void emitShader(Scope scope);
 
 		// Visit AST nodes and output their code to the body stream
-		virtual void visitSymbol(TIntermSymbol*);
-		virtual bool visitBinary(Visit visit, TIntermBinary*);
-		virtual bool visitUnary(Visit visit, TIntermUnary*);
-		virtual bool visitSelection(Visit visit, TIntermSelection*);
-		virtual bool visitAggregate(Visit visit, TIntermAggregate*);
-		virtual bool visitLoop(Visit visit, TIntermLoop*);
-		virtual bool visitBranch(Visit visit, TIntermBranch*);
-		virtual bool visitSwitch(Visit, TIntermSwitch*);
+		void visitSymbol(TIntermSymbol*) override;
+		bool visitBinary(Visit visit, TIntermBinary*) override;
+		bool visitUnary(Visit visit, TIntermUnary*) override;
+		bool visitSelection(Visit visit, TIntermSelection*) override;
+		bool visitAggregate(Visit visit, TIntermAggregate*) override;
+		bool visitLoop(Visit visit, TIntermLoop*) override;
+		bool visitBranch(Visit visit, TIntermBranch*) override;
+		bool visitSwitch(Visit, TIntermSwitch*) override;
 
 		sw::Shader::Opcode getOpcode(sw::Shader::Opcode op, TIntermTyped *in) const;
 		Instruction *emit(sw::Shader::Opcode op, TIntermTyped *dst = 0, TIntermNode *src0 = 0, TIntermNode *src1 = 0, TIntermNode *src2 = 0, TIntermNode *src3 = 0, TIntermNode *src4 = 0);
@@ -270,10 +270,12 @@
 		void emitAssign(sw::Shader::Opcode op, TIntermTyped *result, TIntermTyped *lhs, TIntermTyped *src0, TIntermTyped *src1 = 0);
 		void emitCmp(sw::Shader::Control cmpOp, TIntermTyped *dst, TIntermNode *left, TIntermNode *right, int index = 0);
 		void emitDeterminant(TIntermTyped *result, TIntermTyped *arg, int size, int col = -1, int row = -1, int outCol = 0, int outRow = 0);
-		void argument(sw::Shader::SourceParameter &parameter, TIntermNode *argument, int index = 0);
+		void source(sw::Shader::SourceParameter &parameter, TIntermNode *argument, int index = 0);
+		void destination(sw::Shader::DestinationParameter &parameter, TIntermTyped *argument, int index = 0);
 		void copy(TIntermTyped *dst, TIntermNode *src, int offset = 0);
 		void assignLvalue(TIntermTyped *dst, TIntermTyped *src);
 		int lvalue(sw::Shader::DestinationParameter &dst, Temporary &address, TIntermTyped *node);
+		int lvalue(TIntermTyped *&root, unsigned int &offset, sw::Shader::Relative &rel, unsigned char &mask, Temporary &address, TIntermTyped *node);
 		sw::Shader::ParameterType registerType(TIntermTyped *operand);
 		bool hasFlatQualifier(TIntermTyped *operand);
 		unsigned int registerIndex(TIntermTyped *operand);
diff --git a/src/Shader/Shader.hpp b/src/Shader/Shader.hpp
index 7f89359..695f72e 100644
--- a/src/Shader/Shader.hpp
+++ b/src/Shader/Shader.hpp
@@ -396,6 +396,15 @@
 			ANALYSIS_LEAVE    = 0x00000008,
 		};
 
+		struct Relative
+		{
+			ParameterType type : 8;
+			unsigned int index;
+			unsigned int swizzle : 8;
+			unsigned int scale;
+			bool deterministic;   // Equal accross shader instances run in lockstep (e.g. unrollable loop couters)
+		};
+
 		struct Parameter
 		{
 			union
@@ -404,14 +413,7 @@
 				{
 					unsigned int index;   // For registers types
 
-					struct
-					{
-						ParameterType type : 8;
-						unsigned int index;
-						unsigned int swizzle : 8;
-						unsigned int scale;
-						bool deterministic;   // Equal accross shader instances run in lockstep (e.g. unrollable loop couters)
-					} rel;
+					Relative rel;
 				};
 
 				float value[4];       // For float constants