SpirvShader: Implement OpCopyObject

Bug: b/132333003
Tests: dEQP-VK.spirv_assembly.instruction.compute.opcopyobject.spotcheck
Change-Id: I0b94fa49e4d788d045e296970f60ee2e9c460de6
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/31009
Presubmit-Ready: Ben Clayton <bclayton@google.com>
Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
Reviewed-by: Chris Forbes <chrisforbes@google.com>
Tested-by: Ben Clayton <bclayton@google.com>
diff --git a/src/Pipeline/SpirvShader.cpp b/src/Pipeline/SpirvShader.cpp
index 6ac9316..423706d 100644
--- a/src/Pipeline/SpirvShader.cpp
+++ b/src/Pipeline/SpirvShader.cpp
@@ -875,6 +875,7 @@
 			case spv::OpImageRead:
 			case spv::OpImageTexelPointer:
 			case spv::OpGroupNonUniformElect:
+			case spv::OpCopyObject:
 				// Instructions that yield an intermediate value or divergent pointer
 				DefineResult(insn);
 				break;
@@ -2468,6 +2469,9 @@
 		case spv::OpImage:
 			return EmitSampledImageCombineOrSplit(insn, state);
 
+		case spv::OpCopyObject:
+			return EmitCopyObject(insn, state);
+
 		case spv::OpCopyMemory:
 			return EmitCopyMemory(insn, state);
 
@@ -5461,6 +5465,18 @@
 		return EmitResult::Continue;
 	}
 
+	SpirvShader::EmitResult SpirvShader::EmitCopyObject(InsnIterator insn, EmitState *state) const
+	{
+		auto ty = getType(insn.word(1));
+		auto &dst = state->routine->createIntermediate(insn.word(2), ty.sizeInComponents);
+		auto src = GenericValue(this, state->routine, insn.word(3));
+		for (uint32_t i = 0; i < ty.sizeInComponents; i++)
+		{
+			dst.move(i, src.Int(i));
+		}
+		return EmitResult::Continue;
+	}
+
 	SpirvShader::EmitResult SpirvShader::EmitCopyMemory(InsnIterator insn, EmitState *state) const
 	{
 		Object::ID dstPtrId = insn.word(1);
diff --git a/src/Pipeline/SpirvShader.hpp b/src/Pipeline/SpirvShader.hpp
index 1eaa6f8..292f4d2 100644
--- a/src/Pipeline/SpirvShader.hpp
+++ b/src/Pipeline/SpirvShader.hpp
@@ -939,6 +939,7 @@
 		EmitResult EmitAtomicOp(InsnIterator insn, EmitState *state) const;
 		EmitResult EmitAtomicCompareExchange(InsnIterator insn, EmitState *state) const;
 		EmitResult EmitSampledImageCombineOrSplit(InsnIterator insn, EmitState *state) const;
+		EmitResult EmitCopyObject(InsnIterator insn, EmitState *state) const;
 		EmitResult EmitCopyMemory(InsnIterator insn, EmitState *state) const;
 		EmitResult EmitControlBarrier(InsnIterator insn, EmitState *state) const;
 		EmitResult EmitMemoryBarrier(InsnIterator insn, EmitState *state) const;