Implement proper handling of constants

Previously we had only supported simple integer constants, as that was
enough to parse array declarations etc. Fully implement constants,
including large null objects, and constant composites constructed out
of other constants.

Bug: b/124934655
Change-Id: Ia1087f62a2bd75a3ca2f784ea24b0b3f01984ad9
Reviewed-on: https://swiftshader-review.googlesource.com/c/25148
Tested-by: Chris Forbes <chrisforbes@google.com>
Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
diff --git a/src/Pipeline/SpirvShader.cpp b/src/Pipeline/SpirvShader.cpp
index 7326dc4..6f894fc 100644
--- a/src/Pipeline/SpirvShader.cpp
+++ b/src/Pipeline/SpirvShader.cpp
@@ -177,17 +177,34 @@
 			}
 
 			case spv::OpConstant:
-			case spv::OpConstantComposite:
+				CreateConstant(insn).constantValue[0] = insn.word(3);
+				break;
 			case spv::OpConstantFalse:
+				CreateConstant(insn).constantValue[0] = 0;		// represent boolean false as zero
+				break;
 			case spv::OpConstantTrue:
+				CreateConstant(insn).constantValue[0] = ~0u;	// represent boolean true as all bits set
+				break;
 			case spv::OpConstantNull:
 			{
-				auto typeId = insn.word(1);
-				auto resultId = insn.word(2);
-				auto &object = defs[resultId];
-				object.kind = Object::Kind::Constant;
-				object.definition = insn;
-				object.sizeInComponents = getType(typeId).sizeInComponents;
+				// OpConstantNull forms a constant of arbitrary type, all zeros.
+				auto & object = CreateConstant(insn);
+				for (auto i = 0u; i < object.sizeInComponents; i++)
+				{
+					object.constantValue[i] = 0;
+				}
+				break;
+			}
+			case spv::OpConstantComposite:
+			{
+				auto &object = CreateConstant(insn);
+				auto offset = 0u;
+				for (auto i = 0u; i < insn.wordCount() - 3; i++)
+				{
+					auto & constituent = getObject(insn.word(i + 3));
+					for (auto j = 0u; j < constituent.sizeInComponents; j++)
+						object.constantValue[offset++] = constituent.constantValue[j];
+				}
 				break;
 			}
 
@@ -254,6 +271,18 @@
 		}
 	}
 
+	SpirvShader::Object& SpirvShader::CreateConstant(InsnIterator insn)
+	{
+		auto typeId = insn.word(1);
+		auto resultId = insn.word(2);
+		auto &object = defs[resultId];
+		object.kind = Object::Kind::Constant;
+		object.definition = insn;
+		object.sizeInComponents = getType(typeId).sizeInComponents;
+		object.constantValue = std::unique_ptr<uint32_t[]>(new uint32_t[object.sizeInComponents]);
+		return object;
+	}
+
 	void SpirvShader::ProcessInterfaceVariable(Object &object)
 	{
 		assert(object.storageClass == spv::StorageClassInput || object.storageClass == spv::StorageClassOutput);
@@ -764,27 +793,57 @@
 				}
 
 				SpirvRoutine::Value& ptrBase = routine->getValue(pointer.pointerBase);
-				auto & src = routine->getIntermediate(insn.word(2));;
 
-				if (pointer.kind == Object::Kind::Value)
+				if (object.kind == Object::Kind::Constant)
 				{
-					auto offsets = As<Int4>(routine->getIntermediate(insn.word(1))[0]);
-					for (auto i = 0u; i < object.sizeInComponents; i++)
+					auto src = reinterpret_cast<float *>(object.constantValue.get());
+
+					if (pointer.kind == Object::Kind::Value)
 					{
-						// Scattered store
-						for (int j = 0; j < 4; j++)
+						auto offsets = As<Int4>(routine->getIntermediate(insn.word(1))[0]);
+						for (auto i = 0u; i < object.sizeInComponents; i++)
 						{
-							auto dst = ptrBase[Int(i) + Extract(offsets, j)];
-							dst = Insert(dst, Extract(src[i], j), j);
+							// Scattered store
+							for (int j = 0; j < 4; j++)
+							{
+								auto dst = ptrBase[Int(i) + Extract(offsets, j)];
+								dst = Insert(dst, Float(src[i]), j);
+							}
+						}
+					}
+					else
+					{
+						// no divergent offsets
+						for (auto i = 0u; i < object.sizeInComponents; i++)
+						{
+							ptrBase[i] = RValue<Float4>(src[i]);
 						}
 					}
 				}
 				else
 				{
-					// no divergent offsets
-					for (auto i = 0u; i < object.sizeInComponents; i++)
+					auto &src = routine->getIntermediate(insn.word(2));
+
+					if (pointer.kind == Object::Kind::Value)
 					{
-						ptrBase[i] = src[i];
+						auto offsets = As<Int4>(routine->getIntermediate(insn.word(1))[0]);
+						for (auto i = 0u; i < object.sizeInComponents; i++)
+						{
+							// Scattered store
+							for (int j = 0; j < 4; j++)
+							{
+								auto dst = ptrBase[Int(i) + Extract(offsets, j)];
+								dst = Insert(dst, Extract(src[i], j), j);
+							}
+						}
+					}
+					else
+					{
+						// no divergent offsets
+						for (auto i = 0u; i < object.sizeInComponents; i++)
+						{
+							ptrBase[i] = src[i];
+						}
 					}
 				}
 				break;
diff --git a/src/Pipeline/SpirvShader.hpp b/src/Pipeline/SpirvShader.hpp
index 173465d..1256a47 100644
--- a/src/Pipeline/SpirvShader.hpp
+++ b/src/Pipeline/SpirvShader.hpp
@@ -206,6 +206,7 @@
 			uint32_t sizeInComponents = 0;
 			bool isBuiltInBlock = false;
 			uint32_t pointerBase = 0;
+			std::unique_ptr<uint32_t[]> constantValue = nullptr;
 
 			enum class Kind
 			{
@@ -355,6 +356,7 @@
 		void VisitInterface(uint32_t id, F f) const;
 
 		uint32_t GetConstantInt(uint32_t id) const;
+		Object& CreateConstant(InsnIterator it);
 
 		void ProcessInterfaceVariable(Object &object);