Add helper methods for obtaining type and result ID

For instructions which define objects, the type ID and result ID are
always the second and third SPIR-V instruction word, respectively.

Bug: b/129000021
Change-Id: I6879251732860b80e1f7780d9078ad7bc9751b4c
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/43691
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.hpp b/src/Pipeline/SpirvShader.hpp
index 6d38c46..96b67ef 100644
--- a/src/Pipeline/SpirvShader.hpp
+++ b/src/Pipeline/SpirvShader.hpp
@@ -26,6 +26,7 @@
 #include "Vulkan/VkConfig.h"
 #include "Vulkan/VkDescriptorSet.hpp"
 
+#define SPV_ENABLE_UTILITY_CODE
 #include <spirv/unified1/spirv.hpp>
 
 #include <array>
@@ -143,12 +144,22 @@
 		ControlBarrier,
 	};
 
-	/* Pseudo-iterator over SPIRV instructions, designed to support range-based-for. */
+	class Type;
+	class Object;
+
+	// Pseudo-iterator over SPIRV instructions, designed to support range-based-for.
 	class InsnIterator
 	{
-		InsnStore::const_iterator iter;
-
 	public:
+		InsnIterator(InsnIterator const &other) = default;
+
+		InsnIterator() = default;
+
+		explicit InsnIterator(InsnStore::const_iterator iter)
+		    : iter{ iter }
+		{
+		}
+
 		spv::Op opcode() const
 		{
 			return static_cast<spv::Op>(*iter & spv::OpCodeMask);
@@ -176,6 +187,26 @@
 			return reinterpret_cast<const char *>(wordPointer(n));
 		}
 
+		bool hasResultAndType() const
+		{
+			bool hasResult = false, hasResultType = false;
+			spv::HasResultAndType(opcode(), &hasResult, &hasResultType);
+
+			return hasResultType;
+		}
+
+		SpirvID<Type> resultTypeId() const
+		{
+			ASSERT(hasResultAndType());
+			return word(1);
+		}
+
+		SpirvID<Object> resultId() const
+		{
+			ASSERT(hasResultAndType());
+			return word(2);
+		}
+
 		bool operator==(InsnIterator const &other) const
 		{
 			return iter == other.iter;
@@ -204,14 +235,8 @@
 			return ret;
 		}
 
-		InsnIterator(InsnIterator const &other) = default;
-
-		InsnIterator() = default;
-
-		explicit InsnIterator(InsnStore::const_iterator iter)
-		    : iter{ iter }
-		{
-		}
+	private:
+		InsnStore::const_iterator iter;
 	};
 
 	/* range-based-for interface */
@@ -247,9 +272,11 @@
 		using ID = SpirvID<Object>;
 
 		spv::Op opcode() const { return definition.opcode(); }
+		Type::ID typeId() const { return definition.resultTypeId(); }
+		Object::ID id() const { return definition.resultId(); }
 
 		InsnIterator definition;
-		Type::ID type;
+		Type::ID type;  // TODO(b/129000021): Eliminate. Use typeId() instead.
 		std::unique_ptr<uint32_t[]> constantValue = nullptr;
 
 		enum class Kind
@@ -1006,7 +1033,12 @@
 			return SIMD::UInt(constantValue[i]);
 		}
 
-		SpirvShader::Type::ID const type;
+		SpirvShader::Type::ID const type;  // TODO(b/129000021): Eliminate. Use typeId() instead.
+
+		Type::ID typeId() const
+		{
+			return obj.typeId();
+		}
 	};
 
 	Type const &getType(Type::ID id) const
@@ -1016,6 +1048,16 @@
 		return it->second;
 	}
 
+	Type const &getType(const Object &object) const
+	{
+		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);
@@ -1167,6 +1209,10 @@
 	// etc).
 	static bool IsStatement(spv::Op op);
 
+	// HasTypeAndResult() returns true if the given opcode's instruction
+	// has a result type ID and result ID, i.e. defines an Object.
+	static bool HasTypeAndResult(spv::Op op);
+
 	// Helper as we often need to take dot products as part of doing other things.
 	SIMD::Float Dot(unsigned numComponents, Operand const &x, Operand const &y) const;