Only store component count in Operand

The Operand class is a low-level abstraction of rvalues and constants.
It should not carry the SPIR-V type ID. We only need the size in
components.

Bug: b/129000021
Change-Id: I6cb3ed6341b1ccf5ef759075d7410ba447617c8b
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/43693
Presubmit-Ready: Nicolas Capens <nicolascapens@google.com>
Kokoro-Result: kokoro <noreply+kokoro@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
Tested-by: Nicolas Capens <nicolascapens@google.com>
diff --git a/src/Pipeline/SpirvShader.cpp b/src/Pipeline/SpirvShader.cpp
index 159bc73..b098cb1 100644
--- a/src/Pipeline/SpirvShader.cpp
+++ b/src/Pipeline/SpirvShader.cpp
@@ -795,7 +795,7 @@
 	auto &objectTy = getType(typeId);
 	object.kind = Object::Kind::Constant;
 	object.definition = insn;
-	object.constantValue = std::unique_ptr<uint32_t[]>(new uint32_t[objectTy.componentCount]);
+	object.constantValue.resize(objectTy.componentCount);
 
 	return object;
 }
@@ -2138,7 +2138,7 @@
 	auto &type = getType(insn.resultTypeId());
 	auto &dst = state->createIntermediate(insn.resultId(), type.componentCount);
 	auto cond = Operand(this, state, insn.word(3));
-	auto condIsScalar = (getType(cond).componentCount == 1);
+	auto condIsScalar = (cond.componentCount == 1);
 	auto lhs = Operand(this, state, insn.word(4));
 	auto rhs = Operand(this, state, insn.word(5));
 
@@ -2419,11 +2419,18 @@
 	}
 }
 
-SpirvShader::Operand::Operand(SpirvShader const *shader, EmitState const *state, SpirvShader::Object::ID objId)
-    : obj(shader->getObject(objId))
-    , intermediate(obj.kind == SpirvShader::Object::Kind::Intermediate ? &state->getIntermediate(objId) : nullptr)
+SpirvShader::Operand::Operand(const SpirvShader *shader, const EmitState *state, SpirvShader::Object::ID objectId)
+    : Operand(state, shader->getObject(objectId))
 {}
 
+SpirvShader::Operand::Operand(const EmitState *state, const Object &object)
+    : constant(object.constantValue.data())
+    , intermediate(object.kind == SpirvShader::Object::Kind::Intermediate ? &state->getIntermediate(object.id()) : nullptr)
+    , componentCount(intermediate ? intermediate->componentCount : object.constantValue.size())
+{
+	ASSERT(intermediate || (object.kind == SpirvShader::Object::Kind::Constant));
+}
+
 SpirvRoutine::SpirvRoutine(vk::PipelineLayout const *pipelineLayout)
     : pipelineLayout(pipelineLayout)
 {
diff --git a/src/Pipeline/SpirvShader.hpp b/src/Pipeline/SpirvShader.hpp
index 38f866e..7fa2a55 100644
--- a/src/Pipeline/SpirvShader.hpp
+++ b/src/Pipeline/SpirvShader.hpp
@@ -72,10 +72,10 @@
 {
 public:
 	Intermediate(uint32_t componentCount)
-	    : scalar(new rr::Value *[componentCount])
-	    , componentCount(componentCount)
+	    : componentCount(componentCount)
+	    , scalar(new rr::Value *[componentCount])
 	{
-		memset(scalar, 0, sizeof(rr::Value *) * componentCount);
+		for(auto i = 0u; i < componentCount; i++) { scalar[i] = nullptr; }
 	}
 
 	~Intermediate()
@@ -119,6 +119,8 @@
 	Intermediate &operator=(Intermediate const &) = delete;
 	Intermediate &operator=(Intermediate &&) = delete;
 
+	const uint32_t componentCount;
+
 private:
 	void emplace(uint32_t i, rr::Value *value)
 	{
@@ -128,7 +130,6 @@
 	}
 
 	rr::Value **const scalar;
-	uint32_t componentCount;
 };
 
 class SpirvShader
@@ -276,7 +277,7 @@
 		Object::ID id() const { return definition.resultId(); }
 
 		InsnIterator definition;
-		std::unique_ptr<uint32_t[]> constantValue = nullptr;
+		std::vector<uint32_t> constantValue;
 
 		enum class Kind
 		{
@@ -989,11 +990,8 @@
 	// significantly different based on whether the value is uniform across lanes.
 	class Operand
 	{
-		SpirvShader::Object const &obj;
-		Intermediate const *intermediate;
-
 	public:
-		Operand(SpirvShader const *shader, EmitState const *state, SpirvShader::Object::ID objId);
+		Operand(const SpirvShader *shader, const EmitState *state, SpirvShader::Object::ID objectId);
 
 		RValue<SIMD::Float> Float(uint32_t i) const
 		{
@@ -1005,9 +1003,7 @@
 			// Constructing a constant SIMD::Float is not guaranteed to preserve the data's exact
 			// bit pattern, but SPIR-V provides 32-bit words representing "the bit pattern for the constant".
 			// Thus we must first construct an integer constant, and bitcast to float.
-			ASSERT(obj.kind == SpirvShader::Object::Kind::Constant);
-			auto constantValue = reinterpret_cast<uint32_t *>(obj.constantValue.get());
-			return As<SIMD::Float>(SIMD::UInt(constantValue[i]));
+			return As<SIMD::Float>(SIMD::UInt(constant[i]));
 		}
 
 		RValue<SIMD::Int> Int(uint32_t i) const
@@ -1016,9 +1012,8 @@
 			{
 				return intermediate->Int(i);
 			}
-			ASSERT(obj.kind == SpirvShader::Object::Kind::Constant);
-			auto constantValue = reinterpret_cast<int *>(obj.constantValue.get());
-			return SIMD::Int(constantValue[i]);
+
+			return SIMD::Int(constant[i]);
 		}
 
 		RValue<SIMD::UInt> UInt(uint32_t i) const
@@ -1027,15 +1022,19 @@
 			{
 				return intermediate->UInt(i);
 			}
-			ASSERT(obj.kind == SpirvShader::Object::Kind::Constant);
-			auto constantValue = reinterpret_cast<uint32_t *>(obj.constantValue.get());
-			return SIMD::UInt(constantValue[i]);
+
+			return SIMD::UInt(constant[i]);
 		}
 
-		Type::ID typeId() const
-		{
-			return obj.typeId();
-		}
+	private:
+		// Delegate constructor
+		Operand(const EmitState *state, const Object &object);
+
+		const uint32_t *constant;
+		const Intermediate *intermediate;
+
+	public:
+		const uint32_t componentCount;
 	};
 
 	Type const &getType(Type::ID id) const
@@ -1050,11 +1049,6 @@
 		return getType(object.typeId());
 	}
 
-	Type const &getType(const Operand &operand) const
-	{
-		return getType(operand.typeId());
-	}
-
 	Object const &getObject(Object::ID id) const
 	{
 		auto it = defs.find(id);
diff --git a/src/Pipeline/SpirvShaderArithmetic.cpp b/src/Pipeline/SpirvShaderArithmetic.cpp
index 6ea7611..59c499b 100644
--- a/src/Pipeline/SpirvShaderArithmetic.cpp
+++ b/src/Pipeline/SpirvShaderArithmetic.cpp
@@ -41,12 +41,11 @@
 	auto &dst = state->createIntermediate(insn.resultId(), type.componentCount);
 	auto lhs = Operand(this, state, insn.word(3));
 	auto rhs = Operand(this, state, insn.word(4));
-	auto rhsType = getType(rhs);
 
 	for(auto i = 0u; i < type.componentCount; i++)
 	{
 		SIMD::Float v = lhs.Float(i) * rhs.Float(0);
-		for(auto j = 1u; j < rhsType.componentCount; j++)
+		for(auto j = 1u; j < rhs.componentCount; j++)
 		{
 			v += lhs.Float(i + type.componentCount * j) * rhs.Float(j);
 		}
@@ -62,14 +61,13 @@
 	auto &dst = state->createIntermediate(insn.resultId(), type.componentCount);
 	auto lhs = Operand(this, state, insn.word(3));
 	auto rhs = Operand(this, state, insn.word(4));
-	auto lhsType = getType(lhs);
 
 	for(auto i = 0u; i < type.componentCount; i++)
 	{
-		SIMD::Float v = lhs.Float(0) * rhs.Float(i * lhsType.componentCount);
-		for(auto j = 1u; j < lhsType.componentCount; j++)
+		SIMD::Float v = lhs.Float(0) * rhs.Float(i * lhs.componentCount);
+		for(auto j = 1u; j < lhs.componentCount; j++)
 		{
-			v += lhs.Float(j) * rhs.Float(i * lhsType.componentCount + j);
+			v += lhs.Float(j) * rhs.Float(i * lhs.componentCount + j);
 		}
 		dst.move(i, v);
 	}
@@ -110,17 +108,9 @@
 	auto &dst = state->createIntermediate(insn.resultId(), type.componentCount);
 	auto lhs = Operand(this, state, insn.word(3));
 	auto rhs = Operand(this, state, insn.word(4));
-	auto &lhsType = getType(lhs);
-	auto &rhsType = getType(rhs);
 
-	ASSERT(type.definition.opcode() == spv::OpTypeMatrix);
-	ASSERT(lhsType.definition.opcode() == spv::OpTypeVector);
-	ASSERT(rhsType.definition.opcode() == spv::OpTypeVector);
-	ASSERT(getType(lhsType.element).opcode() == spv::OpTypeFloat);
-	ASSERT(getType(rhsType.element).opcode() == spv::OpTypeFloat);
-
-	auto numRows = lhsType.definition.word(3);
-	auto numCols = rhsType.definition.word(3);
+	auto numRows = lhs.componentCount;
+	auto numCols = rhs.componentCount;
 
 	for(auto col = 0u; col < numCols; col++)
 	{
diff --git a/src/Pipeline/SpirvShaderControlFlow.cpp b/src/Pipeline/SpirvShaderControlFlow.cpp
index dc140fe..80cf455 100644
--- a/src/Pipeline/SpirvShaderControlFlow.cpp
+++ b/src/Pipeline/SpirvShaderControlFlow.cpp
@@ -496,7 +496,7 @@
 	auto falseBlockId = Block::ID(block.branchInstruction.word(3));
 
 	auto cond = Operand(this, state, condId);
-	ASSERT_MSG(getType(cond).componentCount == 1, "Condition must be a Boolean type scalar");
+	ASSERT_MSG(getType(getObject(condId)).componentCount == 1, "Condition must be a Boolean type scalar");
 
 	// TODO: Optimize for case where all lanes take same path.
 
@@ -515,7 +515,7 @@
 	auto selId = Object::ID(block.branchInstruction.word(1));
 
 	auto sel = Operand(this, state, selId);
-	ASSERT_MSG(getType(sel).componentCount == 1, "Selector must be a scalar");
+	ASSERT_MSG(sel.componentCount == 1, "Selector must be a scalar");
 
 	auto numCases = (block.branchInstruction.wordCount() - 3) / 2;
 
diff --git a/src/Pipeline/SpirvShaderDebugger.cpp b/src/Pipeline/SpirvShaderDebugger.cpp
index 0a555d9..be57e54 100644
--- a/src/Pipeline/SpirvShaderDebugger.cpp
+++ b/src/Pipeline/SpirvShaderDebugger.cpp
@@ -1153,11 +1153,12 @@
     EmitState *state,
     int wordOffset /* = 0 */) const
 {
+	auto &obj = shader->getObject(id);
+
 	if(type != nullptr)
 	{
 		if(auto ty = debug::cast<debug::BasicType>(type))
 		{
-			auto &obj = shader->getObject(id);
 			SIMD::Int val;
 			switch(obj.kind)
 			{
@@ -1288,7 +1289,7 @@
 
 	// No debug type information. Derive from SPIR-V.
 	Operand val(shader, state, id);
-	switch(shader->getType(val).opcode())
+	switch(shader->getType(obj).opcode())
 	{
 		case spv::OpTypeInt:
 		{
@@ -1302,7 +1303,7 @@
 		break;
 		case spv::OpTypeVector:
 		{
-			auto count = shader->getType(val).definition.word(3);
+			auto count = shader->getType(obj).definition.word(3);
 			switch(count)
 			{
 				case 1:
diff --git a/src/Pipeline/SpirvShaderGLSLstd450.cpp b/src/Pipeline/SpirvShaderGLSLstd450.cpp
index 554cbe4..5b8d953 100644
--- a/src/Pipeline/SpirvShaderGLSLstd450.cpp
+++ b/src/Pipeline/SpirvShaderGLSLstd450.cpp
@@ -338,12 +338,11 @@
 		{
 			auto p0 = Operand(this, state, insn.word(5));
 			auto p1 = Operand(this, state, insn.word(6));
-			auto p0Type = getType(p0);
 
 			// sqrt(dot(p0-p1, p0-p1))
 			SIMD::Float d = (p0.Float(0) - p1.Float(0)) * (p0.Float(0) - p1.Float(0));
 
-			for(auto i = 1u; i < p0Type.componentCount; i++)
+			for(auto i = 1u; i < p0.componentCount; i++)
 			{
 				d += (p0.Float(i) - p1.Float(i)) * (p0.Float(i) - p1.Float(i));
 			}
@@ -378,14 +377,13 @@
 		case GLSLstd450ModfStruct:
 		{
 			auto val = Operand(this, state, insn.word(5));
-			auto valTy = getType(val);
 
-			for(auto i = 0u; i < valTy.componentCount; i++)
+			for(auto i = 0u; i < val.componentCount; i++)
 			{
 				SIMD::Float whole, frac;
 				std::tie(whole, frac) = Modf(val.Float(i));
 				dst.move(i, frac);
-				dst.move(i + valTy.componentCount, whole);
+				dst.move(i + val.componentCount, whole);
 			}
 			break;
 		}
@@ -527,12 +525,12 @@
 		case GLSLstd450FrexpStruct:
 		{
 			auto val = Operand(this, state, insn.word(5));
-			auto numComponents = getType(val).componentCount;
-			for(auto i = 0u; i < numComponents; i++)
+
+			for(auto i = 0u; i < val.componentCount; i++)
 			{
 				auto significandAndExponent = Frexp(val.Float(i));
 				dst.move(i, significandAndExponent.first);
-				dst.move(i + numComponents, significandAndExponent.second);
+				dst.move(val.componentCount + i, significandAndExponent.second);
 			}
 			break;
 		}
@@ -785,8 +783,8 @@
 		case GLSLstd450Determinant:
 		{
 			auto mat = Operand(this, state, insn.word(5));
-			auto numComponents = getType(mat).componentCount;
-			switch(numComponents)
+
+			switch(mat.componentCount)
 			{
 				case 4:  // 2x2
 					dst.move(0, Determinant(
@@ -807,15 +805,15 @@
 					                mat.Float(12), mat.Float(13), mat.Float(14), mat.Float(15)));
 					break;
 				default:
-					UNREACHABLE("GLSLstd450Determinant can only operate with square matrices. Got %d elements", int(numComponents));
+					UNREACHABLE("GLSLstd450Determinant can only operate with square matrices. Got %d elements", int(mat.componentCount));
 			}
 			break;
 		}
 		case GLSLstd450MatrixInverse:
 		{
 			auto mat = Operand(this, state, insn.word(5));
-			auto numComponents = getType(mat).componentCount;
-			switch(numComponents)
+
+			switch(mat.componentCount)
 			{
 				case 4:  // 2x2
 				{
@@ -854,7 +852,7 @@
 					break;
 				}
 				default:
-					UNREACHABLE("GLSLstd450MatrixInverse can only operate with square matrices. Got %d elements", int(numComponents));
+					UNREACHABLE("GLSLstd450MatrixInverse can only operate with square matrices. Got %d elements", int(mat.componentCount));
 			}
 			break;
 		}
diff --git a/src/Pipeline/SpirvShaderImage.cpp b/src/Pipeline/SpirvShaderImage.cpp
index e6dab75..8197df0 100644
--- a/src/Pipeline/SpirvShaderImage.cpp
+++ b/src/Pipeline/SpirvShaderImage.cpp
@@ -119,7 +119,6 @@
 	auto samplerDescriptor = (sampledImage.opcode() == spv::OpSampledImage) ? state->getPointer(sampledImage.definition.word(4)).base : imageDescriptor;
 
 	auto coordinate = Operand(this, state, coordinateId);
-	auto &coordinateType = getType(coordinate);
 
 	Pointer<Byte> sampler = samplerDescriptor + OFFSET(vk::SampledImageDescriptor, sampler);  // vk::Sampler*
 	Pointer<Byte> texture = imageDescriptor + OFFSET(vk::SampledImageDescriptor, texture);    // sw::Texture*
@@ -204,7 +203,7 @@
 
 	Array<SIMD::Float> in(16);  // Maximum 16 input parameter components.
 
-	uint32_t coordinates = coordinateType.componentCount - instruction.isProj();
+	uint32_t coordinates = coordinate.componentCount - instruction.isProj();
 	instruction.coordinates = coordinates;
 
 	uint32_t i = 0;
@@ -246,17 +245,16 @@
 	{
 		auto dxValue = Operand(this, state, gradDxId);
 		auto dyValue = Operand(this, state, gradDyId);
-		auto &dxyType = getType(dxValue);
-		ASSERT(dxyType.componentCount == getType(dyValue).componentCount);
+		ASSERT(dxValue.componentCount == dxValue.componentCount);
 
-		instruction.grad = dxyType.componentCount;
+		instruction.grad = dxValue.componentCount;
 
-		for(uint32_t j = 0; j < dxyType.componentCount; j++, i++)
+		for(uint32_t j = 0; j < dxValue.componentCount; j++, i++)
 		{
 			in[i] = dxValue.Float(j);
 		}
 
-		for(uint32_t j = 0; j < dxyType.componentCount; j++, i++)
+		for(uint32_t j = 0; j < dxValue.componentCount; j++, i++)
 		{
 			in[i] = dyValue.Float(j);
 		}
@@ -273,11 +271,9 @@
 	if(constOffset)
 	{
 		auto offsetValue = Operand(this, state, offsetId);
-		auto &offsetType = getType(offsetValue);
+		instruction.offset = offsetValue.componentCount;
 
-		instruction.offset = offsetType.componentCount;
-
-		for(uint32_t j = 0; j < offsetType.componentCount; j++, i++)
+		for(uint32_t j = 0; j < offsetValue.componentCount; j++, i++)
 		{
 			in[i] = As<SIMD::Float>(offsetValue.Int(j));  // Integer values, but transfered as float.
 		}
@@ -383,7 +379,7 @@
 	if(lodId != 0)
 	{
 		auto lodVal = Operand(this, state, lodId);
-		ASSERT(getType(lodVal).componentCount == 1);
+		ASSERT(lodVal.componentCount == 1);
 		auto lod = lodVal.Int(0);
 		auto one = SIMD::Int(1);
 		for(uint32_t i = 0; i < dimensions; i++)
@@ -476,12 +472,12 @@
 	auto routine = state->routine;
 	bool isArrayed = imageType.definition.word(5) != 0;
 	auto dim = static_cast<spv::Dim>(imageType.definition.word(3));
-	int dims = getType(coordinate).componentCount - (isArrayed ? 1 : 0);
+	int dims = coordinate.componentCount - (isArrayed ? 1 : 0);
 
 	SIMD::Int u = coordinate.Int(0);
 	SIMD::Int v = SIMD::Int(0);
 
-	if(getType(coordinate).componentCount > 1)
+	if(coordinate.componentCount > 1)
 	{
 		v = coordinate.Int(1);
 	}
diff --git a/src/Pipeline/SpirvShaderMemory.cpp b/src/Pipeline/SpirvShaderMemory.cpp
index b85200f..b37f163 100644
--- a/src/Pipeline/SpirvShaderMemory.cpp
+++ b/src/Pipeline/SpirvShaderMemory.cpp
@@ -99,7 +99,7 @@
 	if(object.kind == Object::Kind::Constant)
 	{
 		// Constant source data.
-		const uint32_t *src = object.constantValue.get();
+		const uint32_t *src = object.constantValue.data();
 		VisitMemoryObject(pointerId, [&](const MemoryElement &el) {
 			auto p = ptr + el.offset;
 			if(interleavedByLane) { p = InterleaveByLane(p); }