hlsl: Implement compound assignment

Use the ExpandCompoundAssignment transform to convert compound
assignments to regular assignments.

Bug: tint:1325
Change-Id: Ic843964ec24d8a2f00f801823f8f8bbf1c6fab5c
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/85284
Reviewed-by: Ben Clayton <bclayton@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
diff --git a/src/tint/writer/hlsl/generator_impl.cc b/src/tint/writer/hlsl/generator_impl.cc
index 9ed948d..a8981f9 100644
--- a/src/tint/writer/hlsl/generator_impl.cc
+++ b/src/tint/writer/hlsl/generator_impl.cc
@@ -52,6 +52,7 @@
 #include "src/tint/transform/calculate_array_length.h"
 #include "src/tint/transform/canonicalize_entry_point_io.h"
 #include "src/tint/transform/decompose_memory_access.h"
+#include "src/tint/transform/expand_compound_assignment.h"
 #include "src/tint/transform/fold_trivial_single_use_lets.h"
 #include "src/tint/transform/localize_struct_array_assignment.h"
 #include "src/tint/transform/loop_to_for_loop.h"
@@ -188,6 +189,7 @@
   // assumes that num_workgroups builtins only appear as struct members and are
   // only accessed directly via member accessors.
   manager.Add<transform::NumWorkgroupsFromUniform>();
+  manager.Add<transform::ExpandCompoundAssignment>();
   manager.Add<transform::PromoteSideEffectsToDecl>();
   manager.Add<transform::UnwindDiscardFunctions>();
   manager.Add<transform::SimplifyPointers>();
diff --git a/test/tint/statements/compound_assign/complex_lhs.wgsl.expected.hlsl b/test/tint/statements/compound_assign/complex_lhs.wgsl.expected.hlsl
index 7ba50af..c9c2c3d 100644
--- a/test/tint/statements/compound_assign/complex_lhs.wgsl.expected.hlsl
+++ b/test/tint/statements/compound_assign/complex_lhs.wgsl.expected.hlsl
@@ -1,26 +1,32 @@
-SKIP: FAILED
+void set_int4(inout int4 vec, int idx, int val) {
+  vec = (idx.xxxx == int4(0, 1, 2, 3)) ? val.xxxx : vec;
+}
 
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+  return;
+}
 
 struct S {
-  a : array<vec4<i32>, 4>,
-}
+  int4 a[4];
+};
 
-var<private> counter : i32;
+static int counter = 0;
 
-fn foo() -> i32 {
-  counter += 1;
+int foo() {
+  counter = (counter + 1);
   return counter;
 }
 
-fn bar() -> i32 {
-  counter += 2;
+int bar() {
+  counter = (counter + 2);
   return counter;
 }
 
-fn main() {
-  var x = S();
-  let p = &(x);
-  (*(p)).a[foo()][bar()] += 5;
+void main() {
+  S x = (S)0;
+  const int tint_symbol_2 = foo();
+  const int tint_symbol_save = tint_symbol_2;
+  const int tint_symbol_1 = bar();
+  set_int4(x.a[tint_symbol_save], tint_symbol_1, (x.a[tint_symbol_save][tint_symbol_1] + 5));
 }
-
-Failed to generate: error: unknown statement type: tint::ast::CompoundAssignmentStatement
diff --git a/test/tint/statements/compound_assign/divide_by_zero.wgsl.expected.hlsl b/test/tint/statements/compound_assign/divide_by_zero.wgsl.expected.hlsl
index eeec903..b90f357 100644
--- a/test/tint/statements/compound_assign/divide_by_zero.wgsl.expected.hlsl
+++ b/test/tint/statements/compound_assign/divide_by_zero.wgsl.expected.hlsl
@@ -1,19 +1,18 @@
-SKIP: FAILED
-
-
-var<private> a : i32;
-
-var<private> b : f32;
-
-fn foo(maybe_zero : i32) {
-  a /= 0;
-  a %= 0;
-  a /= maybe_zero;
-  a %= maybe_zero;
-  b /= 0.0;
-  b %= 0.0;
-  b /= f32(maybe_zero);
-  b %= f32(maybe_zero);
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+  return;
 }
 
-Failed to generate: error: unknown statement type: tint::ast::CompoundAssignmentStatement
+static int a = 0;
+static float b = 0.0f;
+
+void foo(int maybe_zero) {
+  a = (a / 1);
+  a = (a % 1);
+  a = (a / (maybe_zero == 0 ? 1 : maybe_zero));
+  a = (a % (maybe_zero == 0 ? 1 : maybe_zero));
+  b = (b / 0.0f);
+  b = (b % 0.0f);
+  b = (b / float(maybe_zero));
+  b = (b % float(maybe_zero));
+}
diff --git a/test/tint/statements/compound_assign/for_loop.wgsl.expected.hlsl b/test/tint/statements/compound_assign/for_loop.wgsl.expected.hlsl
index 2903ab7..53bd1a0 100644
--- a/test/tint/statements/compound_assign/for_loop.wgsl.expected.hlsl
+++ b/test/tint/statements/compound_assign/for_loop.wgsl.expected.hlsl
@@ -1,35 +1,44 @@
-SKIP: FAILED
-
-
-struct S {
-  a : i32,
-  b : vec4<f32>,
-  c : mat2x2<f32>,
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+  return;
 }
 
-@group(0) @binding(0) var<storage, read_write> v : S;
+RWByteAddressBuffer v : register(u0, space0);
+static uint i = 0u;
 
-var<private> i : u32;
-
-fn idx1() -> i32 {
-  i += 1u;
+int idx1() {
+  i = (i + 1u);
   return 1;
 }
 
-fn idx2() -> i32 {
-  i += 2u;
+int idx2() {
+  i = (i + 2u);
   return 1;
 }
 
-fn idx3() -> i32 {
-  i += 3u;
+int idx3() {
+  i = (i + 3u);
   return 1;
 }
 
-fn foo() {
-  var a = array<f32, 4>();
-  for(a[idx1()] *= 2.0; (a[idx2()] < 10.0); a[idx3()] += 1.0) {
+void foo() {
+  float a[4] = (float[4])0;
+  const int tint_symbol_2 = idx1();
+  const int tint_symbol_save = tint_symbol_2;
+  {
+    a[tint_symbol_save] = (a[tint_symbol_save] * 2.0f);
+    [loop] while (true) {
+      const int tint_symbol_3 = idx2();
+      if (!((a[tint_symbol_3] < 10.0f))) {
+        break;
+      }
+      {
+      }
+      {
+        const int tint_symbol_4 = idx3();
+        const int tint_symbol_1_save = tint_symbol_4;
+        a[tint_symbol_1_save] = (a[tint_symbol_1_save] + 1.0f);
+      }
+    }
   }
 }
-
-Failed to generate: error: unknown statement type: tint::ast::CompoundAssignmentStatement
diff --git a/test/tint/statements/compound_assign/function.wgsl.expected.hlsl b/test/tint/statements/compound_assign/function.wgsl.expected.hlsl
index 1d0e27a..da9f1de 100644
--- a/test/tint/statements/compound_assign/function.wgsl.expected.hlsl
+++ b/test/tint/statements/compound_assign/function.wgsl.expected.hlsl
@@ -1,13 +1,13 @@
-SKIP: FAILED
-
-
-fn foo() {
-  var<function> a : i32;
-  var<function> b : vec4<f32>;
-  var<function> c : mat2x2<f32>;
-  a /= 2;
-  b *= mat4x4<f32>();
-  c *= 2.0;
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+  return;
 }
 
-Failed to generate: error: unknown statement type: tint::ast::CompoundAssignmentStatement
+void foo() {
+  int a = 0;
+  float4 b = float4(0.0f, 0.0f, 0.0f, 0.0f);
+  float2x2 c = float2x2(0.0f, 0.0f, 0.0f, 0.0f);
+  a = (a / 2);
+  b = mul(float4x4(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), b);
+  c = (c * 2.0f);
+}
diff --git a/test/tint/statements/compound_assign/matrix/minus.wgsl.expected.hlsl b/test/tint/statements/compound_assign/matrix/minus.wgsl.expected.hlsl
index 12462f0..dc28af6 100644
--- a/test/tint/statements/compound_assign/matrix/minus.wgsl.expected.hlsl
+++ b/test/tint/statements/compound_assign/matrix/minus.wgsl.expected.hlsl
@@ -1,14 +1,21 @@
-SKIP: FAILED
-
-
-struct S {
-  a : mat4x4<f32>,
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+  return;
 }
 
-@group(0) @binding(0) var<storage, read_write> v : S;
+RWByteAddressBuffer v : register(u0, space0);
 
-fn foo() {
-  v.a -= mat4x4<f32>();
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, float4x4 value) {
+  buffer.Store4((offset + 0u), asuint(value[0u]));
+  buffer.Store4((offset + 16u), asuint(value[1u]));
+  buffer.Store4((offset + 32u), asuint(value[2u]));
+  buffer.Store4((offset + 48u), asuint(value[3u]));
 }
 
-Failed to generate: error: cannot assign to value of type 'mat4x4<f32>'
+float4x4 tint_symbol_2(RWByteAddressBuffer buffer, uint offset) {
+  return float4x4(asfloat(buffer.Load4((offset + 0u))), asfloat(buffer.Load4((offset + 16u))), asfloat(buffer.Load4((offset + 32u))), asfloat(buffer.Load4((offset + 48u))));
+}
+
+void foo() {
+  tint_symbol(v, 0u, (tint_symbol_2(v, 0u) - float4x4(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)));
+}
diff --git a/test/tint/statements/compound_assign/matrix/plus.wgsl.expected.hlsl b/test/tint/statements/compound_assign/matrix/plus.wgsl.expected.hlsl
index f227f3c..b4d6c77 100644
--- a/test/tint/statements/compound_assign/matrix/plus.wgsl.expected.hlsl
+++ b/test/tint/statements/compound_assign/matrix/plus.wgsl.expected.hlsl
@@ -1,14 +1,21 @@
-SKIP: FAILED
-
-
-struct S {
-  a : mat4x4<f32>,
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+  return;
 }
 
-@group(0) @binding(0) var<storage, read_write> v : S;
+RWByteAddressBuffer v : register(u0, space0);
 
-fn foo() {
-  v.a += mat4x4<f32>();
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, float4x4 value) {
+  buffer.Store4((offset + 0u), asuint(value[0u]));
+  buffer.Store4((offset + 16u), asuint(value[1u]));
+  buffer.Store4((offset + 32u), asuint(value[2u]));
+  buffer.Store4((offset + 48u), asuint(value[3u]));
 }
 
-Failed to generate: error: cannot assign to value of type 'mat4x4<f32>'
+float4x4 tint_symbol_2(RWByteAddressBuffer buffer, uint offset) {
+  return float4x4(asfloat(buffer.Load4((offset + 0u))), asfloat(buffer.Load4((offset + 16u))), asfloat(buffer.Load4((offset + 32u))), asfloat(buffer.Load4((offset + 48u))));
+}
+
+void foo() {
+  tint_symbol(v, 0u, (tint_symbol_2(v, 0u) + float4x4(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)));
+}
diff --git a/test/tint/statements/compound_assign/matrix/times-scalar.wgsl.expected.hlsl b/test/tint/statements/compound_assign/matrix/times-scalar.wgsl.expected.hlsl
index ed559f7..24236fd 100644
--- a/test/tint/statements/compound_assign/matrix/times-scalar.wgsl.expected.hlsl
+++ b/test/tint/statements/compound_assign/matrix/times-scalar.wgsl.expected.hlsl
@@ -1,14 +1,21 @@
-SKIP: FAILED
-
-
-struct S {
-  a : mat4x4<f32>,
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+  return;
 }
 
-@group(0) @binding(0) var<storage, read_write> v : S;
+RWByteAddressBuffer v : register(u0, space0);
 
-fn foo() {
-  v.a *= 2.0;
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, float4x4 value) {
+  buffer.Store4((offset + 0u), asuint(value[0u]));
+  buffer.Store4((offset + 16u), asuint(value[1u]));
+  buffer.Store4((offset + 32u), asuint(value[2u]));
+  buffer.Store4((offset + 48u), asuint(value[3u]));
 }
 
-Failed to generate: error: cannot assign to value of type 'mat4x4<f32>'
+float4x4 tint_symbol_2(RWByteAddressBuffer buffer, uint offset) {
+  return float4x4(asfloat(buffer.Load4((offset + 0u))), asfloat(buffer.Load4((offset + 16u))), asfloat(buffer.Load4((offset + 32u))), asfloat(buffer.Load4((offset + 48u))));
+}
+
+void foo() {
+  tint_symbol(v, 0u, (tint_symbol_2(v, 0u) * 2.0f));
+}
diff --git a/test/tint/statements/compound_assign/matrix/times.wgsl.expected.hlsl b/test/tint/statements/compound_assign/matrix/times.wgsl.expected.hlsl
index 6132eae..464338c 100644
--- a/test/tint/statements/compound_assign/matrix/times.wgsl.expected.hlsl
+++ b/test/tint/statements/compound_assign/matrix/times.wgsl.expected.hlsl
@@ -1,14 +1,21 @@
-SKIP: FAILED
-
-
-struct S {
-  a : mat4x4<f32>,
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+  return;
 }
 
-@group(0) @binding(0) var<storage, read_write> v : S;
+RWByteAddressBuffer v : register(u0, space0);
 
-fn foo() {
-  v.a *= mat4x4<f32>();
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, float4x4 value) {
+  buffer.Store4((offset + 0u), asuint(value[0u]));
+  buffer.Store4((offset + 16u), asuint(value[1u]));
+  buffer.Store4((offset + 32u), asuint(value[2u]));
+  buffer.Store4((offset + 48u), asuint(value[3u]));
 }
 
-Failed to generate: error: cannot assign to value of type 'mat4x4<f32>'
+float4x4 tint_symbol_2(RWByteAddressBuffer buffer, uint offset) {
+  return float4x4(asfloat(buffer.Load4((offset + 0u))), asfloat(buffer.Load4((offset + 16u))), asfloat(buffer.Load4((offset + 32u))), asfloat(buffer.Load4((offset + 48u))));
+}
+
+void foo() {
+  tint_symbol(v, 0u, mul(float4x4(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), tint_symbol_2(v, 0u)));
+}
diff --git a/test/tint/statements/compound_assign/private.wgsl.expected.hlsl b/test/tint/statements/compound_assign/private.wgsl.expected.hlsl
index c655dcf..469c402 100644
--- a/test/tint/statements/compound_assign/private.wgsl.expected.hlsl
+++ b/test/tint/statements/compound_assign/private.wgsl.expected.hlsl
@@ -1,16 +1,14 @@
-SKIP: FAILED
-
-
-var<private> a : i32;
-
-var<private> b : vec4<f32>;
-
-var<private> c : mat2x2<f32>;
-
-fn foo() {
-  a /= 2;
-  b *= mat4x4<f32>();
-  c *= 2.0;
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+  return;
 }
 
-Failed to generate: error: unknown statement type: tint::ast::CompoundAssignmentStatement
+static int a = 0;
+static float4 b = float4(0.0f, 0.0f, 0.0f, 0.0f);
+static float2x2 c = float2x2(0.0f, 0.0f, 0.0f, 0.0f);
+
+void foo() {
+  a = (a / 2);
+  b = mul(float4x4(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), b);
+  c = (c * 2.0f);
+}
diff --git a/test/tint/statements/compound_assign/scalar/and.wgsl.expected.hlsl b/test/tint/statements/compound_assign/scalar/and.wgsl.expected.hlsl
index f0ed522..8af8952 100644
--- a/test/tint/statements/compound_assign/scalar/and.wgsl.expected.hlsl
+++ b/test/tint/statements/compound_assign/scalar/and.wgsl.expected.hlsl
@@ -1,14 +1,10 @@
-SKIP: FAILED
-
-
-struct S {
-  a : i32,
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+  return;
 }
 
-@group(0) @binding(0) var<storage, read_write> v : S;
+RWByteAddressBuffer v : register(u0, space0);
 
-fn foo() {
-  v.a &= 2;
+void foo() {
+  v.Store(0u, asuint((asint(v.Load(0u)) & 2)));
 }
-
-Failed to generate: error: cannot assign to value of type 'i32'
diff --git a/test/tint/statements/compound_assign/scalar/divide.wgsl.expected.hlsl b/test/tint/statements/compound_assign/scalar/divide.wgsl.expected.hlsl
index 6ceb4c3..affbb2b 100644
--- a/test/tint/statements/compound_assign/scalar/divide.wgsl.expected.hlsl
+++ b/test/tint/statements/compound_assign/scalar/divide.wgsl.expected.hlsl
@@ -1,14 +1,10 @@
-SKIP: FAILED
-
-
-struct S {
-  a : i32,
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+  return;
 }
 
-@group(0) @binding(0) var<storage, read_write> v : S;
+RWByteAddressBuffer v : register(u0, space0);
 
-fn foo() {
-  v.a /= 2;
+void foo() {
+  v.Store(0u, asuint((asint(v.Load(0u)) / 2)));
 }
-
-Failed to generate: error: cannot assign to value of type 'i32'
diff --git a/test/tint/statements/compound_assign/scalar/minus.wgsl.expected.hlsl b/test/tint/statements/compound_assign/scalar/minus.wgsl.expected.hlsl
index f878485..1b557a1 100644
--- a/test/tint/statements/compound_assign/scalar/minus.wgsl.expected.hlsl
+++ b/test/tint/statements/compound_assign/scalar/minus.wgsl.expected.hlsl
@@ -1,14 +1,10 @@
-SKIP: FAILED
-
-
-struct S {
-  a : i32,
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+  return;
 }
 
-@group(0) @binding(0) var<storage, read_write> v : S;
+RWByteAddressBuffer v : register(u0, space0);
 
-fn foo() {
-  v.a -= 2;
+void foo() {
+  v.Store(0u, asuint((asint(v.Load(0u)) - 2)));
 }
-
-Failed to generate: error: cannot assign to value of type 'i32'
diff --git a/test/tint/statements/compound_assign/scalar/modulo.wgsl.expected.hlsl b/test/tint/statements/compound_assign/scalar/modulo.wgsl.expected.hlsl
index 24d87bd..fec5816 100644
--- a/test/tint/statements/compound_assign/scalar/modulo.wgsl.expected.hlsl
+++ b/test/tint/statements/compound_assign/scalar/modulo.wgsl.expected.hlsl
@@ -1,14 +1,10 @@
-SKIP: FAILED
-
-
-struct S {
-  a : i32,
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+  return;
 }
 
-@group(0) @binding(0) var<storage, read_write> v : S;
+RWByteAddressBuffer v : register(u0, space0);
 
-fn foo() {
-  v.a %= 2;
+void foo() {
+  v.Store(0u, asuint((asint(v.Load(0u)) % 2)));
 }
-
-Failed to generate: error: cannot assign to value of type 'i32'
diff --git a/test/tint/statements/compound_assign/scalar/or.wgsl.expected.hlsl b/test/tint/statements/compound_assign/scalar/or.wgsl.expected.hlsl
index 15ce0f2..309c612 100644
--- a/test/tint/statements/compound_assign/scalar/or.wgsl.expected.hlsl
+++ b/test/tint/statements/compound_assign/scalar/or.wgsl.expected.hlsl
@@ -1,14 +1,10 @@
-SKIP: FAILED
-
-
-struct S {
-  a : i32,
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+  return;
 }
 
-@group(0) @binding(0) var<storage, read_write> v : S;
+RWByteAddressBuffer v : register(u0, space0);
 
-fn foo() {
-  v.a |= 2;
+void foo() {
+  v.Store(0u, asuint((asint(v.Load(0u)) | 2)));
 }
-
-Failed to generate: error: cannot assign to value of type 'i32'
diff --git a/test/tint/statements/compound_assign/scalar/plus.wgsl.expected.hlsl b/test/tint/statements/compound_assign/scalar/plus.wgsl.expected.hlsl
index c8629d3..20f9d1c 100644
--- a/test/tint/statements/compound_assign/scalar/plus.wgsl.expected.hlsl
+++ b/test/tint/statements/compound_assign/scalar/plus.wgsl.expected.hlsl
@@ -1,14 +1,10 @@
-SKIP: FAILED
-
-
-struct S {
-  a : i32,
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+  return;
 }
 
-@group(0) @binding(0) var<storage, read_write> v : S;
+RWByteAddressBuffer v : register(u0, space0);
 
-fn foo() {
-  v.a += 2;
+void foo() {
+  v.Store(0u, asuint((asint(v.Load(0u)) + 2)));
 }
-
-Failed to generate: error: cannot assign to value of type 'i32'
diff --git a/test/tint/statements/compound_assign/scalar/times.wgsl.expected.hlsl b/test/tint/statements/compound_assign/scalar/times.wgsl.expected.hlsl
index 136c564..2735d37 100644
--- a/test/tint/statements/compound_assign/scalar/times.wgsl.expected.hlsl
+++ b/test/tint/statements/compound_assign/scalar/times.wgsl.expected.hlsl
@@ -1,14 +1,10 @@
-SKIP: FAILED
-
-
-struct S {
-  a : i32,
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+  return;
 }
 
-@group(0) @binding(0) var<storage, read_write> v : S;
+RWByteAddressBuffer v : register(u0, space0);
 
-fn foo() {
-  v.a *= 2;
+void foo() {
+  v.Store(0u, asuint((asint(v.Load(0u)) * 2)));
 }
-
-Failed to generate: error: cannot assign to value of type 'i32'
diff --git a/test/tint/statements/compound_assign/scalar/xor.wgsl.expected.hlsl b/test/tint/statements/compound_assign/scalar/xor.wgsl.expected.hlsl
index 7a8bb45..69a4c5e 100644
--- a/test/tint/statements/compound_assign/scalar/xor.wgsl.expected.hlsl
+++ b/test/tint/statements/compound_assign/scalar/xor.wgsl.expected.hlsl
@@ -1,14 +1,10 @@
-SKIP: FAILED
-
-
-struct S {
-  a : i32,
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+  return;
 }
 
-@group(0) @binding(0) var<storage, read_write> v : S;
+RWByteAddressBuffer v : register(u0, space0);
 
-fn foo() {
-  v.a ^= 2;
+void foo() {
+  v.Store(0u, asuint((asint(v.Load(0u)) ^ 2)));
 }
-
-Failed to generate: error: cannot assign to value of type 'i32'
diff --git a/test/tint/statements/compound_assign/vector/and.wgsl.expected.hlsl b/test/tint/statements/compound_assign/vector/and.wgsl.expected.hlsl
index fb13cb3..34c5c0d 100644
--- a/test/tint/statements/compound_assign/vector/and.wgsl.expected.hlsl
+++ b/test/tint/statements/compound_assign/vector/and.wgsl.expected.hlsl
@@ -1,14 +1,10 @@
-SKIP: FAILED
-
-
-struct S {
-  a : vec4<i32>,
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+  return;
 }
 
-@group(0) @binding(0) var<storage, read_write> v : S;
+RWByteAddressBuffer v : register(u0, space0);
 
-fn foo() {
-  v.a &= vec4<i32>(2);
+void foo() {
+  v.Store4(0u, asuint((asint(v.Load4(0u)) & int4((2).xxxx))));
 }
-
-Failed to generate: error: cannot assign to value of type 'vec4<i32>'
diff --git a/test/tint/statements/compound_assign/vector/divide-scalar.wgsl.expected.hlsl b/test/tint/statements/compound_assign/vector/divide-scalar.wgsl.expected.hlsl
index 082db55..e0b7c7b 100644
--- a/test/tint/statements/compound_assign/vector/divide-scalar.wgsl.expected.hlsl
+++ b/test/tint/statements/compound_assign/vector/divide-scalar.wgsl.expected.hlsl
@@ -1,14 +1,10 @@
-SKIP: FAILED
-
-
-struct S {
-  a : vec4<f32>,
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+  return;
 }
 
-@group(0) @binding(0) var<storage, read_write> v : S;
+RWByteAddressBuffer v : register(u0, space0);
 
-fn foo() {
-  v.a /= 2.0;
+void foo() {
+  v.Store4(0u, asuint((asfloat(v.Load4(0u)) / 2.0f)));
 }
-
-Failed to generate: error: cannot assign to value of type 'vec4<f32>'
diff --git a/test/tint/statements/compound_assign/vector/divide.wgsl.expected.hlsl b/test/tint/statements/compound_assign/vector/divide.wgsl.expected.hlsl
index 309e2f9..8ef0666 100644
--- a/test/tint/statements/compound_assign/vector/divide.wgsl.expected.hlsl
+++ b/test/tint/statements/compound_assign/vector/divide.wgsl.expected.hlsl
@@ -1,14 +1,10 @@
-SKIP: FAILED
-
-
-struct S {
-  a : vec4<i32>,
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+  return;
 }
 
-@group(0) @binding(0) var<storage, read_write> v : S;
+RWByteAddressBuffer v : register(u0, space0);
 
-fn foo() {
-  v.a /= vec4<i32>(2);
+void foo() {
+  v.Store4(0u, asuint((asint(v.Load4(0u)) / int4((2).xxxx))));
 }
-
-Failed to generate: error: cannot assign to value of type 'vec4<i32>'
diff --git a/test/tint/statements/compound_assign/vector/minus-scalar.wgsl.expected.hlsl b/test/tint/statements/compound_assign/vector/minus-scalar.wgsl.expected.hlsl
index 5cd4dbc..9309375 100644
--- a/test/tint/statements/compound_assign/vector/minus-scalar.wgsl.expected.hlsl
+++ b/test/tint/statements/compound_assign/vector/minus-scalar.wgsl.expected.hlsl
@@ -1,14 +1,10 @@
-SKIP: FAILED
-
-
-struct S {
-  a : vec4<f32>,
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+  return;
 }
 
-@group(0) @binding(0) var<storage, read_write> v : S;
+RWByteAddressBuffer v : register(u0, space0);
 
-fn foo() {
-  v.a -= 2.0;
+void foo() {
+  v.Store4(0u, asuint((asfloat(v.Load4(0u)) - 2.0f)));
 }
-
-Failed to generate: error: cannot assign to value of type 'vec4<f32>'
diff --git a/test/tint/statements/compound_assign/vector/minus.wgsl.expected.hlsl b/test/tint/statements/compound_assign/vector/minus.wgsl.expected.hlsl
index 6eab7f8..15e224f 100644
--- a/test/tint/statements/compound_assign/vector/minus.wgsl.expected.hlsl
+++ b/test/tint/statements/compound_assign/vector/minus.wgsl.expected.hlsl
@@ -1,14 +1,10 @@
-SKIP: FAILED
-
-
-struct S {
-  a : vec4<i32>,
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+  return;
 }
 
-@group(0) @binding(0) var<storage, read_write> v : S;
+RWByteAddressBuffer v : register(u0, space0);
 
-fn foo() {
-  v.a -= vec4<i32>(2);
+void foo() {
+  v.Store4(0u, asuint((asint(v.Load4(0u)) - int4((2).xxxx))));
 }
-
-Failed to generate: error: cannot assign to value of type 'vec4<i32>'
diff --git a/test/tint/statements/compound_assign/vector/modulo-scalar.wgsl.expected.hlsl b/test/tint/statements/compound_assign/vector/modulo-scalar.wgsl.expected.hlsl
index 4b030d5..f5f8675 100644
--- a/test/tint/statements/compound_assign/vector/modulo-scalar.wgsl.expected.hlsl
+++ b/test/tint/statements/compound_assign/vector/modulo-scalar.wgsl.expected.hlsl
@@ -1,14 +1,10 @@
-SKIP: FAILED
-
-
-struct S {
-  a : vec4<i32>,
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+  return;
 }
 
-@group(0) @binding(0) var<storage, read_write> v : S;
+RWByteAddressBuffer v : register(u0, space0);
 
-fn foo() {
-  v.a %= 2;
+void foo() {
+  v.Store4(0u, asuint((asint(v.Load4(0u)) % 2)));
 }
-
-Failed to generate: error: cannot assign to value of type 'vec4<i32>'
diff --git a/test/tint/statements/compound_assign/vector/modulo.wgsl.expected.hlsl b/test/tint/statements/compound_assign/vector/modulo.wgsl.expected.hlsl
index 076b36f..8c38a69 100644
--- a/test/tint/statements/compound_assign/vector/modulo.wgsl.expected.hlsl
+++ b/test/tint/statements/compound_assign/vector/modulo.wgsl.expected.hlsl
@@ -1,14 +1,10 @@
-SKIP: FAILED
-
-
-struct S {
-  a : vec4<i32>,
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+  return;
 }
 
-@group(0) @binding(0) var<storage, read_write> v : S;
+RWByteAddressBuffer v : register(u0, space0);
 
-fn foo() {
-  v.a %= vec4<i32>(2);
+void foo() {
+  v.Store4(0u, asuint((asint(v.Load4(0u)) % int4((2).xxxx))));
 }
-
-Failed to generate: error: cannot assign to value of type 'vec4<i32>'
diff --git a/test/tint/statements/compound_assign/vector/or.wgsl.expected.hlsl b/test/tint/statements/compound_assign/vector/or.wgsl.expected.hlsl
index 1b844da..f8b82af 100644
--- a/test/tint/statements/compound_assign/vector/or.wgsl.expected.hlsl
+++ b/test/tint/statements/compound_assign/vector/or.wgsl.expected.hlsl
@@ -1,14 +1,10 @@
-SKIP: FAILED
-
-
-struct S {
-  a : vec4<i32>,
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+  return;
 }
 
-@group(0) @binding(0) var<storage, read_write> v : S;
+RWByteAddressBuffer v : register(u0, space0);
 
-fn foo() {
-  v.a |= vec4<i32>(2);
+void foo() {
+  v.Store4(0u, asuint((asint(v.Load4(0u)) | int4((2).xxxx))));
 }
-
-Failed to generate: error: cannot assign to value of type 'vec4<i32>'
diff --git a/test/tint/statements/compound_assign/vector/plus-scalar.wgsl.expected.hlsl b/test/tint/statements/compound_assign/vector/plus-scalar.wgsl.expected.hlsl
index a3cacaa..40c7df0 100644
--- a/test/tint/statements/compound_assign/vector/plus-scalar.wgsl.expected.hlsl
+++ b/test/tint/statements/compound_assign/vector/plus-scalar.wgsl.expected.hlsl
@@ -1,14 +1,10 @@
-SKIP: FAILED
-
-
-struct S {
-  a : vec4<f32>,
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+  return;
 }
 
-@group(0) @binding(0) var<storage, read_write> v : S;
+RWByteAddressBuffer v : register(u0, space0);
 
-fn foo() {
-  v.a += 2.0;
+void foo() {
+  v.Store4(0u, asuint((asfloat(v.Load4(0u)) + 2.0f)));
 }
-
-Failed to generate: error: cannot assign to value of type 'vec4<f32>'
diff --git a/test/tint/statements/compound_assign/vector/plus.wgsl.expected.hlsl b/test/tint/statements/compound_assign/vector/plus.wgsl.expected.hlsl
index 7405e1d..10269a0 100644
--- a/test/tint/statements/compound_assign/vector/plus.wgsl.expected.hlsl
+++ b/test/tint/statements/compound_assign/vector/plus.wgsl.expected.hlsl
@@ -1,14 +1,10 @@
-SKIP: FAILED
-
-
-struct S {
-  a : vec4<i32>,
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+  return;
 }
 
-@group(0) @binding(0) var<storage, read_write> v : S;
+RWByteAddressBuffer v : register(u0, space0);
 
-fn foo() {
-  v.a += vec4<i32>(2);
+void foo() {
+  v.Store4(0u, asuint((asint(v.Load4(0u)) + int4((2).xxxx))));
 }
-
-Failed to generate: error: cannot assign to value of type 'vec4<i32>'
diff --git a/test/tint/statements/compound_assign/vector/times-matrix.wgsl.expected.hlsl b/test/tint/statements/compound_assign/vector/times-matrix.wgsl.expected.hlsl
index 92704de..c4083be 100644
--- a/test/tint/statements/compound_assign/vector/times-matrix.wgsl.expected.hlsl
+++ b/test/tint/statements/compound_assign/vector/times-matrix.wgsl.expected.hlsl
@@ -1,14 +1,10 @@
-SKIP: FAILED
-
-
-struct S {
-  a : vec4<f32>,
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+  return;
 }
 
-@group(0) @binding(0) var<storage, read_write> v : S;
+RWByteAddressBuffer v : register(u0, space0);
 
-fn foo() {
-  v.a *= mat4x4<f32>();
+void foo() {
+  v.Store4(0u, asuint(mul(float4x4(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), asfloat(v.Load4(0u)))));
 }
-
-Failed to generate: error: cannot assign to value of type 'vec4<f32>'
diff --git a/test/tint/statements/compound_assign/vector/times-scalar.wgsl.expected.hlsl b/test/tint/statements/compound_assign/vector/times-scalar.wgsl.expected.hlsl
index 1e026cd..67f16d8 100644
--- a/test/tint/statements/compound_assign/vector/times-scalar.wgsl.expected.hlsl
+++ b/test/tint/statements/compound_assign/vector/times-scalar.wgsl.expected.hlsl
@@ -1,14 +1,10 @@
-SKIP: FAILED
-
-
-struct S {
-  a : vec4<f32>,
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+  return;
 }
 
-@group(0) @binding(0) var<storage, read_write> v : S;
+RWByteAddressBuffer v : register(u0, space0);
 
-fn foo() {
-  v.a *= 2.0;
+void foo() {
+  v.Store4(0u, asuint((asfloat(v.Load4(0u)) * 2.0f)));
 }
-
-Failed to generate: error: cannot assign to value of type 'vec4<f32>'
diff --git a/test/tint/statements/compound_assign/vector/times.wgsl.expected.hlsl b/test/tint/statements/compound_assign/vector/times.wgsl.expected.hlsl
index 31340f9..7b9a6bd 100644
--- a/test/tint/statements/compound_assign/vector/times.wgsl.expected.hlsl
+++ b/test/tint/statements/compound_assign/vector/times.wgsl.expected.hlsl
@@ -1,14 +1,10 @@
-SKIP: FAILED
-
-
-struct S {
-  a : vec4<i32>,
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+  return;
 }
 
-@group(0) @binding(0) var<storage, read_write> v : S;
+RWByteAddressBuffer v : register(u0, space0);
 
-fn foo() {
-  v.a *= vec4<i32>(2);
+void foo() {
+  v.Store4(0u, asuint((asint(v.Load4(0u)) * int4((2).xxxx))));
 }
-
-Failed to generate: error: cannot assign to value of type 'vec4<i32>'
diff --git a/test/tint/statements/compound_assign/vector/xor.wgsl.expected.hlsl b/test/tint/statements/compound_assign/vector/xor.wgsl.expected.hlsl
index b325284..a76154a 100644
--- a/test/tint/statements/compound_assign/vector/xor.wgsl.expected.hlsl
+++ b/test/tint/statements/compound_assign/vector/xor.wgsl.expected.hlsl
@@ -1,14 +1,10 @@
-SKIP: FAILED
-
-
-struct S {
-  a : vec4<i32>,
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+  return;
 }
 
-@group(0) @binding(0) var<storage, read_write> v : S;
+RWByteAddressBuffer v : register(u0, space0);
 
-fn foo() {
-  v.a ^= vec4<i32>(2);
+void foo() {
+  v.Store4(0u, asuint((asint(v.Load4(0u)) ^ int4((2).xxxx))));
 }
-
-Failed to generate: error: cannot assign to value of type 'vec4<i32>'
diff --git a/test/tint/statements/compound_assign/workgroup.wgsl.expected.hlsl b/test/tint/statements/compound_assign/workgroup.wgsl.expected.hlsl
index 5cdf29f..1f7527b 100644
--- a/test/tint/statements/compound_assign/workgroup.wgsl.expected.hlsl
+++ b/test/tint/statements/compound_assign/workgroup.wgsl.expected.hlsl
@@ -1,16 +1,14 @@
-SKIP: FAILED
-
-
-var<workgroup> a : i32;
-
-var<workgroup> b : vec4<f32>;
-
-var<workgroup> c : mat2x2<f32>;
-
-fn foo() {
-  a /= 2;
-  b *= mat4x4<f32>();
-  c *= 2.0;
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+  return;
 }
 
-Failed to generate: error: unknown statement type: tint::ast::CompoundAssignmentStatement
+groupshared int a;
+groupshared float4 b;
+groupshared float2x2 c;
+
+void foo() {
+  a = (a / 2);
+  b = mul(float4x4(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), b);
+  c = (c * 2.0f);
+}