Determine SPIR-V zero constants from SPIR-V binary only

Previously the Operand::isConstantZero() method would tell us whether
an operand passed to an instruction is actually a constant expression
with a value of zero. However, the Operand class is a wrapper for
Reactor variables, which also supports constants, so we need to be
actively emitting the Reactor routine that compiles the SPIR-V code, to
use it.

Since determining whether an object represents a value of zero can be
done entirely from the SPIR-V code alone, this change moves this method
to the Object class.

Concretely it has the advantage of being able to tell whether an image
instruction has a Sample operand which is zero, so it ca be ignored,
without passing around the EmitState pointer.

Bug: b/203730083
Change-Id: Ie8e6eb819802d5f9662c727ef81d04f47a9610ad
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/59409
Kokoro-Result: kokoro <noreply+kokoro@google.com>
Tested-by: Nicolas Capens <nicolascapens@google.com>
Presubmit-Ready: Alexis Hétu <sugoi@google.com>
Reviewed-by: Alexis Hétu <sugoi@google.com>
diff --git a/src/Pipeline/SpirvShader.cpp b/src/Pipeline/SpirvShader.cpp
index 2666ef5..59a2c0c 100644
--- a/src/Pipeline/SpirvShader.cpp
+++ b/src/Pipeline/SpirvShader.cpp
@@ -940,7 +940,7 @@
 	uint32_t packedInterpolant = 0;
 	for(uint32_t i = 0; i < maxInterpolant; ++i)
 	{
-		if (inputs[i].Type != ATTRIBTYPE_UNUSED)
+		if(inputs[i].Type != ATTRIBTYPE_UNUSED)
 		{
 			++packedInterpolant;
 		}
@@ -2564,16 +2564,16 @@
 {
 }
 
-bool SpirvShader::Operand::isConstantZero() const
+bool SpirvShader::Object::isConstantZero() const
 {
-	if(!constant)
+	if(kind != Kind::Constant)
 	{
 		return false;
 	}
 
-	for(uint32_t i = 0; i < componentCount; i++)
+	for(uint32_t i = 0; i < constantValue.size(); i++)
 	{
-		if(constant[i] != 0)
+		if(constantValue[i] != 0)
 		{
 			return false;
 		}
diff --git a/src/Pipeline/SpirvShader.hpp b/src/Pipeline/SpirvShader.hpp
index 1d8e5f6..26b3b6a 100644
--- a/src/Pipeline/SpirvShader.hpp
+++ b/src/Pipeline/SpirvShader.hpp
@@ -327,6 +327,8 @@
 		Type::ID typeId() const { return definition.resultTypeId(); }
 		Object::ID id() const { return definition.resultId(); }
 
+		bool isConstantZero() const;
+
 		InsnIterator definition;
 		std::vector<uint32_t> constantValue;
 
@@ -1158,8 +1160,6 @@
 			return SIMD::UInt(constant[i]);
 		}
 
-		bool isConstantZero() const;
-
 	private:
 		RR_PRINT_ONLY(friend struct rr::PrintValue::Ty<Operand>;)
 
diff --git a/src/Pipeline/SpirvShaderImage.cpp b/src/Pipeline/SpirvShaderImage.cpp
index c048426..4c59e71 100644
--- a/src/Pipeline/SpirvShaderImage.cpp
+++ b/src/Pipeline/SpirvShaderImage.cpp
@@ -167,7 +167,7 @@
 		operandsIndex += 1;
 		imageOperands &= ~spv::ImageOperandsSampleMask;
 
-		sample = true;
+		sample = !spirv.getObject(sampleId).isConstantZero();
 	}
 
 	// TODO(b/174475384)
@@ -619,9 +619,9 @@
 	SIMD::Int n = 0;
 	if(sampleId != 0)
 	{
-		Operand sample(this, state, sampleId);
-		if(!sample.isConstantZero())
+		if(!getObject(sampleId).isConstantZero())
 		{
+			Operand sample(this, state, sampleId);
 			n = sample.Int(0);
 			ptrOffset += n * samplePitch;
 		}
@@ -649,8 +649,7 @@
 
 		if(sampleId != 0)
 		{
-			Operand sample(this, state, sampleId);
-			if(!sample.isConstantZero())
+			if(!getObject(sampleId).isConstantZero())
 			{
 				SIMD::UInt sampleCount = *Pointer<UInt>(descriptor + OFFSET(vk::StorageImageDescriptor, sampleCount));
 				oobMask |= As<SIMD::Int>(CmpNLT(As<SIMD::UInt>(n), sampleCount));