spirv-reader: support OpCopyMemory

Bug: tint:3
Change-Id: I779593c379b1f24cb805b69e788c467e64af6db3
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/51041
Auto-Submit: David Neto <dneto@google.com>
Commit-Queue: David Neto <dneto@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
diff --git a/src/reader/spirv/function.cc b/src/reader/spirv/function.cc
index 6aad051..3bb750c 100644
--- a/src/reader/spirv/function.cc
+++ b/src/reader/spirv/function.cc
@@ -3349,6 +3349,29 @@
       return EmitConstDefOrWriteToHoistedVar(inst, expr);
     }
 
+    case SpvOpCopyMemory: {
+      // Generate an assignment.
+      // TODO(dneto): When supporting ptr-ref, the LHS pointer and RHS pointer
+      // map to reference types in WGSL.
+      auto lhs = MakeOperand(inst, 0);
+      auto rhs = MakeOperand(inst, 1);
+      // Ignore any potential memory operands. Currently they are all for
+      // concepts not in WGSL:
+      //   Volatile
+      //   Aligned
+      //   Nontemporal
+      //   MakePointerAvailable ; Vulkan memory model
+      //   MakePointerVisible   ; Vulkan memory model
+      //   NonPrivatePointer    ; Vulkan memory model
+
+      if (!success()) {
+        return false;
+      }
+      AddStatement(
+          create<ast::AssignmentStatement>(Source{}, lhs.expr, rhs.expr));
+      return success();
+    }
+
     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
diff --git a/src/reader/spirv/function_memory_test.cc b/src/reader/spirv/function_memory_test.cc
index a26a065..e6b1d3e 100644
--- a/src/reader/spirv/function_memory_test.cc
+++ b/src/reader/spirv/function_memory_test.cc
@@ -292,6 +292,34 @@
 })"));
 }
 
+TEST_F(SpvParserMemoryTest,
+       EmitStatement_CopyMemory_Scalar_Workgroup_To_Private) {
+  auto p = parser(test::Assemble(Preamble() + R"(
+     %void = OpTypeVoid
+     %voidfn = OpTypeFunction %void
+     %ty = OpTypeInt 32 0
+     %val = OpConstant %ty 42
+     %ptr_wg_ty = OpTypePointer Workgroup %ty
+     %ptr_priv_ty = OpTypePointer Private %ty
+     %1 = OpVariable %ptr_wg_ty Workgroup
+     %2 = OpVariable %ptr_priv_ty Workgroup
+     %100 = OpFunction %void None %voidfn
+     %entry = OpLabel
+     OpCopyMemory %2 %1
+     OpReturn
+     OpFunctionEnd
+  )"));
+  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+  auto fe = p->function_emitter(100);
+  EXPECT_TRUE(fe.EmitBody());
+  const auto got = ToString(p->builder(), fe.ast_body());
+  const auto* expected = R"(Assignment{
+  Identifier[not set]{x_2}
+  Identifier[not set]{x_1}
+})";
+  EXPECT_THAT(got, HasSubstr(expected));
+}
+
 TEST_F(SpvParserMemoryTest, EmitStatement_AccessChain_NoOperands) {
   auto err = test::AssembleFailure(Preamble() + R"(
      %void = OpTypeVoid