[tint][ast] Fix DemoteToHelper with atomicCompareExchangeWeak()

Since the resolver was able to parse 'untypable' builtin structures with https://dawn-review.googlesource.com/c/dawn/+/129482, some transforms (like PromoteInitializersToLet) are able to create lets of these 'untypeable' builtin types.

The DemoteToHelper transform had its own workaround for the 'untypeable' atomicCompareExchangeWeak() result type, by creating a user-declared structure with the same shape. This workaround can fail if a previous transform builds a variable with the 'untypeable' result type, as the user-declared type cannot be assigned to it.

Fortunately the fix here is simple - we can just remove the workaround in DemoteToHelper, which makes the transform emit the 'untypeable' result type, and so the assignment matches types.

Bug: chromium:324439761
Fixed: tint:2147
Change-Id: I89ca496c60ce140bfb7c5d6de54f4931afc85fbf
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/173180
Auto-Submit: Ben Clayton <bclayton@google.com>
Reviewed-by: Antonio Maiorano <amaiorano@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
(cherry picked from commit f83de0f6583483d76b647ad716702723ec276a42)
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/174024
Reviewed-by: David Neto <dneto@google.com>
Kokoro: Ben Clayton <bclayton@google.com>
diff --git a/src/tint/lang/wgsl/ast/transform/demote_to_helper.cc b/src/tint/lang/wgsl/ast/transform/demote_to_helper.cc
index 93a539c..1b88f20 100644
--- a/src/tint/lang/wgsl/ast/transform/demote_to_helper.cc
+++ b/src/tint/lang/wgsl/ast/transform/demote_to_helper.cc
@@ -191,50 +191,10 @@
                         //   }
                         //   let y = x + tmp;
                         auto result = b.Sym();
-                        Type result_ty;
-                        const Statement* masked_call = nullptr;
-                        if (builtin->Fn() == wgsl::BuiltinFn::kAtomicCompareExchangeWeak) {
-                            // Special case for atomicCompareExchangeWeak as we cannot name its
-                            // result type. We have to declare an equivalent struct and copy the
-                            // original member values over to it.
-
-                            // Declare a struct to hold the result values.
-                            auto* result_struct = sem_call->Type()->As<core::type::Struct>();
-                            auto* atomic_ty = result_struct->Members()[0]->Type();
-                            result_ty =
-                                b.ty(tint::GetOrCreate(atomic_cmpxchg_result_types, atomic_ty, [&] {
-                                    auto name = b.Sym();
-                                    b.Structure(
-                                        name,
-                                        tint::Vector{
-                                            b.Member("old_value", CreateASTTypeFor(ctx, atomic_ty)),
-                                            b.Member("exchanged", b.ty.bool_()),
-                                        });
-                                    return name;
-                                }));
-
-                            // Generate the masked call and member-wise copy:
-                            //   if (!tint_discarded) {
-                            //     let tmp_result = atomicCompareExchangeWeak(&p, 1, 2);
-                            //     result.exchanged = tmp_result.exchanged;
-                            //     result.old_value = tmp_result.old_value;
-                            //   }
-                            auto tmp_result = b.Sym();
-                            masked_call =
-                                b.If(b.Not(flag),
-                                     b.Block(tint::Vector{
-                                         b.Decl(b.Let(tmp_result, ctx.CloneWithoutTransform(call))),
-                                         b.Assign(b.MemberAccessor(result, "old_value"),
-                                                  b.MemberAccessor(tmp_result, "old_value")),
-                                         b.Assign(b.MemberAccessor(result, "exchanged"),
-                                                  b.MemberAccessor(tmp_result, "exchanged")),
-                                     }));
-                        } else {
-                            result_ty = CreateASTTypeFor(ctx, sem_call->Type());
-                            masked_call =
-                                b.If(b.Not(flag),
-                                     b.Block(b.Assign(result, ctx.CloneWithoutTransform(call))));
-                        }
+                        auto result_ty = CreateASTTypeFor(ctx, sem_call->Type());
+                        auto* masked_call =
+                            b.If(b.Not(flag),
+                                 b.Block(b.Assign(result, ctx.CloneWithoutTransform(call))));
                         auto* result_decl = b.Decl(b.Var(result, result_ty));
                         hoist_to_decl_before.Prepare(sem_call);
                         hoist_to_decl_before.InsertBefore(stmt, result_decl);
diff --git a/src/tint/lang/wgsl/ast/transform/demote_to_helper_test.cc b/src/tint/lang/wgsl/ast/transform/demote_to_helper_test.cc
index de590a4..0af6dd1 100644
--- a/src/tint/lang/wgsl/ast/transform/demote_to_helper_test.cc
+++ b/src/tint/lang/wgsl/ast/transform/demote_to_helper_test.cc
@@ -1187,11 +1187,6 @@
     auto* expect = R"(
 var<private> tint_discarded = false;
 
-struct tint_symbol_1 {
-  old_value : i32,
-  exchanged : bool,
-}
-
 @group(0) @binding(0) var t : texture_2d<f32>;
 
 @group(0) @binding(1) var s : sampler;
@@ -1204,20 +1199,16 @@
     tint_discarded = true;
   }
   var result = 0;
-  var tint_symbol : tint_symbol_1;
+  var tint_symbol : __atomic_compare_exchange_result_i32;
   if (!(tint_discarded)) {
-    let tint_symbol_2 = atomicCompareExchangeWeak(&(a), i32(in), 42);
-    tint_symbol.old_value = tint_symbol_2.old_value;
-    tint_symbol.exchanged = tint_symbol_2.exchanged;
+    tint_symbol = atomicCompareExchangeWeak(&(a), i32(in), 42);
   }
   if (!(tint_symbol.exchanged)) {
-    var tint_symbol_3 : tint_symbol_1;
+    var tint_symbol_1 : __atomic_compare_exchange_result_i32;
     if (!(tint_discarded)) {
-      let tint_symbol_4 = atomicCompareExchangeWeak(&(a), i32(in), 42);
-      tint_symbol_3.old_value = tint_symbol_4.old_value;
-      tint_symbol_3.exchanged = tint_symbol_4.exchanged;
+      tint_symbol_1 = atomicCompareExchangeWeak(&(a), i32(in), 42);
     }
-    let xchg = tint_symbol_3;
+    let xchg = tint_symbol_1;
     result = xchg.old_value;
   }
   result += i32(textureSample(t, s, coord).x);
diff --git a/test/tint/bug/tint/2147.wgsl b/test/tint/bug/tint/2147.wgsl
new file mode 100644
index 0000000..97c0f58
--- /dev/null
+++ b/test/tint/bug/tint/2147.wgsl
@@ -0,0 +1,11 @@
+
+@group(0) @binding(0) var<storage, read_write> S : atomic<i32>;
+
+@fragment
+fn main() -> @location(0) vec4f {
+  if (false) {
+    discard;
+  }
+  let old_value = atomicCompareExchangeWeak(&S, 0i, 1i).old_value;
+  return vec4f(f32(old_value));
+}
diff --git a/test/tint/bug/tint/2147.wgsl.expected.dxc.hlsl b/test/tint/bug/tint/2147.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..c2ed537
--- /dev/null
+++ b/test/tint/bug/tint/2147.wgsl.expected.dxc.hlsl
@@ -0,0 +1,41 @@
+struct atomic_compare_exchange_result_i32 {
+  int old_value;
+  bool exchanged;
+};
+static bool tint_discarded = false;
+RWByteAddressBuffer S : register(u0);
+
+struct tint_symbol_1 {
+  float4 value : SV_Target0;
+};
+
+atomic_compare_exchange_result_i32 SatomicCompareExchangeWeak(uint offset, int compare, int value) {
+  atomic_compare_exchange_result_i32 result=(atomic_compare_exchange_result_i32)0;
+  S.InterlockedCompareExchange(offset, compare, value, result.old_value);
+  result.exchanged = result.old_value == compare;
+  return result;
+}
+
+
+float4 main_inner() {
+  if (false) {
+    tint_discarded = true;
+  }
+  atomic_compare_exchange_result_i32 tint_symbol_2 = (atomic_compare_exchange_result_i32)0;
+  if (!(tint_discarded)) {
+    tint_symbol_2 = SatomicCompareExchangeWeak(0u, 0, 1);
+  }
+  const atomic_compare_exchange_result_i32 tint_symbol = tint_symbol_2;
+  const int old_value = tint_symbol.old_value;
+  return float4((float(old_value)).xxxx);
+}
+
+tint_symbol_1 main() {
+  const float4 inner_result = main_inner();
+  tint_symbol_1 wrapper_result = (tint_symbol_1)0;
+  wrapper_result.value = inner_result;
+  if (tint_discarded) {
+    discard;
+  }
+  return wrapper_result;
+}
diff --git a/test/tint/bug/tint/2147.wgsl.expected.fxc.hlsl b/test/tint/bug/tint/2147.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..c2ed537
--- /dev/null
+++ b/test/tint/bug/tint/2147.wgsl.expected.fxc.hlsl
@@ -0,0 +1,41 @@
+struct atomic_compare_exchange_result_i32 {
+  int old_value;
+  bool exchanged;
+};
+static bool tint_discarded = false;
+RWByteAddressBuffer S : register(u0);
+
+struct tint_symbol_1 {
+  float4 value : SV_Target0;
+};
+
+atomic_compare_exchange_result_i32 SatomicCompareExchangeWeak(uint offset, int compare, int value) {
+  atomic_compare_exchange_result_i32 result=(atomic_compare_exchange_result_i32)0;
+  S.InterlockedCompareExchange(offset, compare, value, result.old_value);
+  result.exchanged = result.old_value == compare;
+  return result;
+}
+
+
+float4 main_inner() {
+  if (false) {
+    tint_discarded = true;
+  }
+  atomic_compare_exchange_result_i32 tint_symbol_2 = (atomic_compare_exchange_result_i32)0;
+  if (!(tint_discarded)) {
+    tint_symbol_2 = SatomicCompareExchangeWeak(0u, 0, 1);
+  }
+  const atomic_compare_exchange_result_i32 tint_symbol = tint_symbol_2;
+  const int old_value = tint_symbol.old_value;
+  return float4((float(old_value)).xxxx);
+}
+
+tint_symbol_1 main() {
+  const float4 inner_result = main_inner();
+  tint_symbol_1 wrapper_result = (tint_symbol_1)0;
+  wrapper_result.value = inner_result;
+  if (tint_discarded) {
+    discard;
+  }
+  return wrapper_result;
+}
diff --git a/test/tint/bug/tint/2147.wgsl.expected.glsl b/test/tint/bug/tint/2147.wgsl.expected.glsl
new file mode 100644
index 0000000..62cd623
--- /dev/null
+++ b/test/tint/bug/tint/2147.wgsl.expected.glsl
@@ -0,0 +1,39 @@
+#version 310 es
+precision highp float;
+
+struct atomic_compare_exchange_result_i32 {
+  int old_value;
+  bool exchanged;
+};
+
+
+bool tint_discarded = false;
+layout(location = 0) out vec4 value;
+layout(binding = 0, std430) buffer S_block_ssbo {
+  int inner;
+} S;
+
+vec4 tint_symbol() {
+  if (false) {
+    tint_discarded = true;
+  }
+  atomic_compare_exchange_result_i32 tint_symbol_2 = atomic_compare_exchange_result_i32(0, false);
+  if (!(tint_discarded)) {
+    atomic_compare_exchange_result_i32 atomic_compare_result;
+    atomic_compare_result.old_value = atomicCompSwap(S.inner, 0, 1);
+    atomic_compare_result.exchanged = atomic_compare_result.old_value == 0;
+    tint_symbol_2 = atomic_compare_result;
+  }
+  atomic_compare_exchange_result_i32 tint_symbol_1 = tint_symbol_2;
+  int old_value = tint_symbol_1.old_value;
+  return vec4(float(old_value));
+}
+
+void main() {
+  vec4 inner_result = tint_symbol();
+  value = inner_result;
+  if (tint_discarded) {
+    discard;
+  }
+  return;
+}
diff --git a/test/tint/bug/tint/2147.wgsl.expected.msl b/test/tint/bug/tint/2147.wgsl.expected.msl
new file mode 100644
index 0000000..7b22eef
--- /dev/null
+++ b/test/tint/bug/tint/2147.wgsl.expected.msl
@@ -0,0 +1,47 @@
+#include <metal_stdlib>
+
+using namespace metal;
+
+struct atomic_compare_exchange_result_i32 {
+  int old_value;
+  bool exchanged;
+};
+atomic_compare_exchange_result_i32 atomicCompareExchangeWeak_1(device atomic_int* atomic, int compare, int value) {
+  int old_value = compare;
+  bool exchanged = atomic_compare_exchange_weak_explicit(atomic, &old_value, value, memory_order_relaxed, memory_order_relaxed);
+  return {old_value, exchanged};
+}
+
+struct tint_private_vars_struct {
+  bool tint_discarded;
+};
+
+struct tint_symbol_2 {
+  float4 value [[color(0)]];
+};
+
+float4 tint_symbol_inner(thread tint_private_vars_struct* const tint_private_vars, device atomic_int* const tint_symbol_4) {
+  if (false) {
+    (*(tint_private_vars)).tint_discarded = true;
+  }
+  atomic_compare_exchange_result_i32 tint_symbol_3 = {};
+  if (!((*(tint_private_vars)).tint_discarded)) {
+    tint_symbol_3 = atomicCompareExchangeWeak_1(tint_symbol_4, 0, 1);
+  }
+  atomic_compare_exchange_result_i32 const tint_symbol_1 = tint_symbol_3;
+  int const old_value = tint_symbol_1.old_value;
+  return float4(float(old_value));
+}
+
+fragment tint_symbol_2 tint_symbol(device atomic_int* tint_symbol_5 [[buffer(0)]]) {
+  thread tint_private_vars_struct tint_private_vars = {};
+  tint_private_vars.tint_discarded = false;
+  float4 const inner_result = tint_symbol_inner(&(tint_private_vars), tint_symbol_5);
+  tint_symbol_2 wrapper_result = {};
+  wrapper_result.value = inner_result;
+  if (tint_private_vars.tint_discarded) {
+    discard_fragment();
+  }
+  return wrapper_result;
+}
+
diff --git a/test/tint/bug/tint/2147.wgsl.expected.spvasm b/test/tint/bug/tint/2147.wgsl.expected.spvasm
new file mode 100644
index 0000000..6db60b7
--- /dev/null
+++ b/test/tint/bug/tint/2147.wgsl.expected.spvasm
@@ -0,0 +1,92 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 51
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %main "main" %value
+               OpExecutionMode %main OriginUpperLeft
+               OpName %tint_discarded "tint_discarded"
+               OpName %value "value"
+               OpName %S_block "S_block"
+               OpMemberName %S_block 0 "inner"
+               OpName %S "S"
+               OpName %main_inner "main_inner"
+               OpName %__atomic_compare_exchange_result_i32 "__atomic_compare_exchange_result_i32"
+               OpMemberName %__atomic_compare_exchange_result_i32 0 "old_value"
+               OpMemberName %__atomic_compare_exchange_result_i32 1 "exchanged"
+               OpName %tint_symbol_1 "tint_symbol_1"
+               OpName %main "main"
+               OpDecorate %value Location 0
+               OpDecorate %S_block Block
+               OpMemberDecorate %S_block 0 Offset 0
+               OpDecorate %S DescriptorSet 0
+               OpDecorate %S Binding 0
+               OpMemberDecorate %__atomic_compare_exchange_result_i32 0 Offset 0
+               OpMemberDecorate %__atomic_compare_exchange_result_i32 1 Offset 4
+       %bool = OpTypeBool
+          %2 = OpConstantNull %bool
+%_ptr_Private_bool = OpTypePointer Private %bool
+%tint_discarded = OpVariable %_ptr_Private_bool Private %2
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+          %9 = OpConstantNull %v4float
+      %value = OpVariable %_ptr_Output_v4float Output %9
+        %int = OpTypeInt 32 1
+    %S_block = OpTypeStruct %int
+%_ptr_StorageBuffer_S_block = OpTypePointer StorageBuffer %S_block
+          %S = OpVariable %_ptr_StorageBuffer_S_block StorageBuffer
+         %14 = OpTypeFunction %v4float
+       %true = OpConstantTrue %bool
+%__atomic_compare_exchange_result_i32 = OpTypeStruct %int %bool
+%_ptr_Function___atomic_compare_exchange_result_i32 = OpTypePointer Function %__atomic_compare_exchange_result_i32
+         %23 = OpConstantNull %__atomic_compare_exchange_result_i32
+       %uint = OpTypeInt 32 0
+     %uint_1 = OpConstant %uint 1
+     %uint_0 = OpConstant %uint 0
+%_ptr_StorageBuffer_int = OpTypePointer StorageBuffer %int
+      %int_1 = OpConstant %int 1
+         %36 = OpConstantNull %int
+       %void = OpTypeVoid
+         %43 = OpTypeFunction %void
+ %main_inner = OpFunction %v4float None %14
+         %16 = OpLabel
+%tint_symbol_1 = OpVariable %_ptr_Function___atomic_compare_exchange_result_i32 Function %23
+               OpSelectionMerge %17 None
+               OpBranchConditional %2 %18 %17
+         %18 = OpLabel
+               OpStore %tint_discarded %true
+               OpBranch %17
+         %17 = OpLabel
+         %25 = OpLoad %bool %tint_discarded
+         %24 = OpLogicalNot %bool %25
+               OpSelectionMerge %26 None
+               OpBranchConditional %24 %27 %26
+         %27 = OpLabel
+         %34 = OpAccessChain %_ptr_StorageBuffer_int %S %uint_0
+         %37 = OpAtomicCompareExchange %int %34 %uint_1 %uint_0 %uint_0 %int_1 %36
+         %38 = OpIEqual %bool %37 %36
+         %28 = OpCompositeConstruct %__atomic_compare_exchange_result_i32 %37 %38
+               OpStore %tint_symbol_1 %28
+               OpBranch %26
+         %26 = OpLabel
+         %39 = OpLoad %__atomic_compare_exchange_result_i32 %tint_symbol_1
+         %40 = OpCompositeExtract %int %39 0
+         %41 = OpConvertSToF %float %40
+         %42 = OpCompositeConstruct %v4float %41 %41 %41 %41
+               OpReturnValue %42
+               OpFunctionEnd
+       %main = OpFunction %void None %43
+         %46 = OpLabel
+         %47 = OpFunctionCall %v4float %main_inner
+               OpStore %value %47
+         %48 = OpLoad %bool %tint_discarded
+               OpSelectionMerge %49 None
+               OpBranchConditional %48 %50 %49
+         %50 = OpLabel
+               OpKill
+         %49 = OpLabel
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/bug/tint/2147.wgsl.expected.wgsl b/test/tint/bug/tint/2147.wgsl.expected.wgsl
new file mode 100644
index 0000000..dfb1f4d
--- /dev/null
+++ b/test/tint/bug/tint/2147.wgsl.expected.wgsl
@@ -0,0 +1,10 @@
+@group(0) @binding(0) var<storage, read_write> S : atomic<i32>;
+
+@fragment
+fn main() -> @location(0) vec4f {
+  if (false) {
+    discard;
+  }
+  let old_value = atomicCompareExchangeWeak(&(S), 0i, 1i).old_value;
+  return vec4f(f32(old_value));
+}
diff --git a/test/tint/statements/discard/atomic_cmpxchg.wgsl.expected.dxc.hlsl b/test/tint/statements/discard/atomic_cmpxchg.wgsl.expected.dxc.hlsl
index 2f5f807..a8418d6 100644
--- a/test/tint/statements/discard/atomic_cmpxchg.wgsl.expected.dxc.hlsl
+++ b/test/tint/statements/discard/atomic_cmpxchg.wgsl.expected.dxc.hlsl
@@ -3,12 +3,6 @@
   bool exchanged;
 };
 static bool tint_discarded = false;
-
-struct tint_symbol_2 {
-  int old_value;
-  bool exchanged;
-};
-
 RWByteAddressBuffer a : register(u0);
 
 struct tint_symbol {
@@ -26,13 +20,11 @@
 int foo_inner() {
   tint_discarded = true;
   int x = 0;
-  tint_symbol_2 tint_symbol_1 = (tint_symbol_2)0;
+  atomic_compare_exchange_result_i32 tint_symbol_1 = (atomic_compare_exchange_result_i32)0;
   if (!(tint_discarded)) {
-    const atomic_compare_exchange_result_i32 tint_symbol_3 = aatomicCompareExchangeWeak(0u, 0, 1);
-    tint_symbol_1.old_value = tint_symbol_3.old_value;
-    tint_symbol_1.exchanged = tint_symbol_3.exchanged;
+    tint_symbol_1 = aatomicCompareExchangeWeak(0u, 0, 1);
   }
-  const tint_symbol_2 result = tint_symbol_1;
+  const atomic_compare_exchange_result_i32 result = tint_symbol_1;
   if (result.exchanged) {
     x = result.old_value;
   }
diff --git a/test/tint/statements/discard/atomic_cmpxchg.wgsl.expected.fxc.hlsl b/test/tint/statements/discard/atomic_cmpxchg.wgsl.expected.fxc.hlsl
index 2f5f807..a8418d6 100644
--- a/test/tint/statements/discard/atomic_cmpxchg.wgsl.expected.fxc.hlsl
+++ b/test/tint/statements/discard/atomic_cmpxchg.wgsl.expected.fxc.hlsl
@@ -3,12 +3,6 @@
   bool exchanged;
 };
 static bool tint_discarded = false;
-
-struct tint_symbol_2 {
-  int old_value;
-  bool exchanged;
-};
-
 RWByteAddressBuffer a : register(u0);
 
 struct tint_symbol {
@@ -26,13 +20,11 @@
 int foo_inner() {
   tint_discarded = true;
   int x = 0;
-  tint_symbol_2 tint_symbol_1 = (tint_symbol_2)0;
+  atomic_compare_exchange_result_i32 tint_symbol_1 = (atomic_compare_exchange_result_i32)0;
   if (!(tint_discarded)) {
-    const atomic_compare_exchange_result_i32 tint_symbol_3 = aatomicCompareExchangeWeak(0u, 0, 1);
-    tint_symbol_1.old_value = tint_symbol_3.old_value;
-    tint_symbol_1.exchanged = tint_symbol_3.exchanged;
+    tint_symbol_1 = aatomicCompareExchangeWeak(0u, 0, 1);
   }
-  const tint_symbol_2 result = tint_symbol_1;
+  const atomic_compare_exchange_result_i32 result = tint_symbol_1;
   if (result.exchanged) {
     x = result.old_value;
   }
diff --git a/test/tint/statements/discard/atomic_cmpxchg.wgsl.expected.glsl b/test/tint/statements/discard/atomic_cmpxchg.wgsl.expected.glsl
index 6e53b76..a0bff77 100644
--- a/test/tint/statements/discard/atomic_cmpxchg.wgsl.expected.glsl
+++ b/test/tint/statements/discard/atomic_cmpxchg.wgsl.expected.glsl
@@ -8,11 +8,6 @@
 
 
 bool tint_discarded = false;
-struct tint_symbol_1 {
-  int old_value;
-  bool exchanged;
-};
-
 layout(location = 0) out int value;
 layout(binding = 0, std430) buffer a_block_ssbo {
   int inner;
@@ -21,16 +16,14 @@
 int foo() {
   tint_discarded = true;
   int x = 0;
-  tint_symbol_1 tint_symbol = tint_symbol_1(0, false);
+  atomic_compare_exchange_result_i32 tint_symbol = atomic_compare_exchange_result_i32(0, false);
   if (!(tint_discarded)) {
     atomic_compare_exchange_result_i32 atomic_compare_result;
     atomic_compare_result.old_value = atomicCompSwap(a.inner, 0, 1);
     atomic_compare_result.exchanged = atomic_compare_result.old_value == 0;
-    atomic_compare_exchange_result_i32 tint_symbol_2 = atomic_compare_result;
-    tint_symbol.old_value = tint_symbol_2.old_value;
-    tint_symbol.exchanged = tint_symbol_2.exchanged;
+    tint_symbol = atomic_compare_result;
   }
-  tint_symbol_1 result = tint_symbol;
+  atomic_compare_exchange_result_i32 result = tint_symbol;
   if (result.exchanged) {
     x = result.old_value;
   }
diff --git a/test/tint/statements/discard/atomic_cmpxchg.wgsl.expected.msl b/test/tint/statements/discard/atomic_cmpxchg.wgsl.expected.msl
index 5164349..0818c09 100644
--- a/test/tint/statements/discard/atomic_cmpxchg.wgsl.expected.msl
+++ b/test/tint/statements/discard/atomic_cmpxchg.wgsl.expected.msl
@@ -16,35 +16,28 @@
   bool tint_discarded;
 };
 
-struct tint_symbol_2 {
-  int old_value;
-  bool exchanged;
-};
-
 struct tint_symbol {
   int value [[color(0)]];
 };
 
-int foo_inner(thread tint_private_vars_struct* const tint_private_vars, device atomic_int* const tint_symbol_4) {
+int foo_inner(thread tint_private_vars_struct* const tint_private_vars, device atomic_int* const tint_symbol_2) {
   (*(tint_private_vars)).tint_discarded = true;
   int x = 0;
-  tint_symbol_2 tint_symbol_1 = {};
+  atomic_compare_exchange_result_i32 tint_symbol_1 = {};
   if (!((*(tint_private_vars)).tint_discarded)) {
-    atomic_compare_exchange_result_i32 const tint_symbol_3 = atomicCompareExchangeWeak_1(tint_symbol_4, 0, 1);
-    tint_symbol_1.old_value = tint_symbol_3.old_value;
-    tint_symbol_1.exchanged = tint_symbol_3.exchanged;
+    tint_symbol_1 = atomicCompareExchangeWeak_1(tint_symbol_2, 0, 1);
   }
-  tint_symbol_2 const result = tint_symbol_1;
+  atomic_compare_exchange_result_i32 const result = tint_symbol_1;
   if (result.exchanged) {
     x = result.old_value;
   }
   return x;
 }
 
-fragment tint_symbol foo(device atomic_int* tint_symbol_5 [[buffer(0)]]) {
+fragment tint_symbol foo(device atomic_int* tint_symbol_3 [[buffer(0)]]) {
   thread tint_private_vars_struct tint_private_vars = {};
   tint_private_vars.tint_discarded = false;
-  int const inner_result = foo_inner(&(tint_private_vars), tint_symbol_5);
+  int const inner_result = foo_inner(&(tint_private_vars), tint_symbol_3);
   tint_symbol wrapper_result = {};
   wrapper_result.value = inner_result;
   if (tint_private_vars.tint_discarded) {
diff --git a/test/tint/statements/discard/atomic_cmpxchg.wgsl.expected.spvasm b/test/tint/statements/discard/atomic_cmpxchg.wgsl.expected.spvasm
index fd658dc..2c0e942 100644
--- a/test/tint/statements/discard/atomic_cmpxchg.wgsl.expected.spvasm
+++ b/test/tint/statements/discard/atomic_cmpxchg.wgsl.expected.spvasm
@@ -1,7 +1,7 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 56
+; Bound: 50
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
@@ -14,21 +14,16 @@
                OpName %a "a"
                OpName %foo_inner "foo_inner"
                OpName %x "x"
-               OpName %tint_symbol_1 "tint_symbol_1"
-               OpMemberName %tint_symbol_1 0 "old_value"
-               OpMemberName %tint_symbol_1 1 "exchanged"
-               OpName %tint_symbol "tint_symbol"
                OpName %__atomic_compare_exchange_result_i32 "__atomic_compare_exchange_result_i32"
                OpMemberName %__atomic_compare_exchange_result_i32 0 "old_value"
                OpMemberName %__atomic_compare_exchange_result_i32 1 "exchanged"
+               OpName %tint_symbol "tint_symbol"
                OpName %foo "foo"
                OpDecorate %value Location 0
                OpDecorate %a_block Block
                OpMemberDecorate %a_block 0 Offset 0
                OpDecorate %a DescriptorSet 0
                OpDecorate %a Binding 0
-               OpMemberDecorate %tint_symbol_1 0 Offset 0
-               OpMemberDecorate %tint_symbol_1 1 Offset 4
                OpMemberDecorate %__atomic_compare_exchange_result_i32 0 Offset 0
                OpMemberDecorate %__atomic_compare_exchange_result_i32 1 Offset 4
        %bool = OpTypeBool
@@ -45,22 +40,20 @@
          %12 = OpTypeFunction %int
        %true = OpConstantTrue %bool
 %_ptr_Function_int = OpTypePointer Function %int
-%tint_symbol_1 = OpTypeStruct %int %bool
-%_ptr_Function_tint_symbol_1 = OpTypePointer Function %tint_symbol_1
-         %21 = OpConstantNull %tint_symbol_1
 %__atomic_compare_exchange_result_i32 = OpTypeStruct %int %bool
+%_ptr_Function___atomic_compare_exchange_result_i32 = OpTypePointer Function %__atomic_compare_exchange_result_i32
+         %21 = OpConstantNull %__atomic_compare_exchange_result_i32
        %uint = OpTypeInt 32 0
      %uint_1 = OpConstant %uint 1
      %uint_0 = OpConstant %uint 0
 %_ptr_StorageBuffer_int = OpTypePointer StorageBuffer %int
       %int_1 = OpConstant %int 1
-%_ptr_Function_bool = OpTypePointer Function %bool
        %void = OpTypeVoid
-         %48 = OpTypeFunction %void
+         %42 = OpTypeFunction %void
   %foo_inner = OpFunction %int None %12
          %14 = OpLabel
           %x = OpVariable %_ptr_Function_int Function %8
-%tint_symbol = OpVariable %_ptr_Function_tint_symbol_1 Function %21
+%tint_symbol = OpVariable %_ptr_Function___atomic_compare_exchange_result_i32 Function %21
                OpStore %tint_discarded %true
                OpStore %x %8
          %23 = OpLoad %bool %tint_discarded
@@ -68,39 +61,34 @@
                OpSelectionMerge %24 None
                OpBranchConditional %22 %25 %24
          %25 = OpLabel
-         %33 = OpAccessChain %_ptr_StorageBuffer_int %a %uint_0
-         %35 = OpAtomicCompareExchange %int %33 %uint_1 %uint_0 %uint_0 %int_1 %8
-         %36 = OpIEqual %bool %35 %8
-         %26 = OpCompositeConstruct %__atomic_compare_exchange_result_i32 %35 %36
-         %37 = OpAccessChain %_ptr_Function_int %tint_symbol %uint_0
-         %38 = OpCompositeExtract %int %26 0
-               OpStore %37 %38
-         %40 = OpAccessChain %_ptr_Function_bool %tint_symbol %uint_1
-         %41 = OpCompositeExtract %bool %26 1
-               OpStore %40 %41
+         %32 = OpAccessChain %_ptr_StorageBuffer_int %a %uint_0
+         %34 = OpAtomicCompareExchange %int %32 %uint_1 %uint_0 %uint_0 %int_1 %8
+         %35 = OpIEqual %bool %34 %8
+         %26 = OpCompositeConstruct %__atomic_compare_exchange_result_i32 %34 %35
+               OpStore %tint_symbol %26
                OpBranch %24
          %24 = OpLabel
-         %42 = OpLoad %tint_symbol_1 %tint_symbol
-         %43 = OpCompositeExtract %bool %42 1
-               OpSelectionMerge %44 None
-               OpBranchConditional %43 %45 %44
-         %45 = OpLabel
-         %46 = OpCompositeExtract %int %42 0
-               OpStore %x %46
-               OpBranch %44
-         %44 = OpLabel
-         %47 = OpLoad %int %x
-               OpReturnValue %47
+         %36 = OpLoad %__atomic_compare_exchange_result_i32 %tint_symbol
+         %37 = OpCompositeExtract %bool %36 1
+               OpSelectionMerge %38 None
+               OpBranchConditional %37 %39 %38
+         %39 = OpLabel
+         %40 = OpCompositeExtract %int %36 0
+               OpStore %x %40
+               OpBranch %38
+         %38 = OpLabel
+         %41 = OpLoad %int %x
+               OpReturnValue %41
                OpFunctionEnd
-        %foo = OpFunction %void None %48
-         %51 = OpLabel
-         %52 = OpFunctionCall %int %foo_inner
-               OpStore %value %52
-         %53 = OpLoad %bool %tint_discarded
-               OpSelectionMerge %54 None
-               OpBranchConditional %53 %55 %54
-         %55 = OpLabel
+        %foo = OpFunction %void None %42
+         %45 = OpLabel
+         %46 = OpFunctionCall %int %foo_inner
+               OpStore %value %46
+         %47 = OpLoad %bool %tint_discarded
+               OpSelectionMerge %48 None
+               OpBranchConditional %47 %49 %48
+         %49 = OpLabel
                OpKill
-         %54 = OpLabel
+         %48 = OpLabel
                OpReturn
                OpFunctionEnd