test: Split binary_expressions into separate tests

Tests should be as fine-grained as possible.
Not all the permutations were covered.
Not all the backends were actually generating anything useful, as the
functions were not called by an entry point.

Change-Id: I76658533d3112d202f7482a19531079550e66f83
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/58392
Auto-Submit: Ben Clayton <bclayton@google.com>
Commit-Queue: David Neto <dneto@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: David Neto <dneto@google.com>
diff --git a/test/expressions/binary/add/mat3x3-mat3x3/f32.wgsl b/test/expressions/binary/add/mat3x3-mat3x3/f32.wgsl
new file mode 100644
index 0000000..403b87f
--- /dev/null
+++ b/test/expressions/binary/add/mat3x3-mat3x3/f32.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+    let a = mat3x3<f32>(vec3<f32>( 1.,  2.,  3.), vec3<f32>( 4.,  5.,  6.), vec3<f32>( 7.,  8.,  9.));
+    let b = mat3x3<f32>(vec3<f32>(-1., -2., -3.), vec3<f32>(-4., -5., -6.), vec3<f32>(-7., -8., -9.));
+    let r : mat3x3<f32> = a + b;
+}
diff --git a/test/expressions/binary/add/mat3x3-mat3x3/f32.wgsl.expected.hlsl b/test/expressions/binary/add/mat3x3-mat3x3/f32.wgsl.expected.hlsl
new file mode 100644
index 0000000..e20dd07
--- /dev/null
+++ b/test/expressions/binary/add/mat3x3-mat3x3/f32.wgsl.expected.hlsl
@@ -0,0 +1,7 @@
+[numthreads(1, 1, 1)]
+void f() {
+  const float3x3 a = float3x3(float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f), float3(7.0f, 8.0f, 9.0f));
+  const float3x3 b = float3x3(float3(-1.0f, -2.0f, -3.0f), float3(-4.0f, -5.0f, -6.0f), float3(-7.0f, -8.0f, -9.0f));
+  const float3x3 r = (a + b);
+  return;
+}
diff --git a/test/expressions/binary/add/mat3x3-mat3x3/f32.wgsl.expected.msl b/test/expressions/binary/add/mat3x3-mat3x3/f32.wgsl.expected.msl
new file mode 100644
index 0000000..4c6ced5
--- /dev/null
+++ b/test/expressions/binary/add/mat3x3-mat3x3/f32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f() {
+  float3x3 const a = float3x3(float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f), float3(7.0f, 8.0f, 9.0f));
+  float3x3 const b = float3x3(float3(-1.0f, -2.0f, -3.0f), float3(-4.0f, -5.0f, -6.0f), float3(-7.0f, -8.0f, -9.0f));
+  float3x3 const r = (a + b);
+  return;
+}
+
diff --git a/test/expressions/binary/add/mat3x3-mat3x3/f32.wgsl.expected.spvasm b/test/expressions/binary/add/mat3x3-mat3x3/f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..12f96a5
--- /dev/null
+++ b/test/expressions/binary/add/mat3x3-mat3x3/f32.wgsl.expected.spvasm
@@ -0,0 +1,55 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 45
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %f "f"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+%mat3v3float = OpTypeMatrix %v3float 3
+    %float_1 = OpConstant %float 1
+    %float_2 = OpConstant %float 2
+    %float_3 = OpConstant %float 3
+         %11 = OpConstantComposite %v3float %float_1 %float_2 %float_3
+    %float_4 = OpConstant %float 4
+    %float_5 = OpConstant %float 5
+    %float_6 = OpConstant %float 6
+         %15 = OpConstantComposite %v3float %float_4 %float_5 %float_6
+    %float_7 = OpConstant %float 7
+    %float_8 = OpConstant %float 8
+    %float_9 = OpConstant %float 9
+         %19 = OpConstantComposite %v3float %float_7 %float_8 %float_9
+         %20 = OpConstantComposite %mat3v3float %11 %15 %19
+   %float_n1 = OpConstant %float -1
+   %float_n2 = OpConstant %float -2
+   %float_n3 = OpConstant %float -3
+         %24 = OpConstantComposite %v3float %float_n1 %float_n2 %float_n3
+   %float_n4 = OpConstant %float -4
+   %float_n5 = OpConstant %float -5
+   %float_n6 = OpConstant %float -6
+         %28 = OpConstantComposite %v3float %float_n4 %float_n5 %float_n6
+   %float_n7 = OpConstant %float -7
+   %float_n8 = OpConstant %float -8
+   %float_n9 = OpConstant %float -9
+         %32 = OpConstantComposite %v3float %float_n7 %float_n8 %float_n9
+         %33 = OpConstantComposite %mat3v3float %24 %28 %32
+          %f = OpFunction %void None %1
+          %4 = OpLabel
+         %35 = OpCompositeExtract %v3float %20 0
+         %36 = OpCompositeExtract %v3float %33 0
+         %37 = OpFAdd %v3float %35 %36
+         %38 = OpCompositeExtract %v3float %20 1
+         %39 = OpCompositeExtract %v3float %33 1
+         %40 = OpFAdd %v3float %38 %39
+         %41 = OpCompositeExtract %v3float %20 2
+         %42 = OpCompositeExtract %v3float %33 2
+         %43 = OpFAdd %v3float %41 %42
+         %44 = OpCompositeConstruct %mat3v3float %37 %40 %43
+               OpReturn
+               OpFunctionEnd
diff --git a/test/expressions/binary/add/mat3x3-mat3x3/f32.wgsl.expected.wgsl b/test/expressions/binary/add/mat3x3-mat3x3/f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..9113851
--- /dev/null
+++ b/test/expressions/binary/add/mat3x3-mat3x3/f32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+  let a = mat3x3<f32>(vec3<f32>(1.0, 2.0, 3.0), vec3<f32>(4.0, 5.0, 6.0), vec3<f32>(7.0, 8.0, 9.0));
+  let b = mat3x3<f32>(vec3<f32>(-1.0, -2.0, -3.0), vec3<f32>(-4.0, -5.0, -6.0), vec3<f32>(-7.0, -8.0, -9.0));
+  let r : mat3x3<f32> = (a + b);
+}
diff --git a/test/expressions/binary/add/scalar-scalar/f32.wgsl b/test/expressions/binary/add/scalar-scalar/f32.wgsl
new file mode 100644
index 0000000..25bf677
--- /dev/null
+++ b/test/expressions/binary/add/scalar-scalar/f32.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+    let a = 1.;
+    let b = 2.;
+    let r : f32 = a + b;
+}
diff --git a/test/expressions/binary/add/scalar-scalar/f32.wgsl.expected.hlsl b/test/expressions/binary/add/scalar-scalar/f32.wgsl.expected.hlsl
new file mode 100644
index 0000000..7d73fa9
--- /dev/null
+++ b/test/expressions/binary/add/scalar-scalar/f32.wgsl.expected.hlsl
@@ -0,0 +1,5 @@
+[numthreads(1, 1, 1)]
+void f() {
+  const float r = (1.0f + 2.0f);
+  return;
+}
diff --git a/test/expressions/binary/add/scalar-scalar/f32.wgsl.expected.msl b/test/expressions/binary/add/scalar-scalar/f32.wgsl.expected.msl
new file mode 100644
index 0000000..bcb61ac
--- /dev/null
+++ b/test/expressions/binary/add/scalar-scalar/f32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f() {
+  float const a = 1.0f;
+  float const b = 2.0f;
+  float const r = (a + b);
+  return;
+}
+
diff --git a/test/expressions/binary/add/scalar-scalar/f32.wgsl.expected.spvasm b/test/expressions/binary/add/scalar-scalar/f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..5f1590d
--- /dev/null
+++ b/test/expressions/binary/add/scalar-scalar/f32.wgsl.expected.spvasm
@@ -0,0 +1,20 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 9
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %f "f"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+      %float = OpTypeFloat 32
+    %float_1 = OpConstant %float 1
+    %float_2 = OpConstant %float 2
+          %f = OpFunction %void None %1
+          %4 = OpLabel
+          %8 = OpFAdd %float %float_1 %float_2
+               OpReturn
+               OpFunctionEnd
diff --git a/test/expressions/binary/add/scalar-scalar/f32.wgsl.expected.wgsl b/test/expressions/binary/add/scalar-scalar/f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..3db4790
--- /dev/null
+++ b/test/expressions/binary/add/scalar-scalar/f32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+  let a = 1.0;
+  let b = 2.0;
+  let r : f32 = (a + b);
+}
diff --git a/test/expressions/binary/add/scalar-scalar/i32.wgsl b/test/expressions/binary/add/scalar-scalar/i32.wgsl
new file mode 100644
index 0000000..bb39f2e
--- /dev/null
+++ b/test/expressions/binary/add/scalar-scalar/i32.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+    let a = 1;
+    let b = 2;
+    let r : i32 = a + b;
+}
diff --git a/test/expressions/binary/add/scalar-scalar/i32.wgsl.expected.hlsl b/test/expressions/binary/add/scalar-scalar/i32.wgsl.expected.hlsl
new file mode 100644
index 0000000..9a9dd1f
--- /dev/null
+++ b/test/expressions/binary/add/scalar-scalar/i32.wgsl.expected.hlsl
@@ -0,0 +1,5 @@
+[numthreads(1, 1, 1)]
+void f() {
+  const int r = (1 + 2);
+  return;
+}
diff --git a/test/expressions/binary/add/scalar-scalar/i32.wgsl.expected.msl b/test/expressions/binary/add/scalar-scalar/i32.wgsl.expected.msl
new file mode 100644
index 0000000..062cf47
--- /dev/null
+++ b/test/expressions/binary/add/scalar-scalar/i32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f() {
+  int const a = 1;
+  int const b = 2;
+  int const r = (a + b);
+  return;
+}
+
diff --git a/test/expressions/binary/add/scalar-scalar/i32.wgsl.expected.spvasm b/test/expressions/binary/add/scalar-scalar/i32.wgsl.expected.spvasm
new file mode 100644
index 0000000..41bc067
--- /dev/null
+++ b/test/expressions/binary/add/scalar-scalar/i32.wgsl.expected.spvasm
@@ -0,0 +1,20 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 9
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %f "f"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+      %int_2 = OpConstant %int 2
+          %f = OpFunction %void None %1
+          %4 = OpLabel
+          %8 = OpIAdd %int %int_1 %int_2
+               OpReturn
+               OpFunctionEnd
diff --git a/test/expressions/binary/add/scalar-scalar/i32.wgsl.expected.wgsl b/test/expressions/binary/add/scalar-scalar/i32.wgsl.expected.wgsl
new file mode 100644
index 0000000..7022af1
--- /dev/null
+++ b/test/expressions/binary/add/scalar-scalar/i32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+  let a = 1;
+  let b = 2;
+  let r : i32 = (a + b);
+}
diff --git a/test/expressions/binary/add/scalar-scalar/u32.wgsl b/test/expressions/binary/add/scalar-scalar/u32.wgsl
new file mode 100644
index 0000000..9f5be35
--- /dev/null
+++ b/test/expressions/binary/add/scalar-scalar/u32.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+    let a = 1u;
+    let b = 2u;
+    let r : u32 = a + b;
+}
diff --git a/test/expressions/binary/add/scalar-scalar/u32.wgsl.expected.hlsl b/test/expressions/binary/add/scalar-scalar/u32.wgsl.expected.hlsl
new file mode 100644
index 0000000..f540a81
--- /dev/null
+++ b/test/expressions/binary/add/scalar-scalar/u32.wgsl.expected.hlsl
@@ -0,0 +1,5 @@
+[numthreads(1, 1, 1)]
+void f() {
+  const uint r = (1u + 2u);
+  return;
+}
diff --git a/test/expressions/binary/add/scalar-scalar/u32.wgsl.expected.msl b/test/expressions/binary/add/scalar-scalar/u32.wgsl.expected.msl
new file mode 100644
index 0000000..ca9e441
--- /dev/null
+++ b/test/expressions/binary/add/scalar-scalar/u32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f() {
+  uint const a = 1u;
+  uint const b = 2u;
+  uint const r = (a + b);
+  return;
+}
+
diff --git a/test/expressions/binary/add/scalar-scalar/u32.wgsl.expected.spvasm b/test/expressions/binary/add/scalar-scalar/u32.wgsl.expected.spvasm
new file mode 100644
index 0000000..88c551f
--- /dev/null
+++ b/test/expressions/binary/add/scalar-scalar/u32.wgsl.expected.spvasm
@@ -0,0 +1,20 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 9
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %f "f"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+          %f = OpFunction %void None %1
+          %4 = OpLabel
+          %8 = OpIAdd %uint %uint_1 %uint_2
+               OpReturn
+               OpFunctionEnd
diff --git a/test/expressions/binary/add/scalar-scalar/u32.wgsl.expected.wgsl b/test/expressions/binary/add/scalar-scalar/u32.wgsl.expected.wgsl
new file mode 100644
index 0000000..fc83a3e
--- /dev/null
+++ b/test/expressions/binary/add/scalar-scalar/u32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+  let a = 1u;
+  let b = 2u;
+  let r : u32 = (a + b);
+}
diff --git a/test/expressions/binary/add/scalar-vec3/f32.wgsl b/test/expressions/binary/add/scalar-vec3/f32.wgsl
new file mode 100644
index 0000000..8adb291
--- /dev/null
+++ b/test/expressions/binary/add/scalar-vec3/f32.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+    let a = 4.;
+    let b = vec3<f32>(1., 2., 3.);
+    let r : vec3<f32> = a + b;
+}
diff --git a/test/expressions/binary/add/scalar-vec3/f32.wgsl.expected.hlsl b/test/expressions/binary/add/scalar-vec3/f32.wgsl.expected.hlsl
new file mode 100644
index 0000000..bab272b
--- /dev/null
+++ b/test/expressions/binary/add/scalar-vec3/f32.wgsl.expected.hlsl
@@ -0,0 +1,7 @@
+[numthreads(1, 1, 1)]
+void f() {
+  const float a = 4.0f;
+  const float3 b = float3(1.0f, 2.0f, 3.0f);
+  const float3 r = (a + b);
+  return;
+}
diff --git a/test/expressions/binary/add/scalar-vec3/f32.wgsl.expected.msl b/test/expressions/binary/add/scalar-vec3/f32.wgsl.expected.msl
new file mode 100644
index 0000000..aad4aba
--- /dev/null
+++ b/test/expressions/binary/add/scalar-vec3/f32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f() {
+  float const a = 4.0f;
+  float3 const b = float3(1.0f, 2.0f, 3.0f);
+  float3 const r = (a + b);
+  return;
+}
+
diff --git a/test/expressions/binary/add/scalar-vec3/f32.wgsl.expected.spvasm b/test/expressions/binary/add/scalar-vec3/f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..1c59243
--- /dev/null
+++ b/test/expressions/binary/add/scalar-vec3/f32.wgsl.expected.spvasm
@@ -0,0 +1,28 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 17
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %f "f"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+      %float = OpTypeFloat 32
+    %float_4 = OpConstant %float 4
+    %v3float = OpTypeVector %float 3
+    %float_1 = OpConstant %float 1
+    %float_2 = OpConstant %float 2
+    %float_3 = OpConstant %float 3
+         %11 = OpConstantComposite %v3float %float_1 %float_2 %float_3
+%_ptr_Function_v3float = OpTypePointer Function %v3float
+         %15 = OpConstantNull %v3float
+          %f = OpFunction %void None %1
+          %4 = OpLabel
+         %13 = OpVariable %_ptr_Function_v3float Function %15
+         %16 = OpCompositeConstruct %v3float %float_4 %float_4 %float_4
+         %12 = OpFAdd %v3float %16 %11
+               OpReturn
+               OpFunctionEnd
diff --git a/test/expressions/binary/add/scalar-vec3/f32.wgsl.expected.wgsl b/test/expressions/binary/add/scalar-vec3/f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..f113f0e
--- /dev/null
+++ b/test/expressions/binary/add/scalar-vec3/f32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+  let a = 4.0;
+  let b = vec3<f32>(1.0, 2.0, 3.0);
+  let r : vec3<f32> = (a + b);
+}
diff --git a/test/expressions/binary/add/scalar-vec3/i32.wgsl b/test/expressions/binary/add/scalar-vec3/i32.wgsl
new file mode 100644
index 0000000..327473e
--- /dev/null
+++ b/test/expressions/binary/add/scalar-vec3/i32.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+    let a = 4;
+    let b = vec3<i32>(1, 2, 3);
+    let r : vec3<i32> = a + b;
+}
diff --git a/test/expressions/binary/add/scalar-vec3/i32.wgsl.expected.hlsl b/test/expressions/binary/add/scalar-vec3/i32.wgsl.expected.hlsl
new file mode 100644
index 0000000..1b2562e
--- /dev/null
+++ b/test/expressions/binary/add/scalar-vec3/i32.wgsl.expected.hlsl
@@ -0,0 +1,7 @@
+[numthreads(1, 1, 1)]
+void f() {
+  const int a = 4;
+  const int3 b = int3(1, 2, 3);
+  const int3 r = (a + b);
+  return;
+}
diff --git a/test/expressions/binary/add/scalar-vec3/i32.wgsl.expected.msl b/test/expressions/binary/add/scalar-vec3/i32.wgsl.expected.msl
new file mode 100644
index 0000000..f46975e
--- /dev/null
+++ b/test/expressions/binary/add/scalar-vec3/i32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f() {
+  int const a = 4;
+  int3 const b = int3(1, 2, 3);
+  int3 const r = (a + b);
+  return;
+}
+
diff --git a/test/expressions/binary/add/scalar-vec3/i32.wgsl.expected.spvasm b/test/expressions/binary/add/scalar-vec3/i32.wgsl.expected.spvasm
new file mode 100644
index 0000000..51975b7
--- /dev/null
+++ b/test/expressions/binary/add/scalar-vec3/i32.wgsl.expected.spvasm
@@ -0,0 +1,28 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 17
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %f "f"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+        %int = OpTypeInt 32 1
+      %int_4 = OpConstant %int 4
+      %v3int = OpTypeVector %int 3
+      %int_1 = OpConstant %int 1
+      %int_2 = OpConstant %int 2
+      %int_3 = OpConstant %int 3
+         %11 = OpConstantComposite %v3int %int_1 %int_2 %int_3
+%_ptr_Function_v3int = OpTypePointer Function %v3int
+         %15 = OpConstantNull %v3int
+          %f = OpFunction %void None %1
+          %4 = OpLabel
+         %13 = OpVariable %_ptr_Function_v3int Function %15
+         %16 = OpCompositeConstruct %v3int %int_4 %int_4 %int_4
+         %12 = OpIAdd %v3int %16 %11
+               OpReturn
+               OpFunctionEnd
diff --git a/test/expressions/binary/add/scalar-vec3/i32.wgsl.expected.wgsl b/test/expressions/binary/add/scalar-vec3/i32.wgsl.expected.wgsl
new file mode 100644
index 0000000..6123ca1
--- /dev/null
+++ b/test/expressions/binary/add/scalar-vec3/i32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+  let a = 4;
+  let b = vec3<i32>(1, 2, 3);
+  let r : vec3<i32> = (a + b);
+}
diff --git a/test/expressions/binary/add/scalar-vec3/u32.wgsl b/test/expressions/binary/add/scalar-vec3/u32.wgsl
new file mode 100644
index 0000000..e36d881
--- /dev/null
+++ b/test/expressions/binary/add/scalar-vec3/u32.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+    let a = 4u;
+    let b = vec3<u32>(1u, 2u, 3u);
+    let r : vec3<u32> = a + b;
+}
diff --git a/test/expressions/binary/add/scalar-vec3/u32.wgsl.expected.hlsl b/test/expressions/binary/add/scalar-vec3/u32.wgsl.expected.hlsl
new file mode 100644
index 0000000..5b43e9e
--- /dev/null
+++ b/test/expressions/binary/add/scalar-vec3/u32.wgsl.expected.hlsl
@@ -0,0 +1,7 @@
+[numthreads(1, 1, 1)]
+void f() {
+  const uint a = 4u;
+  const uint3 b = uint3(1u, 2u, 3u);
+  const uint3 r = (a + b);
+  return;
+}
diff --git a/test/expressions/binary/add/scalar-vec3/u32.wgsl.expected.msl b/test/expressions/binary/add/scalar-vec3/u32.wgsl.expected.msl
new file mode 100644
index 0000000..71345d5
--- /dev/null
+++ b/test/expressions/binary/add/scalar-vec3/u32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f() {
+  uint const a = 4u;
+  uint3 const b = uint3(1u, 2u, 3u);
+  uint3 const r = (a + b);
+  return;
+}
+
diff --git a/test/expressions/binary/add/scalar-vec3/u32.wgsl.expected.spvasm b/test/expressions/binary/add/scalar-vec3/u32.wgsl.expected.spvasm
new file mode 100644
index 0000000..9fd4b14
--- /dev/null
+++ b/test/expressions/binary/add/scalar-vec3/u32.wgsl.expected.spvasm
@@ -0,0 +1,28 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 17
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %f "f"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+     %v3uint = OpTypeVector %uint 3
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+     %uint_3 = OpConstant %uint 3
+         %11 = OpConstantComposite %v3uint %uint_1 %uint_2 %uint_3
+%_ptr_Function_v3uint = OpTypePointer Function %v3uint
+         %15 = OpConstantNull %v3uint
+          %f = OpFunction %void None %1
+          %4 = OpLabel
+         %13 = OpVariable %_ptr_Function_v3uint Function %15
+         %16 = OpCompositeConstruct %v3uint %uint_4 %uint_4 %uint_4
+         %12 = OpIAdd %v3uint %16 %11
+               OpReturn
+               OpFunctionEnd
diff --git a/test/expressions/binary/add/scalar-vec3/u32.wgsl.expected.wgsl b/test/expressions/binary/add/scalar-vec3/u32.wgsl.expected.wgsl
new file mode 100644
index 0000000..457841e
--- /dev/null
+++ b/test/expressions/binary/add/scalar-vec3/u32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+  let a = 4u;
+  let b = vec3<u32>(1u, 2u, 3u);
+  let r : vec3<u32> = (a + b);
+}
diff --git a/test/expressions/binary/add/vec3-scalar/f32.wgsl b/test/expressions/binary/add/vec3-scalar/f32.wgsl
new file mode 100644
index 0000000..dd38642
--- /dev/null
+++ b/test/expressions/binary/add/vec3-scalar/f32.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+    let a = vec3<f32>(1., 2., 3.);
+    let b = 4.;
+    let r : vec3<f32> = a + b;
+}
diff --git a/test/expressions/binary/add/vec3-scalar/f32.wgsl.expected.hlsl b/test/expressions/binary/add/vec3-scalar/f32.wgsl.expected.hlsl
new file mode 100644
index 0000000..a7fe143
--- /dev/null
+++ b/test/expressions/binary/add/vec3-scalar/f32.wgsl.expected.hlsl
@@ -0,0 +1,6 @@
+[numthreads(1, 1, 1)]
+void f() {
+  const float3 a = float3(1.0f, 2.0f, 3.0f);
+  const float3 r = (a + 4.0f);
+  return;
+}
diff --git a/test/expressions/binary/add/vec3-scalar/f32.wgsl.expected.msl b/test/expressions/binary/add/vec3-scalar/f32.wgsl.expected.msl
new file mode 100644
index 0000000..e156063
--- /dev/null
+++ b/test/expressions/binary/add/vec3-scalar/f32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f() {
+  float3 const a = float3(1.0f, 2.0f, 3.0f);
+  float const b = 4.0f;
+  float3 const r = (a + b);
+  return;
+}
+
diff --git a/test/expressions/binary/add/vec3-scalar/f32.wgsl.expected.spvasm b/test/expressions/binary/add/vec3-scalar/f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..c7169bc
--- /dev/null
+++ b/test/expressions/binary/add/vec3-scalar/f32.wgsl.expected.spvasm
@@ -0,0 +1,28 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 17
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %f "f"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+    %float_1 = OpConstant %float 1
+    %float_2 = OpConstant %float 2
+    %float_3 = OpConstant %float 3
+         %10 = OpConstantComposite %v3float %float_1 %float_2 %float_3
+    %float_4 = OpConstant %float 4
+%_ptr_Function_v3float = OpTypePointer Function %v3float
+         %15 = OpConstantNull %v3float
+          %f = OpFunction %void None %1
+          %4 = OpLabel
+         %13 = OpVariable %_ptr_Function_v3float Function %15
+         %16 = OpCompositeConstruct %v3float %float_4 %float_4 %float_4
+         %12 = OpFAdd %v3float %10 %16
+               OpReturn
+               OpFunctionEnd
diff --git a/test/expressions/binary/add/vec3-scalar/f32.wgsl.expected.wgsl b/test/expressions/binary/add/vec3-scalar/f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..62aa160
--- /dev/null
+++ b/test/expressions/binary/add/vec3-scalar/f32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+  let a = vec3<f32>(1.0, 2.0, 3.0);
+  let b = 4.0;
+  let r : vec3<f32> = (a + b);
+}
diff --git a/test/expressions/binary/add/vec3-scalar/i32.wgsl b/test/expressions/binary/add/vec3-scalar/i32.wgsl
new file mode 100644
index 0000000..1e4324a
--- /dev/null
+++ b/test/expressions/binary/add/vec3-scalar/i32.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+    let a = vec3<i32>(1, 2, 3);
+    let b = 4;
+    let r : vec3<i32> = a + b;
+}
diff --git a/test/expressions/binary/add/vec3-scalar/i32.wgsl.expected.hlsl b/test/expressions/binary/add/vec3-scalar/i32.wgsl.expected.hlsl
new file mode 100644
index 0000000..5875ef7
--- /dev/null
+++ b/test/expressions/binary/add/vec3-scalar/i32.wgsl.expected.hlsl
@@ -0,0 +1,6 @@
+[numthreads(1, 1, 1)]
+void f() {
+  const int3 a = int3(1, 2, 3);
+  const int3 r = (a + 4);
+  return;
+}
diff --git a/test/expressions/binary/add/vec3-scalar/i32.wgsl.expected.msl b/test/expressions/binary/add/vec3-scalar/i32.wgsl.expected.msl
new file mode 100644
index 0000000..ba1fdc5
--- /dev/null
+++ b/test/expressions/binary/add/vec3-scalar/i32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f() {
+  int3 const a = int3(1, 2, 3);
+  int const b = 4;
+  int3 const r = (a + b);
+  return;
+}
+
diff --git a/test/expressions/binary/add/vec3-scalar/i32.wgsl.expected.spvasm b/test/expressions/binary/add/vec3-scalar/i32.wgsl.expected.spvasm
new file mode 100644
index 0000000..0cb5e23
--- /dev/null
+++ b/test/expressions/binary/add/vec3-scalar/i32.wgsl.expected.spvasm
@@ -0,0 +1,28 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 17
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %f "f"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+        %int = OpTypeInt 32 1
+      %v3int = OpTypeVector %int 3
+      %int_1 = OpConstant %int 1
+      %int_2 = OpConstant %int 2
+      %int_3 = OpConstant %int 3
+         %10 = OpConstantComposite %v3int %int_1 %int_2 %int_3
+      %int_4 = OpConstant %int 4
+%_ptr_Function_v3int = OpTypePointer Function %v3int
+         %15 = OpConstantNull %v3int
+          %f = OpFunction %void None %1
+          %4 = OpLabel
+         %13 = OpVariable %_ptr_Function_v3int Function %15
+         %16 = OpCompositeConstruct %v3int %int_4 %int_4 %int_4
+         %12 = OpIAdd %v3int %10 %16
+               OpReturn
+               OpFunctionEnd
diff --git a/test/expressions/binary/add/vec3-scalar/i32.wgsl.expected.wgsl b/test/expressions/binary/add/vec3-scalar/i32.wgsl.expected.wgsl
new file mode 100644
index 0000000..378b1d2
--- /dev/null
+++ b/test/expressions/binary/add/vec3-scalar/i32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+  let a = vec3<i32>(1, 2, 3);
+  let b = 4;
+  let r : vec3<i32> = (a + b);
+}
diff --git a/test/expressions/binary/add/vec3-scalar/u32.wgsl b/test/expressions/binary/add/vec3-scalar/u32.wgsl
new file mode 100644
index 0000000..cfff6f1
--- /dev/null
+++ b/test/expressions/binary/add/vec3-scalar/u32.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+    let a = vec3<u32>(1u, 2u, 3u);
+    let b = 4u;
+    let r : vec3<u32> = a + b;
+}
diff --git a/test/expressions/binary/add/vec3-scalar/u32.wgsl.expected.hlsl b/test/expressions/binary/add/vec3-scalar/u32.wgsl.expected.hlsl
new file mode 100644
index 0000000..056ee37
--- /dev/null
+++ b/test/expressions/binary/add/vec3-scalar/u32.wgsl.expected.hlsl
@@ -0,0 +1,6 @@
+[numthreads(1, 1, 1)]
+void f() {
+  const uint3 a = uint3(1u, 2u, 3u);
+  const uint3 r = (a + 4u);
+  return;
+}
diff --git a/test/expressions/binary/add/vec3-scalar/u32.wgsl.expected.msl b/test/expressions/binary/add/vec3-scalar/u32.wgsl.expected.msl
new file mode 100644
index 0000000..830bcdd
--- /dev/null
+++ b/test/expressions/binary/add/vec3-scalar/u32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f() {
+  uint3 const a = uint3(1u, 2u, 3u);
+  uint const b = 4u;
+  uint3 const r = (a + b);
+  return;
+}
+
diff --git a/test/expressions/binary/add/vec3-scalar/u32.wgsl.expected.spvasm b/test/expressions/binary/add/vec3-scalar/u32.wgsl.expected.spvasm
new file mode 100644
index 0000000..f5f979a
--- /dev/null
+++ b/test/expressions/binary/add/vec3-scalar/u32.wgsl.expected.spvasm
@@ -0,0 +1,28 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 17
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %f "f"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %v3uint = OpTypeVector %uint 3
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+     %uint_3 = OpConstant %uint 3
+         %10 = OpConstantComposite %v3uint %uint_1 %uint_2 %uint_3
+     %uint_4 = OpConstant %uint 4
+%_ptr_Function_v3uint = OpTypePointer Function %v3uint
+         %15 = OpConstantNull %v3uint
+          %f = OpFunction %void None %1
+          %4 = OpLabel
+         %13 = OpVariable %_ptr_Function_v3uint Function %15
+         %16 = OpCompositeConstruct %v3uint %uint_4 %uint_4 %uint_4
+         %12 = OpIAdd %v3uint %10 %16
+               OpReturn
+               OpFunctionEnd
diff --git a/test/expressions/binary/add/vec3-scalar/u32.wgsl.expected.wgsl b/test/expressions/binary/add/vec3-scalar/u32.wgsl.expected.wgsl
new file mode 100644
index 0000000..df0f990
--- /dev/null
+++ b/test/expressions/binary/add/vec3-scalar/u32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+  let a = vec3<u32>(1u, 2u, 3u);
+  let b = 4u;
+  let r : vec3<u32> = (a + b);
+}
diff --git a/test/expressions/binary/add/vec3-vec3/f32.wgsl b/test/expressions/binary/add/vec3-vec3/f32.wgsl
new file mode 100644
index 0000000..4f71797
--- /dev/null
+++ b/test/expressions/binary/add/vec3-vec3/f32.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+    let a = vec3<f32>(1., 2., 3.);
+    let b = vec3<f32>(4., 5., 6.);
+    let r : vec3<f32> = a + b;
+}
diff --git a/test/expressions/binary/add/vec3-vec3/f32.wgsl.expected.hlsl b/test/expressions/binary/add/vec3-vec3/f32.wgsl.expected.hlsl
new file mode 100644
index 0000000..2fa34ec
--- /dev/null
+++ b/test/expressions/binary/add/vec3-vec3/f32.wgsl.expected.hlsl
@@ -0,0 +1,7 @@
+[numthreads(1, 1, 1)]
+void f() {
+  const float3 a = float3(1.0f, 2.0f, 3.0f);
+  const float3 b = float3(4.0f, 5.0f, 6.0f);
+  const float3 r = (a + b);
+  return;
+}
diff --git a/test/expressions/binary/add/vec3-vec3/f32.wgsl.expected.msl b/test/expressions/binary/add/vec3-vec3/f32.wgsl.expected.msl
new file mode 100644
index 0000000..011652a
--- /dev/null
+++ b/test/expressions/binary/add/vec3-vec3/f32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f() {
+  float3 const a = float3(1.0f, 2.0f, 3.0f);
+  float3 const b = float3(4.0f, 5.0f, 6.0f);
+  float3 const r = (a + b);
+  return;
+}
+
diff --git a/test/expressions/binary/add/vec3-vec3/f32.wgsl.expected.spvasm b/test/expressions/binary/add/vec3-vec3/f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..d52cc80
--- /dev/null
+++ b/test/expressions/binary/add/vec3-vec3/f32.wgsl.expected.spvasm
@@ -0,0 +1,27 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 16
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %f "f"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+    %float_1 = OpConstant %float 1
+    %float_2 = OpConstant %float 2
+    %float_3 = OpConstant %float 3
+         %10 = OpConstantComposite %v3float %float_1 %float_2 %float_3
+    %float_4 = OpConstant %float 4
+    %float_5 = OpConstant %float 5
+    %float_6 = OpConstant %float 6
+         %14 = OpConstantComposite %v3float %float_4 %float_5 %float_6
+          %f = OpFunction %void None %1
+          %4 = OpLabel
+         %15 = OpFAdd %v3float %10 %14
+               OpReturn
+               OpFunctionEnd
diff --git a/test/expressions/binary/add/vec3-vec3/f32.wgsl.expected.wgsl b/test/expressions/binary/add/vec3-vec3/f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..54d52b1
--- /dev/null
+++ b/test/expressions/binary/add/vec3-vec3/f32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+  let a = vec3<f32>(1.0, 2.0, 3.0);
+  let b = vec3<f32>(4.0, 5.0, 6.0);
+  let r : vec3<f32> = (a + b);
+}
diff --git a/test/expressions/binary/add/vec3-vec3/i32.wgsl b/test/expressions/binary/add/vec3-vec3/i32.wgsl
new file mode 100644
index 0000000..dd170f5
--- /dev/null
+++ b/test/expressions/binary/add/vec3-vec3/i32.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+    let a = vec3<i32>(1, 2, 3);
+    let b = vec3<i32>(4, 5, 6);
+    let r : vec3<i32> = a + b;
+}
diff --git a/test/expressions/binary/add/vec3-vec3/i32.wgsl.expected.hlsl b/test/expressions/binary/add/vec3-vec3/i32.wgsl.expected.hlsl
new file mode 100644
index 0000000..3ff77a0
--- /dev/null
+++ b/test/expressions/binary/add/vec3-vec3/i32.wgsl.expected.hlsl
@@ -0,0 +1,7 @@
+[numthreads(1, 1, 1)]
+void f() {
+  const int3 a = int3(1, 2, 3);
+  const int3 b = int3(4, 5, 6);
+  const int3 r = (a + b);
+  return;
+}
diff --git a/test/expressions/binary/add/vec3-vec3/i32.wgsl.expected.msl b/test/expressions/binary/add/vec3-vec3/i32.wgsl.expected.msl
new file mode 100644
index 0000000..2f4fbae
--- /dev/null
+++ b/test/expressions/binary/add/vec3-vec3/i32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f() {
+  int3 const a = int3(1, 2, 3);
+  int3 const b = int3(4, 5, 6);
+  int3 const r = (a + b);
+  return;
+}
+
diff --git a/test/expressions/binary/add/vec3-vec3/i32.wgsl.expected.spvasm b/test/expressions/binary/add/vec3-vec3/i32.wgsl.expected.spvasm
new file mode 100644
index 0000000..8111e5f
--- /dev/null
+++ b/test/expressions/binary/add/vec3-vec3/i32.wgsl.expected.spvasm
@@ -0,0 +1,27 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 16
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %f "f"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+        %int = OpTypeInt 32 1
+      %v3int = OpTypeVector %int 3
+      %int_1 = OpConstant %int 1
+      %int_2 = OpConstant %int 2
+      %int_3 = OpConstant %int 3
+         %10 = OpConstantComposite %v3int %int_1 %int_2 %int_3
+      %int_4 = OpConstant %int 4
+      %int_5 = OpConstant %int 5
+      %int_6 = OpConstant %int 6
+         %14 = OpConstantComposite %v3int %int_4 %int_5 %int_6
+          %f = OpFunction %void None %1
+          %4 = OpLabel
+         %15 = OpIAdd %v3int %10 %14
+               OpReturn
+               OpFunctionEnd
diff --git a/test/expressions/binary/add/vec3-vec3/i32.wgsl.expected.wgsl b/test/expressions/binary/add/vec3-vec3/i32.wgsl.expected.wgsl
new file mode 100644
index 0000000..5f1226d
--- /dev/null
+++ b/test/expressions/binary/add/vec3-vec3/i32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+  let a = vec3<i32>(1, 2, 3);
+  let b = vec3<i32>(4, 5, 6);
+  let r : vec3<i32> = (a + b);
+}
diff --git a/test/expressions/binary/add/vec3-vec3/u32.wgsl b/test/expressions/binary/add/vec3-vec3/u32.wgsl
new file mode 100644
index 0000000..433e52d
--- /dev/null
+++ b/test/expressions/binary/add/vec3-vec3/u32.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+    let a = vec3<u32>(1u, 2u, 3u);
+    let b = vec3<u32>(4u, 5u, 6u);
+    let r : vec3<u32> = a + b;
+}
diff --git a/test/expressions/binary/add/vec3-vec3/u32.wgsl.expected.hlsl b/test/expressions/binary/add/vec3-vec3/u32.wgsl.expected.hlsl
new file mode 100644
index 0000000..5bf8554
--- /dev/null
+++ b/test/expressions/binary/add/vec3-vec3/u32.wgsl.expected.hlsl
@@ -0,0 +1,7 @@
+[numthreads(1, 1, 1)]
+void f() {
+  const uint3 a = uint3(1u, 2u, 3u);
+  const uint3 b = uint3(4u, 5u, 6u);
+  const uint3 r = (a + b);
+  return;
+}
diff --git a/test/expressions/binary/add/vec3-vec3/u32.wgsl.expected.msl b/test/expressions/binary/add/vec3-vec3/u32.wgsl.expected.msl
new file mode 100644
index 0000000..5299d8a
--- /dev/null
+++ b/test/expressions/binary/add/vec3-vec3/u32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f() {
+  uint3 const a = uint3(1u, 2u, 3u);
+  uint3 const b = uint3(4u, 5u, 6u);
+  uint3 const r = (a + b);
+  return;
+}
+
diff --git a/test/expressions/binary/add/vec3-vec3/u32.wgsl.expected.spvasm b/test/expressions/binary/add/vec3-vec3/u32.wgsl.expected.spvasm
new file mode 100644
index 0000000..faa656e
--- /dev/null
+++ b/test/expressions/binary/add/vec3-vec3/u32.wgsl.expected.spvasm
@@ -0,0 +1,27 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 16
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %f "f"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %v3uint = OpTypeVector %uint 3
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+     %uint_3 = OpConstant %uint 3
+         %10 = OpConstantComposite %v3uint %uint_1 %uint_2 %uint_3
+     %uint_4 = OpConstant %uint 4
+     %uint_5 = OpConstant %uint 5
+     %uint_6 = OpConstant %uint 6
+         %14 = OpConstantComposite %v3uint %uint_4 %uint_5 %uint_6
+          %f = OpFunction %void None %1
+          %4 = OpLabel
+         %15 = OpIAdd %v3uint %10 %14
+               OpReturn
+               OpFunctionEnd
diff --git a/test/expressions/binary/add/vec3-vec3/u32.wgsl.expected.wgsl b/test/expressions/binary/add/vec3-vec3/u32.wgsl.expected.wgsl
new file mode 100644
index 0000000..85dad76
--- /dev/null
+++ b/test/expressions/binary/add/vec3-vec3/u32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+  let a = vec3<u32>(1u, 2u, 3u);
+  let b = vec3<u32>(4u, 5u, 6u);
+  let r : vec3<u32> = (a + b);
+}
diff --git a/test/expressions/binary/bit-and/scalar-scalar/i32.wgsl b/test/expressions/binary/bit-and/scalar-scalar/i32.wgsl
new file mode 100644
index 0000000..9ad0a83
--- /dev/null
+++ b/test/expressions/binary/bit-and/scalar-scalar/i32.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+    let a = 1;
+    let b = 2;
+    let r : i32 = a & b;
+}
diff --git a/test/expressions/binary/bit-and/scalar-scalar/i32.wgsl.expected.hlsl b/test/expressions/binary/bit-and/scalar-scalar/i32.wgsl.expected.hlsl
new file mode 100644
index 0000000..632b46c
--- /dev/null
+++ b/test/expressions/binary/bit-and/scalar-scalar/i32.wgsl.expected.hlsl
@@ -0,0 +1,5 @@
+[numthreads(1, 1, 1)]
+void f() {
+  const int r = (1 & 2);
+  return;
+}
diff --git a/test/expressions/binary/bit-and/scalar-scalar/i32.wgsl.expected.msl b/test/expressions/binary/bit-and/scalar-scalar/i32.wgsl.expected.msl
new file mode 100644
index 0000000..bb30c81
--- /dev/null
+++ b/test/expressions/binary/bit-and/scalar-scalar/i32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f() {
+  int const a = 1;
+  int const b = 2;
+  int const r = (a & b);
+  return;
+}
+
diff --git a/test/expressions/binary/bit-and/scalar-scalar/i32.wgsl.expected.spvasm b/test/expressions/binary/bit-and/scalar-scalar/i32.wgsl.expected.spvasm
new file mode 100644
index 0000000..ad7063e
--- /dev/null
+++ b/test/expressions/binary/bit-and/scalar-scalar/i32.wgsl.expected.spvasm
@@ -0,0 +1,20 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 9
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %f "f"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+      %int_2 = OpConstant %int 2
+          %f = OpFunction %void None %1
+          %4 = OpLabel
+          %8 = OpBitwiseAnd %int %int_1 %int_2
+               OpReturn
+               OpFunctionEnd
diff --git a/test/expressions/binary/bit-and/scalar-scalar/i32.wgsl.expected.wgsl b/test/expressions/binary/bit-and/scalar-scalar/i32.wgsl.expected.wgsl
new file mode 100644
index 0000000..ce96c2d
--- /dev/null
+++ b/test/expressions/binary/bit-and/scalar-scalar/i32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+  let a = 1;
+  let b = 2;
+  let r : i32 = (a & b);
+}
diff --git a/test/expressions/binary/bit-and/scalar-scalar/u32.wgsl b/test/expressions/binary/bit-and/scalar-scalar/u32.wgsl
new file mode 100644
index 0000000..ee0fb0a
--- /dev/null
+++ b/test/expressions/binary/bit-and/scalar-scalar/u32.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+    let a = 1u;
+    let b = 2u;
+    let r : u32 = a & b;
+}
diff --git a/test/expressions/binary/bit-and/scalar-scalar/u32.wgsl.expected.hlsl b/test/expressions/binary/bit-and/scalar-scalar/u32.wgsl.expected.hlsl
new file mode 100644
index 0000000..0024712
--- /dev/null
+++ b/test/expressions/binary/bit-and/scalar-scalar/u32.wgsl.expected.hlsl
@@ -0,0 +1,5 @@
+[numthreads(1, 1, 1)]
+void f() {
+  const uint r = (1u & 2u);
+  return;
+}
diff --git a/test/expressions/binary/bit-and/scalar-scalar/u32.wgsl.expected.msl b/test/expressions/binary/bit-and/scalar-scalar/u32.wgsl.expected.msl
new file mode 100644
index 0000000..b3ca220
--- /dev/null
+++ b/test/expressions/binary/bit-and/scalar-scalar/u32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f() {
+  uint const a = 1u;
+  uint const b = 2u;
+  uint const r = (a & b);
+  return;
+}
+
diff --git a/test/expressions/binary/bit-and/scalar-scalar/u32.wgsl.expected.spvasm b/test/expressions/binary/bit-and/scalar-scalar/u32.wgsl.expected.spvasm
new file mode 100644
index 0000000..e91daf8
--- /dev/null
+++ b/test/expressions/binary/bit-and/scalar-scalar/u32.wgsl.expected.spvasm
@@ -0,0 +1,20 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 9
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %f "f"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+          %f = OpFunction %void None %1
+          %4 = OpLabel
+          %8 = OpBitwiseAnd %uint %uint_1 %uint_2
+               OpReturn
+               OpFunctionEnd
diff --git a/test/expressions/binary/bit-and/scalar-scalar/u32.wgsl.expected.wgsl b/test/expressions/binary/bit-and/scalar-scalar/u32.wgsl.expected.wgsl
new file mode 100644
index 0000000..e5c60f1
--- /dev/null
+++ b/test/expressions/binary/bit-and/scalar-scalar/u32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+  let a = 1u;
+  let b = 2u;
+  let r : u32 = (a & b);
+}
diff --git a/test/expressions/binary/bit-and/vec3-vec3/i32.wgsl b/test/expressions/binary/bit-and/vec3-vec3/i32.wgsl
new file mode 100644
index 0000000..5dc71ef
--- /dev/null
+++ b/test/expressions/binary/bit-and/vec3-vec3/i32.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+    let a = vec3<i32>(1, 2, 3);
+    let b = vec3<i32>(4, 5, 6);
+    let r : vec3<i32> = a & b;
+}
diff --git a/test/expressions/binary/bit-and/vec3-vec3/i32.wgsl.expected.hlsl b/test/expressions/binary/bit-and/vec3-vec3/i32.wgsl.expected.hlsl
new file mode 100644
index 0000000..34f8f47
--- /dev/null
+++ b/test/expressions/binary/bit-and/vec3-vec3/i32.wgsl.expected.hlsl
@@ -0,0 +1,7 @@
+[numthreads(1, 1, 1)]
+void f() {
+  const int3 a = int3(1, 2, 3);
+  const int3 b = int3(4, 5, 6);
+  const int3 r = (a & b);
+  return;
+}
diff --git a/test/expressions/binary/bit-and/vec3-vec3/i32.wgsl.expected.msl b/test/expressions/binary/bit-and/vec3-vec3/i32.wgsl.expected.msl
new file mode 100644
index 0000000..22dbd49
--- /dev/null
+++ b/test/expressions/binary/bit-and/vec3-vec3/i32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f() {
+  int3 const a = int3(1, 2, 3);
+  int3 const b = int3(4, 5, 6);
+  int3 const r = (a & b);
+  return;
+}
+
diff --git a/test/expressions/binary/bit-and/vec3-vec3/i32.wgsl.expected.spvasm b/test/expressions/binary/bit-and/vec3-vec3/i32.wgsl.expected.spvasm
new file mode 100644
index 0000000..e0cab84
--- /dev/null
+++ b/test/expressions/binary/bit-and/vec3-vec3/i32.wgsl.expected.spvasm
@@ -0,0 +1,27 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 16
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %f "f"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+        %int = OpTypeInt 32 1
+      %v3int = OpTypeVector %int 3
+      %int_1 = OpConstant %int 1
+      %int_2 = OpConstant %int 2
+      %int_3 = OpConstant %int 3
+         %10 = OpConstantComposite %v3int %int_1 %int_2 %int_3
+      %int_4 = OpConstant %int 4
+      %int_5 = OpConstant %int 5
+      %int_6 = OpConstant %int 6
+         %14 = OpConstantComposite %v3int %int_4 %int_5 %int_6
+          %f = OpFunction %void None %1
+          %4 = OpLabel
+         %15 = OpBitwiseAnd %v3int %10 %14
+               OpReturn
+               OpFunctionEnd
diff --git a/test/expressions/binary/bit-and/vec3-vec3/i32.wgsl.expected.wgsl b/test/expressions/binary/bit-and/vec3-vec3/i32.wgsl.expected.wgsl
new file mode 100644
index 0000000..a30b1f5
--- /dev/null
+++ b/test/expressions/binary/bit-and/vec3-vec3/i32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+  let a = vec3<i32>(1, 2, 3);
+  let b = vec3<i32>(4, 5, 6);
+  let r : vec3<i32> = (a & b);
+}
diff --git a/test/expressions/binary/bit-and/vec3-vec3/u32.wgsl b/test/expressions/binary/bit-and/vec3-vec3/u32.wgsl
new file mode 100644
index 0000000..c520bc3
--- /dev/null
+++ b/test/expressions/binary/bit-and/vec3-vec3/u32.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+    let a = vec3<u32>(1u, 2u, 3u);
+    let b = vec3<u32>(4u, 5u, 6u);
+    let r : vec3<u32> = a & b;
+}
diff --git a/test/expressions/binary/bit-and/vec3-vec3/u32.wgsl.expected.hlsl b/test/expressions/binary/bit-and/vec3-vec3/u32.wgsl.expected.hlsl
new file mode 100644
index 0000000..8e74758
--- /dev/null
+++ b/test/expressions/binary/bit-and/vec3-vec3/u32.wgsl.expected.hlsl
@@ -0,0 +1,7 @@
+[numthreads(1, 1, 1)]
+void f() {
+  const uint3 a = uint3(1u, 2u, 3u);
+  const uint3 b = uint3(4u, 5u, 6u);
+  const uint3 r = (a & b);
+  return;
+}
diff --git a/test/expressions/binary/bit-and/vec3-vec3/u32.wgsl.expected.msl b/test/expressions/binary/bit-and/vec3-vec3/u32.wgsl.expected.msl
new file mode 100644
index 0000000..f0aefd1
--- /dev/null
+++ b/test/expressions/binary/bit-and/vec3-vec3/u32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f() {
+  uint3 const a = uint3(1u, 2u, 3u);
+  uint3 const b = uint3(4u, 5u, 6u);
+  uint3 const r = (a & b);
+  return;
+}
+
diff --git a/test/expressions/binary/bit-and/vec3-vec3/u32.wgsl.expected.spvasm b/test/expressions/binary/bit-and/vec3-vec3/u32.wgsl.expected.spvasm
new file mode 100644
index 0000000..3d3deac
--- /dev/null
+++ b/test/expressions/binary/bit-and/vec3-vec3/u32.wgsl.expected.spvasm
@@ -0,0 +1,27 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 16
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %f "f"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %v3uint = OpTypeVector %uint 3
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+     %uint_3 = OpConstant %uint 3
+         %10 = OpConstantComposite %v3uint %uint_1 %uint_2 %uint_3
+     %uint_4 = OpConstant %uint 4
+     %uint_5 = OpConstant %uint 5
+     %uint_6 = OpConstant %uint 6
+         %14 = OpConstantComposite %v3uint %uint_4 %uint_5 %uint_6
+          %f = OpFunction %void None %1
+          %4 = OpLabel
+         %15 = OpBitwiseAnd %v3uint %10 %14
+               OpReturn
+               OpFunctionEnd
diff --git a/test/expressions/binary/bit-and/vec3-vec3/u32.wgsl.expected.wgsl b/test/expressions/binary/bit-and/vec3-vec3/u32.wgsl.expected.wgsl
new file mode 100644
index 0000000..b9c2d80
--- /dev/null
+++ b/test/expressions/binary/bit-and/vec3-vec3/u32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+  let a = vec3<u32>(1u, 2u, 3u);
+  let b = vec3<u32>(4u, 5u, 6u);
+  let r : vec3<u32> = (a & b);
+}
diff --git a/test/expressions/binary/bit-or/scalar-scalar/i32.wgsl b/test/expressions/binary/bit-or/scalar-scalar/i32.wgsl
new file mode 100644
index 0000000..9e2d99c
--- /dev/null
+++ b/test/expressions/binary/bit-or/scalar-scalar/i32.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+    let a = 1;
+    let b = 2;
+    let r : i32 = a | b;
+}
diff --git a/test/expressions/binary/bit-or/scalar-scalar/i32.wgsl.expected.hlsl b/test/expressions/binary/bit-or/scalar-scalar/i32.wgsl.expected.hlsl
new file mode 100644
index 0000000..4818fbd
--- /dev/null
+++ b/test/expressions/binary/bit-or/scalar-scalar/i32.wgsl.expected.hlsl
@@ -0,0 +1,5 @@
+[numthreads(1, 1, 1)]
+void f() {
+  const int r = (1 | 2);
+  return;
+}
diff --git a/test/expressions/binary/bit-or/scalar-scalar/i32.wgsl.expected.msl b/test/expressions/binary/bit-or/scalar-scalar/i32.wgsl.expected.msl
new file mode 100644
index 0000000..b3bbf94
--- /dev/null
+++ b/test/expressions/binary/bit-or/scalar-scalar/i32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f() {
+  int const a = 1;
+  int const b = 2;
+  int const r = (a | b);
+  return;
+}
+
diff --git a/test/expressions/binary/bit-or/scalar-scalar/i32.wgsl.expected.spvasm b/test/expressions/binary/bit-or/scalar-scalar/i32.wgsl.expected.spvasm
new file mode 100644
index 0000000..9823f65
--- /dev/null
+++ b/test/expressions/binary/bit-or/scalar-scalar/i32.wgsl.expected.spvasm
@@ -0,0 +1,20 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 9
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %f "f"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+      %int_2 = OpConstant %int 2
+          %f = OpFunction %void None %1
+          %4 = OpLabel
+          %8 = OpBitwiseOr %int %int_1 %int_2
+               OpReturn
+               OpFunctionEnd
diff --git a/test/expressions/binary/bit-or/scalar-scalar/i32.wgsl.expected.wgsl b/test/expressions/binary/bit-or/scalar-scalar/i32.wgsl.expected.wgsl
new file mode 100644
index 0000000..3a13163
--- /dev/null
+++ b/test/expressions/binary/bit-or/scalar-scalar/i32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+  let a = 1;
+  let b = 2;
+  let r : i32 = (a | b);
+}
diff --git a/test/expressions/binary/bit-or/scalar-scalar/u32.wgsl b/test/expressions/binary/bit-or/scalar-scalar/u32.wgsl
new file mode 100644
index 0000000..edf8a70
--- /dev/null
+++ b/test/expressions/binary/bit-or/scalar-scalar/u32.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+    let a = 1u;
+    let b = 2u;
+    let r : u32 = a | b;
+}
diff --git a/test/expressions/binary/bit-or/scalar-scalar/u32.wgsl.expected.hlsl b/test/expressions/binary/bit-or/scalar-scalar/u32.wgsl.expected.hlsl
new file mode 100644
index 0000000..90fd8af
--- /dev/null
+++ b/test/expressions/binary/bit-or/scalar-scalar/u32.wgsl.expected.hlsl
@@ -0,0 +1,5 @@
+[numthreads(1, 1, 1)]
+void f() {
+  const uint r = (1u | 2u);
+  return;
+}
diff --git a/test/expressions/binary/bit-or/scalar-scalar/u32.wgsl.expected.msl b/test/expressions/binary/bit-or/scalar-scalar/u32.wgsl.expected.msl
new file mode 100644
index 0000000..ca18514
--- /dev/null
+++ b/test/expressions/binary/bit-or/scalar-scalar/u32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f() {
+  uint const a = 1u;
+  uint const b = 2u;
+  uint const r = (a | b);
+  return;
+}
+
diff --git a/test/expressions/binary/bit-or/scalar-scalar/u32.wgsl.expected.spvasm b/test/expressions/binary/bit-or/scalar-scalar/u32.wgsl.expected.spvasm
new file mode 100644
index 0000000..0dd9b04
--- /dev/null
+++ b/test/expressions/binary/bit-or/scalar-scalar/u32.wgsl.expected.spvasm
@@ -0,0 +1,20 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 9
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %f "f"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+          %f = OpFunction %void None %1
+          %4 = OpLabel
+          %8 = OpBitwiseOr %uint %uint_1 %uint_2
+               OpReturn
+               OpFunctionEnd
diff --git a/test/expressions/binary/bit-or/scalar-scalar/u32.wgsl.expected.wgsl b/test/expressions/binary/bit-or/scalar-scalar/u32.wgsl.expected.wgsl
new file mode 100644
index 0000000..231ecb5
--- /dev/null
+++ b/test/expressions/binary/bit-or/scalar-scalar/u32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+  let a = 1u;
+  let b = 2u;
+  let r : u32 = (a | b);
+}
diff --git a/test/expressions/binary/bit-or/vec3-vec3/i32.wgsl b/test/expressions/binary/bit-or/vec3-vec3/i32.wgsl
new file mode 100644
index 0000000..dc5ed1c
--- /dev/null
+++ b/test/expressions/binary/bit-or/vec3-vec3/i32.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+    let a = vec3<i32>(1, 2, 3);
+    let b = vec3<i32>(4, 5, 6);
+    let r : vec3<i32> = a | b;
+}
diff --git a/test/expressions/binary/bit-or/vec3-vec3/i32.wgsl.expected.hlsl b/test/expressions/binary/bit-or/vec3-vec3/i32.wgsl.expected.hlsl
new file mode 100644
index 0000000..6d95413
--- /dev/null
+++ b/test/expressions/binary/bit-or/vec3-vec3/i32.wgsl.expected.hlsl
@@ -0,0 +1,7 @@
+[numthreads(1, 1, 1)]
+void f() {
+  const int3 a = int3(1, 2, 3);
+  const int3 b = int3(4, 5, 6);
+  const int3 r = (a | b);
+  return;
+}
diff --git a/test/expressions/binary/bit-or/vec3-vec3/i32.wgsl.expected.msl b/test/expressions/binary/bit-or/vec3-vec3/i32.wgsl.expected.msl
new file mode 100644
index 0000000..5096a8c
--- /dev/null
+++ b/test/expressions/binary/bit-or/vec3-vec3/i32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f() {
+  int3 const a = int3(1, 2, 3);
+  int3 const b = int3(4, 5, 6);
+  int3 const r = (a | b);
+  return;
+}
+
diff --git a/test/expressions/binary/bit-or/vec3-vec3/i32.wgsl.expected.spvasm b/test/expressions/binary/bit-or/vec3-vec3/i32.wgsl.expected.spvasm
new file mode 100644
index 0000000..3721f59
--- /dev/null
+++ b/test/expressions/binary/bit-or/vec3-vec3/i32.wgsl.expected.spvasm
@@ -0,0 +1,27 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 16
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %f "f"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+        %int = OpTypeInt 32 1
+      %v3int = OpTypeVector %int 3
+      %int_1 = OpConstant %int 1
+      %int_2 = OpConstant %int 2
+      %int_3 = OpConstant %int 3
+         %10 = OpConstantComposite %v3int %int_1 %int_2 %int_3
+      %int_4 = OpConstant %int 4
+      %int_5 = OpConstant %int 5
+      %int_6 = OpConstant %int 6
+         %14 = OpConstantComposite %v3int %int_4 %int_5 %int_6
+          %f = OpFunction %void None %1
+          %4 = OpLabel
+         %15 = OpBitwiseOr %v3int %10 %14
+               OpReturn
+               OpFunctionEnd
diff --git a/test/expressions/binary/bit-or/vec3-vec3/i32.wgsl.expected.wgsl b/test/expressions/binary/bit-or/vec3-vec3/i32.wgsl.expected.wgsl
new file mode 100644
index 0000000..8941e04
--- /dev/null
+++ b/test/expressions/binary/bit-or/vec3-vec3/i32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+  let a = vec3<i32>(1, 2, 3);
+  let b = vec3<i32>(4, 5, 6);
+  let r : vec3<i32> = (a | b);
+}
diff --git a/test/expressions/binary/bit-or/vec3-vec3/u32.wgsl b/test/expressions/binary/bit-or/vec3-vec3/u32.wgsl
new file mode 100644
index 0000000..e1adda8
--- /dev/null
+++ b/test/expressions/binary/bit-or/vec3-vec3/u32.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+    let a = vec3<u32>(1u, 2u, 3u);
+    let b = vec3<u32>(4u, 5u, 6u);
+    let r : vec3<u32> = a | b;
+}
diff --git a/test/expressions/binary/bit-or/vec3-vec3/u32.wgsl.expected.hlsl b/test/expressions/binary/bit-or/vec3-vec3/u32.wgsl.expected.hlsl
new file mode 100644
index 0000000..4e2c7a5
--- /dev/null
+++ b/test/expressions/binary/bit-or/vec3-vec3/u32.wgsl.expected.hlsl
@@ -0,0 +1,7 @@
+[numthreads(1, 1, 1)]
+void f() {
+  const uint3 a = uint3(1u, 2u, 3u);
+  const uint3 b = uint3(4u, 5u, 6u);
+  const uint3 r = (a | b);
+  return;
+}
diff --git a/test/expressions/binary/bit-or/vec3-vec3/u32.wgsl.expected.msl b/test/expressions/binary/bit-or/vec3-vec3/u32.wgsl.expected.msl
new file mode 100644
index 0000000..f2f90d0
--- /dev/null
+++ b/test/expressions/binary/bit-or/vec3-vec3/u32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f() {
+  uint3 const a = uint3(1u, 2u, 3u);
+  uint3 const b = uint3(4u, 5u, 6u);
+  uint3 const r = (a | b);
+  return;
+}
+
diff --git a/test/expressions/binary/bit-or/vec3-vec3/u32.wgsl.expected.spvasm b/test/expressions/binary/bit-or/vec3-vec3/u32.wgsl.expected.spvasm
new file mode 100644
index 0000000..9a82d90
--- /dev/null
+++ b/test/expressions/binary/bit-or/vec3-vec3/u32.wgsl.expected.spvasm
@@ -0,0 +1,27 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 16
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %f "f"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %v3uint = OpTypeVector %uint 3
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+     %uint_3 = OpConstant %uint 3
+         %10 = OpConstantComposite %v3uint %uint_1 %uint_2 %uint_3
+     %uint_4 = OpConstant %uint 4
+     %uint_5 = OpConstant %uint 5
+     %uint_6 = OpConstant %uint 6
+         %14 = OpConstantComposite %v3uint %uint_4 %uint_5 %uint_6
+          %f = OpFunction %void None %1
+          %4 = OpLabel
+         %15 = OpBitwiseOr %v3uint %10 %14
+               OpReturn
+               OpFunctionEnd
diff --git a/test/expressions/binary/bit-or/vec3-vec3/u32.wgsl.expected.wgsl b/test/expressions/binary/bit-or/vec3-vec3/u32.wgsl.expected.wgsl
new file mode 100644
index 0000000..800d5d0
--- /dev/null
+++ b/test/expressions/binary/bit-or/vec3-vec3/u32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+  let a = vec3<u32>(1u, 2u, 3u);
+  let b = vec3<u32>(4u, 5u, 6u);
+  let r : vec3<u32> = (a | b);
+}
diff --git a/test/expressions/binary/bit-xor/scalar-scalar/i32.wgsl b/test/expressions/binary/bit-xor/scalar-scalar/i32.wgsl
new file mode 100644
index 0000000..c0112a3
--- /dev/null
+++ b/test/expressions/binary/bit-xor/scalar-scalar/i32.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+    let a = 1;
+    let b = 2;
+    let r : i32 = a ^ b;
+}
diff --git a/test/expressions/binary/bit-xor/scalar-scalar/i32.wgsl.expected.hlsl b/test/expressions/binary/bit-xor/scalar-scalar/i32.wgsl.expected.hlsl
new file mode 100644
index 0000000..f3a33ad
--- /dev/null
+++ b/test/expressions/binary/bit-xor/scalar-scalar/i32.wgsl.expected.hlsl
@@ -0,0 +1,5 @@
+[numthreads(1, 1, 1)]
+void f() {
+  const int r = (1 ^ 2);
+  return;
+}
diff --git a/test/expressions/binary/bit-xor/scalar-scalar/i32.wgsl.expected.msl b/test/expressions/binary/bit-xor/scalar-scalar/i32.wgsl.expected.msl
new file mode 100644
index 0000000..62360a8
--- /dev/null
+++ b/test/expressions/binary/bit-xor/scalar-scalar/i32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f() {
+  int const a = 1;
+  int const b = 2;
+  int const r = (a ^ b);
+  return;
+}
+
diff --git a/test/expressions/binary/bit-xor/scalar-scalar/i32.wgsl.expected.spvasm b/test/expressions/binary/bit-xor/scalar-scalar/i32.wgsl.expected.spvasm
new file mode 100644
index 0000000..32398d0
--- /dev/null
+++ b/test/expressions/binary/bit-xor/scalar-scalar/i32.wgsl.expected.spvasm
@@ -0,0 +1,20 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 9
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %f "f"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+      %int_2 = OpConstant %int 2
+          %f = OpFunction %void None %1
+          %4 = OpLabel
+          %8 = OpBitwiseXor %int %int_1 %int_2
+               OpReturn
+               OpFunctionEnd
diff --git a/test/expressions/binary/bit-xor/scalar-scalar/i32.wgsl.expected.wgsl b/test/expressions/binary/bit-xor/scalar-scalar/i32.wgsl.expected.wgsl
new file mode 100644
index 0000000..860a11d
--- /dev/null
+++ b/test/expressions/binary/bit-xor/scalar-scalar/i32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+  let a = 1;
+  let b = 2;
+  let r : i32 = (a ^ b);
+}
diff --git a/test/expressions/binary/bit-xor/scalar-scalar/u32.wgsl b/test/expressions/binary/bit-xor/scalar-scalar/u32.wgsl
new file mode 100644
index 0000000..32d3b95
--- /dev/null
+++ b/test/expressions/binary/bit-xor/scalar-scalar/u32.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+    let a = 1u;
+    let b = 2u;
+    let r : u32 = a ^ b;
+}
diff --git a/test/expressions/binary/bit-xor/scalar-scalar/u32.wgsl.expected.hlsl b/test/expressions/binary/bit-xor/scalar-scalar/u32.wgsl.expected.hlsl
new file mode 100644
index 0000000..5e4b909
--- /dev/null
+++ b/test/expressions/binary/bit-xor/scalar-scalar/u32.wgsl.expected.hlsl
@@ -0,0 +1,5 @@
+[numthreads(1, 1, 1)]
+void f() {
+  const uint r = (1u ^ 2u);
+  return;
+}
diff --git a/test/expressions/binary/bit-xor/scalar-scalar/u32.wgsl.expected.msl b/test/expressions/binary/bit-xor/scalar-scalar/u32.wgsl.expected.msl
new file mode 100644
index 0000000..8093c0c
--- /dev/null
+++ b/test/expressions/binary/bit-xor/scalar-scalar/u32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f() {
+  uint const a = 1u;
+  uint const b = 2u;
+  uint const r = (a ^ b);
+  return;
+}
+
diff --git a/test/expressions/binary/bit-xor/scalar-scalar/u32.wgsl.expected.spvasm b/test/expressions/binary/bit-xor/scalar-scalar/u32.wgsl.expected.spvasm
new file mode 100644
index 0000000..5855aa7
--- /dev/null
+++ b/test/expressions/binary/bit-xor/scalar-scalar/u32.wgsl.expected.spvasm
@@ -0,0 +1,20 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 9
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %f "f"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+          %f = OpFunction %void None %1
+          %4 = OpLabel
+          %8 = OpBitwiseXor %uint %uint_1 %uint_2
+               OpReturn
+               OpFunctionEnd
diff --git a/test/expressions/binary/bit-xor/scalar-scalar/u32.wgsl.expected.wgsl b/test/expressions/binary/bit-xor/scalar-scalar/u32.wgsl.expected.wgsl
new file mode 100644
index 0000000..26dda45
--- /dev/null
+++ b/test/expressions/binary/bit-xor/scalar-scalar/u32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+  let a = 1u;
+  let b = 2u;
+  let r : u32 = (a ^ b);
+}
diff --git a/test/expressions/binary/bit-xor/vec3-vec3/i32.wgsl b/test/expressions/binary/bit-xor/vec3-vec3/i32.wgsl
new file mode 100644
index 0000000..c4972f7
--- /dev/null
+++ b/test/expressions/binary/bit-xor/vec3-vec3/i32.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+    let a = vec3<i32>(1, 2, 3);
+    let b = vec3<i32>(4, 5, 6);
+    let r : vec3<i32> = a ^ b;
+}
diff --git a/test/expressions/binary/bit-xor/vec3-vec3/i32.wgsl.expected.hlsl b/test/expressions/binary/bit-xor/vec3-vec3/i32.wgsl.expected.hlsl
new file mode 100644
index 0000000..db0a3c1
--- /dev/null
+++ b/test/expressions/binary/bit-xor/vec3-vec3/i32.wgsl.expected.hlsl
@@ -0,0 +1,7 @@
+[numthreads(1, 1, 1)]
+void f() {
+  const int3 a = int3(1, 2, 3);
+  const int3 b = int3(4, 5, 6);
+  const int3 r = (a ^ b);
+  return;
+}
diff --git a/test/expressions/binary/bit-xor/vec3-vec3/i32.wgsl.expected.msl b/test/expressions/binary/bit-xor/vec3-vec3/i32.wgsl.expected.msl
new file mode 100644
index 0000000..82c280b
--- /dev/null
+++ b/test/expressions/binary/bit-xor/vec3-vec3/i32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f() {
+  int3 const a = int3(1, 2, 3);
+  int3 const b = int3(4, 5, 6);
+  int3 const r = (a ^ b);
+  return;
+}
+
diff --git a/test/expressions/binary/bit-xor/vec3-vec3/i32.wgsl.expected.spvasm b/test/expressions/binary/bit-xor/vec3-vec3/i32.wgsl.expected.spvasm
new file mode 100644
index 0000000..51e7ba8
--- /dev/null
+++ b/test/expressions/binary/bit-xor/vec3-vec3/i32.wgsl.expected.spvasm
@@ -0,0 +1,27 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 16
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %f "f"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+        %int = OpTypeInt 32 1
+      %v3int = OpTypeVector %int 3
+      %int_1 = OpConstant %int 1
+      %int_2 = OpConstant %int 2
+      %int_3 = OpConstant %int 3
+         %10 = OpConstantComposite %v3int %int_1 %int_2 %int_3
+      %int_4 = OpConstant %int 4
+      %int_5 = OpConstant %int 5
+      %int_6 = OpConstant %int 6
+         %14 = OpConstantComposite %v3int %int_4 %int_5 %int_6
+          %f = OpFunction %void None %1
+          %4 = OpLabel
+         %15 = OpBitwiseXor %v3int %10 %14
+               OpReturn
+               OpFunctionEnd
diff --git a/test/expressions/binary/bit-xor/vec3-vec3/i32.wgsl.expected.wgsl b/test/expressions/binary/bit-xor/vec3-vec3/i32.wgsl.expected.wgsl
new file mode 100644
index 0000000..2811f15
--- /dev/null
+++ b/test/expressions/binary/bit-xor/vec3-vec3/i32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+  let a = vec3<i32>(1, 2, 3);
+  let b = vec3<i32>(4, 5, 6);
+  let r : vec3<i32> = (a ^ b);
+}
diff --git a/test/expressions/binary/bit-xor/vec3-vec3/u32.wgsl b/test/expressions/binary/bit-xor/vec3-vec3/u32.wgsl
new file mode 100644
index 0000000..2e62570
--- /dev/null
+++ b/test/expressions/binary/bit-xor/vec3-vec3/u32.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+    let a = vec3<u32>(1u, 2u, 3u);
+    let b = vec3<u32>(4u, 5u, 6u);
+    let r : vec3<u32> = a ^ b;
+}
diff --git a/test/expressions/binary/bit-xor/vec3-vec3/u32.wgsl.expected.hlsl b/test/expressions/binary/bit-xor/vec3-vec3/u32.wgsl.expected.hlsl
new file mode 100644
index 0000000..e29687a
--- /dev/null
+++ b/test/expressions/binary/bit-xor/vec3-vec3/u32.wgsl.expected.hlsl
@@ -0,0 +1,7 @@
+[numthreads(1, 1, 1)]
+void f() {
+  const uint3 a = uint3(1u, 2u, 3u);
+  const uint3 b = uint3(4u, 5u, 6u);
+  const uint3 r = (a ^ b);
+  return;
+}
diff --git a/test/expressions/binary/bit-xor/vec3-vec3/u32.wgsl.expected.msl b/test/expressions/binary/bit-xor/vec3-vec3/u32.wgsl.expected.msl
new file mode 100644
index 0000000..d77b0b5
--- /dev/null
+++ b/test/expressions/binary/bit-xor/vec3-vec3/u32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f() {
+  uint3 const a = uint3(1u, 2u, 3u);
+  uint3 const b = uint3(4u, 5u, 6u);
+  uint3 const r = (a ^ b);
+  return;
+}
+
diff --git a/test/expressions/binary/bit-xor/vec3-vec3/u32.wgsl.expected.spvasm b/test/expressions/binary/bit-xor/vec3-vec3/u32.wgsl.expected.spvasm
new file mode 100644
index 0000000..844d22d
--- /dev/null
+++ b/test/expressions/binary/bit-xor/vec3-vec3/u32.wgsl.expected.spvasm
@@ -0,0 +1,27 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 16
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %f "f"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %v3uint = OpTypeVector %uint 3
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+     %uint_3 = OpConstant %uint 3
+         %10 = OpConstantComposite %v3uint %uint_1 %uint_2 %uint_3
+     %uint_4 = OpConstant %uint 4
+     %uint_5 = OpConstant %uint 5
+     %uint_6 = OpConstant %uint 6
+         %14 = OpConstantComposite %v3uint %uint_4 %uint_5 %uint_6
+          %f = OpFunction %void None %1
+          %4 = OpLabel
+         %15 = OpBitwiseXor %v3uint %10 %14
+               OpReturn
+               OpFunctionEnd
diff --git a/test/expressions/binary/bit-xor/vec3-vec3/u32.wgsl.expected.wgsl b/test/expressions/binary/bit-xor/vec3-vec3/u32.wgsl.expected.wgsl
new file mode 100644
index 0000000..4ba52c5
--- /dev/null
+++ b/test/expressions/binary/bit-xor/vec3-vec3/u32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+  let a = vec3<u32>(1u, 2u, 3u);
+  let b = vec3<u32>(4u, 5u, 6u);
+  let r : vec3<u32> = (a ^ b);
+}
diff --git a/test/expressions/binary/div/scalar-scalar/f32.wgsl b/test/expressions/binary/div/scalar-scalar/f32.wgsl
new file mode 100644
index 0000000..50cabd0
--- /dev/null
+++ b/test/expressions/binary/div/scalar-scalar/f32.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+    let a = 1.;
+    let b = 2.;
+    let r : f32 = a / b;
+}
diff --git a/test/expressions/binary/div/scalar-scalar/f32.wgsl.expected.hlsl b/test/expressions/binary/div/scalar-scalar/f32.wgsl.expected.hlsl
new file mode 100644
index 0000000..e9f00ff
--- /dev/null
+++ b/test/expressions/binary/div/scalar-scalar/f32.wgsl.expected.hlsl
@@ -0,0 +1,5 @@
+[numthreads(1, 1, 1)]
+void f() {
+  const float r = (1.0f / 2.0f);
+  return;
+}
diff --git a/test/expressions/binary/div/scalar-scalar/f32.wgsl.expected.msl b/test/expressions/binary/div/scalar-scalar/f32.wgsl.expected.msl
new file mode 100644
index 0000000..5268a5e
--- /dev/null
+++ b/test/expressions/binary/div/scalar-scalar/f32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f() {
+  float const a = 1.0f;
+  float const b = 2.0f;
+  float const r = (a / b);
+  return;
+}
+
diff --git a/test/expressions/binary/div/scalar-scalar/f32.wgsl.expected.spvasm b/test/expressions/binary/div/scalar-scalar/f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..827625e
--- /dev/null
+++ b/test/expressions/binary/div/scalar-scalar/f32.wgsl.expected.spvasm
@@ -0,0 +1,20 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 9
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %f "f"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+      %float = OpTypeFloat 32
+    %float_1 = OpConstant %float 1
+    %float_2 = OpConstant %float 2
+          %f = OpFunction %void None %1
+          %4 = OpLabel
+          %8 = OpFDiv %float %float_1 %float_2
+               OpReturn
+               OpFunctionEnd
diff --git a/test/expressions/binary/div/scalar-scalar/f32.wgsl.expected.wgsl b/test/expressions/binary/div/scalar-scalar/f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..5bc760d
--- /dev/null
+++ b/test/expressions/binary/div/scalar-scalar/f32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+  let a = 1.0;
+  let b = 2.0;
+  let r : f32 = (a / b);
+}
diff --git a/test/expressions/binary/div/scalar-scalar/i32.wgsl b/test/expressions/binary/div/scalar-scalar/i32.wgsl
new file mode 100644
index 0000000..1192d80
--- /dev/null
+++ b/test/expressions/binary/div/scalar-scalar/i32.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+    let a = 1;
+    let b = 2;
+    let r : i32 = a / b;
+}
diff --git a/test/expressions/binary/div/scalar-scalar/i32.wgsl.expected.hlsl b/test/expressions/binary/div/scalar-scalar/i32.wgsl.expected.hlsl
new file mode 100644
index 0000000..8fe265a
--- /dev/null
+++ b/test/expressions/binary/div/scalar-scalar/i32.wgsl.expected.hlsl
@@ -0,0 +1,5 @@
+[numthreads(1, 1, 1)]
+void f() {
+  const int r = (1 / 2);
+  return;
+}
diff --git a/test/expressions/binary/div/scalar-scalar/i32.wgsl.expected.msl b/test/expressions/binary/div/scalar-scalar/i32.wgsl.expected.msl
new file mode 100644
index 0000000..17d1709
--- /dev/null
+++ b/test/expressions/binary/div/scalar-scalar/i32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f() {
+  int const a = 1;
+  int const b = 2;
+  int const r = (a / b);
+  return;
+}
+
diff --git a/test/expressions/binary/div/scalar-scalar/i32.wgsl.expected.spvasm b/test/expressions/binary/div/scalar-scalar/i32.wgsl.expected.spvasm
new file mode 100644
index 0000000..b5a41dc
--- /dev/null
+++ b/test/expressions/binary/div/scalar-scalar/i32.wgsl.expected.spvasm
@@ -0,0 +1,20 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 9
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %f "f"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+      %int_2 = OpConstant %int 2
+          %f = OpFunction %void None %1
+          %4 = OpLabel
+          %8 = OpSDiv %int %int_1 %int_2
+               OpReturn
+               OpFunctionEnd
diff --git a/test/expressions/binary/div/scalar-scalar/i32.wgsl.expected.wgsl b/test/expressions/binary/div/scalar-scalar/i32.wgsl.expected.wgsl
new file mode 100644
index 0000000..6ecb865
--- /dev/null
+++ b/test/expressions/binary/div/scalar-scalar/i32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+  let a = 1;
+  let b = 2;
+  let r : i32 = (a / b);
+}
diff --git a/test/expressions/binary/div/scalar-scalar/u32.wgsl b/test/expressions/binary/div/scalar-scalar/u32.wgsl
new file mode 100644
index 0000000..6e18ad7
--- /dev/null
+++ b/test/expressions/binary/div/scalar-scalar/u32.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+    let a = 1u;
+    let b = 2u;
+    let r : u32 = a / b;
+}
diff --git a/test/expressions/binary/div/scalar-scalar/u32.wgsl.expected.hlsl b/test/expressions/binary/div/scalar-scalar/u32.wgsl.expected.hlsl
new file mode 100644
index 0000000..f1d7c0c
--- /dev/null
+++ b/test/expressions/binary/div/scalar-scalar/u32.wgsl.expected.hlsl
@@ -0,0 +1,5 @@
+[numthreads(1, 1, 1)]
+void f() {
+  const uint r = (1u / 2u);
+  return;
+}
diff --git a/test/expressions/binary/div/scalar-scalar/u32.wgsl.expected.msl b/test/expressions/binary/div/scalar-scalar/u32.wgsl.expected.msl
new file mode 100644
index 0000000..fa9d9e7
--- /dev/null
+++ b/test/expressions/binary/div/scalar-scalar/u32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f() {
+  uint const a = 1u;
+  uint const b = 2u;
+  uint const r = (a / b);
+  return;
+}
+
diff --git a/test/expressions/binary/div/scalar-scalar/u32.wgsl.expected.spvasm b/test/expressions/binary/div/scalar-scalar/u32.wgsl.expected.spvasm
new file mode 100644
index 0000000..012fb2b
--- /dev/null
+++ b/test/expressions/binary/div/scalar-scalar/u32.wgsl.expected.spvasm
@@ -0,0 +1,20 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 9
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %f "f"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+          %f = OpFunction %void None %1
+          %4 = OpLabel
+          %8 = OpUDiv %uint %uint_1 %uint_2
+               OpReturn
+               OpFunctionEnd
diff --git a/test/expressions/binary/div/scalar-scalar/u32.wgsl.expected.wgsl b/test/expressions/binary/div/scalar-scalar/u32.wgsl.expected.wgsl
new file mode 100644
index 0000000..b5d2f7e
--- /dev/null
+++ b/test/expressions/binary/div/scalar-scalar/u32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+  let a = 1u;
+  let b = 2u;
+  let r : u32 = (a / b);
+}
diff --git a/test/expressions/binary/div/scalar-vec3/f32.wgsl b/test/expressions/binary/div/scalar-vec3/f32.wgsl
new file mode 100644
index 0000000..a9cab92
--- /dev/null
+++ b/test/expressions/binary/div/scalar-vec3/f32.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+    let a = 4.;
+    let b = vec3<f32>(1., 2., 3.);
+    let r : vec3<f32> = a / b;
+}
diff --git a/test/expressions/binary/div/scalar-vec3/f32.wgsl.expected.hlsl b/test/expressions/binary/div/scalar-vec3/f32.wgsl.expected.hlsl
new file mode 100644
index 0000000..3eabba0
--- /dev/null
+++ b/test/expressions/binary/div/scalar-vec3/f32.wgsl.expected.hlsl
@@ -0,0 +1,7 @@
+[numthreads(1, 1, 1)]
+void f() {
+  const float a = 4.0f;
+  const float3 b = float3(1.0f, 2.0f, 3.0f);
+  const float3 r = (a / b);
+  return;
+}
diff --git a/test/expressions/binary/div/scalar-vec3/f32.wgsl.expected.msl b/test/expressions/binary/div/scalar-vec3/f32.wgsl.expected.msl
new file mode 100644
index 0000000..1fed91b
--- /dev/null
+++ b/test/expressions/binary/div/scalar-vec3/f32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f() {
+  float const a = 4.0f;
+  float3 const b = float3(1.0f, 2.0f, 3.0f);
+  float3 const r = (a / b);
+  return;
+}
+
diff --git a/test/expressions/binary/div/scalar-vec3/f32.wgsl.expected.spvasm b/test/expressions/binary/div/scalar-vec3/f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..aed0688
--- /dev/null
+++ b/test/expressions/binary/div/scalar-vec3/f32.wgsl.expected.spvasm
@@ -0,0 +1,28 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 17
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %f "f"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+      %float = OpTypeFloat 32
+    %float_4 = OpConstant %float 4
+    %v3float = OpTypeVector %float 3
+    %float_1 = OpConstant %float 1
+    %float_2 = OpConstant %float 2
+    %float_3 = OpConstant %float 3
+         %11 = OpConstantComposite %v3float %float_1 %float_2 %float_3
+%_ptr_Function_v3float = OpTypePointer Function %v3float
+         %15 = OpConstantNull %v3float
+          %f = OpFunction %void None %1
+          %4 = OpLabel
+         %13 = OpVariable %_ptr_Function_v3float Function %15
+         %16 = OpCompositeConstruct %v3float %float_4 %float_4 %float_4
+         %12 = OpFDiv %v3float %16 %11
+               OpReturn
+               OpFunctionEnd
diff --git a/test/expressions/binary/div/scalar-vec3/f32.wgsl.expected.wgsl b/test/expressions/binary/div/scalar-vec3/f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..bd9de59
--- /dev/null
+++ b/test/expressions/binary/div/scalar-vec3/f32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+  let a = 4.0;
+  let b = vec3<f32>(1.0, 2.0, 3.0);
+  let r : vec3<f32> = (a / b);
+}
diff --git a/test/expressions/binary/div/scalar-vec3/i32.wgsl b/test/expressions/binary/div/scalar-vec3/i32.wgsl
new file mode 100644
index 0000000..ae9daea
--- /dev/null
+++ b/test/expressions/binary/div/scalar-vec3/i32.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+    let a = 4;
+    let b = vec3<i32>(1, 2, 3);
+    let r : vec3<i32> = a / b;
+}
diff --git a/test/expressions/binary/div/scalar-vec3/i32.wgsl.expected.hlsl b/test/expressions/binary/div/scalar-vec3/i32.wgsl.expected.hlsl
new file mode 100644
index 0000000..cb4a95b
--- /dev/null
+++ b/test/expressions/binary/div/scalar-vec3/i32.wgsl.expected.hlsl
@@ -0,0 +1,7 @@
+[numthreads(1, 1, 1)]
+void f() {
+  const int a = 4;
+  const int3 b = int3(1, 2, 3);
+  const int3 r = (a / b);
+  return;
+}
diff --git a/test/expressions/binary/div/scalar-vec3/i32.wgsl.expected.msl b/test/expressions/binary/div/scalar-vec3/i32.wgsl.expected.msl
new file mode 100644
index 0000000..4124223
--- /dev/null
+++ b/test/expressions/binary/div/scalar-vec3/i32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f() {
+  int const a = 4;
+  int3 const b = int3(1, 2, 3);
+  int3 const r = (a / b);
+  return;
+}
+
diff --git a/test/expressions/binary/div/scalar-vec3/i32.wgsl.expected.spvasm b/test/expressions/binary/div/scalar-vec3/i32.wgsl.expected.spvasm
new file mode 100644
index 0000000..c52ce21
--- /dev/null
+++ b/test/expressions/binary/div/scalar-vec3/i32.wgsl.expected.spvasm
@@ -0,0 +1,28 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 17
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %f "f"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+        %int = OpTypeInt 32 1
+      %int_4 = OpConstant %int 4
+      %v3int = OpTypeVector %int 3
+      %int_1 = OpConstant %int 1
+      %int_2 = OpConstant %int 2
+      %int_3 = OpConstant %int 3
+         %11 = OpConstantComposite %v3int %int_1 %int_2 %int_3
+%_ptr_Function_v3int = OpTypePointer Function %v3int
+         %15 = OpConstantNull %v3int
+          %f = OpFunction %void None %1
+          %4 = OpLabel
+         %13 = OpVariable %_ptr_Function_v3int Function %15
+         %16 = OpCompositeConstruct %v3int %int_4 %int_4 %int_4
+         %12 = OpSDiv %v3int %16 %11
+               OpReturn
+               OpFunctionEnd
diff --git a/test/expressions/binary/div/scalar-vec3/i32.wgsl.expected.wgsl b/test/expressions/binary/div/scalar-vec3/i32.wgsl.expected.wgsl
new file mode 100644
index 0000000..6d7e7a4
--- /dev/null
+++ b/test/expressions/binary/div/scalar-vec3/i32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+  let a = 4;
+  let b = vec3<i32>(1, 2, 3);
+  let r : vec3<i32> = (a / b);
+}
diff --git a/test/expressions/binary/div/scalar-vec3/u32.wgsl b/test/expressions/binary/div/scalar-vec3/u32.wgsl
new file mode 100644
index 0000000..0923fb2
--- /dev/null
+++ b/test/expressions/binary/div/scalar-vec3/u32.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+    let a = 4u;
+    let b = vec3<u32>(1u, 2u, 3u);
+    let r : vec3<u32> = a / b;
+}
diff --git a/test/expressions/binary/div/scalar-vec3/u32.wgsl.expected.hlsl b/test/expressions/binary/div/scalar-vec3/u32.wgsl.expected.hlsl
new file mode 100644
index 0000000..8942ff8
--- /dev/null
+++ b/test/expressions/binary/div/scalar-vec3/u32.wgsl.expected.hlsl
@@ -0,0 +1,7 @@
+[numthreads(1, 1, 1)]
+void f() {
+  const uint a = 4u;
+  const uint3 b = uint3(1u, 2u, 3u);
+  const uint3 r = (a / b);
+  return;
+}
diff --git a/test/expressions/binary/div/scalar-vec3/u32.wgsl.expected.msl b/test/expressions/binary/div/scalar-vec3/u32.wgsl.expected.msl
new file mode 100644
index 0000000..aa59c35
--- /dev/null
+++ b/test/expressions/binary/div/scalar-vec3/u32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f() {
+  uint const a = 4u;
+  uint3 const b = uint3(1u, 2u, 3u);
+  uint3 const r = (a / b);
+  return;
+}
+
diff --git a/test/expressions/binary/div/scalar-vec3/u32.wgsl.expected.spvasm b/test/expressions/binary/div/scalar-vec3/u32.wgsl.expected.spvasm
new file mode 100644
index 0000000..3bf5436
--- /dev/null
+++ b/test/expressions/binary/div/scalar-vec3/u32.wgsl.expected.spvasm
@@ -0,0 +1,28 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 17
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %f "f"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+     %v3uint = OpTypeVector %uint 3
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+     %uint_3 = OpConstant %uint 3
+         %11 = OpConstantComposite %v3uint %uint_1 %uint_2 %uint_3
+%_ptr_Function_v3uint = OpTypePointer Function %v3uint
+         %15 = OpConstantNull %v3uint
+          %f = OpFunction %void None %1
+          %4 = OpLabel
+         %13 = OpVariable %_ptr_Function_v3uint Function %15
+         %16 = OpCompositeConstruct %v3uint %uint_4 %uint_4 %uint_4
+         %12 = OpUDiv %v3uint %16 %11
+               OpReturn
+               OpFunctionEnd
diff --git a/test/expressions/binary/div/scalar-vec3/u32.wgsl.expected.wgsl b/test/expressions/binary/div/scalar-vec3/u32.wgsl.expected.wgsl
new file mode 100644
index 0000000..5c678e8
--- /dev/null
+++ b/test/expressions/binary/div/scalar-vec3/u32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+  let a = 4u;
+  let b = vec3<u32>(1u, 2u, 3u);
+  let r : vec3<u32> = (a / b);
+}
diff --git a/test/expressions/binary/div/vec3-scalar/f32.wgsl b/test/expressions/binary/div/vec3-scalar/f32.wgsl
new file mode 100644
index 0000000..247abdf
--- /dev/null
+++ b/test/expressions/binary/div/vec3-scalar/f32.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+    let a = vec3<f32>(1., 2., 3.);
+    let b = 4.;
+    let r : vec3<f32> = a / b;
+}
diff --git a/test/expressions/binary/div/vec3-scalar/f32.wgsl.expected.hlsl b/test/expressions/binary/div/vec3-scalar/f32.wgsl.expected.hlsl
new file mode 100644
index 0000000..f1645a2
--- /dev/null
+++ b/test/expressions/binary/div/vec3-scalar/f32.wgsl.expected.hlsl
@@ -0,0 +1,6 @@
+[numthreads(1, 1, 1)]
+void f() {
+  const float3 a = float3(1.0f, 2.0f, 3.0f);
+  const float3 r = (a / 4.0f);
+  return;
+}
diff --git a/test/expressions/binary/div/vec3-scalar/f32.wgsl.expected.msl b/test/expressions/binary/div/vec3-scalar/f32.wgsl.expected.msl
new file mode 100644
index 0000000..8c1ca16
--- /dev/null
+++ b/test/expressions/binary/div/vec3-scalar/f32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f() {
+  float3 const a = float3(1.0f, 2.0f, 3.0f);
+  float const b = 4.0f;
+  float3 const r = (a / b);
+  return;
+}
+
diff --git a/test/expressions/binary/div/vec3-scalar/f32.wgsl.expected.spvasm b/test/expressions/binary/div/vec3-scalar/f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..3328802
--- /dev/null
+++ b/test/expressions/binary/div/vec3-scalar/f32.wgsl.expected.spvasm
@@ -0,0 +1,28 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 17
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %f "f"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+    %float_1 = OpConstant %float 1
+    %float_2 = OpConstant %float 2
+    %float_3 = OpConstant %float 3
+         %10 = OpConstantComposite %v3float %float_1 %float_2 %float_3
+    %float_4 = OpConstant %float 4
+%_ptr_Function_v3float = OpTypePointer Function %v3float
+         %15 = OpConstantNull %v3float
+          %f = OpFunction %void None %1
+          %4 = OpLabel
+         %13 = OpVariable %_ptr_Function_v3float Function %15
+         %16 = OpCompositeConstruct %v3float %float_4 %float_4 %float_4
+         %12 = OpFDiv %v3float %10 %16
+               OpReturn
+               OpFunctionEnd
diff --git a/test/expressions/binary/div/vec3-scalar/f32.wgsl.expected.wgsl b/test/expressions/binary/div/vec3-scalar/f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..df8a3df
--- /dev/null
+++ b/test/expressions/binary/div/vec3-scalar/f32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+  let a = vec3<f32>(1.0, 2.0, 3.0);
+  let b = 4.0;
+  let r : vec3<f32> = (a / b);
+}
diff --git a/test/expressions/binary/div/vec3-scalar/i32.wgsl b/test/expressions/binary/div/vec3-scalar/i32.wgsl
new file mode 100644
index 0000000..7e730df
--- /dev/null
+++ b/test/expressions/binary/div/vec3-scalar/i32.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+    let a = vec3<i32>(1, 2, 3);
+    let b = 4;
+    let r : vec3<i32> = a / b;
+}
diff --git a/test/expressions/binary/div/vec3-scalar/i32.wgsl.expected.hlsl b/test/expressions/binary/div/vec3-scalar/i32.wgsl.expected.hlsl
new file mode 100644
index 0000000..672f46e
--- /dev/null
+++ b/test/expressions/binary/div/vec3-scalar/i32.wgsl.expected.hlsl
@@ -0,0 +1,6 @@
+[numthreads(1, 1, 1)]
+void f() {
+  const int3 a = int3(1, 2, 3);
+  const int3 r = (a / 4);
+  return;
+}
diff --git a/test/expressions/binary/div/vec3-scalar/i32.wgsl.expected.msl b/test/expressions/binary/div/vec3-scalar/i32.wgsl.expected.msl
new file mode 100644
index 0000000..73678c8
--- /dev/null
+++ b/test/expressions/binary/div/vec3-scalar/i32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f() {
+  int3 const a = int3(1, 2, 3);
+  int const b = 4;
+  int3 const r = (a / b);
+  return;
+}
+
diff --git a/test/expressions/binary/div/vec3-scalar/i32.wgsl.expected.spvasm b/test/expressions/binary/div/vec3-scalar/i32.wgsl.expected.spvasm
new file mode 100644
index 0000000..be6616a
--- /dev/null
+++ b/test/expressions/binary/div/vec3-scalar/i32.wgsl.expected.spvasm
@@ -0,0 +1,28 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 17
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %f "f"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+        %int = OpTypeInt 32 1
+      %v3int = OpTypeVector %int 3
+      %int_1 = OpConstant %int 1
+      %int_2 = OpConstant %int 2
+      %int_3 = OpConstant %int 3
+         %10 = OpConstantComposite %v3int %int_1 %int_2 %int_3
+      %int_4 = OpConstant %int 4
+%_ptr_Function_v3int = OpTypePointer Function %v3int
+         %15 = OpConstantNull %v3int
+          %f = OpFunction %void None %1
+          %4 = OpLabel
+         %13 = OpVariable %_ptr_Function_v3int Function %15
+         %16 = OpCompositeConstruct %v3int %int_4 %int_4 %int_4
+         %12 = OpSDiv %v3int %10 %16
+               OpReturn
+               OpFunctionEnd
diff --git a/test/expressions/binary/div/vec3-scalar/i32.wgsl.expected.wgsl b/test/expressions/binary/div/vec3-scalar/i32.wgsl.expected.wgsl
new file mode 100644
index 0000000..fa76ca6
--- /dev/null
+++ b/test/expressions/binary/div/vec3-scalar/i32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+  let a = vec3<i32>(1, 2, 3);
+  let b = 4;
+  let r : vec3<i32> = (a / b);
+}
diff --git a/test/expressions/binary/div/vec3-scalar/u32.wgsl b/test/expressions/binary/div/vec3-scalar/u32.wgsl
new file mode 100644
index 0000000..5eadf33
--- /dev/null
+++ b/test/expressions/binary/div/vec3-scalar/u32.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+    let a = vec3<u32>(1u, 2u, 3u);
+    let b = 4u;
+    let r : vec3<u32> = a / b;
+}
diff --git a/test/expressions/binary/div/vec3-scalar/u32.wgsl.expected.hlsl b/test/expressions/binary/div/vec3-scalar/u32.wgsl.expected.hlsl
new file mode 100644
index 0000000..2f4dc9c
--- /dev/null
+++ b/test/expressions/binary/div/vec3-scalar/u32.wgsl.expected.hlsl
@@ -0,0 +1,6 @@
+[numthreads(1, 1, 1)]
+void f() {
+  const uint3 a = uint3(1u, 2u, 3u);
+  const uint3 r = (a / 4u);
+  return;
+}
diff --git a/test/expressions/binary/div/vec3-scalar/u32.wgsl.expected.msl b/test/expressions/binary/div/vec3-scalar/u32.wgsl.expected.msl
new file mode 100644
index 0000000..749829b
--- /dev/null
+++ b/test/expressions/binary/div/vec3-scalar/u32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f() {
+  uint3 const a = uint3(1u, 2u, 3u);
+  uint const b = 4u;
+  uint3 const r = (a / b);
+  return;
+}
+
diff --git a/test/expressions/binary/div/vec3-scalar/u32.wgsl.expected.spvasm b/test/expressions/binary/div/vec3-scalar/u32.wgsl.expected.spvasm
new file mode 100644
index 0000000..9a52fdc
--- /dev/null
+++ b/test/expressions/binary/div/vec3-scalar/u32.wgsl.expected.spvasm
@@ -0,0 +1,28 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 17
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %f "f"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %v3uint = OpTypeVector %uint 3
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+     %uint_3 = OpConstant %uint 3
+         %10 = OpConstantComposite %v3uint %uint_1 %uint_2 %uint_3
+     %uint_4 = OpConstant %uint 4
+%_ptr_Function_v3uint = OpTypePointer Function %v3uint
+         %15 = OpConstantNull %v3uint
+          %f = OpFunction %void None %1
+          %4 = OpLabel
+         %13 = OpVariable %_ptr_Function_v3uint Function %15
+         %16 = OpCompositeConstruct %v3uint %uint_4 %uint_4 %uint_4
+         %12 = OpUDiv %v3uint %10 %16
+               OpReturn
+               OpFunctionEnd
diff --git a/test/expressions/binary/div/vec3-scalar/u32.wgsl.expected.wgsl b/test/expressions/binary/div/vec3-scalar/u32.wgsl.expected.wgsl
new file mode 100644
index 0000000..8e60c28
--- /dev/null
+++ b/test/expressions/binary/div/vec3-scalar/u32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+  let a = vec3<u32>(1u, 2u, 3u);
+  let b = 4u;
+  let r : vec3<u32> = (a / b);
+}
diff --git a/test/expressions/binary/div/vec3-vec3/f32.wgsl b/test/expressions/binary/div/vec3-vec3/f32.wgsl
new file mode 100644
index 0000000..f779554
--- /dev/null
+++ b/test/expressions/binary/div/vec3-vec3/f32.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+    let a = vec3<f32>(1., 2., 3.);
+    let b = vec3<f32>(4., 5., 6.);
+    let r : vec3<f32> = a / b;
+}
diff --git a/test/expressions/binary/div/vec3-vec3/f32.wgsl.expected.hlsl b/test/expressions/binary/div/vec3-vec3/f32.wgsl.expected.hlsl
new file mode 100644
index 0000000..7ae0123
--- /dev/null
+++ b/test/expressions/binary/div/vec3-vec3/f32.wgsl.expected.hlsl
@@ -0,0 +1,7 @@
+[numthreads(1, 1, 1)]
+void f() {
+  const float3 a = float3(1.0f, 2.0f, 3.0f);
+  const float3 b = float3(4.0f, 5.0f, 6.0f);
+  const float3 r = (a / b);
+  return;
+}
diff --git a/test/expressions/binary/div/vec3-vec3/f32.wgsl.expected.msl b/test/expressions/binary/div/vec3-vec3/f32.wgsl.expected.msl
new file mode 100644
index 0000000..a2c6698
--- /dev/null
+++ b/test/expressions/binary/div/vec3-vec3/f32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f() {
+  float3 const a = float3(1.0f, 2.0f, 3.0f);
+  float3 const b = float3(4.0f, 5.0f, 6.0f);
+  float3 const r = (a / b);
+  return;
+}
+
diff --git a/test/expressions/binary/div/vec3-vec3/f32.wgsl.expected.spvasm b/test/expressions/binary/div/vec3-vec3/f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..842bcd7
--- /dev/null
+++ b/test/expressions/binary/div/vec3-vec3/f32.wgsl.expected.spvasm
@@ -0,0 +1,27 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 16
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %f "f"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+    %float_1 = OpConstant %float 1
+    %float_2 = OpConstant %float 2
+    %float_3 = OpConstant %float 3
+         %10 = OpConstantComposite %v3float %float_1 %float_2 %float_3
+    %float_4 = OpConstant %float 4
+    %float_5 = OpConstant %float 5
+    %float_6 = OpConstant %float 6
+         %14 = OpConstantComposite %v3float %float_4 %float_5 %float_6
+          %f = OpFunction %void None %1
+          %4 = OpLabel
+         %15 = OpFDiv %v3float %10 %14
+               OpReturn
+               OpFunctionEnd
diff --git a/test/expressions/binary/div/vec3-vec3/f32.wgsl.expected.wgsl b/test/expressions/binary/div/vec3-vec3/f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..e824aa5
--- /dev/null
+++ b/test/expressions/binary/div/vec3-vec3/f32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+  let a = vec3<f32>(1.0, 2.0, 3.0);
+  let b = vec3<f32>(4.0, 5.0, 6.0);
+  let r : vec3<f32> = (a / b);
+}
diff --git a/test/expressions/binary/div/vec3-vec3/i32.wgsl b/test/expressions/binary/div/vec3-vec3/i32.wgsl
new file mode 100644
index 0000000..40e6d7a
--- /dev/null
+++ b/test/expressions/binary/div/vec3-vec3/i32.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+    let a = vec3<i32>(1, 2, 3);
+    let b = vec3<i32>(4, 5, 6);
+    let r : vec3<i32> = a / b;
+}
diff --git a/test/expressions/binary/div/vec3-vec3/i32.wgsl.expected.hlsl b/test/expressions/binary/div/vec3-vec3/i32.wgsl.expected.hlsl
new file mode 100644
index 0000000..33a4443
--- /dev/null
+++ b/test/expressions/binary/div/vec3-vec3/i32.wgsl.expected.hlsl
@@ -0,0 +1,7 @@
+[numthreads(1, 1, 1)]
+void f() {
+  const int3 a = int3(1, 2, 3);
+  const int3 b = int3(4, 5, 6);
+  const int3 r = (a / b);
+  return;
+}
diff --git a/test/expressions/binary/div/vec3-vec3/i32.wgsl.expected.msl b/test/expressions/binary/div/vec3-vec3/i32.wgsl.expected.msl
new file mode 100644
index 0000000..bb0f942
--- /dev/null
+++ b/test/expressions/binary/div/vec3-vec3/i32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f() {
+  int3 const a = int3(1, 2, 3);
+  int3 const b = int3(4, 5, 6);
+  int3 const r = (a / b);
+  return;
+}
+
diff --git a/test/expressions/binary/div/vec3-vec3/i32.wgsl.expected.spvasm b/test/expressions/binary/div/vec3-vec3/i32.wgsl.expected.spvasm
new file mode 100644
index 0000000..f0115f7
--- /dev/null
+++ b/test/expressions/binary/div/vec3-vec3/i32.wgsl.expected.spvasm
@@ -0,0 +1,27 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 16
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %f "f"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+        %int = OpTypeInt 32 1
+      %v3int = OpTypeVector %int 3
+      %int_1 = OpConstant %int 1
+      %int_2 = OpConstant %int 2
+      %int_3 = OpConstant %int 3
+         %10 = OpConstantComposite %v3int %int_1 %int_2 %int_3
+      %int_4 = OpConstant %int 4
+      %int_5 = OpConstant %int 5
+      %int_6 = OpConstant %int 6
+         %14 = OpConstantComposite %v3int %int_4 %int_5 %int_6
+          %f = OpFunction %void None %1
+          %4 = OpLabel
+         %15 = OpSDiv %v3int %10 %14
+               OpReturn
+               OpFunctionEnd
diff --git a/test/expressions/binary/div/vec3-vec3/i32.wgsl.expected.wgsl b/test/expressions/binary/div/vec3-vec3/i32.wgsl.expected.wgsl
new file mode 100644
index 0000000..940e6d9
--- /dev/null
+++ b/test/expressions/binary/div/vec3-vec3/i32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+  let a = vec3<i32>(1, 2, 3);
+  let b = vec3<i32>(4, 5, 6);
+  let r : vec3<i32> = (a / b);
+}
diff --git a/test/expressions/binary/div/vec3-vec3/u32.wgsl b/test/expressions/binary/div/vec3-vec3/u32.wgsl
new file mode 100644
index 0000000..39fdc1d
--- /dev/null
+++ b/test/expressions/binary/div/vec3-vec3/u32.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+    let a = vec3<u32>(1u, 2u, 3u);
+    let b = vec3<u32>(4u, 5u, 6u);
+    let r : vec3<u32> = a / b;
+}
diff --git a/test/expressions/binary/div/vec3-vec3/u32.wgsl.expected.hlsl b/test/expressions/binary/div/vec3-vec3/u32.wgsl.expected.hlsl
new file mode 100644
index 0000000..815ad9b
--- /dev/null
+++ b/test/expressions/binary/div/vec3-vec3/u32.wgsl.expected.hlsl
@@ -0,0 +1,7 @@
+[numthreads(1, 1, 1)]
+void f() {
+  const uint3 a = uint3(1u, 2u, 3u);
+  const uint3 b = uint3(4u, 5u, 6u);
+  const uint3 r = (a / b);
+  return;
+}
diff --git a/test/expressions/binary/div/vec3-vec3/u32.wgsl.expected.msl b/test/expressions/binary/div/vec3-vec3/u32.wgsl.expected.msl
new file mode 100644
index 0000000..bfddf5a
--- /dev/null
+++ b/test/expressions/binary/div/vec3-vec3/u32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f() {
+  uint3 const a = uint3(1u, 2u, 3u);
+  uint3 const b = uint3(4u, 5u, 6u);
+  uint3 const r = (a / b);
+  return;
+}
+
diff --git a/test/expressions/binary/div/vec3-vec3/u32.wgsl.expected.spvasm b/test/expressions/binary/div/vec3-vec3/u32.wgsl.expected.spvasm
new file mode 100644
index 0000000..116085e
--- /dev/null
+++ b/test/expressions/binary/div/vec3-vec3/u32.wgsl.expected.spvasm
@@ -0,0 +1,27 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 16
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %f "f"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %v3uint = OpTypeVector %uint 3
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+     %uint_3 = OpConstant %uint 3
+         %10 = OpConstantComposite %v3uint %uint_1 %uint_2 %uint_3
+     %uint_4 = OpConstant %uint 4
+     %uint_5 = OpConstant %uint 5
+     %uint_6 = OpConstant %uint 6
+         %14 = OpConstantComposite %v3uint %uint_4 %uint_5 %uint_6
+          %f = OpFunction %void None %1
+          %4 = OpLabel
+         %15 = OpUDiv %v3uint %10 %14
+               OpReturn
+               OpFunctionEnd
diff --git a/test/expressions/binary/div/vec3-vec3/u32.wgsl.expected.wgsl b/test/expressions/binary/div/vec3-vec3/u32.wgsl.expected.wgsl
new file mode 100644
index 0000000..cbf76b7
--- /dev/null
+++ b/test/expressions/binary/div/vec3-vec3/u32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+  let a = vec3<u32>(1u, 2u, 3u);
+  let b = vec3<u32>(4u, 5u, 6u);
+  let r : vec3<u32> = (a / b);
+}
diff --git a/test/expressions/binary/mod/scalar-scalar/f32.wgsl b/test/expressions/binary/mod/scalar-scalar/f32.wgsl
new file mode 100644
index 0000000..4ab4923
--- /dev/null
+++ b/test/expressions/binary/mod/scalar-scalar/f32.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+    let a = 1.;
+    let b = 2.;
+    let r : f32 = a % b;
+}
diff --git a/test/expressions/binary/mod/scalar-scalar/f32.wgsl.expected.hlsl b/test/expressions/binary/mod/scalar-scalar/f32.wgsl.expected.hlsl
new file mode 100644
index 0000000..2d9e671
--- /dev/null
+++ b/test/expressions/binary/mod/scalar-scalar/f32.wgsl.expected.hlsl
@@ -0,0 +1,5 @@
+[numthreads(1, 1, 1)]
+void f() {
+  const float r = (1.0f % 2.0f);
+  return;
+}
diff --git a/test/expressions/binary/mod/scalar-scalar/f32.wgsl.expected.msl b/test/expressions/binary/mod/scalar-scalar/f32.wgsl.expected.msl
new file mode 100644
index 0000000..111652a
--- /dev/null
+++ b/test/expressions/binary/mod/scalar-scalar/f32.wgsl.expected.msl
@@ -0,0 +1,19 @@
+SKIP: FAILED
+
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f() {
+  float const a = 1.0f;
+  float const b = 2.0f;
+  float const r = (a % b);
+  return;
+}
+
+Compilation failed: 
+
+program_source:7:22: error: invalid operands to binary expression ('const float' and 'const float')
+  float const r = (a % b);
+                   ~ ^ ~
+
+
diff --git a/test/expressions/binary/mod/scalar-scalar/f32.wgsl.expected.spvasm b/test/expressions/binary/mod/scalar-scalar/f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..2be0b7e
--- /dev/null
+++ b/test/expressions/binary/mod/scalar-scalar/f32.wgsl.expected.spvasm
@@ -0,0 +1,20 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 9
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %f "f"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+      %float = OpTypeFloat 32
+    %float_1 = OpConstant %float 1
+    %float_2 = OpConstant %float 2
+          %f = OpFunction %void None %1
+          %4 = OpLabel
+          %8 = OpFMod %float %float_1 %float_2
+               OpReturn
+               OpFunctionEnd
diff --git a/test/expressions/binary/mod/scalar-scalar/f32.wgsl.expected.wgsl b/test/expressions/binary/mod/scalar-scalar/f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..66c2041
--- /dev/null
+++ b/test/expressions/binary/mod/scalar-scalar/f32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+  let a = 1.0;
+  let b = 2.0;
+  let r : f32 = (a % b);
+}
diff --git a/test/expressions/binary/mod/scalar-scalar/i32.wgsl b/test/expressions/binary/mod/scalar-scalar/i32.wgsl
new file mode 100644
index 0000000..f186706
--- /dev/null
+++ b/test/expressions/binary/mod/scalar-scalar/i32.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+    let a = 1;
+    let b = 2;
+    let r : i32 = a % b;
+}
diff --git a/test/expressions/binary/mod/scalar-scalar/i32.wgsl.expected.hlsl b/test/expressions/binary/mod/scalar-scalar/i32.wgsl.expected.hlsl
new file mode 100644
index 0000000..9088e51
--- /dev/null
+++ b/test/expressions/binary/mod/scalar-scalar/i32.wgsl.expected.hlsl
@@ -0,0 +1,5 @@
+[numthreads(1, 1, 1)]
+void f() {
+  const int r = (1 % 2);
+  return;
+}
diff --git a/test/expressions/binary/mod/scalar-scalar/i32.wgsl.expected.msl b/test/expressions/binary/mod/scalar-scalar/i32.wgsl.expected.msl
new file mode 100644
index 0000000..a67d6fe
--- /dev/null
+++ b/test/expressions/binary/mod/scalar-scalar/i32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f() {
+  int const a = 1;
+  int const b = 2;
+  int const r = (a % b);
+  return;
+}
+
diff --git a/test/expressions/binary/mod/scalar-scalar/i32.wgsl.expected.spvasm b/test/expressions/binary/mod/scalar-scalar/i32.wgsl.expected.spvasm
new file mode 100644
index 0000000..3e9f944
--- /dev/null
+++ b/test/expressions/binary/mod/scalar-scalar/i32.wgsl.expected.spvasm
@@ -0,0 +1,20 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 9
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %f "f"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+      %int_2 = OpConstant %int 2
+          %f = OpFunction %void None %1
+          %4 = OpLabel
+          %8 = OpSMod %int %int_1 %int_2
+               OpReturn
+               OpFunctionEnd
diff --git a/test/expressions/binary/mod/scalar-scalar/i32.wgsl.expected.wgsl b/test/expressions/binary/mod/scalar-scalar/i32.wgsl.expected.wgsl
new file mode 100644
index 0000000..f692f9e
--- /dev/null
+++ b/test/expressions/binary/mod/scalar-scalar/i32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+  let a = 1;
+  let b = 2;
+  let r : i32 = (a % b);
+}
diff --git a/test/expressions/binary/mod/scalar-scalar/u32.wgsl b/test/expressions/binary/mod/scalar-scalar/u32.wgsl
new file mode 100644
index 0000000..d1b56f7
--- /dev/null
+++ b/test/expressions/binary/mod/scalar-scalar/u32.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+    let a = 1u;
+    let b = 2u;
+    let r : u32 = a % b;
+}
diff --git a/test/expressions/binary/mod/scalar-scalar/u32.wgsl.expected.hlsl b/test/expressions/binary/mod/scalar-scalar/u32.wgsl.expected.hlsl
new file mode 100644
index 0000000..e5e11c5
--- /dev/null
+++ b/test/expressions/binary/mod/scalar-scalar/u32.wgsl.expected.hlsl
@@ -0,0 +1,5 @@
+[numthreads(1, 1, 1)]
+void f() {
+  const uint r = (1u % 2u);
+  return;
+}
diff --git a/test/expressions/binary/mod/scalar-scalar/u32.wgsl.expected.msl b/test/expressions/binary/mod/scalar-scalar/u32.wgsl.expected.msl
new file mode 100644
index 0000000..5d4b949
--- /dev/null
+++ b/test/expressions/binary/mod/scalar-scalar/u32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f() {
+  uint const a = 1u;
+  uint const b = 2u;
+  uint const r = (a % b);
+  return;
+}
+
diff --git a/test/expressions/binary/mod/scalar-scalar/u32.wgsl.expected.spvasm b/test/expressions/binary/mod/scalar-scalar/u32.wgsl.expected.spvasm
new file mode 100644
index 0000000..57f2d38
--- /dev/null
+++ b/test/expressions/binary/mod/scalar-scalar/u32.wgsl.expected.spvasm
@@ -0,0 +1,20 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 9
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %f "f"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+          %f = OpFunction %void None %1
+          %4 = OpLabel
+          %8 = OpUMod %uint %uint_1 %uint_2
+               OpReturn
+               OpFunctionEnd
diff --git a/test/expressions/binary/mod/scalar-scalar/u32.wgsl.expected.wgsl b/test/expressions/binary/mod/scalar-scalar/u32.wgsl.expected.wgsl
new file mode 100644
index 0000000..e3da2c7
--- /dev/null
+++ b/test/expressions/binary/mod/scalar-scalar/u32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+  let a = 1u;
+  let b = 2u;
+  let r : u32 = (a % b);
+}
diff --git a/test/expressions/binary/mod/vec3-vec3/f32.wgsl b/test/expressions/binary/mod/vec3-vec3/f32.wgsl
new file mode 100644
index 0000000..d7cebb2
--- /dev/null
+++ b/test/expressions/binary/mod/vec3-vec3/f32.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+    let a = vec3<f32>(1., 2., 3.);
+    let b = vec3<f32>(4., 5., 6.);
+    let r : vec3<f32> = a % b;
+}
diff --git a/test/expressions/binary/mod/vec3-vec3/f32.wgsl.expected.hlsl b/test/expressions/binary/mod/vec3-vec3/f32.wgsl.expected.hlsl
new file mode 100644
index 0000000..87e4dd4
--- /dev/null
+++ b/test/expressions/binary/mod/vec3-vec3/f32.wgsl.expected.hlsl
@@ -0,0 +1,7 @@
+[numthreads(1, 1, 1)]
+void f() {
+  const float3 a = float3(1.0f, 2.0f, 3.0f);
+  const float3 b = float3(4.0f, 5.0f, 6.0f);
+  const float3 r = (a % b);
+  return;
+}
diff --git a/test/expressions/binary/mod/vec3-vec3/f32.wgsl.expected.msl b/test/expressions/binary/mod/vec3-vec3/f32.wgsl.expected.msl
new file mode 100644
index 0000000..53894a9
--- /dev/null
+++ b/test/expressions/binary/mod/vec3-vec3/f32.wgsl.expected.msl
@@ -0,0 +1,19 @@
+SKIP: FAILED
+
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f() {
+  float3 const a = float3(1.0f, 2.0f, 3.0f);
+  float3 const b = float3(4.0f, 5.0f, 6.0f);
+  float3 const r = (a % b);
+  return;
+}
+
+Compilation failed: 
+
+program_source:7:23: error: invalid operands to binary expression ('const float3' (vector of 3 'float' values) and 'const float3')
+  float3 const r = (a % b);
+                    ~ ^ ~
+
+
diff --git a/test/expressions/binary/mod/vec3-vec3/f32.wgsl.expected.spvasm b/test/expressions/binary/mod/vec3-vec3/f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..83be413
--- /dev/null
+++ b/test/expressions/binary/mod/vec3-vec3/f32.wgsl.expected.spvasm
@@ -0,0 +1,27 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 16
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %f "f"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+    %float_1 = OpConstant %float 1
+    %float_2 = OpConstant %float 2
+    %float_3 = OpConstant %float 3
+         %10 = OpConstantComposite %v3float %float_1 %float_2 %float_3
+    %float_4 = OpConstant %float 4
+    %float_5 = OpConstant %float 5
+    %float_6 = OpConstant %float 6
+         %14 = OpConstantComposite %v3float %float_4 %float_5 %float_6
+          %f = OpFunction %void None %1
+          %4 = OpLabel
+         %15 = OpFMod %v3float %10 %14
+               OpReturn
+               OpFunctionEnd
diff --git a/test/expressions/binary/mod/vec3-vec3/f32.wgsl.expected.wgsl b/test/expressions/binary/mod/vec3-vec3/f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..d0ef8c9
--- /dev/null
+++ b/test/expressions/binary/mod/vec3-vec3/f32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+  let a = vec3<f32>(1.0, 2.0, 3.0);
+  let b = vec3<f32>(4.0, 5.0, 6.0);
+  let r : vec3<f32> = (a % b);
+}
diff --git a/test/expressions/binary/mod/vec3-vec3/i32.wgsl b/test/expressions/binary/mod/vec3-vec3/i32.wgsl
new file mode 100644
index 0000000..b26013f
--- /dev/null
+++ b/test/expressions/binary/mod/vec3-vec3/i32.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+    let a = vec3<i32>(1, 2, 3);
+    let b = vec3<i32>(4, 5, 6);
+    let r : vec3<i32> = a % b;
+}
diff --git a/test/expressions/binary/mod/vec3-vec3/i32.wgsl.expected.hlsl b/test/expressions/binary/mod/vec3-vec3/i32.wgsl.expected.hlsl
new file mode 100644
index 0000000..f39516d
--- /dev/null
+++ b/test/expressions/binary/mod/vec3-vec3/i32.wgsl.expected.hlsl
@@ -0,0 +1,7 @@
+[numthreads(1, 1, 1)]
+void f() {
+  const int3 a = int3(1, 2, 3);
+  const int3 b = int3(4, 5, 6);
+  const int3 r = (a % b);
+  return;
+}
diff --git a/test/expressions/binary/mod/vec3-vec3/i32.wgsl.expected.msl b/test/expressions/binary/mod/vec3-vec3/i32.wgsl.expected.msl
new file mode 100644
index 0000000..2bd4b5f
--- /dev/null
+++ b/test/expressions/binary/mod/vec3-vec3/i32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f() {
+  int3 const a = int3(1, 2, 3);
+  int3 const b = int3(4, 5, 6);
+  int3 const r = (a % b);
+  return;
+}
+
diff --git a/test/expressions/binary/mod/vec3-vec3/i32.wgsl.expected.spvasm b/test/expressions/binary/mod/vec3-vec3/i32.wgsl.expected.spvasm
new file mode 100644
index 0000000..af8e454
--- /dev/null
+++ b/test/expressions/binary/mod/vec3-vec3/i32.wgsl.expected.spvasm
@@ -0,0 +1,27 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 16
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %f "f"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+        %int = OpTypeInt 32 1
+      %v3int = OpTypeVector %int 3
+      %int_1 = OpConstant %int 1
+      %int_2 = OpConstant %int 2
+      %int_3 = OpConstant %int 3
+         %10 = OpConstantComposite %v3int %int_1 %int_2 %int_3
+      %int_4 = OpConstant %int 4
+      %int_5 = OpConstant %int 5
+      %int_6 = OpConstant %int 6
+         %14 = OpConstantComposite %v3int %int_4 %int_5 %int_6
+          %f = OpFunction %void None %1
+          %4 = OpLabel
+         %15 = OpSMod %v3int %10 %14
+               OpReturn
+               OpFunctionEnd
diff --git a/test/expressions/binary/mod/vec3-vec3/i32.wgsl.expected.wgsl b/test/expressions/binary/mod/vec3-vec3/i32.wgsl.expected.wgsl
new file mode 100644
index 0000000..553af2b
--- /dev/null
+++ b/test/expressions/binary/mod/vec3-vec3/i32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+  let a = vec3<i32>(1, 2, 3);
+  let b = vec3<i32>(4, 5, 6);
+  let r : vec3<i32> = (a % b);
+}
diff --git a/test/expressions/binary/mod/vec3-vec3/u32.wgsl b/test/expressions/binary/mod/vec3-vec3/u32.wgsl
new file mode 100644
index 0000000..2ad96bc
--- /dev/null
+++ b/test/expressions/binary/mod/vec3-vec3/u32.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+    let a = vec3<u32>(1u, 2u, 3u);
+    let b = vec3<u32>(4u, 5u, 6u);
+    let r : vec3<u32> = a % b;
+}
diff --git a/test/expressions/binary/mod/vec3-vec3/u32.wgsl.expected.hlsl b/test/expressions/binary/mod/vec3-vec3/u32.wgsl.expected.hlsl
new file mode 100644
index 0000000..33e6b96
--- /dev/null
+++ b/test/expressions/binary/mod/vec3-vec3/u32.wgsl.expected.hlsl
@@ -0,0 +1,7 @@
+[numthreads(1, 1, 1)]
+void f() {
+  const uint3 a = uint3(1u, 2u, 3u);
+  const uint3 b = uint3(4u, 5u, 6u);
+  const uint3 r = (a % b);
+  return;
+}
diff --git a/test/expressions/binary/mod/vec3-vec3/u32.wgsl.expected.msl b/test/expressions/binary/mod/vec3-vec3/u32.wgsl.expected.msl
new file mode 100644
index 0000000..954924c
--- /dev/null
+++ b/test/expressions/binary/mod/vec3-vec3/u32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f() {
+  uint3 const a = uint3(1u, 2u, 3u);
+  uint3 const b = uint3(4u, 5u, 6u);
+  uint3 const r = (a % b);
+  return;
+}
+
diff --git a/test/expressions/binary/mod/vec3-vec3/u32.wgsl.expected.spvasm b/test/expressions/binary/mod/vec3-vec3/u32.wgsl.expected.spvasm
new file mode 100644
index 0000000..6f69999
--- /dev/null
+++ b/test/expressions/binary/mod/vec3-vec3/u32.wgsl.expected.spvasm
@@ -0,0 +1,27 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 16
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %f "f"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %v3uint = OpTypeVector %uint 3
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+     %uint_3 = OpConstant %uint 3
+         %10 = OpConstantComposite %v3uint %uint_1 %uint_2 %uint_3
+     %uint_4 = OpConstant %uint 4
+     %uint_5 = OpConstant %uint 5
+     %uint_6 = OpConstant %uint 6
+         %14 = OpConstantComposite %v3uint %uint_4 %uint_5 %uint_6
+          %f = OpFunction %void None %1
+          %4 = OpLabel
+         %15 = OpUMod %v3uint %10 %14
+               OpReturn
+               OpFunctionEnd
diff --git a/test/expressions/binary/mod/vec3-vec3/u32.wgsl.expected.wgsl b/test/expressions/binary/mod/vec3-vec3/u32.wgsl.expected.wgsl
new file mode 100644
index 0000000..ca63195
--- /dev/null
+++ b/test/expressions/binary/mod/vec3-vec3/u32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+  let a = vec3<u32>(1u, 2u, 3u);
+  let b = vec3<u32>(4u, 5u, 6u);
+  let r : vec3<u32> = (a % b);
+}
diff --git a/test/expressions/binary/mul/mat2x4-mat4x2/f32.wgsl b/test/expressions/binary/mul/mat2x4-mat4x2/f32.wgsl
new file mode 100644
index 0000000..ade50cb
--- /dev/null
+++ b/test/expressions/binary/mul/mat2x4-mat4x2/f32.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+    let a = mat2x4<f32>(vec4<f32>(1., 2., 3., 4.), vec4<f32>(5., 6., 7., 8.));
+    let b = mat4x2<f32>(vec2<f32>(-1., -2.), vec2<f32>(-3., -4.), vec2<f32>(-5., -6.), vec2<f32>(-7., -8.));
+    let r : mat4x4<f32> = a * b;
+}
diff --git a/test/expressions/binary/mul/mat2x4-mat4x2/f32.wgsl.expected.hlsl b/test/expressions/binary/mul/mat2x4-mat4x2/f32.wgsl.expected.hlsl
new file mode 100644
index 0000000..c502b09
--- /dev/null
+++ b/test/expressions/binary/mul/mat2x4-mat4x2/f32.wgsl.expected.hlsl
@@ -0,0 +1,7 @@
+[numthreads(1, 1, 1)]
+void f() {
+  const float2x4 a = float2x4(float4(1.0f, 2.0f, 3.0f, 4.0f), float4(5.0f, 6.0f, 7.0f, 8.0f));
+  const float4x2 b = float4x2(float2(-1.0f, -2.0f), float2(-3.0f, -4.0f), float2(-5.0f, -6.0f), float2(-7.0f, -8.0f));
+  const float4x4 r = mul(b, a);
+  return;
+}
diff --git a/test/expressions/binary/mul/mat2x4-mat4x2/f32.wgsl.expected.msl b/test/expressions/binary/mul/mat2x4-mat4x2/f32.wgsl.expected.msl
new file mode 100644
index 0000000..b706400
--- /dev/null
+++ b/test/expressions/binary/mul/mat2x4-mat4x2/f32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f() {
+  float2x4 const a = float2x4(float4(1.0f, 2.0f, 3.0f, 4.0f), float4(5.0f, 6.0f, 7.0f, 8.0f));
+  float4x2 const b = float4x2(float2(-1.0f, -2.0f), float2(-3.0f, -4.0f), float2(-5.0f, -6.0f), float2(-7.0f, -8.0f));
+  float4x4 const r = (a * b);
+  return;
+}
+
diff --git a/test/expressions/binary/mul/mat2x4-mat4x2/f32.wgsl.expected.spvasm b/test/expressions/binary/mul/mat2x4-mat4x2/f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..7f475dc
--- /dev/null
+++ b/test/expressions/binary/mul/mat2x4-mat4x2/f32.wgsl.expected.spvasm
@@ -0,0 +1,47 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 36
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %f "f"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%mat2v4float = OpTypeMatrix %v4float 2
+    %float_1 = OpConstant %float 1
+    %float_2 = OpConstant %float 2
+    %float_3 = OpConstant %float 3
+    %float_4 = OpConstant %float 4
+         %12 = OpConstantComposite %v4float %float_1 %float_2 %float_3 %float_4
+    %float_5 = OpConstant %float 5
+    %float_6 = OpConstant %float 6
+    %float_7 = OpConstant %float 7
+    %float_8 = OpConstant %float 8
+         %17 = OpConstantComposite %v4float %float_5 %float_6 %float_7 %float_8
+         %18 = OpConstantComposite %mat2v4float %12 %17
+    %v2float = OpTypeVector %float 2
+%mat4v2float = OpTypeMatrix %v2float 4
+   %float_n1 = OpConstant %float -1
+   %float_n2 = OpConstant %float -2
+         %23 = OpConstantComposite %v2float %float_n1 %float_n2
+   %float_n3 = OpConstant %float -3
+   %float_n4 = OpConstant %float -4
+         %26 = OpConstantComposite %v2float %float_n3 %float_n4
+   %float_n5 = OpConstant %float -5
+   %float_n6 = OpConstant %float -6
+         %29 = OpConstantComposite %v2float %float_n5 %float_n6
+   %float_n7 = OpConstant %float -7
+   %float_n8 = OpConstant %float -8
+         %32 = OpConstantComposite %v2float %float_n7 %float_n8
+         %33 = OpConstantComposite %mat4v2float %23 %26 %29 %32
+%mat4v4float = OpTypeMatrix %v4float 4
+          %f = OpFunction %void None %1
+          %4 = OpLabel
+         %34 = OpMatrixTimesMatrix %mat4v4float %18 %33
+               OpReturn
+               OpFunctionEnd
diff --git a/test/expressions/binary/mul/mat2x4-mat4x2/f32.wgsl.expected.wgsl b/test/expressions/binary/mul/mat2x4-mat4x2/f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..794ec9b
--- /dev/null
+++ b/test/expressions/binary/mul/mat2x4-mat4x2/f32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+  let a = mat2x4<f32>(vec4<f32>(1.0, 2.0, 3.0, 4.0), vec4<f32>(5.0, 6.0, 7.0, 8.0));
+  let b = mat4x2<f32>(vec2<f32>(-1.0, -2.0), vec2<f32>(-3.0, -4.0), vec2<f32>(-5.0, -6.0), vec2<f32>(-7.0, -8.0));
+  let r : mat4x4<f32> = (a * b);
+}
diff --git a/test/expressions/binary/mul/mat3x3-mat3x3/f32.wgsl b/test/expressions/binary/mul/mat3x3-mat3x3/f32.wgsl
new file mode 100644
index 0000000..06744d7
--- /dev/null
+++ b/test/expressions/binary/mul/mat3x3-mat3x3/f32.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+    let a = mat3x3<f32>(vec3<f32>( 1.,  2.,  3.), vec3<f32>( 4.,  5.,  6.), vec3<f32>( 7.,  8.,  9.));
+    let b = mat3x3<f32>(vec3<f32>(-1., -2., -3.), vec3<f32>(-4., -5., -6.), vec3<f32>(-7., -8., -9.));
+    let r : mat3x3<f32> = a * b;
+}
diff --git a/test/expressions/binary/mul/mat3x3-mat3x3/f32.wgsl.expected.hlsl b/test/expressions/binary/mul/mat3x3-mat3x3/f32.wgsl.expected.hlsl
new file mode 100644
index 0000000..22af87e
--- /dev/null
+++ b/test/expressions/binary/mul/mat3x3-mat3x3/f32.wgsl.expected.hlsl
@@ -0,0 +1,7 @@
+[numthreads(1, 1, 1)]
+void f() {
+  const float3x3 a = float3x3(float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f), float3(7.0f, 8.0f, 9.0f));
+  const float3x3 b = float3x3(float3(-1.0f, -2.0f, -3.0f), float3(-4.0f, -5.0f, -6.0f), float3(-7.0f, -8.0f, -9.0f));
+  const float3x3 r = mul(b, a);
+  return;
+}
diff --git a/test/expressions/binary/mul/mat3x3-mat3x3/f32.wgsl.expected.msl b/test/expressions/binary/mul/mat3x3-mat3x3/f32.wgsl.expected.msl
new file mode 100644
index 0000000..d51ecb1
--- /dev/null
+++ b/test/expressions/binary/mul/mat3x3-mat3x3/f32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f() {
+  float3x3 const a = float3x3(float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f), float3(7.0f, 8.0f, 9.0f));
+  float3x3 const b = float3x3(float3(-1.0f, -2.0f, -3.0f), float3(-4.0f, -5.0f, -6.0f), float3(-7.0f, -8.0f, -9.0f));
+  float3x3 const r = (a * b);
+  return;
+}
+
diff --git a/test/expressions/binary/mul/mat3x3-mat3x3/f32.wgsl.expected.spvasm b/test/expressions/binary/mul/mat3x3-mat3x3/f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..5aafd7f
--- /dev/null
+++ b/test/expressions/binary/mul/mat3x3-mat3x3/f32.wgsl.expected.spvasm
@@ -0,0 +1,46 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 35
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %f "f"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+%mat3v3float = OpTypeMatrix %v3float 3
+    %float_1 = OpConstant %float 1
+    %float_2 = OpConstant %float 2
+    %float_3 = OpConstant %float 3
+         %11 = OpConstantComposite %v3float %float_1 %float_2 %float_3
+    %float_4 = OpConstant %float 4
+    %float_5 = OpConstant %float 5
+    %float_6 = OpConstant %float 6
+         %15 = OpConstantComposite %v3float %float_4 %float_5 %float_6
+    %float_7 = OpConstant %float 7
+    %float_8 = OpConstant %float 8
+    %float_9 = OpConstant %float 9
+         %19 = OpConstantComposite %v3float %float_7 %float_8 %float_9
+         %20 = OpConstantComposite %mat3v3float %11 %15 %19
+   %float_n1 = OpConstant %float -1
+   %float_n2 = OpConstant %float -2
+   %float_n3 = OpConstant %float -3
+         %24 = OpConstantComposite %v3float %float_n1 %float_n2 %float_n3
+   %float_n4 = OpConstant %float -4
+   %float_n5 = OpConstant %float -5
+   %float_n6 = OpConstant %float -6
+         %28 = OpConstantComposite %v3float %float_n4 %float_n5 %float_n6
+   %float_n7 = OpConstant %float -7
+   %float_n8 = OpConstant %float -8
+   %float_n9 = OpConstant %float -9
+         %32 = OpConstantComposite %v3float %float_n7 %float_n8 %float_n9
+         %33 = OpConstantComposite %mat3v3float %24 %28 %32
+          %f = OpFunction %void None %1
+          %4 = OpLabel
+         %34 = OpMatrixTimesMatrix %mat3v3float %20 %33
+               OpReturn
+               OpFunctionEnd
diff --git a/test/expressions/binary/mul/mat3x3-mat3x3/f32.wgsl.expected.wgsl b/test/expressions/binary/mul/mat3x3-mat3x3/f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..2dd4a96
--- /dev/null
+++ b/test/expressions/binary/mul/mat3x3-mat3x3/f32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+  let a = mat3x3<f32>(vec3<f32>(1.0, 2.0, 3.0), vec3<f32>(4.0, 5.0, 6.0), vec3<f32>(7.0, 8.0, 9.0));
+  let b = mat3x3<f32>(vec3<f32>(-1.0, -2.0, -3.0), vec3<f32>(-4.0, -5.0, -6.0), vec3<f32>(-7.0, -8.0, -9.0));
+  let r : mat3x3<f32> = (a * b);
+}
diff --git a/test/expressions/binary/mul/mat4x2-mat2x4/f32.wgsl b/test/expressions/binary/mul/mat4x2-mat2x4/f32.wgsl
new file mode 100644
index 0000000..236146e
--- /dev/null
+++ b/test/expressions/binary/mul/mat4x2-mat2x4/f32.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+    let a = mat4x2<f32>(vec2<f32>(-1., -2.), vec2<f32>(-3., -4.), vec2<f32>(-5., -6.), vec2<f32>(-7., -8.));
+    let b = mat2x4<f32>(vec4<f32>(1., 2., 3., 4.), vec4<f32>(5., 6., 7., 8.));
+    let r : mat2x2<f32> = a * b;
+}
diff --git a/test/expressions/binary/mul/mat4x2-mat2x4/f32.wgsl.expected.hlsl b/test/expressions/binary/mul/mat4x2-mat2x4/f32.wgsl.expected.hlsl
new file mode 100644
index 0000000..9f4028a
--- /dev/null
+++ b/test/expressions/binary/mul/mat4x2-mat2x4/f32.wgsl.expected.hlsl
@@ -0,0 +1,7 @@
+[numthreads(1, 1, 1)]
+void f() {
+  const float4x2 a = float4x2(float2(-1.0f, -2.0f), float2(-3.0f, -4.0f), float2(-5.0f, -6.0f), float2(-7.0f, -8.0f));
+  const float2x4 b = float2x4(float4(1.0f, 2.0f, 3.0f, 4.0f), float4(5.0f, 6.0f, 7.0f, 8.0f));
+  const float2x2 r = mul(b, a);
+  return;
+}
diff --git a/test/expressions/binary/mul/mat4x2-mat2x4/f32.wgsl.expected.msl b/test/expressions/binary/mul/mat4x2-mat2x4/f32.wgsl.expected.msl
new file mode 100644
index 0000000..7b95ad6
--- /dev/null
+++ b/test/expressions/binary/mul/mat4x2-mat2x4/f32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f() {
+  float4x2 const a = float4x2(float2(-1.0f, -2.0f), float2(-3.0f, -4.0f), float2(-5.0f, -6.0f), float2(-7.0f, -8.0f));
+  float2x4 const b = float2x4(float4(1.0f, 2.0f, 3.0f, 4.0f), float4(5.0f, 6.0f, 7.0f, 8.0f));
+  float2x2 const r = (a * b);
+  return;
+}
+
diff --git a/test/expressions/binary/mul/mat4x2-mat2x4/f32.wgsl.expected.spvasm b/test/expressions/binary/mul/mat4x2-mat2x4/f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..dd96804
--- /dev/null
+++ b/test/expressions/binary/mul/mat4x2-mat2x4/f32.wgsl.expected.spvasm
@@ -0,0 +1,47 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 36
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %f "f"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+      %float = OpTypeFloat 32
+    %v2float = OpTypeVector %float 2
+%mat4v2float = OpTypeMatrix %v2float 4
+   %float_n1 = OpConstant %float -1
+   %float_n2 = OpConstant %float -2
+         %10 = OpConstantComposite %v2float %float_n1 %float_n2
+   %float_n3 = OpConstant %float -3
+   %float_n4 = OpConstant %float -4
+         %13 = OpConstantComposite %v2float %float_n3 %float_n4
+   %float_n5 = OpConstant %float -5
+   %float_n6 = OpConstant %float -6
+         %16 = OpConstantComposite %v2float %float_n5 %float_n6
+   %float_n7 = OpConstant %float -7
+   %float_n8 = OpConstant %float -8
+         %19 = OpConstantComposite %v2float %float_n7 %float_n8
+         %20 = OpConstantComposite %mat4v2float %10 %13 %16 %19
+    %v4float = OpTypeVector %float 4
+%mat2v4float = OpTypeMatrix %v4float 2
+    %float_1 = OpConstant %float 1
+    %float_2 = OpConstant %float 2
+    %float_3 = OpConstant %float 3
+    %float_4 = OpConstant %float 4
+         %27 = OpConstantComposite %v4float %float_1 %float_2 %float_3 %float_4
+    %float_5 = OpConstant %float 5
+    %float_6 = OpConstant %float 6
+    %float_7 = OpConstant %float 7
+    %float_8 = OpConstant %float 8
+         %32 = OpConstantComposite %v4float %float_5 %float_6 %float_7 %float_8
+         %33 = OpConstantComposite %mat2v4float %27 %32
+%mat2v2float = OpTypeMatrix %v2float 2
+          %f = OpFunction %void None %1
+          %4 = OpLabel
+         %34 = OpMatrixTimesMatrix %mat2v2float %20 %33
+               OpReturn
+               OpFunctionEnd
diff --git a/test/expressions/binary/mul/mat4x2-mat2x4/f32.wgsl.expected.wgsl b/test/expressions/binary/mul/mat4x2-mat2x4/f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..b4803d4
--- /dev/null
+++ b/test/expressions/binary/mul/mat4x2-mat2x4/f32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+  let a = mat4x2<f32>(vec2<f32>(-1.0, -2.0), vec2<f32>(-3.0, -4.0), vec2<f32>(-5.0, -6.0), vec2<f32>(-7.0, -8.0));
+  let b = mat2x4<f32>(vec4<f32>(1.0, 2.0, 3.0, 4.0), vec4<f32>(5.0, 6.0, 7.0, 8.0));
+  let r : mat2x2<f32> = (a * b);
+}
diff --git a/test/expressions/binary/mul/scalar-scalar/f32.wgsl b/test/expressions/binary/mul/scalar-scalar/f32.wgsl
new file mode 100644
index 0000000..23d7371
--- /dev/null
+++ b/test/expressions/binary/mul/scalar-scalar/f32.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+    let a = 1.;
+    let b = 2.;
+    let r : f32 = a * b;
+}
diff --git a/test/expressions/binary/mul/scalar-scalar/f32.wgsl.expected.hlsl b/test/expressions/binary/mul/scalar-scalar/f32.wgsl.expected.hlsl
new file mode 100644
index 0000000..a2d27f9
--- /dev/null
+++ b/test/expressions/binary/mul/scalar-scalar/f32.wgsl.expected.hlsl
@@ -0,0 +1,5 @@
+[numthreads(1, 1, 1)]
+void f() {
+  const float r = (1.0f * 2.0f);
+  return;
+}
diff --git a/test/expressions/binary/mul/scalar-scalar/f32.wgsl.expected.msl b/test/expressions/binary/mul/scalar-scalar/f32.wgsl.expected.msl
new file mode 100644
index 0000000..daaade6
--- /dev/null
+++ b/test/expressions/binary/mul/scalar-scalar/f32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f() {
+  float const a = 1.0f;
+  float const b = 2.0f;
+  float const r = (a * b);
+  return;
+}
+
diff --git a/test/expressions/binary/mul/scalar-scalar/f32.wgsl.expected.spvasm b/test/expressions/binary/mul/scalar-scalar/f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..faae711
--- /dev/null
+++ b/test/expressions/binary/mul/scalar-scalar/f32.wgsl.expected.spvasm
@@ -0,0 +1,20 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 9
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %f "f"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+      %float = OpTypeFloat 32
+    %float_1 = OpConstant %float 1
+    %float_2 = OpConstant %float 2
+          %f = OpFunction %void None %1
+          %4 = OpLabel
+          %8 = OpFMul %float %float_1 %float_2
+               OpReturn
+               OpFunctionEnd
diff --git a/test/expressions/binary/mul/scalar-scalar/f32.wgsl.expected.wgsl b/test/expressions/binary/mul/scalar-scalar/f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..6f874935
--- /dev/null
+++ b/test/expressions/binary/mul/scalar-scalar/f32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+  let a = 1.0;
+  let b = 2.0;
+  let r : f32 = (a * b);
+}
diff --git a/test/expressions/binary/mul/scalar-scalar/i32.wgsl b/test/expressions/binary/mul/scalar-scalar/i32.wgsl
new file mode 100644
index 0000000..ea58328
--- /dev/null
+++ b/test/expressions/binary/mul/scalar-scalar/i32.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+    let a = 1;
+    let b = 2;
+    let r : i32 = a * b;
+}
diff --git a/test/expressions/binary/mul/scalar-scalar/i32.wgsl.expected.hlsl b/test/expressions/binary/mul/scalar-scalar/i32.wgsl.expected.hlsl
new file mode 100644
index 0000000..4b93ecb
--- /dev/null
+++ b/test/expressions/binary/mul/scalar-scalar/i32.wgsl.expected.hlsl
@@ -0,0 +1,5 @@
+[numthreads(1, 1, 1)]
+void f() {
+  const int r = (1 * 2);
+  return;
+}
diff --git a/test/expressions/binary/mul/scalar-scalar/i32.wgsl.expected.msl b/test/expressions/binary/mul/scalar-scalar/i32.wgsl.expected.msl
new file mode 100644
index 0000000..1bd365e
--- /dev/null
+++ b/test/expressions/binary/mul/scalar-scalar/i32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f() {
+  int const a = 1;
+  int const b = 2;
+  int const r = (a * b);
+  return;
+}
+
diff --git a/test/expressions/binary/mul/scalar-scalar/i32.wgsl.expected.spvasm b/test/expressions/binary/mul/scalar-scalar/i32.wgsl.expected.spvasm
new file mode 100644
index 0000000..0f753ea
--- /dev/null
+++ b/test/expressions/binary/mul/scalar-scalar/i32.wgsl.expected.spvasm
@@ -0,0 +1,20 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 9
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %f "f"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+      %int_2 = OpConstant %int 2
+          %f = OpFunction %void None %1
+          %4 = OpLabel
+          %8 = OpIMul %int %int_1 %int_2
+               OpReturn
+               OpFunctionEnd
diff --git a/test/expressions/binary/mul/scalar-scalar/i32.wgsl.expected.wgsl b/test/expressions/binary/mul/scalar-scalar/i32.wgsl.expected.wgsl
new file mode 100644
index 0000000..5f53be8
--- /dev/null
+++ b/test/expressions/binary/mul/scalar-scalar/i32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+  let a = 1;
+  let b = 2;
+  let r : i32 = (a * b);
+}
diff --git a/test/expressions/binary/mul/scalar-scalar/u32.wgsl b/test/expressions/binary/mul/scalar-scalar/u32.wgsl
new file mode 100644
index 0000000..ec6a61d
--- /dev/null
+++ b/test/expressions/binary/mul/scalar-scalar/u32.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+    let a = 1u;
+    let b = 2u;
+    let r : u32 = a * b;
+}
diff --git a/test/expressions/binary/mul/scalar-scalar/u32.wgsl.expected.hlsl b/test/expressions/binary/mul/scalar-scalar/u32.wgsl.expected.hlsl
new file mode 100644
index 0000000..4623783
--- /dev/null
+++ b/test/expressions/binary/mul/scalar-scalar/u32.wgsl.expected.hlsl
@@ -0,0 +1,5 @@
+[numthreads(1, 1, 1)]
+void f() {
+  const uint r = (1u * 2u);
+  return;
+}
diff --git a/test/expressions/binary/mul/scalar-scalar/u32.wgsl.expected.msl b/test/expressions/binary/mul/scalar-scalar/u32.wgsl.expected.msl
new file mode 100644
index 0000000..7e9738a
--- /dev/null
+++ b/test/expressions/binary/mul/scalar-scalar/u32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f() {
+  uint const a = 1u;
+  uint const b = 2u;
+  uint const r = (a * b);
+  return;
+}
+
diff --git a/test/expressions/binary/mul/scalar-scalar/u32.wgsl.expected.spvasm b/test/expressions/binary/mul/scalar-scalar/u32.wgsl.expected.spvasm
new file mode 100644
index 0000000..a014353
--- /dev/null
+++ b/test/expressions/binary/mul/scalar-scalar/u32.wgsl.expected.spvasm
@@ -0,0 +1,20 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 9
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %f "f"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+          %f = OpFunction %void None %1
+          %4 = OpLabel
+          %8 = OpIMul %uint %uint_1 %uint_2
+               OpReturn
+               OpFunctionEnd
diff --git a/test/expressions/binary/mul/scalar-scalar/u32.wgsl.expected.wgsl b/test/expressions/binary/mul/scalar-scalar/u32.wgsl.expected.wgsl
new file mode 100644
index 0000000..92cffef
--- /dev/null
+++ b/test/expressions/binary/mul/scalar-scalar/u32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+  let a = 1u;
+  let b = 2u;
+  let r : u32 = (a * b);
+}
diff --git a/test/expressions/binary/mul/scalar-vec3/f32.wgsl b/test/expressions/binary/mul/scalar-vec3/f32.wgsl
new file mode 100644
index 0000000..cd19d3b
--- /dev/null
+++ b/test/expressions/binary/mul/scalar-vec3/f32.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+    let a = 4.;
+    let b = vec3<f32>(1., 2., 3.);
+    let r : vec3<f32> = a * b;
+}
diff --git a/test/expressions/binary/mul/scalar-vec3/f32.wgsl.expected.hlsl b/test/expressions/binary/mul/scalar-vec3/f32.wgsl.expected.hlsl
new file mode 100644
index 0000000..ab39cdc
--- /dev/null
+++ b/test/expressions/binary/mul/scalar-vec3/f32.wgsl.expected.hlsl
@@ -0,0 +1,7 @@
+[numthreads(1, 1, 1)]
+void f() {
+  const float a = 4.0f;
+  const float3 b = float3(1.0f, 2.0f, 3.0f);
+  const float3 r = (a * b);
+  return;
+}
diff --git a/test/expressions/binary/mul/scalar-vec3/f32.wgsl.expected.msl b/test/expressions/binary/mul/scalar-vec3/f32.wgsl.expected.msl
new file mode 100644
index 0000000..5ea4340
--- /dev/null
+++ b/test/expressions/binary/mul/scalar-vec3/f32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f() {
+  float const a = 4.0f;
+  float3 const b = float3(1.0f, 2.0f, 3.0f);
+  float3 const r = (a * b);
+  return;
+}
+
diff --git a/test/expressions/binary/mul/scalar-vec3/f32.wgsl.expected.spvasm b/test/expressions/binary/mul/scalar-vec3/f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..3dd13a7
--- /dev/null
+++ b/test/expressions/binary/mul/scalar-vec3/f32.wgsl.expected.spvasm
@@ -0,0 +1,24 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 13
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %f "f"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+      %float = OpTypeFloat 32
+    %float_4 = OpConstant %float 4
+    %v3float = OpTypeVector %float 3
+    %float_1 = OpConstant %float 1
+    %float_2 = OpConstant %float 2
+    %float_3 = OpConstant %float 3
+         %11 = OpConstantComposite %v3float %float_1 %float_2 %float_3
+          %f = OpFunction %void None %1
+          %4 = OpLabel
+         %12 = OpVectorTimesScalar %v3float %11 %float_4
+               OpReturn
+               OpFunctionEnd
diff --git a/test/expressions/binary/mul/scalar-vec3/f32.wgsl.expected.wgsl b/test/expressions/binary/mul/scalar-vec3/f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..65ac8cc
--- /dev/null
+++ b/test/expressions/binary/mul/scalar-vec3/f32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+  let a = 4.0;
+  let b = vec3<f32>(1.0, 2.0, 3.0);
+  let r : vec3<f32> = (a * b);
+}
diff --git a/test/expressions/binary/mul/scalar-vec3/i32.wgsl b/test/expressions/binary/mul/scalar-vec3/i32.wgsl
new file mode 100644
index 0000000..8d1bf3f
--- /dev/null
+++ b/test/expressions/binary/mul/scalar-vec3/i32.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+    let a = 4;
+    let b = vec3<i32>(1, 2, 3);
+    let r : vec3<i32> = a * b;
+}
diff --git a/test/expressions/binary/mul/scalar-vec3/i32.wgsl.expected.hlsl b/test/expressions/binary/mul/scalar-vec3/i32.wgsl.expected.hlsl
new file mode 100644
index 0000000..6d7c62a
--- /dev/null
+++ b/test/expressions/binary/mul/scalar-vec3/i32.wgsl.expected.hlsl
@@ -0,0 +1,7 @@
+[numthreads(1, 1, 1)]
+void f() {
+  const int a = 4;
+  const int3 b = int3(1, 2, 3);
+  const int3 r = (a * b);
+  return;
+}
diff --git a/test/expressions/binary/mul/scalar-vec3/i32.wgsl.expected.msl b/test/expressions/binary/mul/scalar-vec3/i32.wgsl.expected.msl
new file mode 100644
index 0000000..733799e
--- /dev/null
+++ b/test/expressions/binary/mul/scalar-vec3/i32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f() {
+  int const a = 4;
+  int3 const b = int3(1, 2, 3);
+  int3 const r = (a * b);
+  return;
+}
+
diff --git a/test/expressions/binary/mul/scalar-vec3/i32.wgsl.expected.spvasm b/test/expressions/binary/mul/scalar-vec3/i32.wgsl.expected.spvasm
new file mode 100644
index 0000000..42c9b54
--- /dev/null
+++ b/test/expressions/binary/mul/scalar-vec3/i32.wgsl.expected.spvasm
@@ -0,0 +1,28 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 17
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %f "f"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+        %int = OpTypeInt 32 1
+      %int_4 = OpConstant %int 4
+      %v3int = OpTypeVector %int 3
+      %int_1 = OpConstant %int 1
+      %int_2 = OpConstant %int 2
+      %int_3 = OpConstant %int 3
+         %11 = OpConstantComposite %v3int %int_1 %int_2 %int_3
+%_ptr_Function_v3int = OpTypePointer Function %v3int
+         %15 = OpConstantNull %v3int
+          %f = OpFunction %void None %1
+          %4 = OpLabel
+         %13 = OpVariable %_ptr_Function_v3int Function %15
+         %16 = OpCompositeConstruct %v3int %int_4 %int_4 %int_4
+         %12 = OpIMul %v3int %16 %11
+               OpReturn
+               OpFunctionEnd
diff --git a/test/expressions/binary/mul/scalar-vec3/i32.wgsl.expected.wgsl b/test/expressions/binary/mul/scalar-vec3/i32.wgsl.expected.wgsl
new file mode 100644
index 0000000..c5744b7
--- /dev/null
+++ b/test/expressions/binary/mul/scalar-vec3/i32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+  let a = 4;
+  let b = vec3<i32>(1, 2, 3);
+  let r : vec3<i32> = (a * b);
+}
diff --git a/test/expressions/binary/mul/scalar-vec3/u32.wgsl b/test/expressions/binary/mul/scalar-vec3/u32.wgsl
new file mode 100644
index 0000000..d5f432e6
--- /dev/null
+++ b/test/expressions/binary/mul/scalar-vec3/u32.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+    let a = 4u;
+    let b = vec3<u32>(1u, 2u, 3u);
+    let r : vec3<u32> = a * b;
+}
diff --git a/test/expressions/binary/mul/scalar-vec3/u32.wgsl.expected.hlsl b/test/expressions/binary/mul/scalar-vec3/u32.wgsl.expected.hlsl
new file mode 100644
index 0000000..73ec042
--- /dev/null
+++ b/test/expressions/binary/mul/scalar-vec3/u32.wgsl.expected.hlsl
@@ -0,0 +1,7 @@
+[numthreads(1, 1, 1)]
+void f() {
+  const uint a = 4u;
+  const uint3 b = uint3(1u, 2u, 3u);
+  const uint3 r = (a * b);
+  return;
+}
diff --git a/test/expressions/binary/mul/scalar-vec3/u32.wgsl.expected.msl b/test/expressions/binary/mul/scalar-vec3/u32.wgsl.expected.msl
new file mode 100644
index 0000000..6ff7ae2
--- /dev/null
+++ b/test/expressions/binary/mul/scalar-vec3/u32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f() {
+  uint const a = 4u;
+  uint3 const b = uint3(1u, 2u, 3u);
+  uint3 const r = (a * b);
+  return;
+}
+
diff --git a/test/expressions/binary/mul/scalar-vec3/u32.wgsl.expected.spvasm b/test/expressions/binary/mul/scalar-vec3/u32.wgsl.expected.spvasm
new file mode 100644
index 0000000..4877ed6
--- /dev/null
+++ b/test/expressions/binary/mul/scalar-vec3/u32.wgsl.expected.spvasm
@@ -0,0 +1,28 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 17
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %f "f"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+     %v3uint = OpTypeVector %uint 3
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+     %uint_3 = OpConstant %uint 3
+         %11 = OpConstantComposite %v3uint %uint_1 %uint_2 %uint_3
+%_ptr_Function_v3uint = OpTypePointer Function %v3uint
+         %15 = OpConstantNull %v3uint
+          %f = OpFunction %void None %1
+          %4 = OpLabel
+         %13 = OpVariable %_ptr_Function_v3uint Function %15
+         %16 = OpCompositeConstruct %v3uint %uint_4 %uint_4 %uint_4
+         %12 = OpIMul %v3uint %16 %11
+               OpReturn
+               OpFunctionEnd
diff --git a/test/expressions/binary/mul/scalar-vec3/u32.wgsl.expected.wgsl b/test/expressions/binary/mul/scalar-vec3/u32.wgsl.expected.wgsl
new file mode 100644
index 0000000..60505a4
--- /dev/null
+++ b/test/expressions/binary/mul/scalar-vec3/u32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+  let a = 4u;
+  let b = vec3<u32>(1u, 2u, 3u);
+  let r : vec3<u32> = (a * b);
+}
diff --git a/test/expressions/binary/mul/vec3-scalar/f32.wgsl b/test/expressions/binary/mul/vec3-scalar/f32.wgsl
new file mode 100644
index 0000000..34a7b70
--- /dev/null
+++ b/test/expressions/binary/mul/vec3-scalar/f32.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+    let a = vec3<f32>(1., 2., 3.);
+    let b = 4.;
+    let r : vec3<f32> = a * b;
+}
diff --git a/test/expressions/binary/mul/vec3-scalar/f32.wgsl.expected.hlsl b/test/expressions/binary/mul/vec3-scalar/f32.wgsl.expected.hlsl
new file mode 100644
index 0000000..646399d
--- /dev/null
+++ b/test/expressions/binary/mul/vec3-scalar/f32.wgsl.expected.hlsl
@@ -0,0 +1,6 @@
+[numthreads(1, 1, 1)]
+void f() {
+  const float3 a = float3(1.0f, 2.0f, 3.0f);
+  const float3 r = (a * 4.0f);
+  return;
+}
diff --git a/test/expressions/binary/mul/vec3-scalar/f32.wgsl.expected.msl b/test/expressions/binary/mul/vec3-scalar/f32.wgsl.expected.msl
new file mode 100644
index 0000000..2779faf
--- /dev/null
+++ b/test/expressions/binary/mul/vec3-scalar/f32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f() {
+  float3 const a = float3(1.0f, 2.0f, 3.0f);
+  float const b = 4.0f;
+  float3 const r = (a * b);
+  return;
+}
+
diff --git a/test/expressions/binary/mul/vec3-scalar/f32.wgsl.expected.spvasm b/test/expressions/binary/mul/vec3-scalar/f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..eb84b87
--- /dev/null
+++ b/test/expressions/binary/mul/vec3-scalar/f32.wgsl.expected.spvasm
@@ -0,0 +1,24 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 13
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %f "f"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+    %float_1 = OpConstant %float 1
+    %float_2 = OpConstant %float 2
+    %float_3 = OpConstant %float 3
+         %10 = OpConstantComposite %v3float %float_1 %float_2 %float_3
+    %float_4 = OpConstant %float 4
+          %f = OpFunction %void None %1
+          %4 = OpLabel
+         %12 = OpVectorTimesScalar %v3float %10 %float_4
+               OpReturn
+               OpFunctionEnd
diff --git a/test/expressions/binary/mul/vec3-scalar/f32.wgsl.expected.wgsl b/test/expressions/binary/mul/vec3-scalar/f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..712df51
--- /dev/null
+++ b/test/expressions/binary/mul/vec3-scalar/f32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+  let a = vec3<f32>(1.0, 2.0, 3.0);
+  let b = 4.0;
+  let r : vec3<f32> = (a * b);
+}
diff --git a/test/expressions/binary/mul/vec3-scalar/i32.wgsl b/test/expressions/binary/mul/vec3-scalar/i32.wgsl
new file mode 100644
index 0000000..a8f8d1e
--- /dev/null
+++ b/test/expressions/binary/mul/vec3-scalar/i32.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+    let a = vec3<i32>(1, 2, 3);
+    let b = 4;
+    let r : vec3<i32> = a * b;
+}
diff --git a/test/expressions/binary/mul/vec3-scalar/i32.wgsl.expected.hlsl b/test/expressions/binary/mul/vec3-scalar/i32.wgsl.expected.hlsl
new file mode 100644
index 0000000..e86c189
--- /dev/null
+++ b/test/expressions/binary/mul/vec3-scalar/i32.wgsl.expected.hlsl
@@ -0,0 +1,6 @@
+[numthreads(1, 1, 1)]
+void f() {
+  const int3 a = int3(1, 2, 3);
+  const int3 r = (a * 4);
+  return;
+}
diff --git a/test/expressions/binary/mul/vec3-scalar/i32.wgsl.expected.msl b/test/expressions/binary/mul/vec3-scalar/i32.wgsl.expected.msl
new file mode 100644
index 0000000..afabaf3
--- /dev/null
+++ b/test/expressions/binary/mul/vec3-scalar/i32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f() {
+  int3 const a = int3(1, 2, 3);
+  int const b = 4;
+  int3 const r = (a * b);
+  return;
+}
+
diff --git a/test/expressions/binary/mul/vec3-scalar/i32.wgsl.expected.spvasm b/test/expressions/binary/mul/vec3-scalar/i32.wgsl.expected.spvasm
new file mode 100644
index 0000000..bb4153b
--- /dev/null
+++ b/test/expressions/binary/mul/vec3-scalar/i32.wgsl.expected.spvasm
@@ -0,0 +1,28 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 17
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %f "f"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+        %int = OpTypeInt 32 1
+      %v3int = OpTypeVector %int 3
+      %int_1 = OpConstant %int 1
+      %int_2 = OpConstant %int 2
+      %int_3 = OpConstant %int 3
+         %10 = OpConstantComposite %v3int %int_1 %int_2 %int_3
+      %int_4 = OpConstant %int 4
+%_ptr_Function_v3int = OpTypePointer Function %v3int
+         %15 = OpConstantNull %v3int
+          %f = OpFunction %void None %1
+          %4 = OpLabel
+         %13 = OpVariable %_ptr_Function_v3int Function %15
+         %16 = OpCompositeConstruct %v3int %int_4 %int_4 %int_4
+         %12 = OpIMul %v3int %10 %16
+               OpReturn
+               OpFunctionEnd
diff --git a/test/expressions/binary/mul/vec3-scalar/i32.wgsl.expected.wgsl b/test/expressions/binary/mul/vec3-scalar/i32.wgsl.expected.wgsl
new file mode 100644
index 0000000..d8f7e63
--- /dev/null
+++ b/test/expressions/binary/mul/vec3-scalar/i32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+  let a = vec3<i32>(1, 2, 3);
+  let b = 4;
+  let r : vec3<i32> = (a * b);
+}
diff --git a/test/expressions/binary/mul/vec3-scalar/u32.wgsl b/test/expressions/binary/mul/vec3-scalar/u32.wgsl
new file mode 100644
index 0000000..a63cb22
--- /dev/null
+++ b/test/expressions/binary/mul/vec3-scalar/u32.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+    let a = vec3<u32>(1u, 2u, 3u);
+    let b = 4u;
+    let r : vec3<u32> = a * b;
+}
diff --git a/test/expressions/binary/mul/vec3-scalar/u32.wgsl.expected.hlsl b/test/expressions/binary/mul/vec3-scalar/u32.wgsl.expected.hlsl
new file mode 100644
index 0000000..d61b59a
--- /dev/null
+++ b/test/expressions/binary/mul/vec3-scalar/u32.wgsl.expected.hlsl
@@ -0,0 +1,6 @@
+[numthreads(1, 1, 1)]
+void f() {
+  const uint3 a = uint3(1u, 2u, 3u);
+  const uint3 r = (a * 4u);
+  return;
+}
diff --git a/test/expressions/binary/mul/vec3-scalar/u32.wgsl.expected.msl b/test/expressions/binary/mul/vec3-scalar/u32.wgsl.expected.msl
new file mode 100644
index 0000000..b0b38b0
--- /dev/null
+++ b/test/expressions/binary/mul/vec3-scalar/u32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f() {
+  uint3 const a = uint3(1u, 2u, 3u);
+  uint const b = 4u;
+  uint3 const r = (a * b);
+  return;
+}
+
diff --git a/test/expressions/binary/mul/vec3-scalar/u32.wgsl.expected.spvasm b/test/expressions/binary/mul/vec3-scalar/u32.wgsl.expected.spvasm
new file mode 100644
index 0000000..cecab21
--- /dev/null
+++ b/test/expressions/binary/mul/vec3-scalar/u32.wgsl.expected.spvasm
@@ -0,0 +1,28 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 17
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %f "f"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %v3uint = OpTypeVector %uint 3
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+     %uint_3 = OpConstant %uint 3
+         %10 = OpConstantComposite %v3uint %uint_1 %uint_2 %uint_3
+     %uint_4 = OpConstant %uint 4
+%_ptr_Function_v3uint = OpTypePointer Function %v3uint
+         %15 = OpConstantNull %v3uint
+          %f = OpFunction %void None %1
+          %4 = OpLabel
+         %13 = OpVariable %_ptr_Function_v3uint Function %15
+         %16 = OpCompositeConstruct %v3uint %uint_4 %uint_4 %uint_4
+         %12 = OpIMul %v3uint %10 %16
+               OpReturn
+               OpFunctionEnd
diff --git a/test/expressions/binary/mul/vec3-scalar/u32.wgsl.expected.wgsl b/test/expressions/binary/mul/vec3-scalar/u32.wgsl.expected.wgsl
new file mode 100644
index 0000000..995a6a3
--- /dev/null
+++ b/test/expressions/binary/mul/vec3-scalar/u32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+  let a = vec3<u32>(1u, 2u, 3u);
+  let b = 4u;
+  let r : vec3<u32> = (a * b);
+}
diff --git a/test/expressions/binary/mul/vec3-vec3/f32.wgsl b/test/expressions/binary/mul/vec3-vec3/f32.wgsl
new file mode 100644
index 0000000..184a9fb
--- /dev/null
+++ b/test/expressions/binary/mul/vec3-vec3/f32.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+    let a = vec3<f32>(1., 2., 3.);
+    let b = vec3<f32>(4., 5., 6.);
+    let r : vec3<f32> = a * b;
+}
diff --git a/test/expressions/binary/mul/vec3-vec3/f32.wgsl.expected.hlsl b/test/expressions/binary/mul/vec3-vec3/f32.wgsl.expected.hlsl
new file mode 100644
index 0000000..8a51b14
--- /dev/null
+++ b/test/expressions/binary/mul/vec3-vec3/f32.wgsl.expected.hlsl
@@ -0,0 +1,7 @@
+[numthreads(1, 1, 1)]
+void f() {
+  const float3 a = float3(1.0f, 2.0f, 3.0f);
+  const float3 b = float3(4.0f, 5.0f, 6.0f);
+  const float3 r = (a * b);
+  return;
+}
diff --git a/test/expressions/binary/mul/vec3-vec3/f32.wgsl.expected.msl b/test/expressions/binary/mul/vec3-vec3/f32.wgsl.expected.msl
new file mode 100644
index 0000000..2c70f56
--- /dev/null
+++ b/test/expressions/binary/mul/vec3-vec3/f32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f() {
+  float3 const a = float3(1.0f, 2.0f, 3.0f);
+  float3 const b = float3(4.0f, 5.0f, 6.0f);
+  float3 const r = (a * b);
+  return;
+}
+
diff --git a/test/expressions/binary/mul/vec3-vec3/f32.wgsl.expected.spvasm b/test/expressions/binary/mul/vec3-vec3/f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..0983487
--- /dev/null
+++ b/test/expressions/binary/mul/vec3-vec3/f32.wgsl.expected.spvasm
@@ -0,0 +1,27 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 16
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %f "f"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+    %float_1 = OpConstant %float 1
+    %float_2 = OpConstant %float 2
+    %float_3 = OpConstant %float 3
+         %10 = OpConstantComposite %v3float %float_1 %float_2 %float_3
+    %float_4 = OpConstant %float 4
+    %float_5 = OpConstant %float 5
+    %float_6 = OpConstant %float 6
+         %14 = OpConstantComposite %v3float %float_4 %float_5 %float_6
+          %f = OpFunction %void None %1
+          %4 = OpLabel
+         %15 = OpFMul %v3float %10 %14
+               OpReturn
+               OpFunctionEnd
diff --git a/test/expressions/binary/mul/vec3-vec3/f32.wgsl.expected.wgsl b/test/expressions/binary/mul/vec3-vec3/f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..fff2a26
--- /dev/null
+++ b/test/expressions/binary/mul/vec3-vec3/f32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+  let a = vec3<f32>(1.0, 2.0, 3.0);
+  let b = vec3<f32>(4.0, 5.0, 6.0);
+  let r : vec3<f32> = (a * b);
+}
diff --git a/test/expressions/binary/mul/vec3-vec3/i32.wgsl b/test/expressions/binary/mul/vec3-vec3/i32.wgsl
new file mode 100644
index 0000000..dc812d8
--- /dev/null
+++ b/test/expressions/binary/mul/vec3-vec3/i32.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+    let a = vec3<i32>(1, 2, 3);
+    let b = vec3<i32>(4, 5, 6);
+    let r : vec3<i32> = a * b;
+}
diff --git a/test/expressions/binary/mul/vec3-vec3/i32.wgsl.expected.hlsl b/test/expressions/binary/mul/vec3-vec3/i32.wgsl.expected.hlsl
new file mode 100644
index 0000000..d532aaf
--- /dev/null
+++ b/test/expressions/binary/mul/vec3-vec3/i32.wgsl.expected.hlsl
@@ -0,0 +1,7 @@
+[numthreads(1, 1, 1)]
+void f() {
+  const int3 a = int3(1, 2, 3);
+  const int3 b = int3(4, 5, 6);
+  const int3 r = (a * b);
+  return;
+}
diff --git a/test/expressions/binary/mul/vec3-vec3/i32.wgsl.expected.msl b/test/expressions/binary/mul/vec3-vec3/i32.wgsl.expected.msl
new file mode 100644
index 0000000..91d1b9f
--- /dev/null
+++ b/test/expressions/binary/mul/vec3-vec3/i32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f() {
+  int3 const a = int3(1, 2, 3);
+  int3 const b = int3(4, 5, 6);
+  int3 const r = (a * b);
+  return;
+}
+
diff --git a/test/expressions/binary/mul/vec3-vec3/i32.wgsl.expected.spvasm b/test/expressions/binary/mul/vec3-vec3/i32.wgsl.expected.spvasm
new file mode 100644
index 0000000..98d2734
--- /dev/null
+++ b/test/expressions/binary/mul/vec3-vec3/i32.wgsl.expected.spvasm
@@ -0,0 +1,27 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 16
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %f "f"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+        %int = OpTypeInt 32 1
+      %v3int = OpTypeVector %int 3
+      %int_1 = OpConstant %int 1
+      %int_2 = OpConstant %int 2
+      %int_3 = OpConstant %int 3
+         %10 = OpConstantComposite %v3int %int_1 %int_2 %int_3
+      %int_4 = OpConstant %int 4
+      %int_5 = OpConstant %int 5
+      %int_6 = OpConstant %int 6
+         %14 = OpConstantComposite %v3int %int_4 %int_5 %int_6
+          %f = OpFunction %void None %1
+          %4 = OpLabel
+         %15 = OpIMul %v3int %10 %14
+               OpReturn
+               OpFunctionEnd
diff --git a/test/expressions/binary/mul/vec3-vec3/i32.wgsl.expected.wgsl b/test/expressions/binary/mul/vec3-vec3/i32.wgsl.expected.wgsl
new file mode 100644
index 0000000..3ca04ae
--- /dev/null
+++ b/test/expressions/binary/mul/vec3-vec3/i32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+  let a = vec3<i32>(1, 2, 3);
+  let b = vec3<i32>(4, 5, 6);
+  let r : vec3<i32> = (a * b);
+}
diff --git a/test/expressions/binary/mul/vec3-vec3/u32.wgsl b/test/expressions/binary/mul/vec3-vec3/u32.wgsl
new file mode 100644
index 0000000..d1e2219
--- /dev/null
+++ b/test/expressions/binary/mul/vec3-vec3/u32.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+    let a = vec3<u32>(1u, 2u, 3u);
+    let b = vec3<u32>(4u, 5u, 6u);
+    let r : vec3<u32> = a * b;
+}
diff --git a/test/expressions/binary/mul/vec3-vec3/u32.wgsl.expected.hlsl b/test/expressions/binary/mul/vec3-vec3/u32.wgsl.expected.hlsl
new file mode 100644
index 0000000..5db3034
--- /dev/null
+++ b/test/expressions/binary/mul/vec3-vec3/u32.wgsl.expected.hlsl
@@ -0,0 +1,7 @@
+[numthreads(1, 1, 1)]
+void f() {
+  const uint3 a = uint3(1u, 2u, 3u);
+  const uint3 b = uint3(4u, 5u, 6u);
+  const uint3 r = (a * b);
+  return;
+}
diff --git a/test/expressions/binary/mul/vec3-vec3/u32.wgsl.expected.msl b/test/expressions/binary/mul/vec3-vec3/u32.wgsl.expected.msl
new file mode 100644
index 0000000..3bdad2d
--- /dev/null
+++ b/test/expressions/binary/mul/vec3-vec3/u32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f() {
+  uint3 const a = uint3(1u, 2u, 3u);
+  uint3 const b = uint3(4u, 5u, 6u);
+  uint3 const r = (a * b);
+  return;
+}
+
diff --git a/test/expressions/binary/mul/vec3-vec3/u32.wgsl.expected.spvasm b/test/expressions/binary/mul/vec3-vec3/u32.wgsl.expected.spvasm
new file mode 100644
index 0000000..2e60fba
--- /dev/null
+++ b/test/expressions/binary/mul/vec3-vec3/u32.wgsl.expected.spvasm
@@ -0,0 +1,27 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 16
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %f "f"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %v3uint = OpTypeVector %uint 3
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+     %uint_3 = OpConstant %uint 3
+         %10 = OpConstantComposite %v3uint %uint_1 %uint_2 %uint_3
+     %uint_4 = OpConstant %uint 4
+     %uint_5 = OpConstant %uint 5
+     %uint_6 = OpConstant %uint 6
+         %14 = OpConstantComposite %v3uint %uint_4 %uint_5 %uint_6
+          %f = OpFunction %void None %1
+          %4 = OpLabel
+         %15 = OpIMul %v3uint %10 %14
+               OpReturn
+               OpFunctionEnd
diff --git a/test/expressions/binary/mul/vec3-vec3/u32.wgsl.expected.wgsl b/test/expressions/binary/mul/vec3-vec3/u32.wgsl.expected.wgsl
new file mode 100644
index 0000000..4392855
--- /dev/null
+++ b/test/expressions/binary/mul/vec3-vec3/u32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+  let a = vec3<u32>(1u, 2u, 3u);
+  let b = vec3<u32>(4u, 5u, 6u);
+  let r : vec3<u32> = (a * b);
+}
diff --git a/test/expressions/binary/sub/mat3x3-mat3x3/f32.wgsl b/test/expressions/binary/sub/mat3x3-mat3x3/f32.wgsl
new file mode 100644
index 0000000..4dec34d
--- /dev/null
+++ b/test/expressions/binary/sub/mat3x3-mat3x3/f32.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+    let a = mat3x3<f32>(vec3<f32>( 1.,  2.,  3.), vec3<f32>( 4.,  5.,  6.), vec3<f32>( 7.,  8.,  9.));
+    let b = mat3x3<f32>(vec3<f32>(-1., -2., -3.), vec3<f32>(-4., -5., -6.), vec3<f32>(-7., -8., -9.));
+    let r : mat3x3<f32> = a - b;
+}
diff --git a/test/expressions/binary/sub/mat3x3-mat3x3/f32.wgsl.expected.hlsl b/test/expressions/binary/sub/mat3x3-mat3x3/f32.wgsl.expected.hlsl
new file mode 100644
index 0000000..9d1b2b3
--- /dev/null
+++ b/test/expressions/binary/sub/mat3x3-mat3x3/f32.wgsl.expected.hlsl
@@ -0,0 +1,7 @@
+[numthreads(1, 1, 1)]
+void f() {
+  const float3x3 a = float3x3(float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f), float3(7.0f, 8.0f, 9.0f));
+  const float3x3 b = float3x3(float3(-1.0f, -2.0f, -3.0f), float3(-4.0f, -5.0f, -6.0f), float3(-7.0f, -8.0f, -9.0f));
+  const float3x3 r = (a - b);
+  return;
+}
diff --git a/test/expressions/binary/sub/mat3x3-mat3x3/f32.wgsl.expected.msl b/test/expressions/binary/sub/mat3x3-mat3x3/f32.wgsl.expected.msl
new file mode 100644
index 0000000..bcf7b16
--- /dev/null
+++ b/test/expressions/binary/sub/mat3x3-mat3x3/f32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f() {
+  float3x3 const a = float3x3(float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f), float3(7.0f, 8.0f, 9.0f));
+  float3x3 const b = float3x3(float3(-1.0f, -2.0f, -3.0f), float3(-4.0f, -5.0f, -6.0f), float3(-7.0f, -8.0f, -9.0f));
+  float3x3 const r = (a - b);
+  return;
+}
+
diff --git a/test/expressions/binary/sub/mat3x3-mat3x3/f32.wgsl.expected.spvasm b/test/expressions/binary/sub/mat3x3-mat3x3/f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..bfec754
--- /dev/null
+++ b/test/expressions/binary/sub/mat3x3-mat3x3/f32.wgsl.expected.spvasm
@@ -0,0 +1,55 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 45
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %f "f"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+%mat3v3float = OpTypeMatrix %v3float 3
+    %float_1 = OpConstant %float 1
+    %float_2 = OpConstant %float 2
+    %float_3 = OpConstant %float 3
+         %11 = OpConstantComposite %v3float %float_1 %float_2 %float_3
+    %float_4 = OpConstant %float 4
+    %float_5 = OpConstant %float 5
+    %float_6 = OpConstant %float 6
+         %15 = OpConstantComposite %v3float %float_4 %float_5 %float_6
+    %float_7 = OpConstant %float 7
+    %float_8 = OpConstant %float 8
+    %float_9 = OpConstant %float 9
+         %19 = OpConstantComposite %v3float %float_7 %float_8 %float_9
+         %20 = OpConstantComposite %mat3v3float %11 %15 %19
+   %float_n1 = OpConstant %float -1
+   %float_n2 = OpConstant %float -2
+   %float_n3 = OpConstant %float -3
+         %24 = OpConstantComposite %v3float %float_n1 %float_n2 %float_n3
+   %float_n4 = OpConstant %float -4
+   %float_n5 = OpConstant %float -5
+   %float_n6 = OpConstant %float -6
+         %28 = OpConstantComposite %v3float %float_n4 %float_n5 %float_n6
+   %float_n7 = OpConstant %float -7
+   %float_n8 = OpConstant %float -8
+   %float_n9 = OpConstant %float -9
+         %32 = OpConstantComposite %v3float %float_n7 %float_n8 %float_n9
+         %33 = OpConstantComposite %mat3v3float %24 %28 %32
+          %f = OpFunction %void None %1
+          %4 = OpLabel
+         %35 = OpCompositeExtract %v3float %20 0
+         %36 = OpCompositeExtract %v3float %33 0
+         %37 = OpFSub %v3float %35 %36
+         %38 = OpCompositeExtract %v3float %20 1
+         %39 = OpCompositeExtract %v3float %33 1
+         %40 = OpFSub %v3float %38 %39
+         %41 = OpCompositeExtract %v3float %20 2
+         %42 = OpCompositeExtract %v3float %33 2
+         %43 = OpFSub %v3float %41 %42
+         %44 = OpCompositeConstruct %mat3v3float %37 %40 %43
+               OpReturn
+               OpFunctionEnd
diff --git a/test/expressions/binary/sub/mat3x3-mat3x3/f32.wgsl.expected.wgsl b/test/expressions/binary/sub/mat3x3-mat3x3/f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..5003fea
--- /dev/null
+++ b/test/expressions/binary/sub/mat3x3-mat3x3/f32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+  let a = mat3x3<f32>(vec3<f32>(1.0, 2.0, 3.0), vec3<f32>(4.0, 5.0, 6.0), vec3<f32>(7.0, 8.0, 9.0));
+  let b = mat3x3<f32>(vec3<f32>(-1.0, -2.0, -3.0), vec3<f32>(-4.0, -5.0, -6.0), vec3<f32>(-7.0, -8.0, -9.0));
+  let r : mat3x3<f32> = (a - b);
+}
diff --git a/test/expressions/binary/sub/scalar-scalar/f32.wgsl b/test/expressions/binary/sub/scalar-scalar/f32.wgsl
new file mode 100644
index 0000000..b0e6359
--- /dev/null
+++ b/test/expressions/binary/sub/scalar-scalar/f32.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+    let a = 1.;
+    let b = 2.;
+    let r : f32 = a - b;
+}
diff --git a/test/expressions/binary/sub/scalar-scalar/f32.wgsl.expected.hlsl b/test/expressions/binary/sub/scalar-scalar/f32.wgsl.expected.hlsl
new file mode 100644
index 0000000..04ab363
--- /dev/null
+++ b/test/expressions/binary/sub/scalar-scalar/f32.wgsl.expected.hlsl
@@ -0,0 +1,5 @@
+[numthreads(1, 1, 1)]
+void f() {
+  const float r = (1.0f - 2.0f);
+  return;
+}
diff --git a/test/expressions/binary/sub/scalar-scalar/f32.wgsl.expected.msl b/test/expressions/binary/sub/scalar-scalar/f32.wgsl.expected.msl
new file mode 100644
index 0000000..ae19d6c
--- /dev/null
+++ b/test/expressions/binary/sub/scalar-scalar/f32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f() {
+  float const a = 1.0f;
+  float const b = 2.0f;
+  float const r = (a - b);
+  return;
+}
+
diff --git a/test/expressions/binary/sub/scalar-scalar/f32.wgsl.expected.spvasm b/test/expressions/binary/sub/scalar-scalar/f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..59bc3b5
--- /dev/null
+++ b/test/expressions/binary/sub/scalar-scalar/f32.wgsl.expected.spvasm
@@ -0,0 +1,20 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 9
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %f "f"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+      %float = OpTypeFloat 32
+    %float_1 = OpConstant %float 1
+    %float_2 = OpConstant %float 2
+          %f = OpFunction %void None %1
+          %4 = OpLabel
+          %8 = OpFSub %float %float_1 %float_2
+               OpReturn
+               OpFunctionEnd
diff --git a/test/expressions/binary/sub/scalar-scalar/f32.wgsl.expected.wgsl b/test/expressions/binary/sub/scalar-scalar/f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..ffc19e2
--- /dev/null
+++ b/test/expressions/binary/sub/scalar-scalar/f32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+  let a = 1.0;
+  let b = 2.0;
+  let r : f32 = (a - b);
+}
diff --git a/test/expressions/binary/sub/scalar-scalar/i32.wgsl b/test/expressions/binary/sub/scalar-scalar/i32.wgsl
new file mode 100644
index 0000000..7d396dc
--- /dev/null
+++ b/test/expressions/binary/sub/scalar-scalar/i32.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+    let a = 1;
+    let b = 2;
+    let r : i32 = a - b;
+}
diff --git a/test/expressions/binary/sub/scalar-scalar/i32.wgsl.expected.hlsl b/test/expressions/binary/sub/scalar-scalar/i32.wgsl.expected.hlsl
new file mode 100644
index 0000000..4f995b5
--- /dev/null
+++ b/test/expressions/binary/sub/scalar-scalar/i32.wgsl.expected.hlsl
@@ -0,0 +1,5 @@
+[numthreads(1, 1, 1)]
+void f() {
+  const int r = (1 - 2);
+  return;
+}
diff --git a/test/expressions/binary/sub/scalar-scalar/i32.wgsl.expected.msl b/test/expressions/binary/sub/scalar-scalar/i32.wgsl.expected.msl
new file mode 100644
index 0000000..7a7adf0
--- /dev/null
+++ b/test/expressions/binary/sub/scalar-scalar/i32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f() {
+  int const a = 1;
+  int const b = 2;
+  int const r = (a - b);
+  return;
+}
+
diff --git a/test/expressions/binary/sub/scalar-scalar/i32.wgsl.expected.spvasm b/test/expressions/binary/sub/scalar-scalar/i32.wgsl.expected.spvasm
new file mode 100644
index 0000000..c4489ab
--- /dev/null
+++ b/test/expressions/binary/sub/scalar-scalar/i32.wgsl.expected.spvasm
@@ -0,0 +1,20 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 9
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %f "f"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+      %int_2 = OpConstant %int 2
+          %f = OpFunction %void None %1
+          %4 = OpLabel
+          %8 = OpISub %int %int_1 %int_2
+               OpReturn
+               OpFunctionEnd
diff --git a/test/expressions/binary/sub/scalar-scalar/i32.wgsl.expected.wgsl b/test/expressions/binary/sub/scalar-scalar/i32.wgsl.expected.wgsl
new file mode 100644
index 0000000..d881d44
--- /dev/null
+++ b/test/expressions/binary/sub/scalar-scalar/i32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+  let a = 1;
+  let b = 2;
+  let r : i32 = (a - b);
+}
diff --git a/test/expressions/binary/sub/scalar-scalar/u32.wgsl b/test/expressions/binary/sub/scalar-scalar/u32.wgsl
new file mode 100644
index 0000000..5f210c2
--- /dev/null
+++ b/test/expressions/binary/sub/scalar-scalar/u32.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+    let a = 1u;
+    let b = 2u;
+    let r : u32 = a - b;
+}
diff --git a/test/expressions/binary/sub/scalar-scalar/u32.wgsl.expected.hlsl b/test/expressions/binary/sub/scalar-scalar/u32.wgsl.expected.hlsl
new file mode 100644
index 0000000..23719ac
--- /dev/null
+++ b/test/expressions/binary/sub/scalar-scalar/u32.wgsl.expected.hlsl
@@ -0,0 +1,5 @@
+[numthreads(1, 1, 1)]
+void f() {
+  const uint r = (1u - 2u);
+  return;
+}
diff --git a/test/expressions/binary/sub/scalar-scalar/u32.wgsl.expected.msl b/test/expressions/binary/sub/scalar-scalar/u32.wgsl.expected.msl
new file mode 100644
index 0000000..d93a0c7
--- /dev/null
+++ b/test/expressions/binary/sub/scalar-scalar/u32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f() {
+  uint const a = 1u;
+  uint const b = 2u;
+  uint const r = (a - b);
+  return;
+}
+
diff --git a/test/expressions/binary/sub/scalar-scalar/u32.wgsl.expected.spvasm b/test/expressions/binary/sub/scalar-scalar/u32.wgsl.expected.spvasm
new file mode 100644
index 0000000..a68d4e3
--- /dev/null
+++ b/test/expressions/binary/sub/scalar-scalar/u32.wgsl.expected.spvasm
@@ -0,0 +1,20 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 9
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %f "f"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+          %f = OpFunction %void None %1
+          %4 = OpLabel
+          %8 = OpISub %uint %uint_1 %uint_2
+               OpReturn
+               OpFunctionEnd
diff --git a/test/expressions/binary/sub/scalar-scalar/u32.wgsl.expected.wgsl b/test/expressions/binary/sub/scalar-scalar/u32.wgsl.expected.wgsl
new file mode 100644
index 0000000..932d0b7
--- /dev/null
+++ b/test/expressions/binary/sub/scalar-scalar/u32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+  let a = 1u;
+  let b = 2u;
+  let r : u32 = (a - b);
+}
diff --git a/test/expressions/binary/sub/scalar-vec3/f32.wgsl b/test/expressions/binary/sub/scalar-vec3/f32.wgsl
new file mode 100644
index 0000000..1b23e49
--- /dev/null
+++ b/test/expressions/binary/sub/scalar-vec3/f32.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+    let a = 4.;
+    let b = vec3<f32>(1., 2., 3.);
+    let r : vec3<f32> = a - b;
+}
diff --git a/test/expressions/binary/sub/scalar-vec3/f32.wgsl.expected.hlsl b/test/expressions/binary/sub/scalar-vec3/f32.wgsl.expected.hlsl
new file mode 100644
index 0000000..d714c62
--- /dev/null
+++ b/test/expressions/binary/sub/scalar-vec3/f32.wgsl.expected.hlsl
@@ -0,0 +1,7 @@
+[numthreads(1, 1, 1)]
+void f() {
+  const float a = 4.0f;
+  const float3 b = float3(1.0f, 2.0f, 3.0f);
+  const float3 r = (a - b);
+  return;
+}
diff --git a/test/expressions/binary/sub/scalar-vec3/f32.wgsl.expected.msl b/test/expressions/binary/sub/scalar-vec3/f32.wgsl.expected.msl
new file mode 100644
index 0000000..ce03e02
--- /dev/null
+++ b/test/expressions/binary/sub/scalar-vec3/f32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f() {
+  float const a = 4.0f;
+  float3 const b = float3(1.0f, 2.0f, 3.0f);
+  float3 const r = (a - b);
+  return;
+}
+
diff --git a/test/expressions/binary/sub/scalar-vec3/f32.wgsl.expected.spvasm b/test/expressions/binary/sub/scalar-vec3/f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..b7e0f0a
--- /dev/null
+++ b/test/expressions/binary/sub/scalar-vec3/f32.wgsl.expected.spvasm
@@ -0,0 +1,28 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 17
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %f "f"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+      %float = OpTypeFloat 32
+    %float_4 = OpConstant %float 4
+    %v3float = OpTypeVector %float 3
+    %float_1 = OpConstant %float 1
+    %float_2 = OpConstant %float 2
+    %float_3 = OpConstant %float 3
+         %11 = OpConstantComposite %v3float %float_1 %float_2 %float_3
+%_ptr_Function_v3float = OpTypePointer Function %v3float
+         %15 = OpConstantNull %v3float
+          %f = OpFunction %void None %1
+          %4 = OpLabel
+         %13 = OpVariable %_ptr_Function_v3float Function %15
+         %16 = OpCompositeConstruct %v3float %float_4 %float_4 %float_4
+         %12 = OpFSub %v3float %16 %11
+               OpReturn
+               OpFunctionEnd
diff --git a/test/expressions/binary/sub/scalar-vec3/f32.wgsl.expected.wgsl b/test/expressions/binary/sub/scalar-vec3/f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..69ff882
--- /dev/null
+++ b/test/expressions/binary/sub/scalar-vec3/f32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+  let a = 4.0;
+  let b = vec3<f32>(1.0, 2.0, 3.0);
+  let r : vec3<f32> = (a - b);
+}
diff --git a/test/expressions/binary/sub/scalar-vec3/i32.wgsl b/test/expressions/binary/sub/scalar-vec3/i32.wgsl
new file mode 100644
index 0000000..1e024c5
--- /dev/null
+++ b/test/expressions/binary/sub/scalar-vec3/i32.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+    let a = 4;
+    let b = vec3<i32>(1, 2, 3);
+    let r : vec3<i32> = a - b;
+}
diff --git a/test/expressions/binary/sub/scalar-vec3/i32.wgsl.expected.hlsl b/test/expressions/binary/sub/scalar-vec3/i32.wgsl.expected.hlsl
new file mode 100644
index 0000000..1e67f13
--- /dev/null
+++ b/test/expressions/binary/sub/scalar-vec3/i32.wgsl.expected.hlsl
@@ -0,0 +1,7 @@
+[numthreads(1, 1, 1)]
+void f() {
+  const int a = 4;
+  const int3 b = int3(1, 2, 3);
+  const int3 r = (a - b);
+  return;
+}
diff --git a/test/expressions/binary/sub/scalar-vec3/i32.wgsl.expected.msl b/test/expressions/binary/sub/scalar-vec3/i32.wgsl.expected.msl
new file mode 100644
index 0000000..c6791796
--- /dev/null
+++ b/test/expressions/binary/sub/scalar-vec3/i32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f() {
+  int const a = 4;
+  int3 const b = int3(1, 2, 3);
+  int3 const r = (a - b);
+  return;
+}
+
diff --git a/test/expressions/binary/sub/scalar-vec3/i32.wgsl.expected.spvasm b/test/expressions/binary/sub/scalar-vec3/i32.wgsl.expected.spvasm
new file mode 100644
index 0000000..ab003eb
--- /dev/null
+++ b/test/expressions/binary/sub/scalar-vec3/i32.wgsl.expected.spvasm
@@ -0,0 +1,28 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 17
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %f "f"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+        %int = OpTypeInt 32 1
+      %int_4 = OpConstant %int 4
+      %v3int = OpTypeVector %int 3
+      %int_1 = OpConstant %int 1
+      %int_2 = OpConstant %int 2
+      %int_3 = OpConstant %int 3
+         %11 = OpConstantComposite %v3int %int_1 %int_2 %int_3
+%_ptr_Function_v3int = OpTypePointer Function %v3int
+         %15 = OpConstantNull %v3int
+          %f = OpFunction %void None %1
+          %4 = OpLabel
+         %13 = OpVariable %_ptr_Function_v3int Function %15
+         %16 = OpCompositeConstruct %v3int %int_4 %int_4 %int_4
+         %12 = OpISub %v3int %16 %11
+               OpReturn
+               OpFunctionEnd
diff --git a/test/expressions/binary/sub/scalar-vec3/i32.wgsl.expected.wgsl b/test/expressions/binary/sub/scalar-vec3/i32.wgsl.expected.wgsl
new file mode 100644
index 0000000..0efb533
--- /dev/null
+++ b/test/expressions/binary/sub/scalar-vec3/i32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+  let a = 4;
+  let b = vec3<i32>(1, 2, 3);
+  let r : vec3<i32> = (a - b);
+}
diff --git a/test/expressions/binary/sub/scalar-vec3/u32.wgsl b/test/expressions/binary/sub/scalar-vec3/u32.wgsl
new file mode 100644
index 0000000..0042cc2
--- /dev/null
+++ b/test/expressions/binary/sub/scalar-vec3/u32.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+    let a = 4u;
+    let b = vec3<u32>(1u, 2u, 3u);
+    let r : vec3<u32> = a - b;
+}
diff --git a/test/expressions/binary/sub/scalar-vec3/u32.wgsl.expected.hlsl b/test/expressions/binary/sub/scalar-vec3/u32.wgsl.expected.hlsl
new file mode 100644
index 0000000..90f540d
--- /dev/null
+++ b/test/expressions/binary/sub/scalar-vec3/u32.wgsl.expected.hlsl
@@ -0,0 +1,7 @@
+[numthreads(1, 1, 1)]
+void f() {
+  const uint a = 4u;
+  const uint3 b = uint3(1u, 2u, 3u);
+  const uint3 r = (a - b);
+  return;
+}
diff --git a/test/expressions/binary/sub/scalar-vec3/u32.wgsl.expected.msl b/test/expressions/binary/sub/scalar-vec3/u32.wgsl.expected.msl
new file mode 100644
index 0000000..ec8b6cf
--- /dev/null
+++ b/test/expressions/binary/sub/scalar-vec3/u32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f() {
+  uint const a = 4u;
+  uint3 const b = uint3(1u, 2u, 3u);
+  uint3 const r = (a - b);
+  return;
+}
+
diff --git a/test/expressions/binary/sub/scalar-vec3/u32.wgsl.expected.spvasm b/test/expressions/binary/sub/scalar-vec3/u32.wgsl.expected.spvasm
new file mode 100644
index 0000000..f5ca740
--- /dev/null
+++ b/test/expressions/binary/sub/scalar-vec3/u32.wgsl.expected.spvasm
@@ -0,0 +1,28 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 17
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %f "f"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+     %v3uint = OpTypeVector %uint 3
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+     %uint_3 = OpConstant %uint 3
+         %11 = OpConstantComposite %v3uint %uint_1 %uint_2 %uint_3
+%_ptr_Function_v3uint = OpTypePointer Function %v3uint
+         %15 = OpConstantNull %v3uint
+          %f = OpFunction %void None %1
+          %4 = OpLabel
+         %13 = OpVariable %_ptr_Function_v3uint Function %15
+         %16 = OpCompositeConstruct %v3uint %uint_4 %uint_4 %uint_4
+         %12 = OpISub %v3uint %16 %11
+               OpReturn
+               OpFunctionEnd
diff --git a/test/expressions/binary/sub/scalar-vec3/u32.wgsl.expected.wgsl b/test/expressions/binary/sub/scalar-vec3/u32.wgsl.expected.wgsl
new file mode 100644
index 0000000..b78efa7
--- /dev/null
+++ b/test/expressions/binary/sub/scalar-vec3/u32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+  let a = 4u;
+  let b = vec3<u32>(1u, 2u, 3u);
+  let r : vec3<u32> = (a - b);
+}
diff --git a/test/expressions/binary/sub/vec3-scalar/f32.wgsl b/test/expressions/binary/sub/vec3-scalar/f32.wgsl
new file mode 100644
index 0000000..0bdf89e
--- /dev/null
+++ b/test/expressions/binary/sub/vec3-scalar/f32.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+    let a = vec3<f32>(1., 2., 3.);
+    let b = 4.;
+    let r : vec3<f32> = a - b;
+}
diff --git a/test/expressions/binary/sub/vec3-scalar/f32.wgsl.expected.hlsl b/test/expressions/binary/sub/vec3-scalar/f32.wgsl.expected.hlsl
new file mode 100644
index 0000000..0476c62
--- /dev/null
+++ b/test/expressions/binary/sub/vec3-scalar/f32.wgsl.expected.hlsl
@@ -0,0 +1,6 @@
+[numthreads(1, 1, 1)]
+void f() {
+  const float3 a = float3(1.0f, 2.0f, 3.0f);
+  const float3 r = (a - 4.0f);
+  return;
+}
diff --git a/test/expressions/binary/sub/vec3-scalar/f32.wgsl.expected.msl b/test/expressions/binary/sub/vec3-scalar/f32.wgsl.expected.msl
new file mode 100644
index 0000000..7799789
--- /dev/null
+++ b/test/expressions/binary/sub/vec3-scalar/f32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f() {
+  float3 const a = float3(1.0f, 2.0f, 3.0f);
+  float const b = 4.0f;
+  float3 const r = (a - b);
+  return;
+}
+
diff --git a/test/expressions/binary/sub/vec3-scalar/f32.wgsl.expected.spvasm b/test/expressions/binary/sub/vec3-scalar/f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..b09055c
--- /dev/null
+++ b/test/expressions/binary/sub/vec3-scalar/f32.wgsl.expected.spvasm
@@ -0,0 +1,28 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 17
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %f "f"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+    %float_1 = OpConstant %float 1
+    %float_2 = OpConstant %float 2
+    %float_3 = OpConstant %float 3
+         %10 = OpConstantComposite %v3float %float_1 %float_2 %float_3
+    %float_4 = OpConstant %float 4
+%_ptr_Function_v3float = OpTypePointer Function %v3float
+         %15 = OpConstantNull %v3float
+          %f = OpFunction %void None %1
+          %4 = OpLabel
+         %13 = OpVariable %_ptr_Function_v3float Function %15
+         %16 = OpCompositeConstruct %v3float %float_4 %float_4 %float_4
+         %12 = OpFSub %v3float %10 %16
+               OpReturn
+               OpFunctionEnd
diff --git a/test/expressions/binary/sub/vec3-scalar/f32.wgsl.expected.wgsl b/test/expressions/binary/sub/vec3-scalar/f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..de0d72d
--- /dev/null
+++ b/test/expressions/binary/sub/vec3-scalar/f32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+  let a = vec3<f32>(1.0, 2.0, 3.0);
+  let b = 4.0;
+  let r : vec3<f32> = (a - b);
+}
diff --git a/test/expressions/binary/sub/vec3-scalar/i32.wgsl b/test/expressions/binary/sub/vec3-scalar/i32.wgsl
new file mode 100644
index 0000000..0fab83f
--- /dev/null
+++ b/test/expressions/binary/sub/vec3-scalar/i32.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+    let a = vec3<i32>(1, 2, 3);
+    let b = 4;
+    let r : vec3<i32> = a - b;
+}
diff --git a/test/expressions/binary/sub/vec3-scalar/i32.wgsl.expected.hlsl b/test/expressions/binary/sub/vec3-scalar/i32.wgsl.expected.hlsl
new file mode 100644
index 0000000..8db37c9
--- /dev/null
+++ b/test/expressions/binary/sub/vec3-scalar/i32.wgsl.expected.hlsl
@@ -0,0 +1,6 @@
+[numthreads(1, 1, 1)]
+void f() {
+  const int3 a = int3(1, 2, 3);
+  const int3 r = (a - 4);
+  return;
+}
diff --git a/test/expressions/binary/sub/vec3-scalar/i32.wgsl.expected.msl b/test/expressions/binary/sub/vec3-scalar/i32.wgsl.expected.msl
new file mode 100644
index 0000000..9fc724f
--- /dev/null
+++ b/test/expressions/binary/sub/vec3-scalar/i32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f() {
+  int3 const a = int3(1, 2, 3);
+  int const b = 4;
+  int3 const r = (a - b);
+  return;
+}
+
diff --git a/test/expressions/binary/sub/vec3-scalar/i32.wgsl.expected.spvasm b/test/expressions/binary/sub/vec3-scalar/i32.wgsl.expected.spvasm
new file mode 100644
index 0000000..05cd87f
--- /dev/null
+++ b/test/expressions/binary/sub/vec3-scalar/i32.wgsl.expected.spvasm
@@ -0,0 +1,28 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 17
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %f "f"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+        %int = OpTypeInt 32 1
+      %v3int = OpTypeVector %int 3
+      %int_1 = OpConstant %int 1
+      %int_2 = OpConstant %int 2
+      %int_3 = OpConstant %int 3
+         %10 = OpConstantComposite %v3int %int_1 %int_2 %int_3
+      %int_4 = OpConstant %int 4
+%_ptr_Function_v3int = OpTypePointer Function %v3int
+         %15 = OpConstantNull %v3int
+          %f = OpFunction %void None %1
+          %4 = OpLabel
+         %13 = OpVariable %_ptr_Function_v3int Function %15
+         %16 = OpCompositeConstruct %v3int %int_4 %int_4 %int_4
+         %12 = OpISub %v3int %10 %16
+               OpReturn
+               OpFunctionEnd
diff --git a/test/expressions/binary/sub/vec3-scalar/i32.wgsl.expected.wgsl b/test/expressions/binary/sub/vec3-scalar/i32.wgsl.expected.wgsl
new file mode 100644
index 0000000..ea16bd4
--- /dev/null
+++ b/test/expressions/binary/sub/vec3-scalar/i32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+  let a = vec3<i32>(1, 2, 3);
+  let b = 4;
+  let r : vec3<i32> = (a - b);
+}
diff --git a/test/expressions/binary/sub/vec3-scalar/u32.wgsl b/test/expressions/binary/sub/vec3-scalar/u32.wgsl
new file mode 100644
index 0000000..0ec4317
--- /dev/null
+++ b/test/expressions/binary/sub/vec3-scalar/u32.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+    let a = vec3<u32>(1u, 2u, 3u);
+    let b = 4u;
+    let r : vec3<u32> = a - b;
+}
diff --git a/test/expressions/binary/sub/vec3-scalar/u32.wgsl.expected.hlsl b/test/expressions/binary/sub/vec3-scalar/u32.wgsl.expected.hlsl
new file mode 100644
index 0000000..6a9b7ee
--- /dev/null
+++ b/test/expressions/binary/sub/vec3-scalar/u32.wgsl.expected.hlsl
@@ -0,0 +1,6 @@
+[numthreads(1, 1, 1)]
+void f() {
+  const uint3 a = uint3(1u, 2u, 3u);
+  const uint3 r = (a - 4u);
+  return;
+}
diff --git a/test/expressions/binary/sub/vec3-scalar/u32.wgsl.expected.msl b/test/expressions/binary/sub/vec3-scalar/u32.wgsl.expected.msl
new file mode 100644
index 0000000..7f76d5a
--- /dev/null
+++ b/test/expressions/binary/sub/vec3-scalar/u32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f() {
+  uint3 const a = uint3(1u, 2u, 3u);
+  uint const b = 4u;
+  uint3 const r = (a - b);
+  return;
+}
+
diff --git a/test/expressions/binary/sub/vec3-scalar/u32.wgsl.expected.spvasm b/test/expressions/binary/sub/vec3-scalar/u32.wgsl.expected.spvasm
new file mode 100644
index 0000000..98dc260
--- /dev/null
+++ b/test/expressions/binary/sub/vec3-scalar/u32.wgsl.expected.spvasm
@@ -0,0 +1,28 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 17
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %f "f"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %v3uint = OpTypeVector %uint 3
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+     %uint_3 = OpConstant %uint 3
+         %10 = OpConstantComposite %v3uint %uint_1 %uint_2 %uint_3
+     %uint_4 = OpConstant %uint 4
+%_ptr_Function_v3uint = OpTypePointer Function %v3uint
+         %15 = OpConstantNull %v3uint
+          %f = OpFunction %void None %1
+          %4 = OpLabel
+         %13 = OpVariable %_ptr_Function_v3uint Function %15
+         %16 = OpCompositeConstruct %v3uint %uint_4 %uint_4 %uint_4
+         %12 = OpISub %v3uint %10 %16
+               OpReturn
+               OpFunctionEnd
diff --git a/test/expressions/binary/sub/vec3-scalar/u32.wgsl.expected.wgsl b/test/expressions/binary/sub/vec3-scalar/u32.wgsl.expected.wgsl
new file mode 100644
index 0000000..2052d8b
--- /dev/null
+++ b/test/expressions/binary/sub/vec3-scalar/u32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+  let a = vec3<u32>(1u, 2u, 3u);
+  let b = 4u;
+  let r : vec3<u32> = (a - b);
+}
diff --git a/test/expressions/binary/sub/vec3-vec3/f32.wgsl b/test/expressions/binary/sub/vec3-vec3/f32.wgsl
new file mode 100644
index 0000000..3bb31cf
--- /dev/null
+++ b/test/expressions/binary/sub/vec3-vec3/f32.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+    let a = vec3<f32>(1., 2., 3.);
+    let b = vec3<f32>(4., 5., 6.);
+    let r : vec3<f32> = a - b;
+}
diff --git a/test/expressions/binary/sub/vec3-vec3/f32.wgsl.expected.hlsl b/test/expressions/binary/sub/vec3-vec3/f32.wgsl.expected.hlsl
new file mode 100644
index 0000000..f4a568e
--- /dev/null
+++ b/test/expressions/binary/sub/vec3-vec3/f32.wgsl.expected.hlsl
@@ -0,0 +1,7 @@
+[numthreads(1, 1, 1)]
+void f() {
+  const float3 a = float3(1.0f, 2.0f, 3.0f);
+  const float3 b = float3(4.0f, 5.0f, 6.0f);
+  const float3 r = (a - b);
+  return;
+}
diff --git a/test/expressions/binary/sub/vec3-vec3/f32.wgsl.expected.msl b/test/expressions/binary/sub/vec3-vec3/f32.wgsl.expected.msl
new file mode 100644
index 0000000..5ce4e15
--- /dev/null
+++ b/test/expressions/binary/sub/vec3-vec3/f32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f() {
+  float3 const a = float3(1.0f, 2.0f, 3.0f);
+  float3 const b = float3(4.0f, 5.0f, 6.0f);
+  float3 const r = (a - b);
+  return;
+}
+
diff --git a/test/expressions/binary/sub/vec3-vec3/f32.wgsl.expected.spvasm b/test/expressions/binary/sub/vec3-vec3/f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..649b28b
--- /dev/null
+++ b/test/expressions/binary/sub/vec3-vec3/f32.wgsl.expected.spvasm
@@ -0,0 +1,27 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 16
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %f "f"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+    %float_1 = OpConstant %float 1
+    %float_2 = OpConstant %float 2
+    %float_3 = OpConstant %float 3
+         %10 = OpConstantComposite %v3float %float_1 %float_2 %float_3
+    %float_4 = OpConstant %float 4
+    %float_5 = OpConstant %float 5
+    %float_6 = OpConstant %float 6
+         %14 = OpConstantComposite %v3float %float_4 %float_5 %float_6
+          %f = OpFunction %void None %1
+          %4 = OpLabel
+         %15 = OpFSub %v3float %10 %14
+               OpReturn
+               OpFunctionEnd
diff --git a/test/expressions/binary/sub/vec3-vec3/f32.wgsl.expected.wgsl b/test/expressions/binary/sub/vec3-vec3/f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..8beb881
--- /dev/null
+++ b/test/expressions/binary/sub/vec3-vec3/f32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+  let a = vec3<f32>(1.0, 2.0, 3.0);
+  let b = vec3<f32>(4.0, 5.0, 6.0);
+  let r : vec3<f32> = (a - b);
+}
diff --git a/test/expressions/binary/sub/vec3-vec3/i32.wgsl b/test/expressions/binary/sub/vec3-vec3/i32.wgsl
new file mode 100644
index 0000000..7ecdc45
--- /dev/null
+++ b/test/expressions/binary/sub/vec3-vec3/i32.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+    let a = vec3<i32>(1, 2, 3);
+    let b = vec3<i32>(4, 5, 6);
+    let r : vec3<i32> = a - b;
+}
diff --git a/test/expressions/binary/sub/vec3-vec3/i32.wgsl.expected.hlsl b/test/expressions/binary/sub/vec3-vec3/i32.wgsl.expected.hlsl
new file mode 100644
index 0000000..e8a2622
--- /dev/null
+++ b/test/expressions/binary/sub/vec3-vec3/i32.wgsl.expected.hlsl
@@ -0,0 +1,7 @@
+[numthreads(1, 1, 1)]
+void f() {
+  const int3 a = int3(1, 2, 3);
+  const int3 b = int3(4, 5, 6);
+  const int3 r = (a - b);
+  return;
+}
diff --git a/test/expressions/binary/sub/vec3-vec3/i32.wgsl.expected.msl b/test/expressions/binary/sub/vec3-vec3/i32.wgsl.expected.msl
new file mode 100644
index 0000000..f611cb2
--- /dev/null
+++ b/test/expressions/binary/sub/vec3-vec3/i32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f() {
+  int3 const a = int3(1, 2, 3);
+  int3 const b = int3(4, 5, 6);
+  int3 const r = (a - b);
+  return;
+}
+
diff --git a/test/expressions/binary/sub/vec3-vec3/i32.wgsl.expected.spvasm b/test/expressions/binary/sub/vec3-vec3/i32.wgsl.expected.spvasm
new file mode 100644
index 0000000..1a4031d
--- /dev/null
+++ b/test/expressions/binary/sub/vec3-vec3/i32.wgsl.expected.spvasm
@@ -0,0 +1,27 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 16
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %f "f"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+        %int = OpTypeInt 32 1
+      %v3int = OpTypeVector %int 3
+      %int_1 = OpConstant %int 1
+      %int_2 = OpConstant %int 2
+      %int_3 = OpConstant %int 3
+         %10 = OpConstantComposite %v3int %int_1 %int_2 %int_3
+      %int_4 = OpConstant %int 4
+      %int_5 = OpConstant %int 5
+      %int_6 = OpConstant %int 6
+         %14 = OpConstantComposite %v3int %int_4 %int_5 %int_6
+          %f = OpFunction %void None %1
+          %4 = OpLabel
+         %15 = OpISub %v3int %10 %14
+               OpReturn
+               OpFunctionEnd
diff --git a/test/expressions/binary/sub/vec3-vec3/i32.wgsl.expected.wgsl b/test/expressions/binary/sub/vec3-vec3/i32.wgsl.expected.wgsl
new file mode 100644
index 0000000..00ff109
--- /dev/null
+++ b/test/expressions/binary/sub/vec3-vec3/i32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+  let a = vec3<i32>(1, 2, 3);
+  let b = vec3<i32>(4, 5, 6);
+  let r : vec3<i32> = (a - b);
+}
diff --git a/test/expressions/binary/sub/vec3-vec3/u32.wgsl b/test/expressions/binary/sub/vec3-vec3/u32.wgsl
new file mode 100644
index 0000000..547383e
--- /dev/null
+++ b/test/expressions/binary/sub/vec3-vec3/u32.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+    let a = vec3<u32>(1u, 2u, 3u);
+    let b = vec3<u32>(4u, 5u, 6u);
+    let r : vec3<u32> = a - b;
+}
diff --git a/test/expressions/binary/sub/vec3-vec3/u32.wgsl.expected.hlsl b/test/expressions/binary/sub/vec3-vec3/u32.wgsl.expected.hlsl
new file mode 100644
index 0000000..1a8d03f
--- /dev/null
+++ b/test/expressions/binary/sub/vec3-vec3/u32.wgsl.expected.hlsl
@@ -0,0 +1,7 @@
+[numthreads(1, 1, 1)]
+void f() {
+  const uint3 a = uint3(1u, 2u, 3u);
+  const uint3 b = uint3(4u, 5u, 6u);
+  const uint3 r = (a - b);
+  return;
+}
diff --git a/test/expressions/binary/sub/vec3-vec3/u32.wgsl.expected.msl b/test/expressions/binary/sub/vec3-vec3/u32.wgsl.expected.msl
new file mode 100644
index 0000000..0f6cc4b
--- /dev/null
+++ b/test/expressions/binary/sub/vec3-vec3/u32.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f() {
+  uint3 const a = uint3(1u, 2u, 3u);
+  uint3 const b = uint3(4u, 5u, 6u);
+  uint3 const r = (a - b);
+  return;
+}
+
diff --git a/test/expressions/binary/sub/vec3-vec3/u32.wgsl.expected.spvasm b/test/expressions/binary/sub/vec3-vec3/u32.wgsl.expected.spvasm
new file mode 100644
index 0000000..8dfb98d
--- /dev/null
+++ b/test/expressions/binary/sub/vec3-vec3/u32.wgsl.expected.spvasm
@@ -0,0 +1,27 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 16
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %f "f"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %v3uint = OpTypeVector %uint 3
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+     %uint_3 = OpConstant %uint 3
+         %10 = OpConstantComposite %v3uint %uint_1 %uint_2 %uint_3
+     %uint_4 = OpConstant %uint 4
+     %uint_5 = OpConstant %uint 5
+     %uint_6 = OpConstant %uint 6
+         %14 = OpConstantComposite %v3uint %uint_4 %uint_5 %uint_6
+          %f = OpFunction %void None %1
+          %4 = OpLabel
+         %15 = OpISub %v3uint %10 %14
+               OpReturn
+               OpFunctionEnd
diff --git a/test/expressions/binary/sub/vec3-vec3/u32.wgsl.expected.wgsl b/test/expressions/binary/sub/vec3-vec3/u32.wgsl.expected.wgsl
new file mode 100644
index 0000000..7559a1b
--- /dev/null
+++ b/test/expressions/binary/sub/vec3-vec3/u32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+[[stage(compute), workgroup_size(1)]]
+fn f() {
+  let a = vec3<u32>(1u, 2u, 3u);
+  let b = vec3<u32>(4u, 5u, 6u);
+  let r : vec3<u32> = (a - b);
+}
diff --git a/test/expressions/binary_expressions.wgsl b/test/expressions/binary_expressions.wgsl
deleted file mode 100644
index b377a13..0000000
--- a/test/expressions/binary_expressions.wgsl
+++ /dev/null
@@ -1,113 +0,0 @@
-fn bitwise_i32() {

-    var s1 : i32;

-    var s2 : i32;

-    var v1 : vec3<i32>;

-    var v2 : vec3<i32>;

-

-    s1 = s1 | s2;

-    s1 = s1 & s2;

-    s1 = s1 ^ s2;

-

-    v1 = v1 | v2;

-    v1 = v1 & v2;

-    v1 = v1 ^ v2;

-}

-

-fn bitwise_u32() {

-    var s1 : u32;

-    var s2 : u32;

-    var v1 : vec3<u32>;

-    var v2 : vec3<u32>;

-

-    s1 = s1 | s2;

-    s1 = s1 & s2;

-    s1 = s1 ^ s2;

-

-    v1 = v1 | v2;

-    v1 = v1 & v2;

-    v1 = v1 ^ v2;

-}

-

-fn vector_scalar_f32() {

-    var v : vec3<f32>;

-    var s : f32;

-    var r : vec3<f32>;

-    r = v + s;

-    r = v - s;

-    r = v * s;

-    r = v / s;

-    //r = v % s;

-}

-

-fn vector_scalar_i32() {

-    var v : vec3<i32>;

-    var s : i32;

-    var r : vec3<i32>;

-    r = v + s;

-    r = v - s;

-    r = v * s;

-    r = v / s;

-    r = v % s;

-}

-

-fn vector_scalar_u32() {

-    var v : vec3<u32>;

-    var s : u32;

-    var r : vec3<u32>;

-    r = v + s;

-    r = v - s;

-    r = v * s;

-    r = v / s;

-    r = v % s;

-}

-

-fn scalar_vector_f32() {

-    var v : vec3<f32>;

-    var s : f32;

-    var r : vec3<f32>;

-    r = s + v;

-    r = s - v;

-    r = s * v;

-    r = s / v;

-    //r = s % v;

-}

-

-fn scalar_vector_i32() {

-    var v : vec3<i32>;

-    var s : i32;

-    var r : vec3<i32>;

-    r = s + v;

-    r = s - v;

-    r = s * v;

-    r = s / v;

-    r = s % v;

-}

-

-fn scalar_vector_u32() {

-    var v : vec3<u32>;

-    var s : u32;

-    var r : vec3<u32>;

-    r = s + v;

-    r = s - v;

-    r = s * v;

-    r = s / v;

-    r = s % v;

-}

-

-fn matrix_matrix_f32() {

-    var m34 : mat3x4<f32>;

-    var m43 : mat4x3<f32>;

-    var m33 : mat3x3<f32>;

-    var m44 : mat4x4<f32>;

-

-    m34 = m34 + m34;

-    m34 = m34 - m34;

-

-    m33 = m43 * m34;

-    m44 = m34 * m43;

-}

-

-[[stage(fragment)]]

-fn main() -> [[location(0)]] vec4<f32> {

-    return vec4<f32>(0.0,0.0,0.0,0.0);

-}

diff --git a/test/expressions/binary_expressions.wgsl.expected.hlsl b/test/expressions/binary_expressions.wgsl.expected.hlsl
deleted file mode 100644
index 122eaa7..0000000
--- a/test/expressions/binary_expressions.wgsl.expected.hlsl
+++ /dev/null
@@ -1,109 +0,0 @@
-void bitwise_i32() {
-  int s1 = 0;
-  int s2 = 0;
-  int3 v1 = int3(0, 0, 0);
-  int3 v2 = int3(0, 0, 0);
-  s1 = (s1 | s2);
-  s1 = (s1 & s2);
-  s1 = (s1 ^ s2);
-  v1 = (v1 | v2);
-  v1 = (v1 & v2);
-  v1 = (v1 ^ v2);
-}
-
-void bitwise_u32() {
-  uint s1 = 0u;
-  uint s2 = 0u;
-  uint3 v1 = uint3(0u, 0u, 0u);
-  uint3 v2 = uint3(0u, 0u, 0u);
-  s1 = (s1 | s2);
-  s1 = (s1 & s2);
-  s1 = (s1 ^ s2);
-  v1 = (v1 | v2);
-  v1 = (v1 & v2);
-  v1 = (v1 ^ v2);
-}
-
-void vector_scalar_f32() {
-  float3 v = float3(0.0f, 0.0f, 0.0f);
-  float s = 0.0f;
-  float3 r = float3(0.0f, 0.0f, 0.0f);
-  r = (v + s);
-  r = (v - s);
-  r = (v * s);
-  r = (v / s);
-}
-
-void vector_scalar_i32() {
-  int3 v = int3(0, 0, 0);
-  int s = 0;
-  int3 r = int3(0, 0, 0);
-  r = (v + s);
-  r = (v - s);
-  r = (v * s);
-  r = (v / s);
-  r = (v % s);
-}
-
-void vector_scalar_u32() {
-  uint3 v = uint3(0u, 0u, 0u);
-  uint s = 0u;
-  uint3 r = uint3(0u, 0u, 0u);
-  r = (v + s);
-  r = (v - s);
-  r = (v * s);
-  r = (v / s);
-  r = (v % s);
-}
-
-void scalar_vector_f32() {
-  float3 v = float3(0.0f, 0.0f, 0.0f);
-  float s = 0.0f;
-  float3 r = float3(0.0f, 0.0f, 0.0f);
-  r = (s + v);
-  r = (s - v);
-  r = (s * v);
-  r = (s / v);
-}
-
-void scalar_vector_i32() {
-  int3 v = int3(0, 0, 0);
-  int s = 0;
-  int3 r = int3(0, 0, 0);
-  r = (s + v);
-  r = (s - v);
-  r = (s * v);
-  r = (s / v);
-  r = (s % v);
-}
-
-void scalar_vector_u32() {
-  uint3 v = uint3(0u, 0u, 0u);
-  uint s = 0u;
-  uint3 r = uint3(0u, 0u, 0u);
-  r = (s + v);
-  r = (s - v);
-  r = (s * v);
-  r = (s / v);
-  r = (s % v);
-}
-
-void matrix_matrix_f32() {
-  float3x4 m34 = float3x4(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
-  float4x3 m43 = float4x3(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
-  float3x3 m33 = float3x3(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
-  float4x4 m44 = 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);
-  m34 = (m34 + m34);
-  m34 = (m34 - m34);
-  m33 = mul(m34, m43);
-  m44 = mul(m43, m34);
-}
-
-struct tint_symbol {
-  float4 value : SV_Target0;
-};
-
-tint_symbol main() {
-  const tint_symbol tint_symbol_1 = {float4(0.0f, 0.0f, 0.0f, 0.0f)};
-  return tint_symbol_1;
-}
diff --git a/test/expressions/binary_expressions.wgsl.expected.msl b/test/expressions/binary_expressions.wgsl.expected.msl
deleted file mode 100644
index afef456..0000000
--- a/test/expressions/binary_expressions.wgsl.expected.msl
+++ /dev/null
@@ -1,113 +0,0 @@
-#include <metal_stdlib>
-
-using namespace metal;
-struct tint_symbol_1 {
-  float4 value [[color(0)]];
-};
-
-void bitwise_i32() {
-  int s1 = 0;
-  int s2 = 0;
-  int3 v1 = 0;
-  int3 v2 = 0;
-  s1 = (s1 | s2);
-  s1 = (s1 & s2);
-  s1 = (s1 ^ s2);
-  v1 = (v1 | v2);
-  v1 = (v1 & v2);
-  v1 = (v1 ^ v2);
-}
-
-void bitwise_u32() {
-  uint s1 = 0u;
-  uint s2 = 0u;
-  uint3 v1 = 0u;
-  uint3 v2 = 0u;
-  s1 = (s1 | s2);
-  s1 = (s1 & s2);
-  s1 = (s1 ^ s2);
-  v1 = (v1 | v2);
-  v1 = (v1 & v2);
-  v1 = (v1 ^ v2);
-}
-
-void vector_scalar_f32() {
-  float3 v = 0.0f;
-  float s = 0.0f;
-  float3 r = 0.0f;
-  r = (v + s);
-  r = (v - s);
-  r = (v * s);
-  r = (v / s);
-}
-
-void vector_scalar_i32() {
-  int3 v = 0;
-  int s = 0;
-  int3 r = 0;
-  r = (v + s);
-  r = (v - s);
-  r = (v * s);
-  r = (v / s);
-  r = (v % s);
-}
-
-void vector_scalar_u32() {
-  uint3 v = 0u;
-  uint s = 0u;
-  uint3 r = 0u;
-  r = (v + s);
-  r = (v - s);
-  r = (v * s);
-  r = (v / s);
-  r = (v % s);
-}
-
-void scalar_vector_f32() {
-  float3 v = 0.0f;
-  float s = 0.0f;
-  float3 r = 0.0f;
-  r = (s + v);
-  r = (s - v);
-  r = (s * v);
-  r = (s / v);
-}
-
-void scalar_vector_i32() {
-  int3 v = 0;
-  int s = 0;
-  int3 r = 0;
-  r = (s + v);
-  r = (s - v);
-  r = (s * v);
-  r = (s / v);
-  r = (s % v);
-}
-
-void scalar_vector_u32() {
-  uint3 v = 0u;
-  uint s = 0u;
-  uint3 r = 0u;
-  r = (s + v);
-  r = (s - v);
-  r = (s * v);
-  r = (s / v);
-  r = (s % v);
-}
-
-void matrix_matrix_f32() {
-  float3x4 m34 = float3x4(0.0f);
-  float4x3 m43 = float4x3(0.0f);
-  float3x3 m33 = float3x3(0.0f);
-  float4x4 m44 = float4x4(0.0f);
-  m34 = (m34 + m34);
-  m34 = (m34 - m34);
-  m33 = (m43 * m34);
-  m44 = (m34 * m43);
-}
-
-fragment tint_symbol_1 tint_symbol() {
-  tint_symbol_1 const tint_symbol_2 = {.value=float4(0.0f, 0.0f, 0.0f, 0.0f)};
-  return tint_symbol_2;
-}
-
diff --git a/test/expressions/binary_expressions.wgsl.expected.spvasm b/test/expressions/binary_expressions.wgsl.expected.spvasm
deleted file mode 100644
index 9ec4c3e..0000000
--- a/test/expressions/binary_expressions.wgsl.expected.spvasm
+++ /dev/null
@@ -1,415 +0,0 @@
-; SPIR-V
-; Version: 1.3
-; Generator: Google Tint Compiler; 0
-; Bound: 298
-; Schema: 0
-               OpCapability Shader
-               OpMemoryModel Logical GLSL450
-               OpEntryPoint Fragment %main "main" %tint_symbol_1
-               OpExecutionMode %main OriginUpperLeft
-               OpName %tint_symbol_1 "tint_symbol_1"
-               OpName %bitwise_i32 "bitwise_i32"
-               OpName %s1 "s1"
-               OpName %s2 "s2"
-               OpName %v1 "v1"
-               OpName %v2 "v2"
-               OpName %bitwise_u32 "bitwise_u32"
-               OpName %s1_0 "s1"
-               OpName %s2_0 "s2"
-               OpName %v1_0 "v1"
-               OpName %v2_0 "v2"
-               OpName %vector_scalar_f32 "vector_scalar_f32"
-               OpName %v "v"
-               OpName %s "s"
-               OpName %r "r"
-               OpName %vector_scalar_i32 "vector_scalar_i32"
-               OpName %v_0 "v"
-               OpName %s_0 "s"
-               OpName %r_0 "r"
-               OpName %vector_scalar_u32 "vector_scalar_u32"
-               OpName %v_1 "v"
-               OpName %s_1 "s"
-               OpName %r_1 "r"
-               OpName %scalar_vector_f32 "scalar_vector_f32"
-               OpName %v_2 "v"
-               OpName %s_2 "s"
-               OpName %r_2 "r"
-               OpName %scalar_vector_i32 "scalar_vector_i32"
-               OpName %v_3 "v"
-               OpName %s_3 "s"
-               OpName %r_3 "r"
-               OpName %scalar_vector_u32 "scalar_vector_u32"
-               OpName %v_4 "v"
-               OpName %s_4 "s"
-               OpName %r_4 "r"
-               OpName %matrix_matrix_f32 "matrix_matrix_f32"
-               OpName %m34 "m34"
-               OpName %m43 "m43"
-               OpName %m33 "m33"
-               OpName %m44 "m44"
-               OpName %tint_symbol_2 "tint_symbol_2"
-               OpName %tint_symbol "tint_symbol"
-               OpName %main "main"
-               OpDecorate %tint_symbol_1 Location 0
-      %float = OpTypeFloat 32
-    %v4float = OpTypeVector %float 4
-%_ptr_Output_v4float = OpTypePointer Output %v4float
-          %5 = OpConstantNull %v4float
-%tint_symbol_1 = OpVariable %_ptr_Output_v4float Output %5
-       %void = OpTypeVoid
-          %6 = OpTypeFunction %void
-        %int = OpTypeInt 32 1
-%_ptr_Function_int = OpTypePointer Function %int
-         %13 = OpConstantNull %int
-      %v3int = OpTypeVector %int 3
-%_ptr_Function_v3int = OpTypePointer Function %v3int
-         %18 = OpConstantNull %v3int
-       %uint = OpTypeInt 32 0
-%_ptr_Function_uint = OpTypePointer Function %uint
-         %43 = OpConstantNull %uint
-     %v3uint = OpTypeVector %uint 3
-%_ptr_Function_v3uint = OpTypePointer Function %v3uint
-         %48 = OpConstantNull %v3uint
-    %v3float = OpTypeVector %float 3
-%_ptr_Function_v3float = OpTypePointer Function %v3float
-         %73 = OpConstantNull %v3float
-%_ptr_Function_float = OpTypePointer Function %float
-         %76 = OpConstantNull %float
-%mat3v4float = OpTypeMatrix %v4float 3
-%_ptr_Function_mat3v4float = OpTypePointer Function %mat3v4float
-        %244 = OpConstantNull %mat3v4float
-%mat4v3float = OpTypeMatrix %v3float 4
-%_ptr_Function_mat4v3float = OpTypePointer Function %mat4v3float
-        %248 = OpConstantNull %mat4v3float
-%mat3v3float = OpTypeMatrix %v3float 3
-%_ptr_Function_mat3v3float = OpTypePointer Function %mat3v3float
-        %252 = OpConstantNull %mat3v3float
-%mat4v4float = OpTypeMatrix %v4float 4
-%_ptr_Function_mat4v4float = OpTypePointer Function %mat4v4float
-        %256 = OpConstantNull %mat4v4float
-        %289 = OpTypeFunction %void %v4float
-    %float_0 = OpConstant %float 0
-        %297 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
-%bitwise_i32 = OpFunction %void None %6
-          %9 = OpLabel
-         %s1 = OpVariable %_ptr_Function_int Function %13
-         %s2 = OpVariable %_ptr_Function_int Function %13
-         %v1 = OpVariable %_ptr_Function_v3int Function %18
-         %v2 = OpVariable %_ptr_Function_v3int Function %18
-         %20 = OpLoad %int %s1
-         %21 = OpLoad %int %s2
-         %22 = OpBitwiseOr %int %20 %21
-               OpStore %s1 %22
-         %23 = OpLoad %int %s1
-         %24 = OpLoad %int %s2
-         %25 = OpBitwiseAnd %int %23 %24
-               OpStore %s1 %25
-         %26 = OpLoad %int %s1
-         %27 = OpLoad %int %s2
-         %28 = OpBitwiseXor %int %26 %27
-               OpStore %s1 %28
-         %29 = OpLoad %v3int %v1
-         %30 = OpLoad %v3int %v2
-         %31 = OpBitwiseOr %v3int %29 %30
-               OpStore %v1 %31
-         %32 = OpLoad %v3int %v1
-         %33 = OpLoad %v3int %v2
-         %34 = OpBitwiseAnd %v3int %32 %33
-               OpStore %v1 %34
-         %35 = OpLoad %v3int %v1
-         %36 = OpLoad %v3int %v2
-         %37 = OpBitwiseXor %v3int %35 %36
-               OpStore %v1 %37
-               OpReturn
-               OpFunctionEnd
-%bitwise_u32 = OpFunction %void None %6
-         %39 = OpLabel
-       %s1_0 = OpVariable %_ptr_Function_uint Function %43
-       %s2_0 = OpVariable %_ptr_Function_uint Function %43
-       %v1_0 = OpVariable %_ptr_Function_v3uint Function %48
-       %v2_0 = OpVariable %_ptr_Function_v3uint Function %48
-         %50 = OpLoad %uint %s1_0
-         %51 = OpLoad %uint %s2_0
-         %52 = OpBitwiseOr %uint %50 %51
-               OpStore %s1_0 %52
-         %53 = OpLoad %uint %s1_0
-         %54 = OpLoad %uint %s2_0
-         %55 = OpBitwiseAnd %uint %53 %54
-               OpStore %s1_0 %55
-         %56 = OpLoad %uint %s1_0
-         %57 = OpLoad %uint %s2_0
-         %58 = OpBitwiseXor %uint %56 %57
-               OpStore %s1_0 %58
-         %59 = OpLoad %v3uint %v1_0
-         %60 = OpLoad %v3uint %v2_0
-         %61 = OpBitwiseOr %v3uint %59 %60
-               OpStore %v1_0 %61
-         %62 = OpLoad %v3uint %v1_0
-         %63 = OpLoad %v3uint %v2_0
-         %64 = OpBitwiseAnd %v3uint %62 %63
-               OpStore %v1_0 %64
-         %65 = OpLoad %v3uint %v1_0
-         %66 = OpLoad %v3uint %v2_0
-         %67 = OpBitwiseXor %v3uint %65 %66
-               OpStore %v1_0 %67
-               OpReturn
-               OpFunctionEnd
-%vector_scalar_f32 = OpFunction %void None %6
-         %69 = OpLabel
-          %v = OpVariable %_ptr_Function_v3float Function %73
-          %s = OpVariable %_ptr_Function_float Function %76
-          %r = OpVariable %_ptr_Function_v3float Function %73
-         %81 = OpVariable %_ptr_Function_v3float Function %73
-         %86 = OpVariable %_ptr_Function_v3float Function %73
-         %94 = OpVariable %_ptr_Function_v3float Function %73
-         %78 = OpLoad %v3float %v
-         %79 = OpLoad %float %s
-         %82 = OpCompositeConstruct %v3float %79 %79 %79
-         %80 = OpFAdd %v3float %78 %82
-               OpStore %r %80
-         %83 = OpLoad %v3float %v
-         %84 = OpLoad %float %s
-         %87 = OpCompositeConstruct %v3float %84 %84 %84
-         %85 = OpFSub %v3float %83 %87
-               OpStore %r %85
-         %88 = OpLoad %v3float %v
-         %89 = OpLoad %float %s
-         %90 = OpVectorTimesScalar %v3float %88 %89
-               OpStore %r %90
-         %91 = OpLoad %v3float %v
-         %92 = OpLoad %float %s
-         %95 = OpCompositeConstruct %v3float %92 %92 %92
-         %93 = OpFDiv %v3float %91 %95
-               OpStore %r %93
-               OpReturn
-               OpFunctionEnd
-%vector_scalar_i32 = OpFunction %void None %6
-         %97 = OpLabel
-        %v_0 = OpVariable %_ptr_Function_v3int Function %18
-        %s_0 = OpVariable %_ptr_Function_int Function %13
-        %r_0 = OpVariable %_ptr_Function_v3int Function %18
-        %104 = OpVariable %_ptr_Function_v3int Function %18
-        %109 = OpVariable %_ptr_Function_v3int Function %18
-        %114 = OpVariable %_ptr_Function_v3int Function %18
-        %119 = OpVariable %_ptr_Function_v3int Function %18
-        %124 = OpVariable %_ptr_Function_v3int Function %18
-        %101 = OpLoad %v3int %v_0
-        %102 = OpLoad %int %s_0
-        %105 = OpCompositeConstruct %v3int %102 %102 %102
-        %103 = OpIAdd %v3int %101 %105
-               OpStore %r_0 %103
-        %106 = OpLoad %v3int %v_0
-        %107 = OpLoad %int %s_0
-        %110 = OpCompositeConstruct %v3int %107 %107 %107
-        %108 = OpISub %v3int %106 %110
-               OpStore %r_0 %108
-        %111 = OpLoad %v3int %v_0
-        %112 = OpLoad %int %s_0
-        %115 = OpCompositeConstruct %v3int %112 %112 %112
-        %113 = OpIMul %v3int %111 %115
-               OpStore %r_0 %113
-        %116 = OpLoad %v3int %v_0
-        %117 = OpLoad %int %s_0
-        %120 = OpCompositeConstruct %v3int %117 %117 %117
-        %118 = OpSDiv %v3int %116 %120
-               OpStore %r_0 %118
-        %121 = OpLoad %v3int %v_0
-        %122 = OpLoad %int %s_0
-        %125 = OpCompositeConstruct %v3int %122 %122 %122
-        %123 = OpSMod %v3int %121 %125
-               OpStore %r_0 %123
-               OpReturn
-               OpFunctionEnd
-%vector_scalar_u32 = OpFunction %void None %6
-        %127 = OpLabel
-        %v_1 = OpVariable %_ptr_Function_v3uint Function %48
-        %s_1 = OpVariable %_ptr_Function_uint Function %43
-        %r_1 = OpVariable %_ptr_Function_v3uint Function %48
-        %134 = OpVariable %_ptr_Function_v3uint Function %48
-        %139 = OpVariable %_ptr_Function_v3uint Function %48
-        %144 = OpVariable %_ptr_Function_v3uint Function %48
-        %149 = OpVariable %_ptr_Function_v3uint Function %48
-        %154 = OpVariable %_ptr_Function_v3uint Function %48
-        %131 = OpLoad %v3uint %v_1
-        %132 = OpLoad %uint %s_1
-        %135 = OpCompositeConstruct %v3uint %132 %132 %132
-        %133 = OpIAdd %v3uint %131 %135
-               OpStore %r_1 %133
-        %136 = OpLoad %v3uint %v_1
-        %137 = OpLoad %uint %s_1
-        %140 = OpCompositeConstruct %v3uint %137 %137 %137
-        %138 = OpISub %v3uint %136 %140
-               OpStore %r_1 %138
-        %141 = OpLoad %v3uint %v_1
-        %142 = OpLoad %uint %s_1
-        %145 = OpCompositeConstruct %v3uint %142 %142 %142
-        %143 = OpIMul %v3uint %141 %145
-               OpStore %r_1 %143
-        %146 = OpLoad %v3uint %v_1
-        %147 = OpLoad %uint %s_1
-        %150 = OpCompositeConstruct %v3uint %147 %147 %147
-        %148 = OpUDiv %v3uint %146 %150
-               OpStore %r_1 %148
-        %151 = OpLoad %v3uint %v_1
-        %152 = OpLoad %uint %s_1
-        %155 = OpCompositeConstruct %v3uint %152 %152 %152
-        %153 = OpUMod %v3uint %151 %155
-               OpStore %r_1 %153
-               OpReturn
-               OpFunctionEnd
-%scalar_vector_f32 = OpFunction %void None %6
-        %157 = OpLabel
-        %v_2 = OpVariable %_ptr_Function_v3float Function %73
-        %s_2 = OpVariable %_ptr_Function_float Function %76
-        %r_2 = OpVariable %_ptr_Function_v3float Function %73
-        %164 = OpVariable %_ptr_Function_v3float Function %73
-        %169 = OpVariable %_ptr_Function_v3float Function %73
-        %177 = OpVariable %_ptr_Function_v3float Function %73
-        %161 = OpLoad %float %s_2
-        %162 = OpLoad %v3float %v_2
-        %165 = OpCompositeConstruct %v3float %161 %161 %161
-        %163 = OpFAdd %v3float %165 %162
-               OpStore %r_2 %163
-        %166 = OpLoad %float %s_2
-        %167 = OpLoad %v3float %v_2
-        %170 = OpCompositeConstruct %v3float %166 %166 %166
-        %168 = OpFSub %v3float %170 %167
-               OpStore %r_2 %168
-        %171 = OpLoad %float %s_2
-        %172 = OpLoad %v3float %v_2
-        %173 = OpVectorTimesScalar %v3float %172 %171
-               OpStore %r_2 %173
-        %174 = OpLoad %float %s_2
-        %175 = OpLoad %v3float %v_2
-        %178 = OpCompositeConstruct %v3float %174 %174 %174
-        %176 = OpFDiv %v3float %178 %175
-               OpStore %r_2 %176
-               OpReturn
-               OpFunctionEnd
-%scalar_vector_i32 = OpFunction %void None %6
-        %180 = OpLabel
-        %v_3 = OpVariable %_ptr_Function_v3int Function %18
-        %s_3 = OpVariable %_ptr_Function_int Function %13
-        %r_3 = OpVariable %_ptr_Function_v3int Function %18
-        %187 = OpVariable %_ptr_Function_v3int Function %18
-        %192 = OpVariable %_ptr_Function_v3int Function %18
-        %197 = OpVariable %_ptr_Function_v3int Function %18
-        %202 = OpVariable %_ptr_Function_v3int Function %18
-        %207 = OpVariable %_ptr_Function_v3int Function %18
-        %184 = OpLoad %int %s_3
-        %185 = OpLoad %v3int %v_3
-        %188 = OpCompositeConstruct %v3int %184 %184 %184
-        %186 = OpIAdd %v3int %188 %185
-               OpStore %r_3 %186
-        %189 = OpLoad %int %s_3
-        %190 = OpLoad %v3int %v_3
-        %193 = OpCompositeConstruct %v3int %189 %189 %189
-        %191 = OpISub %v3int %193 %190
-               OpStore %r_3 %191
-        %194 = OpLoad %int %s_3
-        %195 = OpLoad %v3int %v_3
-        %198 = OpCompositeConstruct %v3int %194 %194 %194
-        %196 = OpIMul %v3int %198 %195
-               OpStore %r_3 %196
-        %199 = OpLoad %int %s_3
-        %200 = OpLoad %v3int %v_3
-        %203 = OpCompositeConstruct %v3int %199 %199 %199
-        %201 = OpSDiv %v3int %203 %200
-               OpStore %r_3 %201
-        %204 = OpLoad %int %s_3
-        %205 = OpLoad %v3int %v_3
-        %208 = OpCompositeConstruct %v3int %204 %204 %204
-        %206 = OpSMod %v3int %208 %205
-               OpStore %r_3 %206
-               OpReturn
-               OpFunctionEnd
-%scalar_vector_u32 = OpFunction %void None %6
-        %210 = OpLabel
-        %v_4 = OpVariable %_ptr_Function_v3uint Function %48
-        %s_4 = OpVariable %_ptr_Function_uint Function %43
-        %r_4 = OpVariable %_ptr_Function_v3uint Function %48
-        %217 = OpVariable %_ptr_Function_v3uint Function %48
-        %222 = OpVariable %_ptr_Function_v3uint Function %48
-        %227 = OpVariable %_ptr_Function_v3uint Function %48
-        %232 = OpVariable %_ptr_Function_v3uint Function %48
-        %237 = OpVariable %_ptr_Function_v3uint Function %48
-        %214 = OpLoad %uint %s_4
-        %215 = OpLoad %v3uint %v_4
-        %218 = OpCompositeConstruct %v3uint %214 %214 %214
-        %216 = OpIAdd %v3uint %218 %215
-               OpStore %r_4 %216
-        %219 = OpLoad %uint %s_4
-        %220 = OpLoad %v3uint %v_4
-        %223 = OpCompositeConstruct %v3uint %219 %219 %219
-        %221 = OpISub %v3uint %223 %220
-               OpStore %r_4 %221
-        %224 = OpLoad %uint %s_4
-        %225 = OpLoad %v3uint %v_4
-        %228 = OpCompositeConstruct %v3uint %224 %224 %224
-        %226 = OpIMul %v3uint %228 %225
-               OpStore %r_4 %226
-        %229 = OpLoad %uint %s_4
-        %230 = OpLoad %v3uint %v_4
-        %233 = OpCompositeConstruct %v3uint %229 %229 %229
-        %231 = OpUDiv %v3uint %233 %230
-               OpStore %r_4 %231
-        %234 = OpLoad %uint %s_4
-        %235 = OpLoad %v3uint %v_4
-        %238 = OpCompositeConstruct %v3uint %234 %234 %234
-        %236 = OpUMod %v3uint %238 %235
-               OpStore %r_4 %236
-               OpReturn
-               OpFunctionEnd
-%matrix_matrix_f32 = OpFunction %void None %6
-        %240 = OpLabel
-        %m34 = OpVariable %_ptr_Function_mat3v4float Function %244
-        %m43 = OpVariable %_ptr_Function_mat4v3float Function %248
-        %m33 = OpVariable %_ptr_Function_mat3v3float Function %252
-        %m44 = OpVariable %_ptr_Function_mat4v4float Function %256
-        %257 = OpLoad %mat3v4float %m34
-        %258 = OpLoad %mat3v4float %m34
-        %260 = OpCompositeExtract %v4float %257 0
-        %261 = OpCompositeExtract %v4float %258 0
-        %262 = OpFAdd %v4float %260 %261
-        %263 = OpCompositeExtract %v4float %257 1
-        %264 = OpCompositeExtract %v4float %258 1
-        %265 = OpFAdd %v4float %263 %264
-        %266 = OpCompositeExtract %v4float %257 2
-        %267 = OpCompositeExtract %v4float %258 2
-        %268 = OpFAdd %v4float %266 %267
-        %269 = OpCompositeConstruct %mat3v4float %262 %265 %268
-               OpStore %m34 %269
-        %270 = OpLoad %mat3v4float %m34
-        %271 = OpLoad %mat3v4float %m34
-        %273 = OpCompositeExtract %v4float %270 0
-        %274 = OpCompositeExtract %v4float %271 0
-        %275 = OpFSub %v4float %273 %274
-        %276 = OpCompositeExtract %v4float %270 1
-        %277 = OpCompositeExtract %v4float %271 1
-        %278 = OpFSub %v4float %276 %277
-        %279 = OpCompositeExtract %v4float %270 2
-        %280 = OpCompositeExtract %v4float %271 2
-        %281 = OpFSub %v4float %279 %280
-        %282 = OpCompositeConstruct %mat3v4float %275 %278 %281
-               OpStore %m34 %282
-        %283 = OpLoad %mat4v3float %m43
-        %284 = OpLoad %mat3v4float %m34
-        %285 = OpMatrixTimesMatrix %mat3v3float %283 %284
-               OpStore %m33 %285
-        %286 = OpLoad %mat3v4float %m34
-        %287 = OpLoad %mat4v3float %m43
-        %288 = OpMatrixTimesMatrix %mat4v4float %286 %287
-               OpStore %m44 %288
-               OpReturn
-               OpFunctionEnd
-%tint_symbol_2 = OpFunction %void None %289
-%tint_symbol = OpFunctionParameter %v4float
-        %292 = OpLabel
-               OpStore %tint_symbol_1 %tint_symbol
-               OpReturn
-               OpFunctionEnd
-       %main = OpFunction %void None %6
-        %294 = OpLabel
-        %295 = OpFunctionCall %void %tint_symbol_2 %297
-               OpReturn
-               OpFunctionEnd
diff --git a/test/expressions/binary_expressions.wgsl.expected.wgsl b/test/expressions/binary_expressions.wgsl.expected.wgsl
deleted file mode 100644
index d0e3da1..0000000
--- a/test/expressions/binary_expressions.wgsl.expected.wgsl
+++ /dev/null
@@ -1,105 +0,0 @@
-fn bitwise_i32() {
-  var s1 : i32;
-  var s2 : i32;
-  var v1 : vec3<i32>;
-  var v2 : vec3<i32>;
-  s1 = (s1 | s2);
-  s1 = (s1 & s2);
-  s1 = (s1 ^ s2);
-  v1 = (v1 | v2);
-  v1 = (v1 & v2);
-  v1 = (v1 ^ v2);
-}
-
-fn bitwise_u32() {
-  var s1 : u32;
-  var s2 : u32;
-  var v1 : vec3<u32>;
-  var v2 : vec3<u32>;
-  s1 = (s1 | s2);
-  s1 = (s1 & s2);
-  s1 = (s1 ^ s2);
-  v1 = (v1 | v2);
-  v1 = (v1 & v2);
-  v1 = (v1 ^ v2);
-}
-
-fn vector_scalar_f32() {
-  var v : vec3<f32>;
-  var s : f32;
-  var r : vec3<f32>;
-  r = (v + s);
-  r = (v - s);
-  r = (v * s);
-  r = (v / s);
-}
-
-fn vector_scalar_i32() {
-  var v : vec3<i32>;
-  var s : i32;
-  var r : vec3<i32>;
-  r = (v + s);
-  r = (v - s);
-  r = (v * s);
-  r = (v / s);
-  r = (v % s);
-}
-
-fn vector_scalar_u32() {
-  var v : vec3<u32>;
-  var s : u32;
-  var r : vec3<u32>;
-  r = (v + s);
-  r = (v - s);
-  r = (v * s);
-  r = (v / s);
-  r = (v % s);
-}
-
-fn scalar_vector_f32() {
-  var v : vec3<f32>;
-  var s : f32;
-  var r : vec3<f32>;
-  r = (s + v);
-  r = (s - v);
-  r = (s * v);
-  r = (s / v);
-}
-
-fn scalar_vector_i32() {
-  var v : vec3<i32>;
-  var s : i32;
-  var r : vec3<i32>;
-  r = (s + v);
-  r = (s - v);
-  r = (s * v);
-  r = (s / v);
-  r = (s % v);
-}
-
-fn scalar_vector_u32() {
-  var v : vec3<u32>;
-  var s : u32;
-  var r : vec3<u32>;
-  r = (s + v);
-  r = (s - v);
-  r = (s * v);
-  r = (s / v);
-  r = (s % v);
-}
-
-fn matrix_matrix_f32() {
-  var m34 : mat3x4<f32>;
-  var m43 : mat4x3<f32>;
-  var m33 : mat3x3<f32>;
-  var m44 : mat4x4<f32>;
-  m34 = (m34 + m34);
-  m34 = (m34 - m34);
-  m33 = (m43 * m34);
-  m44 = (m34 * m43);
-}
-
-[[stage(fragment)]]
-fn main() -> [[location(0)]] vec4<f32> {
-  return vec4<f32>(0.0, 0.0, 0.0, 0.0);
-}