[glsl][ir] Polyfill float modulo

GLSL does not support float `%`. This CL adds the needed polyfill.

Bug: 42251044
Change-Id: I27a601b31252f235c9b879487711c9795af699b1
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/208354
Reviewed-by: James Price <jrprice@google.com>
Commit-Queue: dan sinclair <dsinclair@chromium.org>
diff --git a/src/tint/lang/glsl/writer/binary_test.cc b/src/tint/lang/glsl/writer/binary_test.cc
index e1a28ec..6240fab 100644
--- a/src/tint/lang/glsl/writer/binary_test.cc
+++ b/src/tint/lang/glsl/writer/binary_test.cc
@@ -214,14 +214,30 @@
                     BinaryData{"greaterThan", core::BinaryOp::kGreaterThan},
                     BinaryData{"greaterThanEqual", core::BinaryOp::kGreaterThanEqual}));
 
-// TODO(dsinclair): Test int_div_mod polyfil
-TEST_F(GlslWriterTest, DISABLED_Binary_Int_Div_Polyfill) {}
+TEST_F(GlslWriterTest, Binary_Float_Modulo) {
+    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kCompute);
+    func->SetWorkgroupSize(1, 1, 1);
+    b.Append(func->Block(), [&] {
+        auto* l = b.Let("left", b.Splat(ty.vec2<f32>(), 1_f));
+        auto* r = b.Let("right", b.Splat(ty.vec2<f32>(), 2_f));
+        auto* bin = b.Modulo(ty.vec2<f32>(), l, r);
+        b.Let("val", bin);
+        b.Return(func);
+    });
 
-// TODO(dsinclair): Test int_div_mod polyfil
-TEST_F(GlslWriterTest, DISABLED_Binary_Int_Mod_Polyfill) {}
-
-// TODO(dsinclair): Float Modulo
-TEST_F(GlslWriterTest, DISABLED_Binary_Float_Modulo) {}
+    ASSERT_TRUE(Generate()) << err_ << output_.glsl;
+    EXPECT_EQ(output_.glsl, GlslHeader() + R"(
+vec2 tint_float_modulo(vec2 x, vec2 y) {
+  return (x - (y * trunc((x / y))));
+}
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  vec2 left = vec2(1.0f);
+  vec2 right = vec2(2.0f);
+  vec2 val = tint_float_modulo(left, right);
+}
+)");
+}
 
 }  // namespace
 }  // namespace tint::glsl::writer
diff --git a/src/tint/lang/glsl/writer/raise/binary_polyfill.cc b/src/tint/lang/glsl/writer/raise/binary_polyfill.cc
index a0cb584..b538f1a 100644
--- a/src/tint/lang/glsl/writer/raise/binary_polyfill.cc
+++ b/src/tint/lang/glsl/writer/raise/binary_polyfill.cc
@@ -51,6 +51,9 @@
     /// The type manager.
     core::type::Manager& ty{ir.Types()};
 
+    /// Float modulo polyfills
+    Hashmap<const core::type::Type*, core::ir::Function*, 4> float_modulo_funcs_{};
+
     /// Process the module.
     void Process() {
         // Find the binary instructions that need replacing.
@@ -65,6 +68,12 @@
                         }
                         break;
                     }
+                    case core::BinaryOp::kModulo: {
+                        if (binary->LHS()->Type()->IsFloatScalarOrVector()) {
+                            binary_worklist.Push(binary);
+                        }
+                        break;
+                    }
                     case core::BinaryOp::kEqual:
                     case core::BinaryOp::kNotEqual:
                     case core::BinaryOp::kLessThan:
@@ -89,6 +98,9 @@
                 case core::BinaryOp::kOr:
                     BitwiseBoolean(binary);
                     break;
+                case core::BinaryOp::kModulo:
+                    FloatModulo(binary);
+                    break;
                 case core::BinaryOp::kEqual:
                 case core::BinaryOp::kNotEqual:
                 case core::BinaryOp::kLessThan:
@@ -155,6 +167,50 @@
         });
         binary->Destroy();
     }
+
+    core::ir::Function* CreateFloatModuloPolyfill(const core::type::Type* type) {
+        return float_modulo_funcs_.GetOrAdd(type, [&]() -> core::ir::Function* {
+            auto* f = b.Function("tint_float_modulo", type);
+            auto* x = b.FunctionParam("x", type);
+            auto* y = b.FunctionParam("y", type);
+            f->SetParams({x, y});
+
+            b.Append(f->Block(), [&] {
+                core::ir::Value* ret = nullptr;
+
+                ret = b.Divide(type, x, y)->Result(0);
+                ret = b.Call(type, core::BuiltinFn::kTrunc, ret)->Result(0);
+                ret = b.Multiply(type, y, ret)->Result(0);
+                ret = b.Subtract(type, x, ret)->Result(0);
+                b.Return(f, ret);
+            });
+            return f;
+        });
+    }
+
+    void FloatModulo(core::ir::Binary* binary) {
+        b.InsertBefore(binary, [&] {
+            auto* lhs = binary->LHS();
+            auto* rhs = binary->RHS();
+
+            auto* res_ty = binary->Result(0)->Type();
+
+            // The WGSL modulo either takes two of the same types, which would then match the
+            // result type, or a mixed scalar/vector combination. The vector type would then match
+            // the result type. If we have a mixed scalar/vector, construct a vector of the scalar
+            // type which makes the polyfill simpler.
+            if (lhs->Type() != res_ty) {
+                lhs = b.Construct(res_ty, lhs)->Result(0);
+            }
+            if (rhs->Type() != res_ty) {
+                rhs = b.Construct(res_ty, rhs)->Result(0);
+            }
+
+            auto* func = CreateFloatModuloPolyfill(res_ty);
+            b.CallWithResult(binary->DetachResult(), func, lhs, rhs);
+        });
+        binary->Destroy();
+    }
 };
 
 }  // namespace
diff --git a/src/tint/lang/glsl/writer/raise/binary_polyfill_test.cc b/src/tint/lang/glsl/writer/raise/binary_polyfill_test.cc
index 57ee59e..5d4c770 100644
--- a/src/tint/lang/glsl/writer/raise/binary_polyfill_test.cc
+++ b/src/tint/lang/glsl/writer/raise/binary_polyfill_test.cc
@@ -457,5 +457,150 @@
     EXPECT_EQ(expect, str());
 }
 
+TEST_F(GlslWriter_BinaryPolyfillTest, FloatModF32) {
+    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    b.Append(func->Block(), [&] {
+        auto* l = b.Let("left", b.Splat(ty.vec2<f32>(), 1_f));
+        auto* r = b.Let("right", b.Splat(ty.vec2<f32>(), 2_f));
+        auto* bin = b.Modulo(ty.vec2<f32>(), l, r);
+        b.Let("val", bin);
+        b.Return(func);
+    });
+
+    auto* src = R"(
+%foo = @fragment func():void {
+  $B1: {
+    %left:vec2<f32> = let vec2<f32>(1.0f)
+    %right:vec2<f32> = let vec2<f32>(2.0f)
+    %4:vec2<f32> = mod %left, %right
+    %val:vec2<f32> = let %4
+    ret
+  }
+}
+)";
+    EXPECT_EQ(src, str());
+
+    auto* expect = R"(
+%foo = @fragment func():void {
+  $B1: {
+    %left:vec2<f32> = let vec2<f32>(1.0f)
+    %right:vec2<f32> = let vec2<f32>(2.0f)
+    %4:vec2<f32> = call %tint_float_modulo, %left, %right
+    %val:vec2<f32> = let %4
+    ret
+  }
+}
+%tint_float_modulo = func(%x:vec2<f32>, %y:vec2<f32>):vec2<f32> {
+  $B2: {
+    %9:vec2<f32> = div %x, %y
+    %10:vec2<f32> = trunc %9
+    %11:vec2<f32> = mul %y, %10
+    %12:vec2<f32> = sub %x, %11
+    ret %12
+  }
+}
+)";
+
+    Run(BinaryPolyfill);
+    EXPECT_EQ(expect, str());
+}
+
+TEST_F(GlslWriter_BinaryPolyfillTest, FloatModMixedF32) {
+    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    b.Append(func->Block(), [&] {
+        auto* l = b.Let("left", 1_f);
+        auto* r = b.Let("right", b.Splat(ty.vec2<f32>(), 2_f));
+        auto* bin = b.Modulo(ty.vec2<f32>(), l, r);
+        b.Let("val", bin);
+        b.Return(func);
+    });
+
+    auto* src = R"(
+%foo = @fragment func():void {
+  $B1: {
+    %left:f32 = let 1.0f
+    %right:vec2<f32> = let vec2<f32>(2.0f)
+    %4:vec2<f32> = mod %left, %right
+    %val:vec2<f32> = let %4
+    ret
+  }
+}
+)";
+    EXPECT_EQ(src, str());
+
+    auto* expect = R"(
+%foo = @fragment func():void {
+  $B1: {
+    %left:f32 = let 1.0f
+    %right:vec2<f32> = let vec2<f32>(2.0f)
+    %4:vec2<f32> = construct %left
+    %5:vec2<f32> = call %tint_float_modulo, %4, %right
+    %val:vec2<f32> = let %5
+    ret
+  }
+}
+%tint_float_modulo = func(%x:vec2<f32>, %y:vec2<f32>):vec2<f32> {
+  $B2: {
+    %10:vec2<f32> = div %x, %y
+    %11:vec2<f32> = trunc %10
+    %12:vec2<f32> = mul %y, %11
+    %13:vec2<f32> = sub %x, %12
+    ret %13
+  }
+}
+)";
+
+    Run(BinaryPolyfill);
+    EXPECT_EQ(expect, str());
+}
+
+TEST_F(GlslWriter_BinaryPolyfillTest, FloatModF16) {
+    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    b.Append(func->Block(), [&] {
+        auto* l = b.Let("left", b.Splat(ty.vec2<f16>(), 1_h));
+        auto* r = b.Let("right", b.Splat(ty.vec2<f16>(), 2_h));
+        auto* bin = b.Modulo(ty.vec2<f16>(), l, r);
+        b.Let("val", bin);
+        b.Return(func);
+    });
+
+    auto* src = R"(
+%foo = @fragment func():void {
+  $B1: {
+    %left:vec2<f16> = let vec2<f16>(1.0h)
+    %right:vec2<f16> = let vec2<f16>(2.0h)
+    %4:vec2<f16> = mod %left, %right
+    %val:vec2<f16> = let %4
+    ret
+  }
+}
+)";
+    EXPECT_EQ(src, str());
+
+    auto* expect = R"(
+%foo = @fragment func():void {
+  $B1: {
+    %left:vec2<f16> = let vec2<f16>(1.0h)
+    %right:vec2<f16> = let vec2<f16>(2.0h)
+    %4:vec2<f16> = call %tint_float_modulo, %left, %right
+    %val:vec2<f16> = let %4
+    ret
+  }
+}
+%tint_float_modulo = func(%x:vec2<f16>, %y:vec2<f16>):vec2<f16> {
+  $B2: {
+    %9:vec2<f16> = div %x, %y
+    %10:vec2<f16> = trunc %9
+    %11:vec2<f16> = mul %y, %10
+    %12:vec2<f16> = sub %x, %11
+    ret %12
+  }
+}
+)";
+
+    Run(BinaryPolyfill);
+    EXPECT_EQ(expect, str());
+}
+
 }  // namespace
 }  // namespace tint::glsl::writer::raise
diff --git a/test/tint/bug/chromium/1434271.wgsl.expected.ir.glsl b/test/tint/bug/chromium/1434271.wgsl.expected.ir.glsl
index 10a638b..2f6e16c 100644
--- a/test/tint/bug/chromium/1434271.wgsl.expected.ir.glsl
+++ b/test/tint/bug/chromium/1434271.wgsl.expected.ir.glsl
@@ -1,5 +1,3 @@
-SKIP: FAILED
-
 #version 310 es
 #extension GL_AMD_gpu_shader_half_float: require
 
@@ -131,12 +129,45 @@
 void main() {
   simulate_inner(gl_GlobalInvocationID);
 }
-<dawn>/src/tint/lang/glsl/writer/printer/printer.cc:1451 internal compiler error: TINT_UNREACHABLE unhandled core builtin: textureStore
-********************************************************************
-*  The tint shader compiler has encountered an unexpected error.   *
-*                                                                  *
-*  Please help us fix this issue by submitting a bug report at     *
-*  crbug.com/tint with the source program that triggered the bug.  *
-********************************************************************
+#version 310 es
 
-tint executable returned error: signal: trace/BPT trap
+
+struct UBO {
+  uint width;
+};
+
+layout(binding = 3, std140)
+uniform tint_symbol_1_1_ubo {
+  UBO tint_symbol;
+} v;
+layout(binding = 4, std430)
+buffer Buffer_1_ssbo {
+  float weights[];
+} buf_in;
+layout(binding = 5, std430)
+buffer Buffer_2_ssbo {
+  float weights[];
+} buf_out;
+layout(binding = 7, rgba8) uniform highp writeonly image2D tex_out;
+float tint_float_modulo(float x, float y) {
+  return (x - (y * trunc((x / y))));
+}
+void export_level_inner(uvec3 coord) {
+  if (all(lessThan(coord.xy, uvec2(uvec2(imageSize(tex_out)))))) {
+    uint dst_offset = (coord[0u] << ((coord[1u] * v.tint_symbol.width) & 31u));
+    uint src_offset = ((coord[0u] - 2u) + ((coord[1u] >> (2u & 31u)) * v.tint_symbol.width));
+    float a = buf_in.weights[(src_offset << (0u & 31u))];
+    float b = buf_in.weights[(src_offset + 1u)];
+    float c = buf_in.weights[((src_offset + 1u) + v.tint_symbol.width)];
+    float d = buf_in.weights[((src_offset + 1u) + v.tint_symbol.width)];
+    float sum = dot(vec4(a, b, c, d), vec4(1.0f));
+    buf_out.weights[dst_offset] = tint_float_modulo(sum, 4.0f);
+    vec4 v_1 = vec4(a, (a * b), ((a / b) + c), sum);
+    vec4 probabilities = (v_1 + max(sum, 0.0f));
+    imageStore(tex_out, ivec2(coord.xy), probabilities);
+  }
+}
+layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  export_level_inner(gl_GlobalInvocationID);
+}
diff --git a/test/tint/expressions/binary/mod/scalar-scalar/f16.wgsl.expected.ir.glsl b/test/tint/expressions/binary/mod/scalar-scalar/f16.wgsl.expected.ir.glsl
index a862921..53d8478 100644
--- a/test/tint/expressions/binary/mod/scalar-scalar/f16.wgsl.expected.ir.glsl
+++ b/test/tint/expressions/binary/mod/scalar-scalar/f16.wgsl.expected.ir.glsl
@@ -1,20 +1,12 @@
-SKIP: FAILED
-
 #version 310 es
 #extension GL_AMD_gpu_shader_half_float: require
 
+float16_t tint_float_modulo(float16_t x, float16_t y) {
+  return (x - (y * trunc((x / y))));
+}
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
 void main() {
   float16_t a = 1.0hf;
   float16_t b = 2.0hf;
-  float16_t r = (a % b);
+  float16_t r = tint_float_modulo(a, b);
 }
-error: Error parsing GLSL shader:
-ERROR: 0:8: '%' :  wrong operand types: no operation '%' exists that takes a left-hand operand of type ' temp float16_t' and a right operand of type ' temp float16_t' (or there is no acceptable conversion)
-ERROR: 0:8: '' : compilation terminated 
-ERROR: 2 compilation errors.  No code generated.
-
-
-
-
-tint executable returned error: exit status 1
diff --git a/test/tint/expressions/binary/mod/scalar-scalar/f32.wgsl.expected.ir.glsl b/test/tint/expressions/binary/mod/scalar-scalar/f32.wgsl.expected.ir.glsl
index 24332de..2b1bc44 100644
--- a/test/tint/expressions/binary/mod/scalar-scalar/f32.wgsl.expected.ir.glsl
+++ b/test/tint/expressions/binary/mod/scalar-scalar/f32.wgsl.expected.ir.glsl
@@ -1,19 +1,11 @@
-SKIP: FAILED
-
 #version 310 es
 
+float tint_float_modulo(float x, float y) {
+  return (x - (y * trunc((x / y))));
+}
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
 void main() {
   float a = 1.0f;
   float b = 2.0f;
-  float r = (a % b);
+  float r = tint_float_modulo(a, b);
 }
-error: Error parsing GLSL shader:
-ERROR: 0:7: '%' :  wrong operand types: no operation '%' exists that takes a left-hand operand of type ' temp highp float' and a right operand of type ' temp highp float' (or there is no acceptable conversion)
-ERROR: 0:7: '' : compilation terminated 
-ERROR: 2 compilation errors.  No code generated.
-
-
-
-
-tint executable returned error: exit status 1
diff --git a/test/tint/expressions/binary/mod/scalar-vec3/f16.wgsl.expected.ir.glsl b/test/tint/expressions/binary/mod/scalar-vec3/f16.wgsl.expected.ir.glsl
index b6611a7..8f23eba 100644
--- a/test/tint/expressions/binary/mod/scalar-vec3/f16.wgsl.expected.ir.glsl
+++ b/test/tint/expressions/binary/mod/scalar-vec3/f16.wgsl.expected.ir.glsl
@@ -1,21 +1,12 @@
-SKIP: FAILED
-
 #version 310 es
 #extension GL_AMD_gpu_shader_half_float: require
 
+f16vec3 tint_float_modulo(f16vec3 x, f16vec3 y) {
+  return (x - (y * trunc((x / y))));
+}
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
 void main() {
   float16_t a = 4.0hf;
   f16vec3 b = f16vec3(1.0hf, 2.0hf, 3.0hf);
-  f16vec3 r = (a % b);
+  f16vec3 r = tint_float_modulo(f16vec3(a), b);
 }
-error: Error parsing GLSL shader:
-ERROR: 0:8: '%' :  wrong operand types: no operation '%' exists that takes a left-hand operand of type ' temp float16_t' and a right operand of type ' temp 3-component vector of float16_t' (or there is no acceptable conversion)
-ERROR: 0:8: '=' :  cannot convert from ' temp float16_t' to ' temp 3-component vector of float16_t'
-ERROR: 0:8: '' : compilation terminated 
-ERROR: 3 compilation errors.  No code generated.
-
-
-
-
-tint executable returned error: exit status 1
diff --git a/test/tint/expressions/binary/mod/scalar-vec3/f32.wgsl.expected.ir.glsl b/test/tint/expressions/binary/mod/scalar-vec3/f32.wgsl.expected.ir.glsl
index 96f7374..7d5b4d3 100644
--- a/test/tint/expressions/binary/mod/scalar-vec3/f32.wgsl.expected.ir.glsl
+++ b/test/tint/expressions/binary/mod/scalar-vec3/f32.wgsl.expected.ir.glsl
@@ -1,20 +1,11 @@
-SKIP: FAILED
-
 #version 310 es
 
+vec3 tint_float_modulo(vec3 x, vec3 y) {
+  return (x - (y * trunc((x / y))));
+}
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
 void main() {
   float a = 4.0f;
   vec3 b = vec3(1.0f, 2.0f, 3.0f);
-  vec3 r = (a % b);
+  vec3 r = tint_float_modulo(vec3(a), b);
 }
-error: Error parsing GLSL shader:
-ERROR: 0:7: '%' :  wrong operand types: no operation '%' exists that takes a left-hand operand of type ' temp highp float' and a right operand of type ' temp highp 3-component vector of float' (or there is no acceptable conversion)
-ERROR: 0:7: '=' :  cannot convert from ' temp highp float' to ' temp highp 3-component vector of float'
-ERROR: 0:7: '' : compilation terminated 
-ERROR: 3 compilation errors.  No code generated.
-
-
-
-
-tint executable returned error: exit status 1
diff --git a/test/tint/expressions/binary/mod/vec3-scalar/f16.wgsl.expected.ir.glsl b/test/tint/expressions/binary/mod/vec3-scalar/f16.wgsl.expected.ir.glsl
index 08f7325..dc63b60 100644
--- a/test/tint/expressions/binary/mod/vec3-scalar/f16.wgsl.expected.ir.glsl
+++ b/test/tint/expressions/binary/mod/vec3-scalar/f16.wgsl.expected.ir.glsl
@@ -1,20 +1,12 @@
-SKIP: FAILED
-
 #version 310 es
 #extension GL_AMD_gpu_shader_half_float: require
 
+f16vec3 tint_float_modulo(f16vec3 x, f16vec3 y) {
+  return (x - (y * trunc((x / y))));
+}
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
 void main() {
   f16vec3 a = f16vec3(1.0hf, 2.0hf, 3.0hf);
   float16_t b = 4.0hf;
-  f16vec3 r = (a % b);
+  f16vec3 r = tint_float_modulo(a, f16vec3(b));
 }
-error: Error parsing GLSL shader:
-ERROR: 0:8: '%' :  wrong operand types: no operation '%' exists that takes a left-hand operand of type ' temp 3-component vector of float16_t' and a right operand of type ' temp float16_t' (or there is no acceptable conversion)
-ERROR: 0:8: '' : compilation terminated 
-ERROR: 2 compilation errors.  No code generated.
-
-
-
-
-tint executable returned error: exit status 1
diff --git a/test/tint/expressions/binary/mod/vec3-scalar/f32.wgsl.expected.ir.glsl b/test/tint/expressions/binary/mod/vec3-scalar/f32.wgsl.expected.ir.glsl
index 330bfab..9b60056 100644
--- a/test/tint/expressions/binary/mod/vec3-scalar/f32.wgsl.expected.ir.glsl
+++ b/test/tint/expressions/binary/mod/vec3-scalar/f32.wgsl.expected.ir.glsl
@@ -1,19 +1,11 @@
-SKIP: FAILED
-
 #version 310 es
 
+vec3 tint_float_modulo(vec3 x, vec3 y) {
+  return (x - (y * trunc((x / y))));
+}
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
 void main() {
   vec3 a = vec3(1.0f, 2.0f, 3.0f);
   float b = 4.0f;
-  vec3 r = (a % b);
+  vec3 r = tint_float_modulo(a, vec3(b));
 }
-error: Error parsing GLSL shader:
-ERROR: 0:7: '%' :  wrong operand types: no operation '%' exists that takes a left-hand operand of type ' temp highp 3-component vector of float' and a right operand of type ' temp highp float' (or there is no acceptable conversion)
-ERROR: 0:7: '' : compilation terminated 
-ERROR: 2 compilation errors.  No code generated.
-
-
-
-
-tint executable returned error: exit status 1
diff --git a/test/tint/expressions/binary/mod/vec3-vec3/f16.wgsl.expected.ir.glsl b/test/tint/expressions/binary/mod/vec3-vec3/f16.wgsl.expected.ir.glsl
index 66d7acc..eda9bc5 100644
--- a/test/tint/expressions/binary/mod/vec3-vec3/f16.wgsl.expected.ir.glsl
+++ b/test/tint/expressions/binary/mod/vec3-vec3/f16.wgsl.expected.ir.glsl
@@ -1,20 +1,12 @@
-SKIP: FAILED
-
 #version 310 es
 #extension GL_AMD_gpu_shader_half_float: require
 
+f16vec3 tint_float_modulo(f16vec3 x, f16vec3 y) {
+  return (x - (y * trunc((x / y))));
+}
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
 void main() {
   f16vec3 a = f16vec3(1.0hf, 2.0hf, 3.0hf);
   f16vec3 b = f16vec3(4.0hf, 5.0hf, 6.0hf);
-  f16vec3 r = (a % b);
+  f16vec3 r = tint_float_modulo(a, b);
 }
-error: Error parsing GLSL shader:
-ERROR: 0:8: '%' :  wrong operand types: no operation '%' exists that takes a left-hand operand of type ' temp 3-component vector of float16_t' and a right operand of type ' temp 3-component vector of float16_t' (or there is no acceptable conversion)
-ERROR: 0:8: '' : compilation terminated 
-ERROR: 2 compilation errors.  No code generated.
-
-
-
-
-tint executable returned error: exit status 1
diff --git a/test/tint/expressions/binary/mod/vec3-vec3/f32.wgsl.expected.ir.glsl b/test/tint/expressions/binary/mod/vec3-vec3/f32.wgsl.expected.ir.glsl
index c251261..ebcd8c7 100644
--- a/test/tint/expressions/binary/mod/vec3-vec3/f32.wgsl.expected.ir.glsl
+++ b/test/tint/expressions/binary/mod/vec3-vec3/f32.wgsl.expected.ir.glsl
@@ -1,19 +1,11 @@
-SKIP: FAILED
-
 #version 310 es
 
+vec3 tint_float_modulo(vec3 x, vec3 y) {
+  return (x - (y * trunc((x / y))));
+}
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
 void main() {
   vec3 a = vec3(1.0f, 2.0f, 3.0f);
   vec3 b = vec3(4.0f, 5.0f, 6.0f);
-  vec3 r = (a % b);
+  vec3 r = tint_float_modulo(a, b);
 }
-error: Error parsing GLSL shader:
-ERROR: 0:7: '%' :  wrong operand types: no operation '%' exists that takes a left-hand operand of type ' temp highp 3-component vector of float' and a right operand of type ' temp highp 3-component vector of float' (or there is no acceptable conversion)
-ERROR: 0:7: '' : compilation terminated 
-ERROR: 2 compilation errors.  No code generated.
-
-
-
-
-tint executable returned error: exit status 1
diff --git a/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-scalar/f16.wgsl.expected.ir.glsl b/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-scalar/f16.wgsl.expected.ir.glsl
index e211e38..5498691 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-scalar/f16.wgsl.expected.ir.glsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-scalar/f16.wgsl.expected.ir.glsl
@@ -1,20 +1,12 @@
-SKIP: FAILED
-
 #version 310 es
 #extension GL_AMD_gpu_shader_half_float: require
 
+float16_t tint_float_modulo(float16_t x, float16_t y) {
+  return (x - (y * trunc((x / y))));
+}
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
 void main() {
   float16_t a = 1.0hf;
   float16_t b = 0.0hf;
-  float16_t r = (a % b);
+  float16_t r = tint_float_modulo(a, b);
 }
-error: Error parsing GLSL shader:
-ERROR: 0:8: '%' :  wrong operand types: no operation '%' exists that takes a left-hand operand of type ' temp float16_t' and a right operand of type ' temp float16_t' (or there is no acceptable conversion)
-ERROR: 0:8: '' : compilation terminated 
-ERROR: 2 compilation errors.  No code generated.
-
-
-
-
-tint executable returned error: exit status 1
diff --git a/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-scalar/f32.wgsl.expected.ir.glsl b/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-scalar/f32.wgsl.expected.ir.glsl
index 3c6a28c..67fb61d 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-scalar/f32.wgsl.expected.ir.glsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-scalar/f32.wgsl.expected.ir.glsl
@@ -1,19 +1,11 @@
-SKIP: FAILED
-
 #version 310 es
 
+float tint_float_modulo(float x, float y) {
+  return (x - (y * trunc((x / y))));
+}
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
 void main() {
   float a = 1.0f;
   float b = 0.0f;
-  float r = (a % b);
+  float r = tint_float_modulo(a, b);
 }
-error: Error parsing GLSL shader:
-ERROR: 0:7: '%' :  wrong operand types: no operation '%' exists that takes a left-hand operand of type ' temp highp float' and a right operand of type ' temp highp float' (or there is no acceptable conversion)
-ERROR: 0:7: '' : compilation terminated 
-ERROR: 2 compilation errors.  No code generated.
-
-
-
-
-tint executable returned error: exit status 1
diff --git a/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-vec3/f16.wgsl.expected.ir.glsl b/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-vec3/f16.wgsl.expected.ir.glsl
index 0037c1a..a7d1cb1 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-vec3/f16.wgsl.expected.ir.glsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-vec3/f16.wgsl.expected.ir.glsl
@@ -1,20 +1,12 @@
-SKIP: FAILED
-
 #version 310 es
 #extension GL_AMD_gpu_shader_half_float: require
 
+f16vec3 tint_float_modulo(f16vec3 x, f16vec3 y) {
+  return (x - (y * trunc((x / y))));
+}
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
 void main() {
   f16vec3 a = f16vec3(1.0hf, 2.0hf, 3.0hf);
   f16vec3 b = f16vec3(0.0hf, 5.0hf, 0.0hf);
-  f16vec3 r = (a % b);
+  f16vec3 r = tint_float_modulo(a, b);
 }
-error: Error parsing GLSL shader:
-ERROR: 0:8: '%' :  wrong operand types: no operation '%' exists that takes a left-hand operand of type ' temp 3-component vector of float16_t' and a right operand of type ' temp 3-component vector of float16_t' (or there is no acceptable conversion)
-ERROR: 0:8: '' : compilation terminated 
-ERROR: 2 compilation errors.  No code generated.
-
-
-
-
-tint executable returned error: exit status 1
diff --git a/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-vec3/f32.wgsl.expected.ir.glsl b/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-vec3/f32.wgsl.expected.ir.glsl
index 8422419..2e75d94 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-vec3/f32.wgsl.expected.ir.glsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-vec3/f32.wgsl.expected.ir.glsl
@@ -1,19 +1,11 @@
-SKIP: FAILED
-
 #version 310 es
 
+vec3 tint_float_modulo(vec3 x, vec3 y) {
+  return (x - (y * trunc((x / y))));
+}
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
 void main() {
   vec3 a = vec3(1.0f, 2.0f, 3.0f);
   vec3 b = vec3(0.0f, 5.0f, 0.0f);
-  vec3 r = (a % b);
+  vec3 r = tint_float_modulo(a, b);
 }
-error: Error parsing GLSL shader:
-ERROR: 0:7: '%' :  wrong operand types: no operation '%' exists that takes a left-hand operand of type ' temp highp 3-component vector of float' and a right operand of type ' temp highp 3-component vector of float' (or there is no acceptable conversion)
-ERROR: 0:7: '' : compilation terminated 
-ERROR: 2 compilation errors.  No code generated.
-
-
-
-
-tint executable returned error: exit status 1
diff --git a/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-scalar/f16.wgsl.expected.ir.glsl b/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-scalar/f16.wgsl.expected.ir.glsl
index 3170931..76fb198 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-scalar/f16.wgsl.expected.ir.glsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-scalar/f16.wgsl.expected.ir.glsl
@@ -1,20 +1,12 @@
-SKIP: FAILED
-
 #version 310 es
 #extension GL_AMD_gpu_shader_half_float: require
 
+float16_t tint_float_modulo(float16_t x, float16_t y) {
+  return (x - (y * trunc((x / y))));
+}
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
 void main() {
   float16_t a = 1.0hf;
   float16_t b = 0.0hf;
-  float16_t r = (a % (b + b));
+  float16_t r = tint_float_modulo(a, (b + b));
 }
-error: Error parsing GLSL shader:
-ERROR: 0:8: '%' :  wrong operand types: no operation '%' exists that takes a left-hand operand of type ' temp float16_t' and a right operand of type ' temp float16_t' (or there is no acceptable conversion)
-ERROR: 0:8: '' : compilation terminated 
-ERROR: 2 compilation errors.  No code generated.
-
-
-
-
-tint executable returned error: exit status 1
diff --git a/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-scalar/f32.wgsl.expected.ir.glsl b/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-scalar/f32.wgsl.expected.ir.glsl
index 019536a..be75764 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-scalar/f32.wgsl.expected.ir.glsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-scalar/f32.wgsl.expected.ir.glsl
@@ -1,19 +1,11 @@
-SKIP: FAILED
-
 #version 310 es
 
+float tint_float_modulo(float x, float y) {
+  return (x - (y * trunc((x / y))));
+}
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
 void main() {
   float a = 1.0f;
   float b = 0.0f;
-  float r = (a % (b + b));
+  float r = tint_float_modulo(a, (b + b));
 }
-error: Error parsing GLSL shader:
-ERROR: 0:7: '%' :  wrong operand types: no operation '%' exists that takes a left-hand operand of type ' temp highp float' and a right operand of type ' temp highp float' (or there is no acceptable conversion)
-ERROR: 0:7: '' : compilation terminated 
-ERROR: 2 compilation errors.  No code generated.
-
-
-
-
-tint executable returned error: exit status 1
diff --git a/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-vec3/f16.wgsl.expected.ir.glsl b/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-vec3/f16.wgsl.expected.ir.glsl
index 44fc283..0824855 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-vec3/f16.wgsl.expected.ir.glsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-vec3/f16.wgsl.expected.ir.glsl
@@ -1,20 +1,12 @@
-SKIP: FAILED
-
 #version 310 es
 #extension GL_AMD_gpu_shader_half_float: require
 
+f16vec3 tint_float_modulo(f16vec3 x, f16vec3 y) {
+  return (x - (y * trunc((x / y))));
+}
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
 void main() {
   f16vec3 a = f16vec3(1.0hf, 2.0hf, 3.0hf);
   f16vec3 b = f16vec3(0.0hf, 5.0hf, 0.0hf);
-  f16vec3 r = (a % (b + b));
+  f16vec3 r = tint_float_modulo(a, (b + b));
 }
-error: Error parsing GLSL shader:
-ERROR: 0:8: '%' :  wrong operand types: no operation '%' exists that takes a left-hand operand of type ' temp 3-component vector of float16_t' and a right operand of type ' temp 3-component vector of float16_t' (or there is no acceptable conversion)
-ERROR: 0:8: '' : compilation terminated 
-ERROR: 2 compilation errors.  No code generated.
-
-
-
-
-tint executable returned error: exit status 1
diff --git a/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-vec3/f32.wgsl.expected.ir.glsl b/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-vec3/f32.wgsl.expected.ir.glsl
index 8db025c..bb1a680 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-vec3/f32.wgsl.expected.ir.glsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-vec3/f32.wgsl.expected.ir.glsl
@@ -1,19 +1,11 @@
-SKIP: FAILED
-
 #version 310 es
 
+vec3 tint_float_modulo(vec3 x, vec3 y) {
+  return (x - (y * trunc((x / y))));
+}
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
 void main() {
   vec3 a = vec3(1.0f, 2.0f, 3.0f);
   vec3 b = vec3(0.0f, 5.0f, 0.0f);
-  vec3 r = (a % (b + b));
+  vec3 r = tint_float_modulo(a, (b + b));
 }
-error: Error parsing GLSL shader:
-ERROR: 0:7: '%' :  wrong operand types: no operation '%' exists that takes a left-hand operand of type ' temp highp 3-component vector of float' and a right operand of type ' temp highp 3-component vector of float' (or there is no acceptable conversion)
-ERROR: 0:7: '' : compilation terminated 
-ERROR: 2 compilation errors.  No code generated.
-
-
-
-
-tint executable returned error: exit status 1
diff --git a/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-scalar/f16.wgsl.expected.ir.glsl b/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-scalar/f16.wgsl.expected.ir.glsl
index e211e38..5498691 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-scalar/f16.wgsl.expected.ir.glsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-scalar/f16.wgsl.expected.ir.glsl
@@ -1,20 +1,12 @@
-SKIP: FAILED
-
 #version 310 es
 #extension GL_AMD_gpu_shader_half_float: require
 
+float16_t tint_float_modulo(float16_t x, float16_t y) {
+  return (x - (y * trunc((x / y))));
+}
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
 void main() {
   float16_t a = 1.0hf;
   float16_t b = 0.0hf;
-  float16_t r = (a % b);
+  float16_t r = tint_float_modulo(a, b);
 }
-error: Error parsing GLSL shader:
-ERROR: 0:8: '%' :  wrong operand types: no operation '%' exists that takes a left-hand operand of type ' temp float16_t' and a right operand of type ' temp float16_t' (or there is no acceptable conversion)
-ERROR: 0:8: '' : compilation terminated 
-ERROR: 2 compilation errors.  No code generated.
-
-
-
-
-tint executable returned error: exit status 1
diff --git a/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-scalar/f32.wgsl.expected.ir.glsl b/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-scalar/f32.wgsl.expected.ir.glsl
index 3c6a28c..67fb61d 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-scalar/f32.wgsl.expected.ir.glsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-scalar/f32.wgsl.expected.ir.glsl
@@ -1,19 +1,11 @@
-SKIP: FAILED
-
 #version 310 es
 
+float tint_float_modulo(float x, float y) {
+  return (x - (y * trunc((x / y))));
+}
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
 void main() {
   float a = 1.0f;
   float b = 0.0f;
-  float r = (a % b);
+  float r = tint_float_modulo(a, b);
 }
-error: Error parsing GLSL shader:
-ERROR: 0:7: '%' :  wrong operand types: no operation '%' exists that takes a left-hand operand of type ' temp highp float' and a right operand of type ' temp highp float' (or there is no acceptable conversion)
-ERROR: 0:7: '' : compilation terminated 
-ERROR: 2 compilation errors.  No code generated.
-
-
-
-
-tint executable returned error: exit status 1
diff --git a/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-vec3/f16.wgsl.expected.ir.glsl b/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-vec3/f16.wgsl.expected.ir.glsl
index 0037c1a..a7d1cb1 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-vec3/f16.wgsl.expected.ir.glsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-vec3/f16.wgsl.expected.ir.glsl
@@ -1,20 +1,12 @@
-SKIP: FAILED
-
 #version 310 es
 #extension GL_AMD_gpu_shader_half_float: require
 
+f16vec3 tint_float_modulo(f16vec3 x, f16vec3 y) {
+  return (x - (y * trunc((x / y))));
+}
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
 void main() {
   f16vec3 a = f16vec3(1.0hf, 2.0hf, 3.0hf);
   f16vec3 b = f16vec3(0.0hf, 5.0hf, 0.0hf);
-  f16vec3 r = (a % b);
+  f16vec3 r = tint_float_modulo(a, b);
 }
-error: Error parsing GLSL shader:
-ERROR: 0:8: '%' :  wrong operand types: no operation '%' exists that takes a left-hand operand of type ' temp 3-component vector of float16_t' and a right operand of type ' temp 3-component vector of float16_t' (or there is no acceptable conversion)
-ERROR: 0:8: '' : compilation terminated 
-ERROR: 2 compilation errors.  No code generated.
-
-
-
-
-tint executable returned error: exit status 1
diff --git a/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-vec3/f32.wgsl.expected.ir.glsl b/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-vec3/f32.wgsl.expected.ir.glsl
index 8422419..2e75d94 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-vec3/f32.wgsl.expected.ir.glsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-vec3/f32.wgsl.expected.ir.glsl
@@ -1,19 +1,11 @@
-SKIP: FAILED
-
 #version 310 es
 
+vec3 tint_float_modulo(vec3 x, vec3 y) {
+  return (x - (y * trunc((x / y))));
+}
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
 void main() {
   vec3 a = vec3(1.0f, 2.0f, 3.0f);
   vec3 b = vec3(0.0f, 5.0f, 0.0f);
-  vec3 r = (a % b);
+  vec3 r = tint_float_modulo(a, b);
 }
-error: Error parsing GLSL shader:
-ERROR: 0:7: '%' :  wrong operand types: no operation '%' exists that takes a left-hand operand of type ' temp highp 3-component vector of float' and a right operand of type ' temp highp 3-component vector of float' (or there is no acceptable conversion)
-ERROR: 0:7: '' : compilation terminated 
-ERROR: 2 compilation errors.  No code generated.
-
-
-
-
-tint executable returned error: exit status 1
diff --git a/test/tint/statements/compound_assign/divide_by_zero.wgsl.expected.ir.glsl b/test/tint/statements/compound_assign/divide_by_zero.wgsl.expected.ir.glsl
index 8dec860..8a2d327 100644
--- a/test/tint/statements/compound_assign/divide_by_zero.wgsl.expected.ir.glsl
+++ b/test/tint/statements/compound_assign/divide_by_zero.wgsl.expected.ir.glsl
@@ -2,6 +2,9 @@
 
 int a = 0;
 float b = 0.0f;
+float tint_float_modulo(float x, float y) {
+  return (x - (y * trunc((x / y))));
+}
 int tint_mod_i32(int lhs, int rhs) {
   uint v = uint((lhs == (-2147483647 - 1)));
   bool v_1 = bool((v & uint((rhs == -1))));
@@ -19,11 +22,11 @@
   a = tint_div_i32(a, maybe_zero);
   a = tint_mod_i32(a, maybe_zero);
   b = (b / 0.0f);
-  b = (b % 0.0f);
+  b = tint_float_modulo(b, 0.0f);
   float v_7 = float(maybe_zero);
   b = (b / v_7);
   float v_8 = float(maybe_zero);
-  b = (b % v_8);
+  b = tint_float_modulo(b, v_8);
 }
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
 void main() {