[spirv-reader] Add OpCopyObject

Bug: tint:3
Change-Id: Ie389c825ddcc8ea6f110997e9b8f39ebbb1e1e0d
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/23340
Reviewed-by: dan sinclair <dsinclair@google.com>
diff --git a/src/reader/spirv/function.cc b/src/reader/spirv/function.cc
index 48c3b7f..0635a80 100644
--- a/src/reader/spirv/function.cc
+++ b/src/reader/spirv/function.cc
@@ -2423,6 +2423,12 @@
       // So represent a load by a new const definition.
       return EmitConstDefinition(
           inst, MakeExpression(inst.GetSingleWordInOperand(0)));
+    case SpvOpCopyObject:
+      // Arguably, OpCopyObject is purely combinatorial. On the other hand,
+      // it exists to make a new name for something. So we choose to make
+      // a new named constant definition.
+      return EmitConstDefinition(
+          inst, MakeExpression(inst.GetSingleWordInOperand(0)));
     case SpvOpFunctionCall:
       // TODO(dneto): Fill this out.  Make this pass, for existing tests
       return success();
diff --git a/src/reader/spirv/function_composite_test.cc b/src/reader/spirv/function_composite_test.cc
index c360617..af6d400 100644
--- a/src/reader/spirv/function_composite_test.cc
+++ b/src/reader/spirv/function_composite_test.cc
@@ -509,6 +509,81 @@
       << ToString(fe.ast_body());
 }
 
+using SpvParserTest_CopyObject = SpvParserTest;
+
+TEST_F(SpvParserTest_CopyObject, Scalar) {
+  const auto assembly = Preamble() + R"(
+     %100 = OpFunction %void None %voidfn
+     %entry = OpLabel
+     %1 = OpCopyObject %uint %uint_3
+     %2 = OpCopyObject %uint %1
+     OpReturn
+     OpFunctionEnd
+  )";
+  auto* p = parser(test::Assemble(assembly));
+  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
+  FunctionEmitter fe(p, *spirv_function(100));
+  EXPECT_TRUE(fe.EmitBody()) << p->error();
+  EXPECT_THAT(ToString(fe.ast_body()), HasSubstr(R"(VariableDeclStatement{
+  Variable{
+    x_1
+    none
+    __u32
+    {
+      ScalarConstructor{3}
+    }
+  }
+}
+VariableDeclStatement{
+  Variable{
+    x_2
+    none
+    __u32
+    {
+      Identifier{x_1}
+    }
+  }
+})")) << ToString(fe.ast_body());
+}
+
+TEST_F(SpvParserTest_CopyObject, Pointer) {
+  const auto assembly = Preamble() + R"(
+     %ptr = OpTypePointer Function %uint
+     %10 = OpVariable %ptr Function
+
+     %100 = OpFunction %void None %voidfn
+     %entry = OpLabel
+     %1 = OpCopyObject %ptr %10
+     %2 = OpCopyObject %ptr %1
+     OpReturn
+     OpFunctionEnd
+  )";
+  auto* p = parser(test::Assemble(assembly));
+  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
+  FunctionEmitter fe(p, *spirv_function(100));
+  EXPECT_TRUE(fe.EmitBody()) << p->error();
+  EXPECT_THAT(ToString(fe.ast_body()), HasSubstr(R"(VariableDeclStatement{
+  Variable{
+    x_1
+    none
+    __ptr_function__u32
+    {
+      Identifier{x_10}
+    }
+  }
+}
+VariableDeclStatement{
+  Variable{
+    x_2
+    none
+    __ptr_function__u32
+    {
+      Identifier{x_1}
+    }
+  }
+})")) << ToString(fe.ast_body());
+}
+
 }  // namespace
 }  // namespace spirv
 }  // namespace reader