[ir] Set parent blocks in Switch::Clone()

Without this, the IR validator is unable to correctly validate that
certain instructions are used in the correct contexts.

Fixed: 344265982
Change-Id: Ibe0a7407eed9f5ca4701c66941b2c86ddf5c5441
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/192220
Auto-Submit: James Price <jrprice@google.com>
Commit-Queue: dan sinclair <dsinclair@google.com>
Reviewed-by: dan sinclair <dsinclair@google.com>
Commit-Queue: James Price <jrprice@google.com>
diff --git a/src/tint/lang/core/ir/switch.cc b/src/tint/lang/core/ir/switch.cc
index 5ba9abf..f94f200 100644
--- a/src/tint/lang/core/ir/switch.cc
+++ b/src/tint/lang/core/ir/switch.cc
@@ -68,6 +68,7 @@
     for (auto& cse : cases_) {
         Switch::Case new_case{};
         new_case.block = ctx.ir.blocks.Create<ir::Block>();
+        new_case.block->SetParent(new_switch);
         cse.block->CloneInto(ctx, new_case.block);
 
         new_case.selectors.Reserve(cse.selectors.Length());
diff --git a/src/tint/lang/core/ir/switch_test.cc b/src/tint/lang/core/ir/switch_test.cc
index 1af4ae8..ee740d1 100644
--- a/src/tint/lang/core/ir/switch_test.cc
+++ b/src/tint/lang/core/ir/switch_test.cc
@@ -75,6 +75,7 @@
         auto& case1 = cases[0];
         EXPECT_NE(nullptr, case1.block);
         EXPECT_NE(switch_->Cases()[0].block, case1.block);
+        EXPECT_EQ(case1.block->Parent(), new_switch);
 
         ASSERT_EQ(2u, case1.selectors.Length());
         EXPECT_EQ(nullptr, case1.selectors[0].val);
@@ -87,6 +88,7 @@
         auto& case2 = cases[1];
         EXPECT_NE(nullptr, case2.block);
         EXPECT_NE(switch_->Cases()[1].block, case2.block);
+        EXPECT_EQ(case2.block->Parent(), new_switch);
 
         ASSERT_EQ(1u, case2.selectors.Length());
         auto val = case2.selectors[0].val->Value();
diff --git a/test/tint/bug/chromium/344265982.wgsl b/test/tint/bug/chromium/344265982.wgsl
new file mode 100644
index 0000000..fd2de5f
--- /dev/null
+++ b/test/tint/bug/chromium/344265982.wgsl
@@ -0,0 +1,20 @@
+@group(0) @binding(0)
+var<storage, read_write> buffer: array<i32, 4>;
+
+fn foo(arg: ptr<storage, array<i32, 4>, read_write>) {
+  for (var i = 0; i < 4; i++) {
+    switch (arg[i]) {
+      case 1: {
+        continue;
+      }
+      default: {
+        arg[i] = 2;
+      }
+    }
+  }
+}
+
+@fragment
+fn main() {
+  foo(&buffer);
+}
diff --git a/test/tint/bug/chromium/344265982.wgsl.expected.dxc.hlsl b/test/tint/bug/chromium/344265982.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..ed83a31
--- /dev/null
+++ b/test/tint/bug/chromium/344265982.wgsl.expected.dxc.hlsl
@@ -0,0 +1,28 @@
+RWByteAddressBuffer buffer : register(u0);
+
+void foo_buffer() {
+  bool tint_continue = false;
+  {
+    for(int i = 0; (i < 4); i = (i + 1)) {
+      tint_continue = false;
+      switch(asint(buffer.Load((4u * uint(i))))) {
+        case 1: {
+          tint_continue = true;
+          break;
+        }
+        default: {
+          buffer.Store((4u * uint(i)), asuint(2));
+          break;
+        }
+      }
+      if (tint_continue) {
+        continue;
+      }
+    }
+  }
+}
+
+void main() {
+  foo_buffer();
+  return;
+}
diff --git a/test/tint/bug/chromium/344265982.wgsl.expected.fxc.hlsl b/test/tint/bug/chromium/344265982.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..ed83a31
--- /dev/null
+++ b/test/tint/bug/chromium/344265982.wgsl.expected.fxc.hlsl
@@ -0,0 +1,28 @@
+RWByteAddressBuffer buffer : register(u0);
+
+void foo_buffer() {
+  bool tint_continue = false;
+  {
+    for(int i = 0; (i < 4); i = (i + 1)) {
+      tint_continue = false;
+      switch(asint(buffer.Load((4u * uint(i))))) {
+        case 1: {
+          tint_continue = true;
+          break;
+        }
+        default: {
+          buffer.Store((4u * uint(i)), asuint(2));
+          break;
+        }
+      }
+      if (tint_continue) {
+        continue;
+      }
+    }
+  }
+}
+
+void main() {
+  foo_buffer();
+  return;
+}
diff --git a/test/tint/bug/chromium/344265982.wgsl.expected.glsl b/test/tint/bug/chromium/344265982.wgsl.expected.glsl
new file mode 100644
index 0000000..67c79ef
--- /dev/null
+++ b/test/tint/bug/chromium/344265982.wgsl.expected.glsl
@@ -0,0 +1,38 @@
+#version 310 es
+precision highp float;
+precision highp int;
+
+layout(binding = 0, std430) buffer tint_symbol_block_ssbo {
+  int inner[4];
+} tint_symbol;
+
+void foo_tint_symbol_inner() {
+  bool tint_continue = false;
+  {
+    for(int i = 0; (i < 4); i = (i + 1)) {
+      tint_continue = false;
+      switch(tint_symbol.inner[i]) {
+        case 1: {
+          tint_continue = true;
+          break;
+        }
+        default: {
+          tint_symbol.inner[i] = 2;
+          break;
+        }
+      }
+      if (tint_continue) {
+        continue;
+      }
+    }
+  }
+}
+
+void tint_symbol_1() {
+  foo_tint_symbol_inner();
+}
+
+void main() {
+  tint_symbol_1();
+  return;
+}
diff --git a/test/tint/bug/chromium/344265982.wgsl.expected.ir.msl b/test/tint/bug/chromium/344265982.wgsl.expected.ir.msl
new file mode 100644
index 0000000..cbc2740
--- /dev/null
+++ b/test/tint/bug/chromium/344265982.wgsl.expected.ir.msl
@@ -0,0 +1,51 @@
+#include <metal_stdlib>
+using namespace metal;
+template<typename T, size_t N>
+struct tint_array {
+  const constant T& operator[](size_t i) const constant { return elements[i]; }
+  device T& operator[](size_t i) device { return elements[i]; }
+  const device T& operator[](size_t i) const device { return elements[i]; }
+  thread T& operator[](size_t i) thread { return elements[i]; }
+  const thread T& operator[](size_t i) const thread { return elements[i]; }
+  threadgroup T& operator[](size_t i) threadgroup { return elements[i]; }
+  const threadgroup T& operator[](size_t i) const threadgroup { return elements[i]; }
+  T elements[N];
+};
+
+struct tint_module_vars_struct {
+  device tint_array<int, 4>* tint_symbol;
+};
+
+void foo(device tint_array<int, 4>* const arg) {
+  {
+    int i = 0;
+    while(true) {
+      if ((i < 4)) {
+      } else {
+        break;
+      }
+      switch((*arg)[i]) {
+        case 1:
+        {
+          {
+            i = (i + 1);
+          }
+          continue;
+        }
+        default:
+        {
+          (*arg)[i] = 2;
+          break;
+        }
+      }
+      {
+        i = (i + 1);
+      }
+      continue;
+    }
+  }
+}
+fragment void tint_symbol_1(device tint_array<int, 4>* tint_symbol [[buffer(0)]]) {
+  tint_module_vars_struct const tint_module_vars = tint_module_vars_struct{.tint_symbol=tint_symbol};
+  foo(tint_module_vars.tint_symbol);
+}
diff --git a/test/tint/bug/chromium/344265982.wgsl.expected.ir.spvasm b/test/tint/bug/chromium/344265982.wgsl.expected.ir.spvasm
new file mode 100644
index 0000000..cd4e0ad
--- /dev/null
+++ b/test/tint/bug/chromium/344265982.wgsl.expected.ir.spvasm
@@ -0,0 +1,81 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 1
+; Bound: 43
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %main "main"
+               OpExecutionMode %main OriginUpperLeft
+               OpMemberName %tint_symbol_1 0 "tint_symbol"
+               OpName %tint_symbol_1 "tint_symbol_1"
+               OpName %foo "foo"
+               OpName %i "i"
+               OpName %main "main"
+               OpDecorate %_arr_int_uint_4 ArrayStride 4
+               OpMemberDecorate %tint_symbol_1 0 Offset 0
+               OpDecorate %tint_symbol_1 Block
+               OpDecorate %1 DescriptorSet 0
+               OpDecorate %1 Binding 0
+        %int = OpTypeInt 32 1
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_int_uint_4 = OpTypeArray %int %uint_4
+%tint_symbol_1 = OpTypeStruct %_arr_int_uint_4
+%_ptr_StorageBuffer_tint_symbol_1 = OpTypePointer StorageBuffer %tint_symbol_1
+          %1 = OpVariable %_ptr_StorageBuffer_tint_symbol_1 StorageBuffer
+       %void = OpTypeVoid
+         %10 = OpTypeFunction %void
+%_ptr_Function_int = OpTypePointer Function %int
+      %int_0 = OpConstant %int 0
+      %int_4 = OpConstant %int 4
+       %bool = OpTypeBool
+%_ptr_StorageBuffer_int = OpTypePointer StorageBuffer %int
+     %uint_0 = OpConstant %uint 0
+      %int_2 = OpConstant %int 2
+      %int_1 = OpConstant %int 1
+        %foo = OpFunction %void None %10
+         %11 = OpLabel
+          %i = OpVariable %_ptr_Function_int Function
+               OpBranch %12
+         %12 = OpLabel
+               OpStore %i %int_0
+               OpBranch %15
+         %15 = OpLabel
+               OpLoopMerge %16 %14 None
+               OpBranch %13
+         %13 = OpLabel
+         %20 = OpLoad %int %i
+         %21 = OpSLessThan %bool %20 %int_4
+               OpSelectionMerge %24 None
+               OpBranchConditional %21 %24 %25
+         %25 = OpLabel
+               OpBranch %16
+         %24 = OpLabel
+         %26 = OpLoad %int %i
+         %27 = OpAccessChain %_ptr_StorageBuffer_int %1 %uint_0 %26
+         %30 = OpLoad %int %27
+               OpSelectionMerge %33 None
+               OpSwitch %30 %31 1 %32
+         %32 = OpLabel
+               OpBranch %14
+         %31 = OpLabel
+         %34 = OpLoad %int %i
+         %35 = OpAccessChain %_ptr_StorageBuffer_int %1 %uint_0 %34
+               OpStore %35 %int_2
+               OpBranch %33
+         %33 = OpLabel
+               OpBranch %14
+         %14 = OpLabel
+         %37 = OpLoad %int %i
+         %38 = OpIAdd %int %37 %int_1
+               OpStore %i %38
+               OpBranch %15
+         %16 = OpLabel
+               OpReturn
+               OpFunctionEnd
+       %main = OpFunction %void None %10
+         %41 = OpLabel
+         %42 = OpFunctionCall %void %foo
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/bug/chromium/344265982.wgsl.expected.msl b/test/tint/bug/chromium/344265982.wgsl.expected.msl
new file mode 100644
index 0000000..b9966d0
--- /dev/null
+++ b/test/tint/bug/chromium/344265982.wgsl.expected.msl
@@ -0,0 +1,45 @@
+#include <metal_stdlib>
+
+using namespace metal;
+
+template<typename T, size_t N>
+struct tint_array {
+    const constant T& operator[](size_t i) const constant { return elements[i]; }
+    device T& operator[](size_t i) device { return elements[i]; }
+    const device T& operator[](size_t i) const device { return elements[i]; }
+    thread T& operator[](size_t i) thread { return elements[i]; }
+    const thread T& operator[](size_t i) const thread { return elements[i]; }
+    threadgroup T& operator[](size_t i) threadgroup { return elements[i]; }
+    const threadgroup T& operator[](size_t i) const threadgroup { return elements[i]; }
+    T elements[N];
+};
+
+#define TINT_ISOLATE_UB(VOLATILE_NAME) \
+  volatile bool VOLATILE_NAME = true; \
+  if (VOLATILE_NAME)
+
+void foo(device tint_array<int, 4>* const arg) {
+  bool tint_continue = false;
+  TINT_ISOLATE_UB(tint_volatile_true) for(int i = 0; (i < 4); i = as_type<int>((as_type<uint>(i) + as_type<uint>(1)))) {
+    tint_continue = false;
+    switch((*(arg))[i]) {
+      case 1: {
+        tint_continue = true;
+        break;
+      }
+      default: {
+        (*(arg))[i] = 2;
+        break;
+      }
+    }
+    if (tint_continue) {
+      continue;
+    }
+  }
+}
+
+fragment void tint_symbol_1(device tint_array<int, 4>* tint_symbol_2 [[buffer(0)]]) {
+  foo(tint_symbol_2);
+  return;
+}
+
diff --git a/test/tint/bug/chromium/344265982.wgsl.expected.spvasm b/test/tint/bug/chromium/344265982.wgsl.expected.spvasm
new file mode 100644
index 0000000..1faedd8
--- /dev/null
+++ b/test/tint/bug/chromium/344265982.wgsl.expected.spvasm
@@ -0,0 +1,81 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 43
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %main "main"
+               OpExecutionMode %main OriginUpperLeft
+               OpName %buffer_block "buffer_block"
+               OpMemberName %buffer_block 0 "inner"
+               OpName %buffer "buffer"
+               OpName %foo_buffer "foo_buffer"
+               OpName %i "i"
+               OpName %main "main"
+               OpDecorate %buffer_block Block
+               OpMemberDecorate %buffer_block 0 Offset 0
+               OpDecorate %_arr_int_uint_4 ArrayStride 4
+               OpDecorate %buffer DescriptorSet 0
+               OpDecorate %buffer Binding 0
+        %int = OpTypeInt 32 1
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_int_uint_4 = OpTypeArray %int %uint_4
+%buffer_block = OpTypeStruct %_arr_int_uint_4
+%_ptr_StorageBuffer_buffer_block = OpTypePointer StorageBuffer %buffer_block
+     %buffer = OpVariable %_ptr_StorageBuffer_buffer_block StorageBuffer
+       %void = OpTypeVoid
+          %8 = OpTypeFunction %void
+         %12 = OpConstantNull %int
+%_ptr_Function_int = OpTypePointer Function %int
+      %int_4 = OpConstant %int 4
+       %bool = OpTypeBool
+     %uint_0 = OpConstant %uint 0
+%_ptr_StorageBuffer_int = OpTypePointer StorageBuffer %int
+      %int_2 = OpConstant %int 2
+      %int_1 = OpConstant %int 1
+ %foo_buffer = OpFunction %void None %8
+         %11 = OpLabel
+          %i = OpVariable %_ptr_Function_int Function %12
+               OpStore %i %12
+               OpBranch %15
+         %15 = OpLabel
+               OpLoopMerge %16 %17 None
+               OpBranch %18
+         %18 = OpLabel
+         %20 = OpLoad %int %i
+         %22 = OpSLessThan %bool %20 %int_4
+         %19 = OpLogicalNot %bool %22
+               OpSelectionMerge %24 None
+               OpBranchConditional %19 %25 %24
+         %25 = OpLabel
+               OpBranch %16
+         %24 = OpLabel
+         %28 = OpLoad %int %i
+         %30 = OpAccessChain %_ptr_StorageBuffer_int %buffer %uint_0 %28
+         %31 = OpLoad %int %30
+               OpSelectionMerge %26 None
+               OpSwitch %31 %32 1 %33
+         %33 = OpLabel
+               OpBranch %17
+         %32 = OpLabel
+         %34 = OpLoad %int %i
+         %35 = OpAccessChain %_ptr_StorageBuffer_int %buffer %uint_0 %34
+               OpStore %35 %int_2
+               OpBranch %26
+         %26 = OpLabel
+               OpBranch %17
+         %17 = OpLabel
+         %37 = OpLoad %int %i
+         %39 = OpIAdd %int %37 %int_1
+               OpStore %i %39
+               OpBranch %15
+         %16 = OpLabel
+               OpReturn
+               OpFunctionEnd
+       %main = OpFunction %void None %8
+         %41 = OpLabel
+         %42 = OpFunctionCall %void %foo_buffer
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/bug/chromium/344265982.wgsl.expected.wgsl b/test/tint/bug/chromium/344265982.wgsl.expected.wgsl
new file mode 100644
index 0000000..cd80a78
--- /dev/null
+++ b/test/tint/bug/chromium/344265982.wgsl.expected.wgsl
@@ -0,0 +1,19 @@
+@group(0) @binding(0) var<storage, read_write> buffer : array<i32, 4>;
+
+fn foo(arg : ptr<storage, array<i32, 4>, read_write>) {
+  for(var i = 0; (i < 4); i++) {
+    switch(arg[i]) {
+      case 1: {
+        continue;
+      }
+      default: {
+        arg[i] = 2;
+      }
+    }
+  }
+}
+
+@fragment
+fn main() {
+  foo(&(buffer));
+}