tint/transform: Implement div / mod polyfill

Prevents UB for divide-by-zero and integer overflow when dividing

Fixed: tint:1349
Change-Id: Ieef66d27d7aec3011628ced076b2bccc7770a8af
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/108925
Commit-Queue: Ben Clayton <bclayton@google.com>
Reviewed-by: Dan Sinclair <dsinclair@chromium.org>
Kokoro: Kokoro <noreply+kokoro@google.com>
diff --git a/src/tint/number.h b/src/tint/number.h
index 0558c8f..c116ddf 100644
--- a/src/tint/number.h
+++ b/src/tint/number.h
@@ -124,6 +124,9 @@
     /// type is the underlying type of the Number
     using type = T;
 
+    /// Number of bits in the number.
+    static constexpr size_t kNumBits = sizeof(T) * 8;
+
     /// Highest finite representable value of this type.
     static constexpr type kHighestValue = std::numeric_limits<type>::max();
 
@@ -187,6 +190,9 @@
     /// C++ does not have a native float16 type, so we use a 32-bit float instead.
     using type = float;
 
+    /// Number of bits in the number.
+    static constexpr size_t kNumBits = 16;
+
     /// Highest finite representable value of this type.
     static constexpr type kHighestValue = 65504.0f;  // 2¹⁵ × (1 + 1023/1024)
 
diff --git a/src/tint/program_builder.h b/src/tint/program_builder.h
index 2f5b5e0..3d1f40e 100644
--- a/src/tint/program_builder.h
+++ b/src/tint/program_builder.h
@@ -3267,6 +3267,14 @@
 //! @cond Doxygen_Suppress
 // Various template specializations for ProgramBuilder::TypesBuilder::CToAST.
 template <>
+struct ProgramBuilder::TypesBuilder::CToAST<AInt> {
+    static const ast::Type* get(const ProgramBuilder::TypesBuilder*) { return nullptr; }
+};
+template <>
+struct ProgramBuilder::TypesBuilder::CToAST<AFloat> {
+    static const ast::Type* get(const ProgramBuilder::TypesBuilder*) { return nullptr; }
+};
+template <>
 struct ProgramBuilder::TypesBuilder::CToAST<i32> {
     static const ast::Type* get(const ProgramBuilder::TypesBuilder* t) { return t->i32(); }
 };
diff --git a/src/tint/transform/builtin_polyfill.cc b/src/tint/transform/builtin_polyfill.cc
index 17fcc20..4dfc149 100644
--- a/src/tint/transform/builtin_polyfill.cc
+++ b/src/tint/transform/builtin_polyfill.cc
@@ -14,6 +14,8 @@
 
 #include "src/tint/transform/builtin_polyfill.h"
 
+#include <algorithm>
+#include <tuple>
 #include <unordered_map>
 #include <utility>
 
@@ -29,6 +31,9 @@
 
 namespace tint::transform {
 
+/// BinaryOpSignature is tuple of a binary op, LHS type and RHS type
+using BinaryOpSignature = std::tuple<ast::BinaryOp, const sem::Type*, const sem::Type*>;
+
 /// PIMPL state for the transform
 struct BuiltinPolyfill::State {
     /// Constructor
@@ -36,15 +41,6 @@
     /// @param p the builtins to polyfill
     State(CloneContext& c, Builtins p) : ctx(c), polyfill(p) {}
 
-    /// The clone context
-    CloneContext& ctx;
-    /// The builtins to polyfill
-    Builtins polyfill;
-    /// The destination program builder
-    ProgramBuilder& b = *ctx.dst;
-    /// The source clone context
-    const sem::Info& sem = ctx.src->Sem();
-
     /// Builds the polyfill function for the `acosh` builtin
     /// @param ty the parameter and return type for the function
     /// @return the polyfill function name
@@ -563,6 +559,63 @@
         return name;
     }
 
+    /// Builds the polyfill function for a divide or modulo operator with integer scalar or vector
+    /// operands.
+    /// @param sig the signature of the binary operator
+    /// @return the polyfill function name
+    Symbol int_div_mod(const BinaryOpSignature& sig) {
+        const auto op = std::get<0>(sig);
+        const auto* lhs_ty = std::get<1>(sig);
+        const auto* rhs_ty = std::get<2>(sig);
+        const bool is_div = op == ast::BinaryOp::kDivide;
+
+        uint32_t lhs_width = 1;
+        uint32_t rhs_width = 1;
+        const auto* lhs_el_ty = sem::Type::ElementOf(lhs_ty, &lhs_width);
+        const auto* rhs_el_ty = sem::Type::ElementOf(rhs_ty, &rhs_width);
+
+        const uint32_t width = std::max(lhs_width, rhs_width);
+
+        const char* lhs = "lhs";
+        const char* rhs = "rhs";
+
+        utils::Vector<const ast::Statement*, 4> body;
+
+        if (lhs_width < width) {
+            // lhs is scalar, rhs is vector. Convert lhs to vector.
+            body.Push(b.Decl(b.Let("l", b.vec(T(lhs_el_ty), width, b.Expr(lhs)))));
+            lhs = "l";
+        }
+        if (rhs_width < width) {
+            // lhs is vector, rhs is scalar. Convert rhs to vector.
+            body.Push(b.Decl(b.Let("r", b.vec(T(rhs_el_ty), width, b.Expr(rhs)))));
+            rhs = "r";
+        }
+
+        auto name = b.Symbols().New(is_div ? "tint_div" : "tint_mod");
+        auto* use_one = b.Equal(rhs, ScalarOrVector(width, 0_a));
+        if (lhs_ty->is_signed_scalar_or_vector()) {
+            const auto bits = lhs_el_ty->Size() * 8;
+            auto min_int = AInt(AInt::kLowestValue >> (AInt::kNumBits - bits));
+            const ast::Expression* lhs_is_min = b.Equal(lhs, ScalarOrVector(width, min_int));
+            const ast::Expression* rhs_is_minus_one = b.Equal(rhs, ScalarOrVector(width, -1_a));
+            // use_one = use_one | ((lhs == MIN_INT) & (rhs == -1))
+            use_one = b.Or(use_one, b.And(lhs_is_min, rhs_is_minus_one));
+        }
+        auto* select = b.Call("select", rhs, ScalarOrVector(width, 1_a), use_one);
+
+        body.Push(b.Return(is_div ? b.Div(lhs, select) : b.Mod(lhs, select)));
+        b.Func(name,
+               utils::Vector{
+                   b.Param("lhs", T(lhs_ty)),
+                   b.Param("rhs", T(rhs_ty)),
+               },
+               width == 1 ? T(lhs_ty) : b.ty.vec(T(lhs_el_ty), width),  // return type
+               std::move(body));
+
+        return name;
+    }
+
     /// Builds the polyfill function for the `saturate` builtin
     /// @param ty the parameter and return type for the function
     /// @return the polyfill function name
@@ -625,6 +678,15 @@
     }
 
   private:
+    /// The clone context
+    CloneContext& ctx;
+    /// The builtins to polyfill
+    Builtins polyfill;
+    /// The destination program builder
+    ProgramBuilder& b = *ctx.dst;
+    /// The source clone context
+    const sem::Info& sem = ctx.src->Sem();
+
     /// @returns the AST type for the given sem type
     const ast::Type* T(const sem::Type* ty) const { return CreateASTTypeFor(ctx, ty); }
 
@@ -659,13 +721,14 @@
         return SkipTransform;
     }
 
-    auto& builtins = cfg->builtins;
+    auto& polyfill = cfg->builtins;
 
     utils::Hashmap<const sem::Builtin*, Symbol, 8> builtin_polyfills;
+    utils::Hashmap<BinaryOpSignature, Symbol, 8> binary_op_polyfills;
 
     ProgramBuilder b;
     CloneContext ctx{&b, src, /* auto_clone_symbols */ true};
-    State s{ctx, builtins};
+    State s{ctx, polyfill};
 
     bool made_changes = false;
     for (auto* node : src->ASTNodes().Objects()) {
@@ -679,84 +742,84 @@
             if (!builtin) {
                 continue;
             }
-            Symbol polyfill;
+            Symbol fn;
             switch (builtin->Type()) {
                 case sem::BuiltinType::kAcosh:
-                    if (builtins.acosh != Level::kNone) {
-                        polyfill = builtin_polyfills.GetOrCreate(
+                    if (polyfill.acosh != Level::kNone) {
+                        fn = builtin_polyfills.GetOrCreate(
                             builtin, [&] { return s.acosh(builtin->ReturnType()); });
                     }
                     break;
                 case sem::BuiltinType::kAsinh:
-                    if (builtins.asinh) {
-                        polyfill = builtin_polyfills.GetOrCreate(
+                    if (polyfill.asinh) {
+                        fn = builtin_polyfills.GetOrCreate(
                             builtin, [&] { return s.asinh(builtin->ReturnType()); });
                     }
                     break;
                 case sem::BuiltinType::kAtanh:
-                    if (builtins.atanh != Level::kNone) {
-                        polyfill = builtin_polyfills.GetOrCreate(
+                    if (polyfill.atanh != Level::kNone) {
+                        fn = builtin_polyfills.GetOrCreate(
                             builtin, [&] { return s.atanh(builtin->ReturnType()); });
                     }
                     break;
                 case sem::BuiltinType::kClamp:
-                    if (builtins.clamp_int) {
+                    if (polyfill.clamp_int) {
                         auto& sig = builtin->Signature();
                         if (sig.parameters[0]->Type()->is_integer_scalar_or_vector()) {
-                            polyfill = builtin_polyfills.GetOrCreate(
+                            fn = builtin_polyfills.GetOrCreate(
                                 builtin, [&] { return s.clampInteger(builtin->ReturnType()); });
                         }
                     }
                     break;
                 case sem::BuiltinType::kCountLeadingZeros:
-                    if (builtins.count_leading_zeros) {
-                        polyfill = builtin_polyfills.GetOrCreate(
+                    if (polyfill.count_leading_zeros) {
+                        fn = builtin_polyfills.GetOrCreate(
                             builtin, [&] { return s.countLeadingZeros(builtin->ReturnType()); });
                     }
                     break;
                 case sem::BuiltinType::kCountTrailingZeros:
-                    if (builtins.count_trailing_zeros) {
-                        polyfill = builtin_polyfills.GetOrCreate(
+                    if (polyfill.count_trailing_zeros) {
+                        fn = builtin_polyfills.GetOrCreate(
                             builtin, [&] { return s.countTrailingZeros(builtin->ReturnType()); });
                     }
                     break;
                 case sem::BuiltinType::kExtractBits:
-                    if (builtins.extract_bits != Level::kNone) {
-                        polyfill = builtin_polyfills.GetOrCreate(
+                    if (polyfill.extract_bits != Level::kNone) {
+                        fn = builtin_polyfills.GetOrCreate(
                             builtin, [&] { return s.extractBits(builtin->ReturnType()); });
                     }
                     break;
                 case sem::BuiltinType::kFirstLeadingBit:
-                    if (builtins.first_leading_bit) {
-                        polyfill = builtin_polyfills.GetOrCreate(
+                    if (polyfill.first_leading_bit) {
+                        fn = builtin_polyfills.GetOrCreate(
                             builtin, [&] { return s.firstLeadingBit(builtin->ReturnType()); });
                     }
                     break;
                 case sem::BuiltinType::kFirstTrailingBit:
-                    if (builtins.first_trailing_bit) {
-                        polyfill = builtin_polyfills.GetOrCreate(
+                    if (polyfill.first_trailing_bit) {
+                        fn = builtin_polyfills.GetOrCreate(
                             builtin, [&] { return s.firstTrailingBit(builtin->ReturnType()); });
                     }
                     break;
                 case sem::BuiltinType::kInsertBits:
-                    if (builtins.insert_bits != Level::kNone) {
-                        polyfill = builtin_polyfills.GetOrCreate(
+                    if (polyfill.insert_bits != Level::kNone) {
+                        fn = builtin_polyfills.GetOrCreate(
                             builtin, [&] { return s.insertBits(builtin->ReturnType()); });
                     }
                     break;
                 case sem::BuiltinType::kSaturate:
-                    if (builtins.saturate) {
-                        polyfill = builtin_polyfills.GetOrCreate(
+                    if (polyfill.saturate) {
+                        fn = builtin_polyfills.GetOrCreate(
                             builtin, [&] { return s.saturate(builtin->ReturnType()); });
                     }
                     break;
                 case sem::BuiltinType::kTextureSampleBaseClampToEdge:
-                    if (builtins.texture_sample_base_clamp_to_edge_2d_f32) {
+                    if (polyfill.texture_sample_base_clamp_to_edge_2d_f32) {
                         auto& sig = builtin->Signature();
                         auto* tex = sig.Parameter(sem::ParameterUsage::kTexture);
                         if (auto* stex = tex->Type()->As<sem::SampledTexture>()) {
                             if (stex->type()->Is<sem::F32>()) {
-                                polyfill = builtin_polyfills.GetOrCreate(builtin, [&] {
+                                fn = builtin_polyfills.GetOrCreate(builtin, [&] {
                                     return s.textureSampleBaseClampToEdge_2d_f32();
                                 });
                             }
@@ -764,9 +827,9 @@
                     }
                     break;
                 case sem::BuiltinType::kQuantizeToF16:
-                    if (builtins.quantize_to_vec_f16) {
+                    if (polyfill.quantize_to_vec_f16) {
                         if (auto* vec = builtin->ReturnType()->As<sem::Vector>()) {
-                            polyfill = builtin_polyfills.GetOrCreate(
+                            fn = builtin_polyfills.GetOrCreate(
                                 builtin, [&] { return s.quantizeToF16(vec); });
                         }
                     }
@@ -776,16 +839,16 @@
                     break;
             }
 
-            if (polyfill.IsValid()) {
-                auto* replacement = s.b.Call(polyfill, ctx.Clone(call->Declaration()->args));
+            if (fn.IsValid()) {
+                auto* replacement = b.Call(fn, ctx.Clone(call->Declaration()->args));
                 ctx.Replace(call->Declaration(), replacement);
                 made_changes = true;
             }
         } else if (auto* bin_op = node->As<ast::BinaryExpression>()) {
             switch (bin_op->op) {
                 case ast::BinaryOp::kShiftLeft:
-                case ast::BinaryOp::kShiftRight:
-                    if (builtins.bitshift_modulo) {
+                case ast::BinaryOp::kShiftRight: {
+                    if (polyfill.bitshift_modulo) {
                         auto* lhs_ty = src->TypeOf(bin_op->lhs)->UnwrapRef();
                         auto* rhs_ty = src->TypeOf(bin_op->rhs)->UnwrapRef();
                         auto* lhs_el_ty = sem::Type::DeepestElementOf(lhs_ty);
@@ -798,6 +861,24 @@
                         made_changes = true;
                     }
                     break;
+                }
+                case ast::BinaryOp::kDivide:
+                case ast::BinaryOp::kModulo: {
+                    if (polyfill.int_div_mod) {
+                        auto* lhs_ty = src->TypeOf(bin_op->lhs)->UnwrapRef();
+                        if (lhs_ty->is_integer_scalar_or_vector()) {
+                            auto* rhs_ty = src->TypeOf(bin_op->rhs)->UnwrapRef();
+                            BinaryOpSignature sig{bin_op->op, lhs_ty, rhs_ty};
+                            auto fn = binary_op_polyfills.GetOrCreate(
+                                sig, [&] { return s.int_div_mod(sig); });
+                            auto* lhs = ctx.Clone(bin_op->lhs);
+                            auto* rhs = ctx.Clone(bin_op->rhs);
+                            ctx.Replace(bin_op, b.Call(fn, lhs, rhs));
+                            made_changes = true;
+                        }
+                    }
+                    break;
+                }
                 default:
                     break;
             }
diff --git a/src/tint/transform/builtin_polyfill.h b/src/tint/transform/builtin_polyfill.h
index 7083aa7..f9eb029 100644
--- a/src/tint/transform/builtin_polyfill.h
+++ b/src/tint/transform/builtin_polyfill.h
@@ -63,6 +63,9 @@
         bool first_trailing_bit = false;
         /// Should `insertBits()` be polyfilled?
         Level insert_bits = Level::kNone;
+        /// Should integer scalar / vector divides and modulos be polyfilled to avoid DBZ and
+        /// integer overflows?
+        bool int_div_mod = false;
         /// Should `saturate()` be polyfilled?
         bool saturate = false;
         /// Should `textureSampleBaseClampToEdge()` be polyfilled for texture_2d<f32> textures?
diff --git a/src/tint/transform/builtin_polyfill_test.cc b/src/tint/transform/builtin_polyfill_test.cc
index 1e380d4..b767167 100644
--- a/src/tint/transform/builtin_polyfill_test.cc
+++ b/src/tint/transform/builtin_polyfill_test.cc
@@ -1921,6 +1921,775 @@
 }
 
 ////////////////////////////////////////////////////////////////////////////////
+// int_div_mod
+////////////////////////////////////////////////////////////////////////////////
+DataMap polyfillIntDivMod() {
+    BuiltinPolyfill::Builtins builtins;
+    builtins.int_div_mod = true;
+    DataMap data;
+    data.Add<BuiltinPolyfill::Config>(builtins);
+    return data;
+}
+
+TEST_F(BuiltinPolyfillTest, ShouldRunIntDiv) {
+    auto* src = R"(
+fn f() {
+  let v = 10i;
+  let x = 20i / v;
+}
+)";
+
+    EXPECT_FALSE(ShouldRun<BuiltinPolyfill>(src));
+    EXPECT_TRUE(ShouldRun<BuiltinPolyfill>(src, polyfillIntDivMod()));
+}
+
+TEST_F(BuiltinPolyfillTest, ShouldRunIntMod) {
+    auto* src = R"(
+fn f() {
+  let v = 10i;
+  let x = 20i % v;
+}
+)";
+
+    EXPECT_FALSE(ShouldRun<BuiltinPolyfill>(src));
+    EXPECT_TRUE(ShouldRun<BuiltinPolyfill>(src, polyfillIntDivMod()));
+}
+
+TEST_F(BuiltinPolyfillTest, IntDiv_ai_i32) {
+    auto* src = R"(
+fn f() {
+  let v = 10i;
+  let x = 20 / v;
+}
+)";
+
+    auto* expect = R"(
+fn tint_div(lhs : i32, rhs : i32) -> i32 {
+  return (lhs / select(rhs, 1, ((rhs == 0) | ((lhs == -2147483648) & (rhs == -1)))));
+}
+
+fn f() {
+  let v = 10i;
+  let x = tint_div(20, v);
+}
+)";
+
+    auto got = Run<BuiltinPolyfill>(src, polyfillIntDivMod());
+
+    EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(BuiltinPolyfillTest, IntMod_ai_i32) {
+    auto* src = R"(
+fn f() {
+  let v = 10i;
+  let x = 20 % v;
+}
+)";
+
+    auto* expect = R"(
+fn tint_mod(lhs : i32, rhs : i32) -> i32 {
+  return (lhs % select(rhs, 1, ((rhs == 0) | ((lhs == -2147483648) & (rhs == -1)))));
+}
+
+fn f() {
+  let v = 10i;
+  let x = tint_mod(20, v);
+}
+)";
+
+    auto got = Run<BuiltinPolyfill>(src, polyfillIntDivMod());
+
+    EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(BuiltinPolyfillTest, IntDiv_i32_ai) {
+    auto* src = R"(
+fn f() {
+  let v = 10i;
+  let x = v / 20;
+}
+)";
+
+    auto* expect = R"(
+fn tint_div(lhs : i32, rhs : i32) -> i32 {
+  return (lhs / select(rhs, 1, ((rhs == 0) | ((lhs == -2147483648) & (rhs == -1)))));
+}
+
+fn f() {
+  let v = 10i;
+  let x = tint_div(v, 20);
+}
+)";
+
+    auto got = Run<BuiltinPolyfill>(src, polyfillIntDivMod());
+
+    EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(BuiltinPolyfillTest, IntMod_i32_ai) {
+    auto* src = R"(
+fn f() {
+  let v = 10i;
+  let x = v % 20;
+}
+)";
+
+    auto* expect = R"(
+fn tint_mod(lhs : i32, rhs : i32) -> i32 {
+  return (lhs % select(rhs, 1, ((rhs == 0) | ((lhs == -2147483648) & (rhs == -1)))));
+}
+
+fn f() {
+  let v = 10i;
+  let x = tint_mod(v, 20);
+}
+)";
+
+    auto got = Run<BuiltinPolyfill>(src, polyfillIntDivMod());
+
+    EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(BuiltinPolyfillTest, IntDiv_i32_i32) {
+    auto* src = R"(
+fn f() {
+  let v = 10i;
+  let x = 20i / v;
+}
+)";
+
+    auto* expect = R"(
+fn tint_div(lhs : i32, rhs : i32) -> i32 {
+  return (lhs / select(rhs, 1, ((rhs == 0) | ((lhs == -2147483648) & (rhs == -1)))));
+}
+
+fn f() {
+  let v = 10i;
+  let x = tint_div(20i, v);
+}
+)";
+
+    auto got = Run<BuiltinPolyfill>(src, polyfillIntDivMod());
+
+    EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(BuiltinPolyfillTest, IntMod_i32_i32) {
+    auto* src = R"(
+fn f() {
+  let v = 10i;
+  let x = 20i % v;
+}
+)";
+
+    auto* expect = R"(
+fn tint_mod(lhs : i32, rhs : i32) -> i32 {
+  return (lhs % select(rhs, 1, ((rhs == 0) | ((lhs == -2147483648) & (rhs == -1)))));
+}
+
+fn f() {
+  let v = 10i;
+  let x = tint_mod(20i, v);
+}
+)";
+
+    auto got = Run<BuiltinPolyfill>(src, polyfillIntDivMod());
+
+    EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(BuiltinPolyfillTest, IntDiv_ai_u32) {
+    auto* src = R"(
+fn f() {
+  let v = 10u;
+  let x = 20 / v;
+}
+)";
+
+    auto* expect = R"(
+fn tint_div(lhs : u32, rhs : u32) -> u32 {
+  return (lhs / select(rhs, 1, (rhs == 0)));
+}
+
+fn f() {
+  let v = 10u;
+  let x = tint_div(20, v);
+}
+)";
+
+    auto got = Run<BuiltinPolyfill>(src, polyfillIntDivMod());
+
+    EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(BuiltinPolyfillTest, IntMod_ai_u32) {
+    auto* src = R"(
+fn f() {
+  let v = 10u;
+  let x = 20 % v;
+}
+)";
+
+    auto* expect = R"(
+fn tint_mod(lhs : u32, rhs : u32) -> u32 {
+  return (lhs % select(rhs, 1, (rhs == 0)));
+}
+
+fn f() {
+  let v = 10u;
+  let x = tint_mod(20, v);
+}
+)";
+
+    auto got = Run<BuiltinPolyfill>(src, polyfillIntDivMod());
+
+    EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(BuiltinPolyfillTest, IntDiv_u32_ai) {
+    auto* src = R"(
+fn f() {
+  let v = 10u;
+  let x = v / 20;
+}
+)";
+
+    auto* expect = R"(
+fn tint_div(lhs : u32, rhs : u32) -> u32 {
+  return (lhs / select(rhs, 1, (rhs == 0)));
+}
+
+fn f() {
+  let v = 10u;
+  let x = tint_div(v, 20);
+}
+)";
+
+    auto got = Run<BuiltinPolyfill>(src, polyfillIntDivMod());
+
+    EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(BuiltinPolyfillTest, IntMod_u32_ai) {
+    auto* src = R"(
+fn f() {
+  let v = 10u;
+  let x = v % 20;
+}
+)";
+
+    auto* expect = R"(
+fn tint_mod(lhs : u32, rhs : u32) -> u32 {
+  return (lhs % select(rhs, 1, (rhs == 0)));
+}
+
+fn f() {
+  let v = 10u;
+  let x = tint_mod(v, 20);
+}
+)";
+
+    auto got = Run<BuiltinPolyfill>(src, polyfillIntDivMod());
+
+    EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(BuiltinPolyfillTest, IntDiv_u32_u32) {
+    auto* src = R"(
+fn f() {
+  let v = 10u;
+  let x = 20u / v;
+}
+)";
+
+    auto* expect = R"(
+fn tint_div(lhs : u32, rhs : u32) -> u32 {
+  return (lhs / select(rhs, 1, (rhs == 0)));
+}
+
+fn f() {
+  let v = 10u;
+  let x = tint_div(20u, v);
+}
+)";
+
+    auto got = Run<BuiltinPolyfill>(src, polyfillIntDivMod());
+
+    EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(BuiltinPolyfillTest, IntMod_u32_u32) {
+    auto* src = R"(
+fn f() {
+  let v = 10u;
+  let x = 20u % v;
+}
+)";
+
+    auto* expect = R"(
+fn tint_mod(lhs : u32, rhs : u32) -> u32 {
+  return (lhs % select(rhs, 1, (rhs == 0)));
+}
+
+fn f() {
+  let v = 10u;
+  let x = tint_mod(20u, v);
+}
+)";
+
+    auto got = Run<BuiltinPolyfill>(src, polyfillIntDivMod());
+
+    EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(BuiltinPolyfillTest, IntDiv_vec3_ai_i32) {
+    auto* src = R"(
+fn f() {
+  let v = 10i;
+  let x = vec3(20) / v;
+}
+)";
+
+    auto* expect = R"(
+fn tint_div(lhs : vec3<i32>, rhs : i32) -> vec3<i32> {
+  let r = vec3<i32>(rhs);
+  return (lhs / select(r, vec3(1), ((r == vec3(0)) | ((lhs == vec3(-2147483648)) & (r == vec3(-1))))));
+}
+
+fn f() {
+  let v = 10i;
+  let x = tint_div(vec3(20), v);
+}
+)";
+
+    auto got = Run<BuiltinPolyfill>(src, polyfillIntDivMod());
+
+    EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(BuiltinPolyfillTest, IntMod_vec3_ai_i32) {
+    auto* src = R"(
+fn f() {
+  let v = 10i;
+  let x = vec3(20) % v;
+}
+)";
+
+    auto* expect = R"(
+fn tint_mod(lhs : vec3<i32>, rhs : i32) -> vec3<i32> {
+  let r = vec3<i32>(rhs);
+  return (lhs % select(r, vec3(1), ((r == vec3(0)) | ((lhs == vec3(-2147483648)) & (r == vec3(-1))))));
+}
+
+fn f() {
+  let v = 10i;
+  let x = tint_mod(vec3(20), v);
+}
+)";
+
+    auto got = Run<BuiltinPolyfill>(src, polyfillIntDivMod());
+
+    EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(BuiltinPolyfillTest, IntDiv_vec3_i32_ai) {
+    auto* src = R"(
+fn f() {
+  let v = 10i;
+  let x = vec3(v) / 20;
+}
+)";
+
+    auto* expect = R"(
+fn tint_div(lhs : vec3<i32>, rhs : i32) -> vec3<i32> {
+  let r = vec3<i32>(rhs);
+  return (lhs / select(r, vec3(1), ((r == vec3(0)) | ((lhs == vec3(-2147483648)) & (r == vec3(-1))))));
+}
+
+fn f() {
+  let v = 10i;
+  let x = tint_div(vec3(v), 20);
+}
+)";
+
+    auto got = Run<BuiltinPolyfill>(src, polyfillIntDivMod());
+
+    EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(BuiltinPolyfillTest, IntMod_vec3_i32_ai) {
+    auto* src = R"(
+fn f() {
+  let v = 10i;
+  let x = vec3(v) % 20;
+}
+)";
+
+    auto* expect = R"(
+fn tint_mod(lhs : vec3<i32>, rhs : i32) -> vec3<i32> {
+  let r = vec3<i32>(rhs);
+  return (lhs % select(r, vec3(1), ((r == vec3(0)) | ((lhs == vec3(-2147483648)) & (r == vec3(-1))))));
+}
+
+fn f() {
+  let v = 10i;
+  let x = tint_mod(vec3(v), 20);
+}
+)";
+
+    auto got = Run<BuiltinPolyfill>(src, polyfillIntDivMod());
+
+    EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(BuiltinPolyfillTest, IntDiv_vec3_i32_i32) {
+    auto* src = R"(
+fn f() {
+  let v = 10i;
+  let x = vec3<i32>(20i) / v;
+}
+)";
+
+    auto* expect = R"(
+fn tint_div(lhs : vec3<i32>, rhs : i32) -> vec3<i32> {
+  let r = vec3<i32>(rhs);
+  return (lhs / select(r, vec3(1), ((r == vec3(0)) | ((lhs == vec3(-2147483648)) & (r == vec3(-1))))));
+}
+
+fn f() {
+  let v = 10i;
+  let x = tint_div(vec3<i32>(20i), v);
+}
+)";
+
+    auto got = Run<BuiltinPolyfill>(src, polyfillIntDivMod());
+
+    EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(BuiltinPolyfillTest, IntMod_vec3_i32_i32) {
+    auto* src = R"(
+fn f() {
+  let v = 10i;
+  let x = vec3<i32>(20i) % v;
+}
+)";
+
+    auto* expect = R"(
+fn tint_mod(lhs : vec3<i32>, rhs : i32) -> vec3<i32> {
+  let r = vec3<i32>(rhs);
+  return (lhs % select(r, vec3(1), ((r == vec3(0)) | ((lhs == vec3(-2147483648)) & (r == vec3(-1))))));
+}
+
+fn f() {
+  let v = 10i;
+  let x = tint_mod(vec3<i32>(20i), v);
+}
+)";
+
+    auto got = Run<BuiltinPolyfill>(src, polyfillIntDivMod());
+
+    EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(BuiltinPolyfillTest, IntDiv_vec3_u32_u32) {
+    auto* src = R"(
+fn f() {
+  let v = 10u;
+  let x = vec3<u32>(20u) / v;
+}
+)";
+
+    auto* expect = R"(
+fn tint_div(lhs : vec3<u32>, rhs : u32) -> vec3<u32> {
+  let r = vec3<u32>(rhs);
+  return (lhs / select(r, vec3(1), (r == vec3(0))));
+}
+
+fn f() {
+  let v = 10u;
+  let x = tint_div(vec3<u32>(20u), v);
+}
+)";
+
+    auto got = Run<BuiltinPolyfill>(src, polyfillIntDivMod());
+
+    EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(BuiltinPolyfillTest, IntMod_vec3_u32_u32) {
+    auto* src = R"(
+fn f() {
+  let v = 10u;
+  let x = vec3<u32>(20u) % v;
+}
+)";
+
+    auto* expect = R"(
+fn tint_mod(lhs : vec3<u32>, rhs : u32) -> vec3<u32> {
+  let r = vec3<u32>(rhs);
+  return (lhs % select(r, vec3(1), (r == vec3(0))));
+}
+
+fn f() {
+  let v = 10u;
+  let x = tint_mod(vec3<u32>(20u), v);
+}
+)";
+
+    auto got = Run<BuiltinPolyfill>(src, polyfillIntDivMod());
+
+    EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(BuiltinPolyfillTest, IntDiv_ai_vec3_i32) {
+    auto* src = R"(
+fn f() {
+  let v = 10i;
+  let x = 20 / vec3(v);
+}
+)";
+
+    auto* expect = R"(
+fn tint_div(lhs : i32, rhs : vec3<i32>) -> vec3<i32> {
+  let l = vec3<i32>(lhs);
+  return (l / select(rhs, vec3(1), ((rhs == vec3(0)) | ((l == vec3(-2147483648)) & (rhs == vec3(-1))))));
+}
+
+fn f() {
+  let v = 10i;
+  let x = tint_div(20, vec3(v));
+}
+)";
+
+    auto got = Run<BuiltinPolyfill>(src, polyfillIntDivMod());
+
+    EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(BuiltinPolyfillTest, IntMod_ai_vec3_i32) {
+    auto* src = R"(
+fn f() {
+  let v = 10i;
+  let x = 20 % vec3(v);
+}
+)";
+
+    auto* expect = R"(
+fn tint_mod(lhs : i32, rhs : vec3<i32>) -> vec3<i32> {
+  let l = vec3<i32>(lhs);
+  return (l % select(rhs, vec3(1), ((rhs == vec3(0)) | ((l == vec3(-2147483648)) & (rhs == vec3(-1))))));
+}
+
+fn f() {
+  let v = 10i;
+  let x = tint_mod(20, vec3(v));
+}
+)";
+
+    auto got = Run<BuiltinPolyfill>(src, polyfillIntDivMod());
+
+    EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(BuiltinPolyfillTest, IntDiv_i32_vec3_i32) {
+    auto* src = R"(
+fn f() {
+  let v = 10i;
+  let x = 20i / vec3<i32>(v);
+}
+)";
+
+    auto* expect = R"(
+fn tint_div(lhs : i32, rhs : vec3<i32>) -> vec3<i32> {
+  let l = vec3<i32>(lhs);
+  return (l / select(rhs, vec3(1), ((rhs == vec3(0)) | ((l == vec3(-2147483648)) & (rhs == vec3(-1))))));
+}
+
+fn f() {
+  let v = 10i;
+  let x = tint_div(20i, vec3<i32>(v));
+}
+)";
+
+    auto got = Run<BuiltinPolyfill>(src, polyfillIntDivMod());
+
+    EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(BuiltinPolyfillTest, IntMod_i32_vec3_i32) {
+    auto* src = R"(
+fn f() {
+  let v = 10i;
+  let x = 20i % vec3<i32>(v);
+}
+)";
+
+    auto* expect = R"(
+fn tint_mod(lhs : i32, rhs : vec3<i32>) -> vec3<i32> {
+  let l = vec3<i32>(lhs);
+  return (l % select(rhs, vec3(1), ((rhs == vec3(0)) | ((l == vec3(-2147483648)) & (rhs == vec3(-1))))));
+}
+
+fn f() {
+  let v = 10i;
+  let x = tint_mod(20i, vec3<i32>(v));
+}
+)";
+
+    auto got = Run<BuiltinPolyfill>(src, polyfillIntDivMod());
+
+    EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(BuiltinPolyfillTest, IntDiv_u32_vec3_u32) {
+    auto* src = R"(
+fn f() {
+  let v = 10u;
+  let x = 20u / vec3<u32>(v);
+}
+)";
+
+    auto* expect = R"(
+fn tint_div(lhs : u32, rhs : vec3<u32>) -> vec3<u32> {
+  let l = vec3<u32>(lhs);
+  return (l / select(rhs, vec3(1), (rhs == vec3(0))));
+}
+
+fn f() {
+  let v = 10u;
+  let x = tint_div(20u, vec3<u32>(v));
+}
+)";
+
+    auto got = Run<BuiltinPolyfill>(src, polyfillIntDivMod());
+
+    EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(BuiltinPolyfillTest, IntMod_u32_vec3_u32) {
+    auto* src = R"(
+fn f() {
+  let v = 10u;
+  let x = 20u % vec3<u32>(v);
+}
+)";
+
+    auto* expect = R"(
+fn tint_mod(lhs : u32, rhs : vec3<u32>) -> vec3<u32> {
+  let l = vec3<u32>(lhs);
+  return (l % select(rhs, vec3(1), (rhs == vec3(0))));
+}
+
+fn f() {
+  let v = 10u;
+  let x = tint_mod(20u, vec3<u32>(v));
+}
+)";
+
+    auto got = Run<BuiltinPolyfill>(src, polyfillIntDivMod());
+
+    EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(BuiltinPolyfillTest, IntDiv_vec3_i32_vec3_i32) {
+    auto* src = R"(
+fn f() {
+  let v = 10i;
+  let x = vec3<i32>(20i) / vec3<i32>(v);
+}
+)";
+
+    auto* expect = R"(
+fn tint_div(lhs : vec3<i32>, rhs : vec3<i32>) -> vec3<i32> {
+  return (lhs / select(rhs, vec3(1), ((rhs == vec3(0)) | ((lhs == vec3(-2147483648)) & (rhs == vec3(-1))))));
+}
+
+fn f() {
+  let v = 10i;
+  let x = tint_div(vec3<i32>(20i), vec3<i32>(v));
+}
+)";
+
+    auto got = Run<BuiltinPolyfill>(src, polyfillIntDivMod());
+
+    EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(BuiltinPolyfillTest, IntMod_vec3_i32_vec3_i32) {
+    auto* src = R"(
+fn f() {
+  let v = 10i;
+  let x = vec3<i32>(20i) % vec3<i32>(v);
+}
+)";
+
+    auto* expect = R"(
+fn tint_mod(lhs : vec3<i32>, rhs : vec3<i32>) -> vec3<i32> {
+  return (lhs % select(rhs, vec3(1), ((rhs == vec3(0)) | ((lhs == vec3(-2147483648)) & (rhs == vec3(-1))))));
+}
+
+fn f() {
+  let v = 10i;
+  let x = tint_mod(vec3<i32>(20i), vec3<i32>(v));
+}
+)";
+
+    auto got = Run<BuiltinPolyfill>(src, polyfillIntDivMod());
+
+    EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(BuiltinPolyfillTest, IntDiv_vec3_u32_vec3_u32) {
+    auto* src = R"(
+fn f() {
+  let v = 10u;
+  let x = vec3<u32>(20u) / vec3<u32>(v);
+}
+)";
+
+    auto* expect = R"(
+fn tint_div(lhs : vec3<u32>, rhs : vec3<u32>) -> vec3<u32> {
+  return (lhs / select(rhs, vec3(1), (rhs == vec3(0))));
+}
+
+fn f() {
+  let v = 10u;
+  let x = tint_div(vec3<u32>(20u), vec3<u32>(v));
+}
+)";
+
+    auto got = Run<BuiltinPolyfill>(src, polyfillIntDivMod());
+
+    EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(BuiltinPolyfillTest, IntMod_vec3_u32_vec3_u32) {
+    auto* src = R"(
+fn f() {
+  let v = 10u;
+  let x = vec3<u32>(20u) % vec3<u32>(v);
+}
+)";
+
+    auto* expect = R"(
+fn tint_mod(lhs : vec3<u32>, rhs : vec3<u32>) -> vec3<u32> {
+  return (lhs % select(rhs, vec3(1), (rhs == vec3(0))));
+}
+
+fn f() {
+  let v = 10u;
+  let x = tint_mod(vec3<u32>(20u), vec3<u32>(v));
+}
+)";
+
+    auto got = Run<BuiltinPolyfill>(src, polyfillIntDivMod());
+
+    EXPECT_EQ(expect, str(got));
+}
+
+////////////////////////////////////////////////////////////////////////////////
 // saturate
 ////////////////////////////////////////////////////////////////////////////////
 DataMap polyfillSaturate() {
diff --git a/src/tint/writer/glsl/generator_impl.cc b/src/tint/writer/glsl/generator_impl.cc
index 29136cb..b8140b9 100644
--- a/src/tint/writer/glsl/generator_impl.cc
+++ b/src/tint/writer/glsl/generator_impl.cc
@@ -182,6 +182,9 @@
 
     manager.Add<transform::DisableUniformityAnalysis>();
 
+    // ExpandCompoundAssignment must come before BuiltinPolyfill
+    manager.Add<transform::ExpandCompoundAssignment>();
+
     {  // Builtin polyfills
         transform::BuiltinPolyfill::Builtins polyfills;
         polyfills.acosh = transform::BuiltinPolyfill::Level::kRangeCheck;
@@ -193,6 +196,7 @@
         polyfills.first_leading_bit = true;
         polyfills.first_trailing_bit = true;
         polyfills.insert_bits = transform::BuiltinPolyfill::Level::kClampParameters;
+        polyfills.int_div_mod = true;
         polyfills.saturate = true;
         polyfills.texture_sample_base_clamp_to_edge_2d_f32 = true;
         data.Add<transform::BuiltinPolyfill::Config>(polyfills);
@@ -214,7 +218,6 @@
         manager.Add<transform::ZeroInitWorkgroupMemory>();
     }
     manager.Add<transform::CanonicalizeEntryPointIO>();
-    manager.Add<transform::ExpandCompoundAssignment>();
     manager.Add<transform::PromoteSideEffectsToDecl>();
     manager.Add<transform::PadStructs>();
 
diff --git a/src/tint/writer/hlsl/generator_impl.cc b/src/tint/writer/hlsl/generator_impl.cc
index a7c3f00..3eb3358 100644
--- a/src/tint/writer/hlsl/generator_impl.cc
+++ b/src/tint/writer/hlsl/generator_impl.cc
@@ -157,6 +157,9 @@
 
     manager.Add<transform::DisableUniformityAnalysis>();
 
+    // ExpandCompoundAssignment must come before BuiltinPolyfill
+    manager.Add<transform::ExpandCompoundAssignment>();
+
     {  // Builtin polyfills
         transform::BuiltinPolyfill::Builtins polyfills;
         polyfills.acosh = transform::BuiltinPolyfill::Level::kFull;
@@ -172,6 +175,7 @@
         polyfills.first_leading_bit = true;
         polyfills.first_trailing_bit = true;
         polyfills.insert_bits = transform::BuiltinPolyfill::Level::kFull;
+        polyfills.int_div_mod = true;
         polyfills.texture_sample_base_clamp_to_edge_2d_f32 = true;
         data.Add<transform::BuiltinPolyfill::Config>(polyfills);
         manager.Add<transform::BuiltinPolyfill>();
@@ -211,7 +215,6 @@
     // assumes that num_workgroups builtins only appear as struct members and are
     // only accessed directly via member accessors.
     manager.Add<transform::NumWorkgroupsFromUniform>();
-    manager.Add<transform::ExpandCompoundAssignment>();
     manager.Add<transform::PromoteSideEffectsToDecl>();
     manager.Add<transform::VectorizeScalarMatrixInitializers>();
     manager.Add<transform::SimplifyPointers>();
@@ -661,117 +664,6 @@
     return true;
 }
 
-bool GeneratorImpl::EmitExpressionOrOneIfZero(std::ostream& out, const ast::Expression* expr) {
-    // For constants, replace literal 0 with 1.
-    if (const auto* val = builder_.Sem().Get(expr)->ConstantValue()) {
-        if (!val->AnyZero()) {
-            return EmitExpression(out, expr);
-        }
-
-        auto* ty = val->Type();
-
-        if (ty->IsAnyOf<sem::I32, sem::U32>()) {
-            return EmitValue(out, ty, 1);
-        }
-
-        if (auto* vec = ty->As<sem::Vector>()) {
-            auto* elem_ty = vec->type();
-
-            if (!EmitType(out, ty, ast::AddressSpace::kNone, ast::Access::kUndefined, "")) {
-                return false;
-            }
-
-            out << "(";
-            for (size_t i = 0; i < vec->Width(); ++i) {
-                if (i != 0) {
-                    out << ", ";
-                }
-                auto s = val->Index(i)->As<AInt>();
-                if (!EmitValue(out, elem_ty, (s == 0) ? 1 : static_cast<int>(s))) {
-                    return false;
-                }
-            }
-            out << ")";
-            return true;
-        }
-
-        TINT_ICE(Writer, diagnostics_)
-            << "EmitExpressionOrOneIfZero expects integer scalar or vector";
-        return false;
-    }
-
-    auto* ty = TypeOf(expr)->UnwrapRef();
-
-    // For non-constants, we need to emit runtime code to check if the value is 0,
-    // and return 1 in that case.
-    std::string zero;
-    {
-        std::ostringstream ss;
-        EmitValue(ss, ty, 0);
-        zero = ss.str();
-    }
-    std::string one;
-    {
-        std::ostringstream ss;
-        EmitValue(ss, ty, 1);
-        one = ss.str();
-    }
-
-    // For identifiers, no need for a function call as it's fine to evaluate
-    // `expr` more than once.
-    if (expr->Is<ast::IdentifierExpression>()) {
-        out << "(";
-        if (!EmitExpression(out, expr)) {
-            return false;
-        }
-        out << " == " << zero << " ? " << one << " : ";
-        if (!EmitExpression(out, expr)) {
-            return false;
-        }
-        out << ")";
-        return true;
-    }
-
-    // For non-identifier expressions, call a function to make sure `expr` is only
-    // evaluated once.
-    auto name = utils::GetOrCreate(value_or_one_if_zero_, ty, [&]() -> std::string {
-        // Example:
-        // int4 tint_value_or_one_if_zero_int4(int4 value) {
-        //   return value == 0 ? 0 : value;
-        // }
-        std::string ty_name;
-        {
-            std::ostringstream ss;
-            if (!EmitType(ss, ty, tint::ast::AddressSpace::kUndefined, ast::Access::kUndefined,
-                          "")) {
-                return "";
-            }
-            ty_name = ss.str();
-        }
-
-        std::string fn = UniqueIdentifier("value_or_one_if_zero_" + ty_name);
-        line(&helpers_) << ty_name << " " << fn << "(" << ty_name << " value) {";
-        {
-            ScopedIndent si(&helpers_);
-            line(&helpers_) << "return value == " << zero << " ? " << one << " : value;";
-        }
-        line(&helpers_) << "}";
-        line(&helpers_);
-        return fn;
-    });
-
-    if (name.empty()) {
-        return false;
-    }
-
-    out << name << "(";
-    if (!EmitExpression(out, expr)) {
-        return false;
-    }
-    out << ")";
-    return true;
-}
-
 bool GeneratorImpl::EmitBinary(std::ostream& out, const ast::BinaryExpression* expr) {
     if (expr->op == ast::BinaryOp::kLogicalAnd || expr->op == ast::BinaryOp::kLogicalOr) {
         auto name = UniqueIdentifier(kTempNamePrefix);
@@ -892,21 +784,9 @@
             break;
         case ast::BinaryOp::kDivide:
             out << "/";
-            // BUG(crbug.com/tint/1083): Integer divide/modulo by zero is a FXC
-            // compile error, and undefined behavior in WGSL.
-            if (TypeOf(expr->rhs)->UnwrapRef()->is_integer_scalar_or_vector()) {
-                out << " ";
-                return EmitExpressionOrOneIfZero(out, expr->rhs);
-            }
             break;
         case ast::BinaryOp::kModulo:
             out << "%";
-            // BUG(crbug.com/tint/1083): Integer divide/modulo by zero is a FXC
-            // compile error, and undefined behavior in WGSL.
-            if (TypeOf(expr->rhs)->UnwrapRef()->is_integer_scalar_or_vector()) {
-                out << " ";
-                return EmitExpressionOrOneIfZero(out, expr->rhs);
-            }
             break;
         case ast::BinaryOp::kNone:
             diagnostics_.add_error(diag::System::Writer, "missing binary operation type");
diff --git a/src/tint/writer/hlsl/generator_impl.h b/src/tint/writer/hlsl/generator_impl.h
index eca7734..16b824b 100644
--- a/src/tint/writer/hlsl/generator_impl.h
+++ b/src/tint/writer/hlsl/generator_impl.h
@@ -93,12 +93,6 @@
     /// @param stmt the statement to emit
     /// @returns true if the statement was emitted successfully
     bool EmitAssign(const ast::AssignmentStatement* stmt);
-    /// Emits code such that if `expr` is zero, it emits one, else `expr`.
-    /// Used to avoid divide-by-zeros by substituting constant zeros with ones.
-    /// @param out the output of the expression stream
-    /// @param expr the expression
-    /// @returns true if the expression was emitted, false otherwise
-    bool EmitExpressionOrOneIfZero(std::ostream& out, const ast::Expression* expr);
     /// Handles generating a binary expression
     /// @param out the output of the expression stream
     /// @param expr the binary expression
diff --git a/src/tint/writer/hlsl/generator_impl_binary_test.cc b/src/tint/writer/hlsl/generator_impl_binary_test.cc
index 1163078..6e2b3c7 100644
--- a/src/tint/writer/hlsl/generator_impl_binary_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_binary_test.cc
@@ -653,295 +653,5 @@
 )");
 }
 
-namespace HlslGeneratorDivMod {
-
-struct Params {
-    enum class Type { Div, Mod };
-    Type type;
-};
-
-struct HlslGeneratorDivModTest : TestParamHelper<Params> {
-    std::string Token() { return GetParam().type == Params::Type::Div ? "/" : "%"; }
-
-    template <typename... Args>
-    auto Op(Args... args) {
-        return GetParam().type == Params::Type::Div ? Div(std::forward<Args>(args)...)
-                                                    : Mod(std::forward<Args>(args)...);
-    }
-};
-
-INSTANTIATE_TEST_SUITE_P(HlslGeneratorImplTest,
-                         HlslGeneratorDivModTest,
-                         testing::Values(Params{Params::Type::Div}, Params{Params::Type::Mod}));
-
-TEST_P(HlslGeneratorDivModTest, DivOrModByLiteralZero_i32) {
-    Func("fn", utils::Empty, ty.void_(),
-         utils::Vector{
-             Decl(Var("a", ty.i32())),
-             Decl(Let("r", Op("a", 0_i))),
-         });
-
-    GeneratorImpl& gen = Build();
-
-    ASSERT_TRUE(gen.Generate());
-    EXPECT_EQ(gen.result(), R"(void fn() {
-  int a = 0;
-  const int r = (a )" + Token() +
-                                R"( 1);
-}
-)");
-}
-
-TEST_P(HlslGeneratorDivModTest, DivOrModByLiteralZero_u32) {
-    Func("fn", utils::Empty, ty.void_(),
-         utils::Vector{
-             Decl(Var("a", ty.u32())),
-             Decl(Let("r", Op("a", 0_u))),
-         });
-
-    GeneratorImpl& gen = Build();
-
-    ASSERT_TRUE(gen.Generate());
-    EXPECT_EQ(gen.result(), R"(void fn() {
-  uint a = 0u;
-  const uint r = (a )" + Token() +
-                                R"( 1u);
-}
-)");
-}
-
-TEST_P(HlslGeneratorDivModTest, DivOrModByLiteralZero_vec_by_vec_i32) {
-    Func("fn", utils::Empty, ty.void_(),
-         utils::Vector{
-             Decl(Var("a", vec4<i32>(100_i, 100_i, 100_i, 100_i))),
-             Decl(Let("r", Op("a", vec4<i32>(50_i, 0_i, 25_i, 0_i)))),
-         });
-
-    GeneratorImpl& gen = Build();
-
-    ASSERT_TRUE(gen.Generate());
-    EXPECT_EQ(gen.result(), R"(void fn() {
-  int4 a = (100).xxxx;
-  const int4 r = (a )" + Token() +
-                                R"( int4(50, 1, 25, 1));
-}
-)");
-}
-
-TEST_P(HlslGeneratorDivModTest, DivOrModByLiteralZero_vec_by_scalar_i32) {
-    Func("fn", utils::Empty, ty.void_(),
-         utils::Vector{
-             Decl(Var("a", vec4<i32>(100_i, 100_i, 100_i, 100_i))),
-             Decl(Let("r", Op("a", 0_i))),
-         });
-
-    GeneratorImpl& gen = Build();
-
-    ASSERT_TRUE(gen.Generate());
-    EXPECT_EQ(gen.result(), R"(void fn() {
-  int4 a = (100).xxxx;
-  const int4 r = (a )" + Token() +
-                                R"( 1);
-}
-)");
-}
-
-TEST_P(HlslGeneratorDivModTest, DivOrModByIdentifier_i32) {
-    Func("fn", utils::Vector{Param("b", ty.i32())}, ty.void_(),
-         utils::Vector{
-             Decl(Var("a", ty.i32())),
-             Decl(Let("r", Op("a", "b"))),
-         });
-
-    GeneratorImpl& gen = Build();
-
-    ASSERT_TRUE(gen.Generate());
-    EXPECT_EQ(gen.result(), R"(void fn(int b) {
-  int a = 0;
-  const int r = (a )" + Token() +
-                                R"( (b == 0 ? 1 : b));
-}
-)");
-}
-
-TEST_P(HlslGeneratorDivModTest, DivOrModByIdentifier_u32) {
-    Func("fn", utils::Vector{Param("b", ty.u32())}, ty.void_(),
-         utils::Vector{
-             Decl(Var("a", ty.u32())),
-             Decl(Let("r", Op("a", "b"))),
-         });
-
-    GeneratorImpl& gen = Build();
-
-    ASSERT_TRUE(gen.Generate());
-    EXPECT_EQ(gen.result(), R"(void fn(uint b) {
-  uint a = 0u;
-  const uint r = (a )" + Token() +
-                                R"( (b == 0u ? 1u : b));
-}
-)");
-}
-
-TEST_P(HlslGeneratorDivModTest, DivOrModByIdentifier_vec_by_vec_i32) {
-    Func("fn", utils::Vector{Param("b", ty.vec3<i32>())}, ty.void_(),
-         utils::Vector{
-             Decl(Var("a", ty.vec3<i32>())),
-             Decl(Let("r", Op("a", "b"))),
-         });
-
-    GeneratorImpl& gen = Build();
-
-    ASSERT_TRUE(gen.Generate());
-    EXPECT_EQ(gen.result(), R"(void fn(int3 b) {
-  int3 a = int3(0, 0, 0);
-  const int3 r = (a )" + Token() +
-                                R"( (b == int3(0, 0, 0) ? int3(1, 1, 1) : b));
-}
-)");
-}
-
-TEST_P(HlslGeneratorDivModTest, DivOrModByIdentifier_vec_by_scalar_i32) {
-    Func("fn", utils::Vector{Param("b", ty.i32())}, ty.void_(),
-         utils::Vector{
-             Decl(Var("a", ty.vec3<i32>())),
-             Decl(Let("r", Op("a", "b"))),
-         });
-
-    GeneratorImpl& gen = Build();
-
-    ASSERT_TRUE(gen.Generate());
-    EXPECT_EQ(gen.result(), R"(void fn(int b) {
-  int3 a = int3(0, 0, 0);
-  const int3 r = (a )" + Token() +
-                                R"( (b == 0 ? 1 : b));
-}
-)");
-}
-
-TEST_P(HlslGeneratorDivModTest, DivOrModByExpression_i32) {
-    Func("zero", utils::Empty, ty.i32(),
-         utils::Vector{
-             Return(Expr(0_i)),
-         });
-
-    Func("fn", utils::Empty, ty.void_(),
-         utils::Vector{
-             Decl(Var("a", ty.i32())),
-             Decl(Let("r", Op("a", Call("zero")))),
-         });
-
-    GeneratorImpl& gen = Build();
-
-    ASSERT_TRUE(gen.Generate());
-    EXPECT_EQ(gen.result(), R"(int value_or_one_if_zero_int(int value) {
-  return value == 0 ? 1 : value;
-}
-
-int zero() {
-  return 0;
-}
-
-void fn() {
-  int a = 0;
-  const int r = (a )" + Token() +
-                                R"( value_or_one_if_zero_int(zero()));
-}
-)");
-}
-
-TEST_P(HlslGeneratorDivModTest, DivOrModByExpression_u32) {
-    Func("zero", utils::Empty, ty.u32(),
-         utils::Vector{
-             Return(Expr(0_u)),
-         });
-
-    Func("fn", utils::Empty, ty.void_(),
-         utils::Vector{
-             Decl(Var("a", ty.u32())),
-             Decl(Let("r", Op("a", Call("zero")))),
-         });
-
-    GeneratorImpl& gen = Build();
-
-    ASSERT_TRUE(gen.Generate());
-    EXPECT_EQ(gen.result(), R"(uint value_or_one_if_zero_uint(uint value) {
-  return value == 0u ? 1u : value;
-}
-
-uint zero() {
-  return 0u;
-}
-
-void fn() {
-  uint a = 0u;
-  const uint r = (a )" + Token() +
-                                R"( value_or_one_if_zero_uint(zero()));
-}
-)");
-}
-
-TEST_P(HlslGeneratorDivModTest, DivOrModByExpression_vec_by_vec_i32) {
-    Func("zero", utils::Empty, ty.vec3<i32>(),
-         utils::Vector{
-             Return(vec3<i32>(0_i, 0_i, 0_i)),
-         });
-
-    Func("fn", utils::Empty, ty.void_(),
-         utils::Vector{
-             Decl(Var("a", ty.vec3<i32>())),
-             Decl(Let("r", Op("a", Call("zero")))),
-         });
-
-    GeneratorImpl& gen = Build();
-
-    ASSERT_TRUE(gen.Generate());
-    EXPECT_EQ(gen.result(), R"(int3 value_or_one_if_zero_int3(int3 value) {
-  return value == int3(0, 0, 0) ? int3(1, 1, 1) : value;
-}
-
-int3 zero() {
-  return (0).xxx;
-}
-
-void fn() {
-  int3 a = int3(0, 0, 0);
-  const int3 r = (a )" + Token() +
-                                R"( value_or_one_if_zero_int3(zero()));
-}
-)");
-}
-
-TEST_P(HlslGeneratorDivModTest, DivOrModByExpression_vec_by_scalar_i32) {
-    Func("zero", utils::Empty, ty.i32(),
-         utils::Vector{
-             Return(0_i),
-         });
-
-    Func("fn", utils::Empty, ty.void_(),
-         utils::Vector{
-             Decl(Var("a", ty.vec3<i32>())),
-             Decl(Let("r", Op("a", Call("zero")))),
-         });
-
-    GeneratorImpl& gen = Build();
-
-    ASSERT_TRUE(gen.Generate());
-    EXPECT_EQ(gen.result(), R"(int value_or_one_if_zero_int(int value) {
-  return value == 0 ? 1 : value;
-}
-
-int zero() {
-  return 0;
-}
-
-void fn() {
-  int3 a = int3(0, 0, 0);
-  const int3 r = (a )" + Token() +
-                                R"( value_or_one_if_zero_int(zero()));
-}
-)");
-}
-}  // namespace HlslGeneratorDivMod
-
 }  // namespace
 }  // namespace tint::writer::hlsl
diff --git a/src/tint/writer/msl/generator_impl.cc b/src/tint/writer/msl/generator_impl.cc
index 88578df..351a6d4 100644
--- a/src/tint/writer/msl/generator_impl.cc
+++ b/src/tint/writer/msl/generator_impl.cc
@@ -167,6 +167,9 @@
 
     manager.Add<transform::DisableUniformityAnalysis>();
 
+    // ExpandCompoundAssignment must come before BuiltinPolyfill
+    manager.Add<transform::ExpandCompoundAssignment>();
+
     {  // Builtin polyfills
         transform::BuiltinPolyfill::Builtins polyfills;
         polyfills.acosh = transform::BuiltinPolyfill::Level::kRangeCheck;
@@ -177,6 +180,7 @@
         polyfills.first_leading_bit = true;
         polyfills.first_trailing_bit = true;
         polyfills.insert_bits = transform::BuiltinPolyfill::Level::kClampParameters;
+        polyfills.int_div_mod = true;
         polyfills.texture_sample_base_clamp_to_edge_2d_f32 = true;
         data.Add<transform::BuiltinPolyfill::Config>(polyfills);
         manager.Add<transform::BuiltinPolyfill>();
@@ -224,7 +228,6 @@
         manager.Add<transform::ZeroInitWorkgroupMemory>();
     }
     manager.Add<transform::CanonicalizeEntryPointIO>();
-    manager.Add<transform::ExpandCompoundAssignment>();
     manager.Add<transform::PromoteSideEffectsToDecl>();
     manager.Add<transform::PromoteInitializersToLet>();
 
diff --git a/src/tint/writer/spirv/generator_impl.cc b/src/tint/writer/spirv/generator_impl.cc
index 30dd186..18c7511 100644
--- a/src/tint/writer/spirv/generator_impl.cc
+++ b/src/tint/writer/spirv/generator_impl.cc
@@ -48,6 +48,9 @@
 
     manager.Add<transform::DisableUniformityAnalysis>();
 
+    // ExpandCompoundAssignment must come before BuiltinPolyfill
+    manager.Add<transform::ExpandCompoundAssignment>();
+
     {  // Builtin polyfills
         transform::BuiltinPolyfill::Builtins polyfills;
         polyfills.acosh = transform::BuiltinPolyfill::Level::kRangeCheck;
@@ -60,6 +63,7 @@
         polyfills.first_leading_bit = true;
         polyfills.first_trailing_bit = true;
         polyfills.insert_bits = transform::BuiltinPolyfill::Level::kClampParameters;
+        polyfills.int_div_mod = true;
         polyfills.saturate = true;
         polyfills.texture_sample_base_clamp_to_edge_2d_f32 = true;
         polyfills.quantize_to_vec_f16 = true;  // crbug.com/tint/1741
@@ -80,7 +84,6 @@
         manager.Add<transform::ZeroInitWorkgroupMemory>();
     }
     manager.Add<transform::RemoveUnreachableStatements>();
-    manager.Add<transform::ExpandCompoundAssignment>();
     manager.Add<transform::PromoteSideEffectsToDecl>();
     manager.Add<transform::SimplifyPointers>();  // Required for arrayLength()
     manager.Add<transform::RemovePhonies>();
diff --git a/test/tint/bug/chromium/1273230.wgsl.expected.dxc.hlsl b/test/tint/bug/chromium/1273230.wgsl.expected.dxc.hlsl
index f37fc2b..7f89b55 100644
--- a/test/tint/bug/chromium/1273230.wgsl.expected.dxc.hlsl
+++ b/test/tint/bug/chromium/1273230.wgsl.expected.dxc.hlsl
@@ -1,5 +1,9 @@
-uint value_or_one_if_zero_uint(uint value) {
-  return value == 0u ? 1u : value;
+uint tint_div(uint lhs, uint rhs) {
+  return (lhs / ((rhs == 0u) ? 1u : rhs));
+}
+
+uint tint_mod(uint lhs, uint rhs) {
+  return (lhs % ((rhs == 0u) ? 1u : rhs));
 }
 
 void marg8uintin() {
@@ -32,9 +36,9 @@
 }
 
 uint3 toIndex4D(uint gridSize, uint index) {
-  uint z_1 = (gridSize / value_or_one_if_zero_uint((index * index)));
-  uint y_1 = ((gridSize - ((gridSize * gridSize) * z_1)) / (gridSize == 0u ? 1u : gridSize));
-  uint x_1 = (index % (gridSize == 0u ? 1u : gridSize));
+  uint z_1 = tint_div(gridSize, (index * index));
+  uint y_1 = tint_div((gridSize - ((gridSize * gridSize) * z_1)), gridSize);
+  uint x_1 = tint_mod(index, gridSize);
   return uint3(z_1, y_1, y_1);
 }
 
diff --git a/test/tint/bug/chromium/1273230.wgsl.expected.fxc.hlsl b/test/tint/bug/chromium/1273230.wgsl.expected.fxc.hlsl
index f37fc2b..7f89b55 100644
--- a/test/tint/bug/chromium/1273230.wgsl.expected.fxc.hlsl
+++ b/test/tint/bug/chromium/1273230.wgsl.expected.fxc.hlsl
@@ -1,5 +1,9 @@
-uint value_or_one_if_zero_uint(uint value) {
-  return value == 0u ? 1u : value;
+uint tint_div(uint lhs, uint rhs) {
+  return (lhs / ((rhs == 0u) ? 1u : rhs));
+}
+
+uint tint_mod(uint lhs, uint rhs) {
+  return (lhs % ((rhs == 0u) ? 1u : rhs));
 }
 
 void marg8uintin() {
@@ -32,9 +36,9 @@
 }
 
 uint3 toIndex4D(uint gridSize, uint index) {
-  uint z_1 = (gridSize / value_or_one_if_zero_uint((index * index)));
-  uint y_1 = ((gridSize - ((gridSize * gridSize) * z_1)) / (gridSize == 0u ? 1u : gridSize));
-  uint x_1 = (index % (gridSize == 0u ? 1u : gridSize));
+  uint z_1 = tint_div(gridSize, (index * index));
+  uint y_1 = tint_div((gridSize - ((gridSize * gridSize) * z_1)), gridSize);
+  uint x_1 = tint_mod(index, gridSize);
   return uint3(z_1, y_1, y_1);
 }
 
diff --git a/test/tint/bug/chromium/1273230.wgsl.expected.msl b/test/tint/bug/chromium/1273230.wgsl.expected.msl
index 1e627d7..15000e6 100644
--- a/test/tint/bug/chromium/1273230.wgsl.expected.msl
+++ b/test/tint/bug/chromium/1273230.wgsl.expected.msl
@@ -14,6 +14,14 @@
     T elements[N];
 };
 
+uint tint_div(uint lhs, uint rhs) {
+  return (lhs / select(rhs, 1u, (rhs == 0u)));
+}
+
+uint tint_mod(uint lhs, uint rhs) {
+  return (lhs % select(rhs, 1u, (rhs == 0u)));
+}
+
 void marg8uintin() {
 }
 
@@ -81,9 +89,9 @@
 }
 
 uint3 toIndex4D(uint gridSize, uint index) {
-  uint z_1 = (gridSize / (index * index));
-  uint y_1 = ((gridSize - ((gridSize * gridSize) * z_1)) / gridSize);
-  uint x_1 = (index % gridSize);
+  uint z_1 = tint_div(gridSize, (index * index));
+  uint y_1 = tint_div((gridSize - ((gridSize * gridSize) * z_1)), gridSize);
+  uint x_1 = tint_mod(index, gridSize);
   return uint3(z_1, y_1, y_1);
 }
 
diff --git a/test/tint/bug/chromium/1273230.wgsl.expected.spvasm b/test/tint/bug/chromium/1273230.wgsl.expected.spvasm
index 110100a..2e66503 100644
--- a/test/tint/bug/chromium/1273230.wgsl.expected.spvasm
+++ b/test/tint/bug/chromium/1273230.wgsl.expected.spvasm
@@ -1,10 +1,10 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 275
+; Bound: 290
 ; Schema: 0
                OpCapability Shader
-         %69 = OpExtInstImport "GLSL.std.450"
+         %86 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %main_count "main_count" %GlobalInvocationID_1
                OpExecutionMode %main_count LocalSize 128 1 1
@@ -47,6 +47,12 @@
                OpMemberName %Dbg 10 "value_f32_2"
                OpMemberName %Dbg 11 "value_f32_3"
                OpName %dbg "dbg"
+               OpName %tint_div "tint_div"
+               OpName %lhs "lhs"
+               OpName %rhs "rhs"
+               OpName %tint_mod "tint_mod"
+               OpName %lhs_0 "lhs"
+               OpName %rhs_0 "rhs"
                OpName %marg8uintin "marg8uintin"
                OpName %toVoxelPos "toVoxelPos"
                OpName %position "position"
@@ -171,291 +177,310 @@
   %dbg_block = OpTypeStruct %Dbg
 %_ptr_StorageBuffer_dbg_block = OpTypePointer StorageBuffer %dbg_block
         %dbg = OpVariable %_ptr_StorageBuffer_dbg_block StorageBuffer
+         %32 = OpTypeFunction %uint %uint %uint
+         %38 = OpConstantNull %uint
+       %bool = OpTypeBool
+     %uint_1 = OpConstant %uint 1
        %void = OpTypeVoid
-         %32 = OpTypeFunction %void
-         %36 = OpTypeFunction %v3float %v3float
+         %50 = OpTypeFunction %void
+         %54 = OpTypeFunction %v3float %v3float
      %uint_0 = OpConstant %uint 0
      %uint_4 = OpConstant %uint 4
 %_ptr_Uniform_float = OpTypePointer Uniform %float
-     %uint_1 = OpConstant %uint 1
      %uint_2 = OpConstant %uint 2
 %_ptr_Function_v3float = OpTypePointer Function %v3float
-         %54 = OpConstantNull %v3float
+         %71 = OpConstantNull %v3float
      %uint_5 = OpConstant %uint 5
 %_ptr_Function_float = OpTypePointer Function %float
-         %79 = OpConstantNull %float
+         %96 = OpConstantNull %float
 %_ptr_Uniform_uint = OpTypePointer Uniform %uint
-        %116 = OpTypeFunction %uint %uint %v3float
+        %133 = OpTypeFunction %uint %uint %v3float
 %_ptr_Function_v3uint = OpTypePointer Function %v3uint
-        %124 = OpConstantNull %v3uint
+        %141 = OpConstantNull %v3uint
 %_ptr_Function_uint = OpTypePointer Function %uint
-        %137 = OpTypeFunction %v3uint %uint %uint
-        %145 = OpConstantNull %uint
-        %158 = OpTypeFunction %v3float %uint
+        %154 = OpTypeFunction %v3uint %uint %uint
+        %174 = OpTypeFunction %v3float %uint
      %uint_3 = OpConstant %uint 3
 %_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %float
 %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
-        %190 = OpConstantNull %int
+        %206 = OpConstantNull %int
 %_ptr_StorageBuffer_uint_0 = OpTypePointer StorageBuffer %uint
 %_ptr_StorageBuffer_int = OpTypePointer StorageBuffer %int
 %_ptr_Function_int = OpTypePointer Function %int
-        %206 = OpTypeFunction %void %v3uint
-       %bool = OpTypeBool
+        %222 = OpTypeFunction %void %v3uint
     %float_3 = OpConstant %float 3
       %int_1 = OpConstant %int 1
-%marg8uintin = OpFunction %void None %32
-         %35 = OpLabel
+   %tint_div = OpFunction %uint None %32
+        %lhs = OpFunctionParameter %uint
+        %rhs = OpFunctionParameter %uint
+         %36 = OpLabel
+         %39 = OpIEqual %bool %rhs %38
+         %37 = OpSelect %uint %39 %uint_1 %rhs
+         %42 = OpUDiv %uint %lhs %37
+               OpReturnValue %42
+               OpFunctionEnd
+   %tint_mod = OpFunction %uint None %32
+      %lhs_0 = OpFunctionParameter %uint
+      %rhs_0 = OpFunctionParameter %uint
+         %46 = OpLabel
+         %48 = OpIEqual %bool %rhs_0 %38
+         %47 = OpSelect %uint %48 %uint_1 %rhs_0
+         %49 = OpUMod %uint %lhs_0 %47
+               OpReturnValue %49
+               OpFunctionEnd
+%marg8uintin = OpFunction %void None %50
+         %53 = OpLabel
                OpReturn
                OpFunctionEnd
- %toVoxelPos = OpFunction %v3float None %36
+ %toVoxelPos = OpFunction %v3float None %54
    %position = OpFunctionParameter %v3float
-         %39 = OpLabel
-      %bbMin = OpVariable %_ptr_Function_v3float Function %54
-      %bbMax = OpVariable %_ptr_Function_v3float Function %54
-     %bbSize = OpVariable %_ptr_Function_v3float Function %54
-   %cubeSize = OpVariable %_ptr_Function_float Function %79
-   %gridSize = OpVariable %_ptr_Function_float Function %79
-         %gx = OpVariable %_ptr_Function_float Function %79
-         %gy = OpVariable %_ptr_Function_float Function %79
-         %gz = OpVariable %_ptr_Function_float Function %79
-         %43 = OpAccessChain %_ptr_Uniform_float %uniforms %uint_0 %uint_4 %uint_0
-         %44 = OpLoad %float %43
-         %46 = OpAccessChain %_ptr_Uniform_float %uniforms %uint_0 %uint_4 %uint_1
-         %47 = OpLoad %float %46
-         %49 = OpAccessChain %_ptr_Uniform_float %uniforms %uint_0 %uint_4 %uint_2
-         %50 = OpLoad %float %49
-         %51 = OpCompositeConstruct %v3float %44 %47 %50
-               OpStore %bbMin %51
-         %56 = OpAccessChain %_ptr_Uniform_float %uniforms %uint_0 %uint_5 %uint_0
-         %57 = OpLoad %float %56
-         %58 = OpAccessChain %_ptr_Uniform_float %uniforms %uint_0 %uint_5 %uint_1
-         %59 = OpLoad %float %58
-         %60 = OpAccessChain %_ptr_Uniform_float %uniforms %uint_0 %uint_5 %uint_2
-         %61 = OpLoad %float %60
-         %62 = OpCompositeConstruct %v3float %57 %59 %61
-               OpStore %bbMax %62
-         %64 = OpLoad %v3float %bbMin
-         %65 = OpLoad %v3float %bbMin
-         %66 = OpFSub %v3float %64 %65
-               OpStore %bbSize %66
-         %72 = OpAccessChain %_ptr_Function_float %bbMax %uint_0
-         %73 = OpLoad %float %72
-         %74 = OpAccessChain %_ptr_Function_float %bbMax %uint_1
-         %75 = OpLoad %float %74
-         %70 = OpExtInst %float %69 NMax %73 %75
-         %76 = OpAccessChain %_ptr_Function_float %bbSize %uint_2
-         %77 = OpLoad %float %76
-         %68 = OpExtInst %float %69 NMax %70 %77
-               OpStore %cubeSize %68
-         %82 = OpAccessChain %_ptr_Uniform_uint %uniforms %uint_0 %uint_1
-         %83 = OpLoad %uint %82
-         %80 = OpConvertUToF %float %83
-               OpStore %gridSize %80
-         %85 = OpLoad %float %cubeSize
-         %86 = OpCompositeExtract %float %position 0
-         %87 = OpAccessChain %_ptr_Uniform_float %uniforms %uint_0 %uint_4 %uint_0
-         %88 = OpLoad %float %87
-         %89 = OpFSub %float %86 %88
-         %90 = OpFMul %float %85 %89
-         %91 = OpLoad %float %cubeSize
-         %92 = OpFDiv %float %90 %91
-               OpStore %gx %92
-         %94 = OpLoad %float %gx
-         %95 = OpCompositeExtract %float %position 1
-         %96 = OpAccessChain %_ptr_Uniform_float %uniforms %uint_0 %uint_4 %uint_1
-         %97 = OpLoad %float %96
-         %98 = OpFSub %float %95 %97
-         %99 = OpFMul %float %94 %98
-        %100 = OpLoad %float %gridSize
-        %101 = OpFDiv %float %99 %100
-               OpStore %gy %101
-        %103 = OpLoad %float %gridSize
-        %104 = OpCompositeExtract %float %position 2
-        %105 = OpAccessChain %_ptr_Uniform_float %uniforms %uint_0 %uint_4 %uint_2
-        %106 = OpLoad %float %105
-        %107 = OpFSub %float %104 %106
-        %108 = OpFMul %float %103 %107
-        %109 = OpLoad %float %gridSize
-        %110 = OpFDiv %float %108 %109
-               OpStore %gz %110
-        %112 = OpLoad %float %gz
-        %113 = OpLoad %float %gz
-        %114 = OpLoad %float %gz
-        %115 = OpCompositeConstruct %v3float %112 %113 %114
-               OpReturnValue %115
+         %57 = OpLabel
+      %bbMin = OpVariable %_ptr_Function_v3float Function %71
+      %bbMax = OpVariable %_ptr_Function_v3float Function %71
+     %bbSize = OpVariable %_ptr_Function_v3float Function %71
+   %cubeSize = OpVariable %_ptr_Function_float Function %96
+   %gridSize = OpVariable %_ptr_Function_float Function %96
+         %gx = OpVariable %_ptr_Function_float Function %96
+         %gy = OpVariable %_ptr_Function_float Function %96
+         %gz = OpVariable %_ptr_Function_float Function %96
+         %61 = OpAccessChain %_ptr_Uniform_float %uniforms %uint_0 %uint_4 %uint_0
+         %62 = OpLoad %float %61
+         %63 = OpAccessChain %_ptr_Uniform_float %uniforms %uint_0 %uint_4 %uint_1
+         %64 = OpLoad %float %63
+         %66 = OpAccessChain %_ptr_Uniform_float %uniforms %uint_0 %uint_4 %uint_2
+         %67 = OpLoad %float %66
+         %68 = OpCompositeConstruct %v3float %62 %64 %67
+               OpStore %bbMin %68
+         %73 = OpAccessChain %_ptr_Uniform_float %uniforms %uint_0 %uint_5 %uint_0
+         %74 = OpLoad %float %73
+         %75 = OpAccessChain %_ptr_Uniform_float %uniforms %uint_0 %uint_5 %uint_1
+         %76 = OpLoad %float %75
+         %77 = OpAccessChain %_ptr_Uniform_float %uniforms %uint_0 %uint_5 %uint_2
+         %78 = OpLoad %float %77
+         %79 = OpCompositeConstruct %v3float %74 %76 %78
+               OpStore %bbMax %79
+         %81 = OpLoad %v3float %bbMin
+         %82 = OpLoad %v3float %bbMin
+         %83 = OpFSub %v3float %81 %82
+               OpStore %bbSize %83
+         %89 = OpAccessChain %_ptr_Function_float %bbMax %uint_0
+         %90 = OpLoad %float %89
+         %91 = OpAccessChain %_ptr_Function_float %bbMax %uint_1
+         %92 = OpLoad %float %91
+         %87 = OpExtInst %float %86 NMax %90 %92
+         %93 = OpAccessChain %_ptr_Function_float %bbSize %uint_2
+         %94 = OpLoad %float %93
+         %85 = OpExtInst %float %86 NMax %87 %94
+               OpStore %cubeSize %85
+         %99 = OpAccessChain %_ptr_Uniform_uint %uniforms %uint_0 %uint_1
+        %100 = OpLoad %uint %99
+         %97 = OpConvertUToF %float %100
+               OpStore %gridSize %97
+        %102 = OpLoad %float %cubeSize
+        %103 = OpCompositeExtract %float %position 0
+        %104 = OpAccessChain %_ptr_Uniform_float %uniforms %uint_0 %uint_4 %uint_0
+        %105 = OpLoad %float %104
+        %106 = OpFSub %float %103 %105
+        %107 = OpFMul %float %102 %106
+        %108 = OpLoad %float %cubeSize
+        %109 = OpFDiv %float %107 %108
+               OpStore %gx %109
+        %111 = OpLoad %float %gx
+        %112 = OpCompositeExtract %float %position 1
+        %113 = OpAccessChain %_ptr_Uniform_float %uniforms %uint_0 %uint_4 %uint_1
+        %114 = OpLoad %float %113
+        %115 = OpFSub %float %112 %114
+        %116 = OpFMul %float %111 %115
+        %117 = OpLoad %float %gridSize
+        %118 = OpFDiv %float %116 %117
+               OpStore %gy %118
+        %120 = OpLoad %float %gridSize
+        %121 = OpCompositeExtract %float %position 2
+        %122 = OpAccessChain %_ptr_Uniform_float %uniforms %uint_0 %uint_4 %uint_2
+        %123 = OpLoad %float %122
+        %124 = OpFSub %float %121 %123
+        %125 = OpFMul %float %120 %124
+        %126 = OpLoad %float %gridSize
+        %127 = OpFDiv %float %125 %126
+               OpStore %gz %127
+        %129 = OpLoad %float %gz
+        %130 = OpLoad %float %gz
+        %131 = OpLoad %float %gz
+        %132 = OpCompositeConstruct %v3float %129 %130 %131
+               OpReturnValue %132
                OpFunctionEnd
-  %toIndex1D = OpFunction %uint None %116
+  %toIndex1D = OpFunction %uint None %133
  %gridSize_0 = OpFunctionParameter %uint
    %voxelPos = OpFunctionParameter %v3float
-        %120 = OpLabel
-     %icoord = OpVariable %_ptr_Function_v3uint Function %124
-        %121 = OpConvertFToU %v3uint %voxelPos
-               OpStore %icoord %121
-        %126 = OpAccessChain %_ptr_Function_uint %icoord %uint_0
-        %127 = OpLoad %uint %126
-        %128 = OpAccessChain %_ptr_Function_uint %icoord %uint_1
-        %129 = OpLoad %uint %128
-        %130 = OpIMul %uint %gridSize_0 %129
-        %131 = OpIAdd %uint %127 %130
-        %132 = OpIMul %uint %gridSize_0 %gridSize_0
-        %133 = OpAccessChain %_ptr_Function_uint %icoord %uint_2
-        %134 = OpLoad %uint %133
-        %135 = OpIMul %uint %132 %134
-        %136 = OpIAdd %uint %131 %135
-               OpReturnValue %136
+        %137 = OpLabel
+     %icoord = OpVariable %_ptr_Function_v3uint Function %141
+        %138 = OpConvertFToU %v3uint %voxelPos
+               OpStore %icoord %138
+        %143 = OpAccessChain %_ptr_Function_uint %icoord %uint_0
+        %144 = OpLoad %uint %143
+        %145 = OpAccessChain %_ptr_Function_uint %icoord %uint_1
+        %146 = OpLoad %uint %145
+        %147 = OpIMul %uint %gridSize_0 %146
+        %148 = OpIAdd %uint %144 %147
+        %149 = OpIMul %uint %gridSize_0 %gridSize_0
+        %150 = OpAccessChain %_ptr_Function_uint %icoord %uint_2
+        %151 = OpLoad %uint %150
+        %152 = OpIMul %uint %149 %151
+        %153 = OpIAdd %uint %148 %152
+               OpReturnValue %153
                OpFunctionEnd
-  %toIndex4D = OpFunction %v3uint None %137
+  %toIndex4D = OpFunction %v3uint None %154
  %gridSize_1 = OpFunctionParameter %uint
       %index = OpFunctionParameter %uint
-        %141 = OpLabel
-          %z = OpVariable %_ptr_Function_uint Function %145
-          %y = OpVariable %_ptr_Function_uint Function %145
-          %x = OpVariable %_ptr_Function_uint Function %145
-        %142 = OpIMul %uint %index %index
-        %143 = OpUDiv %uint %gridSize_1 %142
-               OpStore %z %143
-        %146 = OpIMul %uint %gridSize_1 %gridSize_1
-        %147 = OpLoad %uint %z
-        %148 = OpIMul %uint %146 %147
-        %149 = OpISub %uint %gridSize_1 %148
-        %150 = OpUDiv %uint %149 %gridSize_1
-               OpStore %y %150
-        %152 = OpUMod %uint %index %gridSize_1
-               OpStore %x %152
-        %154 = OpLoad %uint %z
-        %155 = OpLoad %uint %y
-        %156 = OpLoad %uint %y
-        %157 = OpCompositeConstruct %v3uint %154 %155 %156
-               OpReturnValue %157
+        %158 = OpLabel
+          %z = OpVariable %_ptr_Function_uint Function %38
+          %y = OpVariable %_ptr_Function_uint Function %38
+          %x = OpVariable %_ptr_Function_uint Function %38
+        %160 = OpIMul %uint %index %index
+        %159 = OpFunctionCall %uint %tint_div %gridSize_1 %160
+               OpStore %z %159
+        %163 = OpIMul %uint %gridSize_1 %gridSize_1
+        %164 = OpLoad %uint %z
+        %165 = OpIMul %uint %163 %164
+        %166 = OpISub %uint %gridSize_1 %165
+        %162 = OpFunctionCall %uint %tint_div %166 %gridSize_1
+               OpStore %y %162
+        %168 = OpFunctionCall %uint %tint_mod %index %gridSize_1
+               OpStore %x %168
+        %170 = OpLoad %uint %z
+        %171 = OpLoad %uint %y
+        %172 = OpLoad %uint %y
+        %173 = OpCompositeConstruct %v3uint %170 %171 %172
+               OpReturnValue %173
                OpFunctionEnd
-%loadPosition = OpFunction %v3float None %158
+%loadPosition = OpFunction %v3float None %174
 %vertexIndex = OpFunctionParameter %uint
-        %161 = OpLabel
- %position_0 = OpVariable %_ptr_Function_v3float Function %54
-        %163 = OpIMul %uint %uint_3 %vertexIndex
-        %164 = OpIAdd %uint %163 %145
-        %166 = OpAccessChain %_ptr_StorageBuffer_float %positions %uint_0 %164
-        %167 = OpLoad %float %166
-        %168 = OpIMul %uint %uint_3 %vertexIndex
-        %169 = OpIAdd %uint %168 %uint_1
-        %170 = OpAccessChain %_ptr_StorageBuffer_float %positions %uint_0 %169
-        %171 = OpLoad %float %170
-        %172 = OpIMul %uint %uint_3 %vertexIndex
-        %173 = OpIAdd %uint %172 %uint_2
-        %174 = OpAccessChain %_ptr_StorageBuffer_float %positions %uint_0 %173
-        %175 = OpLoad %float %174
-        %176 = OpCompositeConstruct %v3float %167 %171 %175
-               OpStore %position_0 %176
-        %178 = OpLoad %v3float %position_0
-               OpReturnValue %178
+        %177 = OpLabel
+ %position_0 = OpVariable %_ptr_Function_v3float Function %71
+        %179 = OpIMul %uint %uint_3 %vertexIndex
+        %180 = OpIAdd %uint %179 %38
+        %182 = OpAccessChain %_ptr_StorageBuffer_float %positions %uint_0 %180
+        %183 = OpLoad %float %182
+        %184 = OpIMul %uint %uint_3 %vertexIndex
+        %185 = OpIAdd %uint %184 %uint_1
+        %186 = OpAccessChain %_ptr_StorageBuffer_float %positions %uint_0 %185
+        %187 = OpLoad %float %186
+        %188 = OpIMul %uint %uint_3 %vertexIndex
+        %189 = OpIAdd %uint %188 %uint_2
+        %190 = OpAccessChain %_ptr_StorageBuffer_float %positions %uint_0 %189
+        %191 = OpLoad %float %190
+        %192 = OpCompositeConstruct %v3float %183 %187 %191
+               OpStore %position_0 %192
+        %194 = OpLoad %v3float %position_0
+               OpReturnValue %194
                OpFunctionEnd
-   %doIgnore = OpFunction %void None %32
-        %180 = OpLabel
-        %g43 = OpVariable %_ptr_Function_uint Function %145
-        %kj6 = OpVariable %_ptr_Function_uint Function %145
-        %b53 = OpVariable %_ptr_Function_uint Function %145
-        %rwg = OpVariable %_ptr_Function_uint Function %145
-        %rb5 = OpVariable %_ptr_Function_float Function %79
-        %g55 = OpVariable %_ptr_Function_int Function %190
-        %181 = OpAccessChain %_ptr_Uniform_uint %uniforms %uint_0 %uint_0
-        %182 = OpLoad %uint %181
-               OpStore %g43 %182
-        %185 = OpAccessChain %_ptr_StorageBuffer_uint %dbg %uint_0 %uint_5
-        %186 = OpLoad %uint %185
-               OpStore %kj6 %186
-        %192 = OpAccessChain %_ptr_StorageBuffer_uint_0 %counters %uint_0 %190
-        %188 = OpAtomicLoad %uint %192 %uint_1 %uint_0
-               OpStore %b53 %188
-        %194 = OpAccessChain %_ptr_StorageBuffer_uint %indices %uint_0 %190
-        %195 = OpLoad %uint %194
-               OpStore %rwg %195
-        %197 = OpAccessChain %_ptr_StorageBuffer_float %positions %uint_0 %190
-        %198 = OpLoad %float %197
-               OpStore %rb5 %198
-        %203 = OpAccessChain %_ptr_StorageBuffer_int %LUT %uint_0 %190
-        %200 = OpAtomicLoad %int %203 %uint_1 %uint_0
-               OpStore %g55 %200
+   %doIgnore = OpFunction %void None %50
+        %196 = OpLabel
+        %g43 = OpVariable %_ptr_Function_uint Function %38
+        %kj6 = OpVariable %_ptr_Function_uint Function %38
+        %b53 = OpVariable %_ptr_Function_uint Function %38
+        %rwg = OpVariable %_ptr_Function_uint Function %38
+        %rb5 = OpVariable %_ptr_Function_float Function %96
+        %g55 = OpVariable %_ptr_Function_int Function %206
+        %197 = OpAccessChain %_ptr_Uniform_uint %uniforms %uint_0 %uint_0
+        %198 = OpLoad %uint %197
+               OpStore %g43 %198
+        %201 = OpAccessChain %_ptr_StorageBuffer_uint %dbg %uint_0 %uint_5
+        %202 = OpLoad %uint %201
+               OpStore %kj6 %202
+        %208 = OpAccessChain %_ptr_StorageBuffer_uint_0 %counters %uint_0 %206
+        %204 = OpAtomicLoad %uint %208 %uint_1 %uint_0
+               OpStore %b53 %204
+        %210 = OpAccessChain %_ptr_StorageBuffer_uint %indices %uint_0 %206
+        %211 = OpLoad %uint %210
+               OpStore %rwg %211
+        %213 = OpAccessChain %_ptr_StorageBuffer_float %positions %uint_0 %206
+        %214 = OpLoad %float %213
+               OpStore %rb5 %214
+        %219 = OpAccessChain %_ptr_StorageBuffer_int %LUT %uint_0 %206
+        %216 = OpAtomicLoad %int %219 %uint_1 %uint_0
+               OpStore %g55 %216
                OpReturn
                OpFunctionEnd
-%main_count_inner = OpFunction %void None %206
+%main_count_inner = OpFunction %void None %222
 %GlobalInvocationID = OpFunctionParameter %v3uint
-        %209 = OpLabel
-%triangleIndex = OpVariable %_ptr_Function_uint Function %145
-         %i0 = OpVariable %_ptr_Function_uint Function %145
-         %i1 = OpVariable %_ptr_Function_uint Function %145
-         %i2 = OpVariable %_ptr_Function_uint Function %145
-         %p0 = OpVariable %_ptr_Function_v3float Function %54
-         %p1 = OpVariable %_ptr_Function_v3float Function %54
-         %p2 = OpVariable %_ptr_Function_v3float Function %54
-        %254 = OpVariable %_ptr_Function_v3float Function %54
-     %center = OpVariable %_ptr_Function_v3float Function %54
- %voxelPos_0 = OpVariable %_ptr_Function_v3float Function %54
-     %lIndex = OpVariable %_ptr_Function_uint Function %145
-%triangleOffset = OpVariable %_ptr_Function_int Function %190
-        %210 = OpCompositeExtract %uint %GlobalInvocationID 0
-               OpStore %triangleIndex %210
-        %212 = OpLoad %uint %triangleIndex
-        %213 = OpAccessChain %_ptr_Uniform_uint %uniforms %uint_0 %uint_0
-        %214 = OpLoad %uint %213
-        %215 = OpUGreaterThanEqual %bool %212 %214
-               OpSelectionMerge %217 None
-               OpBranchConditional %215 %218 %217
-        %218 = OpLabel
-               OpReturn
-        %217 = OpLabel
-        %219 = OpFunctionCall %void %doIgnore
-        %220 = OpLoad %uint %triangleIndex
-        %221 = OpIMul %uint %uint_3 %220
-        %222 = OpIAdd %uint %221 %145
-        %223 = OpAccessChain %_ptr_StorageBuffer_uint %indices %uint_0 %222
-        %224 = OpLoad %uint %223
-               OpStore %i0 %224
-        %226 = OpLoad %uint %i0
-        %227 = OpIMul %uint %uint_3 %226
-        %228 = OpIAdd %uint %227 %uint_1
-        %229 = OpAccessChain %_ptr_StorageBuffer_uint %indices %uint_0 %228
+        %225 = OpLabel
+%triangleIndex = OpVariable %_ptr_Function_uint Function %38
+         %i0 = OpVariable %_ptr_Function_uint Function %38
+         %i1 = OpVariable %_ptr_Function_uint Function %38
+         %i2 = OpVariable %_ptr_Function_uint Function %38
+         %p0 = OpVariable %_ptr_Function_v3float Function %71
+         %p1 = OpVariable %_ptr_Function_v3float Function %71
+         %p2 = OpVariable %_ptr_Function_v3float Function %71
+        %269 = OpVariable %_ptr_Function_v3float Function %71
+     %center = OpVariable %_ptr_Function_v3float Function %71
+ %voxelPos_0 = OpVariable %_ptr_Function_v3float Function %71
+     %lIndex = OpVariable %_ptr_Function_uint Function %38
+%triangleOffset = OpVariable %_ptr_Function_int Function %206
+        %226 = OpCompositeExtract %uint %GlobalInvocationID 0
+               OpStore %triangleIndex %226
+        %228 = OpLoad %uint %triangleIndex
+        %229 = OpAccessChain %_ptr_Uniform_uint %uniforms %uint_0 %uint_0
         %230 = OpLoad %uint %229
-               OpStore %i1 %230
-        %232 = OpLoad %uint %i0
-        %233 = OpIMul %uint %uint_3 %232
-        %234 = OpIAdd %uint %233 %uint_2
-        %235 = OpAccessChain %_ptr_StorageBuffer_uint %indices %uint_0 %234
-        %236 = OpLoad %uint %235
-               OpStore %i2 %236
-        %239 = OpLoad %uint %i0
-        %238 = OpFunctionCall %v3float %loadPosition %239
-               OpStore %p0 %238
-        %242 = OpLoad %uint %i0
-        %241 = OpFunctionCall %v3float %loadPosition %242
-               OpStore %p1 %241
-        %245 = OpLoad %uint %i2
-        %244 = OpFunctionCall %v3float %loadPosition %245
-               OpStore %p2 %244
-        %247 = OpLoad %v3float %p0
-        %248 = OpLoad %v3float %p2
-        %249 = OpFAdd %v3float %247 %248
-        %250 = OpLoad %v3float %p1
-        %251 = OpFAdd %v3float %249 %250
-        %255 = OpCompositeConstruct %v3float %float_3 %float_3 %float_3
-        %253 = OpFDiv %v3float %251 %255
-               OpStore %center %253
-        %258 = OpLoad %v3float %p1
-        %257 = OpFunctionCall %v3float %toVoxelPos %258
-               OpStore %voxelPos_0 %257
-        %261 = OpAccessChain %_ptr_Uniform_uint %uniforms %uint_0 %uint_1
-        %262 = OpLoad %uint %261
-        %263 = OpLoad %v3float %p0
-        %260 = OpFunctionCall %uint %toIndex1D %262 %263
-               OpStore %lIndex %260
-        %267 = OpLoad %uint %i1
-        %268 = OpAccessChain %_ptr_StorageBuffer_int %LUT %uint_0 %267
-        %265 = OpAtomicIAdd %int %268 %uint_1 %uint_0 %int_1
-               OpStore %triangleOffset %265
+        %231 = OpUGreaterThanEqual %bool %228 %230
+               OpSelectionMerge %232 None
+               OpBranchConditional %231 %233 %232
+        %233 = OpLabel
+               OpReturn
+        %232 = OpLabel
+        %234 = OpFunctionCall %void %doIgnore
+        %235 = OpLoad %uint %triangleIndex
+        %236 = OpIMul %uint %uint_3 %235
+        %237 = OpIAdd %uint %236 %38
+        %238 = OpAccessChain %_ptr_StorageBuffer_uint %indices %uint_0 %237
+        %239 = OpLoad %uint %238
+               OpStore %i0 %239
+        %241 = OpLoad %uint %i0
+        %242 = OpIMul %uint %uint_3 %241
+        %243 = OpIAdd %uint %242 %uint_1
+        %244 = OpAccessChain %_ptr_StorageBuffer_uint %indices %uint_0 %243
+        %245 = OpLoad %uint %244
+               OpStore %i1 %245
+        %247 = OpLoad %uint %i0
+        %248 = OpIMul %uint %uint_3 %247
+        %249 = OpIAdd %uint %248 %uint_2
+        %250 = OpAccessChain %_ptr_StorageBuffer_uint %indices %uint_0 %249
+        %251 = OpLoad %uint %250
+               OpStore %i2 %251
+        %254 = OpLoad %uint %i0
+        %253 = OpFunctionCall %v3float %loadPosition %254
+               OpStore %p0 %253
+        %257 = OpLoad %uint %i0
+        %256 = OpFunctionCall %v3float %loadPosition %257
+               OpStore %p1 %256
+        %260 = OpLoad %uint %i2
+        %259 = OpFunctionCall %v3float %loadPosition %260
+               OpStore %p2 %259
+        %262 = OpLoad %v3float %p0
+        %263 = OpLoad %v3float %p2
+        %264 = OpFAdd %v3float %262 %263
+        %265 = OpLoad %v3float %p1
+        %266 = OpFAdd %v3float %264 %265
+        %270 = OpCompositeConstruct %v3float %float_3 %float_3 %float_3
+        %268 = OpFDiv %v3float %266 %270
+               OpStore %center %268
+        %273 = OpLoad %v3float %p1
+        %272 = OpFunctionCall %v3float %toVoxelPos %273
+               OpStore %voxelPos_0 %272
+        %276 = OpAccessChain %_ptr_Uniform_uint %uniforms %uint_0 %uint_1
+        %277 = OpLoad %uint %276
+        %278 = OpLoad %v3float %p0
+        %275 = OpFunctionCall %uint %toIndex1D %277 %278
+               OpStore %lIndex %275
+        %282 = OpLoad %uint %i1
+        %283 = OpAccessChain %_ptr_StorageBuffer_int %LUT %uint_0 %282
+        %280 = OpAtomicIAdd %int %283 %uint_1 %uint_0 %int_1
+               OpStore %triangleOffset %280
                OpReturn
                OpFunctionEnd
- %main_count = OpFunction %void None %32
-        %272 = OpLabel
-        %274 = OpLoad %v3uint %GlobalInvocationID_1
-        %273 = OpFunctionCall %void %main_count_inner %274
+ %main_count = OpFunction %void None %50
+        %287 = OpLabel
+        %289 = OpLoad %v3uint %GlobalInvocationID_1
+        %288 = OpFunctionCall %void %main_count_inner %289
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/bug/tint/1083.wgsl.expected.dxc.hlsl b/test/tint/bug/tint/1083.wgsl.expected.dxc.hlsl
index a1dedc8..2ce1859 100644
--- a/test/tint/bug/tint/1083.wgsl.expected.dxc.hlsl
+++ b/test/tint/bug/tint/1083.wgsl.expected.dxc.hlsl
@@ -1,7 +1,11 @@
+int tint_div(int lhs, int rhs) {
+  return (lhs / (((rhs == 0) | ((lhs == -2147483648) & (rhs == -1))) ? 1 : rhs));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   const int a = 1;
   const int b = 0;
-  const int c = (a / (b == 0 ? 1 : b));
+  const int c = tint_div(a, b);
   return;
 }
diff --git a/test/tint/bug/tint/1083.wgsl.expected.fxc.hlsl b/test/tint/bug/tint/1083.wgsl.expected.fxc.hlsl
index a1dedc8..2ce1859 100644
--- a/test/tint/bug/tint/1083.wgsl.expected.fxc.hlsl
+++ b/test/tint/bug/tint/1083.wgsl.expected.fxc.hlsl
@@ -1,7 +1,11 @@
+int tint_div(int lhs, int rhs) {
+  return (lhs / (((rhs == 0) | ((lhs == -2147483648) & (rhs == -1))) ? 1 : rhs));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   const int a = 1;
   const int b = 0;
-  const int c = (a / (b == 0 ? 1 : b));
+  const int c = tint_div(a, b);
   return;
 }
diff --git a/test/tint/bug/tint/1083.wgsl.expected.glsl b/test/tint/bug/tint/1083.wgsl.expected.glsl
index 0054f12..28c473f 100644
--- a/test/tint/bug/tint/1083.wgsl.expected.glsl
+++ b/test/tint/bug/tint/1083.wgsl.expected.glsl
@@ -1,9 +1,13 @@
 #version 310 es
 
+int tint_div(int lhs, int rhs) {
+  return (lhs / (bool(uint((rhs == 0)) | uint(bool(uint((lhs == -2147483648)) & uint((rhs == -1))))) ? 1 : rhs));
+}
+
 void f() {
   int a = 1;
   int b = 0;
-  int c = (a / b);
+  int c = tint_div(a, b);
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/bug/tint/1083.wgsl.expected.msl b/test/tint/bug/tint/1083.wgsl.expected.msl
index 08beb2b..0a3dd41 100644
--- a/test/tint/bug/tint/1083.wgsl.expected.msl
+++ b/test/tint/bug/tint/1083.wgsl.expected.msl
@@ -1,10 +1,14 @@
 #include <metal_stdlib>
 
 using namespace metal;
+int tint_div(int lhs, int rhs) {
+  return (lhs / select(rhs, 1, bool((rhs == 0) | bool((lhs == (-2147483647 - 1)) & (rhs == -1)))));
+}
+
 kernel void f() {
   int const a = 1;
   int const b = 0;
-  int const c = (a / b);
+  int const c = tint_div(a, b);
   return;
 }
 
diff --git a/test/tint/bug/tint/1083.wgsl.expected.spvasm b/test/tint/bug/tint/1083.wgsl.expected.spvasm
index fa188bd..162cf50 100644
--- a/test/tint/bug/tint/1083.wgsl.expected.spvasm
+++ b/test/tint/bug/tint/1083.wgsl.expected.spvasm
@@ -1,20 +1,40 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 9
+; Bound: 24
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %f "f"
                OpExecutionMode %f LocalSize 1 1 1
+               OpName %tint_div "tint_div"
+               OpName %lhs "lhs"
+               OpName %rhs "rhs"
                OpName %f "f"
-       %void = OpTypeVoid
-          %1 = OpTypeFunction %void
         %int = OpTypeInt 32 1
+          %1 = OpTypeFunction %int %int %int
+          %8 = OpConstantNull %int
+       %bool = OpTypeBool
+%int_n2147483648 = OpConstant %int -2147483648
+     %int_n1 = OpConstant %int -1
       %int_1 = OpConstant %int 1
-          %7 = OpConstantNull %int
-          %f = OpFunction %void None %1
-          %4 = OpLabel
-          %8 = OpSDiv %int %int_1 %7
+       %void = OpTypeVoid
+         %19 = OpTypeFunction %void
+   %tint_div = OpFunction %int None %1
+        %lhs = OpFunctionParameter %int
+        %rhs = OpFunctionParameter %int
+          %6 = OpLabel
+          %9 = OpIEqual %bool %rhs %8
+         %12 = OpIEqual %bool %lhs %int_n2147483648
+         %14 = OpIEqual %bool %rhs %int_n1
+         %15 = OpLogicalAnd %bool %12 %14
+         %16 = OpLogicalOr %bool %9 %15
+          %7 = OpSelect %int %16 %int_1 %rhs
+         %18 = OpSDiv %int %lhs %7
+               OpReturnValue %18
+               OpFunctionEnd
+          %f = OpFunction %void None %19
+         %22 = OpLabel
+         %23 = OpFunctionCall %int %tint_div %int_1 %8
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/bug/tint/1113.wgsl.expected.dxc.hlsl b/test/tint/bug/tint/1113.wgsl.expected.dxc.hlsl
index 978093c..6a0326e 100644
--- a/test/tint/bug/tint/1113.wgsl.expected.dxc.hlsl
+++ b/test/tint/bug/tint/1113.wgsl.expected.dxc.hlsl
@@ -1,5 +1,9 @@
-uint value_or_one_if_zero_uint(uint value) {
-  return value == 0u ? 1u : value;
+uint tint_div(uint lhs, uint rhs) {
+  return (lhs / ((rhs == 0u) ? 1u : rhs));
+}
+
+uint tint_mod(uint lhs, uint rhs) {
+  return (lhs % ((rhs == 0u) ? 1u : rhs));
 }
 
 cbuffer cbuffer_uniforms : register(b0, space0) {
@@ -29,9 +33,9 @@
 }
 
 uint3 toIndex3D(uint gridSize, uint index) {
-  uint z_1 = (index / value_or_one_if_zero_uint((gridSize * gridSize)));
-  uint y_1 = ((index - ((gridSize * gridSize) * z_1)) / (gridSize == 0u ? 1u : gridSize));
-  uint x_1 = (index % (gridSize == 0u ? 1u : gridSize));
+  uint z_1 = tint_div(index, (gridSize * gridSize));
+  uint y_1 = tint_div((index - ((gridSize * gridSize) * z_1)), gridSize);
+  uint x_1 = tint_mod(index, gridSize);
   return uint3(x_1, y_1, z_1);
 }
 
diff --git a/test/tint/bug/tint/1113.wgsl.expected.fxc.hlsl b/test/tint/bug/tint/1113.wgsl.expected.fxc.hlsl
index 978093c..6a0326e 100644
--- a/test/tint/bug/tint/1113.wgsl.expected.fxc.hlsl
+++ b/test/tint/bug/tint/1113.wgsl.expected.fxc.hlsl
@@ -1,5 +1,9 @@
-uint value_or_one_if_zero_uint(uint value) {
-  return value == 0u ? 1u : value;
+uint tint_div(uint lhs, uint rhs) {
+  return (lhs / ((rhs == 0u) ? 1u : rhs));
+}
+
+uint tint_mod(uint lhs, uint rhs) {
+  return (lhs % ((rhs == 0u) ? 1u : rhs));
 }
 
 cbuffer cbuffer_uniforms : register(b0, space0) {
@@ -29,9 +33,9 @@
 }
 
 uint3 toIndex3D(uint gridSize, uint index) {
-  uint z_1 = (index / value_or_one_if_zero_uint((gridSize * gridSize)));
-  uint y_1 = ((index - ((gridSize * gridSize) * z_1)) / (gridSize == 0u ? 1u : gridSize));
-  uint x_1 = (index % (gridSize == 0u ? 1u : gridSize));
+  uint z_1 = tint_div(index, (gridSize * gridSize));
+  uint y_1 = tint_div((index - ((gridSize * gridSize) * z_1)), gridSize);
+  uint x_1 = tint_mod(index, gridSize);
   return uint3(x_1, y_1, z_1);
 }
 
diff --git a/test/tint/bug/tint/1113.wgsl.expected.msl b/test/tint/bug/tint/1113.wgsl.expected.msl
index bf546c1..0ab0884 100644
--- a/test/tint/bug/tint/1113.wgsl.expected.msl
+++ b/test/tint/bug/tint/1113.wgsl.expected.msl
@@ -14,6 +14,14 @@
     T elements[N];
 };
 
+uint tint_div(uint lhs, uint rhs) {
+  return (lhs / select(rhs, 1u, (rhs == 0u)));
+}
+
+uint tint_mod(uint lhs, uint rhs) {
+  return (lhs % select(rhs, 1u, (rhs == 0u)));
+}
+
 struct Uniforms {
   /* 0x0000 */ uint numTriangles;
   /* 0x0004 */ uint gridSize;
@@ -78,9 +86,9 @@
 }
 
 uint3 toIndex3D(uint gridSize, uint index) {
-  uint z_1 = (index / (gridSize * gridSize));
-  uint y_1 = ((index - ((gridSize * gridSize) * z_1)) / gridSize);
-  uint x_1 = (index % gridSize);
+  uint z_1 = tint_div(index, (gridSize * gridSize));
+  uint y_1 = tint_div((index - ((gridSize * gridSize) * z_1)), gridSize);
+  uint x_1 = tint_mod(index, gridSize);
   return uint3(x_1, y_1, z_1);
 }
 
diff --git a/test/tint/bug/tint/1113.wgsl.expected.spvasm b/test/tint/bug/tint/1113.wgsl.expected.spvasm
index ae2be84..f1eee0c 100644
--- a/test/tint/bug/tint/1113.wgsl.expected.spvasm
+++ b/test/tint/bug/tint/1113.wgsl.expected.spvasm
@@ -1,10 +1,10 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 404
+; Bound: 419
 ; Schema: 0
                OpCapability Shader
-         %67 = OpExtInstImport "GLSL.std.450"
+         %84 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %main_count "main_count" %GlobalInvocationID_1
                OpEntryPoint GLCompute %main_create_lut "main_create_lut" %GlobalInvocationID_2
@@ -53,6 +53,12 @@
                OpMemberName %Dbg 10 "value_f32_2"
                OpMemberName %Dbg 11 "value_f32_3"
                OpName %dbg "dbg"
+               OpName %tint_div "tint_div"
+               OpName %lhs "lhs"
+               OpName %rhs "rhs"
+               OpName %tint_mod "tint_mod"
+               OpName %lhs_0 "lhs"
+               OpName %rhs_0 "rhs"
                OpName %toVoxelPos "toVoxelPos"
                OpName %position "position"
                OpName %bbMin "bbMin"
@@ -201,452 +207,471 @@
   %dbg_block = OpTypeStruct %Dbg
 %_ptr_StorageBuffer_dbg_block = OpTypePointer StorageBuffer %dbg_block
         %dbg = OpVariable %_ptr_StorageBuffer_dbg_block StorageBuffer
-         %34 = OpTypeFunction %v3float %v3float
+         %34 = OpTypeFunction %uint %uint %uint
+         %40 = OpConstantNull %uint
+       %bool = OpTypeBool
+     %uint_1 = OpConstant %uint 1
+         %52 = OpTypeFunction %v3float %v3float
      %uint_0 = OpConstant %uint 0
      %uint_4 = OpConstant %uint 4
 %_ptr_Uniform_float = OpTypePointer Uniform %float
-     %uint_1 = OpConstant %uint 1
      %uint_2 = OpConstant %uint 2
 %_ptr_Function_v3float = OpTypePointer Function %v3float
-         %52 = OpConstantNull %v3float
+         %69 = OpConstantNull %v3float
      %uint_5 = OpConstant %uint 5
 %_ptr_Function_float = OpTypePointer Function %float
-         %77 = OpConstantNull %float
+         %94 = OpConstantNull %float
 %_ptr_Uniform_uint = OpTypePointer Uniform %uint
-        %114 = OpTypeFunction %uint %uint %v3float
+        %131 = OpTypeFunction %uint %uint %v3float
 %_ptr_Function_v3uint = OpTypePointer Function %v3uint
-        %122 = OpConstantNull %v3uint
+        %139 = OpConstantNull %v3uint
 %_ptr_Function_uint = OpTypePointer Function %uint
-        %135 = OpTypeFunction %v3uint %uint %uint
-        %143 = OpConstantNull %uint
-        %156 = OpTypeFunction %v3float %uint
+        %152 = OpTypeFunction %v3uint %uint %uint
+        %172 = OpTypeFunction %v3float %uint
      %uint_3 = OpConstant %uint 3
 %_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %float
        %void = OpTypeVoid
-        %177 = OpTypeFunction %void
+        %193 = OpTypeFunction %void
 %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
-        %190 = OpConstantNull %int
+        %206 = OpConstantNull %int
 %_ptr_StorageBuffer_uint_0 = OpTypePointer StorageBuffer %uint
 %_ptr_StorageBuffer_int = OpTypePointer StorageBuffer %int
 %_ptr_Function_int = OpTypePointer Function %int
-        %206 = OpTypeFunction %void %v3uint
-       %bool = OpTypeBool
+        %222 = OpTypeFunction %void %v3uint
     %float_3 = OpConstant %float 3
      %uint_8 = OpConstant %uint 8
      %uint_9 = OpConstant %uint 9
     %uint_10 = OpConstant %uint 10
      %int_n1 = OpConstant %int -1
       %int_1 = OpConstant %int 1
- %toVoxelPos = OpFunction %v3float None %34
-   %position = OpFunctionParameter %v3float
-         %37 = OpLabel
-      %bbMin = OpVariable %_ptr_Function_v3float Function %52
-      %bbMax = OpVariable %_ptr_Function_v3float Function %52
-     %bbSize = OpVariable %_ptr_Function_v3float Function %52
-   %cubeSize = OpVariable %_ptr_Function_float Function %77
-   %gridSize = OpVariable %_ptr_Function_float Function %77
-         %gx = OpVariable %_ptr_Function_float Function %77
-         %gy = OpVariable %_ptr_Function_float Function %77
-         %gz = OpVariable %_ptr_Function_float Function %77
-         %41 = OpAccessChain %_ptr_Uniform_float %uniforms %uint_0 %uint_4 %uint_0
-         %42 = OpLoad %float %41
-         %44 = OpAccessChain %_ptr_Uniform_float %uniforms %uint_0 %uint_4 %uint_1
-         %45 = OpLoad %float %44
-         %47 = OpAccessChain %_ptr_Uniform_float %uniforms %uint_0 %uint_4 %uint_2
-         %48 = OpLoad %float %47
-         %49 = OpCompositeConstruct %v3float %42 %45 %48
-               OpStore %bbMin %49
-         %54 = OpAccessChain %_ptr_Uniform_float %uniforms %uint_0 %uint_5 %uint_0
-         %55 = OpLoad %float %54
-         %56 = OpAccessChain %_ptr_Uniform_float %uniforms %uint_0 %uint_5 %uint_1
-         %57 = OpLoad %float %56
-         %58 = OpAccessChain %_ptr_Uniform_float %uniforms %uint_0 %uint_5 %uint_2
-         %59 = OpLoad %float %58
-         %60 = OpCompositeConstruct %v3float %55 %57 %59
-               OpStore %bbMax %60
-         %62 = OpLoad %v3float %bbMax
-         %63 = OpLoad %v3float %bbMin
-         %64 = OpFSub %v3float %62 %63
-               OpStore %bbSize %64
-         %70 = OpAccessChain %_ptr_Function_float %bbSize %uint_0
-         %71 = OpLoad %float %70
-         %72 = OpAccessChain %_ptr_Function_float %bbSize %uint_1
-         %73 = OpLoad %float %72
-         %68 = OpExtInst %float %67 NMax %71 %73
-         %74 = OpAccessChain %_ptr_Function_float %bbSize %uint_2
-         %75 = OpLoad %float %74
-         %66 = OpExtInst %float %67 NMax %68 %75
-               OpStore %cubeSize %66
-         %80 = OpAccessChain %_ptr_Uniform_uint %uniforms %uint_0 %uint_1
-         %81 = OpLoad %uint %80
-         %78 = OpConvertUToF %float %81
-               OpStore %gridSize %78
-         %83 = OpLoad %float %gridSize
-         %84 = OpCompositeExtract %float %position 0
-         %85 = OpAccessChain %_ptr_Uniform_float %uniforms %uint_0 %uint_4 %uint_0
-         %86 = OpLoad %float %85
-         %87 = OpFSub %float %84 %86
-         %88 = OpFMul %float %83 %87
-         %89 = OpLoad %float %cubeSize
-         %90 = OpFDiv %float %88 %89
-               OpStore %gx %90
-         %92 = OpLoad %float %gridSize
-         %93 = OpCompositeExtract %float %position 1
-         %94 = OpAccessChain %_ptr_Uniform_float %uniforms %uint_0 %uint_4 %uint_1
-         %95 = OpLoad %float %94
-         %96 = OpFSub %float %93 %95
-         %97 = OpFMul %float %92 %96
-         %98 = OpLoad %float %cubeSize
-         %99 = OpFDiv %float %97 %98
-               OpStore %gy %99
-        %101 = OpLoad %float %gridSize
-        %102 = OpCompositeExtract %float %position 2
-        %103 = OpAccessChain %_ptr_Uniform_float %uniforms %uint_0 %uint_4 %uint_2
-        %104 = OpLoad %float %103
-        %105 = OpFSub %float %102 %104
-        %106 = OpFMul %float %101 %105
-        %107 = OpLoad %float %cubeSize
-        %108 = OpFDiv %float %106 %107
-               OpStore %gz %108
-        %110 = OpLoad %float %gx
-        %111 = OpLoad %float %gy
-        %112 = OpLoad %float %gz
-        %113 = OpCompositeConstruct %v3float %110 %111 %112
-               OpReturnValue %113
+   %tint_div = OpFunction %uint None %34
+        %lhs = OpFunctionParameter %uint
+        %rhs = OpFunctionParameter %uint
+         %38 = OpLabel
+         %41 = OpIEqual %bool %rhs %40
+         %39 = OpSelect %uint %41 %uint_1 %rhs
+         %44 = OpUDiv %uint %lhs %39
+               OpReturnValue %44
                OpFunctionEnd
-  %toIndex1D = OpFunction %uint None %114
+   %tint_mod = OpFunction %uint None %34
+      %lhs_0 = OpFunctionParameter %uint
+      %rhs_0 = OpFunctionParameter %uint
+         %48 = OpLabel
+         %50 = OpIEqual %bool %rhs_0 %40
+         %49 = OpSelect %uint %50 %uint_1 %rhs_0
+         %51 = OpUMod %uint %lhs_0 %49
+               OpReturnValue %51
+               OpFunctionEnd
+ %toVoxelPos = OpFunction %v3float None %52
+   %position = OpFunctionParameter %v3float
+         %55 = OpLabel
+      %bbMin = OpVariable %_ptr_Function_v3float Function %69
+      %bbMax = OpVariable %_ptr_Function_v3float Function %69
+     %bbSize = OpVariable %_ptr_Function_v3float Function %69
+   %cubeSize = OpVariable %_ptr_Function_float Function %94
+   %gridSize = OpVariable %_ptr_Function_float Function %94
+         %gx = OpVariable %_ptr_Function_float Function %94
+         %gy = OpVariable %_ptr_Function_float Function %94
+         %gz = OpVariable %_ptr_Function_float Function %94
+         %59 = OpAccessChain %_ptr_Uniform_float %uniforms %uint_0 %uint_4 %uint_0
+         %60 = OpLoad %float %59
+         %61 = OpAccessChain %_ptr_Uniform_float %uniforms %uint_0 %uint_4 %uint_1
+         %62 = OpLoad %float %61
+         %64 = OpAccessChain %_ptr_Uniform_float %uniforms %uint_0 %uint_4 %uint_2
+         %65 = OpLoad %float %64
+         %66 = OpCompositeConstruct %v3float %60 %62 %65
+               OpStore %bbMin %66
+         %71 = OpAccessChain %_ptr_Uniform_float %uniforms %uint_0 %uint_5 %uint_0
+         %72 = OpLoad %float %71
+         %73 = OpAccessChain %_ptr_Uniform_float %uniforms %uint_0 %uint_5 %uint_1
+         %74 = OpLoad %float %73
+         %75 = OpAccessChain %_ptr_Uniform_float %uniforms %uint_0 %uint_5 %uint_2
+         %76 = OpLoad %float %75
+         %77 = OpCompositeConstruct %v3float %72 %74 %76
+               OpStore %bbMax %77
+         %79 = OpLoad %v3float %bbMax
+         %80 = OpLoad %v3float %bbMin
+         %81 = OpFSub %v3float %79 %80
+               OpStore %bbSize %81
+         %87 = OpAccessChain %_ptr_Function_float %bbSize %uint_0
+         %88 = OpLoad %float %87
+         %89 = OpAccessChain %_ptr_Function_float %bbSize %uint_1
+         %90 = OpLoad %float %89
+         %85 = OpExtInst %float %84 NMax %88 %90
+         %91 = OpAccessChain %_ptr_Function_float %bbSize %uint_2
+         %92 = OpLoad %float %91
+         %83 = OpExtInst %float %84 NMax %85 %92
+               OpStore %cubeSize %83
+         %97 = OpAccessChain %_ptr_Uniform_uint %uniforms %uint_0 %uint_1
+         %98 = OpLoad %uint %97
+         %95 = OpConvertUToF %float %98
+               OpStore %gridSize %95
+        %100 = OpLoad %float %gridSize
+        %101 = OpCompositeExtract %float %position 0
+        %102 = OpAccessChain %_ptr_Uniform_float %uniforms %uint_0 %uint_4 %uint_0
+        %103 = OpLoad %float %102
+        %104 = OpFSub %float %101 %103
+        %105 = OpFMul %float %100 %104
+        %106 = OpLoad %float %cubeSize
+        %107 = OpFDiv %float %105 %106
+               OpStore %gx %107
+        %109 = OpLoad %float %gridSize
+        %110 = OpCompositeExtract %float %position 1
+        %111 = OpAccessChain %_ptr_Uniform_float %uniforms %uint_0 %uint_4 %uint_1
+        %112 = OpLoad %float %111
+        %113 = OpFSub %float %110 %112
+        %114 = OpFMul %float %109 %113
+        %115 = OpLoad %float %cubeSize
+        %116 = OpFDiv %float %114 %115
+               OpStore %gy %116
+        %118 = OpLoad %float %gridSize
+        %119 = OpCompositeExtract %float %position 2
+        %120 = OpAccessChain %_ptr_Uniform_float %uniforms %uint_0 %uint_4 %uint_2
+        %121 = OpLoad %float %120
+        %122 = OpFSub %float %119 %121
+        %123 = OpFMul %float %118 %122
+        %124 = OpLoad %float %cubeSize
+        %125 = OpFDiv %float %123 %124
+               OpStore %gz %125
+        %127 = OpLoad %float %gx
+        %128 = OpLoad %float %gy
+        %129 = OpLoad %float %gz
+        %130 = OpCompositeConstruct %v3float %127 %128 %129
+               OpReturnValue %130
+               OpFunctionEnd
+  %toIndex1D = OpFunction %uint None %131
  %gridSize_0 = OpFunctionParameter %uint
    %voxelPos = OpFunctionParameter %v3float
-        %118 = OpLabel
-     %icoord = OpVariable %_ptr_Function_v3uint Function %122
-        %119 = OpConvertFToU %v3uint %voxelPos
-               OpStore %icoord %119
-        %124 = OpAccessChain %_ptr_Function_uint %icoord %uint_0
-        %125 = OpLoad %uint %124
-        %126 = OpAccessChain %_ptr_Function_uint %icoord %uint_1
-        %127 = OpLoad %uint %126
-        %128 = OpIMul %uint %gridSize_0 %127
-        %129 = OpIAdd %uint %125 %128
-        %130 = OpIMul %uint %gridSize_0 %gridSize_0
-        %131 = OpAccessChain %_ptr_Function_uint %icoord %uint_2
-        %132 = OpLoad %uint %131
-        %133 = OpIMul %uint %130 %132
-        %134 = OpIAdd %uint %129 %133
-               OpReturnValue %134
+        %135 = OpLabel
+     %icoord = OpVariable %_ptr_Function_v3uint Function %139
+        %136 = OpConvertFToU %v3uint %voxelPos
+               OpStore %icoord %136
+        %141 = OpAccessChain %_ptr_Function_uint %icoord %uint_0
+        %142 = OpLoad %uint %141
+        %143 = OpAccessChain %_ptr_Function_uint %icoord %uint_1
+        %144 = OpLoad %uint %143
+        %145 = OpIMul %uint %gridSize_0 %144
+        %146 = OpIAdd %uint %142 %145
+        %147 = OpIMul %uint %gridSize_0 %gridSize_0
+        %148 = OpAccessChain %_ptr_Function_uint %icoord %uint_2
+        %149 = OpLoad %uint %148
+        %150 = OpIMul %uint %147 %149
+        %151 = OpIAdd %uint %146 %150
+               OpReturnValue %151
                OpFunctionEnd
-  %toIndex3D = OpFunction %v3uint None %135
+  %toIndex3D = OpFunction %v3uint None %152
  %gridSize_1 = OpFunctionParameter %uint
       %index = OpFunctionParameter %uint
-        %139 = OpLabel
-          %z = OpVariable %_ptr_Function_uint Function %143
-          %y = OpVariable %_ptr_Function_uint Function %143
-          %x = OpVariable %_ptr_Function_uint Function %143
-        %140 = OpIMul %uint %gridSize_1 %gridSize_1
-        %141 = OpUDiv %uint %index %140
-               OpStore %z %141
-        %144 = OpIMul %uint %gridSize_1 %gridSize_1
-        %145 = OpLoad %uint %z
-        %146 = OpIMul %uint %144 %145
-        %147 = OpISub %uint %index %146
-        %148 = OpUDiv %uint %147 %gridSize_1
-               OpStore %y %148
-        %150 = OpUMod %uint %index %gridSize_1
-               OpStore %x %150
-        %152 = OpLoad %uint %x
-        %153 = OpLoad %uint %y
-        %154 = OpLoad %uint %z
-        %155 = OpCompositeConstruct %v3uint %152 %153 %154
-               OpReturnValue %155
+        %156 = OpLabel
+          %z = OpVariable %_ptr_Function_uint Function %40
+          %y = OpVariable %_ptr_Function_uint Function %40
+          %x = OpVariable %_ptr_Function_uint Function %40
+        %158 = OpIMul %uint %gridSize_1 %gridSize_1
+        %157 = OpFunctionCall %uint %tint_div %index %158
+               OpStore %z %157
+        %161 = OpIMul %uint %gridSize_1 %gridSize_1
+        %162 = OpLoad %uint %z
+        %163 = OpIMul %uint %161 %162
+        %164 = OpISub %uint %index %163
+        %160 = OpFunctionCall %uint %tint_div %164 %gridSize_1
+               OpStore %y %160
+        %166 = OpFunctionCall %uint %tint_mod %index %gridSize_1
+               OpStore %x %166
+        %168 = OpLoad %uint %x
+        %169 = OpLoad %uint %y
+        %170 = OpLoad %uint %z
+        %171 = OpCompositeConstruct %v3uint %168 %169 %170
+               OpReturnValue %171
                OpFunctionEnd
-%loadPosition = OpFunction %v3float None %156
+%loadPosition = OpFunction %v3float None %172
 %vertexIndex = OpFunctionParameter %uint
-        %159 = OpLabel
- %position_0 = OpVariable %_ptr_Function_v3float Function %52
-        %161 = OpIMul %uint %uint_3 %vertexIndex
-        %162 = OpIAdd %uint %161 %143
-        %164 = OpAccessChain %_ptr_StorageBuffer_float %positions %uint_0 %162
-        %165 = OpLoad %float %164
-        %166 = OpIMul %uint %uint_3 %vertexIndex
-        %167 = OpIAdd %uint %166 %uint_1
-        %168 = OpAccessChain %_ptr_StorageBuffer_float %positions %uint_0 %167
-        %169 = OpLoad %float %168
-        %170 = OpIMul %uint %uint_3 %vertexIndex
-        %171 = OpIAdd %uint %170 %uint_2
-        %172 = OpAccessChain %_ptr_StorageBuffer_float %positions %uint_0 %171
-        %173 = OpLoad %float %172
-        %174 = OpCompositeConstruct %v3float %165 %169 %173
-               OpStore %position_0 %174
-        %176 = OpLoad %v3float %position_0
-               OpReturnValue %176
+        %175 = OpLabel
+ %position_0 = OpVariable %_ptr_Function_v3float Function %69
+        %177 = OpIMul %uint %uint_3 %vertexIndex
+        %178 = OpIAdd %uint %177 %40
+        %180 = OpAccessChain %_ptr_StorageBuffer_float %positions %uint_0 %178
+        %181 = OpLoad %float %180
+        %182 = OpIMul %uint %uint_3 %vertexIndex
+        %183 = OpIAdd %uint %182 %uint_1
+        %184 = OpAccessChain %_ptr_StorageBuffer_float %positions %uint_0 %183
+        %185 = OpLoad %float %184
+        %186 = OpIMul %uint %uint_3 %vertexIndex
+        %187 = OpIAdd %uint %186 %uint_2
+        %188 = OpAccessChain %_ptr_StorageBuffer_float %positions %uint_0 %187
+        %189 = OpLoad %float %188
+        %190 = OpCompositeConstruct %v3float %181 %185 %189
+               OpStore %position_0 %190
+        %192 = OpLoad %v3float %position_0
+               OpReturnValue %192
                OpFunctionEnd
-   %doIgnore = OpFunction %void None %177
-        %180 = OpLabel
-        %g42 = OpVariable %_ptr_Function_uint Function %143
-        %kj6 = OpVariable %_ptr_Function_uint Function %143
-        %b53 = OpVariable %_ptr_Function_uint Function %143
-        %rwg = OpVariable %_ptr_Function_uint Function %143
-        %rb5 = OpVariable %_ptr_Function_float Function %77
-        %g55 = OpVariable %_ptr_Function_int Function %190
-        %181 = OpAccessChain %_ptr_Uniform_uint %uniforms %uint_0 %uint_0
-        %182 = OpLoad %uint %181
-               OpStore %g42 %182
-        %185 = OpAccessChain %_ptr_StorageBuffer_uint %dbg %uint_0 %uint_5
-        %186 = OpLoad %uint %185
-               OpStore %kj6 %186
-        %192 = OpAccessChain %_ptr_StorageBuffer_uint_0 %counters %uint_0 %190
-        %188 = OpAtomicLoad %uint %192 %uint_1 %uint_0
-               OpStore %b53 %188
-        %194 = OpAccessChain %_ptr_StorageBuffer_uint %indices %uint_0 %190
-        %195 = OpLoad %uint %194
-               OpStore %rwg %195
-        %197 = OpAccessChain %_ptr_StorageBuffer_float %positions %uint_0 %190
-        %198 = OpLoad %float %197
-               OpStore %rb5 %198
-        %203 = OpAccessChain %_ptr_StorageBuffer_int %LUT %uint_0 %190
-        %200 = OpAtomicLoad %int %203 %uint_1 %uint_0
-               OpStore %g55 %200
+   %doIgnore = OpFunction %void None %193
+        %196 = OpLabel
+        %g42 = OpVariable %_ptr_Function_uint Function %40
+        %kj6 = OpVariable %_ptr_Function_uint Function %40
+        %b53 = OpVariable %_ptr_Function_uint Function %40
+        %rwg = OpVariable %_ptr_Function_uint Function %40
+        %rb5 = OpVariable %_ptr_Function_float Function %94
+        %g55 = OpVariable %_ptr_Function_int Function %206
+        %197 = OpAccessChain %_ptr_Uniform_uint %uniforms %uint_0 %uint_0
+        %198 = OpLoad %uint %197
+               OpStore %g42 %198
+        %201 = OpAccessChain %_ptr_StorageBuffer_uint %dbg %uint_0 %uint_5
+        %202 = OpLoad %uint %201
+               OpStore %kj6 %202
+        %208 = OpAccessChain %_ptr_StorageBuffer_uint_0 %counters %uint_0 %206
+        %204 = OpAtomicLoad %uint %208 %uint_1 %uint_0
+               OpStore %b53 %204
+        %210 = OpAccessChain %_ptr_StorageBuffer_uint %indices %uint_0 %206
+        %211 = OpLoad %uint %210
+               OpStore %rwg %211
+        %213 = OpAccessChain %_ptr_StorageBuffer_float %positions %uint_0 %206
+        %214 = OpLoad %float %213
+               OpStore %rb5 %214
+        %219 = OpAccessChain %_ptr_StorageBuffer_int %LUT %uint_0 %206
+        %216 = OpAtomicLoad %int %219 %uint_1 %uint_0
+               OpStore %g55 %216
                OpReturn
                OpFunctionEnd
-%main_count_inner = OpFunction %void None %206
+%main_count_inner = OpFunction %void None %222
 %GlobalInvocationID = OpFunctionParameter %v3uint
-        %209 = OpLabel
-%triangleIndex = OpVariable %_ptr_Function_uint Function %143
-         %i0 = OpVariable %_ptr_Function_uint Function %143
-         %i1 = OpVariable %_ptr_Function_uint Function %143
-         %i2 = OpVariable %_ptr_Function_uint Function %143
-         %p0 = OpVariable %_ptr_Function_v3float Function %52
-         %p1 = OpVariable %_ptr_Function_v3float Function %52
-         %p2 = OpVariable %_ptr_Function_v3float Function %52
-        %254 = OpVariable %_ptr_Function_v3float Function %52
-     %center = OpVariable %_ptr_Function_v3float Function %52
- %voxelPos_0 = OpVariable %_ptr_Function_v3float Function %52
- %voxelIndex = OpVariable %_ptr_Function_uint Function %143
-      %acefg = OpVariable %_ptr_Function_uint Function %143
-        %210 = OpCompositeExtract %uint %GlobalInvocationID 0
-               OpStore %triangleIndex %210
-        %212 = OpLoad %uint %triangleIndex
-        %213 = OpAccessChain %_ptr_Uniform_uint %uniforms %uint_0 %uint_0
-        %214 = OpLoad %uint %213
-        %215 = OpUGreaterThanEqual %bool %212 %214
-               OpSelectionMerge %217 None
-               OpBranchConditional %215 %218 %217
-        %218 = OpLabel
-               OpReturn
-        %217 = OpLabel
-        %219 = OpFunctionCall %void %doIgnore
-        %220 = OpLoad %uint %triangleIndex
-        %221 = OpIMul %uint %uint_3 %220
-        %222 = OpIAdd %uint %221 %143
-        %223 = OpAccessChain %_ptr_StorageBuffer_uint %indices %uint_0 %222
-        %224 = OpLoad %uint %223
-               OpStore %i0 %224
-        %226 = OpLoad %uint %triangleIndex
-        %227 = OpIMul %uint %uint_3 %226
-        %228 = OpIAdd %uint %227 %uint_1
-        %229 = OpAccessChain %_ptr_StorageBuffer_uint %indices %uint_0 %228
+        %225 = OpLabel
+%triangleIndex = OpVariable %_ptr_Function_uint Function %40
+         %i0 = OpVariable %_ptr_Function_uint Function %40
+         %i1 = OpVariable %_ptr_Function_uint Function %40
+         %i2 = OpVariable %_ptr_Function_uint Function %40
+         %p0 = OpVariable %_ptr_Function_v3float Function %69
+         %p1 = OpVariable %_ptr_Function_v3float Function %69
+         %p2 = OpVariable %_ptr_Function_v3float Function %69
+        %269 = OpVariable %_ptr_Function_v3float Function %69
+     %center = OpVariable %_ptr_Function_v3float Function %69
+ %voxelPos_0 = OpVariable %_ptr_Function_v3float Function %69
+ %voxelIndex = OpVariable %_ptr_Function_uint Function %40
+      %acefg = OpVariable %_ptr_Function_uint Function %40
+        %226 = OpCompositeExtract %uint %GlobalInvocationID 0
+               OpStore %triangleIndex %226
+        %228 = OpLoad %uint %triangleIndex
+        %229 = OpAccessChain %_ptr_Uniform_uint %uniforms %uint_0 %uint_0
         %230 = OpLoad %uint %229
-               OpStore %i1 %230
-        %232 = OpLoad %uint %triangleIndex
-        %233 = OpIMul %uint %uint_3 %232
-        %234 = OpIAdd %uint %233 %uint_2
-        %235 = OpAccessChain %_ptr_StorageBuffer_uint %indices %uint_0 %234
-        %236 = OpLoad %uint %235
-               OpStore %i2 %236
-        %239 = OpLoad %uint %i0
-        %238 = OpFunctionCall %v3float %loadPosition %239
-               OpStore %p0 %238
-        %242 = OpLoad %uint %i1
-        %241 = OpFunctionCall %v3float %loadPosition %242
-               OpStore %p1 %241
-        %245 = OpLoad %uint %i2
-        %244 = OpFunctionCall %v3float %loadPosition %245
-               OpStore %p2 %244
-        %247 = OpLoad %v3float %p0
-        %248 = OpLoad %v3float %p1
-        %249 = OpFAdd %v3float %247 %248
-        %250 = OpLoad %v3float %p2
-        %251 = OpFAdd %v3float %249 %250
-        %255 = OpCompositeConstruct %v3float %float_3 %float_3 %float_3
-        %253 = OpFDiv %v3float %251 %255
-               OpStore %center %253
-        %258 = OpLoad %v3float %center
-        %257 = OpFunctionCall %v3float %toVoxelPos %258
-               OpStore %voxelPos_0 %257
-        %261 = OpAccessChain %_ptr_Uniform_uint %uniforms %uint_0 %uint_1
-        %262 = OpLoad %uint %261
-        %263 = OpLoad %v3float %voxelPos_0
-        %260 = OpFunctionCall %uint %toIndex1D %262 %263
-               OpStore %voxelIndex %260
-        %267 = OpLoad %uint %voxelIndex
-        %268 = OpAccessChain %_ptr_StorageBuffer_uint_0 %counters %uint_0 %267
-        %265 = OpAtomicIAdd %uint %268 %uint_1 %uint_0 %uint_1
-               OpStore %acefg %265
-        %270 = OpLoad %uint %triangleIndex
-        %271 = OpIEqual %bool %270 %143
-               OpSelectionMerge %272 None
-               OpBranchConditional %271 %273 %272
-        %273 = OpLabel
-        %274 = OpAccessChain %_ptr_StorageBuffer_uint %dbg %uint_0 %uint_4
-        %275 = OpAccessChain %_ptr_Uniform_uint %uniforms %uint_0 %uint_1
-        %276 = OpLoad %uint %275
-               OpStore %274 %276
-        %278 = OpAccessChain %_ptr_StorageBuffer_float %dbg %uint_0 %uint_8
-        %279 = OpAccessChain %_ptr_Function_float %center %uint_0
-        %280 = OpLoad %float %279
-               OpStore %278 %280
-        %282 = OpAccessChain %_ptr_StorageBuffer_float %dbg %uint_0 %uint_9
-        %283 = OpAccessChain %_ptr_Function_float %center %uint_1
-        %284 = OpLoad %float %283
-               OpStore %282 %284
-        %286 = OpAccessChain %_ptr_StorageBuffer_float %dbg %uint_0 %uint_10
-        %287 = OpAccessChain %_ptr_Function_float %center %uint_2
-        %288 = OpLoad %float %287
-               OpStore %286 %288
-               OpBranch %272
-        %272 = OpLabel
+        %231 = OpUGreaterThanEqual %bool %228 %230
+               OpSelectionMerge %232 None
+               OpBranchConditional %231 %233 %232
+        %233 = OpLabel
+               OpReturn
+        %232 = OpLabel
+        %234 = OpFunctionCall %void %doIgnore
+        %235 = OpLoad %uint %triangleIndex
+        %236 = OpIMul %uint %uint_3 %235
+        %237 = OpIAdd %uint %236 %40
+        %238 = OpAccessChain %_ptr_StorageBuffer_uint %indices %uint_0 %237
+        %239 = OpLoad %uint %238
+               OpStore %i0 %239
+        %241 = OpLoad %uint %triangleIndex
+        %242 = OpIMul %uint %uint_3 %241
+        %243 = OpIAdd %uint %242 %uint_1
+        %244 = OpAccessChain %_ptr_StorageBuffer_uint %indices %uint_0 %243
+        %245 = OpLoad %uint %244
+               OpStore %i1 %245
+        %247 = OpLoad %uint %triangleIndex
+        %248 = OpIMul %uint %uint_3 %247
+        %249 = OpIAdd %uint %248 %uint_2
+        %250 = OpAccessChain %_ptr_StorageBuffer_uint %indices %uint_0 %249
+        %251 = OpLoad %uint %250
+               OpStore %i2 %251
+        %254 = OpLoad %uint %i0
+        %253 = OpFunctionCall %v3float %loadPosition %254
+               OpStore %p0 %253
+        %257 = OpLoad %uint %i1
+        %256 = OpFunctionCall %v3float %loadPosition %257
+               OpStore %p1 %256
+        %260 = OpLoad %uint %i2
+        %259 = OpFunctionCall %v3float %loadPosition %260
+               OpStore %p2 %259
+        %262 = OpLoad %v3float %p0
+        %263 = OpLoad %v3float %p1
+        %264 = OpFAdd %v3float %262 %263
+        %265 = OpLoad %v3float %p2
+        %266 = OpFAdd %v3float %264 %265
+        %270 = OpCompositeConstruct %v3float %float_3 %float_3 %float_3
+        %268 = OpFDiv %v3float %266 %270
+               OpStore %center %268
+        %273 = OpLoad %v3float %center
+        %272 = OpFunctionCall %v3float %toVoxelPos %273
+               OpStore %voxelPos_0 %272
+        %276 = OpAccessChain %_ptr_Uniform_uint %uniforms %uint_0 %uint_1
+        %277 = OpLoad %uint %276
+        %278 = OpLoad %v3float %voxelPos_0
+        %275 = OpFunctionCall %uint %toIndex1D %277 %278
+               OpStore %voxelIndex %275
+        %282 = OpLoad %uint %voxelIndex
+        %283 = OpAccessChain %_ptr_StorageBuffer_uint_0 %counters %uint_0 %282
+        %280 = OpAtomicIAdd %uint %283 %uint_1 %uint_0 %uint_1
+               OpStore %acefg %280
+        %285 = OpLoad %uint %triangleIndex
+        %286 = OpIEqual %bool %285 %40
+               OpSelectionMerge %287 None
+               OpBranchConditional %286 %288 %287
+        %288 = OpLabel
+        %289 = OpAccessChain %_ptr_StorageBuffer_uint %dbg %uint_0 %uint_4
+        %290 = OpAccessChain %_ptr_Uniform_uint %uniforms %uint_0 %uint_1
+        %291 = OpLoad %uint %290
+               OpStore %289 %291
+        %293 = OpAccessChain %_ptr_StorageBuffer_float %dbg %uint_0 %uint_8
+        %294 = OpAccessChain %_ptr_Function_float %center %uint_0
+        %295 = OpLoad %float %294
+               OpStore %293 %295
+        %297 = OpAccessChain %_ptr_StorageBuffer_float %dbg %uint_0 %uint_9
+        %298 = OpAccessChain %_ptr_Function_float %center %uint_1
+        %299 = OpLoad %float %298
+               OpStore %297 %299
+        %301 = OpAccessChain %_ptr_StorageBuffer_float %dbg %uint_0 %uint_10
+        %302 = OpAccessChain %_ptr_Function_float %center %uint_2
+        %303 = OpLoad %float %302
+               OpStore %301 %303
+               OpBranch %287
+        %287 = OpLabel
                OpReturn
                OpFunctionEnd
- %main_count = OpFunction %void None %177
-        %290 = OpLabel
-        %292 = OpLoad %v3uint %GlobalInvocationID_1
-        %291 = OpFunctionCall %void %main_count_inner %292
+ %main_count = OpFunction %void None %193
+        %305 = OpLabel
+        %307 = OpLoad %v3uint %GlobalInvocationID_1
+        %306 = OpFunctionCall %void %main_count_inner %307
                OpReturn
                OpFunctionEnd
-%main_create_lut_inner = OpFunction %void None %206
+%main_create_lut_inner = OpFunction %void None %222
 %GlobalInvocationID_0 = OpFunctionParameter %v3uint
-        %295 = OpLabel
-%voxelIndex_0 = OpVariable %_ptr_Function_uint Function %143
-  %maxVoxels = OpVariable %_ptr_Function_uint Function %143
-%numTriangles = OpVariable %_ptr_Function_uint Function %143
-     %offset = OpVariable %_ptr_Function_int Function %190
-        %296 = OpCompositeExtract %uint %GlobalInvocationID_0 0
-               OpStore %voxelIndex_0 %296
-        %298 = OpFunctionCall %void %doIgnore
-        %299 = OpAccessChain %_ptr_Uniform_uint %uniforms %uint_0 %uint_1
-        %300 = OpLoad %uint %299
-        %301 = OpAccessChain %_ptr_Uniform_uint %uniforms %uint_0 %uint_1
-        %302 = OpLoad %uint %301
-        %303 = OpIMul %uint %300 %302
-        %304 = OpAccessChain %_ptr_Uniform_uint %uniforms %uint_0 %uint_1
-        %305 = OpLoad %uint %304
-        %306 = OpIMul %uint %303 %305
-               OpStore %maxVoxels %306
-        %308 = OpLoad %uint %voxelIndex_0
-        %309 = OpLoad %uint %maxVoxels
-        %310 = OpUGreaterThanEqual %bool %308 %309
-               OpSelectionMerge %311 None
-               OpBranchConditional %310 %312 %311
-        %312 = OpLabel
+        %310 = OpLabel
+%voxelIndex_0 = OpVariable %_ptr_Function_uint Function %40
+  %maxVoxels = OpVariable %_ptr_Function_uint Function %40
+%numTriangles = OpVariable %_ptr_Function_uint Function %40
+     %offset = OpVariable %_ptr_Function_int Function %206
+        %311 = OpCompositeExtract %uint %GlobalInvocationID_0 0
+               OpStore %voxelIndex_0 %311
+        %313 = OpFunctionCall %void %doIgnore
+        %314 = OpAccessChain %_ptr_Uniform_uint %uniforms %uint_0 %uint_1
+        %315 = OpLoad %uint %314
+        %316 = OpAccessChain %_ptr_Uniform_uint %uniforms %uint_0 %uint_1
+        %317 = OpLoad %uint %316
+        %318 = OpIMul %uint %315 %317
+        %319 = OpAccessChain %_ptr_Uniform_uint %uniforms %uint_0 %uint_1
+        %320 = OpLoad %uint %319
+        %321 = OpIMul %uint %318 %320
+               OpStore %maxVoxels %321
+        %323 = OpLoad %uint %voxelIndex_0
+        %324 = OpLoad %uint %maxVoxels
+        %325 = OpUGreaterThanEqual %bool %323 %324
+               OpSelectionMerge %326 None
+               OpBranchConditional %325 %327 %326
+        %327 = OpLabel
                OpReturn
-        %311 = OpLabel
-        %315 = OpLoad %uint %voxelIndex_0
-        %316 = OpAccessChain %_ptr_StorageBuffer_uint_0 %counters %uint_0 %315
-        %313 = OpAtomicLoad %uint %316 %uint_1 %uint_0
-               OpStore %numTriangles %313
+        %326 = OpLabel
+        %330 = OpLoad %uint %voxelIndex_0
+        %331 = OpAccessChain %_ptr_StorageBuffer_uint_0 %counters %uint_0 %330
+        %328 = OpAtomicLoad %uint %331 %uint_1 %uint_0
+               OpStore %numTriangles %328
                OpStore %offset %int_n1
-        %320 = OpLoad %uint %numTriangles
-        %321 = OpUGreaterThan %bool %320 %143
-               OpSelectionMerge %322 None
-               OpBranchConditional %321 %323 %322
-        %323 = OpLabel
-        %326 = OpAccessChain %_ptr_StorageBuffer_uint_0 %dbg %uint_0 %uint_0
-        %327 = OpLoad %uint %numTriangles
-        %324 = OpAtomicIAdd %uint %326 %uint_1 %uint_0 %327
-        %328 = OpBitcast %int %324
-               OpStore %offset %328
-               OpBranch %322
-        %322 = OpLabel
-        %331 = OpLoad %uint %voxelIndex_0
-        %332 = OpAccessChain %_ptr_StorageBuffer_int %LUT %uint_0 %331
-        %333 = OpLoad %int %offset
-               OpAtomicStore %332 %uint_1 %uint_0 %333
+        %335 = OpLoad %uint %numTriangles
+        %336 = OpUGreaterThan %bool %335 %40
+               OpSelectionMerge %337 None
+               OpBranchConditional %336 %338 %337
+        %338 = OpLabel
+        %341 = OpAccessChain %_ptr_StorageBuffer_uint_0 %dbg %uint_0 %uint_0
+        %342 = OpLoad %uint %numTriangles
+        %339 = OpAtomicIAdd %uint %341 %uint_1 %uint_0 %342
+        %343 = OpBitcast %int %339
+               OpStore %offset %343
+               OpBranch %337
+        %337 = OpLabel
+        %346 = OpLoad %uint %voxelIndex_0
+        %347 = OpAccessChain %_ptr_StorageBuffer_int %LUT %uint_0 %346
+        %348 = OpLoad %int %offset
+               OpAtomicStore %347 %uint_1 %uint_0 %348
                OpReturn
                OpFunctionEnd
-%main_create_lut = OpFunction %void None %177
-        %335 = OpLabel
-        %337 = OpLoad %v3uint %GlobalInvocationID_2
-        %336 = OpFunctionCall %void %main_create_lut_inner %337
+%main_create_lut = OpFunction %void None %193
+        %350 = OpLabel
+        %352 = OpLoad %v3uint %GlobalInvocationID_2
+        %351 = OpFunctionCall %void %main_create_lut_inner %352
                OpReturn
                OpFunctionEnd
-%main_sort_triangles_inner = OpFunction %void None %206
+%main_sort_triangles_inner = OpFunction %void None %222
 %GlobalInvocationID_4 = OpFunctionParameter %v3uint
-        %340 = OpLabel
-%triangleIndex_0 = OpVariable %_ptr_Function_uint Function %143
-       %i0_0 = OpVariable %_ptr_Function_uint Function %143
-       %i1_0 = OpVariable %_ptr_Function_uint Function %143
-       %i2_0 = OpVariable %_ptr_Function_uint Function %143
-       %p0_0 = OpVariable %_ptr_Function_v3float Function %52
-       %p1_0 = OpVariable %_ptr_Function_v3float Function %52
-       %p2_0 = OpVariable %_ptr_Function_v3float Function %52
-        %383 = OpVariable %_ptr_Function_v3float Function %52
-   %center_0 = OpVariable %_ptr_Function_v3float Function %52
- %voxelPos_1 = OpVariable %_ptr_Function_v3float Function %52
-%voxelIndex_1 = OpVariable %_ptr_Function_uint Function %143
-%triangleOffset = OpVariable %_ptr_Function_int Function %190
-        %341 = OpCompositeExtract %uint %GlobalInvocationID_4 0
-               OpStore %triangleIndex_0 %341
-        %343 = OpFunctionCall %void %doIgnore
-        %344 = OpLoad %uint %triangleIndex_0
-        %345 = OpAccessChain %_ptr_Uniform_uint %uniforms %uint_0 %uint_0
-        %346 = OpLoad %uint %345
-        %347 = OpUGreaterThanEqual %bool %344 %346
-               OpSelectionMerge %348 None
-               OpBranchConditional %347 %349 %348
-        %349 = OpLabel
+        %355 = OpLabel
+%triangleIndex_0 = OpVariable %_ptr_Function_uint Function %40
+       %i0_0 = OpVariable %_ptr_Function_uint Function %40
+       %i1_0 = OpVariable %_ptr_Function_uint Function %40
+       %i2_0 = OpVariable %_ptr_Function_uint Function %40
+       %p0_0 = OpVariable %_ptr_Function_v3float Function %69
+       %p1_0 = OpVariable %_ptr_Function_v3float Function %69
+       %p2_0 = OpVariable %_ptr_Function_v3float Function %69
+        %398 = OpVariable %_ptr_Function_v3float Function %69
+   %center_0 = OpVariable %_ptr_Function_v3float Function %69
+ %voxelPos_1 = OpVariable %_ptr_Function_v3float Function %69
+%voxelIndex_1 = OpVariable %_ptr_Function_uint Function %40
+%triangleOffset = OpVariable %_ptr_Function_int Function %206
+        %356 = OpCompositeExtract %uint %GlobalInvocationID_4 0
+               OpStore %triangleIndex_0 %356
+        %358 = OpFunctionCall %void %doIgnore
+        %359 = OpLoad %uint %triangleIndex_0
+        %360 = OpAccessChain %_ptr_Uniform_uint %uniforms %uint_0 %uint_0
+        %361 = OpLoad %uint %360
+        %362 = OpUGreaterThanEqual %bool %359 %361
+               OpSelectionMerge %363 None
+               OpBranchConditional %362 %364 %363
+        %364 = OpLabel
                OpReturn
-        %348 = OpLabel
-        %350 = OpLoad %uint %triangleIndex_0
-        %351 = OpIMul %uint %uint_3 %350
-        %352 = OpIAdd %uint %351 %143
-        %353 = OpAccessChain %_ptr_StorageBuffer_uint %indices %uint_0 %352
-        %354 = OpLoad %uint %353
-               OpStore %i0_0 %354
-        %356 = OpLoad %uint %triangleIndex_0
-        %357 = OpIMul %uint %uint_3 %356
-        %358 = OpIAdd %uint %357 %uint_1
-        %359 = OpAccessChain %_ptr_StorageBuffer_uint %indices %uint_0 %358
-        %360 = OpLoad %uint %359
-               OpStore %i1_0 %360
-        %362 = OpLoad %uint %triangleIndex_0
-        %363 = OpIMul %uint %uint_3 %362
-        %364 = OpIAdd %uint %363 %uint_2
-        %365 = OpAccessChain %_ptr_StorageBuffer_uint %indices %uint_0 %364
-        %366 = OpLoad %uint %365
-               OpStore %i2_0 %366
-        %369 = OpLoad %uint %i0_0
-        %368 = OpFunctionCall %v3float %loadPosition %369
-               OpStore %p0_0 %368
-        %372 = OpLoad %uint %i1_0
-        %371 = OpFunctionCall %v3float %loadPosition %372
-               OpStore %p1_0 %371
-        %375 = OpLoad %uint %i2_0
-        %374 = OpFunctionCall %v3float %loadPosition %375
-               OpStore %p2_0 %374
-        %377 = OpLoad %v3float %p0_0
-        %378 = OpLoad %v3float %p1_0
-        %379 = OpFAdd %v3float %377 %378
-        %380 = OpLoad %v3float %p2_0
-        %381 = OpFAdd %v3float %379 %380
-        %384 = OpCompositeConstruct %v3float %float_3 %float_3 %float_3
-        %382 = OpFDiv %v3float %381 %384
-               OpStore %center_0 %382
-        %387 = OpLoad %v3float %center_0
-        %386 = OpFunctionCall %v3float %toVoxelPos %387
-               OpStore %voxelPos_1 %386
-        %390 = OpAccessChain %_ptr_Uniform_uint %uniforms %uint_0 %uint_1
-        %391 = OpLoad %uint %390
-        %392 = OpLoad %v3float %voxelPos_1
-        %389 = OpFunctionCall %uint %toIndex1D %391 %392
-               OpStore %voxelIndex_1 %389
-        %396 = OpLoad %uint %voxelIndex_1
-        %397 = OpAccessChain %_ptr_StorageBuffer_int %LUT %uint_0 %396
-        %394 = OpAtomicIAdd %int %397 %uint_1 %uint_0 %int_1
-               OpStore %triangleOffset %394
+        %363 = OpLabel
+        %365 = OpLoad %uint %triangleIndex_0
+        %366 = OpIMul %uint %uint_3 %365
+        %367 = OpIAdd %uint %366 %40
+        %368 = OpAccessChain %_ptr_StorageBuffer_uint %indices %uint_0 %367
+        %369 = OpLoad %uint %368
+               OpStore %i0_0 %369
+        %371 = OpLoad %uint %triangleIndex_0
+        %372 = OpIMul %uint %uint_3 %371
+        %373 = OpIAdd %uint %372 %uint_1
+        %374 = OpAccessChain %_ptr_StorageBuffer_uint %indices %uint_0 %373
+        %375 = OpLoad %uint %374
+               OpStore %i1_0 %375
+        %377 = OpLoad %uint %triangleIndex_0
+        %378 = OpIMul %uint %uint_3 %377
+        %379 = OpIAdd %uint %378 %uint_2
+        %380 = OpAccessChain %_ptr_StorageBuffer_uint %indices %uint_0 %379
+        %381 = OpLoad %uint %380
+               OpStore %i2_0 %381
+        %384 = OpLoad %uint %i0_0
+        %383 = OpFunctionCall %v3float %loadPosition %384
+               OpStore %p0_0 %383
+        %387 = OpLoad %uint %i1_0
+        %386 = OpFunctionCall %v3float %loadPosition %387
+               OpStore %p1_0 %386
+        %390 = OpLoad %uint %i2_0
+        %389 = OpFunctionCall %v3float %loadPosition %390
+               OpStore %p2_0 %389
+        %392 = OpLoad %v3float %p0_0
+        %393 = OpLoad %v3float %p1_0
+        %394 = OpFAdd %v3float %392 %393
+        %395 = OpLoad %v3float %p2_0
+        %396 = OpFAdd %v3float %394 %395
+        %399 = OpCompositeConstruct %v3float %float_3 %float_3 %float_3
+        %397 = OpFDiv %v3float %396 %399
+               OpStore %center_0 %397
+        %402 = OpLoad %v3float %center_0
+        %401 = OpFunctionCall %v3float %toVoxelPos %402
+               OpStore %voxelPos_1 %401
+        %405 = OpAccessChain %_ptr_Uniform_uint %uniforms %uint_0 %uint_1
+        %406 = OpLoad %uint %405
+        %407 = OpLoad %v3float %voxelPos_1
+        %404 = OpFunctionCall %uint %toIndex1D %406 %407
+               OpStore %voxelIndex_1 %404
+        %411 = OpLoad %uint %voxelIndex_1
+        %412 = OpAccessChain %_ptr_StorageBuffer_int %LUT %uint_0 %411
+        %409 = OpAtomicIAdd %int %412 %uint_1 %uint_0 %int_1
+               OpStore %triangleOffset %409
                OpReturn
                OpFunctionEnd
-%main_sort_triangles = OpFunction %void None %177
-        %401 = OpLabel
-        %403 = OpLoad %v3uint %GlobalInvocationID_3
-        %402 = OpFunctionCall %void %main_sort_triangles_inner %403
+%main_sort_triangles = OpFunction %void None %193
+        %416 = OpLabel
+        %418 = OpLoad %v3uint %GlobalInvocationID_3
+        %417 = OpFunctionCall %void %main_sort_triangles_inner %418
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/bug/tint/1520.spvasm.expected.dxc.hlsl b/test/tint/bug/tint/1520.spvasm.expected.dxc.hlsl
index 211fd628..e07e2fa 100644
--- a/test/tint/bug/tint/1520.spvasm.expected.dxc.hlsl
+++ b/test/tint/bug/tint/1520.spvasm.expected.dxc.hlsl
@@ -1,5 +1,5 @@
-int4 value_or_one_if_zero_int4(int4 value) {
-  return value == int4(0, 0, 0, 0) ? int4(1, 1, 1, 1) : value;
+int4 tint_div(int4 lhs, int4 rhs) {
+  return (lhs / (((rhs == (0).xxxx) | ((lhs == (-2147483648).xxxx) & (rhs == (-1).xxxx))) ? (1).xxxx : rhs));
 }
 
 cbuffer cbuffer_x_4 : register(b0, space0) {
@@ -25,7 +25,8 @@
   ok = true;
   x_41 = false;
   if (true) {
-    x_40 = all((((0).xxxx / value_or_one_if_zero_int4(int4(x_27, x_27, x_27, x_27))) == (0).xxxx));
+    const int4 tint_symbol_3 = tint_div((0).xxxx, int4(x_27, x_27, x_27, x_27));
+    x_40 = all((tint_symbol_3 == (0).xxxx));
     x_41 = x_40;
   }
   ok = x_41;
@@ -47,11 +48,11 @@
   ok = x_55;
   const int4 x_58 = (x_50 * (2).xxxx);
   val = x_58;
-  const int4 x_59 = (x_58 / (2).xxxx);
+  const int4 x_59 = tint_div(x_58, (2).xxxx);
   val = x_59;
   const int4 x_60 = (x_59 * (2).xxxx);
   val = x_60;
-  const int4 x_61 = (x_60 / (2).xxxx);
+  const int4 x_61 = tint_div(x_60, (2).xxxx);
   val = x_61;
   x_66 = false;
   if (x_55) {
@@ -151,8 +152,8 @@
   sk_Clockwise = sk_Clockwise_param;
   vcolor_S0 = vcolor_S0_param;
   main_1();
-  const main_out tint_symbol_5 = {sk_FragColor};
-  return tint_symbol_5;
+  const main_out tint_symbol_6 = {sk_FragColor};
+  return tint_symbol_6;
 }
 
 tint_symbol_2 main(tint_symbol_1 tint_symbol) {
diff --git a/test/tint/bug/tint/1520.spvasm.expected.fxc.hlsl b/test/tint/bug/tint/1520.spvasm.expected.fxc.hlsl
index 211fd628..e07e2fa 100644
--- a/test/tint/bug/tint/1520.spvasm.expected.fxc.hlsl
+++ b/test/tint/bug/tint/1520.spvasm.expected.fxc.hlsl
@@ -1,5 +1,5 @@
-int4 value_or_one_if_zero_int4(int4 value) {
-  return value == int4(0, 0, 0, 0) ? int4(1, 1, 1, 1) : value;
+int4 tint_div(int4 lhs, int4 rhs) {
+  return (lhs / (((rhs == (0).xxxx) | ((lhs == (-2147483648).xxxx) & (rhs == (-1).xxxx))) ? (1).xxxx : rhs));
 }
 
 cbuffer cbuffer_x_4 : register(b0, space0) {
@@ -25,7 +25,8 @@
   ok = true;
   x_41 = false;
   if (true) {
-    x_40 = all((((0).xxxx / value_or_one_if_zero_int4(int4(x_27, x_27, x_27, x_27))) == (0).xxxx));
+    const int4 tint_symbol_3 = tint_div((0).xxxx, int4(x_27, x_27, x_27, x_27));
+    x_40 = all((tint_symbol_3 == (0).xxxx));
     x_41 = x_40;
   }
   ok = x_41;
@@ -47,11 +48,11 @@
   ok = x_55;
   const int4 x_58 = (x_50 * (2).xxxx);
   val = x_58;
-  const int4 x_59 = (x_58 / (2).xxxx);
+  const int4 x_59 = tint_div(x_58, (2).xxxx);
   val = x_59;
   const int4 x_60 = (x_59 * (2).xxxx);
   val = x_60;
-  const int4 x_61 = (x_60 / (2).xxxx);
+  const int4 x_61 = tint_div(x_60, (2).xxxx);
   val = x_61;
   x_66 = false;
   if (x_55) {
@@ -151,8 +152,8 @@
   sk_Clockwise = sk_Clockwise_param;
   vcolor_S0 = vcolor_S0_param;
   main_1();
-  const main_out tint_symbol_5 = {sk_FragColor};
-  return tint_symbol_5;
+  const main_out tint_symbol_6 = {sk_FragColor};
+  return tint_symbol_6;
 }
 
 tint_symbol_2 main(tint_symbol_1 tint_symbol) {
diff --git a/test/tint/bug/tint/1520.spvasm.expected.glsl b/test/tint/bug/tint/1520.spvasm.expected.glsl
index 74b4409..fbf2852 100644
--- a/test/tint/bug/tint/1520.spvasm.expected.glsl
+++ b/test/tint/bug/tint/1520.spvasm.expected.glsl
@@ -3,6 +3,10 @@
 
 layout(location = 0) in vec4 vcolor_S0_param_1;
 layout(location = 0) out vec4 sk_FragColor_1_1;
+ivec4 tint_div(ivec4 lhs, ivec4 rhs) {
+  return (lhs / mix(rhs, ivec4(1), bvec4(uvec4(equal(rhs, ivec4(0))) | uvec4(bvec4(uvec4(equal(lhs, ivec4(-2147483648))) & uvec4(equal(rhs, ivec4(-1))))))));
+}
+
 struct UniformBuffer {
   uint pad;
   uint pad_1;
@@ -40,7 +44,8 @@
   ok = true;
   x_41 = false;
   if (true) {
-    x_40 = all(equal((ivec4(0) / ivec4(x_27, x_27, x_27, x_27)), ivec4(0)));
+    ivec4 tint_symbol_1 = tint_div(ivec4(0), ivec4(x_27, x_27, x_27, x_27));
+    x_40 = all(equal(tint_symbol_1, ivec4(0)));
     x_41 = x_40;
   }
   ok = x_41;
@@ -62,11 +67,11 @@
   ok = x_55;
   ivec4 x_58 = (x_50 * ivec4(2));
   val = x_58;
-  ivec4 x_59 = (x_58 / ivec4(2));
+  ivec4 x_59 = tint_div(x_58, ivec4(2));
   val = x_59;
   ivec4 x_60 = (x_59 * ivec4(2));
   val = x_60;
-  ivec4 x_61 = (x_60 / ivec4(2));
+  ivec4 x_61 = tint_div(x_60, ivec4(2));
   val = x_61;
   x_66 = false;
   if (x_55) {
@@ -159,8 +164,8 @@
   sk_Clockwise = sk_Clockwise_param;
   vcolor_S0 = vcolor_S0_param;
   main_1();
-  main_out tint_symbol_1 = main_out(sk_FragColor);
-  return tint_symbol_1;
+  main_out tint_symbol_2 = main_out(sk_FragColor);
+  return tint_symbol_2;
 }
 
 void main() {
diff --git a/test/tint/bug/tint/1520.spvasm.expected.msl b/test/tint/bug/tint/1520.spvasm.expected.msl
index d9ff17c..b997052 100644
--- a/test/tint/bug/tint/1520.spvasm.expected.msl
+++ b/test/tint/bug/tint/1520.spvasm.expected.msl
@@ -14,6 +14,10 @@
     T elements[N];
 };
 
+int4 tint_div(int4 lhs, int4 rhs) {
+  return (lhs / select(rhs, int4(1), ((rhs == int4(0)) | ((lhs == int4((-2147483647 - 1))) & (rhs == int4(-1))))));
+}
+
 struct UniformBuffer {
   /* 0x0000 */ tint_array<int8_t, 16> tint_pad;
   /* 0x0010 */ float unknownInput_S1_c0;
@@ -23,7 +27,7 @@
   /* 0x0040 */ float3x3 umatrix_S1;
 };
 
-bool test_int_S1_c0_b(const constant UniformBuffer* const tint_symbol_5) {
+bool test_int_S1_c0_b(const constant UniformBuffer* const tint_symbol_6) {
   int unknown = 0;
   bool ok = false;
   int4 val = 0;
@@ -33,13 +37,14 @@
   bool x_55 = false;
   bool x_65 = false;
   bool x_66 = false;
-  float const x_26 = (*(tint_symbol_5)).unknownInput_S1_c0;
+  float const x_26 = (*(tint_symbol_6)).unknownInput_S1_c0;
   int const x_27 = int(x_26);
   unknown = x_27;
   ok = true;
   x_41 = false;
   if (true) {
-    x_40 = all(((int4(0) / int4(x_27, x_27, x_27, x_27)) == int4(0)));
+    int4 const tint_symbol_4 = tint_div(int4(0), int4(x_27, x_27, x_27, x_27));
+    x_40 = all((tint_symbol_4 == int4(0)));
     x_41 = x_40;
   }
   ok = x_41;
@@ -61,11 +66,11 @@
   ok = x_55;
   int4 const x_58 = as_type<int4>((as_type<uint4>(x_50) * as_type<uint4>(int4(2))));
   val = x_58;
-  int4 const x_59 = (x_58 / int4(2));
+  int4 const x_59 = tint_div(x_58, int4(2));
   val = x_59;
   int4 const x_60 = as_type<int4>((as_type<uint4>(x_59) * as_type<uint4>(int4(2))));
   val = x_60;
-  int4 const x_61 = (x_60 / int4(2));
+  int4 const x_61 = tint_div(x_60, int4(2));
   val = x_61;
   x_66 = false;
   if (x_55) {
@@ -76,7 +81,7 @@
   return x_66;
 }
 
-void main_1(thread float4* const tint_symbol_6, const constant UniformBuffer* const tint_symbol_7, thread float4* const tint_symbol_8) {
+void main_1(thread float4* const tint_symbol_7, const constant UniformBuffer* const tint_symbol_8, thread float4* const tint_symbol_9) {
   float4 outputColor_S0 = 0.0f;
   float4 output_S1 = 0.0f;
   float x_8_unknown = 0.0f;
@@ -91,9 +96,9 @@
   bool x_111 = false;
   bool x_114 = false;
   bool x_115 = false;
-  float4 const x_72 = *(tint_symbol_6);
+  float4 const x_72 = *(tint_symbol_7);
   outputColor_S0 = x_72;
-  float const x_77 = (*(tint_symbol_7)).unknownInput_S1_c0;
+  float const x_77 = (*(tint_symbol_8)).unknownInput_S1_c0;
   x_8_unknown = x_77;
   x_9_ok = true;
   x_87 = false;
@@ -134,19 +139,19 @@
   x_9_ok = x_111;
   x_115 = false;
   if (x_111) {
-    x_114 = test_int_S1_c0_b(tint_symbol_7);
+    x_114 = test_int_S1_c0_b(tint_symbol_8);
     x_115 = x_114;
   }
   if (x_115) {
-    float4 const x_122 = (*(tint_symbol_7)).ucolorGreen_S1_c0;
+    float4 const x_122 = (*(tint_symbol_8)).ucolorGreen_S1_c0;
     x_116 = x_122;
   } else {
-    float4 const x_124 = (*(tint_symbol_7)).ucolorRed_S1_c0;
+    float4 const x_124 = (*(tint_symbol_8)).ucolorRed_S1_c0;
     x_116 = x_124;
   }
   float4 const x_125 = x_116;
   output_S1 = x_125;
-  *(tint_symbol_8) = x_125;
+  *(tint_symbol_9) = x_125;
   return;
 }
 
@@ -162,19 +167,19 @@
   float4 sk_FragColor_1 [[color(0)]];
 };
 
-main_out tint_symbol_inner(bool sk_Clockwise_param, float4 vcolor_S0_param, thread float4* const tint_symbol_10, const constant UniformBuffer* const tint_symbol_11, thread float4* const tint_symbol_12) {
-  thread bool tint_symbol_9 = false;
-  tint_symbol_9 = sk_Clockwise_param;
-  *(tint_symbol_10) = vcolor_S0_param;
-  main_1(tint_symbol_10, tint_symbol_11, tint_symbol_12);
-  main_out const tint_symbol_4 = {.sk_FragColor_1=*(tint_symbol_12)};
-  return tint_symbol_4;
+main_out tint_symbol_inner(bool sk_Clockwise_param, float4 vcolor_S0_param, thread float4* const tint_symbol_11, const constant UniformBuffer* const tint_symbol_12, thread float4* const tint_symbol_13) {
+  thread bool tint_symbol_10 = false;
+  tint_symbol_10 = sk_Clockwise_param;
+  *(tint_symbol_11) = vcolor_S0_param;
+  main_1(tint_symbol_11, tint_symbol_12, tint_symbol_13);
+  main_out const tint_symbol_5 = {.sk_FragColor_1=*(tint_symbol_13)};
+  return tint_symbol_5;
 }
 
-fragment tint_symbol_3 tint_symbol(const constant UniformBuffer* tint_symbol_14 [[buffer(0)]], bool sk_Clockwise_param [[front_facing]], tint_symbol_2 tint_symbol_1 [[stage_in]]) {
-  thread float4 tint_symbol_13 = 0.0f;
-  thread float4 tint_symbol_15 = 0.0f;
-  main_out const inner_result = tint_symbol_inner(sk_Clockwise_param, tint_symbol_1.vcolor_S0_param, &(tint_symbol_13), tint_symbol_14, &(tint_symbol_15));
+fragment tint_symbol_3 tint_symbol(const constant UniformBuffer* tint_symbol_15 [[buffer(0)]], bool sk_Clockwise_param [[front_facing]], tint_symbol_2 tint_symbol_1 [[stage_in]]) {
+  thread float4 tint_symbol_14 = 0.0f;
+  thread float4 tint_symbol_16 = 0.0f;
+  main_out const inner_result = tint_symbol_inner(sk_Clockwise_param, tint_symbol_1.vcolor_S0_param, &(tint_symbol_14), tint_symbol_15, &(tint_symbol_16));
   tint_symbol_3 wrapper_result = {};
   wrapper_result.sk_FragColor_1 = inner_result.sk_FragColor_1;
   return wrapper_result;
diff --git a/test/tint/bug/tint/1520.spvasm.expected.spvasm b/test/tint/bug/tint/1520.spvasm.expected.spvasm
index 5a7ff67..3a07adf 100644
--- a/test/tint/bug/tint/1520.spvasm.expected.spvasm
+++ b/test/tint/bug/tint/1520.spvasm.expected.spvasm
@@ -1,7 +1,7 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 177
+; Bound: 193
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
@@ -21,6 +21,9 @@
                OpName %sk_FragColor "sk_FragColor"
                OpName %sk_Clockwise "sk_Clockwise"
                OpName %vcolor_S0 "vcolor_S0"
+               OpName %tint_div "tint_div"
+               OpName %lhs "lhs"
+               OpName %rhs "rhs"
                OpName %test_int_S1_c0_b "test_int_S1_c0_b"
                OpName %unknown "unknown"
                OpName %ok "ok"
@@ -89,122 +92,140 @@
          %21 = OpConstantNull %bool
 %sk_Clockwise = OpVariable %_ptr_Private_bool Private %21
   %vcolor_S0 = OpVariable %_ptr_Private_v4float Private %10
-         %23 = OpTypeFunction %bool
         %int = OpTypeInt 32 1
-%_ptr_Function_int = OpTypePointer Function %int
-         %29 = OpConstantNull %int
-%_ptr_Function_bool = OpTypePointer Function %bool
       %v4int = OpTypeVector %int 4
+         %23 = OpTypeFunction %v4int %v4int %v4int
+         %31 = OpConstantNull %v4int
+     %v4bool = OpTypeVector %bool 4
+%int_n2147483648 = OpConstant %int -2147483648
+         %35 = OpConstantComposite %v4int %int_n2147483648 %int_n2147483648 %int_n2147483648 %int_n2147483648
+     %int_n1 = OpConstant %int -1
+         %38 = OpConstantComposite %v4int %int_n1 %int_n1 %int_n1 %int_n1
+      %int_1 = OpConstant %int 1
+         %43 = OpConstantComposite %v4int %int_1 %int_1 %int_1 %int_1
+         %45 = OpTypeFunction %bool
+%_ptr_Function_int = OpTypePointer Function %int
+         %50 = OpConstantNull %int
+%_ptr_Function_bool = OpTypePointer Function %bool
 %_ptr_Function_v4int = OpTypePointer Function %v4int
-         %35 = OpConstantNull %v4int
        %uint = OpTypeInt 32 0
      %uint_0 = OpConstant %uint 0
 %_ptr_Uniform_float = OpTypePointer Uniform %float
        %true = OpConstantTrue %bool
-     %v4bool = OpTypeVector %bool 4
-      %int_1 = OpConstant %int 1
-         %60 = OpConstantComposite %v4int %int_1 %int_1 %int_1 %int_1
       %int_2 = OpConstant %int 2
-         %73 = OpConstantComposite %v4int %int_2 %int_2 %int_2 %int_2
+         %89 = OpConstantComposite %v4int %int_2 %int_2 %int_2 %int_2
        %void = OpTypeVoid
-         %86 = OpTypeFunction %void
+        %102 = OpTypeFunction %void
 %_ptr_Function_v4float = OpTypePointer Function %v4float
 %_ptr_Function_float = OpTypePointer Function %float
-         %95 = OpConstantNull %float
+        %111 = OpConstantNull %float
     %float_1 = OpConstant %float 1
-        %120 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
+        %136 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
     %float_2 = OpConstant %float 2
-        %133 = OpConstantComposite %v4float %float_2 %float_2 %float_2 %float_2
+        %149 = OpConstantComposite %v4float %float_2 %float_2 %float_2 %float_2
      %uint_2 = OpConstant %uint 2
 %_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
      %uint_1 = OpConstant %uint 1
    %main_out = OpTypeStruct %v4float
-        %162 = OpTypeFunction %main_out %bool %v4float
-%test_int_S1_c0_b = OpFunction %bool None %23
-         %25 = OpLabel
-    %unknown = OpVariable %_ptr_Function_int Function %29
+        %178 = OpTypeFunction %main_out %bool %v4float
+   %tint_div = OpFunction %v4int None %23
+        %lhs = OpFunctionParameter %v4int
+        %rhs = OpFunctionParameter %v4int
+         %29 = OpLabel
+         %32 = OpIEqual %v4bool %rhs %31
+         %36 = OpIEqual %v4bool %lhs %35
+         %39 = OpIEqual %v4bool %rhs %38
+         %40 = OpLogicalAnd %v4bool %36 %39
+         %41 = OpLogicalOr %v4bool %32 %40
+         %30 = OpSelect %v4int %41 %43 %rhs
+         %44 = OpSDiv %v4int %lhs %30
+               OpReturnValue %44
+               OpFunctionEnd
+%test_int_S1_c0_b = OpFunction %bool None %45
+         %47 = OpLabel
+    %unknown = OpVariable %_ptr_Function_int Function %50
          %ok = OpVariable %_ptr_Function_bool Function %21
-        %val = OpVariable %_ptr_Function_v4int Function %35
+        %val = OpVariable %_ptr_Function_v4int Function %31
        %x_40 = OpVariable %_ptr_Function_bool Function %21
        %x_41 = OpVariable %_ptr_Function_bool Function %21
        %x_54 = OpVariable %_ptr_Function_bool Function %21
        %x_55 = OpVariable %_ptr_Function_bool Function %21
        %x_65 = OpVariable %_ptr_Function_bool Function %21
        %x_66 = OpVariable %_ptr_Function_bool Function %21
-         %45 = OpAccessChain %_ptr_Uniform_float %x_4 %uint_0 %uint_0
-         %46 = OpLoad %float %45
-         %47 = OpConvertFToS %int %46
-               OpStore %unknown %47
+         %64 = OpAccessChain %_ptr_Uniform_float %x_4 %uint_0 %uint_0
+         %65 = OpLoad %float %64
+         %66 = OpConvertFToS %int %65
+               OpStore %unknown %66
                OpStore %ok %true
                OpStore %x_41 %21
-               OpSelectionMerge %49 None
-               OpBranchConditional %true %50 %49
-         %50 = OpLabel
-         %52 = OpCompositeConstruct %v4int %47 %47 %47 %47
-         %53 = OpSDiv %v4int %35 %52
-         %54 = OpIEqual %v4bool %53 %35
-         %51 = OpAll %bool %54
-               OpStore %x_40 %51
-         %56 = OpLoad %bool %x_40
-               OpStore %x_41 %56
-               OpBranch %49
-         %49 = OpLabel
-         %57 = OpLoad %bool %x_41
-               OpStore %ok %57
-         %58 = OpCompositeConstruct %v4int %47 %47 %47 %47
-               OpStore %val %58
-         %61 = OpIAdd %v4int %58 %60
-               OpStore %val %61
-         %62 = OpISub %v4int %61 %60
-               OpStore %val %62
-         %63 = OpIAdd %v4int %62 %60
-               OpStore %val %63
-         %64 = OpISub %v4int %63 %60
-               OpStore %val %64
-               OpStore %x_55 %21
-         %65 = OpLoad %bool %x_41
-               OpSelectionMerge %66 None
-               OpBranchConditional %65 %67 %66
-         %67 = OpLabel
-         %69 = OpIEqual %v4bool %64 %58
-         %68 = OpAll %bool %69
-               OpStore %x_54 %68
-         %70 = OpLoad %bool %x_54
-               OpStore %x_55 %70
-               OpBranch %66
-         %66 = OpLabel
-         %71 = OpLoad %bool %x_55
-               OpStore %ok %71
-         %74 = OpIMul %v4int %64 %73
-               OpStore %val %74
-         %75 = OpSDiv %v4int %74 %73
-               OpStore %val %75
-         %76 = OpIMul %v4int %75 %73
+               OpSelectionMerge %68 None
+               OpBranchConditional %true %69 %68
+         %69 = OpLabel
+         %71 = OpCompositeConstruct %v4int %66 %66 %66 %66
+         %70 = OpFunctionCall %v4int %tint_div %31 %71
+         %73 = OpIEqual %v4bool %70 %31
+         %72 = OpAll %bool %73
+               OpStore %x_40 %72
+         %74 = OpLoad %bool %x_40
+               OpStore %x_41 %74
+               OpBranch %68
+         %68 = OpLabel
+         %75 = OpLoad %bool %x_41
+               OpStore %ok %75
+         %76 = OpCompositeConstruct %v4int %66 %66 %66 %66
                OpStore %val %76
-         %77 = OpSDiv %v4int %76 %73
+         %77 = OpIAdd %v4int %76 %43
                OpStore %val %77
+         %78 = OpISub %v4int %77 %43
+               OpStore %val %78
+         %79 = OpIAdd %v4int %78 %43
+               OpStore %val %79
+         %80 = OpISub %v4int %79 %43
+               OpStore %val %80
+               OpStore %x_55 %21
+         %81 = OpLoad %bool %x_41
+               OpSelectionMerge %82 None
+               OpBranchConditional %81 %83 %82
+         %83 = OpLabel
+         %85 = OpIEqual %v4bool %80 %76
+         %84 = OpAll %bool %85
+               OpStore %x_54 %84
+         %86 = OpLoad %bool %x_54
+               OpStore %x_55 %86
+               OpBranch %82
+         %82 = OpLabel
+         %87 = OpLoad %bool %x_55
+               OpStore %ok %87
+         %90 = OpIMul %v4int %80 %89
+               OpStore %val %90
+         %91 = OpFunctionCall %v4int %tint_div %90 %89
+               OpStore %val %91
+         %92 = OpIMul %v4int %91 %89
+               OpStore %val %92
+         %93 = OpFunctionCall %v4int %tint_div %92 %89
+               OpStore %val %93
                OpStore %x_66 %21
-         %78 = OpLoad %bool %x_55
-               OpSelectionMerge %79 None
-               OpBranchConditional %78 %80 %79
-         %80 = OpLabel
-         %82 = OpIEqual %v4bool %77 %58
-         %81 = OpAll %bool %82
-               OpStore %x_65 %81
-         %83 = OpLoad %bool %x_65
-               OpStore %x_66 %83
-               OpBranch %79
-         %79 = OpLabel
-         %84 = OpLoad %bool %x_66
-               OpStore %ok %84
-         %85 = OpLoad %bool %x_66
-               OpReturnValue %85
+         %94 = OpLoad %bool %x_55
+               OpSelectionMerge %95 None
+               OpBranchConditional %94 %96 %95
+         %96 = OpLabel
+         %98 = OpIEqual %v4bool %93 %76
+         %97 = OpAll %bool %98
+               OpStore %x_65 %97
+         %99 = OpLoad %bool %x_65
+               OpStore %x_66 %99
+               OpBranch %95
+         %95 = OpLabel
+        %100 = OpLoad %bool %x_66
+               OpStore %ok %100
+        %101 = OpLoad %bool %x_66
+               OpReturnValue %101
                OpFunctionEnd
-     %main_1 = OpFunction %void None %86
-         %89 = OpLabel
+     %main_1 = OpFunction %void None %102
+        %105 = OpLabel
 %outputColor_S0 = OpVariable %_ptr_Function_v4float Function %10
   %output_S1 = OpVariable %_ptr_Function_v4float Function %10
-%x_8_unknown = OpVariable %_ptr_Function_float Function %95
+%x_8_unknown = OpVariable %_ptr_Function_float Function %111
      %x_9_ok = OpVariable %_ptr_Function_bool Function %21
    %x_10_val = OpVariable %_ptr_Function_v4float Function %10
       %x_116 = OpVariable %_ptr_Function_v4float Function %10
@@ -216,120 +237,120 @@
       %x_111 = OpVariable %_ptr_Function_bool Function %21
       %x_114 = OpVariable %_ptr_Function_bool Function %21
       %x_115 = OpVariable %_ptr_Function_bool Function %21
-        %107 = OpLoad %v4float %vcolor_S0
-               OpStore %outputColor_S0 %107
-        %108 = OpAccessChain %_ptr_Uniform_float %x_4 %uint_0 %uint_0
-        %109 = OpLoad %float %108
-               OpStore %x_8_unknown %109
+        %123 = OpLoad %v4float %vcolor_S0
+               OpStore %outputColor_S0 %123
+        %124 = OpAccessChain %_ptr_Uniform_float %x_4 %uint_0 %uint_0
+        %125 = OpLoad %float %124
+               OpStore %x_8_unknown %125
                OpStore %x_9_ok %true
                OpStore %x_87 %21
-               OpSelectionMerge %110 None
-               OpBranchConditional %true %111 %110
-        %111 = OpLabel
-        %113 = OpCompositeConstruct %v4float %109 %109 %109 %109
-        %114 = OpFDiv %v4float %10 %113
-        %115 = OpFOrdEqual %v4bool %114 %10
-        %112 = OpAll %bool %115
-               OpStore %x_86 %112
-        %116 = OpLoad %bool %x_86
-               OpStore %x_87 %116
-               OpBranch %110
-        %110 = OpLabel
-        %117 = OpLoad %bool %x_87
-               OpStore %x_9_ok %117
-        %118 = OpCompositeConstruct %v4float %109 %109 %109 %109
-               OpStore %x_10_val %118
-        %121 = OpFAdd %v4float %118 %120
-               OpStore %x_10_val %121
-        %122 = OpFSub %v4float %121 %120
-               OpStore %x_10_val %122
-        %123 = OpFAdd %v4float %122 %120
-               OpStore %x_10_val %123
-        %124 = OpFSub %v4float %123 %120
-               OpStore %x_10_val %124
-               OpStore %x_100 %21
-        %125 = OpLoad %bool %x_87
                OpSelectionMerge %126 None
-               OpBranchConditional %125 %127 %126
+               OpBranchConditional %true %127 %126
         %127 = OpLabel
-        %129 = OpFOrdEqual %v4bool %124 %118
-        %128 = OpAll %bool %129
-               OpStore %x_99 %128
-        %130 = OpLoad %bool %x_99
-               OpStore %x_100 %130
+        %129 = OpCompositeConstruct %v4float %125 %125 %125 %125
+        %130 = OpFDiv %v4float %10 %129
+        %131 = OpFOrdEqual %v4bool %130 %10
+        %128 = OpAll %bool %131
+               OpStore %x_86 %128
+        %132 = OpLoad %bool %x_86
+               OpStore %x_87 %132
                OpBranch %126
         %126 = OpLabel
-        %131 = OpLoad %bool %x_100
-               OpStore %x_9_ok %131
-        %134 = OpFMul %v4float %124 %133
+        %133 = OpLoad %bool %x_87
+               OpStore %x_9_ok %133
+        %134 = OpCompositeConstruct %v4float %125 %125 %125 %125
                OpStore %x_10_val %134
-        %135 = OpFDiv %v4float %134 %133
-               OpStore %x_10_val %135
-        %136 = OpFMul %v4float %135 %133
-               OpStore %x_10_val %136
-        %137 = OpFDiv %v4float %136 %133
+        %137 = OpFAdd %v4float %134 %136
                OpStore %x_10_val %137
+        %138 = OpFSub %v4float %137 %136
+               OpStore %x_10_val %138
+        %139 = OpFAdd %v4float %138 %136
+               OpStore %x_10_val %139
+        %140 = OpFSub %v4float %139 %136
+               OpStore %x_10_val %140
+               OpStore %x_100 %21
+        %141 = OpLoad %bool %x_87
+               OpSelectionMerge %142 None
+               OpBranchConditional %141 %143 %142
+        %143 = OpLabel
+        %145 = OpFOrdEqual %v4bool %140 %134
+        %144 = OpAll %bool %145
+               OpStore %x_99 %144
+        %146 = OpLoad %bool %x_99
+               OpStore %x_100 %146
+               OpBranch %142
+        %142 = OpLabel
+        %147 = OpLoad %bool %x_100
+               OpStore %x_9_ok %147
+        %150 = OpFMul %v4float %140 %149
+               OpStore %x_10_val %150
+        %151 = OpFDiv %v4float %150 %149
+               OpStore %x_10_val %151
+        %152 = OpFMul %v4float %151 %149
+               OpStore %x_10_val %152
+        %153 = OpFDiv %v4float %152 %149
+               OpStore %x_10_val %153
                OpStore %x_111 %21
-        %138 = OpLoad %bool %x_100
-               OpSelectionMerge %139 None
-               OpBranchConditional %138 %140 %139
-        %140 = OpLabel
-        %142 = OpFOrdEqual %v4bool %137 %118
-        %141 = OpAll %bool %142
-               OpStore %x_110 %141
-        %143 = OpLoad %bool %x_110
-               OpStore %x_111 %143
-               OpBranch %139
-        %139 = OpLabel
-        %144 = OpLoad %bool %x_111
-               OpStore %x_9_ok %144
+        %154 = OpLoad %bool %x_100
+               OpSelectionMerge %155 None
+               OpBranchConditional %154 %156 %155
+        %156 = OpLabel
+        %158 = OpFOrdEqual %v4bool %153 %134
+        %157 = OpAll %bool %158
+               OpStore %x_110 %157
+        %159 = OpLoad %bool %x_110
+               OpStore %x_111 %159
+               OpBranch %155
+        %155 = OpLabel
+        %160 = OpLoad %bool %x_111
+               OpStore %x_9_ok %160
                OpStore %x_115 %21
-        %145 = OpLoad %bool %x_111
-               OpSelectionMerge %146 None
-               OpBranchConditional %145 %147 %146
-        %147 = OpLabel
-        %148 = OpFunctionCall %bool %test_int_S1_c0_b
-               OpStore %x_114 %148
-        %149 = OpLoad %bool %x_114
-               OpStore %x_115 %149
-               OpBranch %146
-        %146 = OpLabel
-        %150 = OpLoad %bool %x_115
-               OpSelectionMerge %151 None
-               OpBranchConditional %150 %152 %153
-        %152 = OpLabel
-        %156 = OpAccessChain %_ptr_Uniform_v4float %x_4 %uint_0 %uint_2
-        %157 = OpLoad %v4float %156
-               OpStore %x_116 %157
-               OpBranch %151
-        %153 = OpLabel
-        %159 = OpAccessChain %_ptr_Uniform_v4float %x_4 %uint_0 %uint_1
-        %160 = OpLoad %v4float %159
-               OpStore %x_116 %160
-               OpBranch %151
-        %151 = OpLabel
-        %161 = OpLoad %v4float %x_116
-               OpStore %output_S1 %161
-               OpStore %sk_FragColor %161
+        %161 = OpLoad %bool %x_111
+               OpSelectionMerge %162 None
+               OpBranchConditional %161 %163 %162
+        %163 = OpLabel
+        %164 = OpFunctionCall %bool %test_int_S1_c0_b
+               OpStore %x_114 %164
+        %165 = OpLoad %bool %x_114
+               OpStore %x_115 %165
+               OpBranch %162
+        %162 = OpLabel
+        %166 = OpLoad %bool %x_115
+               OpSelectionMerge %167 None
+               OpBranchConditional %166 %168 %169
+        %168 = OpLabel
+        %172 = OpAccessChain %_ptr_Uniform_v4float %x_4 %uint_0 %uint_2
+        %173 = OpLoad %v4float %172
+               OpStore %x_116 %173
+               OpBranch %167
+        %169 = OpLabel
+        %175 = OpAccessChain %_ptr_Uniform_v4float %x_4 %uint_0 %uint_1
+        %176 = OpLoad %v4float %175
+               OpStore %x_116 %176
+               OpBranch %167
+        %167 = OpLabel
+        %177 = OpLoad %v4float %x_116
+               OpStore %output_S1 %177
+               OpStore %sk_FragColor %177
                OpReturn
                OpFunctionEnd
- %main_inner = OpFunction %main_out None %162
+ %main_inner = OpFunction %main_out None %178
 %sk_Clockwise_param = OpFunctionParameter %bool
 %vcolor_S0_param = OpFunctionParameter %v4float
-        %167 = OpLabel
+        %183 = OpLabel
                OpStore %sk_Clockwise %sk_Clockwise_param
                OpStore %vcolor_S0 %vcolor_S0_param
-        %168 = OpFunctionCall %void %main_1
-        %169 = OpLoad %v4float %sk_FragColor
-        %170 = OpCompositeConstruct %main_out %169
-               OpReturnValue %170
+        %184 = OpFunctionCall %void %main_1
+        %185 = OpLoad %v4float %sk_FragColor
+        %186 = OpCompositeConstruct %main_out %185
+               OpReturnValue %186
                OpFunctionEnd
-       %main = OpFunction %void None %86
-        %172 = OpLabel
-        %174 = OpLoad %bool %sk_Clockwise_param_1
-        %175 = OpLoad %v4float %vcolor_S0_param_1
-        %173 = OpFunctionCall %main_out %main_inner %174 %175
-        %176 = OpCompositeExtract %v4float %173 0
-               OpStore %sk_FragColor_1_1 %176
+       %main = OpFunction %void None %102
+        %188 = OpLabel
+        %190 = OpLoad %bool %sk_Clockwise_param_1
+        %191 = OpLoad %v4float %vcolor_S0_param_1
+        %189 = OpFunctionCall %main_out %main_inner %190 %191
+        %192 = OpCompositeExtract %v4float %189 0
+               OpStore %sk_FragColor_1_1 %192
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/bug/tint/221.wgsl.expected.dxc.hlsl b/test/tint/bug/tint/221.wgsl.expected.dxc.hlsl
index ea467ea..708904c 100644
--- a/test/tint/bug/tint/221.wgsl.expected.dxc.hlsl
+++ b/test/tint/bug/tint/221.wgsl.expected.dxc.hlsl
@@ -1,3 +1,7 @@
+uint tint_mod(uint lhs, uint rhs) {
+  return (lhs % ((rhs == 0u) ? 1u : rhs));
+}
+
 RWByteAddressBuffer b : register(u0, space0);
 
 [numthreads(1, 1, 1)]
@@ -8,7 +12,8 @@
       break;
     }
     const uint p_save = i;
-    if (((i % 2u) == 0u)) {
+    const uint tint_symbol = tint_mod(i, 2u);
+    if ((tint_symbol == 0u)) {
       {
         b.Store((4u + (4u * p_save)), asuint((b.Load((4u + (4u * p_save))) * 2u)));
         i = (i + 1u);
diff --git a/test/tint/bug/tint/221.wgsl.expected.fxc.hlsl b/test/tint/bug/tint/221.wgsl.expected.fxc.hlsl
index ea467ea..708904c 100644
--- a/test/tint/bug/tint/221.wgsl.expected.fxc.hlsl
+++ b/test/tint/bug/tint/221.wgsl.expected.fxc.hlsl
@@ -1,3 +1,7 @@
+uint tint_mod(uint lhs, uint rhs) {
+  return (lhs % ((rhs == 0u) ? 1u : rhs));
+}
+
 RWByteAddressBuffer b : register(u0, space0);
 
 [numthreads(1, 1, 1)]
@@ -8,7 +12,8 @@
       break;
     }
     const uint p_save = i;
-    if (((i % 2u) == 0u)) {
+    const uint tint_symbol = tint_mod(i, 2u);
+    if ((tint_symbol == 0u)) {
       {
         b.Store((4u + (4u * p_save)), asuint((b.Load((4u + (4u * p_save))) * 2u)));
         i = (i + 1u);
diff --git a/test/tint/bug/tint/221.wgsl.expected.glsl b/test/tint/bug/tint/221.wgsl.expected.glsl
index f00f6e2..5f6890f 100644
--- a/test/tint/bug/tint/221.wgsl.expected.glsl
+++ b/test/tint/bug/tint/221.wgsl.expected.glsl
@@ -1,5 +1,9 @@
 #version 310 es
 
+uint tint_mod(uint lhs, uint rhs) {
+  return (lhs % ((rhs == 0u) ? 1u : rhs));
+}
+
 struct Buf {
   uint count;
   uint data[50];
@@ -16,7 +20,8 @@
       break;
     }
     uint p_save = i;
-    if (((i % 2u) == 0u)) {
+    uint tint_symbol_1 = tint_mod(i, 2u);
+    if ((tint_symbol_1 == 0u)) {
       {
         b.inner.data[p_save] = (b.inner.data[p_save] * 2u);
         i = (i + 1u);
diff --git a/test/tint/bug/tint/221.wgsl.expected.msl b/test/tint/bug/tint/221.wgsl.expected.msl
index ad7d150..7e30a18 100644
--- a/test/tint/bug/tint/221.wgsl.expected.msl
+++ b/test/tint/bug/tint/221.wgsl.expected.msl
@@ -14,28 +14,33 @@
     T elements[N];
 };
 
+uint tint_mod(uint lhs, uint rhs) {
+  return (lhs % select(rhs, 1u, (rhs == 0u)));
+}
+
 struct Buf {
   /* 0x0000 */ uint count;
   /* 0x0004 */ tint_array<uint, 50> data;
 };
 
-kernel void tint_symbol(device Buf* tint_symbol_1 [[buffer(0)]]) {
+kernel void tint_symbol(device Buf* tint_symbol_2 [[buffer(0)]]) {
   uint i = 0u;
   while (true) {
-    if ((i >= (*(tint_symbol_1)).count)) {
+    if ((i >= (*(tint_symbol_2)).count)) {
       break;
     }
     uint const p_save = i;
-    if (((i % 2u) == 0u)) {
+    uint const tint_symbol_1 = tint_mod(i, 2u);
+    if ((tint_symbol_1 == 0u)) {
       {
-        (*(tint_symbol_1)).data[p_save] = ((*(tint_symbol_1)).data[p_save] * 2u);
+        (*(tint_symbol_2)).data[p_save] = ((*(tint_symbol_2)).data[p_save] * 2u);
         i = (i + 1u);
       }
       continue;
     }
-    (*(tint_symbol_1)).data[p_save] = 0u;
+    (*(tint_symbol_2)).data[p_save] = 0u;
     {
-      (*(tint_symbol_1)).data[p_save] = ((*(tint_symbol_1)).data[p_save] * 2u);
+      (*(tint_symbol_2)).data[p_save] = ((*(tint_symbol_2)).data[p_save] * 2u);
       i = (i + 1u);
     }
   }
diff --git a/test/tint/bug/tint/221.wgsl.expected.spvasm b/test/tint/bug/tint/221.wgsl.expected.spvasm
index 45ee7a7..335ac8a 100644
--- a/test/tint/bug/tint/221.wgsl.expected.spvasm
+++ b/test/tint/bug/tint/221.wgsl.expected.spvasm
@@ -1,7 +1,7 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 43
+; Bound: 51
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
@@ -13,6 +13,9 @@
                OpMemberName %Buf 0 "count"
                OpMemberName %Buf 1 "data"
                OpName %b "b"
+               OpName %tint_mod "tint_mod"
+               OpName %lhs "lhs"
+               OpName %rhs "rhs"
                OpName %main "main"
                OpName %i "i"
                OpDecorate %b_block Block
@@ -29,55 +32,65 @@
     %b_block = OpTypeStruct %Buf
 %_ptr_StorageBuffer_b_block = OpTypePointer StorageBuffer %b_block
           %b = OpVariable %_ptr_StorageBuffer_b_block StorageBuffer
+          %8 = OpTypeFunction %uint %uint %uint
+         %14 = OpConstantNull %uint
+       %bool = OpTypeBool
+     %uint_1 = OpConstant %uint 1
        %void = OpTypeVoid
-          %8 = OpTypeFunction %void
-         %12 = OpConstantNull %uint
+         %19 = OpTypeFunction %void
 %_ptr_Function_uint = OpTypePointer Function %uint
      %uint_0 = OpConstant %uint 0
 %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
-       %bool = OpTypeBool
      %uint_2 = OpConstant %uint 2
-     %uint_1 = OpConstant %uint 1
-       %main = OpFunction %void None %8
-         %11 = OpLabel
-          %i = OpVariable %_ptr_Function_uint Function %12
-               OpStore %i %12
-               OpBranch %15
-         %15 = OpLabel
-               OpLoopMerge %16 %17 None
-               OpBranch %18
-         %18 = OpLabel
-         %19 = OpLoad %uint %i
-         %22 = OpAccessChain %_ptr_StorageBuffer_uint %b %uint_0 %uint_0
-         %23 = OpLoad %uint %22
-         %24 = OpUGreaterThanEqual %bool %19 %23
-               OpSelectionMerge %26 None
-               OpBranchConditional %24 %27 %26
-         %27 = OpLabel
-               OpBranch %16
-         %26 = OpLabel
-         %28 = OpLoad %uint %i
+   %tint_mod = OpFunction %uint None %8
+        %lhs = OpFunctionParameter %uint
+        %rhs = OpFunctionParameter %uint
+         %12 = OpLabel
+         %15 = OpIEqual %bool %rhs %14
+         %13 = OpSelect %uint %15 %uint_1 %rhs
+         %18 = OpUMod %uint %lhs %13
+               OpReturnValue %18
+               OpFunctionEnd
+       %main = OpFunction %void None %19
+         %22 = OpLabel
+          %i = OpVariable %_ptr_Function_uint Function %14
+               OpStore %i %14
+               OpBranch %25
+         %25 = OpLabel
+               OpLoopMerge %26 %27 None
+               OpBranch %28
+         %28 = OpLabel
          %29 = OpLoad %uint %i
-         %31 = OpUMod %uint %29 %uint_2
-         %32 = OpIEqual %bool %31 %12
-               OpSelectionMerge %33 None
-               OpBranchConditional %32 %34 %33
-         %34 = OpLabel
-               OpBranch %17
-         %33 = OpLabel
-         %36 = OpAccessChain %_ptr_StorageBuffer_uint %b %uint_0 %uint_1 %28
-               OpStore %36 %12
-               OpBranch %17
-         %17 = OpLabel
-         %37 = OpAccessChain %_ptr_StorageBuffer_uint %b %uint_0 %uint_1 %28
-         %38 = OpAccessChain %_ptr_StorageBuffer_uint %b %uint_0 %uint_1 %28
-         %39 = OpLoad %uint %38
-         %40 = OpIMul %uint %39 %uint_2
-               OpStore %37 %40
-         %41 = OpLoad %uint %i
-         %42 = OpIAdd %uint %41 %uint_1
-               OpStore %i %42
-               OpBranch %15
-         %16 = OpLabel
+         %32 = OpAccessChain %_ptr_StorageBuffer_uint %b %uint_0 %uint_0
+         %33 = OpLoad %uint %32
+         %34 = OpUGreaterThanEqual %bool %29 %33
+               OpSelectionMerge %35 None
+               OpBranchConditional %34 %36 %35
+         %36 = OpLabel
+               OpBranch %26
+         %35 = OpLabel
+         %37 = OpLoad %uint %i
+         %39 = OpLoad %uint %i
+         %38 = OpFunctionCall %uint %tint_mod %39 %uint_2
+         %41 = OpIEqual %bool %38 %14
+               OpSelectionMerge %42 None
+               OpBranchConditional %41 %43 %42
+         %43 = OpLabel
+               OpBranch %27
+         %42 = OpLabel
+         %44 = OpAccessChain %_ptr_StorageBuffer_uint %b %uint_0 %uint_1 %37
+               OpStore %44 %14
+               OpBranch %27
+         %27 = OpLabel
+         %45 = OpAccessChain %_ptr_StorageBuffer_uint %b %uint_0 %uint_1 %37
+         %46 = OpAccessChain %_ptr_StorageBuffer_uint %b %uint_0 %uint_1 %37
+         %47 = OpLoad %uint %46
+         %48 = OpIMul %uint %47 %uint_2
+               OpStore %45 %48
+         %49 = OpLoad %uint %i
+         %50 = OpIAdd %uint %49 %uint_1
+               OpStore %i %50
+               OpBranch %25
+         %26 = OpLabel
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/bug/tint/914.wgsl.expected.dxc.hlsl b/test/tint/bug/tint/914.wgsl.expected.dxc.hlsl
index eef4cd9..a893add 100644
--- a/test/tint/bug/tint/914.wgsl.expected.dxc.hlsl
+++ b/test/tint/bug/tint/914.wgsl.expected.dxc.hlsl
@@ -1,3 +1,7 @@
+uint tint_div(uint lhs, uint rhs) {
+  return (lhs / ((rhs == 0u) ? 1u : rhs));
+}
+
 ByteAddressBuffer firstMatrix : register(t0, space0);
 ByteAddressBuffer secondMatrix : register(t1, space0);
 RWByteAddressBuffer resultMatrix : register(u2, space0);
@@ -63,7 +67,8 @@
   const uint tileCol = (local_id.x * 4u);
   const uint globalRow = (global_id.y * 4u);
   const uint globalCol = (global_id.x * 4u);
-  const uint numTiles = (((uniforms[0].y - 1u) / 64u) + 1u);
+  const uint tint_symbol_2 = tint_div((uniforms[0].y - 1u), 64u);
+  const uint numTiles = (tint_symbol_2 + 1u);
   float acc[16] = (float[16])0;
   float ACached = 0.0f;
   float BCached[4] = (float[4])0;
@@ -84,8 +89,8 @@
             for(uint innerCol = 0u; (innerCol < ColPerThreadA); innerCol = (innerCol + 1u)) {
               const uint inputRow = (tileRow + innerRow);
               const uint inputCol = (tileColA + innerCol);
-              const float tint_symbol_2 = mm_readA((globalRow + innerRow), ((t * 64u) + inputCol));
-              mm_Asub[inputRow][inputCol] = tint_symbol_2;
+              const float tint_symbol_3 = mm_readA((globalRow + innerRow), ((t * 64u) + inputCol));
+              mm_Asub[inputRow][inputCol] = tint_symbol_3;
             }
           }
         }
@@ -96,8 +101,8 @@
             for(uint innerCol = 0u; (innerCol < 4u); innerCol = (innerCol + 1u)) {
               const uint inputRow = (tileRowB + innerRow);
               const uint inputCol = (tileCol + innerCol);
-              const float tint_symbol_3 = mm_readB(((t * 64u) + inputRow), (globalCol + innerCol));
-              mm_Bsub[innerCol][inputCol] = tint_symbol_3;
+              const float tint_symbol_4 = mm_readB(((t * 64u) + inputRow), (globalCol + innerCol));
+              mm_Bsub[innerCol][inputCol] = tint_symbol_4;
             }
           }
         }
diff --git a/test/tint/bug/tint/914.wgsl.expected.fxc.hlsl b/test/tint/bug/tint/914.wgsl.expected.fxc.hlsl
index eef4cd9..a893add 100644
--- a/test/tint/bug/tint/914.wgsl.expected.fxc.hlsl
+++ b/test/tint/bug/tint/914.wgsl.expected.fxc.hlsl
@@ -1,3 +1,7 @@
+uint tint_div(uint lhs, uint rhs) {
+  return (lhs / ((rhs == 0u) ? 1u : rhs));
+}
+
 ByteAddressBuffer firstMatrix : register(t0, space0);
 ByteAddressBuffer secondMatrix : register(t1, space0);
 RWByteAddressBuffer resultMatrix : register(u2, space0);
@@ -63,7 +67,8 @@
   const uint tileCol = (local_id.x * 4u);
   const uint globalRow = (global_id.y * 4u);
   const uint globalCol = (global_id.x * 4u);
-  const uint numTiles = (((uniforms[0].y - 1u) / 64u) + 1u);
+  const uint tint_symbol_2 = tint_div((uniforms[0].y - 1u), 64u);
+  const uint numTiles = (tint_symbol_2 + 1u);
   float acc[16] = (float[16])0;
   float ACached = 0.0f;
   float BCached[4] = (float[4])0;
@@ -84,8 +89,8 @@
             for(uint innerCol = 0u; (innerCol < ColPerThreadA); innerCol = (innerCol + 1u)) {
               const uint inputRow = (tileRow + innerRow);
               const uint inputCol = (tileColA + innerCol);
-              const float tint_symbol_2 = mm_readA((globalRow + innerRow), ((t * 64u) + inputCol));
-              mm_Asub[inputRow][inputCol] = tint_symbol_2;
+              const float tint_symbol_3 = mm_readA((globalRow + innerRow), ((t * 64u) + inputCol));
+              mm_Asub[inputRow][inputCol] = tint_symbol_3;
             }
           }
         }
@@ -96,8 +101,8 @@
             for(uint innerCol = 0u; (innerCol < 4u); innerCol = (innerCol + 1u)) {
               const uint inputRow = (tileRowB + innerRow);
               const uint inputCol = (tileCol + innerCol);
-              const float tint_symbol_3 = mm_readB(((t * 64u) + inputRow), (globalCol + innerCol));
-              mm_Bsub[innerCol][inputCol] = tint_symbol_3;
+              const float tint_symbol_4 = mm_readB(((t * 64u) + inputRow), (globalCol + innerCol));
+              mm_Bsub[innerCol][inputCol] = tint_symbol_4;
             }
           }
         }
diff --git a/test/tint/bug/tint/914.wgsl.expected.glsl b/test/tint/bug/tint/914.wgsl.expected.glsl
index 31c557b..2797131 100644
--- a/test/tint/bug/tint/914.wgsl.expected.glsl
+++ b/test/tint/bug/tint/914.wgsl.expected.glsl
@@ -1,5 +1,9 @@
 #version 310 es
 
+uint tint_div(uint lhs, uint rhs) {
+  return (lhs / ((rhs == 0u) ? 1u : rhs));
+}
+
 struct Uniforms {
   uint dimAOuter;
   uint dimInner;
@@ -74,7 +78,8 @@
   uint tileCol = (local_id.x * 4u);
   uint globalRow = (global_id.y * 4u);
   uint globalCol = (global_id.x * 4u);
-  uint numTiles = (((uniforms.inner.dimInner - 1u) / 64u) + 1u);
+  uint tint_symbol_1 = tint_div((uniforms.inner.dimInner - 1u), 64u);
+  uint numTiles = (tint_symbol_1 + 1u);
   float acc[16] = float[16](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);
   float ACached = 0.0f;
   float BCached[4] = float[4](0.0f, 0.0f, 0.0f, 0.0f);
@@ -95,8 +100,8 @@
             for(uint innerCol = 0u; (innerCol < ColPerThreadA); innerCol = (innerCol + 1u)) {
               uint inputRow = (tileRow + innerRow);
               uint inputCol = (tileColA + innerCol);
-              float tint_symbol_1 = mm_readA((globalRow + innerRow), ((t * 64u) + inputCol));
-              mm_Asub[inputRow][inputCol] = tint_symbol_1;
+              float tint_symbol_2 = mm_readA((globalRow + innerRow), ((t * 64u) + inputCol));
+              mm_Asub[inputRow][inputCol] = tint_symbol_2;
             }
           }
         }
@@ -107,8 +112,8 @@
             for(uint innerCol = 0u; (innerCol < 4u); innerCol = (innerCol + 1u)) {
               uint inputRow = (tileRowB + innerRow);
               uint inputCol = (tileCol + innerCol);
-              float tint_symbol_2 = mm_readB(((t * 64u) + inputRow), (globalCol + innerCol));
-              mm_Bsub[innerCol][inputCol] = tint_symbol_2;
+              float tint_symbol_3 = mm_readB(((t * 64u) + inputRow), (globalCol + innerCol));
+              mm_Bsub[innerCol][inputCol] = tint_symbol_3;
             }
           }
         }
diff --git a/test/tint/bug/tint/914.wgsl.expected.msl b/test/tint/bug/tint/914.wgsl.expected.msl
index e1eaf8e..b7dec33 100644
--- a/test/tint/bug/tint/914.wgsl.expected.msl
+++ b/test/tint/bug/tint/914.wgsl.expected.msl
@@ -14,6 +14,10 @@
     T elements[N];
 };
 
+uint tint_div(uint lhs, uint rhs) {
+  return (lhs / select(rhs, 1u, (rhs == 0u)));
+}
+
 struct Uniforms {
   /* 0x0000 */ uint dimAOuter;
   /* 0x0004 */ uint dimInner;
@@ -24,42 +28,43 @@
   /* 0x0000 */ tint_array<float, 1> numbers;
 };
 
-float mm_readA(uint row, uint col, const constant Uniforms* const tint_symbol_3, const device Matrix* const tint_symbol_4) {
-  if (((row < (*(tint_symbol_3)).dimAOuter) && (col < (*(tint_symbol_3)).dimInner))) {
-    float const result = (*(tint_symbol_4)).numbers[((row * (*(tint_symbol_3)).dimInner) + col)];
+float mm_readA(uint row, uint col, const constant Uniforms* const tint_symbol_4, const device Matrix* const tint_symbol_5) {
+  if (((row < (*(tint_symbol_4)).dimAOuter) && (col < (*(tint_symbol_4)).dimInner))) {
+    float const result = (*(tint_symbol_5)).numbers[((row * (*(tint_symbol_4)).dimInner) + col)];
     return result;
   }
   return 0.0f;
 }
 
-float mm_readB(uint row, uint col, const constant Uniforms* const tint_symbol_5, const device Matrix* const tint_symbol_6) {
-  if (((row < (*(tint_symbol_5)).dimInner) && (col < (*(tint_symbol_5)).dimBOuter))) {
-    float const result = (*(tint_symbol_6)).numbers[((row * (*(tint_symbol_5)).dimBOuter) + col)];
+float mm_readB(uint row, uint col, const constant Uniforms* const tint_symbol_6, const device Matrix* const tint_symbol_7) {
+  if (((row < (*(tint_symbol_6)).dimInner) && (col < (*(tint_symbol_6)).dimBOuter))) {
+    float const result = (*(tint_symbol_7)).numbers[((row * (*(tint_symbol_6)).dimBOuter) + col)];
     return result;
   }
   return 0.0f;
 }
 
-void mm_write(uint row, uint col, float value, const constant Uniforms* const tint_symbol_7, device Matrix* const tint_symbol_8) {
-  if (((row < (*(tint_symbol_7)).dimAOuter) && (col < (*(tint_symbol_7)).dimBOuter))) {
-    uint const index = (col + (row * (*(tint_symbol_7)).dimBOuter));
-    (*(tint_symbol_8)).numbers[index] = value;
+void mm_write(uint row, uint col, float value, const constant Uniforms* const tint_symbol_8, device Matrix* const tint_symbol_9) {
+  if (((row < (*(tint_symbol_8)).dimAOuter) && (col < (*(tint_symbol_8)).dimBOuter))) {
+    uint const index = (col + (row * (*(tint_symbol_8)).dimBOuter));
+    (*(tint_symbol_9)).numbers[index] = value;
   }
 }
 
-void tint_symbol_inner(uint3 local_id, uint3 global_id, uint local_invocation_index, threadgroup tint_array<tint_array<float, 64>, 64>* const tint_symbol_9, threadgroup tint_array<tint_array<float, 64>, 64>* const tint_symbol_10, const constant Uniforms* const tint_symbol_11, const device Matrix* const tint_symbol_12, const device Matrix* const tint_symbol_13, device Matrix* const tint_symbol_14) {
+void tint_symbol_inner(uint3 local_id, uint3 global_id, uint local_invocation_index, threadgroup tint_array<tint_array<float, 64>, 64>* const tint_symbol_10, threadgroup tint_array<tint_array<float, 64>, 64>* const tint_symbol_11, const constant Uniforms* const tint_symbol_12, const device Matrix* const tint_symbol_13, const device Matrix* const tint_symbol_14, device Matrix* const tint_symbol_15) {
   for(uint idx = local_invocation_index; (idx < 4096u); idx = (idx + 256u)) {
     uint const i = (idx / 64u);
     uint const i_1 = (idx % 64u);
-    (*(tint_symbol_9))[i][i_1] = 0.0f;
     (*(tint_symbol_10))[i][i_1] = 0.0f;
+    (*(tint_symbol_11))[i][i_1] = 0.0f;
   }
   threadgroup_barrier(mem_flags::mem_threadgroup);
   uint const tileRow = (local_id[1] * 4u);
   uint const tileCol = (local_id[0] * 4u);
   uint const globalRow = (global_id[1] * 4u);
   uint const globalCol = (global_id[0] * 4u);
-  uint const numTiles = ((((*(tint_symbol_11)).dimInner - 1u) / 64u) + 1u);
+  uint const tint_symbol_1 = tint_div(((*(tint_symbol_12)).dimInner - 1u), 64u);
+  uint const numTiles = (tint_symbol_1 + 1u);
   tint_array<float, 16> acc = {};
   float ACached = 0.0f;
   tint_array<float, 4> BCached = {};
@@ -75,25 +80,25 @@
       for(uint innerCol = 0u; (innerCol < ColPerThreadA); innerCol = (innerCol + 1u)) {
         uint const inputRow = (tileRow + innerRow);
         uint const inputCol = (tileColA + innerCol);
-        float const tint_symbol_1 = mm_readA((globalRow + innerRow), ((t * 64u) + inputCol), tint_symbol_11, tint_symbol_12);
-        (*(tint_symbol_9))[inputRow][inputCol] = tint_symbol_1;
+        float const tint_symbol_2 = mm_readA((globalRow + innerRow), ((t * 64u) + inputCol), tint_symbol_12, tint_symbol_13);
+        (*(tint_symbol_10))[inputRow][inputCol] = tint_symbol_2;
       }
     }
     for(uint innerRow = 0u; (innerRow < RowPerThreadB); innerRow = (innerRow + 1u)) {
       for(uint innerCol = 0u; (innerCol < 4u); innerCol = (innerCol + 1u)) {
         uint const inputRow = (tileRowB + innerRow);
         uint const inputCol = (tileCol + innerCol);
-        float const tint_symbol_2 = mm_readB(((t * 64u) + inputRow), (globalCol + innerCol), tint_symbol_11, tint_symbol_13);
-        (*(tint_symbol_10))[innerCol][inputCol] = tint_symbol_2;
+        float const tint_symbol_3 = mm_readB(((t * 64u) + inputRow), (globalCol + innerCol), tint_symbol_12, tint_symbol_14);
+        (*(tint_symbol_11))[innerCol][inputCol] = tint_symbol_3;
       }
     }
     threadgroup_barrier(mem_flags::mem_threadgroup);
     for(uint k = 0u; (k < 64u); k = (k + 1u)) {
       for(uint inner = 0u; (inner < 4u); inner = (inner + 1u)) {
-        BCached[inner] = (*(tint_symbol_10))[k][(tileCol + inner)];
+        BCached[inner] = (*(tint_symbol_11))[k][(tileCol + inner)];
       }
       for(uint innerRow = 0u; (innerRow < 4u); innerRow = (innerRow + 1u)) {
-        ACached = (*(tint_symbol_9))[(tileRow + innerRow)][k];
+        ACached = (*(tint_symbol_10))[(tileRow + innerRow)][k];
         for(uint innerCol = 0u; (innerCol < 4u); innerCol = (innerCol + 1u)) {
           uint const index = ((innerRow * 4u) + innerCol);
           acc[index] = (acc[index] + (ACached * BCached[innerCol]));
@@ -105,15 +110,15 @@
   for(uint innerRow = 0u; (innerRow < 4u); innerRow = (innerRow + 1u)) {
     for(uint innerCol = 0u; (innerCol < 4u); innerCol = (innerCol + 1u)) {
       uint const index = ((innerRow * 4u) + innerCol);
-      mm_write((globalRow + innerRow), (globalCol + innerCol), acc[index], tint_symbol_11, tint_symbol_14);
+      mm_write((globalRow + innerRow), (globalCol + innerCol), acc[index], tint_symbol_12, tint_symbol_15);
     }
   }
 }
 
-kernel void tint_symbol(const constant Uniforms* tint_symbol_17 [[buffer(0)]], const device Matrix* tint_symbol_18 [[buffer(2)]], const device Matrix* tint_symbol_19 [[buffer(3)]], device Matrix* tint_symbol_20 [[buffer(1)]], uint3 local_id [[thread_position_in_threadgroup]], uint3 global_id [[thread_position_in_grid]], uint local_invocation_index [[thread_index_in_threadgroup]]) {
-  threadgroup tint_array<tint_array<float, 64>, 64> tint_symbol_15;
+kernel void tint_symbol(const constant Uniforms* tint_symbol_18 [[buffer(0)]], const device Matrix* tint_symbol_19 [[buffer(2)]], const device Matrix* tint_symbol_20 [[buffer(3)]], device Matrix* tint_symbol_21 [[buffer(1)]], uint3 local_id [[thread_position_in_threadgroup]], uint3 global_id [[thread_position_in_grid]], uint local_invocation_index [[thread_index_in_threadgroup]]) {
   threadgroup tint_array<tint_array<float, 64>, 64> tint_symbol_16;
-  tint_symbol_inner(local_id, global_id, local_invocation_index, &(tint_symbol_15), &(tint_symbol_16), tint_symbol_17, tint_symbol_18, tint_symbol_19, tint_symbol_20);
+  threadgroup tint_array<tint_array<float, 64>, 64> tint_symbol_17;
+  tint_symbol_inner(local_id, global_id, local_invocation_index, &(tint_symbol_16), &(tint_symbol_17), tint_symbol_18, tint_symbol_19, tint_symbol_20, tint_symbol_21);
   return;
 }
 
diff --git a/test/tint/bug/tint/914.wgsl.expected.spvasm b/test/tint/bug/tint/914.wgsl.expected.spvasm
index f6ddfb7..f7719e0 100644
--- a/test/tint/bug/tint/914.wgsl.expected.spvasm
+++ b/test/tint/bug/tint/914.wgsl.expected.spvasm
@@ -1,7 +1,7 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 389
+; Bound: 397
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
@@ -24,6 +24,9 @@
                OpName %uniforms "uniforms"
                OpName %mm_Asub "mm_Asub"
                OpName %mm_Bsub "mm_Bsub"
+               OpName %tint_div "tint_div"
+               OpName %lhs "lhs"
+               OpName %rhs "rhs"
                OpName %mm_readA "mm_readA"
                OpName %row "row"
                OpName %col "col"
@@ -109,23 +112,24 @@
 %_ptr_Workgroup__arr__arr_float_uint_64_uint_64 = OpTypePointer Workgroup %_arr__arr_float_uint_64_uint_64
     %mm_Asub = OpVariable %_ptr_Workgroup__arr__arr_float_uint_64_uint_64 Workgroup
     %mm_Bsub = OpVariable %_ptr_Workgroup__arr__arr_float_uint_64_uint_64 Workgroup
-         %25 = OpTypeFunction %float %uint %uint
+         %25 = OpTypeFunction %uint %uint %uint
+         %31 = OpConstantNull %uint
        %bool = OpTypeBool
+     %uint_1 = OpConstant %uint 1
+         %36 = OpTypeFunction %float %uint %uint
 %_ptr_Function_bool = OpTypePointer Function %bool
-         %33 = OpConstantNull %bool
+         %43 = OpConstantNull %bool
 %_ptr_Function_float = OpTypePointer Function %float
-         %36 = OpConstantNull %float
+         %46 = OpConstantNull %float
      %uint_0 = OpConstant %uint 0
 %_ptr_Uniform_uint = OpTypePointer Uniform %uint
-     %uint_1 = OpConstant %uint 1
 %_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %float
        %true = OpConstantTrue %bool
      %uint_2 = OpConstant %uint 2
        %void = OpTypeVoid
-         %93 = OpTypeFunction %void %uint %uint %float
-        %116 = OpTypeFunction %void %v3uint %v3uint %uint
+        %102 = OpTypeFunction %void %uint %uint %float
+        %125 = OpTypeFunction %void %v3uint %v3uint %uint
 %_ptr_Function_uint = OpTypePointer Function %uint
-        %124 = OpConstantNull %uint
   %uint_4096 = OpConstant %uint 4096
 %_ptr_Workgroup_float = OpTypePointer Workgroup %float
    %uint_256 = OpConstant %uint 256
@@ -134,523 +138,532 @@
     %uint_16 = OpConstant %uint 16
 %_arr_float_uint_16 = OpTypeArray %float %uint_16
 %_ptr_Function__arr_float_uint_16 = OpTypePointer Function %_arr_float_uint_16
-        %165 = OpConstantNull %_arr_float_uint_16
+        %173 = OpConstantNull %_arr_float_uint_16
 %_arr_float_uint_4 = OpTypeArray %float %uint_4
 %_ptr_Function__arr_float_uint_4 = OpTypePointer Function %_arr_float_uint_4
-        %170 = OpConstantNull %_arr_float_uint_4
-        %382 = OpTypeFunction %void
-   %mm_readA = OpFunction %float None %25
+        %178 = OpConstantNull %_arr_float_uint_4
+        %390 = OpTypeFunction %void
+   %tint_div = OpFunction %uint None %25
+        %lhs = OpFunctionParameter %uint
+        %rhs = OpFunctionParameter %uint
+         %29 = OpLabel
+         %32 = OpIEqual %bool %rhs %31
+         %30 = OpSelect %uint %32 %uint_1 %rhs
+         %35 = OpUDiv %uint %lhs %30
+               OpReturnValue %35
+               OpFunctionEnd
+   %mm_readA = OpFunction %float None %36
         %row = OpFunctionParameter %uint
         %col = OpFunctionParameter %uint
-         %29 = OpLabel
-%tint_return_flag = OpVariable %_ptr_Function_bool Function %33
-%tint_return_value = OpVariable %_ptr_Function_float Function %36
-         %39 = OpAccessChain %_ptr_Uniform_uint %uniforms %uint_0 %uint_0
-         %40 = OpLoad %uint %39
-         %41 = OpULessThan %bool %row %40
-               OpSelectionMerge %42 None
-               OpBranchConditional %41 %43 %42
-         %43 = OpLabel
-         %45 = OpAccessChain %_ptr_Uniform_uint %uniforms %uint_0 %uint_1
-         %46 = OpLoad %uint %45
-         %47 = OpULessThan %bool %col %46
-               OpBranch %42
-         %42 = OpLabel
-         %48 = OpPhi %bool %41 %29 %47 %43
-               OpSelectionMerge %49 None
-               OpBranchConditional %48 %50 %49
-         %50 = OpLabel
-         %51 = OpAccessChain %_ptr_Uniform_uint %uniforms %uint_0 %uint_1
-         %52 = OpLoad %uint %51
-         %53 = OpIMul %uint %row %52
-         %54 = OpIAdd %uint %53 %col
-         %56 = OpAccessChain %_ptr_StorageBuffer_float %firstMatrix %uint_0 %54
-         %57 = OpLoad %float %56
+         %40 = OpLabel
+%tint_return_flag = OpVariable %_ptr_Function_bool Function %43
+%tint_return_value = OpVariable %_ptr_Function_float Function %46
+         %49 = OpAccessChain %_ptr_Uniform_uint %uniforms %uint_0 %uint_0
+         %50 = OpLoad %uint %49
+         %51 = OpULessThan %bool %row %50
+               OpSelectionMerge %52 None
+               OpBranchConditional %51 %53 %52
+         %53 = OpLabel
+         %54 = OpAccessChain %_ptr_Uniform_uint %uniforms %uint_0 %uint_1
+         %55 = OpLoad %uint %54
+         %56 = OpULessThan %bool %col %55
+               OpBranch %52
+         %52 = OpLabel
+         %57 = OpPhi %bool %51 %40 %56 %53
+               OpSelectionMerge %58 None
+               OpBranchConditional %57 %59 %58
+         %59 = OpLabel
+         %60 = OpAccessChain %_ptr_Uniform_uint %uniforms %uint_0 %uint_1
+         %61 = OpLoad %uint %60
+         %62 = OpIMul %uint %row %61
+         %63 = OpIAdd %uint %62 %col
+         %65 = OpAccessChain %_ptr_StorageBuffer_float %firstMatrix %uint_0 %63
+         %66 = OpLoad %float %65
                OpStore %tint_return_flag %true
-               OpStore %tint_return_value %57
-               OpBranch %49
-         %49 = OpLabel
-         %60 = OpLoad %bool %tint_return_flag
-         %59 = OpLogicalNot %bool %60
-               OpSelectionMerge %61 None
-               OpBranchConditional %59 %62 %61
-         %62 = OpLabel
+               OpStore %tint_return_value %66
+               OpBranch %58
+         %58 = OpLabel
+         %69 = OpLoad %bool %tint_return_flag
+         %68 = OpLogicalNot %bool %69
+               OpSelectionMerge %70 None
+               OpBranchConditional %68 %71 %70
+         %71 = OpLabel
                OpStore %tint_return_flag %true
-               OpStore %tint_return_value %36
-               OpBranch %61
-         %61 = OpLabel
-         %63 = OpLoad %float %tint_return_value
-               OpReturnValue %63
+               OpStore %tint_return_value %46
+               OpBranch %70
+         %70 = OpLabel
+         %72 = OpLoad %float %tint_return_value
+               OpReturnValue %72
                OpFunctionEnd
-   %mm_readB = OpFunction %float None %25
+   %mm_readB = OpFunction %float None %36
       %row_0 = OpFunctionParameter %uint
       %col_0 = OpFunctionParameter %uint
-         %67 = OpLabel
-%tint_return_flag_1 = OpVariable %_ptr_Function_bool Function %33
-%tint_return_value_1 = OpVariable %_ptr_Function_float Function %36
-         %70 = OpAccessChain %_ptr_Uniform_uint %uniforms %uint_0 %uint_1
-         %71 = OpLoad %uint %70
-         %72 = OpULessThan %bool %row_0 %71
-               OpSelectionMerge %73 None
-               OpBranchConditional %72 %74 %73
-         %74 = OpLabel
-         %76 = OpAccessChain %_ptr_Uniform_uint %uniforms %uint_0 %uint_2
-         %77 = OpLoad %uint %76
-         %78 = OpULessThan %bool %col_0 %77
-               OpBranch %73
-         %73 = OpLabel
-         %79 = OpPhi %bool %72 %67 %78 %74
-               OpSelectionMerge %80 None
-               OpBranchConditional %79 %81 %80
-         %81 = OpLabel
-         %82 = OpAccessChain %_ptr_Uniform_uint %uniforms %uint_0 %uint_2
-         %83 = OpLoad %uint %82
-         %84 = OpIMul %uint %row_0 %83
-         %85 = OpIAdd %uint %84 %col_0
-         %86 = OpAccessChain %_ptr_StorageBuffer_float %secondMatrix %uint_0 %85
-         %87 = OpLoad %float %86
-               OpStore %tint_return_flag_1 %true
-               OpStore %tint_return_value_1 %87
-               OpBranch %80
-         %80 = OpLabel
-         %89 = OpLoad %bool %tint_return_flag_1
-         %88 = OpLogicalNot %bool %89
-               OpSelectionMerge %90 None
-               OpBranchConditional %88 %91 %90
-         %91 = OpLabel
-               OpStore %tint_return_flag_1 %true
-               OpStore %tint_return_value_1 %36
-               OpBranch %90
+         %76 = OpLabel
+%tint_return_flag_1 = OpVariable %_ptr_Function_bool Function %43
+%tint_return_value_1 = OpVariable %_ptr_Function_float Function %46
+         %79 = OpAccessChain %_ptr_Uniform_uint %uniforms %uint_0 %uint_1
+         %80 = OpLoad %uint %79
+         %81 = OpULessThan %bool %row_0 %80
+               OpSelectionMerge %82 None
+               OpBranchConditional %81 %83 %82
+         %83 = OpLabel
+         %85 = OpAccessChain %_ptr_Uniform_uint %uniforms %uint_0 %uint_2
+         %86 = OpLoad %uint %85
+         %87 = OpULessThan %bool %col_0 %86
+               OpBranch %82
+         %82 = OpLabel
+         %88 = OpPhi %bool %81 %76 %87 %83
+               OpSelectionMerge %89 None
+               OpBranchConditional %88 %90 %89
          %90 = OpLabel
-         %92 = OpLoad %float %tint_return_value_1
-               OpReturnValue %92
+         %91 = OpAccessChain %_ptr_Uniform_uint %uniforms %uint_0 %uint_2
+         %92 = OpLoad %uint %91
+         %93 = OpIMul %uint %row_0 %92
+         %94 = OpIAdd %uint %93 %col_0
+         %95 = OpAccessChain %_ptr_StorageBuffer_float %secondMatrix %uint_0 %94
+         %96 = OpLoad %float %95
+               OpStore %tint_return_flag_1 %true
+               OpStore %tint_return_value_1 %96
+               OpBranch %89
+         %89 = OpLabel
+         %98 = OpLoad %bool %tint_return_flag_1
+         %97 = OpLogicalNot %bool %98
+               OpSelectionMerge %99 None
+               OpBranchConditional %97 %100 %99
+        %100 = OpLabel
+               OpStore %tint_return_flag_1 %true
+               OpStore %tint_return_value_1 %46
+               OpBranch %99
+         %99 = OpLabel
+        %101 = OpLoad %float %tint_return_value_1
+               OpReturnValue %101
                OpFunctionEnd
-   %mm_write = OpFunction %void None %93
+   %mm_write = OpFunction %void None %102
       %row_1 = OpFunctionParameter %uint
       %col_1 = OpFunctionParameter %uint
       %value = OpFunctionParameter %float
-         %99 = OpLabel
-        %100 = OpAccessChain %_ptr_Uniform_uint %uniforms %uint_0 %uint_0
-        %101 = OpLoad %uint %100
-        %102 = OpULessThan %bool %row_1 %101
-               OpSelectionMerge %103 None
-               OpBranchConditional %102 %104 %103
-        %104 = OpLabel
-        %105 = OpAccessChain %_ptr_Uniform_uint %uniforms %uint_0 %uint_2
-        %106 = OpLoad %uint %105
-        %107 = OpULessThan %bool %col_1 %106
-               OpBranch %103
-        %103 = OpLabel
-        %108 = OpPhi %bool %102 %99 %107 %104
-               OpSelectionMerge %109 None
-               OpBranchConditional %108 %110 %109
-        %110 = OpLabel
-        %111 = OpAccessChain %_ptr_Uniform_uint %uniforms %uint_0 %uint_2
-        %112 = OpLoad %uint %111
-        %113 = OpIMul %uint %row_1 %112
-        %114 = OpIAdd %uint %col_1 %113
-        %115 = OpAccessChain %_ptr_StorageBuffer_float %resultMatrix %uint_0 %114
-               OpStore %115 %value
-               OpBranch %109
-        %109 = OpLabel
+        %108 = OpLabel
+        %109 = OpAccessChain %_ptr_Uniform_uint %uniforms %uint_0 %uint_0
+        %110 = OpLoad %uint %109
+        %111 = OpULessThan %bool %row_1 %110
+               OpSelectionMerge %112 None
+               OpBranchConditional %111 %113 %112
+        %113 = OpLabel
+        %114 = OpAccessChain %_ptr_Uniform_uint %uniforms %uint_0 %uint_2
+        %115 = OpLoad %uint %114
+        %116 = OpULessThan %bool %col_1 %115
+               OpBranch %112
+        %112 = OpLabel
+        %117 = OpPhi %bool %111 %108 %116 %113
+               OpSelectionMerge %118 None
+               OpBranchConditional %117 %119 %118
+        %119 = OpLabel
+        %120 = OpAccessChain %_ptr_Uniform_uint %uniforms %uint_0 %uint_2
+        %121 = OpLoad %uint %120
+        %122 = OpIMul %uint %row_1 %121
+        %123 = OpIAdd %uint %col_1 %122
+        %124 = OpAccessChain %_ptr_StorageBuffer_float %resultMatrix %uint_0 %123
+               OpStore %124 %value
+               OpBranch %118
+        %118 = OpLabel
                OpReturn
                OpFunctionEnd
- %main_inner = OpFunction %void None %116
+ %main_inner = OpFunction %void None %125
    %local_id = OpFunctionParameter %v3uint
   %global_id = OpFunctionParameter %v3uint
 %local_invocation_index = OpFunctionParameter %uint
-        %121 = OpLabel
-        %idx = OpVariable %_ptr_Function_uint Function %124
-        %acc = OpVariable %_ptr_Function__arr_float_uint_16 Function %165
-    %ACached = OpVariable %_ptr_Function_float Function %36
-    %BCached = OpVariable %_ptr_Function__arr_float_uint_4 Function %170
-      %index = OpVariable %_ptr_Function_uint Function %124
-          %t = OpVariable %_ptr_Function_uint Function %124
-   %innerRow = OpVariable %_ptr_Function_uint Function %124
-   %innerCol = OpVariable %_ptr_Function_uint Function %124
- %innerRow_0 = OpVariable %_ptr_Function_uint Function %124
- %innerCol_0 = OpVariable %_ptr_Function_uint Function %124
-          %k = OpVariable %_ptr_Function_uint Function %124
-      %inner = OpVariable %_ptr_Function_uint Function %124
- %innerRow_1 = OpVariable %_ptr_Function_uint Function %124
- %innerCol_1 = OpVariable %_ptr_Function_uint Function %124
- %innerRow_2 = OpVariable %_ptr_Function_uint Function %124
- %innerCol_2 = OpVariable %_ptr_Function_uint Function %124
+        %130 = OpLabel
+        %idx = OpVariable %_ptr_Function_uint Function %31
+        %acc = OpVariable %_ptr_Function__arr_float_uint_16 Function %173
+    %ACached = OpVariable %_ptr_Function_float Function %46
+    %BCached = OpVariable %_ptr_Function__arr_float_uint_4 Function %178
+      %index = OpVariable %_ptr_Function_uint Function %31
+          %t = OpVariable %_ptr_Function_uint Function %31
+   %innerRow = OpVariable %_ptr_Function_uint Function %31
+   %innerCol = OpVariable %_ptr_Function_uint Function %31
+ %innerRow_0 = OpVariable %_ptr_Function_uint Function %31
+ %innerCol_0 = OpVariable %_ptr_Function_uint Function %31
+          %k = OpVariable %_ptr_Function_uint Function %31
+      %inner = OpVariable %_ptr_Function_uint Function %31
+ %innerRow_1 = OpVariable %_ptr_Function_uint Function %31
+ %innerCol_1 = OpVariable %_ptr_Function_uint Function %31
+ %innerRow_2 = OpVariable %_ptr_Function_uint Function %31
+ %innerCol_2 = OpVariable %_ptr_Function_uint Function %31
                OpStore %idx %local_invocation_index
-               OpBranch %125
-        %125 = OpLabel
-               OpLoopMerge %126 %127 None
-               OpBranch %128
-        %128 = OpLabel
-        %130 = OpLoad %uint %idx
-        %132 = OpULessThan %bool %130 %uint_4096
-        %129 = OpLogicalNot %bool %132
-               OpSelectionMerge %133 None
-               OpBranchConditional %129 %134 %133
-        %134 = OpLabel
-               OpBranch %126
+               OpBranch %133
         %133 = OpLabel
-        %135 = OpLoad %uint %idx
-        %136 = OpUDiv %uint %135 %uint_64
-        %137 = OpLoad %uint %idx
-        %138 = OpUMod %uint %137 %uint_64
-        %140 = OpAccessChain %_ptr_Workgroup_float %mm_Asub %136 %138
-               OpStore %140 %36
-        %141 = OpAccessChain %_ptr_Workgroup_float %mm_Bsub %136 %138
-               OpStore %141 %36
-               OpBranch %127
-        %127 = OpLabel
-        %142 = OpLoad %uint %idx
-        %144 = OpIAdd %uint %142 %uint_256
-               OpStore %idx %144
-               OpBranch %125
-        %126 = OpLabel
+               OpLoopMerge %134 %135 None
+               OpBranch %136
+        %136 = OpLabel
+        %138 = OpLoad %uint %idx
+        %140 = OpULessThan %bool %138 %uint_4096
+        %137 = OpLogicalNot %bool %140
+               OpSelectionMerge %141 None
+               OpBranchConditional %137 %142 %141
+        %142 = OpLabel
+               OpBranch %134
+        %141 = OpLabel
+        %143 = OpLoad %uint %idx
+        %144 = OpUDiv %uint %143 %uint_64
+        %145 = OpLoad %uint %idx
+        %146 = OpUMod %uint %145 %uint_64
+        %148 = OpAccessChain %_ptr_Workgroup_float %mm_Asub %144 %146
+               OpStore %148 %46
+        %149 = OpAccessChain %_ptr_Workgroup_float %mm_Bsub %144 %146
+               OpStore %149 %46
+               OpBranch %135
+        %135 = OpLabel
+        %150 = OpLoad %uint %idx
+        %152 = OpIAdd %uint %150 %uint_256
+               OpStore %idx %152
+               OpBranch %133
+        %134 = OpLabel
                OpControlBarrier %uint_2 %uint_2 %uint_264
-        %147 = OpCompositeExtract %uint %local_id 1
-        %149 = OpIMul %uint %147 %uint_4
-        %150 = OpCompositeExtract %uint %local_id 0
-        %151 = OpIMul %uint %150 %uint_4
-        %152 = OpCompositeExtract %uint %global_id 1
-        %153 = OpIMul %uint %152 %uint_4
-        %154 = OpCompositeExtract %uint %global_id 0
-        %155 = OpIMul %uint %154 %uint_4
-        %156 = OpAccessChain %_ptr_Uniform_uint %uniforms %uint_0 %uint_1
-        %157 = OpLoad %uint %156
-        %158 = OpISub %uint %157 %uint_1
-        %159 = OpUDiv %uint %158 %uint_64
-        %160 = OpIAdd %uint %159 %uint_1
-               OpStore %index %124
-               OpBranch %172
-        %172 = OpLabel
-               OpLoopMerge %173 %174 None
-               OpBranch %175
-        %175 = OpLabel
-        %177 = OpLoad %uint %index
-        %178 = OpULessThan %bool %177 %uint_16
-        %176 = OpLogicalNot %bool %178
-               OpSelectionMerge %179 None
-               OpBranchConditional %176 %180 %179
+        %155 = OpCompositeExtract %uint %local_id 1
+        %157 = OpIMul %uint %155 %uint_4
+        %158 = OpCompositeExtract %uint %local_id 0
+        %159 = OpIMul %uint %158 %uint_4
+        %160 = OpCompositeExtract %uint %global_id 1
+        %161 = OpIMul %uint %160 %uint_4
+        %162 = OpCompositeExtract %uint %global_id 0
+        %163 = OpIMul %uint %162 %uint_4
+        %165 = OpAccessChain %_ptr_Uniform_uint %uniforms %uint_0 %uint_1
+        %166 = OpLoad %uint %165
+        %167 = OpISub %uint %166 %uint_1
+        %164 = OpFunctionCall %uint %tint_div %167 %uint_64
+        %168 = OpIAdd %uint %164 %uint_1
+               OpStore %index %31
+               OpBranch %180
         %180 = OpLabel
-               OpBranch %173
-        %179 = OpLabel
-        %181 = OpLoad %uint %index
-        %182 = OpAccessChain %_ptr_Function_float %acc %181
-               OpStore %182 %36
-               OpBranch %174
-        %174 = OpLabel
-        %183 = OpLoad %uint %index
-        %184 = OpIAdd %uint %183 %uint_1
-               OpStore %index %184
-               OpBranch %172
-        %173 = OpLabel
-        %185 = OpCompositeExtract %uint %local_id 0
-        %186 = OpIMul %uint %185 %uint_4
-        %187 = OpCompositeExtract %uint %local_id 1
-        %188 = OpIMul %uint %187 %uint_4
-               OpStore %t %124
-               OpBranch %190
-        %190 = OpLabel
-               OpLoopMerge %191 %192 None
-               OpBranch %193
-        %193 = OpLabel
-        %195 = OpLoad %uint %t
-        %196 = OpULessThan %bool %195 %160
-        %194 = OpLogicalNot %bool %196
-               OpSelectionMerge %197 None
-               OpBranchConditional %194 %198 %197
+               OpLoopMerge %181 %182 None
+               OpBranch %183
+        %183 = OpLabel
+        %185 = OpLoad %uint %index
+        %186 = OpULessThan %bool %185 %uint_16
+        %184 = OpLogicalNot %bool %186
+               OpSelectionMerge %187 None
+               OpBranchConditional %184 %188 %187
+        %188 = OpLabel
+               OpBranch %181
+        %187 = OpLabel
+        %189 = OpLoad %uint %index
+        %190 = OpAccessChain %_ptr_Function_float %acc %189
+               OpStore %190 %46
+               OpBranch %182
+        %182 = OpLabel
+        %191 = OpLoad %uint %index
+        %192 = OpIAdd %uint %191 %uint_1
+               OpStore %index %192
+               OpBranch %180
+        %181 = OpLabel
+        %193 = OpCompositeExtract %uint %local_id 0
+        %194 = OpIMul %uint %193 %uint_4
+        %195 = OpCompositeExtract %uint %local_id 1
+        %196 = OpIMul %uint %195 %uint_4
+               OpStore %t %31
+               OpBranch %198
         %198 = OpLabel
-               OpBranch %191
-        %197 = OpLabel
-               OpStore %innerRow %124
-               OpBranch %200
-        %200 = OpLabel
-               OpLoopMerge %201 %202 None
-               OpBranch %203
-        %203 = OpLabel
-        %205 = OpLoad %uint %innerRow
-        %206 = OpULessThan %bool %205 %uint_4
-        %204 = OpLogicalNot %bool %206
-               OpSelectionMerge %207 None
-               OpBranchConditional %204 %208 %207
-        %208 = OpLabel
+               OpLoopMerge %199 %200 None
                OpBranch %201
-        %207 = OpLabel
-               OpStore %innerCol %124
+        %201 = OpLabel
+        %203 = OpLoad %uint %t
+        %204 = OpULessThan %bool %203 %168
+        %202 = OpLogicalNot %bool %204
+               OpSelectionMerge %205 None
+               OpBranchConditional %202 %206 %205
+        %206 = OpLabel
+               OpBranch %199
+        %205 = OpLabel
+               OpStore %innerRow %31
+               OpBranch %208
+        %208 = OpLabel
+               OpLoopMerge %209 %210 None
+               OpBranch %211
+        %211 = OpLabel
+        %213 = OpLoad %uint %innerRow
+        %214 = OpULessThan %bool %213 %uint_4
+        %212 = OpLogicalNot %bool %214
+               OpSelectionMerge %215 None
+               OpBranchConditional %212 %216 %215
+        %216 = OpLabel
+               OpBranch %209
+        %215 = OpLabel
+               OpStore %innerCol %31
+               OpBranch %218
+        %218 = OpLabel
+               OpLoopMerge %219 %220 None
+               OpBranch %221
+        %221 = OpLabel
+        %223 = OpLoad %uint %innerCol
+        %224 = OpULessThan %bool %223 %uint_4
+        %222 = OpLogicalNot %bool %224
+               OpSelectionMerge %225 None
+               OpBranchConditional %222 %226 %225
+        %226 = OpLabel
+               OpBranch %219
+        %225 = OpLabel
+        %227 = OpLoad %uint %innerRow
+        %228 = OpIAdd %uint %157 %227
+        %229 = OpLoad %uint %innerCol
+        %230 = OpIAdd %uint %194 %229
+        %232 = OpLoad %uint %innerRow
+        %233 = OpIAdd %uint %161 %232
+        %234 = OpLoad %uint %t
+        %235 = OpIMul %uint %234 %uint_64
+        %236 = OpIAdd %uint %235 %230
+        %231 = OpFunctionCall %float %mm_readA %233 %236
+        %237 = OpAccessChain %_ptr_Workgroup_float %mm_Asub %228 %230
+               OpStore %237 %231
+               OpBranch %220
+        %220 = OpLabel
+        %238 = OpLoad %uint %innerCol
+        %239 = OpIAdd %uint %238 %uint_1
+               OpStore %innerCol %239
+               OpBranch %218
+        %219 = OpLabel
                OpBranch %210
         %210 = OpLabel
-               OpLoopMerge %211 %212 None
-               OpBranch %213
-        %213 = OpLabel
-        %215 = OpLoad %uint %innerCol
-        %216 = OpULessThan %bool %215 %uint_4
-        %214 = OpLogicalNot %bool %216
-               OpSelectionMerge %217 None
-               OpBranchConditional %214 %218 %217
-        %218 = OpLabel
-               OpBranch %211
-        %217 = OpLabel
-        %219 = OpLoad %uint %innerRow
-        %220 = OpIAdd %uint %149 %219
-        %221 = OpLoad %uint %innerCol
-        %222 = OpIAdd %uint %186 %221
-        %224 = OpLoad %uint %innerRow
-        %225 = OpIAdd %uint %153 %224
-        %226 = OpLoad %uint %t
-        %227 = OpIMul %uint %226 %uint_64
-        %228 = OpIAdd %uint %227 %222
-        %223 = OpFunctionCall %float %mm_readA %225 %228
-        %229 = OpAccessChain %_ptr_Workgroup_float %mm_Asub %220 %222
-               OpStore %229 %223
-               OpBranch %212
-        %212 = OpLabel
-        %230 = OpLoad %uint %innerCol
-        %231 = OpIAdd %uint %230 %uint_1
-               OpStore %innerCol %231
-               OpBranch %210
-        %211 = OpLabel
-               OpBranch %202
-        %202 = OpLabel
-        %232 = OpLoad %uint %innerRow
-        %233 = OpIAdd %uint %232 %uint_1
-               OpStore %innerRow %233
-               OpBranch %200
-        %201 = OpLabel
-               OpStore %innerRow_0 %124
-               OpBranch %235
-        %235 = OpLabel
-               OpLoopMerge %236 %237 None
-               OpBranch %238
-        %238 = OpLabel
-        %240 = OpLoad %uint %innerRow_0
-        %241 = OpULessThan %bool %240 %uint_4
-        %239 = OpLogicalNot %bool %241
-               OpSelectionMerge %242 None
-               OpBranchConditional %239 %243 %242
+        %240 = OpLoad %uint %innerRow
+        %241 = OpIAdd %uint %240 %uint_1
+               OpStore %innerRow %241
+               OpBranch %208
+        %209 = OpLabel
+               OpStore %innerRow_0 %31
+               OpBranch %243
         %243 = OpLabel
-               OpBranch %236
-        %242 = OpLabel
-               OpStore %innerCol_0 %124
+               OpLoopMerge %244 %245 None
+               OpBranch %246
+        %246 = OpLabel
+        %248 = OpLoad %uint %innerRow_0
+        %249 = OpULessThan %bool %248 %uint_4
+        %247 = OpLogicalNot %bool %249
+               OpSelectionMerge %250 None
+               OpBranchConditional %247 %251 %250
+        %251 = OpLabel
+               OpBranch %244
+        %250 = OpLabel
+               OpStore %innerCol_0 %31
+               OpBranch %253
+        %253 = OpLabel
+               OpLoopMerge %254 %255 None
+               OpBranch %256
+        %256 = OpLabel
+        %258 = OpLoad %uint %innerCol_0
+        %259 = OpULessThan %bool %258 %uint_4
+        %257 = OpLogicalNot %bool %259
+               OpSelectionMerge %260 None
+               OpBranchConditional %257 %261 %260
+        %261 = OpLabel
+               OpBranch %254
+        %260 = OpLabel
+        %262 = OpLoad %uint %innerRow_0
+        %263 = OpIAdd %uint %196 %262
+        %264 = OpLoad %uint %innerCol_0
+        %265 = OpIAdd %uint %159 %264
+        %267 = OpLoad %uint %t
+        %268 = OpIMul %uint %267 %uint_64
+        %269 = OpIAdd %uint %268 %263
+        %270 = OpLoad %uint %innerCol_0
+        %271 = OpIAdd %uint %163 %270
+        %266 = OpFunctionCall %float %mm_readB %269 %271
+        %272 = OpLoad %uint %innerCol_0
+        %273 = OpAccessChain %_ptr_Workgroup_float %mm_Bsub %272 %265
+               OpStore %273 %266
+               OpBranch %255
+        %255 = OpLabel
+        %274 = OpLoad %uint %innerCol_0
+        %275 = OpIAdd %uint %274 %uint_1
+               OpStore %innerCol_0 %275
+               OpBranch %253
+        %254 = OpLabel
                OpBranch %245
         %245 = OpLabel
-               OpLoopMerge %246 %247 None
-               OpBranch %248
-        %248 = OpLabel
-        %250 = OpLoad %uint %innerCol_0
-        %251 = OpULessThan %bool %250 %uint_4
-        %249 = OpLogicalNot %bool %251
-               OpSelectionMerge %252 None
-               OpBranchConditional %249 %253 %252
-        %253 = OpLabel
-               OpBranch %246
-        %252 = OpLabel
-        %254 = OpLoad %uint %innerRow_0
-        %255 = OpIAdd %uint %188 %254
-        %256 = OpLoad %uint %innerCol_0
-        %257 = OpIAdd %uint %151 %256
-        %259 = OpLoad %uint %t
-        %260 = OpIMul %uint %259 %uint_64
-        %261 = OpIAdd %uint %260 %255
-        %262 = OpLoad %uint %innerCol_0
-        %263 = OpIAdd %uint %155 %262
-        %258 = OpFunctionCall %float %mm_readB %261 %263
-        %264 = OpLoad %uint %innerCol_0
-        %265 = OpAccessChain %_ptr_Workgroup_float %mm_Bsub %264 %257
-               OpStore %265 %258
-               OpBranch %247
-        %247 = OpLabel
-        %266 = OpLoad %uint %innerCol_0
-        %267 = OpIAdd %uint %266 %uint_1
-               OpStore %innerCol_0 %267
-               OpBranch %245
-        %246 = OpLabel
-               OpBranch %237
-        %237 = OpLabel
-        %268 = OpLoad %uint %innerRow_0
-        %269 = OpIAdd %uint %268 %uint_1
-               OpStore %innerRow_0 %269
-               OpBranch %235
-        %236 = OpLabel
+        %276 = OpLoad %uint %innerRow_0
+        %277 = OpIAdd %uint %276 %uint_1
+               OpStore %innerRow_0 %277
+               OpBranch %243
+        %244 = OpLabel
                OpControlBarrier %uint_2 %uint_2 %uint_264
-               OpStore %k %124
-               OpBranch %272
-        %272 = OpLabel
-               OpLoopMerge %273 %274 None
-               OpBranch %275
-        %275 = OpLabel
-        %277 = OpLoad %uint %k
-        %278 = OpULessThan %bool %277 %uint_64
-        %276 = OpLogicalNot %bool %278
-               OpSelectionMerge %279 None
-               OpBranchConditional %276 %280 %279
+               OpStore %k %31
+               OpBranch %280
         %280 = OpLabel
-               OpBranch %273
-        %279 = OpLabel
-               OpStore %inner %124
+               OpLoopMerge %281 %282 None
+               OpBranch %283
+        %283 = OpLabel
+        %285 = OpLoad %uint %k
+        %286 = OpULessThan %bool %285 %uint_64
+        %284 = OpLogicalNot %bool %286
+               OpSelectionMerge %287 None
+               OpBranchConditional %284 %288 %287
+        %288 = OpLabel
+               OpBranch %281
+        %287 = OpLabel
+               OpStore %inner %31
+               OpBranch %290
+        %290 = OpLabel
+               OpLoopMerge %291 %292 None
+               OpBranch %293
+        %293 = OpLabel
+        %295 = OpLoad %uint %inner
+        %296 = OpULessThan %bool %295 %uint_4
+        %294 = OpLogicalNot %bool %296
+               OpSelectionMerge %297 None
+               OpBranchConditional %294 %298 %297
+        %298 = OpLabel
+               OpBranch %291
+        %297 = OpLabel
+        %299 = OpLoad %uint %inner
+        %300 = OpAccessChain %_ptr_Function_float %BCached %299
+        %301 = OpLoad %uint %k
+        %302 = OpLoad %uint %inner
+        %303 = OpIAdd %uint %159 %302
+        %304 = OpAccessChain %_ptr_Workgroup_float %mm_Bsub %301 %303
+        %305 = OpLoad %float %304
+               OpStore %300 %305
+               OpBranch %292
+        %292 = OpLabel
+        %306 = OpLoad %uint %inner
+        %307 = OpIAdd %uint %306 %uint_1
+               OpStore %inner %307
+               OpBranch %290
+        %291 = OpLabel
+               OpStore %innerRow_1 %31
+               OpBranch %309
+        %309 = OpLabel
+               OpLoopMerge %310 %311 None
+               OpBranch %312
+        %312 = OpLabel
+        %314 = OpLoad %uint %innerRow_1
+        %315 = OpULessThan %bool %314 %uint_4
+        %313 = OpLogicalNot %bool %315
+               OpSelectionMerge %316 None
+               OpBranchConditional %313 %317 %316
+        %317 = OpLabel
+               OpBranch %310
+        %316 = OpLabel
+        %318 = OpLoad %uint %innerRow_1
+        %319 = OpIAdd %uint %157 %318
+        %320 = OpLoad %uint %k
+        %321 = OpAccessChain %_ptr_Workgroup_float %mm_Asub %319 %320
+        %322 = OpLoad %float %321
+               OpStore %ACached %322
+               OpStore %innerCol_1 %31
+               OpBranch %324
+        %324 = OpLabel
+               OpLoopMerge %325 %326 None
+               OpBranch %327
+        %327 = OpLabel
+        %329 = OpLoad %uint %innerCol_1
+        %330 = OpULessThan %bool %329 %uint_4
+        %328 = OpLogicalNot %bool %330
+               OpSelectionMerge %331 None
+               OpBranchConditional %328 %332 %331
+        %332 = OpLabel
+               OpBranch %325
+        %331 = OpLabel
+        %333 = OpLoad %uint %innerRow_1
+        %334 = OpIMul %uint %333 %uint_4
+        %335 = OpLoad %uint %innerCol_1
+        %336 = OpIAdd %uint %334 %335
+        %337 = OpAccessChain %_ptr_Function_float %acc %336
+        %338 = OpAccessChain %_ptr_Function_float %acc %336
+        %339 = OpLoad %float %338
+        %340 = OpLoad %float %ACached
+        %341 = OpLoad %uint %innerCol_1
+        %342 = OpAccessChain %_ptr_Function_float %BCached %341
+        %343 = OpLoad %float %342
+        %344 = OpFMul %float %340 %343
+        %345 = OpFAdd %float %339 %344
+               OpStore %337 %345
+               OpBranch %326
+        %326 = OpLabel
+        %346 = OpLoad %uint %innerCol_1
+        %347 = OpIAdd %uint %346 %uint_1
+               OpStore %innerCol_1 %347
+               OpBranch %324
+        %325 = OpLabel
+               OpBranch %311
+        %311 = OpLabel
+        %348 = OpLoad %uint %innerRow_1
+        %349 = OpIAdd %uint %348 %uint_1
+               OpStore %innerRow_1 %349
+               OpBranch %309
+        %310 = OpLabel
                OpBranch %282
         %282 = OpLabel
-               OpLoopMerge %283 %284 None
-               OpBranch %285
-        %285 = OpLabel
-        %287 = OpLoad %uint %inner
-        %288 = OpULessThan %bool %287 %uint_4
-        %286 = OpLogicalNot %bool %288
-               OpSelectionMerge %289 None
-               OpBranchConditional %286 %290 %289
-        %290 = OpLabel
-               OpBranch %283
-        %289 = OpLabel
-        %291 = OpLoad %uint %inner
-        %292 = OpAccessChain %_ptr_Function_float %BCached %291
-        %293 = OpLoad %uint %k
-        %294 = OpLoad %uint %inner
-        %295 = OpIAdd %uint %151 %294
-        %296 = OpAccessChain %_ptr_Workgroup_float %mm_Bsub %293 %295
-        %297 = OpLoad %float %296
-               OpStore %292 %297
-               OpBranch %284
-        %284 = OpLabel
-        %298 = OpLoad %uint %inner
-        %299 = OpIAdd %uint %298 %uint_1
-               OpStore %inner %299
-               OpBranch %282
-        %283 = OpLabel
-               OpStore %innerRow_1 %124
-               OpBranch %301
-        %301 = OpLabel
-               OpLoopMerge %302 %303 None
-               OpBranch %304
-        %304 = OpLabel
-        %306 = OpLoad %uint %innerRow_1
-        %307 = OpULessThan %bool %306 %uint_4
-        %305 = OpLogicalNot %bool %307
-               OpSelectionMerge %308 None
-               OpBranchConditional %305 %309 %308
-        %309 = OpLabel
-               OpBranch %302
-        %308 = OpLabel
-        %310 = OpLoad %uint %innerRow_1
-        %311 = OpIAdd %uint %149 %310
-        %312 = OpLoad %uint %k
-        %313 = OpAccessChain %_ptr_Workgroup_float %mm_Asub %311 %312
-        %314 = OpLoad %float %313
-               OpStore %ACached %314
-               OpStore %innerCol_1 %124
-               OpBranch %316
-        %316 = OpLabel
-               OpLoopMerge %317 %318 None
-               OpBranch %319
-        %319 = OpLabel
-        %321 = OpLoad %uint %innerCol_1
-        %322 = OpULessThan %bool %321 %uint_4
-        %320 = OpLogicalNot %bool %322
-               OpSelectionMerge %323 None
-               OpBranchConditional %320 %324 %323
-        %324 = OpLabel
-               OpBranch %317
-        %323 = OpLabel
-        %325 = OpLoad %uint %innerRow_1
-        %326 = OpIMul %uint %325 %uint_4
-        %327 = OpLoad %uint %innerCol_1
-        %328 = OpIAdd %uint %326 %327
-        %329 = OpAccessChain %_ptr_Function_float %acc %328
-        %330 = OpAccessChain %_ptr_Function_float %acc %328
-        %331 = OpLoad %float %330
-        %332 = OpLoad %float %ACached
-        %333 = OpLoad %uint %innerCol_1
-        %334 = OpAccessChain %_ptr_Function_float %BCached %333
-        %335 = OpLoad %float %334
-        %336 = OpFMul %float %332 %335
-        %337 = OpFAdd %float %331 %336
-               OpStore %329 %337
-               OpBranch %318
-        %318 = OpLabel
-        %338 = OpLoad %uint %innerCol_1
-        %339 = OpIAdd %uint %338 %uint_1
-               OpStore %innerCol_1 %339
-               OpBranch %316
-        %317 = OpLabel
-               OpBranch %303
-        %303 = OpLabel
-        %340 = OpLoad %uint %innerRow_1
-        %341 = OpIAdd %uint %340 %uint_1
-               OpStore %innerRow_1 %341
-               OpBranch %301
-        %302 = OpLabel
-               OpBranch %274
-        %274 = OpLabel
-        %342 = OpLoad %uint %k
-        %343 = OpIAdd %uint %342 %uint_1
-               OpStore %k %343
-               OpBranch %272
-        %273 = OpLabel
+        %350 = OpLoad %uint %k
+        %351 = OpIAdd %uint %350 %uint_1
+               OpStore %k %351
+               OpBranch %280
+        %281 = OpLabel
                OpControlBarrier %uint_2 %uint_2 %uint_264
-               OpBranch %192
-        %192 = OpLabel
-        %345 = OpLoad %uint %t
-        %346 = OpIAdd %uint %345 %uint_1
-               OpStore %t %346
-               OpBranch %190
-        %191 = OpLabel
-               OpStore %innerRow_2 %124
-               OpBranch %348
-        %348 = OpLabel
-               OpLoopMerge %349 %350 None
-               OpBranch %351
-        %351 = OpLabel
-        %353 = OpLoad %uint %innerRow_2
-        %354 = OpULessThan %bool %353 %uint_4
-        %352 = OpLogicalNot %bool %354
-               OpSelectionMerge %355 None
-               OpBranchConditional %352 %356 %355
+               OpBranch %200
+        %200 = OpLabel
+        %353 = OpLoad %uint %t
+        %354 = OpIAdd %uint %353 %uint_1
+               OpStore %t %354
+               OpBranch %198
+        %199 = OpLabel
+               OpStore %innerRow_2 %31
+               OpBranch %356
         %356 = OpLabel
-               OpBranch %349
-        %355 = OpLabel
-               OpStore %innerCol_2 %124
+               OpLoopMerge %357 %358 None
+               OpBranch %359
+        %359 = OpLabel
+        %361 = OpLoad %uint %innerRow_2
+        %362 = OpULessThan %bool %361 %uint_4
+        %360 = OpLogicalNot %bool %362
+               OpSelectionMerge %363 None
+               OpBranchConditional %360 %364 %363
+        %364 = OpLabel
+               OpBranch %357
+        %363 = OpLabel
+               OpStore %innerCol_2 %31
+               OpBranch %366
+        %366 = OpLabel
+               OpLoopMerge %367 %368 None
+               OpBranch %369
+        %369 = OpLabel
+        %371 = OpLoad %uint %innerCol_2
+        %372 = OpULessThan %bool %371 %uint_4
+        %370 = OpLogicalNot %bool %372
+               OpSelectionMerge %373 None
+               OpBranchConditional %370 %374 %373
+        %374 = OpLabel
+               OpBranch %367
+        %373 = OpLabel
+        %375 = OpLoad %uint %innerRow_2
+        %376 = OpIMul %uint %375 %uint_4
+        %377 = OpLoad %uint %innerCol_2
+        %378 = OpIAdd %uint %376 %377
+        %380 = OpLoad %uint %innerRow_2
+        %381 = OpIAdd %uint %161 %380
+        %382 = OpLoad %uint %innerCol_2
+        %383 = OpIAdd %uint %163 %382
+        %384 = OpAccessChain %_ptr_Function_float %acc %378
+        %385 = OpLoad %float %384
+        %379 = OpFunctionCall %void %mm_write %381 %383 %385
+               OpBranch %368
+        %368 = OpLabel
+        %386 = OpLoad %uint %innerCol_2
+        %387 = OpIAdd %uint %386 %uint_1
+               OpStore %innerCol_2 %387
+               OpBranch %366
+        %367 = OpLabel
                OpBranch %358
         %358 = OpLabel
-               OpLoopMerge %359 %360 None
-               OpBranch %361
-        %361 = OpLabel
-        %363 = OpLoad %uint %innerCol_2
-        %364 = OpULessThan %bool %363 %uint_4
-        %362 = OpLogicalNot %bool %364
-               OpSelectionMerge %365 None
-               OpBranchConditional %362 %366 %365
-        %366 = OpLabel
-               OpBranch %359
-        %365 = OpLabel
-        %367 = OpLoad %uint %innerRow_2
-        %368 = OpIMul %uint %367 %uint_4
-        %369 = OpLoad %uint %innerCol_2
-        %370 = OpIAdd %uint %368 %369
-        %372 = OpLoad %uint %innerRow_2
-        %373 = OpIAdd %uint %153 %372
-        %374 = OpLoad %uint %innerCol_2
-        %375 = OpIAdd %uint %155 %374
-        %376 = OpAccessChain %_ptr_Function_float %acc %370
-        %377 = OpLoad %float %376
-        %371 = OpFunctionCall %void %mm_write %373 %375 %377
-               OpBranch %360
-        %360 = OpLabel
-        %378 = OpLoad %uint %innerCol_2
-        %379 = OpIAdd %uint %378 %uint_1
-               OpStore %innerCol_2 %379
-               OpBranch %358
-        %359 = OpLabel
-               OpBranch %350
-        %350 = OpLabel
-        %380 = OpLoad %uint %innerRow_2
-        %381 = OpIAdd %uint %380 %uint_1
-               OpStore %innerRow_2 %381
-               OpBranch %348
-        %349 = OpLabel
+        %388 = OpLoad %uint %innerRow_2
+        %389 = OpIAdd %uint %388 %uint_1
+               OpStore %innerRow_2 %389
+               OpBranch %356
+        %357 = OpLabel
                OpReturn
                OpFunctionEnd
-       %main = OpFunction %void None %382
-        %384 = OpLabel
-        %386 = OpLoad %v3uint %local_id_1
-        %387 = OpLoad %v3uint %global_id_1
-        %388 = OpLoad %uint %local_invocation_index_1
-        %385 = OpFunctionCall %void %main_inner %386 %387 %388
+       %main = OpFunction %void None %390
+        %392 = OpLabel
+        %394 = OpLoad %v3uint %local_id_1
+        %395 = OpLoad %v3uint %global_id_1
+        %396 = OpLoad %uint %local_invocation_index_1
+        %393 = OpFunctionCall %void %main_inner %394 %395 %396
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/bug/tint/942.wgsl.expected.dxc.hlsl b/test/tint/bug/tint/942.wgsl.expected.dxc.hlsl
index 0f2d328..e445348 100644
--- a/test/tint/bug/tint/942.wgsl.expected.dxc.hlsl
+++ b/test/tint/bug/tint/942.wgsl.expected.dxc.hlsl
@@ -1,3 +1,7 @@
+uint tint_div(uint lhs, uint rhs) {
+  return (lhs / ((rhs == 0u) ? 1u : rhs));
+}
+
 SamplerState samp : register(s0, space0);
 cbuffer cbuffer_params : register(b1, space0) {
   uint4 params[1];
@@ -25,7 +29,7 @@
     }
   }
   GroupMemoryBarrierWithGroupSync();
-  const uint filterOffset = ((params[0].x - 1u) / 2u);
+  const uint filterOffset = tint_div((params[0].x - 1u), 2u);
   int3 tint_tmp;
   inputTex.GetDimensions(0, tint_tmp.x, tint_tmp.y, tint_tmp.z);
   const uint2 dims = tint_tmp.xy;
diff --git a/test/tint/bug/tint/942.wgsl.expected.fxc.hlsl b/test/tint/bug/tint/942.wgsl.expected.fxc.hlsl
index 0f2d328..e445348 100644
--- a/test/tint/bug/tint/942.wgsl.expected.fxc.hlsl
+++ b/test/tint/bug/tint/942.wgsl.expected.fxc.hlsl
@@ -1,3 +1,7 @@
+uint tint_div(uint lhs, uint rhs) {
+  return (lhs / ((rhs == 0u) ? 1u : rhs));
+}
+
 SamplerState samp : register(s0, space0);
 cbuffer cbuffer_params : register(b1, space0) {
   uint4 params[1];
@@ -25,7 +29,7 @@
     }
   }
   GroupMemoryBarrierWithGroupSync();
-  const uint filterOffset = ((params[0].x - 1u) / 2u);
+  const uint filterOffset = tint_div((params[0].x - 1u), 2u);
   int3 tint_tmp;
   inputTex.GetDimensions(0, tint_tmp.x, tint_tmp.y, tint_tmp.z);
   const uint2 dims = tint_tmp.xy;
diff --git a/test/tint/bug/tint/942.wgsl.expected.glsl b/test/tint/bug/tint/942.wgsl.expected.glsl
index 6f68af7..77b463a 100644
--- a/test/tint/bug/tint/942.wgsl.expected.glsl
+++ b/test/tint/bug/tint/942.wgsl.expected.glsl
@@ -1,5 +1,9 @@
 #version 310 es
 
+uint tint_div(uint lhs, uint rhs) {
+  return (lhs / ((rhs == 0u) ? 1u : rhs));
+}
+
 struct Params {
   uint filterDim;
   uint blockDim;
@@ -36,7 +40,7 @@
     }
   }
   barrier();
-  uint filterOffset = ((params.inner.filterDim - 1u) / 2u);
+  uint filterOffset = tint_div((params.inner.filterDim - 1u), 2u);
   uvec2 dims = uvec2(textureSize(inputTex_1, 0));
   uvec2 baseIndex = (((WorkGroupID.xy * uvec2(params.inner.blockDim, 4u)) + (LocalInvocationID.xy * uvec2(4u, 1u))) - uvec2(filterOffset, 0u));
   {
diff --git a/test/tint/bug/tint/942.wgsl.expected.msl b/test/tint/bug/tint/942.wgsl.expected.msl
index 4d884bf..507e1bc 100644
--- a/test/tint/bug/tint/942.wgsl.expected.msl
+++ b/test/tint/bug/tint/942.wgsl.expected.msl
@@ -14,6 +14,10 @@
     T elements[N];
 };
 
+uint tint_div(uint lhs, uint rhs) {
+  return (lhs / select(rhs, 1u, (rhs == 0u)));
+}
+
 struct Params {
   /* 0x0000 */ uint filterDim;
   /* 0x0004 */ uint blockDim;
@@ -30,7 +34,7 @@
     (*(tint_symbol_1))[i_1][i_2] = float3(0.0f);
   }
   threadgroup_barrier(mem_flags::mem_threadgroup);
-  uint const filterOffset = (((*(tint_symbol_2)).filterDim - 1u) / 2u);
+  uint const filterOffset = tint_div(((*(tint_symbol_2)).filterDim - 1u), 2u);
   uint2 const dims = uint2(tint_symbol_3.get_width(0), tint_symbol_3.get_height(0));
   uint2 const baseIndex = (((uint3(WorkGroupID).xy * uint2((*(tint_symbol_2)).blockDim, 4u)) + (uint3(LocalInvocationID).xy * uint2(4u, 1u))) - uint2(filterOffset, 0u));
   for(uint r = 0u; (r < 4u); r = (r + 1u)) {
diff --git a/test/tint/bug/tint/942.wgsl.expected.spvasm b/test/tint/bug/tint/942.wgsl.expected.spvasm
index 05b4009..711cab8 100644
--- a/test/tint/bug/tint/942.wgsl.expected.spvasm
+++ b/test/tint/bug/tint/942.wgsl.expected.spvasm
@@ -1,7 +1,7 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 253
+; Bound: 261
 ; Schema: 0
                OpCapability Shader
                OpCapability ImageQuery
@@ -26,6 +26,9 @@
                OpMemberName %Flip 0 "value"
                OpName %flip "flip"
                OpName %tile "tile"
+               OpName %tint_div "tint_div"
+               OpName %lhs "lhs"
+               OpName %rhs "rhs"
                OpName %main_inner "main_inner"
                OpName %WorkGroupID "WorkGroupID"
                OpName %LocalInvocationID "LocalInvocationID"
@@ -98,311 +101,321 @@
 %_arr__arr_v3float_uint_256_uint_4 = OpTypeArray %_arr_v3float_uint_256 %uint_4
 %_ptr_Workgroup__arr__arr_v3float_uint_256_uint_4 = OpTypePointer Workgroup %_arr__arr_v3float_uint_256_uint_4
        %tile = OpVariable %_ptr_Workgroup__arr__arr_v3float_uint_256_uint_4 Workgroup
-       %void = OpTypeVoid
-         %33 = OpTypeFunction %void %v3uint %v3uint %uint
-%_ptr_Function_uint = OpTypePointer Function %uint
-         %42 = OpConstantNull %uint
-  %uint_1024 = OpConstant %uint 1024
+         %33 = OpTypeFunction %uint %uint %uint
+         %39 = OpConstantNull %uint
        %bool = OpTypeBool
+     %uint_1 = OpConstant %uint 1
+       %void = OpTypeVoid
+         %44 = OpTypeFunction %void %v3uint %v3uint %uint
+%_ptr_Function_uint = OpTypePointer Function %uint
+  %uint_1024 = OpConstant %uint 1024
 %_ptr_Workgroup_v3float = OpTypePointer Workgroup %v3float
-         %60 = OpConstantNull %v3float
+         %69 = OpConstantNull %v3float
     %uint_64 = OpConstant %uint 64
      %uint_2 = OpConstant %uint 2
    %uint_264 = OpConstant %uint 264
      %uint_0 = OpConstant %uint 0
 %_ptr_Uniform_uint = OpTypePointer Uniform %uint
-     %uint_1 = OpConstant %uint 1
      %v2uint = OpTypeVector %uint 2
         %int = OpTypeInt 32 1
-         %78 = OpConstantNull %int
-         %85 = OpConstantComposite %v2uint %uint_4 %uint_1
+         %86 = OpConstantNull %int
+         %93 = OpConstantComposite %v2uint %uint_4 %uint_1
 %_ptr_Function_v2uint = OpTypePointer Function %v2uint
-        %116 = OpConstantNull %v2uint
+        %124 = OpConstantNull %v2uint
     %v4float = OpTypeVector %float 4
-        %134 = OpTypeSampledImage %17
+        %142 = OpTypeSampledImage %17
     %v2float = OpTypeVector %float 2
  %float_0_25 = OpConstant %float 0.25
-        %140 = OpConstantComposite %v2float %float_0_25 %float_0_25
-        %144 = OpConstantNull %float
+        %148 = OpConstantComposite %v2float %float_0_25 %float_0_25
+        %152 = OpConstantNull %float
      %v2bool = OpTypeVector %bool 2
 %_ptr_Function_v3float = OpTypePointer Function %v3float
     %float_1 = OpConstant %float 1
-        %246 = OpTypeFunction %void
- %main_inner = OpFunction %void None %33
+        %254 = OpTypeFunction %void
+   %tint_div = OpFunction %uint None %33
+        %lhs = OpFunctionParameter %uint
+        %rhs = OpFunctionParameter %uint
+         %37 = OpLabel
+         %40 = OpIEqual %bool %rhs %39
+         %38 = OpSelect %uint %40 %uint_1 %rhs
+         %43 = OpUDiv %uint %lhs %38
+               OpReturnValue %43
+               OpFunctionEnd
+ %main_inner = OpFunction %void None %44
 %WorkGroupID = OpFunctionParameter %v3uint
 %LocalInvocationID = OpFunctionParameter %v3uint
 %local_invocation_index = OpFunctionParameter %uint
-         %39 = OpLabel
-        %idx = OpVariable %_ptr_Function_uint Function %42
-          %r = OpVariable %_ptr_Function_uint Function %42
-          %c = OpVariable %_ptr_Function_uint Function %42
-  %loadIndex = OpVariable %_ptr_Function_v2uint Function %116
-        %r_0 = OpVariable %_ptr_Function_uint Function %42
-        %c_0 = OpVariable %_ptr_Function_uint Function %42
- %writeIndex = OpVariable %_ptr_Function_v2uint Function %116
-        %acc = OpVariable %_ptr_Function_v3float Function %60
-          %f = OpVariable %_ptr_Function_uint Function %42
-          %i = OpVariable %_ptr_Function_uint Function %42
+         %50 = OpLabel
+        %idx = OpVariable %_ptr_Function_uint Function %39
+          %r = OpVariable %_ptr_Function_uint Function %39
+          %c = OpVariable %_ptr_Function_uint Function %39
+  %loadIndex = OpVariable %_ptr_Function_v2uint Function %124
+        %r_0 = OpVariable %_ptr_Function_uint Function %39
+        %c_0 = OpVariable %_ptr_Function_uint Function %39
+ %writeIndex = OpVariable %_ptr_Function_v2uint Function %124
+        %acc = OpVariable %_ptr_Function_v3float Function %69
+          %f = OpVariable %_ptr_Function_uint Function %39
+          %i = OpVariable %_ptr_Function_uint Function %39
                OpStore %idx %local_invocation_index
-               OpBranch %43
-         %43 = OpLabel
-               OpLoopMerge %44 %45 None
-               OpBranch %46
-         %46 = OpLabel
-         %48 = OpLoad %uint %idx
-         %50 = OpULessThan %bool %48 %uint_1024
-         %47 = OpLogicalNot %bool %50
-               OpSelectionMerge %52 None
-               OpBranchConditional %47 %53 %52
+               OpBranch %53
          %53 = OpLabel
-               OpBranch %44
-         %52 = OpLabel
-         %54 = OpLoad %uint %idx
-         %55 = OpUDiv %uint %54 %uint_256
-         %56 = OpLoad %uint %idx
-         %57 = OpUMod %uint %56 %uint_256
-         %59 = OpAccessChain %_ptr_Workgroup_v3float %tile %55 %57
-               OpStore %59 %60
-               OpBranch %45
-         %45 = OpLabel
-         %61 = OpLoad %uint %idx
-         %63 = OpIAdd %uint %61 %uint_64
-               OpStore %idx %63
-               OpBranch %43
-         %44 = OpLabel
+               OpLoopMerge %54 %55 None
+               OpBranch %56
+         %56 = OpLabel
+         %58 = OpLoad %uint %idx
+         %60 = OpULessThan %bool %58 %uint_1024
+         %57 = OpLogicalNot %bool %60
+               OpSelectionMerge %61 None
+               OpBranchConditional %57 %62 %61
+         %62 = OpLabel
+               OpBranch %54
+         %61 = OpLabel
+         %63 = OpLoad %uint %idx
+         %64 = OpUDiv %uint %63 %uint_256
+         %65 = OpLoad %uint %idx
+         %66 = OpUMod %uint %65 %uint_256
+         %68 = OpAccessChain %_ptr_Workgroup_v3float %tile %64 %66
+               OpStore %68 %69
+               OpBranch %55
+         %55 = OpLabel
+         %70 = OpLoad %uint %idx
+         %72 = OpIAdd %uint %70 %uint_64
+               OpStore %idx %72
+               OpBranch %53
+         %54 = OpLabel
                OpControlBarrier %uint_2 %uint_2 %uint_264
-         %69 = OpAccessChain %_ptr_Uniform_uint %params %uint_0 %uint_0
-         %70 = OpLoad %uint %69
-         %72 = OpISub %uint %70 %uint_1
-         %73 = OpUDiv %uint %72 %uint_2
-         %76 = OpLoad %17 %inputTex
-         %74 = OpImageQuerySizeLod %v2uint %76 %78
-         %79 = OpVectorShuffle %v2uint %WorkGroupID %WorkGroupID 0 1
-         %80 = OpAccessChain %_ptr_Uniform_uint %params %uint_0 %uint_1
-         %81 = OpLoad %uint %80
-         %82 = OpCompositeConstruct %v2uint %81 %uint_4
-         %83 = OpIMul %v2uint %79 %82
-         %84 = OpVectorShuffle %v2uint %LocalInvocationID %LocalInvocationID 0 1
-         %86 = OpIMul %v2uint %84 %85
-         %87 = OpIAdd %v2uint %83 %86
-         %88 = OpCompositeConstruct %v2uint %73 %42
-         %89 = OpISub %v2uint %87 %88
-               OpStore %r %42
-               OpBranch %91
-         %91 = OpLabel
-               OpLoopMerge %92 %93 None
-               OpBranch %94
-         %94 = OpLabel
-         %96 = OpLoad %uint %r
-         %97 = OpULessThan %bool %96 %uint_4
-         %95 = OpLogicalNot %bool %97
-               OpSelectionMerge %98 None
-               OpBranchConditional %95 %99 %98
+         %79 = OpAccessChain %_ptr_Uniform_uint %params %uint_0 %uint_0
+         %80 = OpLoad %uint %79
+         %81 = OpISub %uint %80 %uint_1
+         %76 = OpFunctionCall %uint %tint_div %81 %uint_2
+         %84 = OpLoad %17 %inputTex
+         %82 = OpImageQuerySizeLod %v2uint %84 %86
+         %87 = OpVectorShuffle %v2uint %WorkGroupID %WorkGroupID 0 1
+         %88 = OpAccessChain %_ptr_Uniform_uint %params %uint_0 %uint_1
+         %89 = OpLoad %uint %88
+         %90 = OpCompositeConstruct %v2uint %89 %uint_4
+         %91 = OpIMul %v2uint %87 %90
+         %92 = OpVectorShuffle %v2uint %LocalInvocationID %LocalInvocationID 0 1
+         %94 = OpIMul %v2uint %92 %93
+         %95 = OpIAdd %v2uint %91 %94
+         %96 = OpCompositeConstruct %v2uint %76 %39
+         %97 = OpISub %v2uint %95 %96
+               OpStore %r %39
+               OpBranch %99
          %99 = OpLabel
-               OpBranch %92
-         %98 = OpLabel
-               OpStore %c %42
+               OpLoopMerge %100 %101 None
+               OpBranch %102
+        %102 = OpLabel
+        %104 = OpLoad %uint %r
+        %105 = OpULessThan %bool %104 %uint_4
+        %103 = OpLogicalNot %bool %105
+               OpSelectionMerge %106 None
+               OpBranchConditional %103 %107 %106
+        %107 = OpLabel
+               OpBranch %100
+        %106 = OpLabel
+               OpStore %c %39
+               OpBranch %109
+        %109 = OpLabel
+               OpLoopMerge %110 %111 None
+               OpBranch %112
+        %112 = OpLabel
+        %114 = OpLoad %uint %c
+        %115 = OpULessThan %bool %114 %uint_4
+        %113 = OpLogicalNot %bool %115
+               OpSelectionMerge %116 None
+               OpBranchConditional %113 %117 %116
+        %117 = OpLabel
+               OpBranch %110
+        %116 = OpLabel
+        %118 = OpLoad %uint %c
+        %119 = OpLoad %uint %r
+        %120 = OpCompositeConstruct %v2uint %118 %119
+        %121 = OpIAdd %v2uint %97 %120
+               OpStore %loadIndex %121
+        %125 = OpAccessChain %_ptr_Uniform_uint %flip %uint_0 %uint_0
+        %126 = OpLoad %uint %125
+        %127 = OpINotEqual %bool %126 %39
+               OpSelectionMerge %128 None
+               OpBranchConditional %127 %129 %128
+        %129 = OpLabel
+        %130 = OpLoad %v2uint %loadIndex
+        %131 = OpVectorShuffle %v2uint %130 %130 1 0
+               OpStore %loadIndex %131
+               OpBranch %128
+        %128 = OpLabel
+        %132 = OpLoad %uint %r
+        %133 = OpCompositeExtract %uint %LocalInvocationID 0
+        %134 = OpIMul %uint %uint_4 %133
+        %135 = OpLoad %uint %c
+        %136 = OpIAdd %uint %134 %135
+        %137 = OpAccessChain %_ptr_Workgroup_v3float %tile %132 %136
+        %140 = OpLoad %10 %samp
+        %141 = OpLoad %17 %inputTex
+        %143 = OpSampledImage %142 %141 %140
+        %146 = OpLoad %v2uint %loadIndex
+        %144 = OpConvertUToF %v2float %146
+        %149 = OpFAdd %v2float %144 %148
+        %150 = OpConvertUToF %v2float %82
+        %151 = OpFDiv %v2float %149 %150
+        %138 = OpImageSampleExplicitLod %v4float %143 %151 Lod %152
+        %153 = OpVectorShuffle %v3float %138 %138 0 1 2
+               OpStore %137 %153
+               OpBranch %111
+        %111 = OpLabel
+        %154 = OpLoad %uint %c
+        %155 = OpIAdd %uint %154 %uint_1
+               OpStore %c %155
+               OpBranch %109
+        %110 = OpLabel
                OpBranch %101
         %101 = OpLabel
-               OpLoopMerge %102 %103 None
-               OpBranch %104
-        %104 = OpLabel
-        %106 = OpLoad %uint %c
-        %107 = OpULessThan %bool %106 %uint_4
-        %105 = OpLogicalNot %bool %107
-               OpSelectionMerge %108 None
-               OpBranchConditional %105 %109 %108
-        %109 = OpLabel
-               OpBranch %102
-        %108 = OpLabel
-        %110 = OpLoad %uint %c
-        %111 = OpLoad %uint %r
-        %112 = OpCompositeConstruct %v2uint %110 %111
-        %113 = OpIAdd %v2uint %89 %112
-               OpStore %loadIndex %113
-        %117 = OpAccessChain %_ptr_Uniform_uint %flip %uint_0 %uint_0
-        %118 = OpLoad %uint %117
-        %119 = OpINotEqual %bool %118 %42
-               OpSelectionMerge %120 None
-               OpBranchConditional %119 %121 %120
-        %121 = OpLabel
-        %122 = OpLoad %v2uint %loadIndex
-        %123 = OpVectorShuffle %v2uint %122 %122 1 0
-               OpStore %loadIndex %123
-               OpBranch %120
-        %120 = OpLabel
-        %124 = OpLoad %uint %r
-        %125 = OpCompositeExtract %uint %LocalInvocationID 0
-        %126 = OpIMul %uint %uint_4 %125
-        %127 = OpLoad %uint %c
-        %128 = OpIAdd %uint %126 %127
-        %129 = OpAccessChain %_ptr_Workgroup_v3float %tile %124 %128
-        %132 = OpLoad %10 %samp
-        %133 = OpLoad %17 %inputTex
-        %135 = OpSampledImage %134 %133 %132
-        %138 = OpLoad %v2uint %loadIndex
-        %136 = OpConvertUToF %v2float %138
-        %141 = OpFAdd %v2float %136 %140
-        %142 = OpConvertUToF %v2float %74
-        %143 = OpFDiv %v2float %141 %142
-        %130 = OpImageSampleExplicitLod %v4float %135 %143 Lod %144
-        %145 = OpVectorShuffle %v3float %130 %130 0 1 2
-               OpStore %129 %145
-               OpBranch %103
-        %103 = OpLabel
-        %146 = OpLoad %uint %c
-        %147 = OpIAdd %uint %146 %uint_1
-               OpStore %c %147
-               OpBranch %101
-        %102 = OpLabel
-               OpBranch %93
-         %93 = OpLabel
-        %148 = OpLoad %uint %r
-        %149 = OpIAdd %uint %148 %uint_1
-               OpStore %r %149
-               OpBranch %91
-         %92 = OpLabel
+        %156 = OpLoad %uint %r
+        %157 = OpIAdd %uint %156 %uint_1
+               OpStore %r %157
+               OpBranch %99
+        %100 = OpLabel
                OpControlBarrier %uint_2 %uint_2 %uint_264
-               OpStore %r_0 %42
-               OpBranch %152
-        %152 = OpLabel
-               OpLoopMerge %153 %154 None
-               OpBranch %155
-        %155 = OpLabel
-        %157 = OpLoad %uint %r_0
-        %158 = OpULessThan %bool %157 %uint_4
-        %156 = OpLogicalNot %bool %158
-               OpSelectionMerge %159 None
-               OpBranchConditional %156 %160 %159
+               OpStore %r_0 %39
+               OpBranch %160
         %160 = OpLabel
-               OpBranch %153
-        %159 = OpLabel
-               OpStore %c_0 %42
-               OpBranch %162
-        %162 = OpLabel
-               OpLoopMerge %163 %164 None
-               OpBranch %165
-        %165 = OpLabel
-        %167 = OpLoad %uint %c_0
-        %168 = OpULessThan %bool %167 %uint_4
-        %166 = OpLogicalNot %bool %168
-               OpSelectionMerge %169 None
-               OpBranchConditional %166 %170 %169
-        %170 = OpLabel
+               OpLoopMerge %161 %162 None
                OpBranch %163
-        %169 = OpLabel
-        %171 = OpLoad %uint %c_0
-        %172 = OpLoad %uint %r_0
-        %173 = OpCompositeConstruct %v2uint %171 %172
-        %174 = OpIAdd %v2uint %89 %173
-               OpStore %writeIndex %174
-        %176 = OpAccessChain %_ptr_Uniform_uint %flip %uint_0 %uint_0
-        %177 = OpLoad %uint %176
-        %178 = OpINotEqual %bool %177 %42
-               OpSelectionMerge %179 None
-               OpBranchConditional %178 %180 %179
-        %180 = OpLabel
-        %181 = OpLoad %v2uint %writeIndex
-        %182 = OpVectorShuffle %v2uint %181 %181 1 0
+        %163 = OpLabel
+        %165 = OpLoad %uint %r_0
+        %166 = OpULessThan %bool %165 %uint_4
+        %164 = OpLogicalNot %bool %166
+               OpSelectionMerge %167 None
+               OpBranchConditional %164 %168 %167
+        %168 = OpLabel
+               OpBranch %161
+        %167 = OpLabel
+               OpStore %c_0 %39
+               OpBranch %170
+        %170 = OpLabel
+               OpLoopMerge %171 %172 None
+               OpBranch %173
+        %173 = OpLabel
+        %175 = OpLoad %uint %c_0
+        %176 = OpULessThan %bool %175 %uint_4
+        %174 = OpLogicalNot %bool %176
+               OpSelectionMerge %177 None
+               OpBranchConditional %174 %178 %177
+        %178 = OpLabel
+               OpBranch %171
+        %177 = OpLabel
+        %179 = OpLoad %uint %c_0
+        %180 = OpLoad %uint %r_0
+        %181 = OpCompositeConstruct %v2uint %179 %180
+        %182 = OpIAdd %v2uint %97 %181
                OpStore %writeIndex %182
-               OpBranch %179
-        %179 = OpLabel
-        %183 = OpCompositeExtract %uint %LocalInvocationID 0
-        %184 = OpIMul %uint %uint_4 %183
-        %185 = OpLoad %uint %c_0
-        %186 = OpIAdd %uint %184 %185
-        %187 = OpUGreaterThanEqual %bool %186 %73
-               OpSelectionMerge %188 None
-               OpBranchConditional %187 %189 %188
-        %189 = OpLabel
-        %190 = OpISub %uint %uint_256 %73
-        %191 = OpULessThan %bool %186 %190
-               OpBranch %188
+        %184 = OpAccessChain %_ptr_Uniform_uint %flip %uint_0 %uint_0
+        %185 = OpLoad %uint %184
+        %186 = OpINotEqual %bool %185 %39
+               OpSelectionMerge %187 None
+               OpBranchConditional %186 %188 %187
         %188 = OpLabel
-        %192 = OpPhi %bool %187 %179 %191 %189
-               OpSelectionMerge %193 None
-               OpBranchConditional %192 %194 %193
-        %194 = OpLabel
-        %196 = OpLoad %v2uint %writeIndex
-        %197 = OpULessThan %v2bool %196 %74
-        %195 = OpAll %bool %197
-               OpBranch %193
-        %193 = OpLabel
-        %199 = OpPhi %bool %192 %188 %195 %194
-               OpSelectionMerge %200 None
-               OpBranchConditional %199 %201 %200
+        %189 = OpLoad %v2uint %writeIndex
+        %190 = OpVectorShuffle %v2uint %189 %189 1 0
+               OpStore %writeIndex %190
+               OpBranch %187
+        %187 = OpLabel
+        %191 = OpCompositeExtract %uint %LocalInvocationID 0
+        %192 = OpIMul %uint %uint_4 %191
+        %193 = OpLoad %uint %c_0
+        %194 = OpIAdd %uint %192 %193
+        %195 = OpUGreaterThanEqual %bool %194 %76
+               OpSelectionMerge %196 None
+               OpBranchConditional %195 %197 %196
+        %197 = OpLabel
+        %198 = OpISub %uint %uint_256 %76
+        %199 = OpULessThan %bool %194 %198
+               OpBranch %196
+        %196 = OpLabel
+        %200 = OpPhi %bool %195 %187 %199 %197
+               OpSelectionMerge %201 None
+               OpBranchConditional %200 %202 %201
+        %202 = OpLabel
+        %204 = OpLoad %v2uint %writeIndex
+        %205 = OpULessThan %v2bool %204 %82
+        %203 = OpAll %bool %205
+               OpBranch %201
         %201 = OpLabel
-               OpStore %acc %60
-               OpStore %f %42
-               OpBranch %205
-        %205 = OpLabel
-               OpLoopMerge %206 %207 None
+        %207 = OpPhi %bool %200 %196 %203 %202
+               OpSelectionMerge %208 None
+               OpBranchConditional %207 %209 %208
+        %209 = OpLabel
+               OpStore %acc %69
+               OpStore %f %39
+               OpBranch %213
+        %213 = OpLabel
+               OpLoopMerge %214 %215 None
+               OpBranch %216
+        %216 = OpLabel
+        %218 = OpLoad %uint %f
+        %219 = OpAccessChain %_ptr_Uniform_uint %params %uint_0 %uint_0
+        %220 = OpLoad %uint %219
+        %221 = OpULessThan %bool %218 %220
+        %217 = OpLogicalNot %bool %221
+               OpSelectionMerge %222 None
+               OpBranchConditional %217 %223 %222
+        %223 = OpLabel
+               OpBranch %214
+        %222 = OpLabel
+        %224 = OpLoad %uint %f
+        %225 = OpIAdd %uint %194 %224
+        %226 = OpISub %uint %225 %76
+               OpStore %i %226
+        %228 = OpLoad %v3float %acc
+        %231 = OpAccessChain %_ptr_Uniform_uint %params %uint_0 %uint_0
+        %232 = OpLoad %uint %231
+        %230 = OpConvertUToF %float %232
+        %233 = OpFDiv %float %float_1 %230
+        %234 = OpLoad %uint %r_0
+        %235 = OpLoad %uint %i
+        %236 = OpAccessChain %_ptr_Workgroup_v3float %tile %234 %235
+        %237 = OpLoad %v3float %236
+        %238 = OpVectorTimesScalar %v3float %237 %233
+        %239 = OpFAdd %v3float %228 %238
+               OpStore %acc %239
+               OpBranch %215
+        %215 = OpLabel
+        %240 = OpLoad %uint %f
+        %241 = OpIAdd %uint %240 %uint_1
+               OpStore %f %241
+               OpBranch %213
+        %214 = OpLabel
+        %243 = OpLoad %21 %outputTex
+        %244 = OpLoad %v2uint %writeIndex
+        %245 = OpLoad %v3float %acc
+        %246 = OpCompositeExtract %float %245 0
+        %247 = OpCompositeExtract %float %245 1
+        %248 = OpCompositeExtract %float %245 2
+        %249 = OpCompositeConstruct %v4float %246 %247 %248 %float_1
+               OpImageWrite %243 %244 %249
                OpBranch %208
         %208 = OpLabel
-        %210 = OpLoad %uint %f
-        %211 = OpAccessChain %_ptr_Uniform_uint %params %uint_0 %uint_0
-        %212 = OpLoad %uint %211
-        %213 = OpULessThan %bool %210 %212
-        %209 = OpLogicalNot %bool %213
-               OpSelectionMerge %214 None
-               OpBranchConditional %209 %215 %214
-        %215 = OpLabel
-               OpBranch %206
-        %214 = OpLabel
-        %216 = OpLoad %uint %f
-        %217 = OpIAdd %uint %186 %216
-        %218 = OpISub %uint %217 %73
-               OpStore %i %218
-        %220 = OpLoad %v3float %acc
-        %223 = OpAccessChain %_ptr_Uniform_uint %params %uint_0 %uint_0
-        %224 = OpLoad %uint %223
-        %222 = OpConvertUToF %float %224
-        %225 = OpFDiv %float %float_1 %222
-        %226 = OpLoad %uint %r_0
-        %227 = OpLoad %uint %i
-        %228 = OpAccessChain %_ptr_Workgroup_v3float %tile %226 %227
-        %229 = OpLoad %v3float %228
-        %230 = OpVectorTimesScalar %v3float %229 %225
-        %231 = OpFAdd %v3float %220 %230
-               OpStore %acc %231
-               OpBranch %207
-        %207 = OpLabel
-        %232 = OpLoad %uint %f
-        %233 = OpIAdd %uint %232 %uint_1
-               OpStore %f %233
-               OpBranch %205
-        %206 = OpLabel
-        %235 = OpLoad %21 %outputTex
-        %236 = OpLoad %v2uint %writeIndex
-        %237 = OpLoad %v3float %acc
-        %238 = OpCompositeExtract %float %237 0
-        %239 = OpCompositeExtract %float %237 1
-        %240 = OpCompositeExtract %float %237 2
-        %241 = OpCompositeConstruct %v4float %238 %239 %240 %float_1
-               OpImageWrite %235 %236 %241
-               OpBranch %200
-        %200 = OpLabel
-               OpBranch %164
-        %164 = OpLabel
-        %242 = OpLoad %uint %c_0
-        %243 = OpIAdd %uint %242 %uint_1
-               OpStore %c_0 %243
+               OpBranch %172
+        %172 = OpLabel
+        %250 = OpLoad %uint %c_0
+        %251 = OpIAdd %uint %250 %uint_1
+               OpStore %c_0 %251
+               OpBranch %170
+        %171 = OpLabel
                OpBranch %162
-        %163 = OpLabel
-               OpBranch %154
-        %154 = OpLabel
-        %244 = OpLoad %uint %r_0
-        %245 = OpIAdd %uint %244 %uint_1
-               OpStore %r_0 %245
-               OpBranch %152
-        %153 = OpLabel
+        %162 = OpLabel
+        %252 = OpLoad %uint %r_0
+        %253 = OpIAdd %uint %252 %uint_1
+               OpStore %r_0 %253
+               OpBranch %160
+        %161 = OpLabel
                OpReturn
                OpFunctionEnd
-       %main = OpFunction %void None %246
-        %248 = OpLabel
-        %250 = OpLoad %v3uint %WorkGroupID_1
-        %251 = OpLoad %v3uint %LocalInvocationID_1
-        %252 = OpLoad %uint %local_invocation_index_1
-        %249 = OpFunctionCall %void %main_inner %250 %251 %252
+       %main = OpFunction %void None %254
+        %256 = OpLabel
+        %258 = OpLoad %v3uint %WorkGroupID_1
+        %259 = OpLoad %v3uint %LocalInvocationID_1
+        %260 = OpLoad %uint %local_invocation_index_1
+        %257 = OpFunctionCall %void %main_inner %258 %259 %260
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/builtins/atomicStore/array/aliased_arrays.spvasm.expected.dxc.hlsl b/test/tint/builtins/atomicStore/array/aliased_arrays.spvasm.expected.dxc.hlsl
index a24f87a..b3bbd36 100644
--- a/test/tint/builtins/atomicStore/array/aliased_arrays.spvasm.expected.dxc.hlsl
+++ b/test/tint/builtins/atomicStore/array/aliased_arrays.spvasm.expected.dxc.hlsl
@@ -1,3 +1,11 @@
+uint tint_div(uint lhs, uint rhs) {
+  return (lhs / ((rhs == 0u) ? 1u : rhs));
+}
+
+uint tint_mod(uint lhs, uint rhs) {
+  return (lhs % ((rhs == 0u) ? 1u : rhs));
+}
+
 static uint local_invocation_index_1 = 0u;
 groupshared uint wg[3][2][1];
 
@@ -12,8 +20,11 @@
     const uint x_31 = idx;
     const uint x_33 = idx;
     const uint x_35 = idx;
+    const uint tint_symbol_2 = tint_div(x_31, 2u);
+    const uint tint_symbol_3 = tint_mod(x_33, 2u);
+    const uint tint_symbol_4 = tint_mod(x_35, 1u);
     uint atomic_result = 0u;
-    InterlockedExchange(wg[(x_31 / 2u)][(x_33 % 2u)][(x_35 % 1u)], 0u, atomic_result);
+    InterlockedExchange(wg[tint_symbol_2][tint_symbol_3][tint_symbol_4], 0u, atomic_result);
     {
       const uint x_42 = idx;
       idx = (x_42 + 1u);
diff --git a/test/tint/builtins/atomicStore/array/aliased_arrays.spvasm.expected.fxc.hlsl b/test/tint/builtins/atomicStore/array/aliased_arrays.spvasm.expected.fxc.hlsl
index a24f87a..b3bbd36 100644
--- a/test/tint/builtins/atomicStore/array/aliased_arrays.spvasm.expected.fxc.hlsl
+++ b/test/tint/builtins/atomicStore/array/aliased_arrays.spvasm.expected.fxc.hlsl
@@ -1,3 +1,11 @@
+uint tint_div(uint lhs, uint rhs) {
+  return (lhs / ((rhs == 0u) ? 1u : rhs));
+}
+
+uint tint_mod(uint lhs, uint rhs) {
+  return (lhs % ((rhs == 0u) ? 1u : rhs));
+}
+
 static uint local_invocation_index_1 = 0u;
 groupshared uint wg[3][2][1];
 
@@ -12,8 +20,11 @@
     const uint x_31 = idx;
     const uint x_33 = idx;
     const uint x_35 = idx;
+    const uint tint_symbol_2 = tint_div(x_31, 2u);
+    const uint tint_symbol_3 = tint_mod(x_33, 2u);
+    const uint tint_symbol_4 = tint_mod(x_35, 1u);
     uint atomic_result = 0u;
-    InterlockedExchange(wg[(x_31 / 2u)][(x_33 % 2u)][(x_35 % 1u)], 0u, atomic_result);
+    InterlockedExchange(wg[tint_symbol_2][tint_symbol_3][tint_symbol_4], 0u, atomic_result);
     {
       const uint x_42 = idx;
       idx = (x_42 + 1u);
diff --git a/test/tint/builtins/atomicStore/array/aliased_arrays.spvasm.expected.glsl b/test/tint/builtins/atomicStore/array/aliased_arrays.spvasm.expected.glsl
index f73d1c9..d21534a 100644
--- a/test/tint/builtins/atomicStore/array/aliased_arrays.spvasm.expected.glsl
+++ b/test/tint/builtins/atomicStore/array/aliased_arrays.spvasm.expected.glsl
@@ -1,5 +1,13 @@
 #version 310 es
 
+uint tint_div(uint lhs, uint rhs) {
+  return (lhs / ((rhs == 0u) ? 1u : rhs));
+}
+
+uint tint_mod(uint lhs, uint rhs) {
+  return (lhs % ((rhs == 0u) ? 1u : rhs));
+}
+
 uint local_invocation_index_1 = 0u;
 shared uint wg[3][2][1];
 void compute_main_inner(uint local_invocation_index) {
@@ -13,7 +21,10 @@
     uint x_31 = idx;
     uint x_33 = idx;
     uint x_35 = idx;
-    atomicExchange(wg[(x_31 / 2u)][(x_33 % 2u)][(x_35 % 1u)], 0u);
+    uint tint_symbol = tint_div(x_31, 2u);
+    uint tint_symbol_1 = tint_mod(x_33, 2u);
+    uint tint_symbol_2 = tint_mod(x_35, 1u);
+    atomicExchange(wg[tint_symbol][tint_symbol_1][tint_symbol_2], 0u);
     {
       uint x_42 = idx;
       idx = (x_42 + 1u);
diff --git a/test/tint/builtins/atomicStore/array/aliased_arrays.spvasm.expected.msl b/test/tint/builtins/atomicStore/array/aliased_arrays.spvasm.expected.msl
index 943a64c..f1220af 100644
--- a/test/tint/builtins/atomicStore/array/aliased_arrays.spvasm.expected.msl
+++ b/test/tint/builtins/atomicStore/array/aliased_arrays.spvasm.expected.msl
@@ -14,7 +14,15 @@
     T elements[N];
 };
 
-void compute_main_inner(uint local_invocation_index, threadgroup tint_array<tint_array<tint_array<atomic_uint, 1>, 2>, 3>* const tint_symbol) {
+uint tint_div(uint lhs, uint rhs) {
+  return (lhs / select(rhs, 1u, (rhs == 0u)));
+}
+
+uint tint_mod(uint lhs, uint rhs) {
+  return (lhs % select(rhs, 1u, (rhs == 0u)));
+}
+
+void compute_main_inner(uint local_invocation_index, threadgroup tint_array<tint_array<tint_array<atomic_uint, 1>, 2>, 3>* const tint_symbol_3) {
   uint idx = 0u;
   idx = local_invocation_index;
   while (true) {
@@ -25,39 +33,42 @@
     uint const x_31 = idx;
     uint const x_33 = idx;
     uint const x_35 = idx;
-    atomic_store_explicit(&((*(tint_symbol))[(x_31 / 2u)][(x_33 % 2u)][(x_35 % 1u)]), 0u, memory_order_relaxed);
+    uint const tint_symbol = tint_div(x_31, 2u);
+    uint const tint_symbol_1 = tint_mod(x_33, 2u);
+    uint const tint_symbol_2 = tint_mod(x_35, 1u);
+    atomic_store_explicit(&((*(tint_symbol_3))[tint_symbol][tint_symbol_1][tint_symbol_2]), 0u, memory_order_relaxed);
     {
       uint const x_42 = idx;
       idx = (x_42 + 1u);
     }
   }
   threadgroup_barrier(mem_flags::mem_threadgroup);
-  atomic_store_explicit(&((*(tint_symbol))[2][1][0]), 1u, memory_order_relaxed);
+  atomic_store_explicit(&((*(tint_symbol_3))[2][1][0]), 1u, memory_order_relaxed);
   return;
 }
 
-void compute_main_1(thread uint* const tint_symbol_1, threadgroup tint_array<tint_array<tint_array<atomic_uint, 1>, 2>, 3>* const tint_symbol_2) {
-  uint const x_57 = *(tint_symbol_1);
-  compute_main_inner(x_57, tint_symbol_2);
+void compute_main_1(thread uint* const tint_symbol_4, threadgroup tint_array<tint_array<tint_array<atomic_uint, 1>, 2>, 3>* const tint_symbol_5) {
+  uint const x_57 = *(tint_symbol_4);
+  compute_main_inner(x_57, tint_symbol_5);
   return;
 }
 
-void compute_main_inner_1(uint local_invocation_index_1_param, threadgroup tint_array<tint_array<tint_array<atomic_uint, 1>, 2>, 3>* const tint_symbol_3, thread uint* const tint_symbol_4) {
+void compute_main_inner_1(uint local_invocation_index_1_param, threadgroup tint_array<tint_array<tint_array<atomic_uint, 1>, 2>, 3>* const tint_symbol_6, thread uint* const tint_symbol_7) {
   for(uint idx_1 = local_invocation_index_1_param; (idx_1 < 6u); idx_1 = (idx_1 + 1u)) {
     uint const i = (idx_1 / 2u);
     uint const i_1 = (idx_1 % 2u);
     uint const i_2 = (idx_1 % 1u);
-    atomic_store_explicit(&((*(tint_symbol_3))[i][i_1][i_2]), 0u, memory_order_relaxed);
+    atomic_store_explicit(&((*(tint_symbol_6))[i][i_1][i_2]), 0u, memory_order_relaxed);
   }
   threadgroup_barrier(mem_flags::mem_threadgroup);
-  *(tint_symbol_4) = local_invocation_index_1_param;
-  compute_main_1(tint_symbol_4, tint_symbol_3);
+  *(tint_symbol_7) = local_invocation_index_1_param;
+  compute_main_1(tint_symbol_7, tint_symbol_6);
 }
 
 kernel void compute_main(uint local_invocation_index_1_param [[thread_index_in_threadgroup]]) {
-  threadgroup tint_array<tint_array<tint_array<atomic_uint, 1>, 2>, 3> tint_symbol_5;
-  thread uint tint_symbol_6 = 0u;
-  compute_main_inner_1(local_invocation_index_1_param, &(tint_symbol_5), &(tint_symbol_6));
+  threadgroup tint_array<tint_array<tint_array<atomic_uint, 1>, 2>, 3> tint_symbol_8;
+  thread uint tint_symbol_9 = 0u;
+  compute_main_inner_1(local_invocation_index_1_param, &(tint_symbol_8), &(tint_symbol_9));
   return;
 }
 
diff --git a/test/tint/builtins/atomicStore/array/aliased_arrays.spvasm.expected.spvasm b/test/tint/builtins/atomicStore/array/aliased_arrays.spvasm.expected.spvasm
index 8091c97..fb00bc8 100644
--- a/test/tint/builtins/atomicStore/array/aliased_arrays.spvasm.expected.spvasm
+++ b/test/tint/builtins/atomicStore/array/aliased_arrays.spvasm.expected.spvasm
@@ -1,7 +1,7 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 90
+; Bound: 105
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
@@ -10,6 +10,12 @@
                OpName %local_invocation_index_1_param_1 "local_invocation_index_1_param_1"
                OpName %local_invocation_index_1 "local_invocation_index_1"
                OpName %wg "wg"
+               OpName %tint_div "tint_div"
+               OpName %lhs "lhs"
+               OpName %rhs "rhs"
+               OpName %tint_mod "tint_mod"
+               OpName %lhs_0 "lhs"
+               OpName %rhs_0 "rhs"
                OpName %compute_main_inner "compute_main_inner"
                OpName %local_invocation_index "local_invocation_index"
                OpName %idx "idx"
@@ -36,105 +42,124 @@
 %_arr__arr__arr_uint_uint_1_uint_2_uint_3 = OpTypeArray %_arr__arr_uint_uint_1_uint_2 %uint_3
 %_ptr_Workgroup__arr__arr__arr_uint_uint_1_uint_2_uint_3 = OpTypePointer Workgroup %_arr__arr__arr_uint_uint_1_uint_2_uint_3
          %wg = OpVariable %_ptr_Workgroup__arr__arr__arr_uint_uint_1_uint_2_uint_3 Workgroup
+         %15 = OpTypeFunction %uint %uint %uint
+       %bool = OpTypeBool
        %void = OpTypeVoid
-         %15 = OpTypeFunction %void %uint
+         %31 = OpTypeFunction %void %uint
 %_ptr_Function_uint = OpTypePointer Function %uint
      %uint_6 = OpConstant %uint 6
-       %bool = OpTypeBool
      %uint_0 = OpConstant %uint 0
 %_ptr_Workgroup_uint = OpTypePointer Workgroup %uint
    %uint_264 = OpConstant %uint 264
         %int = OpTypeInt 32 1
       %int_2 = OpConstant %int 2
       %int_1 = OpConstant %int 1
-         %53 = OpConstantNull %int
-         %55 = OpTypeFunction %void
-%compute_main_inner = OpFunction %void None %15
-%local_invocation_index = OpFunctionParameter %uint
+         %68 = OpConstantNull %int
+         %70 = OpTypeFunction %void
+   %tint_div = OpFunction %uint None %15
+        %lhs = OpFunctionParameter %uint
+        %rhs = OpFunctionParameter %uint
          %19 = OpLabel
+         %21 = OpIEqual %bool %rhs %6
+         %20 = OpSelect %uint %21 %uint_1 %rhs
+         %23 = OpUDiv %uint %lhs %20
+               OpReturnValue %23
+               OpFunctionEnd
+   %tint_mod = OpFunction %uint None %15
+      %lhs_0 = OpFunctionParameter %uint
+      %rhs_0 = OpFunctionParameter %uint
+         %27 = OpLabel
+         %29 = OpIEqual %bool %rhs_0 %6
+         %28 = OpSelect %uint %29 %uint_1 %rhs_0
+         %30 = OpUMod %uint %lhs_0 %28
+               OpReturnValue %30
+               OpFunctionEnd
+%compute_main_inner = OpFunction %void None %31
+%local_invocation_index = OpFunctionParameter %uint
+         %35 = OpLabel
         %idx = OpVariable %_ptr_Function_uint Function %6
                OpStore %idx %6
                OpStore %idx %local_invocation_index
-               OpBranch %22
-         %22 = OpLabel
-               OpLoopMerge %23 %24 None
-               OpBranch %25
-         %25 = OpLabel
-         %26 = OpLoad %uint %idx
-         %29 = OpULessThan %bool %26 %uint_6
-         %27 = OpLogicalNot %bool %29
-               OpSelectionMerge %31 None
-               OpBranchConditional %27 %32 %31
-         %32 = OpLabel
-               OpBranch %23
-         %31 = OpLabel
-         %33 = OpLoad %uint %idx
-         %34 = OpLoad %uint %idx
-         %35 = OpLoad %uint %idx
-         %39 = OpUDiv %uint %33 %uint_2
-         %40 = OpUMod %uint %34 %uint_2
-         %41 = OpUMod %uint %35 %uint_1
-         %43 = OpAccessChain %_ptr_Workgroup_uint %wg %39 %40 %41
-               OpAtomicStore %43 %uint_2 %uint_0 %6
-               OpBranch %24
-         %24 = OpLabel
-         %44 = OpLoad %uint %idx
-         %45 = OpIAdd %uint %44 %uint_1
-               OpStore %idx %45
-               OpBranch %22
-         %23 = OpLabel
+               OpBranch %38
+         %38 = OpLabel
+               OpLoopMerge %39 %40 None
+               OpBranch %41
+         %41 = OpLabel
+         %42 = OpLoad %uint %idx
+         %45 = OpULessThan %bool %42 %uint_6
+         %43 = OpLogicalNot %bool %45
+               OpSelectionMerge %46 None
+               OpBranchConditional %43 %47 %46
+         %47 = OpLabel
+               OpBranch %39
+         %46 = OpLabel
+         %48 = OpLoad %uint %idx
+         %49 = OpLoad %uint %idx
+         %50 = OpLoad %uint %idx
+         %51 = OpFunctionCall %uint %tint_div %48 %uint_2
+         %52 = OpFunctionCall %uint %tint_mod %49 %uint_2
+         %53 = OpFunctionCall %uint %tint_mod %50 %uint_1
+         %58 = OpAccessChain %_ptr_Workgroup_uint %wg %51 %52 %53
+               OpAtomicStore %58 %uint_2 %uint_0 %6
+               OpBranch %40
+         %40 = OpLabel
+         %59 = OpLoad %uint %idx
+         %60 = OpIAdd %uint %59 %uint_1
+               OpStore %idx %60
+               OpBranch %38
+         %39 = OpLabel
                OpControlBarrier %uint_2 %uint_2 %uint_264
-         %54 = OpAccessChain %_ptr_Workgroup_uint %wg %int_2 %int_1 %53
-               OpAtomicStore %54 %uint_2 %uint_0 %uint_1
+         %69 = OpAccessChain %_ptr_Workgroup_uint %wg %int_2 %int_1 %68
+               OpAtomicStore %69 %uint_2 %uint_0 %uint_1
                OpReturn
                OpFunctionEnd
-%compute_main_1 = OpFunction %void None %55
-         %57 = OpLabel
-         %58 = OpLoad %uint %local_invocation_index_1
-         %59 = OpFunctionCall %void %compute_main_inner %58
+%compute_main_1 = OpFunction %void None %70
+         %72 = OpLabel
+         %73 = OpLoad %uint %local_invocation_index_1
+         %74 = OpFunctionCall %void %compute_main_inner %73
                OpReturn
                OpFunctionEnd
-%compute_main_inner_1 = OpFunction %void None %15
+%compute_main_inner_1 = OpFunction %void None %31
 %local_invocation_index_1_param = OpFunctionParameter %uint
-         %62 = OpLabel
+         %77 = OpLabel
       %idx_1 = OpVariable %_ptr_Function_uint Function %6
                OpStore %idx_1 %local_invocation_index_1_param
-               OpBranch %64
-         %64 = OpLabel
-               OpLoopMerge %65 %66 None
-               OpBranch %67
-         %67 = OpLabel
-         %69 = OpLoad %uint %idx_1
-         %70 = OpULessThan %bool %69 %uint_6
-         %68 = OpLogicalNot %bool %70
-               OpSelectionMerge %71 None
-               OpBranchConditional %68 %72 %71
-         %72 = OpLabel
-               OpBranch %65
-         %71 = OpLabel
-         %73 = OpLoad %uint %idx_1
-         %74 = OpUDiv %uint %73 %uint_2
-         %75 = OpLoad %uint %idx_1
-         %76 = OpUMod %uint %75 %uint_2
-         %77 = OpLoad %uint %idx_1
-         %78 = OpUMod %uint %77 %uint_1
-         %81 = OpAccessChain %_ptr_Workgroup_uint %wg %74 %76 %78
-               OpAtomicStore %81 %uint_2 %uint_0 %6
-               OpBranch %66
-         %66 = OpLabel
-         %82 = OpLoad %uint %idx_1
-         %83 = OpIAdd %uint %82 %uint_1
-               OpStore %idx_1 %83
-               OpBranch %64
-         %65 = OpLabel
+               OpBranch %79
+         %79 = OpLabel
+               OpLoopMerge %80 %81 None
+               OpBranch %82
+         %82 = OpLabel
+         %84 = OpLoad %uint %idx_1
+         %85 = OpULessThan %bool %84 %uint_6
+         %83 = OpLogicalNot %bool %85
+               OpSelectionMerge %86 None
+               OpBranchConditional %83 %87 %86
+         %87 = OpLabel
+               OpBranch %80
+         %86 = OpLabel
+         %88 = OpLoad %uint %idx_1
+         %89 = OpUDiv %uint %88 %uint_2
+         %90 = OpLoad %uint %idx_1
+         %91 = OpUMod %uint %90 %uint_2
+         %92 = OpLoad %uint %idx_1
+         %93 = OpUMod %uint %92 %uint_1
+         %96 = OpAccessChain %_ptr_Workgroup_uint %wg %89 %91 %93
+               OpAtomicStore %96 %uint_2 %uint_0 %6
+               OpBranch %81
+         %81 = OpLabel
+         %97 = OpLoad %uint %idx_1
+         %98 = OpIAdd %uint %97 %uint_1
+               OpStore %idx_1 %98
+               OpBranch %79
+         %80 = OpLabel
                OpControlBarrier %uint_2 %uint_2 %uint_264
                OpStore %local_invocation_index_1 %local_invocation_index_1_param
-         %85 = OpFunctionCall %void %compute_main_1
+        %100 = OpFunctionCall %void %compute_main_1
                OpReturn
                OpFunctionEnd
-%compute_main = OpFunction %void None %55
-         %87 = OpLabel
-         %89 = OpLoad %uint %local_invocation_index_1_param_1
-         %88 = OpFunctionCall %void %compute_main_inner_1 %89
+%compute_main = OpFunction %void None %70
+        %102 = OpLabel
+        %104 = OpLoad %uint %local_invocation_index_1_param_1
+        %103 = OpFunctionCall %void %compute_main_inner_1 %104
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/builtins/atomicStore/array/arrays.spvasm.expected.dxc.hlsl b/test/tint/builtins/atomicStore/array/arrays.spvasm.expected.dxc.hlsl
index a24f87a..b3bbd36 100644
--- a/test/tint/builtins/atomicStore/array/arrays.spvasm.expected.dxc.hlsl
+++ b/test/tint/builtins/atomicStore/array/arrays.spvasm.expected.dxc.hlsl
@@ -1,3 +1,11 @@
+uint tint_div(uint lhs, uint rhs) {
+  return (lhs / ((rhs == 0u) ? 1u : rhs));
+}
+
+uint tint_mod(uint lhs, uint rhs) {
+  return (lhs % ((rhs == 0u) ? 1u : rhs));
+}
+
 static uint local_invocation_index_1 = 0u;
 groupshared uint wg[3][2][1];
 
@@ -12,8 +20,11 @@
     const uint x_31 = idx;
     const uint x_33 = idx;
     const uint x_35 = idx;
+    const uint tint_symbol_2 = tint_div(x_31, 2u);
+    const uint tint_symbol_3 = tint_mod(x_33, 2u);
+    const uint tint_symbol_4 = tint_mod(x_35, 1u);
     uint atomic_result = 0u;
-    InterlockedExchange(wg[(x_31 / 2u)][(x_33 % 2u)][(x_35 % 1u)], 0u, atomic_result);
+    InterlockedExchange(wg[tint_symbol_2][tint_symbol_3][tint_symbol_4], 0u, atomic_result);
     {
       const uint x_42 = idx;
       idx = (x_42 + 1u);
diff --git a/test/tint/builtins/atomicStore/array/arrays.spvasm.expected.fxc.hlsl b/test/tint/builtins/atomicStore/array/arrays.spvasm.expected.fxc.hlsl
index a24f87a..b3bbd36 100644
--- a/test/tint/builtins/atomicStore/array/arrays.spvasm.expected.fxc.hlsl
+++ b/test/tint/builtins/atomicStore/array/arrays.spvasm.expected.fxc.hlsl
@@ -1,3 +1,11 @@
+uint tint_div(uint lhs, uint rhs) {
+  return (lhs / ((rhs == 0u) ? 1u : rhs));
+}
+
+uint tint_mod(uint lhs, uint rhs) {
+  return (lhs % ((rhs == 0u) ? 1u : rhs));
+}
+
 static uint local_invocation_index_1 = 0u;
 groupshared uint wg[3][2][1];
 
@@ -12,8 +20,11 @@
     const uint x_31 = idx;
     const uint x_33 = idx;
     const uint x_35 = idx;
+    const uint tint_symbol_2 = tint_div(x_31, 2u);
+    const uint tint_symbol_3 = tint_mod(x_33, 2u);
+    const uint tint_symbol_4 = tint_mod(x_35, 1u);
     uint atomic_result = 0u;
-    InterlockedExchange(wg[(x_31 / 2u)][(x_33 % 2u)][(x_35 % 1u)], 0u, atomic_result);
+    InterlockedExchange(wg[tint_symbol_2][tint_symbol_3][tint_symbol_4], 0u, atomic_result);
     {
       const uint x_42 = idx;
       idx = (x_42 + 1u);
diff --git a/test/tint/builtins/atomicStore/array/arrays.spvasm.expected.glsl b/test/tint/builtins/atomicStore/array/arrays.spvasm.expected.glsl
index f73d1c9..d21534a 100644
--- a/test/tint/builtins/atomicStore/array/arrays.spvasm.expected.glsl
+++ b/test/tint/builtins/atomicStore/array/arrays.spvasm.expected.glsl
@@ -1,5 +1,13 @@
 #version 310 es
 
+uint tint_div(uint lhs, uint rhs) {
+  return (lhs / ((rhs == 0u) ? 1u : rhs));
+}
+
+uint tint_mod(uint lhs, uint rhs) {
+  return (lhs % ((rhs == 0u) ? 1u : rhs));
+}
+
 uint local_invocation_index_1 = 0u;
 shared uint wg[3][2][1];
 void compute_main_inner(uint local_invocation_index) {
@@ -13,7 +21,10 @@
     uint x_31 = idx;
     uint x_33 = idx;
     uint x_35 = idx;
-    atomicExchange(wg[(x_31 / 2u)][(x_33 % 2u)][(x_35 % 1u)], 0u);
+    uint tint_symbol = tint_div(x_31, 2u);
+    uint tint_symbol_1 = tint_mod(x_33, 2u);
+    uint tint_symbol_2 = tint_mod(x_35, 1u);
+    atomicExchange(wg[tint_symbol][tint_symbol_1][tint_symbol_2], 0u);
     {
       uint x_42 = idx;
       idx = (x_42 + 1u);
diff --git a/test/tint/builtins/atomicStore/array/arrays.spvasm.expected.msl b/test/tint/builtins/atomicStore/array/arrays.spvasm.expected.msl
index 943a64c..f1220af 100644
--- a/test/tint/builtins/atomicStore/array/arrays.spvasm.expected.msl
+++ b/test/tint/builtins/atomicStore/array/arrays.spvasm.expected.msl
@@ -14,7 +14,15 @@
     T elements[N];
 };
 
-void compute_main_inner(uint local_invocation_index, threadgroup tint_array<tint_array<tint_array<atomic_uint, 1>, 2>, 3>* const tint_symbol) {
+uint tint_div(uint lhs, uint rhs) {
+  return (lhs / select(rhs, 1u, (rhs == 0u)));
+}
+
+uint tint_mod(uint lhs, uint rhs) {
+  return (lhs % select(rhs, 1u, (rhs == 0u)));
+}
+
+void compute_main_inner(uint local_invocation_index, threadgroup tint_array<tint_array<tint_array<atomic_uint, 1>, 2>, 3>* const tint_symbol_3) {
   uint idx = 0u;
   idx = local_invocation_index;
   while (true) {
@@ -25,39 +33,42 @@
     uint const x_31 = idx;
     uint const x_33 = idx;
     uint const x_35 = idx;
-    atomic_store_explicit(&((*(tint_symbol))[(x_31 / 2u)][(x_33 % 2u)][(x_35 % 1u)]), 0u, memory_order_relaxed);
+    uint const tint_symbol = tint_div(x_31, 2u);
+    uint const tint_symbol_1 = tint_mod(x_33, 2u);
+    uint const tint_symbol_2 = tint_mod(x_35, 1u);
+    atomic_store_explicit(&((*(tint_symbol_3))[tint_symbol][tint_symbol_1][tint_symbol_2]), 0u, memory_order_relaxed);
     {
       uint const x_42 = idx;
       idx = (x_42 + 1u);
     }
   }
   threadgroup_barrier(mem_flags::mem_threadgroup);
-  atomic_store_explicit(&((*(tint_symbol))[2][1][0]), 1u, memory_order_relaxed);
+  atomic_store_explicit(&((*(tint_symbol_3))[2][1][0]), 1u, memory_order_relaxed);
   return;
 }
 
-void compute_main_1(thread uint* const tint_symbol_1, threadgroup tint_array<tint_array<tint_array<atomic_uint, 1>, 2>, 3>* const tint_symbol_2) {
-  uint const x_57 = *(tint_symbol_1);
-  compute_main_inner(x_57, tint_symbol_2);
+void compute_main_1(thread uint* const tint_symbol_4, threadgroup tint_array<tint_array<tint_array<atomic_uint, 1>, 2>, 3>* const tint_symbol_5) {
+  uint const x_57 = *(tint_symbol_4);
+  compute_main_inner(x_57, tint_symbol_5);
   return;
 }
 
-void compute_main_inner_1(uint local_invocation_index_1_param, threadgroup tint_array<tint_array<tint_array<atomic_uint, 1>, 2>, 3>* const tint_symbol_3, thread uint* const tint_symbol_4) {
+void compute_main_inner_1(uint local_invocation_index_1_param, threadgroup tint_array<tint_array<tint_array<atomic_uint, 1>, 2>, 3>* const tint_symbol_6, thread uint* const tint_symbol_7) {
   for(uint idx_1 = local_invocation_index_1_param; (idx_1 < 6u); idx_1 = (idx_1 + 1u)) {
     uint const i = (idx_1 / 2u);
     uint const i_1 = (idx_1 % 2u);
     uint const i_2 = (idx_1 % 1u);
-    atomic_store_explicit(&((*(tint_symbol_3))[i][i_1][i_2]), 0u, memory_order_relaxed);
+    atomic_store_explicit(&((*(tint_symbol_6))[i][i_1][i_2]), 0u, memory_order_relaxed);
   }
   threadgroup_barrier(mem_flags::mem_threadgroup);
-  *(tint_symbol_4) = local_invocation_index_1_param;
-  compute_main_1(tint_symbol_4, tint_symbol_3);
+  *(tint_symbol_7) = local_invocation_index_1_param;
+  compute_main_1(tint_symbol_7, tint_symbol_6);
 }
 
 kernel void compute_main(uint local_invocation_index_1_param [[thread_index_in_threadgroup]]) {
-  threadgroup tint_array<tint_array<tint_array<atomic_uint, 1>, 2>, 3> tint_symbol_5;
-  thread uint tint_symbol_6 = 0u;
-  compute_main_inner_1(local_invocation_index_1_param, &(tint_symbol_5), &(tint_symbol_6));
+  threadgroup tint_array<tint_array<tint_array<atomic_uint, 1>, 2>, 3> tint_symbol_8;
+  thread uint tint_symbol_9 = 0u;
+  compute_main_inner_1(local_invocation_index_1_param, &(tint_symbol_8), &(tint_symbol_9));
   return;
 }
 
diff --git a/test/tint/builtins/atomicStore/array/arrays.spvasm.expected.spvasm b/test/tint/builtins/atomicStore/array/arrays.spvasm.expected.spvasm
index 8091c97..fb00bc8 100644
--- a/test/tint/builtins/atomicStore/array/arrays.spvasm.expected.spvasm
+++ b/test/tint/builtins/atomicStore/array/arrays.spvasm.expected.spvasm
@@ -1,7 +1,7 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 90
+; Bound: 105
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
@@ -10,6 +10,12 @@
                OpName %local_invocation_index_1_param_1 "local_invocation_index_1_param_1"
                OpName %local_invocation_index_1 "local_invocation_index_1"
                OpName %wg "wg"
+               OpName %tint_div "tint_div"
+               OpName %lhs "lhs"
+               OpName %rhs "rhs"
+               OpName %tint_mod "tint_mod"
+               OpName %lhs_0 "lhs"
+               OpName %rhs_0 "rhs"
                OpName %compute_main_inner "compute_main_inner"
                OpName %local_invocation_index "local_invocation_index"
                OpName %idx "idx"
@@ -36,105 +42,124 @@
 %_arr__arr__arr_uint_uint_1_uint_2_uint_3 = OpTypeArray %_arr__arr_uint_uint_1_uint_2 %uint_3
 %_ptr_Workgroup__arr__arr__arr_uint_uint_1_uint_2_uint_3 = OpTypePointer Workgroup %_arr__arr__arr_uint_uint_1_uint_2_uint_3
          %wg = OpVariable %_ptr_Workgroup__arr__arr__arr_uint_uint_1_uint_2_uint_3 Workgroup
+         %15 = OpTypeFunction %uint %uint %uint
+       %bool = OpTypeBool
        %void = OpTypeVoid
-         %15 = OpTypeFunction %void %uint
+         %31 = OpTypeFunction %void %uint
 %_ptr_Function_uint = OpTypePointer Function %uint
      %uint_6 = OpConstant %uint 6
-       %bool = OpTypeBool
      %uint_0 = OpConstant %uint 0
 %_ptr_Workgroup_uint = OpTypePointer Workgroup %uint
    %uint_264 = OpConstant %uint 264
         %int = OpTypeInt 32 1
       %int_2 = OpConstant %int 2
       %int_1 = OpConstant %int 1
-         %53 = OpConstantNull %int
-         %55 = OpTypeFunction %void
-%compute_main_inner = OpFunction %void None %15
-%local_invocation_index = OpFunctionParameter %uint
+         %68 = OpConstantNull %int
+         %70 = OpTypeFunction %void
+   %tint_div = OpFunction %uint None %15
+        %lhs = OpFunctionParameter %uint
+        %rhs = OpFunctionParameter %uint
          %19 = OpLabel
+         %21 = OpIEqual %bool %rhs %6
+         %20 = OpSelect %uint %21 %uint_1 %rhs
+         %23 = OpUDiv %uint %lhs %20
+               OpReturnValue %23
+               OpFunctionEnd
+   %tint_mod = OpFunction %uint None %15
+      %lhs_0 = OpFunctionParameter %uint
+      %rhs_0 = OpFunctionParameter %uint
+         %27 = OpLabel
+         %29 = OpIEqual %bool %rhs_0 %6
+         %28 = OpSelect %uint %29 %uint_1 %rhs_0
+         %30 = OpUMod %uint %lhs_0 %28
+               OpReturnValue %30
+               OpFunctionEnd
+%compute_main_inner = OpFunction %void None %31
+%local_invocation_index = OpFunctionParameter %uint
+         %35 = OpLabel
         %idx = OpVariable %_ptr_Function_uint Function %6
                OpStore %idx %6
                OpStore %idx %local_invocation_index
-               OpBranch %22
-         %22 = OpLabel
-               OpLoopMerge %23 %24 None
-               OpBranch %25
-         %25 = OpLabel
-         %26 = OpLoad %uint %idx
-         %29 = OpULessThan %bool %26 %uint_6
-         %27 = OpLogicalNot %bool %29
-               OpSelectionMerge %31 None
-               OpBranchConditional %27 %32 %31
-         %32 = OpLabel
-               OpBranch %23
-         %31 = OpLabel
-         %33 = OpLoad %uint %idx
-         %34 = OpLoad %uint %idx
-         %35 = OpLoad %uint %idx
-         %39 = OpUDiv %uint %33 %uint_2
-         %40 = OpUMod %uint %34 %uint_2
-         %41 = OpUMod %uint %35 %uint_1
-         %43 = OpAccessChain %_ptr_Workgroup_uint %wg %39 %40 %41
-               OpAtomicStore %43 %uint_2 %uint_0 %6
-               OpBranch %24
-         %24 = OpLabel
-         %44 = OpLoad %uint %idx
-         %45 = OpIAdd %uint %44 %uint_1
-               OpStore %idx %45
-               OpBranch %22
-         %23 = OpLabel
+               OpBranch %38
+         %38 = OpLabel
+               OpLoopMerge %39 %40 None
+               OpBranch %41
+         %41 = OpLabel
+         %42 = OpLoad %uint %idx
+         %45 = OpULessThan %bool %42 %uint_6
+         %43 = OpLogicalNot %bool %45
+               OpSelectionMerge %46 None
+               OpBranchConditional %43 %47 %46
+         %47 = OpLabel
+               OpBranch %39
+         %46 = OpLabel
+         %48 = OpLoad %uint %idx
+         %49 = OpLoad %uint %idx
+         %50 = OpLoad %uint %idx
+         %51 = OpFunctionCall %uint %tint_div %48 %uint_2
+         %52 = OpFunctionCall %uint %tint_mod %49 %uint_2
+         %53 = OpFunctionCall %uint %tint_mod %50 %uint_1
+         %58 = OpAccessChain %_ptr_Workgroup_uint %wg %51 %52 %53
+               OpAtomicStore %58 %uint_2 %uint_0 %6
+               OpBranch %40
+         %40 = OpLabel
+         %59 = OpLoad %uint %idx
+         %60 = OpIAdd %uint %59 %uint_1
+               OpStore %idx %60
+               OpBranch %38
+         %39 = OpLabel
                OpControlBarrier %uint_2 %uint_2 %uint_264
-         %54 = OpAccessChain %_ptr_Workgroup_uint %wg %int_2 %int_1 %53
-               OpAtomicStore %54 %uint_2 %uint_0 %uint_1
+         %69 = OpAccessChain %_ptr_Workgroup_uint %wg %int_2 %int_1 %68
+               OpAtomicStore %69 %uint_2 %uint_0 %uint_1
                OpReturn
                OpFunctionEnd
-%compute_main_1 = OpFunction %void None %55
-         %57 = OpLabel
-         %58 = OpLoad %uint %local_invocation_index_1
-         %59 = OpFunctionCall %void %compute_main_inner %58
+%compute_main_1 = OpFunction %void None %70
+         %72 = OpLabel
+         %73 = OpLoad %uint %local_invocation_index_1
+         %74 = OpFunctionCall %void %compute_main_inner %73
                OpReturn
                OpFunctionEnd
-%compute_main_inner_1 = OpFunction %void None %15
+%compute_main_inner_1 = OpFunction %void None %31
 %local_invocation_index_1_param = OpFunctionParameter %uint
-         %62 = OpLabel
+         %77 = OpLabel
       %idx_1 = OpVariable %_ptr_Function_uint Function %6
                OpStore %idx_1 %local_invocation_index_1_param
-               OpBranch %64
-         %64 = OpLabel
-               OpLoopMerge %65 %66 None
-               OpBranch %67
-         %67 = OpLabel
-         %69 = OpLoad %uint %idx_1
-         %70 = OpULessThan %bool %69 %uint_6
-         %68 = OpLogicalNot %bool %70
-               OpSelectionMerge %71 None
-               OpBranchConditional %68 %72 %71
-         %72 = OpLabel
-               OpBranch %65
-         %71 = OpLabel
-         %73 = OpLoad %uint %idx_1
-         %74 = OpUDiv %uint %73 %uint_2
-         %75 = OpLoad %uint %idx_1
-         %76 = OpUMod %uint %75 %uint_2
-         %77 = OpLoad %uint %idx_1
-         %78 = OpUMod %uint %77 %uint_1
-         %81 = OpAccessChain %_ptr_Workgroup_uint %wg %74 %76 %78
-               OpAtomicStore %81 %uint_2 %uint_0 %6
-               OpBranch %66
-         %66 = OpLabel
-         %82 = OpLoad %uint %idx_1
-         %83 = OpIAdd %uint %82 %uint_1
-               OpStore %idx_1 %83
-               OpBranch %64
-         %65 = OpLabel
+               OpBranch %79
+         %79 = OpLabel
+               OpLoopMerge %80 %81 None
+               OpBranch %82
+         %82 = OpLabel
+         %84 = OpLoad %uint %idx_1
+         %85 = OpULessThan %bool %84 %uint_6
+         %83 = OpLogicalNot %bool %85
+               OpSelectionMerge %86 None
+               OpBranchConditional %83 %87 %86
+         %87 = OpLabel
+               OpBranch %80
+         %86 = OpLabel
+         %88 = OpLoad %uint %idx_1
+         %89 = OpUDiv %uint %88 %uint_2
+         %90 = OpLoad %uint %idx_1
+         %91 = OpUMod %uint %90 %uint_2
+         %92 = OpLoad %uint %idx_1
+         %93 = OpUMod %uint %92 %uint_1
+         %96 = OpAccessChain %_ptr_Workgroup_uint %wg %89 %91 %93
+               OpAtomicStore %96 %uint_2 %uint_0 %6
+               OpBranch %81
+         %81 = OpLabel
+         %97 = OpLoad %uint %idx_1
+         %98 = OpIAdd %uint %97 %uint_1
+               OpStore %idx_1 %98
+               OpBranch %79
+         %80 = OpLabel
                OpControlBarrier %uint_2 %uint_2 %uint_264
                OpStore %local_invocation_index_1 %local_invocation_index_1_param
-         %85 = OpFunctionCall %void %compute_main_1
+        %100 = OpFunctionCall %void %compute_main_1
                OpReturn
                OpFunctionEnd
-%compute_main = OpFunction %void None %55
-         %87 = OpLabel
-         %89 = OpLoad %uint %local_invocation_index_1_param_1
-         %88 = OpFunctionCall %void %compute_main_inner_1 %89
+%compute_main = OpFunction %void None %70
+        %102 = OpLabel
+        %104 = OpLoad %uint %local_invocation_index_1_param_1
+        %103 = OpFunctionCall %void %compute_main_inner_1 %104
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/expressions/binary/div/scalar-scalar/i32.wgsl.expected.dxc.hlsl b/test/tint/expressions/binary/div/scalar-scalar/i32.wgsl.expected.dxc.hlsl
index 14717d6..9a4fe9b 100644
--- a/test/tint/expressions/binary/div/scalar-scalar/i32.wgsl.expected.dxc.hlsl
+++ b/test/tint/expressions/binary/div/scalar-scalar/i32.wgsl.expected.dxc.hlsl
@@ -1,7 +1,11 @@
+int tint_div(int lhs, int rhs) {
+  return (lhs / (((rhs == 0) | ((lhs == -2147483648) & (rhs == -1))) ? 1 : rhs));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   const int a = 1;
   const int b = 2;
-  const int r = (a / (b == 0 ? 1 : b));
+  const int r = tint_div(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/div/scalar-scalar/i32.wgsl.expected.fxc.hlsl b/test/tint/expressions/binary/div/scalar-scalar/i32.wgsl.expected.fxc.hlsl
index 14717d6..9a4fe9b 100644
--- a/test/tint/expressions/binary/div/scalar-scalar/i32.wgsl.expected.fxc.hlsl
+++ b/test/tint/expressions/binary/div/scalar-scalar/i32.wgsl.expected.fxc.hlsl
@@ -1,7 +1,11 @@
+int tint_div(int lhs, int rhs) {
+  return (lhs / (((rhs == 0) | ((lhs == -2147483648) & (rhs == -1))) ? 1 : rhs));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   const int a = 1;
   const int b = 2;
-  const int r = (a / (b == 0 ? 1 : b));
+  const int r = tint_div(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/div/scalar-scalar/i32.wgsl.expected.glsl b/test/tint/expressions/binary/div/scalar-scalar/i32.wgsl.expected.glsl
index 3af5945..db43bc2 100644
--- a/test/tint/expressions/binary/div/scalar-scalar/i32.wgsl.expected.glsl
+++ b/test/tint/expressions/binary/div/scalar-scalar/i32.wgsl.expected.glsl
@@ -1,9 +1,13 @@
 #version 310 es
 
+int tint_div(int lhs, int rhs) {
+  return (lhs / (bool(uint((rhs == 0)) | uint(bool(uint((lhs == -2147483648)) & uint((rhs == -1))))) ? 1 : rhs));
+}
+
 void f() {
   int a = 1;
   int b = 2;
-  int r = (a / b);
+  int r = tint_div(a, b);
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/expressions/binary/div/scalar-scalar/i32.wgsl.expected.msl b/test/tint/expressions/binary/div/scalar-scalar/i32.wgsl.expected.msl
index 17d1709..8be210c 100644
--- a/test/tint/expressions/binary/div/scalar-scalar/i32.wgsl.expected.msl
+++ b/test/tint/expressions/binary/div/scalar-scalar/i32.wgsl.expected.msl
@@ -1,10 +1,14 @@
 #include <metal_stdlib>
 
 using namespace metal;
+int tint_div(int lhs, int rhs) {
+  return (lhs / select(rhs, 1, bool((rhs == 0) | bool((lhs == (-2147483647 - 1)) & (rhs == -1)))));
+}
+
 kernel void f() {
   int const a = 1;
   int const b = 2;
-  int const r = (a / b);
+  int const r = tint_div(a, b);
   return;
 }
 
diff --git a/test/tint/expressions/binary/div/scalar-scalar/i32.wgsl.expected.spvasm b/test/tint/expressions/binary/div/scalar-scalar/i32.wgsl.expected.spvasm
index b5a41dc..86e459e 100644
--- a/test/tint/expressions/binary/div/scalar-scalar/i32.wgsl.expected.spvasm
+++ b/test/tint/expressions/binary/div/scalar-scalar/i32.wgsl.expected.spvasm
@@ -1,20 +1,41 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 9
+; Bound: 25
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %f "f"
                OpExecutionMode %f LocalSize 1 1 1
+               OpName %tint_div "tint_div"
+               OpName %lhs "lhs"
+               OpName %rhs "rhs"
                OpName %f "f"
-       %void = OpTypeVoid
-          %1 = OpTypeFunction %void
         %int = OpTypeInt 32 1
+          %1 = OpTypeFunction %int %int %int
+          %8 = OpConstantNull %int
+       %bool = OpTypeBool
+%int_n2147483648 = OpConstant %int -2147483648
+     %int_n1 = OpConstant %int -1
       %int_1 = OpConstant %int 1
+       %void = OpTypeVoid
+         %19 = OpTypeFunction %void
       %int_2 = OpConstant %int 2
-          %f = OpFunction %void None %1
-          %4 = OpLabel
-          %8 = OpSDiv %int %int_1 %int_2
+   %tint_div = OpFunction %int None %1
+        %lhs = OpFunctionParameter %int
+        %rhs = OpFunctionParameter %int
+          %6 = OpLabel
+          %9 = OpIEqual %bool %rhs %8
+         %12 = OpIEqual %bool %lhs %int_n2147483648
+         %14 = OpIEqual %bool %rhs %int_n1
+         %15 = OpLogicalAnd %bool %12 %14
+         %16 = OpLogicalOr %bool %9 %15
+          %7 = OpSelect %int %16 %int_1 %rhs
+         %18 = OpSDiv %int %lhs %7
+               OpReturnValue %18
+               OpFunctionEnd
+          %f = OpFunction %void None %19
+         %22 = OpLabel
+         %24 = OpFunctionCall %int %tint_div %int_1 %int_2
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/expressions/binary/div/scalar-scalar/u32.wgsl.expected.dxc.hlsl b/test/tint/expressions/binary/div/scalar-scalar/u32.wgsl.expected.dxc.hlsl
index 668387a..3aabfa6 100644
--- a/test/tint/expressions/binary/div/scalar-scalar/u32.wgsl.expected.dxc.hlsl
+++ b/test/tint/expressions/binary/div/scalar-scalar/u32.wgsl.expected.dxc.hlsl
@@ -1,7 +1,11 @@
+uint tint_div(uint lhs, uint rhs) {
+  return (lhs / ((rhs == 0u) ? 1u : rhs));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   const uint a = 1u;
   const uint b = 2u;
-  const uint r = (a / (b == 0u ? 1u : b));
+  const uint r = tint_div(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/div/scalar-scalar/u32.wgsl.expected.fxc.hlsl b/test/tint/expressions/binary/div/scalar-scalar/u32.wgsl.expected.fxc.hlsl
index 668387a..3aabfa6 100644
--- a/test/tint/expressions/binary/div/scalar-scalar/u32.wgsl.expected.fxc.hlsl
+++ b/test/tint/expressions/binary/div/scalar-scalar/u32.wgsl.expected.fxc.hlsl
@@ -1,7 +1,11 @@
+uint tint_div(uint lhs, uint rhs) {
+  return (lhs / ((rhs == 0u) ? 1u : rhs));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   const uint a = 1u;
   const uint b = 2u;
-  const uint r = (a / (b == 0u ? 1u : b));
+  const uint r = tint_div(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/div/scalar-scalar/u32.wgsl.expected.glsl b/test/tint/expressions/binary/div/scalar-scalar/u32.wgsl.expected.glsl
index 5780a27..e3a6918 100644
--- a/test/tint/expressions/binary/div/scalar-scalar/u32.wgsl.expected.glsl
+++ b/test/tint/expressions/binary/div/scalar-scalar/u32.wgsl.expected.glsl
@@ -1,9 +1,13 @@
 #version 310 es
 
+uint tint_div(uint lhs, uint rhs) {
+  return (lhs / ((rhs == 0u) ? 1u : rhs));
+}
+
 void f() {
   uint a = 1u;
   uint b = 2u;
-  uint r = (a / b);
+  uint r = tint_div(a, b);
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/expressions/binary/div/scalar-scalar/u32.wgsl.expected.msl b/test/tint/expressions/binary/div/scalar-scalar/u32.wgsl.expected.msl
index fa9d9e7..679758c 100644
--- a/test/tint/expressions/binary/div/scalar-scalar/u32.wgsl.expected.msl
+++ b/test/tint/expressions/binary/div/scalar-scalar/u32.wgsl.expected.msl
@@ -1,10 +1,14 @@
 #include <metal_stdlib>
 
 using namespace metal;
+uint tint_div(uint lhs, uint rhs) {
+  return (lhs / select(rhs, 1u, (rhs == 0u)));
+}
+
 kernel void f() {
   uint const a = 1u;
   uint const b = 2u;
-  uint const r = (a / b);
+  uint const r = tint_div(a, b);
   return;
 }
 
diff --git a/test/tint/expressions/binary/div/scalar-scalar/u32.wgsl.expected.spvasm b/test/tint/expressions/binary/div/scalar-scalar/u32.wgsl.expected.spvasm
index 012fb2b..ba6afb4 100644
--- a/test/tint/expressions/binary/div/scalar-scalar/u32.wgsl.expected.spvasm
+++ b/test/tint/expressions/binary/div/scalar-scalar/u32.wgsl.expected.spvasm
@@ -1,20 +1,35 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 9
+; Bound: 19
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %f "f"
                OpExecutionMode %f LocalSize 1 1 1
+               OpName %tint_div "tint_div"
+               OpName %lhs "lhs"
+               OpName %rhs "rhs"
                OpName %f "f"
-       %void = OpTypeVoid
-          %1 = OpTypeFunction %void
        %uint = OpTypeInt 32 0
+          %1 = OpTypeFunction %uint %uint %uint
+          %8 = OpConstantNull %uint
+       %bool = OpTypeBool
      %uint_1 = OpConstant %uint 1
+       %void = OpTypeVoid
+         %13 = OpTypeFunction %void
      %uint_2 = OpConstant %uint 2
-          %f = OpFunction %void None %1
-          %4 = OpLabel
-          %8 = OpUDiv %uint %uint_1 %uint_2
+   %tint_div = OpFunction %uint None %1
+        %lhs = OpFunctionParameter %uint
+        %rhs = OpFunctionParameter %uint
+          %6 = OpLabel
+          %9 = OpIEqual %bool %rhs %8
+          %7 = OpSelect %uint %9 %uint_1 %rhs
+         %12 = OpUDiv %uint %lhs %7
+               OpReturnValue %12
+               OpFunctionEnd
+          %f = OpFunction %void None %13
+         %16 = OpLabel
+         %18 = OpFunctionCall %uint %tint_div %uint_1 %uint_2
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/expressions/binary/div/scalar-vec3/i32.wgsl.expected.dxc.hlsl b/test/tint/expressions/binary/div/scalar-vec3/i32.wgsl.expected.dxc.hlsl
index c41e7ef..21ccbde 100644
--- a/test/tint/expressions/binary/div/scalar-vec3/i32.wgsl.expected.dxc.hlsl
+++ b/test/tint/expressions/binary/div/scalar-vec3/i32.wgsl.expected.dxc.hlsl
@@ -1,7 +1,12 @@
+int3 tint_div(int lhs, int3 rhs) {
+  const int3 l = int3((lhs).xxx);
+  return (l / (((rhs == (0).xxx) | ((l == (-2147483648).xxx) & (rhs == (-1).xxx))) ? (1).xxx : rhs));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   const int a = 4;
   const int3 b = int3(1, 2, 3);
-  const int3 r = (a / (b == int3(0, 0, 0) ? int3(1, 1, 1) : b));
+  const int3 r = tint_div(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/div/scalar-vec3/i32.wgsl.expected.fxc.hlsl b/test/tint/expressions/binary/div/scalar-vec3/i32.wgsl.expected.fxc.hlsl
index c41e7ef..21ccbde 100644
--- a/test/tint/expressions/binary/div/scalar-vec3/i32.wgsl.expected.fxc.hlsl
+++ b/test/tint/expressions/binary/div/scalar-vec3/i32.wgsl.expected.fxc.hlsl
@@ -1,7 +1,12 @@
+int3 tint_div(int lhs, int3 rhs) {
+  const int3 l = int3((lhs).xxx);
+  return (l / (((rhs == (0).xxx) | ((l == (-2147483648).xxx) & (rhs == (-1).xxx))) ? (1).xxx : rhs));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   const int a = 4;
   const int3 b = int3(1, 2, 3);
-  const int3 r = (a / (b == int3(0, 0, 0) ? int3(1, 1, 1) : b));
+  const int3 r = tint_div(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/div/scalar-vec3/i32.wgsl.expected.glsl b/test/tint/expressions/binary/div/scalar-vec3/i32.wgsl.expected.glsl
index 94f8b1f..324ae7b 100644
--- a/test/tint/expressions/binary/div/scalar-vec3/i32.wgsl.expected.glsl
+++ b/test/tint/expressions/binary/div/scalar-vec3/i32.wgsl.expected.glsl
@@ -1,9 +1,14 @@
 #version 310 es
 
+ivec3 tint_div(int lhs, ivec3 rhs) {
+  ivec3 l = ivec3(lhs);
+  return (l / mix(rhs, ivec3(1), bvec3(uvec3(equal(rhs, ivec3(0))) | uvec3(bvec3(uvec3(equal(l, ivec3(-2147483648))) & uvec3(equal(rhs, ivec3(-1))))))));
+}
+
 void f() {
   int a = 4;
   ivec3 b = ivec3(1, 2, 3);
-  ivec3 r = (a / b);
+  ivec3 r = tint_div(a, b);
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/expressions/binary/div/scalar-vec3/i32.wgsl.expected.msl b/test/tint/expressions/binary/div/scalar-vec3/i32.wgsl.expected.msl
index 4124223..0dd80df 100644
--- a/test/tint/expressions/binary/div/scalar-vec3/i32.wgsl.expected.msl
+++ b/test/tint/expressions/binary/div/scalar-vec3/i32.wgsl.expected.msl
@@ -1,10 +1,15 @@
 #include <metal_stdlib>
 
 using namespace metal;
+int3 tint_div(int lhs, int3 rhs) {
+  int3 const l = int3(lhs);
+  return (l / select(rhs, int3(1), ((rhs == int3(0)) | ((l == int3((-2147483647 - 1))) & (rhs == int3(-1))))));
+}
+
 kernel void f() {
   int const a = 4;
   int3 const b = int3(1, 2, 3);
-  int3 const r = (a / b);
+  int3 const r = tint_div(a, b);
   return;
 }
 
diff --git a/test/tint/expressions/binary/div/scalar-vec3/i32.wgsl.expected.spvasm b/test/tint/expressions/binary/div/scalar-vec3/i32.wgsl.expected.spvasm
index c52ce21..8bf9103 100644
--- a/test/tint/expressions/binary/div/scalar-vec3/i32.wgsl.expected.spvasm
+++ b/test/tint/expressions/binary/div/scalar-vec3/i32.wgsl.expected.spvasm
@@ -1,28 +1,50 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 17
+; Bound: 34
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %f "f"
                OpExecutionMode %f LocalSize 1 1 1
+               OpName %tint_div "tint_div"
+               OpName %lhs "lhs"
+               OpName %rhs "rhs"
                OpName %f "f"
-       %void = OpTypeVoid
-          %1 = OpTypeFunction %void
         %int = OpTypeInt 32 1
-      %int_4 = OpConstant %int 4
       %v3int = OpTypeVector %int 3
+          %1 = OpTypeFunction %v3int %int %v3int
+         %10 = OpConstantNull %v3int
+       %bool = OpTypeBool
+     %v3bool = OpTypeVector %bool 3
+%int_n2147483648 = OpConstant %int -2147483648
+         %15 = OpConstantComposite %v3int %int_n2147483648 %int_n2147483648 %int_n2147483648
+     %int_n1 = OpConstant %int -1
+         %18 = OpConstantComposite %v3int %int_n1 %int_n1 %int_n1
       %int_1 = OpConstant %int 1
+         %23 = OpConstantComposite %v3int %int_1 %int_1 %int_1
+       %void = OpTypeVoid
+         %25 = OpTypeFunction %void
+      %int_4 = OpConstant %int 4
       %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
+         %32 = OpConstantComposite %v3int %int_1 %int_2 %int_3
+   %tint_div = OpFunction %v3int None %1
+        %lhs = OpFunctionParameter %int
+        %rhs = OpFunctionParameter %v3int
+          %7 = OpLabel
+          %8 = OpCompositeConstruct %v3int %lhs %lhs %lhs
+         %11 = OpIEqual %v3bool %rhs %10
+         %16 = OpIEqual %v3bool %8 %15
+         %19 = OpIEqual %v3bool %rhs %18
+         %20 = OpLogicalAnd %v3bool %16 %19
+         %21 = OpLogicalOr %v3bool %11 %20
+          %9 = OpSelect %v3int %21 %23 %rhs
+         %24 = OpSDiv %v3int %8 %9
+               OpReturnValue %24
+               OpFunctionEnd
+          %f = OpFunction %void None %25
+         %28 = OpLabel
+         %33 = OpFunctionCall %v3int %tint_div %int_4 %32
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/expressions/binary/div/scalar-vec3/u32.wgsl.expected.dxc.hlsl b/test/tint/expressions/binary/div/scalar-vec3/u32.wgsl.expected.dxc.hlsl
index ac675e2..fc09d79 100644
--- a/test/tint/expressions/binary/div/scalar-vec3/u32.wgsl.expected.dxc.hlsl
+++ b/test/tint/expressions/binary/div/scalar-vec3/u32.wgsl.expected.dxc.hlsl
@@ -1,7 +1,12 @@
+uint3 tint_div(uint lhs, uint3 rhs) {
+  const uint3 l = uint3((lhs).xxx);
+  return (l / ((rhs == (0u).xxx) ? (1u).xxx : rhs));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   const uint a = 4u;
   const uint3 b = uint3(1u, 2u, 3u);
-  const uint3 r = (a / (b == uint3(0u, 0u, 0u) ? uint3(1u, 1u, 1u) : b));
+  const uint3 r = tint_div(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/div/scalar-vec3/u32.wgsl.expected.fxc.hlsl b/test/tint/expressions/binary/div/scalar-vec3/u32.wgsl.expected.fxc.hlsl
index ac675e2..fc09d79 100644
--- a/test/tint/expressions/binary/div/scalar-vec3/u32.wgsl.expected.fxc.hlsl
+++ b/test/tint/expressions/binary/div/scalar-vec3/u32.wgsl.expected.fxc.hlsl
@@ -1,7 +1,12 @@
+uint3 tint_div(uint lhs, uint3 rhs) {
+  const uint3 l = uint3((lhs).xxx);
+  return (l / ((rhs == (0u).xxx) ? (1u).xxx : rhs));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   const uint a = 4u;
   const uint3 b = uint3(1u, 2u, 3u);
-  const uint3 r = (a / (b == uint3(0u, 0u, 0u) ? uint3(1u, 1u, 1u) : b));
+  const uint3 r = tint_div(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/div/scalar-vec3/u32.wgsl.expected.glsl b/test/tint/expressions/binary/div/scalar-vec3/u32.wgsl.expected.glsl
index ff9ebbe..39dc7a7 100644
--- a/test/tint/expressions/binary/div/scalar-vec3/u32.wgsl.expected.glsl
+++ b/test/tint/expressions/binary/div/scalar-vec3/u32.wgsl.expected.glsl
@@ -1,9 +1,14 @@
 #version 310 es
 
+uvec3 tint_div(uint lhs, uvec3 rhs) {
+  uvec3 l = uvec3(lhs);
+  return (l / mix(rhs, uvec3(1u), equal(rhs, uvec3(0u))));
+}
+
 void f() {
   uint a = 4u;
   uvec3 b = uvec3(1u, 2u, 3u);
-  uvec3 r = (a / b);
+  uvec3 r = tint_div(a, b);
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/expressions/binary/div/scalar-vec3/u32.wgsl.expected.msl b/test/tint/expressions/binary/div/scalar-vec3/u32.wgsl.expected.msl
index aa59c35..6228ec2 100644
--- a/test/tint/expressions/binary/div/scalar-vec3/u32.wgsl.expected.msl
+++ b/test/tint/expressions/binary/div/scalar-vec3/u32.wgsl.expected.msl
@@ -1,10 +1,15 @@
 #include <metal_stdlib>
 
 using namespace metal;
+uint3 tint_div(uint lhs, uint3 rhs) {
+  uint3 const l = uint3(lhs);
+  return (l / select(rhs, uint3(1u), (rhs == uint3(0u))));
+}
+
 kernel void f() {
   uint const a = 4u;
   uint3 const b = uint3(1u, 2u, 3u);
-  uint3 const r = (a / b);
+  uint3 const r = tint_div(a, b);
   return;
 }
 
diff --git a/test/tint/expressions/binary/div/scalar-vec3/u32.wgsl.expected.spvasm b/test/tint/expressions/binary/div/scalar-vec3/u32.wgsl.expected.spvasm
index 3bf5436..29ec8ab 100644
--- a/test/tint/expressions/binary/div/scalar-vec3/u32.wgsl.expected.spvasm
+++ b/test/tint/expressions/binary/div/scalar-vec3/u32.wgsl.expected.spvasm
@@ -1,28 +1,42 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 17
+; Bound: 26
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %f "f"
                OpExecutionMode %f LocalSize 1 1 1
+               OpName %tint_div "tint_div"
+               OpName %lhs "lhs"
+               OpName %rhs "rhs"
                OpName %f "f"
-       %void = OpTypeVoid
-          %1 = OpTypeFunction %void
        %uint = OpTypeInt 32 0
-     %uint_4 = OpConstant %uint 4
      %v3uint = OpTypeVector %uint 3
+          %1 = OpTypeFunction %v3uint %uint %v3uint
+         %10 = OpConstantNull %v3uint
+       %bool = OpTypeBool
+     %v3bool = OpTypeVector %bool 3
      %uint_1 = OpConstant %uint 1
+         %15 = OpConstantComposite %v3uint %uint_1 %uint_1 %uint_1
+       %void = OpTypeVoid
+         %17 = OpTypeFunction %void
+     %uint_4 = OpConstant %uint 4
      %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
+         %24 = OpConstantComposite %v3uint %uint_1 %uint_2 %uint_3
+   %tint_div = OpFunction %v3uint None %1
+        %lhs = OpFunctionParameter %uint
+        %rhs = OpFunctionParameter %v3uint
+          %7 = OpLabel
+          %8 = OpCompositeConstruct %v3uint %lhs %lhs %lhs
+         %11 = OpIEqual %v3bool %rhs %10
+          %9 = OpSelect %v3uint %11 %15 %rhs
+         %16 = OpUDiv %v3uint %8 %9
+               OpReturnValue %16
+               OpFunctionEnd
+          %f = OpFunction %void None %17
+         %20 = OpLabel
+         %25 = OpFunctionCall %v3uint %tint_div %uint_4 %24
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/expressions/binary/div/vec3-scalar/i32.wgsl.expected.dxc.hlsl b/test/tint/expressions/binary/div/vec3-scalar/i32.wgsl.expected.dxc.hlsl
index 8278e3b..9c7f386 100644
--- a/test/tint/expressions/binary/div/vec3-scalar/i32.wgsl.expected.dxc.hlsl
+++ b/test/tint/expressions/binary/div/vec3-scalar/i32.wgsl.expected.dxc.hlsl
@@ -1,7 +1,12 @@
+int3 tint_div(int3 lhs, int rhs) {
+  const int3 r = int3((rhs).xxx);
+  return (lhs / (((r == (0).xxx) | ((lhs == (-2147483648).xxx) & (r == (-1).xxx))) ? (1).xxx : r));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   const int3 a = int3(1, 2, 3);
   const int b = 4;
-  const int3 r = (a / (b == 0 ? 1 : b));
+  const int3 r = tint_div(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/div/vec3-scalar/i32.wgsl.expected.fxc.hlsl b/test/tint/expressions/binary/div/vec3-scalar/i32.wgsl.expected.fxc.hlsl
index 8278e3b..9c7f386 100644
--- a/test/tint/expressions/binary/div/vec3-scalar/i32.wgsl.expected.fxc.hlsl
+++ b/test/tint/expressions/binary/div/vec3-scalar/i32.wgsl.expected.fxc.hlsl
@@ -1,7 +1,12 @@
+int3 tint_div(int3 lhs, int rhs) {
+  const int3 r = int3((rhs).xxx);
+  return (lhs / (((r == (0).xxx) | ((lhs == (-2147483648).xxx) & (r == (-1).xxx))) ? (1).xxx : r));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   const int3 a = int3(1, 2, 3);
   const int b = 4;
-  const int3 r = (a / (b == 0 ? 1 : b));
+  const int3 r = tint_div(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/div/vec3-scalar/i32.wgsl.expected.glsl b/test/tint/expressions/binary/div/vec3-scalar/i32.wgsl.expected.glsl
index a690f5f..1451a22 100644
--- a/test/tint/expressions/binary/div/vec3-scalar/i32.wgsl.expected.glsl
+++ b/test/tint/expressions/binary/div/vec3-scalar/i32.wgsl.expected.glsl
@@ -1,9 +1,14 @@
 #version 310 es
 
+ivec3 tint_div(ivec3 lhs, int rhs) {
+  ivec3 r = ivec3(rhs);
+  return (lhs / mix(r, ivec3(1), bvec3(uvec3(equal(r, ivec3(0))) | uvec3(bvec3(uvec3(equal(lhs, ivec3(-2147483648))) & uvec3(equal(r, ivec3(-1))))))));
+}
+
 void f() {
   ivec3 a = ivec3(1, 2, 3);
   int b = 4;
-  ivec3 r = (a / b);
+  ivec3 r = tint_div(a, b);
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/expressions/binary/div/vec3-scalar/i32.wgsl.expected.msl b/test/tint/expressions/binary/div/vec3-scalar/i32.wgsl.expected.msl
index 73678c8..30eaa91 100644
--- a/test/tint/expressions/binary/div/vec3-scalar/i32.wgsl.expected.msl
+++ b/test/tint/expressions/binary/div/vec3-scalar/i32.wgsl.expected.msl
@@ -1,10 +1,15 @@
 #include <metal_stdlib>
 
 using namespace metal;
+int3 tint_div(int3 lhs, int rhs) {
+  int3 const r = int3(rhs);
+  return (lhs / select(r, int3(1), ((r == int3(0)) | ((lhs == int3((-2147483647 - 1))) & (r == int3(-1))))));
+}
+
 kernel void f() {
   int3 const a = int3(1, 2, 3);
   int const b = 4;
-  int3 const r = (a / b);
+  int3 const r = tint_div(a, b);
   return;
 }
 
diff --git a/test/tint/expressions/binary/div/vec3-scalar/i32.wgsl.expected.spvasm b/test/tint/expressions/binary/div/vec3-scalar/i32.wgsl.expected.spvasm
index be6616a..7307e91 100644
--- a/test/tint/expressions/binary/div/vec3-scalar/i32.wgsl.expected.spvasm
+++ b/test/tint/expressions/binary/div/vec3-scalar/i32.wgsl.expected.spvasm
@@ -1,28 +1,50 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 17
+; Bound: 34
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %f "f"
                OpExecutionMode %f LocalSize 1 1 1
+               OpName %tint_div "tint_div"
+               OpName %lhs "lhs"
+               OpName %rhs "rhs"
                OpName %f "f"
-       %void = OpTypeVoid
-          %1 = OpTypeFunction %void
         %int = OpTypeInt 32 1
       %v3int = OpTypeVector %int 3
+          %1 = OpTypeFunction %v3int %v3int %int
+         %10 = OpConstantNull %v3int
+       %bool = OpTypeBool
+     %v3bool = OpTypeVector %bool 3
+%int_n2147483648 = OpConstant %int -2147483648
+         %15 = OpConstantComposite %v3int %int_n2147483648 %int_n2147483648 %int_n2147483648
+     %int_n1 = OpConstant %int -1
+         %18 = OpConstantComposite %v3int %int_n1 %int_n1 %int_n1
       %int_1 = OpConstant %int 1
+         %23 = OpConstantComposite %v3int %int_1 %int_1 %int_1
+       %void = OpTypeVoid
+         %25 = OpTypeFunction %void
       %int_2 = OpConstant %int 2
       %int_3 = OpConstant %int 3
-         %10 = OpConstantComposite %v3int %int_1 %int_2 %int_3
+         %31 = 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
+   %tint_div = OpFunction %v3int None %1
+        %lhs = OpFunctionParameter %v3int
+        %rhs = OpFunctionParameter %int
+          %7 = OpLabel
+          %8 = OpCompositeConstruct %v3int %rhs %rhs %rhs
+         %11 = OpIEqual %v3bool %8 %10
+         %16 = OpIEqual %v3bool %lhs %15
+         %19 = OpIEqual %v3bool %8 %18
+         %20 = OpLogicalAnd %v3bool %16 %19
+         %21 = OpLogicalOr %v3bool %11 %20
+          %9 = OpSelect %v3int %21 %23 %8
+         %24 = OpSDiv %v3int %lhs %9
+               OpReturnValue %24
+               OpFunctionEnd
+          %f = OpFunction %void None %25
+         %28 = OpLabel
+         %33 = OpFunctionCall %v3int %tint_div %31 %int_4
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/expressions/binary/div/vec3-scalar/u32.wgsl.expected.dxc.hlsl b/test/tint/expressions/binary/div/vec3-scalar/u32.wgsl.expected.dxc.hlsl
index 7c2f924..16a364b 100644
--- a/test/tint/expressions/binary/div/vec3-scalar/u32.wgsl.expected.dxc.hlsl
+++ b/test/tint/expressions/binary/div/vec3-scalar/u32.wgsl.expected.dxc.hlsl
@@ -1,7 +1,12 @@
+uint3 tint_div(uint3 lhs, uint rhs) {
+  const uint3 r = uint3((rhs).xxx);
+  return (lhs / ((r == (0u).xxx) ? (1u).xxx : r));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   const uint3 a = uint3(1u, 2u, 3u);
   const uint b = 4u;
-  const uint3 r = (a / (b == 0u ? 1u : b));
+  const uint3 r = tint_div(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/div/vec3-scalar/u32.wgsl.expected.fxc.hlsl b/test/tint/expressions/binary/div/vec3-scalar/u32.wgsl.expected.fxc.hlsl
index 7c2f924..16a364b 100644
--- a/test/tint/expressions/binary/div/vec3-scalar/u32.wgsl.expected.fxc.hlsl
+++ b/test/tint/expressions/binary/div/vec3-scalar/u32.wgsl.expected.fxc.hlsl
@@ -1,7 +1,12 @@
+uint3 tint_div(uint3 lhs, uint rhs) {
+  const uint3 r = uint3((rhs).xxx);
+  return (lhs / ((r == (0u).xxx) ? (1u).xxx : r));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   const uint3 a = uint3(1u, 2u, 3u);
   const uint b = 4u;
-  const uint3 r = (a / (b == 0u ? 1u : b));
+  const uint3 r = tint_div(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/div/vec3-scalar/u32.wgsl.expected.glsl b/test/tint/expressions/binary/div/vec3-scalar/u32.wgsl.expected.glsl
index abcbfa7..a648733 100644
--- a/test/tint/expressions/binary/div/vec3-scalar/u32.wgsl.expected.glsl
+++ b/test/tint/expressions/binary/div/vec3-scalar/u32.wgsl.expected.glsl
@@ -1,9 +1,14 @@
 #version 310 es
 
+uvec3 tint_div(uvec3 lhs, uint rhs) {
+  uvec3 r = uvec3(rhs);
+  return (lhs / mix(r, uvec3(1u), equal(r, uvec3(0u))));
+}
+
 void f() {
   uvec3 a = uvec3(1u, 2u, 3u);
   uint b = 4u;
-  uvec3 r = (a / b);
+  uvec3 r = tint_div(a, b);
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/expressions/binary/div/vec3-scalar/u32.wgsl.expected.msl b/test/tint/expressions/binary/div/vec3-scalar/u32.wgsl.expected.msl
index 749829b..c34665b 100644
--- a/test/tint/expressions/binary/div/vec3-scalar/u32.wgsl.expected.msl
+++ b/test/tint/expressions/binary/div/vec3-scalar/u32.wgsl.expected.msl
@@ -1,10 +1,15 @@
 #include <metal_stdlib>
 
 using namespace metal;
+uint3 tint_div(uint3 lhs, uint rhs) {
+  uint3 const r = uint3(rhs);
+  return (lhs / select(r, uint3(1u), (r == uint3(0u))));
+}
+
 kernel void f() {
   uint3 const a = uint3(1u, 2u, 3u);
   uint const b = 4u;
-  uint3 const r = (a / b);
+  uint3 const r = tint_div(a, b);
   return;
 }
 
diff --git a/test/tint/expressions/binary/div/vec3-scalar/u32.wgsl.expected.spvasm b/test/tint/expressions/binary/div/vec3-scalar/u32.wgsl.expected.spvasm
index 9a52fdc..b3e4924 100644
--- a/test/tint/expressions/binary/div/vec3-scalar/u32.wgsl.expected.spvasm
+++ b/test/tint/expressions/binary/div/vec3-scalar/u32.wgsl.expected.spvasm
@@ -1,28 +1,42 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 17
+; Bound: 26
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %f "f"
                OpExecutionMode %f LocalSize 1 1 1
+               OpName %tint_div "tint_div"
+               OpName %lhs "lhs"
+               OpName %rhs "rhs"
                OpName %f "f"
-       %void = OpTypeVoid
-          %1 = OpTypeFunction %void
        %uint = OpTypeInt 32 0
      %v3uint = OpTypeVector %uint 3
+          %1 = OpTypeFunction %v3uint %v3uint %uint
+         %10 = OpConstantNull %v3uint
+       %bool = OpTypeBool
+     %v3bool = OpTypeVector %bool 3
      %uint_1 = OpConstant %uint 1
+         %15 = OpConstantComposite %v3uint %uint_1 %uint_1 %uint_1
+       %void = OpTypeVoid
+         %17 = OpTypeFunction %void
      %uint_2 = OpConstant %uint 2
      %uint_3 = OpConstant %uint 3
-         %10 = OpConstantComposite %v3uint %uint_1 %uint_2 %uint_3
+         %23 = 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
+   %tint_div = OpFunction %v3uint None %1
+        %lhs = OpFunctionParameter %v3uint
+        %rhs = OpFunctionParameter %uint
+          %7 = OpLabel
+          %8 = OpCompositeConstruct %v3uint %rhs %rhs %rhs
+         %11 = OpIEqual %v3bool %8 %10
+          %9 = OpSelect %v3uint %11 %15 %8
+         %16 = OpUDiv %v3uint %lhs %9
+               OpReturnValue %16
+               OpFunctionEnd
+          %f = OpFunction %void None %17
+         %20 = OpLabel
+         %25 = OpFunctionCall %v3uint %tint_div %23 %uint_4
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/expressions/binary/div/vec3-vec3/i32.wgsl.expected.dxc.hlsl b/test/tint/expressions/binary/div/vec3-vec3/i32.wgsl.expected.dxc.hlsl
index 98c4e64..fe73055 100644
--- a/test/tint/expressions/binary/div/vec3-vec3/i32.wgsl.expected.dxc.hlsl
+++ b/test/tint/expressions/binary/div/vec3-vec3/i32.wgsl.expected.dxc.hlsl
@@ -1,7 +1,11 @@
+int3 tint_div(int3 lhs, int3 rhs) {
+  return (lhs / (((rhs == (0).xxx) | ((lhs == (-2147483648).xxx) & (rhs == (-1).xxx))) ? (1).xxx : rhs));
+}
+
 [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 == int3(0, 0, 0) ? int3(1, 1, 1) : b));
+  const int3 r = tint_div(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/div/vec3-vec3/i32.wgsl.expected.fxc.hlsl b/test/tint/expressions/binary/div/vec3-vec3/i32.wgsl.expected.fxc.hlsl
index 98c4e64..fe73055 100644
--- a/test/tint/expressions/binary/div/vec3-vec3/i32.wgsl.expected.fxc.hlsl
+++ b/test/tint/expressions/binary/div/vec3-vec3/i32.wgsl.expected.fxc.hlsl
@@ -1,7 +1,11 @@
+int3 tint_div(int3 lhs, int3 rhs) {
+  return (lhs / (((rhs == (0).xxx) | ((lhs == (-2147483648).xxx) & (rhs == (-1).xxx))) ? (1).xxx : rhs));
+}
+
 [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 == int3(0, 0, 0) ? int3(1, 1, 1) : b));
+  const int3 r = tint_div(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/div/vec3-vec3/i32.wgsl.expected.glsl b/test/tint/expressions/binary/div/vec3-vec3/i32.wgsl.expected.glsl
index 6d61168..db941fa 100644
--- a/test/tint/expressions/binary/div/vec3-vec3/i32.wgsl.expected.glsl
+++ b/test/tint/expressions/binary/div/vec3-vec3/i32.wgsl.expected.glsl
@@ -1,9 +1,13 @@
 #version 310 es
 
+ivec3 tint_div(ivec3 lhs, ivec3 rhs) {
+  return (lhs / mix(rhs, ivec3(1), bvec3(uvec3(equal(rhs, ivec3(0))) | uvec3(bvec3(uvec3(equal(lhs, ivec3(-2147483648))) & uvec3(equal(rhs, ivec3(-1))))))));
+}
+
 void f() {
   ivec3 a = ivec3(1, 2, 3);
   ivec3 b = ivec3(4, 5, 6);
-  ivec3 r = (a / b);
+  ivec3 r = tint_div(a, b);
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/expressions/binary/div/vec3-vec3/i32.wgsl.expected.msl b/test/tint/expressions/binary/div/vec3-vec3/i32.wgsl.expected.msl
index bb0f942..a2d1a2c 100644
--- a/test/tint/expressions/binary/div/vec3-vec3/i32.wgsl.expected.msl
+++ b/test/tint/expressions/binary/div/vec3-vec3/i32.wgsl.expected.msl
@@ -1,10 +1,14 @@
 #include <metal_stdlib>
 
 using namespace metal;
+int3 tint_div(int3 lhs, int3 rhs) {
+  return (lhs / select(rhs, int3(1), ((rhs == int3(0)) | ((lhs == int3((-2147483647 - 1))) & (rhs == int3(-1))))));
+}
+
 kernel void f() {
   int3 const a = int3(1, 2, 3);
   int3 const b = int3(4, 5, 6);
-  int3 const r = (a / b);
+  int3 const r = tint_div(a, b);
   return;
 }
 
diff --git a/test/tint/expressions/binary/div/vec3-vec3/i32.wgsl.expected.spvasm b/test/tint/expressions/binary/div/vec3-vec3/i32.wgsl.expected.spvasm
index f0115f7..ab422bc 100644
--- a/test/tint/expressions/binary/div/vec3-vec3/i32.wgsl.expected.spvasm
+++ b/test/tint/expressions/binary/div/vec3-vec3/i32.wgsl.expected.spvasm
@@ -1,27 +1,52 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 16
+; Bound: 36
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %f "f"
                OpExecutionMode %f LocalSize 1 1 1
+               OpName %tint_div "tint_div"
+               OpName %lhs "lhs"
+               OpName %rhs "rhs"
                OpName %f "f"
-       %void = OpTypeVoid
-          %1 = OpTypeFunction %void
         %int = OpTypeInt 32 1
       %v3int = OpTypeVector %int 3
+          %1 = OpTypeFunction %v3int %v3int %v3int
+          %9 = OpConstantNull %v3int
+       %bool = OpTypeBool
+     %v3bool = OpTypeVector %bool 3
+%int_n2147483648 = OpConstant %int -2147483648
+         %14 = OpConstantComposite %v3int %int_n2147483648 %int_n2147483648 %int_n2147483648
+     %int_n1 = OpConstant %int -1
+         %17 = OpConstantComposite %v3int %int_n1 %int_n1 %int_n1
       %int_1 = OpConstant %int 1
+         %22 = OpConstantComposite %v3int %int_1 %int_1 %int_1
+       %void = OpTypeVoid
+         %24 = OpTypeFunction %void
       %int_2 = OpConstant %int 2
       %int_3 = OpConstant %int 3
-         %10 = OpConstantComposite %v3int %int_1 %int_2 %int_3
+         %30 = 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
+         %34 = OpConstantComposite %v3int %int_4 %int_5 %int_6
+   %tint_div = OpFunction %v3int None %1
+        %lhs = OpFunctionParameter %v3int
+        %rhs = OpFunctionParameter %v3int
+          %7 = OpLabel
+         %10 = OpIEqual %v3bool %rhs %9
+         %15 = OpIEqual %v3bool %lhs %14
+         %18 = OpIEqual %v3bool %rhs %17
+         %19 = OpLogicalAnd %v3bool %15 %18
+         %20 = OpLogicalOr %v3bool %10 %19
+          %8 = OpSelect %v3int %20 %22 %rhs
+         %23 = OpSDiv %v3int %lhs %8
+               OpReturnValue %23
+               OpFunctionEnd
+          %f = OpFunction %void None %24
+         %27 = OpLabel
+         %35 = OpFunctionCall %v3int %tint_div %30 %34
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/expressions/binary/div/vec3-vec3/u32.wgsl.expected.dxc.hlsl b/test/tint/expressions/binary/div/vec3-vec3/u32.wgsl.expected.dxc.hlsl
index 2f2a501..7e4d88c 100644
--- a/test/tint/expressions/binary/div/vec3-vec3/u32.wgsl.expected.dxc.hlsl
+++ b/test/tint/expressions/binary/div/vec3-vec3/u32.wgsl.expected.dxc.hlsl
@@ -1,7 +1,11 @@
+uint3 tint_div(uint3 lhs, uint3 rhs) {
+  return (lhs / ((rhs == (0u).xxx) ? (1u).xxx : rhs));
+}
+
 [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 == uint3(0u, 0u, 0u) ? uint3(1u, 1u, 1u) : b));
+  const uint3 r = tint_div(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/div/vec3-vec3/u32.wgsl.expected.fxc.hlsl b/test/tint/expressions/binary/div/vec3-vec3/u32.wgsl.expected.fxc.hlsl
index 2f2a501..7e4d88c 100644
--- a/test/tint/expressions/binary/div/vec3-vec3/u32.wgsl.expected.fxc.hlsl
+++ b/test/tint/expressions/binary/div/vec3-vec3/u32.wgsl.expected.fxc.hlsl
@@ -1,7 +1,11 @@
+uint3 tint_div(uint3 lhs, uint3 rhs) {
+  return (lhs / ((rhs == (0u).xxx) ? (1u).xxx : rhs));
+}
+
 [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 == uint3(0u, 0u, 0u) ? uint3(1u, 1u, 1u) : b));
+  const uint3 r = tint_div(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/div/vec3-vec3/u32.wgsl.expected.glsl b/test/tint/expressions/binary/div/vec3-vec3/u32.wgsl.expected.glsl
index 75013bc..8320c3f 100644
--- a/test/tint/expressions/binary/div/vec3-vec3/u32.wgsl.expected.glsl
+++ b/test/tint/expressions/binary/div/vec3-vec3/u32.wgsl.expected.glsl
@@ -1,9 +1,13 @@
 #version 310 es
 
+uvec3 tint_div(uvec3 lhs, uvec3 rhs) {
+  return (lhs / mix(rhs, uvec3(1u), equal(rhs, uvec3(0u))));
+}
+
 void f() {
   uvec3 a = uvec3(1u, 2u, 3u);
   uvec3 b = uvec3(4u, 5u, 6u);
-  uvec3 r = (a / b);
+  uvec3 r = tint_div(a, b);
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/expressions/binary/div/vec3-vec3/u32.wgsl.expected.msl b/test/tint/expressions/binary/div/vec3-vec3/u32.wgsl.expected.msl
index bfddf5a..a79a7ab 100644
--- a/test/tint/expressions/binary/div/vec3-vec3/u32.wgsl.expected.msl
+++ b/test/tint/expressions/binary/div/vec3-vec3/u32.wgsl.expected.msl
@@ -1,10 +1,14 @@
 #include <metal_stdlib>
 
 using namespace metal;
+uint3 tint_div(uint3 lhs, uint3 rhs) {
+  return (lhs / select(rhs, uint3(1u), (rhs == uint3(0u))));
+}
+
 kernel void f() {
   uint3 const a = uint3(1u, 2u, 3u);
   uint3 const b = uint3(4u, 5u, 6u);
-  uint3 const r = (a / b);
+  uint3 const r = tint_div(a, b);
   return;
 }
 
diff --git a/test/tint/expressions/binary/div/vec3-vec3/u32.wgsl.expected.spvasm b/test/tint/expressions/binary/div/vec3-vec3/u32.wgsl.expected.spvasm
index 116085e..acb2bbf 100644
--- a/test/tint/expressions/binary/div/vec3-vec3/u32.wgsl.expected.spvasm
+++ b/test/tint/expressions/binary/div/vec3-vec3/u32.wgsl.expected.spvasm
@@ -1,27 +1,44 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 16
+; Bound: 28
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %f "f"
                OpExecutionMode %f LocalSize 1 1 1
+               OpName %tint_div "tint_div"
+               OpName %lhs "lhs"
+               OpName %rhs "rhs"
                OpName %f "f"
-       %void = OpTypeVoid
-          %1 = OpTypeFunction %void
        %uint = OpTypeInt 32 0
      %v3uint = OpTypeVector %uint 3
+          %1 = OpTypeFunction %v3uint %v3uint %v3uint
+          %9 = OpConstantNull %v3uint
+       %bool = OpTypeBool
+     %v3bool = OpTypeVector %bool 3
      %uint_1 = OpConstant %uint 1
+         %14 = OpConstantComposite %v3uint %uint_1 %uint_1 %uint_1
+       %void = OpTypeVoid
+         %16 = OpTypeFunction %void
      %uint_2 = OpConstant %uint 2
      %uint_3 = OpConstant %uint 3
-         %10 = OpConstantComposite %v3uint %uint_1 %uint_2 %uint_3
+         %22 = 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
+         %26 = OpConstantComposite %v3uint %uint_4 %uint_5 %uint_6
+   %tint_div = OpFunction %v3uint None %1
+        %lhs = OpFunctionParameter %v3uint
+        %rhs = OpFunctionParameter %v3uint
+          %7 = OpLabel
+         %10 = OpIEqual %v3bool %rhs %9
+          %8 = OpSelect %v3uint %10 %14 %rhs
+         %15 = OpUDiv %v3uint %lhs %8
+               OpReturnValue %15
+               OpFunctionEnd
+          %f = OpFunction %void None %16
+         %19 = OpLabel
+         %27 = OpFunctionCall %v3uint %tint_div %22 %26
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/expressions/binary/div_by_zero/by_constant/scalar-scalar/i32.wgsl.expected.dxc.hlsl b/test/tint/expressions/binary/div_by_zero/by_constant/scalar-scalar/i32.wgsl.expected.dxc.hlsl
index 1969e5f..57589da 100644
--- a/test/tint/expressions/binary/div_by_zero/by_constant/scalar-scalar/i32.wgsl.expected.dxc.hlsl
+++ b/test/tint/expressions/binary/div_by_zero/by_constant/scalar-scalar/i32.wgsl.expected.dxc.hlsl
@@ -1,7 +1,11 @@
+int tint_div(int lhs, int rhs) {
+  return (lhs / (((rhs == 0) | ((lhs == -2147483648) & (rhs == -1))) ? 1 : rhs));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   const int a = 1;
   const int b = 0;
-  const int r = (a / (b == 0 ? 1 : b));
+  const int r = tint_div(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/div_by_zero/by_constant/scalar-scalar/i32.wgsl.expected.fxc.hlsl b/test/tint/expressions/binary/div_by_zero/by_constant/scalar-scalar/i32.wgsl.expected.fxc.hlsl
index 1969e5f..57589da 100644
--- a/test/tint/expressions/binary/div_by_zero/by_constant/scalar-scalar/i32.wgsl.expected.fxc.hlsl
+++ b/test/tint/expressions/binary/div_by_zero/by_constant/scalar-scalar/i32.wgsl.expected.fxc.hlsl
@@ -1,7 +1,11 @@
+int tint_div(int lhs, int rhs) {
+  return (lhs / (((rhs == 0) | ((lhs == -2147483648) & (rhs == -1))) ? 1 : rhs));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   const int a = 1;
   const int b = 0;
-  const int r = (a / (b == 0 ? 1 : b));
+  const int r = tint_div(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/div_by_zero/by_constant/scalar-scalar/i32.wgsl.expected.glsl b/test/tint/expressions/binary/div_by_zero/by_constant/scalar-scalar/i32.wgsl.expected.glsl
index 8ec81fd..5cdd988 100644
--- a/test/tint/expressions/binary/div_by_zero/by_constant/scalar-scalar/i32.wgsl.expected.glsl
+++ b/test/tint/expressions/binary/div_by_zero/by_constant/scalar-scalar/i32.wgsl.expected.glsl
@@ -1,9 +1,13 @@
 #version 310 es
 
+int tint_div(int lhs, int rhs) {
+  return (lhs / (bool(uint((rhs == 0)) | uint(bool(uint((lhs == -2147483648)) & uint((rhs == -1))))) ? 1 : rhs));
+}
+
 void f() {
   int a = 1;
   int b = 0;
-  int r = (a / b);
+  int r = tint_div(a, b);
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/expressions/binary/div_by_zero/by_constant/scalar-scalar/i32.wgsl.expected.msl b/test/tint/expressions/binary/div_by_zero/by_constant/scalar-scalar/i32.wgsl.expected.msl
index 0923684..092d9a9 100644
--- a/test/tint/expressions/binary/div_by_zero/by_constant/scalar-scalar/i32.wgsl.expected.msl
+++ b/test/tint/expressions/binary/div_by_zero/by_constant/scalar-scalar/i32.wgsl.expected.msl
@@ -1,10 +1,14 @@
 #include <metal_stdlib>
 
 using namespace metal;
+int tint_div(int lhs, int rhs) {
+  return (lhs / select(rhs, 1, bool((rhs == 0) | bool((lhs == (-2147483647 - 1)) & (rhs == -1)))));
+}
+
 kernel void f() {
   int const a = 1;
   int const b = 0;
-  int const r = (a / b);
+  int const r = tint_div(a, b);
   return;
 }
 
diff --git a/test/tint/expressions/binary/div_by_zero/by_constant/scalar-scalar/i32.wgsl.expected.spvasm b/test/tint/expressions/binary/div_by_zero/by_constant/scalar-scalar/i32.wgsl.expected.spvasm
index fa188bd..162cf50 100644
--- a/test/tint/expressions/binary/div_by_zero/by_constant/scalar-scalar/i32.wgsl.expected.spvasm
+++ b/test/tint/expressions/binary/div_by_zero/by_constant/scalar-scalar/i32.wgsl.expected.spvasm
@@ -1,20 +1,40 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 9
+; Bound: 24
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %f "f"
                OpExecutionMode %f LocalSize 1 1 1
+               OpName %tint_div "tint_div"
+               OpName %lhs "lhs"
+               OpName %rhs "rhs"
                OpName %f "f"
-       %void = OpTypeVoid
-          %1 = OpTypeFunction %void
         %int = OpTypeInt 32 1
+          %1 = OpTypeFunction %int %int %int
+          %8 = OpConstantNull %int
+       %bool = OpTypeBool
+%int_n2147483648 = OpConstant %int -2147483648
+     %int_n1 = OpConstant %int -1
       %int_1 = OpConstant %int 1
-          %7 = OpConstantNull %int
-          %f = OpFunction %void None %1
-          %4 = OpLabel
-          %8 = OpSDiv %int %int_1 %7
+       %void = OpTypeVoid
+         %19 = OpTypeFunction %void
+   %tint_div = OpFunction %int None %1
+        %lhs = OpFunctionParameter %int
+        %rhs = OpFunctionParameter %int
+          %6 = OpLabel
+          %9 = OpIEqual %bool %rhs %8
+         %12 = OpIEqual %bool %lhs %int_n2147483648
+         %14 = OpIEqual %bool %rhs %int_n1
+         %15 = OpLogicalAnd %bool %12 %14
+         %16 = OpLogicalOr %bool %9 %15
+          %7 = OpSelect %int %16 %int_1 %rhs
+         %18 = OpSDiv %int %lhs %7
+               OpReturnValue %18
+               OpFunctionEnd
+          %f = OpFunction %void None %19
+         %22 = OpLabel
+         %23 = OpFunctionCall %int %tint_div %int_1 %8
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/expressions/binary/div_by_zero/by_constant/scalar-scalar/u32.wgsl.expected.dxc.hlsl b/test/tint/expressions/binary/div_by_zero/by_constant/scalar-scalar/u32.wgsl.expected.dxc.hlsl
index ce15f24..92efb50 100644
--- a/test/tint/expressions/binary/div_by_zero/by_constant/scalar-scalar/u32.wgsl.expected.dxc.hlsl
+++ b/test/tint/expressions/binary/div_by_zero/by_constant/scalar-scalar/u32.wgsl.expected.dxc.hlsl
@@ -1,7 +1,11 @@
+uint tint_div(uint lhs, uint rhs) {
+  return (lhs / ((rhs == 0u) ? 1u : rhs));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   const uint a = 1u;
   const uint b = 0u;
-  const uint r = (a / (b == 0u ? 1u : b));
+  const uint r = tint_div(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/div_by_zero/by_constant/scalar-scalar/u32.wgsl.expected.fxc.hlsl b/test/tint/expressions/binary/div_by_zero/by_constant/scalar-scalar/u32.wgsl.expected.fxc.hlsl
index ce15f24..92efb50 100644
--- a/test/tint/expressions/binary/div_by_zero/by_constant/scalar-scalar/u32.wgsl.expected.fxc.hlsl
+++ b/test/tint/expressions/binary/div_by_zero/by_constant/scalar-scalar/u32.wgsl.expected.fxc.hlsl
@@ -1,7 +1,11 @@
+uint tint_div(uint lhs, uint rhs) {
+  return (lhs / ((rhs == 0u) ? 1u : rhs));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   const uint a = 1u;
   const uint b = 0u;
-  const uint r = (a / (b == 0u ? 1u : b));
+  const uint r = tint_div(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/div_by_zero/by_constant/scalar-scalar/u32.wgsl.expected.glsl b/test/tint/expressions/binary/div_by_zero/by_constant/scalar-scalar/u32.wgsl.expected.glsl
index aee0413..30a1f0c 100644
--- a/test/tint/expressions/binary/div_by_zero/by_constant/scalar-scalar/u32.wgsl.expected.glsl
+++ b/test/tint/expressions/binary/div_by_zero/by_constant/scalar-scalar/u32.wgsl.expected.glsl
@@ -1,9 +1,13 @@
 #version 310 es
 
+uint tint_div(uint lhs, uint rhs) {
+  return (lhs / ((rhs == 0u) ? 1u : rhs));
+}
+
 void f() {
   uint a = 1u;
   uint b = 0u;
-  uint r = (a / b);
+  uint r = tint_div(a, b);
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/expressions/binary/div_by_zero/by_constant/scalar-scalar/u32.wgsl.expected.msl b/test/tint/expressions/binary/div_by_zero/by_constant/scalar-scalar/u32.wgsl.expected.msl
index 2c1b78a..5247453 100644
--- a/test/tint/expressions/binary/div_by_zero/by_constant/scalar-scalar/u32.wgsl.expected.msl
+++ b/test/tint/expressions/binary/div_by_zero/by_constant/scalar-scalar/u32.wgsl.expected.msl
@@ -1,10 +1,14 @@
 #include <metal_stdlib>
 
 using namespace metal;
+uint tint_div(uint lhs, uint rhs) {
+  return (lhs / select(rhs, 1u, (rhs == 0u)));
+}
+
 kernel void f() {
   uint const a = 1u;
   uint const b = 0u;
-  uint const r = (a / b);
+  uint const r = tint_div(a, b);
   return;
 }
 
diff --git a/test/tint/expressions/binary/div_by_zero/by_constant/scalar-scalar/u32.wgsl.expected.spvasm b/test/tint/expressions/binary/div_by_zero/by_constant/scalar-scalar/u32.wgsl.expected.spvasm
index 57df980..af0914e 100644
--- a/test/tint/expressions/binary/div_by_zero/by_constant/scalar-scalar/u32.wgsl.expected.spvasm
+++ b/test/tint/expressions/binary/div_by_zero/by_constant/scalar-scalar/u32.wgsl.expected.spvasm
@@ -1,20 +1,34 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 9
+; Bound: 18
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %f "f"
                OpExecutionMode %f LocalSize 1 1 1
+               OpName %tint_div "tint_div"
+               OpName %lhs "lhs"
+               OpName %rhs "rhs"
                OpName %f "f"
-       %void = OpTypeVoid
-          %1 = OpTypeFunction %void
        %uint = OpTypeInt 32 0
+          %1 = OpTypeFunction %uint %uint %uint
+          %8 = OpConstantNull %uint
+       %bool = OpTypeBool
      %uint_1 = OpConstant %uint 1
-          %7 = OpConstantNull %uint
-          %f = OpFunction %void None %1
-          %4 = OpLabel
-          %8 = OpUDiv %uint %uint_1 %7
+       %void = OpTypeVoid
+         %13 = OpTypeFunction %void
+   %tint_div = OpFunction %uint None %1
+        %lhs = OpFunctionParameter %uint
+        %rhs = OpFunctionParameter %uint
+          %6 = OpLabel
+          %9 = OpIEqual %bool %rhs %8
+          %7 = OpSelect %uint %9 %uint_1 %rhs
+         %12 = OpUDiv %uint %lhs %7
+               OpReturnValue %12
+               OpFunctionEnd
+          %f = OpFunction %void None %13
+         %16 = OpLabel
+         %17 = OpFunctionCall %uint %tint_div %uint_1 %8
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/expressions/binary/div_by_zero/by_constant/scalar-vec3/i32.wgsl.expected.dxc.hlsl b/test/tint/expressions/binary/div_by_zero/by_constant/scalar-vec3/i32.wgsl.expected.dxc.hlsl
index 99ed924..69aec32 100644
--- a/test/tint/expressions/binary/div_by_zero/by_constant/scalar-vec3/i32.wgsl.expected.dxc.hlsl
+++ b/test/tint/expressions/binary/div_by_zero/by_constant/scalar-vec3/i32.wgsl.expected.dxc.hlsl
@@ -1,7 +1,12 @@
+int3 tint_div(int lhs, int3 rhs) {
+  const int3 l = int3((lhs).xxx);
+  return (l / (((rhs == (0).xxx) | ((l == (-2147483648).xxx) & (rhs == (-1).xxx))) ? (1).xxx : rhs));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   const int a = 4;
   const int3 b = int3(0, 2, 0);
-  const int3 r = (a / (b == int3(0, 0, 0) ? int3(1, 1, 1) : b));
+  const int3 r = tint_div(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/div_by_zero/by_constant/scalar-vec3/i32.wgsl.expected.fxc.hlsl b/test/tint/expressions/binary/div_by_zero/by_constant/scalar-vec3/i32.wgsl.expected.fxc.hlsl
index 99ed924..69aec32 100644
--- a/test/tint/expressions/binary/div_by_zero/by_constant/scalar-vec3/i32.wgsl.expected.fxc.hlsl
+++ b/test/tint/expressions/binary/div_by_zero/by_constant/scalar-vec3/i32.wgsl.expected.fxc.hlsl
@@ -1,7 +1,12 @@
+int3 tint_div(int lhs, int3 rhs) {
+  const int3 l = int3((lhs).xxx);
+  return (l / (((rhs == (0).xxx) | ((l == (-2147483648).xxx) & (rhs == (-1).xxx))) ? (1).xxx : rhs));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   const int a = 4;
   const int3 b = int3(0, 2, 0);
-  const int3 r = (a / (b == int3(0, 0, 0) ? int3(1, 1, 1) : b));
+  const int3 r = tint_div(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/div_by_zero/by_constant/scalar-vec3/i32.wgsl.expected.glsl b/test/tint/expressions/binary/div_by_zero/by_constant/scalar-vec3/i32.wgsl.expected.glsl
index 2fdf8fe..a33eaa7 100644
--- a/test/tint/expressions/binary/div_by_zero/by_constant/scalar-vec3/i32.wgsl.expected.glsl
+++ b/test/tint/expressions/binary/div_by_zero/by_constant/scalar-vec3/i32.wgsl.expected.glsl
@@ -1,9 +1,14 @@
 #version 310 es
 
+ivec3 tint_div(int lhs, ivec3 rhs) {
+  ivec3 l = ivec3(lhs);
+  return (l / mix(rhs, ivec3(1), bvec3(uvec3(equal(rhs, ivec3(0))) | uvec3(bvec3(uvec3(equal(l, ivec3(-2147483648))) & uvec3(equal(rhs, ivec3(-1))))))));
+}
+
 void f() {
   int a = 4;
   ivec3 b = ivec3(0, 2, 0);
-  ivec3 r = (a / b);
+  ivec3 r = tint_div(a, b);
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/expressions/binary/div_by_zero/by_constant/scalar-vec3/i32.wgsl.expected.msl b/test/tint/expressions/binary/div_by_zero/by_constant/scalar-vec3/i32.wgsl.expected.msl
index 89df256..bf13240 100644
--- a/test/tint/expressions/binary/div_by_zero/by_constant/scalar-vec3/i32.wgsl.expected.msl
+++ b/test/tint/expressions/binary/div_by_zero/by_constant/scalar-vec3/i32.wgsl.expected.msl
@@ -1,10 +1,15 @@
 #include <metal_stdlib>
 
 using namespace metal;
+int3 tint_div(int lhs, int3 rhs) {
+  int3 const l = int3(lhs);
+  return (l / select(rhs, int3(1), ((rhs == int3(0)) | ((l == int3((-2147483647 - 1))) & (rhs == int3(-1))))));
+}
+
 kernel void f() {
   int const a = 4;
   int3 const b = int3(0, 2, 0);
-  int3 const r = (a / b);
+  int3 const r = tint_div(a, b);
   return;
 }
 
diff --git a/test/tint/expressions/binary/div_by_zero/by_constant/scalar-vec3/i32.wgsl.expected.spvasm b/test/tint/expressions/binary/div_by_zero/by_constant/scalar-vec3/i32.wgsl.expected.spvasm
index 7cfcbad..8b76fe0 100644
--- a/test/tint/expressions/binary/div_by_zero/by_constant/scalar-vec3/i32.wgsl.expected.spvasm
+++ b/test/tint/expressions/binary/div_by_zero/by_constant/scalar-vec3/i32.wgsl.expected.spvasm
@@ -1,27 +1,50 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 16
+; Bound: 34
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %f "f"
                OpExecutionMode %f LocalSize 1 1 1
+               OpName %tint_div "tint_div"
+               OpName %lhs "lhs"
+               OpName %rhs "rhs"
                OpName %f "f"
-       %void = OpTypeVoid
-          %1 = OpTypeFunction %void
         %int = OpTypeInt 32 1
-      %int_4 = OpConstant %int 4
       %v3int = OpTypeVector %int 3
-          %8 = OpConstantNull %int
+          %1 = OpTypeFunction %v3int %int %v3int
+         %10 = OpConstantNull %v3int
+       %bool = OpTypeBool
+     %v3bool = OpTypeVector %bool 3
+%int_n2147483648 = OpConstant %int -2147483648
+         %15 = OpConstantComposite %v3int %int_n2147483648 %int_n2147483648 %int_n2147483648
+     %int_n1 = OpConstant %int -1
+         %18 = OpConstantComposite %v3int %int_n1 %int_n1 %int_n1
+      %int_1 = OpConstant %int 1
+         %23 = OpConstantComposite %v3int %int_1 %int_1 %int_1
+       %void = OpTypeVoid
+         %25 = OpTypeFunction %void
+      %int_4 = OpConstant %int 4
+         %30 = OpConstantNull %int
       %int_2 = OpConstant %int 2
-         %10 = OpConstantComposite %v3int %8 %int_2 %8
-%_ptr_Function_v3int = OpTypePointer Function %v3int
-         %14 = OpConstantNull %v3int
-          %f = OpFunction %void None %1
-          %4 = OpLabel
-         %12 = OpVariable %_ptr_Function_v3int Function %14
-         %15 = OpCompositeConstruct %v3int %int_4 %int_4 %int_4
-         %11 = OpSDiv %v3int %15 %10
+         %32 = OpConstantComposite %v3int %30 %int_2 %30
+   %tint_div = OpFunction %v3int None %1
+        %lhs = OpFunctionParameter %int
+        %rhs = OpFunctionParameter %v3int
+          %7 = OpLabel
+          %8 = OpCompositeConstruct %v3int %lhs %lhs %lhs
+         %11 = OpIEqual %v3bool %rhs %10
+         %16 = OpIEqual %v3bool %8 %15
+         %19 = OpIEqual %v3bool %rhs %18
+         %20 = OpLogicalAnd %v3bool %16 %19
+         %21 = OpLogicalOr %v3bool %11 %20
+          %9 = OpSelect %v3int %21 %23 %rhs
+         %24 = OpSDiv %v3int %8 %9
+               OpReturnValue %24
+               OpFunctionEnd
+          %f = OpFunction %void None %25
+         %28 = OpLabel
+         %33 = OpFunctionCall %v3int %tint_div %int_4 %32
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/expressions/binary/div_by_zero/by_constant/scalar-vec3/u32.wgsl.expected.dxc.hlsl b/test/tint/expressions/binary/div_by_zero/by_constant/scalar-vec3/u32.wgsl.expected.dxc.hlsl
index 1ebcc7f..e4319c1 100644
--- a/test/tint/expressions/binary/div_by_zero/by_constant/scalar-vec3/u32.wgsl.expected.dxc.hlsl
+++ b/test/tint/expressions/binary/div_by_zero/by_constant/scalar-vec3/u32.wgsl.expected.dxc.hlsl
@@ -1,7 +1,12 @@
+uint3 tint_div(uint lhs, uint3 rhs) {
+  const uint3 l = uint3((lhs).xxx);
+  return (l / ((rhs == (0u).xxx) ? (1u).xxx : rhs));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   const uint a = 4u;
   const uint3 b = uint3(0u, 2u, 0u);
-  const uint3 r = (a / (b == uint3(0u, 0u, 0u) ? uint3(1u, 1u, 1u) : b));
+  const uint3 r = tint_div(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/div_by_zero/by_constant/scalar-vec3/u32.wgsl.expected.fxc.hlsl b/test/tint/expressions/binary/div_by_zero/by_constant/scalar-vec3/u32.wgsl.expected.fxc.hlsl
index 1ebcc7f..e4319c1 100644
--- a/test/tint/expressions/binary/div_by_zero/by_constant/scalar-vec3/u32.wgsl.expected.fxc.hlsl
+++ b/test/tint/expressions/binary/div_by_zero/by_constant/scalar-vec3/u32.wgsl.expected.fxc.hlsl
@@ -1,7 +1,12 @@
+uint3 tint_div(uint lhs, uint3 rhs) {
+  const uint3 l = uint3((lhs).xxx);
+  return (l / ((rhs == (0u).xxx) ? (1u).xxx : rhs));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   const uint a = 4u;
   const uint3 b = uint3(0u, 2u, 0u);
-  const uint3 r = (a / (b == uint3(0u, 0u, 0u) ? uint3(1u, 1u, 1u) : b));
+  const uint3 r = tint_div(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/div_by_zero/by_constant/scalar-vec3/u32.wgsl.expected.glsl b/test/tint/expressions/binary/div_by_zero/by_constant/scalar-vec3/u32.wgsl.expected.glsl
index 6d14d8f..50ab5b3 100644
--- a/test/tint/expressions/binary/div_by_zero/by_constant/scalar-vec3/u32.wgsl.expected.glsl
+++ b/test/tint/expressions/binary/div_by_zero/by_constant/scalar-vec3/u32.wgsl.expected.glsl
@@ -1,9 +1,14 @@
 #version 310 es
 
+uvec3 tint_div(uint lhs, uvec3 rhs) {
+  uvec3 l = uvec3(lhs);
+  return (l / mix(rhs, uvec3(1u), equal(rhs, uvec3(0u))));
+}
+
 void f() {
   uint a = 4u;
   uvec3 b = uvec3(0u, 2u, 0u);
-  uvec3 r = (a / b);
+  uvec3 r = tint_div(a, b);
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/expressions/binary/div_by_zero/by_constant/scalar-vec3/u32.wgsl.expected.msl b/test/tint/expressions/binary/div_by_zero/by_constant/scalar-vec3/u32.wgsl.expected.msl
index eb1c975..248755d 100644
--- a/test/tint/expressions/binary/div_by_zero/by_constant/scalar-vec3/u32.wgsl.expected.msl
+++ b/test/tint/expressions/binary/div_by_zero/by_constant/scalar-vec3/u32.wgsl.expected.msl
@@ -1,10 +1,15 @@
 #include <metal_stdlib>
 
 using namespace metal;
+uint3 tint_div(uint lhs, uint3 rhs) {
+  uint3 const l = uint3(lhs);
+  return (l / select(rhs, uint3(1u), (rhs == uint3(0u))));
+}
+
 kernel void f() {
   uint const a = 4u;
   uint3 const b = uint3(0u, 2u, 0u);
-  uint3 const r = (a / b);
+  uint3 const r = tint_div(a, b);
   return;
 }
 
diff --git a/test/tint/expressions/binary/div_by_zero/by_constant/scalar-vec3/u32.wgsl.expected.spvasm b/test/tint/expressions/binary/div_by_zero/by_constant/scalar-vec3/u32.wgsl.expected.spvasm
index 81b4416..b0ce71b 100644
--- a/test/tint/expressions/binary/div_by_zero/by_constant/scalar-vec3/u32.wgsl.expected.spvasm
+++ b/test/tint/expressions/binary/div_by_zero/by_constant/scalar-vec3/u32.wgsl.expected.spvasm
@@ -1,27 +1,42 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 16
+; Bound: 26
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %f "f"
                OpExecutionMode %f LocalSize 1 1 1
+               OpName %tint_div "tint_div"
+               OpName %lhs "lhs"
+               OpName %rhs "rhs"
                OpName %f "f"
-       %void = OpTypeVoid
-          %1 = OpTypeFunction %void
        %uint = OpTypeInt 32 0
-     %uint_4 = OpConstant %uint 4
      %v3uint = OpTypeVector %uint 3
-          %8 = OpConstantNull %uint
+          %1 = OpTypeFunction %v3uint %uint %v3uint
+         %10 = OpConstantNull %v3uint
+       %bool = OpTypeBool
+     %v3bool = OpTypeVector %bool 3
+     %uint_1 = OpConstant %uint 1
+         %15 = OpConstantComposite %v3uint %uint_1 %uint_1 %uint_1
+       %void = OpTypeVoid
+         %17 = OpTypeFunction %void
+     %uint_4 = OpConstant %uint 4
+         %22 = OpConstantNull %uint
      %uint_2 = OpConstant %uint 2
-         %10 = OpConstantComposite %v3uint %8 %uint_2 %8
-%_ptr_Function_v3uint = OpTypePointer Function %v3uint
-         %14 = OpConstantNull %v3uint
-          %f = OpFunction %void None %1
-          %4 = OpLabel
-         %12 = OpVariable %_ptr_Function_v3uint Function %14
-         %15 = OpCompositeConstruct %v3uint %uint_4 %uint_4 %uint_4
-         %11 = OpUDiv %v3uint %15 %10
+         %24 = OpConstantComposite %v3uint %22 %uint_2 %22
+   %tint_div = OpFunction %v3uint None %1
+        %lhs = OpFunctionParameter %uint
+        %rhs = OpFunctionParameter %v3uint
+          %7 = OpLabel
+          %8 = OpCompositeConstruct %v3uint %lhs %lhs %lhs
+         %11 = OpIEqual %v3bool %rhs %10
+          %9 = OpSelect %v3uint %11 %15 %rhs
+         %16 = OpUDiv %v3uint %8 %9
+               OpReturnValue %16
+               OpFunctionEnd
+          %f = OpFunction %void None %17
+         %20 = OpLabel
+         %25 = OpFunctionCall %v3uint %tint_div %uint_4 %24
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/expressions/binary/div_by_zero/by_constant/vec3-scalar/i32.wgsl.expected.dxc.hlsl b/test/tint/expressions/binary/div_by_zero/by_constant/vec3-scalar/i32.wgsl.expected.dxc.hlsl
index 7029295..e24fb82 100644
--- a/test/tint/expressions/binary/div_by_zero/by_constant/vec3-scalar/i32.wgsl.expected.dxc.hlsl
+++ b/test/tint/expressions/binary/div_by_zero/by_constant/vec3-scalar/i32.wgsl.expected.dxc.hlsl
@@ -1,7 +1,12 @@
+int3 tint_div(int3 lhs, int rhs) {
+  const int3 r = int3((rhs).xxx);
+  return (lhs / (((r == (0).xxx) | ((lhs == (-2147483648).xxx) & (r == (-1).xxx))) ? (1).xxx : r));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   const int3 a = int3(1, 2, 3);
   const int b = 0;
-  const int3 r = (a / (b == 0 ? 1 : b));
+  const int3 r = tint_div(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/div_by_zero/by_constant/vec3-scalar/i32.wgsl.expected.fxc.hlsl b/test/tint/expressions/binary/div_by_zero/by_constant/vec3-scalar/i32.wgsl.expected.fxc.hlsl
index 7029295..e24fb82 100644
--- a/test/tint/expressions/binary/div_by_zero/by_constant/vec3-scalar/i32.wgsl.expected.fxc.hlsl
+++ b/test/tint/expressions/binary/div_by_zero/by_constant/vec3-scalar/i32.wgsl.expected.fxc.hlsl
@@ -1,7 +1,12 @@
+int3 tint_div(int3 lhs, int rhs) {
+  const int3 r = int3((rhs).xxx);
+  return (lhs / (((r == (0).xxx) | ((lhs == (-2147483648).xxx) & (r == (-1).xxx))) ? (1).xxx : r));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   const int3 a = int3(1, 2, 3);
   const int b = 0;
-  const int3 r = (a / (b == 0 ? 1 : b));
+  const int3 r = tint_div(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/div_by_zero/by_constant/vec3-scalar/i32.wgsl.expected.glsl b/test/tint/expressions/binary/div_by_zero/by_constant/vec3-scalar/i32.wgsl.expected.glsl
index 0c7f6a9..28ba692 100644
--- a/test/tint/expressions/binary/div_by_zero/by_constant/vec3-scalar/i32.wgsl.expected.glsl
+++ b/test/tint/expressions/binary/div_by_zero/by_constant/vec3-scalar/i32.wgsl.expected.glsl
@@ -1,9 +1,14 @@
 #version 310 es
 
+ivec3 tint_div(ivec3 lhs, int rhs) {
+  ivec3 r = ivec3(rhs);
+  return (lhs / mix(r, ivec3(1), bvec3(uvec3(equal(r, ivec3(0))) | uvec3(bvec3(uvec3(equal(lhs, ivec3(-2147483648))) & uvec3(equal(r, ivec3(-1))))))));
+}
+
 void f() {
   ivec3 a = ivec3(1, 2, 3);
   int b = 0;
-  ivec3 r = (a / b);
+  ivec3 r = tint_div(a, b);
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/expressions/binary/div_by_zero/by_constant/vec3-scalar/i32.wgsl.expected.msl b/test/tint/expressions/binary/div_by_zero/by_constant/vec3-scalar/i32.wgsl.expected.msl
index c187dd2..82f039b 100644
--- a/test/tint/expressions/binary/div_by_zero/by_constant/vec3-scalar/i32.wgsl.expected.msl
+++ b/test/tint/expressions/binary/div_by_zero/by_constant/vec3-scalar/i32.wgsl.expected.msl
@@ -1,10 +1,15 @@
 #include <metal_stdlib>
 
 using namespace metal;
+int3 tint_div(int3 lhs, int rhs) {
+  int3 const r = int3(rhs);
+  return (lhs / select(r, int3(1), ((r == int3(0)) | ((lhs == int3((-2147483647 - 1))) & (r == int3(-1))))));
+}
+
 kernel void f() {
   int3 const a = int3(1, 2, 3);
   int const b = 0;
-  int3 const r = (a / b);
+  int3 const r = tint_div(a, b);
   return;
 }
 
diff --git a/test/tint/expressions/binary/div_by_zero/by_constant/vec3-scalar/i32.wgsl.expected.spvasm b/test/tint/expressions/binary/div_by_zero/by_constant/vec3-scalar/i32.wgsl.expected.spvasm
index af40beb..c78b7c4 100644
--- a/test/tint/expressions/binary/div_by_zero/by_constant/vec3-scalar/i32.wgsl.expected.spvasm
+++ b/test/tint/expressions/binary/div_by_zero/by_constant/vec3-scalar/i32.wgsl.expected.spvasm
@@ -1,28 +1,50 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 17
+; Bound: 34
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %f "f"
                OpExecutionMode %f LocalSize 1 1 1
+               OpName %tint_div "tint_div"
+               OpName %lhs "lhs"
+               OpName %rhs "rhs"
                OpName %f "f"
-       %void = OpTypeVoid
-          %1 = OpTypeFunction %void
         %int = OpTypeInt 32 1
       %v3int = OpTypeVector %int 3
+          %1 = OpTypeFunction %v3int %v3int %int
+         %10 = OpConstantNull %v3int
+       %bool = OpTypeBool
+     %v3bool = OpTypeVector %bool 3
+%int_n2147483648 = OpConstant %int -2147483648
+         %15 = OpConstantComposite %v3int %int_n2147483648 %int_n2147483648 %int_n2147483648
+     %int_n1 = OpConstant %int -1
+         %18 = OpConstantComposite %v3int %int_n1 %int_n1 %int_n1
       %int_1 = OpConstant %int 1
+         %23 = OpConstantComposite %v3int %int_1 %int_1 %int_1
+       %void = OpTypeVoid
+         %25 = OpTypeFunction %void
       %int_2 = OpConstant %int 2
       %int_3 = OpConstant %int 3
-         %10 = OpConstantComposite %v3int %int_1 %int_2 %int_3
-         %11 = OpConstantNull %int
-%_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 %11 %11 %11
-         %12 = OpSDiv %v3int %10 %16
+         %31 = OpConstantComposite %v3int %int_1 %int_2 %int_3
+         %32 = OpConstantNull %int
+   %tint_div = OpFunction %v3int None %1
+        %lhs = OpFunctionParameter %v3int
+        %rhs = OpFunctionParameter %int
+          %7 = OpLabel
+          %8 = OpCompositeConstruct %v3int %rhs %rhs %rhs
+         %11 = OpIEqual %v3bool %8 %10
+         %16 = OpIEqual %v3bool %lhs %15
+         %19 = OpIEqual %v3bool %8 %18
+         %20 = OpLogicalAnd %v3bool %16 %19
+         %21 = OpLogicalOr %v3bool %11 %20
+          %9 = OpSelect %v3int %21 %23 %8
+         %24 = OpSDiv %v3int %lhs %9
+               OpReturnValue %24
+               OpFunctionEnd
+          %f = OpFunction %void None %25
+         %28 = OpLabel
+         %33 = OpFunctionCall %v3int %tint_div %31 %32
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/expressions/binary/div_by_zero/by_constant/vec3-scalar/u32.wgsl.expected.dxc.hlsl b/test/tint/expressions/binary/div_by_zero/by_constant/vec3-scalar/u32.wgsl.expected.dxc.hlsl
index bfe9e02..267d104 100644
--- a/test/tint/expressions/binary/div_by_zero/by_constant/vec3-scalar/u32.wgsl.expected.dxc.hlsl
+++ b/test/tint/expressions/binary/div_by_zero/by_constant/vec3-scalar/u32.wgsl.expected.dxc.hlsl
@@ -1,7 +1,12 @@
+uint3 tint_div(uint3 lhs, uint rhs) {
+  const uint3 r = uint3((rhs).xxx);
+  return (lhs / ((r == (0u).xxx) ? (1u).xxx : r));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   const uint3 a = uint3(1u, 2u, 3u);
   const uint b = 0u;
-  const uint3 r = (a / (b == 0u ? 1u : b));
+  const uint3 r = tint_div(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/div_by_zero/by_constant/vec3-scalar/u32.wgsl.expected.fxc.hlsl b/test/tint/expressions/binary/div_by_zero/by_constant/vec3-scalar/u32.wgsl.expected.fxc.hlsl
index bfe9e02..267d104 100644
--- a/test/tint/expressions/binary/div_by_zero/by_constant/vec3-scalar/u32.wgsl.expected.fxc.hlsl
+++ b/test/tint/expressions/binary/div_by_zero/by_constant/vec3-scalar/u32.wgsl.expected.fxc.hlsl
@@ -1,7 +1,12 @@
+uint3 tint_div(uint3 lhs, uint rhs) {
+  const uint3 r = uint3((rhs).xxx);
+  return (lhs / ((r == (0u).xxx) ? (1u).xxx : r));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   const uint3 a = uint3(1u, 2u, 3u);
   const uint b = 0u;
-  const uint3 r = (a / (b == 0u ? 1u : b));
+  const uint3 r = tint_div(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/div_by_zero/by_constant/vec3-scalar/u32.wgsl.expected.glsl b/test/tint/expressions/binary/div_by_zero/by_constant/vec3-scalar/u32.wgsl.expected.glsl
index 05bca8a..926d784 100644
--- a/test/tint/expressions/binary/div_by_zero/by_constant/vec3-scalar/u32.wgsl.expected.glsl
+++ b/test/tint/expressions/binary/div_by_zero/by_constant/vec3-scalar/u32.wgsl.expected.glsl
@@ -1,9 +1,14 @@
 #version 310 es
 
+uvec3 tint_div(uvec3 lhs, uint rhs) {
+  uvec3 r = uvec3(rhs);
+  return (lhs / mix(r, uvec3(1u), equal(r, uvec3(0u))));
+}
+
 void f() {
   uvec3 a = uvec3(1u, 2u, 3u);
   uint b = 0u;
-  uvec3 r = (a / b);
+  uvec3 r = tint_div(a, b);
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/expressions/binary/div_by_zero/by_constant/vec3-scalar/u32.wgsl.expected.msl b/test/tint/expressions/binary/div_by_zero/by_constant/vec3-scalar/u32.wgsl.expected.msl
index 2d342e7..716c969 100644
--- a/test/tint/expressions/binary/div_by_zero/by_constant/vec3-scalar/u32.wgsl.expected.msl
+++ b/test/tint/expressions/binary/div_by_zero/by_constant/vec3-scalar/u32.wgsl.expected.msl
@@ -1,10 +1,15 @@
 #include <metal_stdlib>
 
 using namespace metal;
+uint3 tint_div(uint3 lhs, uint rhs) {
+  uint3 const r = uint3(rhs);
+  return (lhs / select(r, uint3(1u), (r == uint3(0u))));
+}
+
 kernel void f() {
   uint3 const a = uint3(1u, 2u, 3u);
   uint const b = 0u;
-  uint3 const r = (a / b);
+  uint3 const r = tint_div(a, b);
   return;
 }
 
diff --git a/test/tint/expressions/binary/div_by_zero/by_constant/vec3-scalar/u32.wgsl.expected.spvasm b/test/tint/expressions/binary/div_by_zero/by_constant/vec3-scalar/u32.wgsl.expected.spvasm
index 2a83009..618d427 100644
--- a/test/tint/expressions/binary/div_by_zero/by_constant/vec3-scalar/u32.wgsl.expected.spvasm
+++ b/test/tint/expressions/binary/div_by_zero/by_constant/vec3-scalar/u32.wgsl.expected.spvasm
@@ -1,28 +1,42 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 17
+; Bound: 26
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %f "f"
                OpExecutionMode %f LocalSize 1 1 1
+               OpName %tint_div "tint_div"
+               OpName %lhs "lhs"
+               OpName %rhs "rhs"
                OpName %f "f"
-       %void = OpTypeVoid
-          %1 = OpTypeFunction %void
        %uint = OpTypeInt 32 0
      %v3uint = OpTypeVector %uint 3
+          %1 = OpTypeFunction %v3uint %v3uint %uint
+         %10 = OpConstantNull %v3uint
+       %bool = OpTypeBool
+     %v3bool = OpTypeVector %bool 3
      %uint_1 = OpConstant %uint 1
+         %15 = OpConstantComposite %v3uint %uint_1 %uint_1 %uint_1
+       %void = OpTypeVoid
+         %17 = OpTypeFunction %void
      %uint_2 = OpConstant %uint 2
      %uint_3 = OpConstant %uint 3
-         %10 = OpConstantComposite %v3uint %uint_1 %uint_2 %uint_3
-         %11 = OpConstantNull %uint
-%_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 %11 %11 %11
-         %12 = OpUDiv %v3uint %10 %16
+         %23 = OpConstantComposite %v3uint %uint_1 %uint_2 %uint_3
+         %24 = OpConstantNull %uint
+   %tint_div = OpFunction %v3uint None %1
+        %lhs = OpFunctionParameter %v3uint
+        %rhs = OpFunctionParameter %uint
+          %7 = OpLabel
+          %8 = OpCompositeConstruct %v3uint %rhs %rhs %rhs
+         %11 = OpIEqual %v3bool %8 %10
+          %9 = OpSelect %v3uint %11 %15 %8
+         %16 = OpUDiv %v3uint %lhs %9
+               OpReturnValue %16
+               OpFunctionEnd
+          %f = OpFunction %void None %17
+         %20 = OpLabel
+         %25 = OpFunctionCall %v3uint %tint_div %23 %24
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/expressions/binary/div_by_zero/by_constant/vec3-vec3/i32.wgsl.expected.dxc.hlsl b/test/tint/expressions/binary/div_by_zero/by_constant/vec3-vec3/i32.wgsl.expected.dxc.hlsl
index 30d26ca..f6889c1 100644
--- a/test/tint/expressions/binary/div_by_zero/by_constant/vec3-vec3/i32.wgsl.expected.dxc.hlsl
+++ b/test/tint/expressions/binary/div_by_zero/by_constant/vec3-vec3/i32.wgsl.expected.dxc.hlsl
@@ -1,7 +1,11 @@
+int3 tint_div(int3 lhs, int3 rhs) {
+  return (lhs / (((rhs == (0).xxx) | ((lhs == (-2147483648).xxx) & (rhs == (-1).xxx))) ? (1).xxx : rhs));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   const int3 a = int3(1, 2, 3);
   const int3 b = int3(0, 5, 0);
-  const int3 r = (a / (b == int3(0, 0, 0) ? int3(1, 1, 1) : b));
+  const int3 r = tint_div(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/div_by_zero/by_constant/vec3-vec3/i32.wgsl.expected.fxc.hlsl b/test/tint/expressions/binary/div_by_zero/by_constant/vec3-vec3/i32.wgsl.expected.fxc.hlsl
index 30d26ca..f6889c1 100644
--- a/test/tint/expressions/binary/div_by_zero/by_constant/vec3-vec3/i32.wgsl.expected.fxc.hlsl
+++ b/test/tint/expressions/binary/div_by_zero/by_constant/vec3-vec3/i32.wgsl.expected.fxc.hlsl
@@ -1,7 +1,11 @@
+int3 tint_div(int3 lhs, int3 rhs) {
+  return (lhs / (((rhs == (0).xxx) | ((lhs == (-2147483648).xxx) & (rhs == (-1).xxx))) ? (1).xxx : rhs));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   const int3 a = int3(1, 2, 3);
   const int3 b = int3(0, 5, 0);
-  const int3 r = (a / (b == int3(0, 0, 0) ? int3(1, 1, 1) : b));
+  const int3 r = tint_div(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/div_by_zero/by_constant/vec3-vec3/i32.wgsl.expected.glsl b/test/tint/expressions/binary/div_by_zero/by_constant/vec3-vec3/i32.wgsl.expected.glsl
index 6e11b34..2ea6128 100644
--- a/test/tint/expressions/binary/div_by_zero/by_constant/vec3-vec3/i32.wgsl.expected.glsl
+++ b/test/tint/expressions/binary/div_by_zero/by_constant/vec3-vec3/i32.wgsl.expected.glsl
@@ -1,9 +1,13 @@
 #version 310 es
 
+ivec3 tint_div(ivec3 lhs, ivec3 rhs) {
+  return (lhs / mix(rhs, ivec3(1), bvec3(uvec3(equal(rhs, ivec3(0))) | uvec3(bvec3(uvec3(equal(lhs, ivec3(-2147483648))) & uvec3(equal(rhs, ivec3(-1))))))));
+}
+
 void f() {
   ivec3 a = ivec3(1, 2, 3);
   ivec3 b = ivec3(0, 5, 0);
-  ivec3 r = (a / b);
+  ivec3 r = tint_div(a, b);
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/expressions/binary/div_by_zero/by_constant/vec3-vec3/i32.wgsl.expected.msl b/test/tint/expressions/binary/div_by_zero/by_constant/vec3-vec3/i32.wgsl.expected.msl
index 7cf2681..97271f2 100644
--- a/test/tint/expressions/binary/div_by_zero/by_constant/vec3-vec3/i32.wgsl.expected.msl
+++ b/test/tint/expressions/binary/div_by_zero/by_constant/vec3-vec3/i32.wgsl.expected.msl
@@ -1,10 +1,14 @@
 #include <metal_stdlib>
 
 using namespace metal;
+int3 tint_div(int3 lhs, int3 rhs) {
+  return (lhs / select(rhs, int3(1), ((rhs == int3(0)) | ((lhs == int3((-2147483647 - 1))) & (rhs == int3(-1))))));
+}
+
 kernel void f() {
   int3 const a = int3(1, 2, 3);
   int3 const b = int3(0, 5, 0);
-  int3 const r = (a / b);
+  int3 const r = tint_div(a, b);
   return;
 }
 
diff --git a/test/tint/expressions/binary/div_by_zero/by_constant/vec3-vec3/i32.wgsl.expected.spvasm b/test/tint/expressions/binary/div_by_zero/by_constant/vec3-vec3/i32.wgsl.expected.spvasm
index e986304..4ba4fc8 100644
--- a/test/tint/expressions/binary/div_by_zero/by_constant/vec3-vec3/i32.wgsl.expected.spvasm
+++ b/test/tint/expressions/binary/div_by_zero/by_constant/vec3-vec3/i32.wgsl.expected.spvasm
@@ -1,26 +1,51 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 15
+; Bound: 35
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %f "f"
                OpExecutionMode %f LocalSize 1 1 1
+               OpName %tint_div "tint_div"
+               OpName %lhs "lhs"
+               OpName %rhs "rhs"
                OpName %f "f"
-       %void = OpTypeVoid
-          %1 = OpTypeFunction %void
         %int = OpTypeInt 32 1
       %v3int = OpTypeVector %int 3
+          %1 = OpTypeFunction %v3int %v3int %v3int
+          %9 = OpConstantNull %v3int
+       %bool = OpTypeBool
+     %v3bool = OpTypeVector %bool 3
+%int_n2147483648 = OpConstant %int -2147483648
+         %14 = OpConstantComposite %v3int %int_n2147483648 %int_n2147483648 %int_n2147483648
+     %int_n1 = OpConstant %int -1
+         %17 = OpConstantComposite %v3int %int_n1 %int_n1 %int_n1
       %int_1 = OpConstant %int 1
+         %22 = OpConstantComposite %v3int %int_1 %int_1 %int_1
+       %void = OpTypeVoid
+         %24 = OpTypeFunction %void
       %int_2 = OpConstant %int 2
       %int_3 = OpConstant %int 3
-         %10 = OpConstantComposite %v3int %int_1 %int_2 %int_3
-         %11 = OpConstantNull %int
+         %30 = OpConstantComposite %v3int %int_1 %int_2 %int_3
+         %31 = OpConstantNull %int
       %int_5 = OpConstant %int 5
-         %13 = OpConstantComposite %v3int %11 %int_5 %11
-          %f = OpFunction %void None %1
-          %4 = OpLabel
-         %14 = OpSDiv %v3int %10 %13
+         %33 = OpConstantComposite %v3int %31 %int_5 %31
+   %tint_div = OpFunction %v3int None %1
+        %lhs = OpFunctionParameter %v3int
+        %rhs = OpFunctionParameter %v3int
+          %7 = OpLabel
+         %10 = OpIEqual %v3bool %rhs %9
+         %15 = OpIEqual %v3bool %lhs %14
+         %18 = OpIEqual %v3bool %rhs %17
+         %19 = OpLogicalAnd %v3bool %15 %18
+         %20 = OpLogicalOr %v3bool %10 %19
+          %8 = OpSelect %v3int %20 %22 %rhs
+         %23 = OpSDiv %v3int %lhs %8
+               OpReturnValue %23
+               OpFunctionEnd
+          %f = OpFunction %void None %24
+         %27 = OpLabel
+         %34 = OpFunctionCall %v3int %tint_div %30 %33
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/expressions/binary/div_by_zero/by_constant/vec3-vec3/u32.wgsl.expected.dxc.hlsl b/test/tint/expressions/binary/div_by_zero/by_constant/vec3-vec3/u32.wgsl.expected.dxc.hlsl
index c337dc3..46dca5a 100644
--- a/test/tint/expressions/binary/div_by_zero/by_constant/vec3-vec3/u32.wgsl.expected.dxc.hlsl
+++ b/test/tint/expressions/binary/div_by_zero/by_constant/vec3-vec3/u32.wgsl.expected.dxc.hlsl
@@ -1,7 +1,11 @@
+uint3 tint_div(uint3 lhs, uint3 rhs) {
+  return (lhs / ((rhs == (0u).xxx) ? (1u).xxx : rhs));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   const uint3 a = uint3(1u, 2u, 3u);
   const uint3 b = uint3(0u, 5u, 0u);
-  const uint3 r = (a / (b == uint3(0u, 0u, 0u) ? uint3(1u, 1u, 1u) : b));
+  const uint3 r = tint_div(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/div_by_zero/by_constant/vec3-vec3/u32.wgsl.expected.fxc.hlsl b/test/tint/expressions/binary/div_by_zero/by_constant/vec3-vec3/u32.wgsl.expected.fxc.hlsl
index c337dc3..46dca5a 100644
--- a/test/tint/expressions/binary/div_by_zero/by_constant/vec3-vec3/u32.wgsl.expected.fxc.hlsl
+++ b/test/tint/expressions/binary/div_by_zero/by_constant/vec3-vec3/u32.wgsl.expected.fxc.hlsl
@@ -1,7 +1,11 @@
+uint3 tint_div(uint3 lhs, uint3 rhs) {
+  return (lhs / ((rhs == (0u).xxx) ? (1u).xxx : rhs));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   const uint3 a = uint3(1u, 2u, 3u);
   const uint3 b = uint3(0u, 5u, 0u);
-  const uint3 r = (a / (b == uint3(0u, 0u, 0u) ? uint3(1u, 1u, 1u) : b));
+  const uint3 r = tint_div(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/div_by_zero/by_constant/vec3-vec3/u32.wgsl.expected.glsl b/test/tint/expressions/binary/div_by_zero/by_constant/vec3-vec3/u32.wgsl.expected.glsl
index 657cdb4..000bf89 100644
--- a/test/tint/expressions/binary/div_by_zero/by_constant/vec3-vec3/u32.wgsl.expected.glsl
+++ b/test/tint/expressions/binary/div_by_zero/by_constant/vec3-vec3/u32.wgsl.expected.glsl
@@ -1,9 +1,13 @@
 #version 310 es
 
+uvec3 tint_div(uvec3 lhs, uvec3 rhs) {
+  return (lhs / mix(rhs, uvec3(1u), equal(rhs, uvec3(0u))));
+}
+
 void f() {
   uvec3 a = uvec3(1u, 2u, 3u);
   uvec3 b = uvec3(0u, 5u, 0u);
-  uvec3 r = (a / b);
+  uvec3 r = tint_div(a, b);
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/expressions/binary/div_by_zero/by_constant/vec3-vec3/u32.wgsl.expected.msl b/test/tint/expressions/binary/div_by_zero/by_constant/vec3-vec3/u32.wgsl.expected.msl
index 66ee158..dac86ae 100644
--- a/test/tint/expressions/binary/div_by_zero/by_constant/vec3-vec3/u32.wgsl.expected.msl
+++ b/test/tint/expressions/binary/div_by_zero/by_constant/vec3-vec3/u32.wgsl.expected.msl
@@ -1,10 +1,14 @@
 #include <metal_stdlib>
 
 using namespace metal;
+uint3 tint_div(uint3 lhs, uint3 rhs) {
+  return (lhs / select(rhs, uint3(1u), (rhs == uint3(0u))));
+}
+
 kernel void f() {
   uint3 const a = uint3(1u, 2u, 3u);
   uint3 const b = uint3(0u, 5u, 0u);
-  uint3 const r = (a / b);
+  uint3 const r = tint_div(a, b);
   return;
 }
 
diff --git a/test/tint/expressions/binary/div_by_zero/by_constant/vec3-vec3/u32.wgsl.expected.spvasm b/test/tint/expressions/binary/div_by_zero/by_constant/vec3-vec3/u32.wgsl.expected.spvasm
index 2536318..45bde36 100644
--- a/test/tint/expressions/binary/div_by_zero/by_constant/vec3-vec3/u32.wgsl.expected.spvasm
+++ b/test/tint/expressions/binary/div_by_zero/by_constant/vec3-vec3/u32.wgsl.expected.spvasm
@@ -1,26 +1,43 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 15
+; Bound: 27
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %f "f"
                OpExecutionMode %f LocalSize 1 1 1
+               OpName %tint_div "tint_div"
+               OpName %lhs "lhs"
+               OpName %rhs "rhs"
                OpName %f "f"
-       %void = OpTypeVoid
-          %1 = OpTypeFunction %void
        %uint = OpTypeInt 32 0
      %v3uint = OpTypeVector %uint 3
+          %1 = OpTypeFunction %v3uint %v3uint %v3uint
+          %9 = OpConstantNull %v3uint
+       %bool = OpTypeBool
+     %v3bool = OpTypeVector %bool 3
      %uint_1 = OpConstant %uint 1
+         %14 = OpConstantComposite %v3uint %uint_1 %uint_1 %uint_1
+       %void = OpTypeVoid
+         %16 = OpTypeFunction %void
      %uint_2 = OpConstant %uint 2
      %uint_3 = OpConstant %uint 3
-         %10 = OpConstantComposite %v3uint %uint_1 %uint_2 %uint_3
-         %11 = OpConstantNull %uint
+         %22 = OpConstantComposite %v3uint %uint_1 %uint_2 %uint_3
+         %23 = OpConstantNull %uint
      %uint_5 = OpConstant %uint 5
-         %13 = OpConstantComposite %v3uint %11 %uint_5 %11
-          %f = OpFunction %void None %1
-          %4 = OpLabel
-         %14 = OpUDiv %v3uint %10 %13
+         %25 = OpConstantComposite %v3uint %23 %uint_5 %23
+   %tint_div = OpFunction %v3uint None %1
+        %lhs = OpFunctionParameter %v3uint
+        %rhs = OpFunctionParameter %v3uint
+          %7 = OpLabel
+         %10 = OpIEqual %v3bool %rhs %9
+          %8 = OpSelect %v3uint %10 %14 %rhs
+         %15 = OpUDiv %v3uint %lhs %8
+               OpReturnValue %15
+               OpFunctionEnd
+          %f = OpFunction %void None %16
+         %19 = OpLabel
+         %26 = OpFunctionCall %v3uint %tint_div %22 %25
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/expressions/binary/div_by_zero/by_expression/scalar-scalar/i32.wgsl.expected.dxc.hlsl b/test/tint/expressions/binary/div_by_zero/by_expression/scalar-scalar/i32.wgsl.expected.dxc.hlsl
index 6ed4430..e6a1488 100644
--- a/test/tint/expressions/binary/div_by_zero/by_expression/scalar-scalar/i32.wgsl.expected.dxc.hlsl
+++ b/test/tint/expressions/binary/div_by_zero/by_expression/scalar-scalar/i32.wgsl.expected.dxc.hlsl
@@ -1,11 +1,11 @@
-int value_or_one_if_zero_int(int value) {
-  return value == 0 ? 1 : value;
+int tint_div(int lhs, int rhs) {
+  return (lhs / (((rhs == 0) | ((lhs == -2147483648) & (rhs == -1))) ? 1 : rhs));
 }
 
 [numthreads(1, 1, 1)]
 void f() {
   int a = 1;
   int b = 0;
-  const int r = (a / value_or_one_if_zero_int((b + b)));
+  const int r = tint_div(a, (b + b));
   return;
 }
diff --git a/test/tint/expressions/binary/div_by_zero/by_expression/scalar-scalar/i32.wgsl.expected.fxc.hlsl b/test/tint/expressions/binary/div_by_zero/by_expression/scalar-scalar/i32.wgsl.expected.fxc.hlsl
index 6ed4430..e6a1488 100644
--- a/test/tint/expressions/binary/div_by_zero/by_expression/scalar-scalar/i32.wgsl.expected.fxc.hlsl
+++ b/test/tint/expressions/binary/div_by_zero/by_expression/scalar-scalar/i32.wgsl.expected.fxc.hlsl
@@ -1,11 +1,11 @@
-int value_or_one_if_zero_int(int value) {
-  return value == 0 ? 1 : value;
+int tint_div(int lhs, int rhs) {
+  return (lhs / (((rhs == 0) | ((lhs == -2147483648) & (rhs == -1))) ? 1 : rhs));
 }
 
 [numthreads(1, 1, 1)]
 void f() {
   int a = 1;
   int b = 0;
-  const int r = (a / value_or_one_if_zero_int((b + b)));
+  const int r = tint_div(a, (b + b));
   return;
 }
diff --git a/test/tint/expressions/binary/div_by_zero/by_expression/scalar-scalar/i32.wgsl.expected.glsl b/test/tint/expressions/binary/div_by_zero/by_expression/scalar-scalar/i32.wgsl.expected.glsl
index b3aef3b..9109801 100644
--- a/test/tint/expressions/binary/div_by_zero/by_expression/scalar-scalar/i32.wgsl.expected.glsl
+++ b/test/tint/expressions/binary/div_by_zero/by_expression/scalar-scalar/i32.wgsl.expected.glsl
@@ -1,9 +1,13 @@
 #version 310 es
 
+int tint_div(int lhs, int rhs) {
+  return (lhs / (bool(uint((rhs == 0)) | uint(bool(uint((lhs == -2147483648)) & uint((rhs == -1))))) ? 1 : rhs));
+}
+
 void f() {
   int a = 1;
   int b = 0;
-  int r = (a / (b + b));
+  int r = tint_div(a, (b + b));
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/expressions/binary/div_by_zero/by_expression/scalar-scalar/i32.wgsl.expected.msl b/test/tint/expressions/binary/div_by_zero/by_expression/scalar-scalar/i32.wgsl.expected.msl
index c319da3..e0cf597 100644
--- a/test/tint/expressions/binary/div_by_zero/by_expression/scalar-scalar/i32.wgsl.expected.msl
+++ b/test/tint/expressions/binary/div_by_zero/by_expression/scalar-scalar/i32.wgsl.expected.msl
@@ -1,10 +1,14 @@
 #include <metal_stdlib>
 
 using namespace metal;
+int tint_div(int lhs, int rhs) {
+  return (lhs / select(rhs, 1, bool((rhs == 0) | bool((lhs == (-2147483647 - 1)) & (rhs == -1)))));
+}
+
 kernel void f() {
   int a = 1;
   int b = 0;
-  int const r = (a / as_type<int>((as_type<uint>(b) + as_type<uint>(b))));
+  int const r = tint_div(a, as_type<int>((as_type<uint>(b) + as_type<uint>(b))));
   return;
 }
 
diff --git a/test/tint/expressions/binary/div_by_zero/by_expression/scalar-scalar/i32.wgsl.expected.spvasm b/test/tint/expressions/binary/div_by_zero/by_expression/scalar-scalar/i32.wgsl.expected.spvasm
index 2cad16a..5891caa 100644
--- a/test/tint/expressions/binary/div_by_zero/by_expression/scalar-scalar/i32.wgsl.expected.spvasm
+++ b/test/tint/expressions/binary/div_by_zero/by_expression/scalar-scalar/i32.wgsl.expected.spvasm
@@ -1,31 +1,51 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 16
+; Bound: 31
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %f "f"
                OpExecutionMode %f LocalSize 1 1 1
+               OpName %tint_div "tint_div"
+               OpName %lhs "lhs"
+               OpName %rhs "rhs"
                OpName %f "f"
                OpName %a "a"
                OpName %b "b"
-       %void = OpTypeVoid
-          %1 = OpTypeFunction %void
         %int = OpTypeInt 32 1
+          %1 = OpTypeFunction %int %int %int
+          %8 = OpConstantNull %int
+       %bool = OpTypeBool
+%int_n2147483648 = OpConstant %int -2147483648
+     %int_n1 = OpConstant %int -1
       %int_1 = OpConstant %int 1
+       %void = OpTypeVoid
+         %19 = OpTypeFunction %void
 %_ptr_Function_int = OpTypePointer Function %int
-          %9 = OpConstantNull %int
-          %f = OpFunction %void None %1
-          %4 = OpLabel
-          %a = OpVariable %_ptr_Function_int Function %9
-          %b = OpVariable %_ptr_Function_int Function %9
+   %tint_div = OpFunction %int None %1
+        %lhs = OpFunctionParameter %int
+        %rhs = OpFunctionParameter %int
+          %6 = OpLabel
+          %9 = OpIEqual %bool %rhs %8
+         %12 = OpIEqual %bool %lhs %int_n2147483648
+         %14 = OpIEqual %bool %rhs %int_n1
+         %15 = OpLogicalAnd %bool %12 %14
+         %16 = OpLogicalOr %bool %9 %15
+          %7 = OpSelect %int %16 %int_1 %rhs
+         %18 = OpSDiv %int %lhs %7
+               OpReturnValue %18
+               OpFunctionEnd
+          %f = OpFunction %void None %19
+         %22 = OpLabel
+          %a = OpVariable %_ptr_Function_int Function %8
+          %b = OpVariable %_ptr_Function_int Function %8
                OpStore %a %int_1
-               OpStore %b %9
-         %11 = OpLoad %int %a
-         %12 = OpLoad %int %b
-         %13 = OpLoad %int %b
-         %14 = OpIAdd %int %12 %13
-         %15 = OpSDiv %int %11 %14
+               OpStore %b %8
+         %27 = OpLoad %int %a
+         %28 = OpLoad %int %b
+         %29 = OpLoad %int %b
+         %30 = OpIAdd %int %28 %29
+         %26 = OpFunctionCall %int %tint_div %27 %30
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/expressions/binary/div_by_zero/by_expression/scalar-scalar/u32.wgsl.expected.dxc.hlsl b/test/tint/expressions/binary/div_by_zero/by_expression/scalar-scalar/u32.wgsl.expected.dxc.hlsl
index ec658be..e7b89f2 100644
--- a/test/tint/expressions/binary/div_by_zero/by_expression/scalar-scalar/u32.wgsl.expected.dxc.hlsl
+++ b/test/tint/expressions/binary/div_by_zero/by_expression/scalar-scalar/u32.wgsl.expected.dxc.hlsl
@@ -1,11 +1,11 @@
-uint value_or_one_if_zero_uint(uint value) {
-  return value == 0u ? 1u : value;
+uint tint_div(uint lhs, uint rhs) {
+  return (lhs / ((rhs == 0u) ? 1u : rhs));
 }
 
 [numthreads(1, 1, 1)]
 void f() {
   uint a = 1u;
   uint b = 0u;
-  const uint r = (a / value_or_one_if_zero_uint((b + b)));
+  const uint r = tint_div(a, (b + b));
   return;
 }
diff --git a/test/tint/expressions/binary/div_by_zero/by_expression/scalar-scalar/u32.wgsl.expected.fxc.hlsl b/test/tint/expressions/binary/div_by_zero/by_expression/scalar-scalar/u32.wgsl.expected.fxc.hlsl
index ec658be..e7b89f2 100644
--- a/test/tint/expressions/binary/div_by_zero/by_expression/scalar-scalar/u32.wgsl.expected.fxc.hlsl
+++ b/test/tint/expressions/binary/div_by_zero/by_expression/scalar-scalar/u32.wgsl.expected.fxc.hlsl
@@ -1,11 +1,11 @@
-uint value_or_one_if_zero_uint(uint value) {
-  return value == 0u ? 1u : value;
+uint tint_div(uint lhs, uint rhs) {
+  return (lhs / ((rhs == 0u) ? 1u : rhs));
 }
 
 [numthreads(1, 1, 1)]
 void f() {
   uint a = 1u;
   uint b = 0u;
-  const uint r = (a / value_or_one_if_zero_uint((b + b)));
+  const uint r = tint_div(a, (b + b));
   return;
 }
diff --git a/test/tint/expressions/binary/div_by_zero/by_expression/scalar-scalar/u32.wgsl.expected.glsl b/test/tint/expressions/binary/div_by_zero/by_expression/scalar-scalar/u32.wgsl.expected.glsl
index b15631c..cf9e739 100644
--- a/test/tint/expressions/binary/div_by_zero/by_expression/scalar-scalar/u32.wgsl.expected.glsl
+++ b/test/tint/expressions/binary/div_by_zero/by_expression/scalar-scalar/u32.wgsl.expected.glsl
@@ -1,9 +1,13 @@
 #version 310 es
 
+uint tint_div(uint lhs, uint rhs) {
+  return (lhs / ((rhs == 0u) ? 1u : rhs));
+}
+
 void f() {
   uint a = 1u;
   uint b = 0u;
-  uint r = (a / (b + b));
+  uint r = tint_div(a, (b + b));
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/expressions/binary/div_by_zero/by_expression/scalar-scalar/u32.wgsl.expected.msl b/test/tint/expressions/binary/div_by_zero/by_expression/scalar-scalar/u32.wgsl.expected.msl
index ad2302f..64d213b 100644
--- a/test/tint/expressions/binary/div_by_zero/by_expression/scalar-scalar/u32.wgsl.expected.msl
+++ b/test/tint/expressions/binary/div_by_zero/by_expression/scalar-scalar/u32.wgsl.expected.msl
@@ -1,10 +1,14 @@
 #include <metal_stdlib>
 
 using namespace metal;
+uint tint_div(uint lhs, uint rhs) {
+  return (lhs / select(rhs, 1u, (rhs == 0u)));
+}
+
 kernel void f() {
   uint a = 1u;
   uint b = 0u;
-  uint const r = (a / (b + b));
+  uint const r = tint_div(a, (b + b));
   return;
 }
 
diff --git a/test/tint/expressions/binary/div_by_zero/by_expression/scalar-scalar/u32.wgsl.expected.spvasm b/test/tint/expressions/binary/div_by_zero/by_expression/scalar-scalar/u32.wgsl.expected.spvasm
index f245f40..9fbd92f 100644
--- a/test/tint/expressions/binary/div_by_zero/by_expression/scalar-scalar/u32.wgsl.expected.spvasm
+++ b/test/tint/expressions/binary/div_by_zero/by_expression/scalar-scalar/u32.wgsl.expected.spvasm
@@ -1,31 +1,45 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 16
+; Bound: 25
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %f "f"
                OpExecutionMode %f LocalSize 1 1 1
+               OpName %tint_div "tint_div"
+               OpName %lhs "lhs"
+               OpName %rhs "rhs"
                OpName %f "f"
                OpName %a "a"
                OpName %b "b"
-       %void = OpTypeVoid
-          %1 = OpTypeFunction %void
        %uint = OpTypeInt 32 0
+          %1 = OpTypeFunction %uint %uint %uint
+          %8 = OpConstantNull %uint
+       %bool = OpTypeBool
      %uint_1 = OpConstant %uint 1
+       %void = OpTypeVoid
+         %13 = OpTypeFunction %void
 %_ptr_Function_uint = OpTypePointer Function %uint
-          %9 = OpConstantNull %uint
-          %f = OpFunction %void None %1
-          %4 = OpLabel
-          %a = OpVariable %_ptr_Function_uint Function %9
-          %b = OpVariable %_ptr_Function_uint Function %9
+   %tint_div = OpFunction %uint None %1
+        %lhs = OpFunctionParameter %uint
+        %rhs = OpFunctionParameter %uint
+          %6 = OpLabel
+          %9 = OpIEqual %bool %rhs %8
+          %7 = OpSelect %uint %9 %uint_1 %rhs
+         %12 = OpUDiv %uint %lhs %7
+               OpReturnValue %12
+               OpFunctionEnd
+          %f = OpFunction %void None %13
+         %16 = OpLabel
+          %a = OpVariable %_ptr_Function_uint Function %8
+          %b = OpVariable %_ptr_Function_uint Function %8
                OpStore %a %uint_1
-               OpStore %b %9
-         %11 = OpLoad %uint %a
-         %12 = OpLoad %uint %b
-         %13 = OpLoad %uint %b
-         %14 = OpIAdd %uint %12 %13
-         %15 = OpUDiv %uint %11 %14
+               OpStore %b %8
+         %21 = OpLoad %uint %a
+         %22 = OpLoad %uint %b
+         %23 = OpLoad %uint %b
+         %24 = OpIAdd %uint %22 %23
+         %20 = OpFunctionCall %uint %tint_div %21 %24
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/expressions/binary/div_by_zero/by_expression/scalar-vec3/i32.wgsl.expected.dxc.hlsl b/test/tint/expressions/binary/div_by_zero/by_expression/scalar-vec3/i32.wgsl.expected.dxc.hlsl
index f23bda3..52f716f 100644
--- a/test/tint/expressions/binary/div_by_zero/by_expression/scalar-vec3/i32.wgsl.expected.dxc.hlsl
+++ b/test/tint/expressions/binary/div_by_zero/by_expression/scalar-vec3/i32.wgsl.expected.dxc.hlsl
@@ -1,11 +1,12 @@
-int3 value_or_one_if_zero_int3(int3 value) {
-  return value == int3(0, 0, 0) ? int3(1, 1, 1) : value;
+int3 tint_div(int lhs, int3 rhs) {
+  const int3 l = int3((lhs).xxx);
+  return (l / (((rhs == (0).xxx) | ((l == (-2147483648).xxx) & (rhs == (-1).xxx))) ? (1).xxx : rhs));
 }
 
 [numthreads(1, 1, 1)]
 void f() {
   int a = 4;
   int3 b = int3(0, 2, 0);
-  const int3 r = (a / value_or_one_if_zero_int3((b + b)));
+  const int3 r = tint_div(a, (b + b));
   return;
 }
diff --git a/test/tint/expressions/binary/div_by_zero/by_expression/scalar-vec3/i32.wgsl.expected.fxc.hlsl b/test/tint/expressions/binary/div_by_zero/by_expression/scalar-vec3/i32.wgsl.expected.fxc.hlsl
index f23bda3..52f716f 100644
--- a/test/tint/expressions/binary/div_by_zero/by_expression/scalar-vec3/i32.wgsl.expected.fxc.hlsl
+++ b/test/tint/expressions/binary/div_by_zero/by_expression/scalar-vec3/i32.wgsl.expected.fxc.hlsl
@@ -1,11 +1,12 @@
-int3 value_or_one_if_zero_int3(int3 value) {
-  return value == int3(0, 0, 0) ? int3(1, 1, 1) : value;
+int3 tint_div(int lhs, int3 rhs) {
+  const int3 l = int3((lhs).xxx);
+  return (l / (((rhs == (0).xxx) | ((l == (-2147483648).xxx) & (rhs == (-1).xxx))) ? (1).xxx : rhs));
 }
 
 [numthreads(1, 1, 1)]
 void f() {
   int a = 4;
   int3 b = int3(0, 2, 0);
-  const int3 r = (a / value_or_one_if_zero_int3((b + b)));
+  const int3 r = tint_div(a, (b + b));
   return;
 }
diff --git a/test/tint/expressions/binary/div_by_zero/by_expression/scalar-vec3/i32.wgsl.expected.glsl b/test/tint/expressions/binary/div_by_zero/by_expression/scalar-vec3/i32.wgsl.expected.glsl
index d2f146a..0a46644 100644
--- a/test/tint/expressions/binary/div_by_zero/by_expression/scalar-vec3/i32.wgsl.expected.glsl
+++ b/test/tint/expressions/binary/div_by_zero/by_expression/scalar-vec3/i32.wgsl.expected.glsl
@@ -1,9 +1,14 @@
 #version 310 es
 
+ivec3 tint_div(int lhs, ivec3 rhs) {
+  ivec3 l = ivec3(lhs);
+  return (l / mix(rhs, ivec3(1), bvec3(uvec3(equal(rhs, ivec3(0))) | uvec3(bvec3(uvec3(equal(l, ivec3(-2147483648))) & uvec3(equal(rhs, ivec3(-1))))))));
+}
+
 void f() {
   int a = 4;
   ivec3 b = ivec3(0, 2, 0);
-  ivec3 r = (a / (b + b));
+  ivec3 r = tint_div(a, (b + b));
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/expressions/binary/div_by_zero/by_expression/scalar-vec3/i32.wgsl.expected.msl b/test/tint/expressions/binary/div_by_zero/by_expression/scalar-vec3/i32.wgsl.expected.msl
index 72cb90c..b414a14 100644
--- a/test/tint/expressions/binary/div_by_zero/by_expression/scalar-vec3/i32.wgsl.expected.msl
+++ b/test/tint/expressions/binary/div_by_zero/by_expression/scalar-vec3/i32.wgsl.expected.msl
@@ -1,10 +1,15 @@
 #include <metal_stdlib>
 
 using namespace metal;
+int3 tint_div(int lhs, int3 rhs) {
+  int3 const l = int3(lhs);
+  return (l / select(rhs, int3(1), ((rhs == int3(0)) | ((l == int3((-2147483647 - 1))) & (rhs == int3(-1))))));
+}
+
 kernel void f() {
   int a = 4;
   int3 b = int3(0, 2, 0);
-  int3 const r = (a / as_type<int3>((as_type<uint3>(b) + as_type<uint3>(b))));
+  int3 const r = tint_div(a, as_type<int3>((as_type<uint3>(b) + as_type<uint3>(b))));
   return;
 }
 
diff --git a/test/tint/expressions/binary/div_by_zero/by_expression/scalar-vec3/i32.wgsl.expected.spvasm b/test/tint/expressions/binary/div_by_zero/by_expression/scalar-vec3/i32.wgsl.expected.spvasm
index ac46dbb..ef478dd 100644
--- a/test/tint/expressions/binary/div_by_zero/by_expression/scalar-vec3/i32.wgsl.expected.spvasm
+++ b/test/tint/expressions/binary/div_by_zero/by_expression/scalar-vec3/i32.wgsl.expected.spvasm
@@ -1,38 +1,62 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 23
+; Bound: 42
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %f "f"
                OpExecutionMode %f LocalSize 1 1 1
+               OpName %tint_div "tint_div"
+               OpName %lhs "lhs"
+               OpName %rhs "rhs"
                OpName %f "f"
                OpName %a "a"
                OpName %b "b"
-       %void = OpTypeVoid
-          %1 = OpTypeFunction %void
         %int = OpTypeInt 32 1
+      %v3int = OpTypeVector %int 3
+          %1 = OpTypeFunction %v3int %int %v3int
+         %10 = OpConstantNull %v3int
+       %bool = OpTypeBool
+     %v3bool = OpTypeVector %bool 3
+%int_n2147483648 = OpConstant %int -2147483648
+         %15 = OpConstantComposite %v3int %int_n2147483648 %int_n2147483648 %int_n2147483648
+     %int_n1 = OpConstant %int -1
+         %18 = OpConstantComposite %v3int %int_n1 %int_n1 %int_n1
+      %int_1 = OpConstant %int 1
+         %23 = OpConstantComposite %v3int %int_1 %int_1 %int_1
+       %void = OpTypeVoid
+         %25 = OpTypeFunction %void
       %int_4 = OpConstant %int 4
 %_ptr_Function_int = OpTypePointer Function %int
-          %9 = OpConstantNull %int
-      %v3int = OpTypeVector %int 3
+         %32 = OpConstantNull %int
       %int_2 = OpConstant %int 2
-         %12 = OpConstantComposite %v3int %9 %int_2 %9
+         %34 = OpConstantComposite %v3int %32 %int_2 %32
 %_ptr_Function_v3int = OpTypePointer Function %v3int
-         %15 = OpConstantNull %v3int
-          %f = OpFunction %void None %1
-          %4 = OpLabel
-          %a = OpVariable %_ptr_Function_int Function %9
-          %b = OpVariable %_ptr_Function_v3int Function %15
-         %21 = OpVariable %_ptr_Function_v3int Function %15
+   %tint_div = OpFunction %v3int None %1
+        %lhs = OpFunctionParameter %int
+        %rhs = OpFunctionParameter %v3int
+          %7 = OpLabel
+          %8 = OpCompositeConstruct %v3int %lhs %lhs %lhs
+         %11 = OpIEqual %v3bool %rhs %10
+         %16 = OpIEqual %v3bool %8 %15
+         %19 = OpIEqual %v3bool %rhs %18
+         %20 = OpLogicalAnd %v3bool %16 %19
+         %21 = OpLogicalOr %v3bool %11 %20
+          %9 = OpSelect %v3int %21 %23 %rhs
+         %24 = OpSDiv %v3int %8 %9
+               OpReturnValue %24
+               OpFunctionEnd
+          %f = OpFunction %void None %25
+         %28 = OpLabel
+          %a = OpVariable %_ptr_Function_int Function %32
+          %b = OpVariable %_ptr_Function_v3int Function %10
                OpStore %a %int_4
-               OpStore %b %12
-         %16 = OpLoad %int %a
-         %17 = OpLoad %v3int %b
-         %18 = OpLoad %v3int %b
-         %19 = OpIAdd %v3int %17 %18
-         %22 = OpCompositeConstruct %v3int %16 %16 %16
-         %20 = OpSDiv %v3int %22 %19
+               OpStore %b %34
+         %38 = OpLoad %int %a
+         %39 = OpLoad %v3int %b
+         %40 = OpLoad %v3int %b
+         %41 = OpIAdd %v3int %39 %40
+         %37 = OpFunctionCall %v3int %tint_div %38 %41
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/expressions/binary/div_by_zero/by_expression/scalar-vec3/u32.wgsl.expected.dxc.hlsl b/test/tint/expressions/binary/div_by_zero/by_expression/scalar-vec3/u32.wgsl.expected.dxc.hlsl
index ec3621c..9ad34b2 100644
--- a/test/tint/expressions/binary/div_by_zero/by_expression/scalar-vec3/u32.wgsl.expected.dxc.hlsl
+++ b/test/tint/expressions/binary/div_by_zero/by_expression/scalar-vec3/u32.wgsl.expected.dxc.hlsl
@@ -1,11 +1,12 @@
-uint3 value_or_one_if_zero_uint3(uint3 value) {
-  return value == uint3(0u, 0u, 0u) ? uint3(1u, 1u, 1u) : value;
+uint3 tint_div(uint lhs, uint3 rhs) {
+  const uint3 l = uint3((lhs).xxx);
+  return (l / ((rhs == (0u).xxx) ? (1u).xxx : rhs));
 }
 
 [numthreads(1, 1, 1)]
 void f() {
   uint a = 4u;
   uint3 b = uint3(0u, 2u, 0u);
-  const uint3 r = (a / value_or_one_if_zero_uint3((b + b)));
+  const uint3 r = tint_div(a, (b + b));
   return;
 }
diff --git a/test/tint/expressions/binary/div_by_zero/by_expression/scalar-vec3/u32.wgsl.expected.fxc.hlsl b/test/tint/expressions/binary/div_by_zero/by_expression/scalar-vec3/u32.wgsl.expected.fxc.hlsl
index ec3621c..9ad34b2 100644
--- a/test/tint/expressions/binary/div_by_zero/by_expression/scalar-vec3/u32.wgsl.expected.fxc.hlsl
+++ b/test/tint/expressions/binary/div_by_zero/by_expression/scalar-vec3/u32.wgsl.expected.fxc.hlsl
@@ -1,11 +1,12 @@
-uint3 value_or_one_if_zero_uint3(uint3 value) {
-  return value == uint3(0u, 0u, 0u) ? uint3(1u, 1u, 1u) : value;
+uint3 tint_div(uint lhs, uint3 rhs) {
+  const uint3 l = uint3((lhs).xxx);
+  return (l / ((rhs == (0u).xxx) ? (1u).xxx : rhs));
 }
 
 [numthreads(1, 1, 1)]
 void f() {
   uint a = 4u;
   uint3 b = uint3(0u, 2u, 0u);
-  const uint3 r = (a / value_or_one_if_zero_uint3((b + b)));
+  const uint3 r = tint_div(a, (b + b));
   return;
 }
diff --git a/test/tint/expressions/binary/div_by_zero/by_expression/scalar-vec3/u32.wgsl.expected.glsl b/test/tint/expressions/binary/div_by_zero/by_expression/scalar-vec3/u32.wgsl.expected.glsl
index 67af12e..187744b 100644
--- a/test/tint/expressions/binary/div_by_zero/by_expression/scalar-vec3/u32.wgsl.expected.glsl
+++ b/test/tint/expressions/binary/div_by_zero/by_expression/scalar-vec3/u32.wgsl.expected.glsl
@@ -1,9 +1,14 @@
 #version 310 es
 
+uvec3 tint_div(uint lhs, uvec3 rhs) {
+  uvec3 l = uvec3(lhs);
+  return (l / mix(rhs, uvec3(1u), equal(rhs, uvec3(0u))));
+}
+
 void f() {
   uint a = 4u;
   uvec3 b = uvec3(0u, 2u, 0u);
-  uvec3 r = (a / (b + b));
+  uvec3 r = tint_div(a, (b + b));
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/expressions/binary/div_by_zero/by_expression/scalar-vec3/u32.wgsl.expected.msl b/test/tint/expressions/binary/div_by_zero/by_expression/scalar-vec3/u32.wgsl.expected.msl
index f742cd5..8722f2a 100644
--- a/test/tint/expressions/binary/div_by_zero/by_expression/scalar-vec3/u32.wgsl.expected.msl
+++ b/test/tint/expressions/binary/div_by_zero/by_expression/scalar-vec3/u32.wgsl.expected.msl
@@ -1,10 +1,15 @@
 #include <metal_stdlib>
 
 using namespace metal;
+uint3 tint_div(uint lhs, uint3 rhs) {
+  uint3 const l = uint3(lhs);
+  return (l / select(rhs, uint3(1u), (rhs == uint3(0u))));
+}
+
 kernel void f() {
   uint a = 4u;
   uint3 b = uint3(0u, 2u, 0u);
-  uint3 const r = (a / (b + b));
+  uint3 const r = tint_div(a, (b + b));
   return;
 }
 
diff --git a/test/tint/expressions/binary/div_by_zero/by_expression/scalar-vec3/u32.wgsl.expected.spvasm b/test/tint/expressions/binary/div_by_zero/by_expression/scalar-vec3/u32.wgsl.expected.spvasm
index d4fb717..7eba1c6 100644
--- a/test/tint/expressions/binary/div_by_zero/by_expression/scalar-vec3/u32.wgsl.expected.spvasm
+++ b/test/tint/expressions/binary/div_by_zero/by_expression/scalar-vec3/u32.wgsl.expected.spvasm
@@ -1,38 +1,54 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 23
+; Bound: 34
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %f "f"
                OpExecutionMode %f LocalSize 1 1 1
+               OpName %tint_div "tint_div"
+               OpName %lhs "lhs"
+               OpName %rhs "rhs"
                OpName %f "f"
                OpName %a "a"
                OpName %b "b"
-       %void = OpTypeVoid
-          %1 = OpTypeFunction %void
        %uint = OpTypeInt 32 0
+     %v3uint = OpTypeVector %uint 3
+          %1 = OpTypeFunction %v3uint %uint %v3uint
+         %10 = OpConstantNull %v3uint
+       %bool = OpTypeBool
+     %v3bool = OpTypeVector %bool 3
+     %uint_1 = OpConstant %uint 1
+         %15 = OpConstantComposite %v3uint %uint_1 %uint_1 %uint_1
+       %void = OpTypeVoid
+         %17 = OpTypeFunction %void
      %uint_4 = OpConstant %uint 4
 %_ptr_Function_uint = OpTypePointer Function %uint
-          %9 = OpConstantNull %uint
-     %v3uint = OpTypeVector %uint 3
+         %24 = OpConstantNull %uint
      %uint_2 = OpConstant %uint 2
-         %12 = OpConstantComposite %v3uint %9 %uint_2 %9
+         %26 = OpConstantComposite %v3uint %24 %uint_2 %24
 %_ptr_Function_v3uint = OpTypePointer Function %v3uint
-         %15 = OpConstantNull %v3uint
-          %f = OpFunction %void None %1
-          %4 = OpLabel
-          %a = OpVariable %_ptr_Function_uint Function %9
-          %b = OpVariable %_ptr_Function_v3uint Function %15
-         %21 = OpVariable %_ptr_Function_v3uint Function %15
+   %tint_div = OpFunction %v3uint None %1
+        %lhs = OpFunctionParameter %uint
+        %rhs = OpFunctionParameter %v3uint
+          %7 = OpLabel
+          %8 = OpCompositeConstruct %v3uint %lhs %lhs %lhs
+         %11 = OpIEqual %v3bool %rhs %10
+          %9 = OpSelect %v3uint %11 %15 %rhs
+         %16 = OpUDiv %v3uint %8 %9
+               OpReturnValue %16
+               OpFunctionEnd
+          %f = OpFunction %void None %17
+         %20 = OpLabel
+          %a = OpVariable %_ptr_Function_uint Function %24
+          %b = OpVariable %_ptr_Function_v3uint Function %10
                OpStore %a %uint_4
-               OpStore %b %12
-         %16 = OpLoad %uint %a
-         %17 = OpLoad %v3uint %b
-         %18 = OpLoad %v3uint %b
-         %19 = OpIAdd %v3uint %17 %18
-         %22 = OpCompositeConstruct %v3uint %16 %16 %16
-         %20 = OpUDiv %v3uint %22 %19
+               OpStore %b %26
+         %30 = OpLoad %uint %a
+         %31 = OpLoad %v3uint %b
+         %32 = OpLoad %v3uint %b
+         %33 = OpIAdd %v3uint %31 %32
+         %29 = OpFunctionCall %v3uint %tint_div %30 %33
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/expressions/binary/div_by_zero/by_expression/vec3-scalar/i32.wgsl.expected.dxc.hlsl b/test/tint/expressions/binary/div_by_zero/by_expression/vec3-scalar/i32.wgsl.expected.dxc.hlsl
index 964d275..6bdd31e 100644
--- a/test/tint/expressions/binary/div_by_zero/by_expression/vec3-scalar/i32.wgsl.expected.dxc.hlsl
+++ b/test/tint/expressions/binary/div_by_zero/by_expression/vec3-scalar/i32.wgsl.expected.dxc.hlsl
@@ -1,11 +1,12 @@
-int value_or_one_if_zero_int(int value) {
-  return value == 0 ? 1 : value;
+int3 tint_div(int3 lhs, int rhs) {
+  const int3 r = int3((rhs).xxx);
+  return (lhs / (((r == (0).xxx) | ((lhs == (-2147483648).xxx) & (r == (-1).xxx))) ? (1).xxx : r));
 }
 
 [numthreads(1, 1, 1)]
 void f() {
   int3 a = int3(1, 2, 3);
   int b = 0;
-  const int3 r = (a / value_or_one_if_zero_int((b + b)));
+  const int3 r = tint_div(a, (b + b));
   return;
 }
diff --git a/test/tint/expressions/binary/div_by_zero/by_expression/vec3-scalar/i32.wgsl.expected.fxc.hlsl b/test/tint/expressions/binary/div_by_zero/by_expression/vec3-scalar/i32.wgsl.expected.fxc.hlsl
index 964d275..6bdd31e 100644
--- a/test/tint/expressions/binary/div_by_zero/by_expression/vec3-scalar/i32.wgsl.expected.fxc.hlsl
+++ b/test/tint/expressions/binary/div_by_zero/by_expression/vec3-scalar/i32.wgsl.expected.fxc.hlsl
@@ -1,11 +1,12 @@
-int value_or_one_if_zero_int(int value) {
-  return value == 0 ? 1 : value;
+int3 tint_div(int3 lhs, int rhs) {
+  const int3 r = int3((rhs).xxx);
+  return (lhs / (((r == (0).xxx) | ((lhs == (-2147483648).xxx) & (r == (-1).xxx))) ? (1).xxx : r));
 }
 
 [numthreads(1, 1, 1)]
 void f() {
   int3 a = int3(1, 2, 3);
   int b = 0;
-  const int3 r = (a / value_or_one_if_zero_int((b + b)));
+  const int3 r = tint_div(a, (b + b));
   return;
 }
diff --git a/test/tint/expressions/binary/div_by_zero/by_expression/vec3-scalar/i32.wgsl.expected.glsl b/test/tint/expressions/binary/div_by_zero/by_expression/vec3-scalar/i32.wgsl.expected.glsl
index 1ee33f9..4221f2a 100644
--- a/test/tint/expressions/binary/div_by_zero/by_expression/vec3-scalar/i32.wgsl.expected.glsl
+++ b/test/tint/expressions/binary/div_by_zero/by_expression/vec3-scalar/i32.wgsl.expected.glsl
@@ -1,9 +1,14 @@
 #version 310 es
 
+ivec3 tint_div(ivec3 lhs, int rhs) {
+  ivec3 r = ivec3(rhs);
+  return (lhs / mix(r, ivec3(1), bvec3(uvec3(equal(r, ivec3(0))) | uvec3(bvec3(uvec3(equal(lhs, ivec3(-2147483648))) & uvec3(equal(r, ivec3(-1))))))));
+}
+
 void f() {
   ivec3 a = ivec3(1, 2, 3);
   int b = 0;
-  ivec3 r = (a / (b + b));
+  ivec3 r = tint_div(a, (b + b));
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/expressions/binary/div_by_zero/by_expression/vec3-scalar/i32.wgsl.expected.msl b/test/tint/expressions/binary/div_by_zero/by_expression/vec3-scalar/i32.wgsl.expected.msl
index b2a2e6a..79b0f79 100644
--- a/test/tint/expressions/binary/div_by_zero/by_expression/vec3-scalar/i32.wgsl.expected.msl
+++ b/test/tint/expressions/binary/div_by_zero/by_expression/vec3-scalar/i32.wgsl.expected.msl
@@ -1,10 +1,15 @@
 #include <metal_stdlib>
 
 using namespace metal;
+int3 tint_div(int3 lhs, int rhs) {
+  int3 const r = int3(rhs);
+  return (lhs / select(r, int3(1), ((r == int3(0)) | ((lhs == int3((-2147483647 - 1))) & (r == int3(-1))))));
+}
+
 kernel void f() {
   int3 a = int3(1, 2, 3);
   int b = 0;
-  int3 const r = (a / as_type<int>((as_type<uint>(b) + as_type<uint>(b))));
+  int3 const r = tint_div(a, as_type<int>((as_type<uint>(b) + as_type<uint>(b))));
   return;
 }
 
diff --git a/test/tint/expressions/binary/div_by_zero/by_expression/vec3-scalar/i32.wgsl.expected.spvasm b/test/tint/expressions/binary/div_by_zero/by_expression/vec3-scalar/i32.wgsl.expected.spvasm
index 565dd46..a07a5ea 100644
--- a/test/tint/expressions/binary/div_by_zero/by_expression/vec3-scalar/i32.wgsl.expected.spvasm
+++ b/test/tint/expressions/binary/div_by_zero/by_expression/vec3-scalar/i32.wgsl.expected.spvasm
@@ -1,39 +1,62 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 24
+; Bound: 42
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %f "f"
                OpExecutionMode %f LocalSize 1 1 1
+               OpName %tint_div "tint_div"
+               OpName %lhs "lhs"
+               OpName %rhs "rhs"
                OpName %f "f"
                OpName %a "a"
                OpName %b "b"
-       %void = OpTypeVoid
-          %1 = OpTypeFunction %void
         %int = OpTypeInt 32 1
       %v3int = OpTypeVector %int 3
+          %1 = OpTypeFunction %v3int %v3int %int
+         %10 = OpConstantNull %v3int
+       %bool = OpTypeBool
+     %v3bool = OpTypeVector %bool 3
+%int_n2147483648 = OpConstant %int -2147483648
+         %15 = OpConstantComposite %v3int %int_n2147483648 %int_n2147483648 %int_n2147483648
+     %int_n1 = OpConstant %int -1
+         %18 = OpConstantComposite %v3int %int_n1 %int_n1 %int_n1
       %int_1 = OpConstant %int 1
+         %23 = OpConstantComposite %v3int %int_1 %int_1 %int_1
+       %void = OpTypeVoid
+         %25 = OpTypeFunction %void
       %int_2 = OpConstant %int 2
       %int_3 = OpConstant %int 3
-         %10 = OpConstantComposite %v3int %int_1 %int_2 %int_3
+         %31 = OpConstantComposite %v3int %int_1 %int_2 %int_3
 %_ptr_Function_v3int = OpTypePointer Function %v3int
-         %13 = OpConstantNull %v3int
-         %14 = OpConstantNull %int
+         %34 = OpConstantNull %int
 %_ptr_Function_int = OpTypePointer Function %int
-          %f = OpFunction %void None %1
-          %4 = OpLabel
-          %a = OpVariable %_ptr_Function_v3int Function %13
-          %b = OpVariable %_ptr_Function_int Function %14
-         %22 = OpVariable %_ptr_Function_v3int Function %13
-               OpStore %a %10
-               OpStore %b %14
-         %17 = OpLoad %v3int %a
-         %18 = OpLoad %int %b
-         %19 = OpLoad %int %b
-         %20 = OpIAdd %int %18 %19
-         %23 = OpCompositeConstruct %v3int %20 %20 %20
-         %21 = OpSDiv %v3int %17 %23
+   %tint_div = OpFunction %v3int None %1
+        %lhs = OpFunctionParameter %v3int
+        %rhs = OpFunctionParameter %int
+          %7 = OpLabel
+          %8 = OpCompositeConstruct %v3int %rhs %rhs %rhs
+         %11 = OpIEqual %v3bool %8 %10
+         %16 = OpIEqual %v3bool %lhs %15
+         %19 = OpIEqual %v3bool %8 %18
+         %20 = OpLogicalAnd %v3bool %16 %19
+         %21 = OpLogicalOr %v3bool %11 %20
+          %9 = OpSelect %v3int %21 %23 %8
+         %24 = OpSDiv %v3int %lhs %9
+               OpReturnValue %24
+               OpFunctionEnd
+          %f = OpFunction %void None %25
+         %28 = OpLabel
+          %a = OpVariable %_ptr_Function_v3int Function %10
+          %b = OpVariable %_ptr_Function_int Function %34
+               OpStore %a %31
+               OpStore %b %34
+         %38 = OpLoad %v3int %a
+         %39 = OpLoad %int %b
+         %40 = OpLoad %int %b
+         %41 = OpIAdd %int %39 %40
+         %37 = OpFunctionCall %v3int %tint_div %38 %41
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/expressions/binary/div_by_zero/by_expression/vec3-scalar/u32.wgsl.expected.dxc.hlsl b/test/tint/expressions/binary/div_by_zero/by_expression/vec3-scalar/u32.wgsl.expected.dxc.hlsl
index f4bd21b..9ef2147 100644
--- a/test/tint/expressions/binary/div_by_zero/by_expression/vec3-scalar/u32.wgsl.expected.dxc.hlsl
+++ b/test/tint/expressions/binary/div_by_zero/by_expression/vec3-scalar/u32.wgsl.expected.dxc.hlsl
@@ -1,11 +1,12 @@
-uint value_or_one_if_zero_uint(uint value) {
-  return value == 0u ? 1u : value;
+uint3 tint_div(uint3 lhs, uint rhs) {
+  const uint3 r = uint3((rhs).xxx);
+  return (lhs / ((r == (0u).xxx) ? (1u).xxx : r));
 }
 
 [numthreads(1, 1, 1)]
 void f() {
   uint3 a = uint3(1u, 2u, 3u);
   uint b = 0u;
-  const uint3 r = (a / value_or_one_if_zero_uint((b + b)));
+  const uint3 r = tint_div(a, (b + b));
   return;
 }
diff --git a/test/tint/expressions/binary/div_by_zero/by_expression/vec3-scalar/u32.wgsl.expected.fxc.hlsl b/test/tint/expressions/binary/div_by_zero/by_expression/vec3-scalar/u32.wgsl.expected.fxc.hlsl
index f4bd21b..9ef2147 100644
--- a/test/tint/expressions/binary/div_by_zero/by_expression/vec3-scalar/u32.wgsl.expected.fxc.hlsl
+++ b/test/tint/expressions/binary/div_by_zero/by_expression/vec3-scalar/u32.wgsl.expected.fxc.hlsl
@@ -1,11 +1,12 @@
-uint value_or_one_if_zero_uint(uint value) {
-  return value == 0u ? 1u : value;
+uint3 tint_div(uint3 lhs, uint rhs) {
+  const uint3 r = uint3((rhs).xxx);
+  return (lhs / ((r == (0u).xxx) ? (1u).xxx : r));
 }
 
 [numthreads(1, 1, 1)]
 void f() {
   uint3 a = uint3(1u, 2u, 3u);
   uint b = 0u;
-  const uint3 r = (a / value_or_one_if_zero_uint((b + b)));
+  const uint3 r = tint_div(a, (b + b));
   return;
 }
diff --git a/test/tint/expressions/binary/div_by_zero/by_expression/vec3-scalar/u32.wgsl.expected.glsl b/test/tint/expressions/binary/div_by_zero/by_expression/vec3-scalar/u32.wgsl.expected.glsl
index e592a96..4f7e3f3 100644
--- a/test/tint/expressions/binary/div_by_zero/by_expression/vec3-scalar/u32.wgsl.expected.glsl
+++ b/test/tint/expressions/binary/div_by_zero/by_expression/vec3-scalar/u32.wgsl.expected.glsl
@@ -1,9 +1,14 @@
 #version 310 es
 
+uvec3 tint_div(uvec3 lhs, uint rhs) {
+  uvec3 r = uvec3(rhs);
+  return (lhs / mix(r, uvec3(1u), equal(r, uvec3(0u))));
+}
+
 void f() {
   uvec3 a = uvec3(1u, 2u, 3u);
   uint b = 0u;
-  uvec3 r = (a / (b + b));
+  uvec3 r = tint_div(a, (b + b));
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/expressions/binary/div_by_zero/by_expression/vec3-scalar/u32.wgsl.expected.msl b/test/tint/expressions/binary/div_by_zero/by_expression/vec3-scalar/u32.wgsl.expected.msl
index 05e7e6e..b2df05c 100644
--- a/test/tint/expressions/binary/div_by_zero/by_expression/vec3-scalar/u32.wgsl.expected.msl
+++ b/test/tint/expressions/binary/div_by_zero/by_expression/vec3-scalar/u32.wgsl.expected.msl
@@ -1,10 +1,15 @@
 #include <metal_stdlib>
 
 using namespace metal;
+uint3 tint_div(uint3 lhs, uint rhs) {
+  uint3 const r = uint3(rhs);
+  return (lhs / select(r, uint3(1u), (r == uint3(0u))));
+}
+
 kernel void f() {
   uint3 a = uint3(1u, 2u, 3u);
   uint b = 0u;
-  uint3 const r = (a / (b + b));
+  uint3 const r = tint_div(a, (b + b));
   return;
 }
 
diff --git a/test/tint/expressions/binary/div_by_zero/by_expression/vec3-scalar/u32.wgsl.expected.spvasm b/test/tint/expressions/binary/div_by_zero/by_expression/vec3-scalar/u32.wgsl.expected.spvasm
index 726b715..3fe925b 100644
--- a/test/tint/expressions/binary/div_by_zero/by_expression/vec3-scalar/u32.wgsl.expected.spvasm
+++ b/test/tint/expressions/binary/div_by_zero/by_expression/vec3-scalar/u32.wgsl.expected.spvasm
@@ -1,39 +1,54 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 24
+; Bound: 34
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %f "f"
                OpExecutionMode %f LocalSize 1 1 1
+               OpName %tint_div "tint_div"
+               OpName %lhs "lhs"
+               OpName %rhs "rhs"
                OpName %f "f"
                OpName %a "a"
                OpName %b "b"
-       %void = OpTypeVoid
-          %1 = OpTypeFunction %void
        %uint = OpTypeInt 32 0
      %v3uint = OpTypeVector %uint 3
+          %1 = OpTypeFunction %v3uint %v3uint %uint
+         %10 = OpConstantNull %v3uint
+       %bool = OpTypeBool
+     %v3bool = OpTypeVector %bool 3
      %uint_1 = OpConstant %uint 1
+         %15 = OpConstantComposite %v3uint %uint_1 %uint_1 %uint_1
+       %void = OpTypeVoid
+         %17 = OpTypeFunction %void
      %uint_2 = OpConstant %uint 2
      %uint_3 = OpConstant %uint 3
-         %10 = OpConstantComposite %v3uint %uint_1 %uint_2 %uint_3
+         %23 = OpConstantComposite %v3uint %uint_1 %uint_2 %uint_3
 %_ptr_Function_v3uint = OpTypePointer Function %v3uint
-         %13 = OpConstantNull %v3uint
-         %14 = OpConstantNull %uint
+         %26 = OpConstantNull %uint
 %_ptr_Function_uint = OpTypePointer Function %uint
-          %f = OpFunction %void None %1
-          %4 = OpLabel
-          %a = OpVariable %_ptr_Function_v3uint Function %13
-          %b = OpVariable %_ptr_Function_uint Function %14
-         %22 = OpVariable %_ptr_Function_v3uint Function %13
-               OpStore %a %10
-               OpStore %b %14
-         %17 = OpLoad %v3uint %a
-         %18 = OpLoad %uint %b
-         %19 = OpLoad %uint %b
-         %20 = OpIAdd %uint %18 %19
-         %23 = OpCompositeConstruct %v3uint %20 %20 %20
-         %21 = OpUDiv %v3uint %17 %23
+   %tint_div = OpFunction %v3uint None %1
+        %lhs = OpFunctionParameter %v3uint
+        %rhs = OpFunctionParameter %uint
+          %7 = OpLabel
+          %8 = OpCompositeConstruct %v3uint %rhs %rhs %rhs
+         %11 = OpIEqual %v3bool %8 %10
+          %9 = OpSelect %v3uint %11 %15 %8
+         %16 = OpUDiv %v3uint %lhs %9
+               OpReturnValue %16
+               OpFunctionEnd
+          %f = OpFunction %void None %17
+         %20 = OpLabel
+          %a = OpVariable %_ptr_Function_v3uint Function %10
+          %b = OpVariable %_ptr_Function_uint Function %26
+               OpStore %a %23
+               OpStore %b %26
+         %30 = OpLoad %v3uint %a
+         %31 = OpLoad %uint %b
+         %32 = OpLoad %uint %b
+         %33 = OpIAdd %uint %31 %32
+         %29 = OpFunctionCall %v3uint %tint_div %30 %33
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/expressions/binary/div_by_zero/by_expression/vec3-vec3/i32.wgsl.expected.dxc.hlsl b/test/tint/expressions/binary/div_by_zero/by_expression/vec3-vec3/i32.wgsl.expected.dxc.hlsl
index fefc614..dd810ea 100644
--- a/test/tint/expressions/binary/div_by_zero/by_expression/vec3-vec3/i32.wgsl.expected.dxc.hlsl
+++ b/test/tint/expressions/binary/div_by_zero/by_expression/vec3-vec3/i32.wgsl.expected.dxc.hlsl
@@ -1,11 +1,11 @@
-int3 value_or_one_if_zero_int3(int3 value) {
-  return value == int3(0, 0, 0) ? int3(1, 1, 1) : value;
+int3 tint_div(int3 lhs, int3 rhs) {
+  return (lhs / (((rhs == (0).xxx) | ((lhs == (-2147483648).xxx) & (rhs == (-1).xxx))) ? (1).xxx : rhs));
 }
 
 [numthreads(1, 1, 1)]
 void f() {
   int3 a = int3(1, 2, 3);
   int3 b = int3(0, 5, 0);
-  const int3 r = (a / value_or_one_if_zero_int3((b + b)));
+  const int3 r = tint_div(a, (b + b));
   return;
 }
diff --git a/test/tint/expressions/binary/div_by_zero/by_expression/vec3-vec3/i32.wgsl.expected.fxc.hlsl b/test/tint/expressions/binary/div_by_zero/by_expression/vec3-vec3/i32.wgsl.expected.fxc.hlsl
index fefc614..dd810ea 100644
--- a/test/tint/expressions/binary/div_by_zero/by_expression/vec3-vec3/i32.wgsl.expected.fxc.hlsl
+++ b/test/tint/expressions/binary/div_by_zero/by_expression/vec3-vec3/i32.wgsl.expected.fxc.hlsl
@@ -1,11 +1,11 @@
-int3 value_or_one_if_zero_int3(int3 value) {
-  return value == int3(0, 0, 0) ? int3(1, 1, 1) : value;
+int3 tint_div(int3 lhs, int3 rhs) {
+  return (lhs / (((rhs == (0).xxx) | ((lhs == (-2147483648).xxx) & (rhs == (-1).xxx))) ? (1).xxx : rhs));
 }
 
 [numthreads(1, 1, 1)]
 void f() {
   int3 a = int3(1, 2, 3);
   int3 b = int3(0, 5, 0);
-  const int3 r = (a / value_or_one_if_zero_int3((b + b)));
+  const int3 r = tint_div(a, (b + b));
   return;
 }
diff --git a/test/tint/expressions/binary/div_by_zero/by_expression/vec3-vec3/i32.wgsl.expected.glsl b/test/tint/expressions/binary/div_by_zero/by_expression/vec3-vec3/i32.wgsl.expected.glsl
index a4756fb..36f0cc2 100644
--- a/test/tint/expressions/binary/div_by_zero/by_expression/vec3-vec3/i32.wgsl.expected.glsl
+++ b/test/tint/expressions/binary/div_by_zero/by_expression/vec3-vec3/i32.wgsl.expected.glsl
@@ -1,9 +1,13 @@
 #version 310 es
 
+ivec3 tint_div(ivec3 lhs, ivec3 rhs) {
+  return (lhs / mix(rhs, ivec3(1), bvec3(uvec3(equal(rhs, ivec3(0))) | uvec3(bvec3(uvec3(equal(lhs, ivec3(-2147483648))) & uvec3(equal(rhs, ivec3(-1))))))));
+}
+
 void f() {
   ivec3 a = ivec3(1, 2, 3);
   ivec3 b = ivec3(0, 5, 0);
-  ivec3 r = (a / (b + b));
+  ivec3 r = tint_div(a, (b + b));
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/expressions/binary/div_by_zero/by_expression/vec3-vec3/i32.wgsl.expected.msl b/test/tint/expressions/binary/div_by_zero/by_expression/vec3-vec3/i32.wgsl.expected.msl
index e2a2a76..8c124b5 100644
--- a/test/tint/expressions/binary/div_by_zero/by_expression/vec3-vec3/i32.wgsl.expected.msl
+++ b/test/tint/expressions/binary/div_by_zero/by_expression/vec3-vec3/i32.wgsl.expected.msl
@@ -1,10 +1,14 @@
 #include <metal_stdlib>
 
 using namespace metal;
+int3 tint_div(int3 lhs, int3 rhs) {
+  return (lhs / select(rhs, int3(1), ((rhs == int3(0)) | ((lhs == int3((-2147483647 - 1))) & (rhs == int3(-1))))));
+}
+
 kernel void f() {
   int3 a = int3(1, 2, 3);
   int3 b = int3(0, 5, 0);
-  int3 const r = (a / as_type<int3>((as_type<uint3>(b) + as_type<uint3>(b))));
+  int3 const r = tint_div(a, as_type<int3>((as_type<uint3>(b) + as_type<uint3>(b))));
   return;
 }
 
diff --git a/test/tint/expressions/binary/div_by_zero/by_expression/vec3-vec3/i32.wgsl.expected.spvasm b/test/tint/expressions/binary/div_by_zero/by_expression/vec3-vec3/i32.wgsl.expected.spvasm
index 03b642c..75ecf795 100644
--- a/test/tint/expressions/binary/div_by_zero/by_expression/vec3-vec3/i32.wgsl.expected.spvasm
+++ b/test/tint/expressions/binary/div_by_zero/by_expression/vec3-vec3/i32.wgsl.expected.spvasm
@@ -1,38 +1,62 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 23
+; Bound: 42
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %f "f"
                OpExecutionMode %f LocalSize 1 1 1
+               OpName %tint_div "tint_div"
+               OpName %lhs "lhs"
+               OpName %rhs "rhs"
                OpName %f "f"
                OpName %a "a"
                OpName %b "b"
-       %void = OpTypeVoid
-          %1 = OpTypeFunction %void
         %int = OpTypeInt 32 1
       %v3int = OpTypeVector %int 3
+          %1 = OpTypeFunction %v3int %v3int %v3int
+          %9 = OpConstantNull %v3int
+       %bool = OpTypeBool
+     %v3bool = OpTypeVector %bool 3
+%int_n2147483648 = OpConstant %int -2147483648
+         %14 = OpConstantComposite %v3int %int_n2147483648 %int_n2147483648 %int_n2147483648
+     %int_n1 = OpConstant %int -1
+         %17 = OpConstantComposite %v3int %int_n1 %int_n1 %int_n1
       %int_1 = OpConstant %int 1
+         %22 = OpConstantComposite %v3int %int_1 %int_1 %int_1
+       %void = OpTypeVoid
+         %24 = OpTypeFunction %void
       %int_2 = OpConstant %int 2
       %int_3 = OpConstant %int 3
-         %10 = OpConstantComposite %v3int %int_1 %int_2 %int_3
+         %30 = OpConstantComposite %v3int %int_1 %int_2 %int_3
 %_ptr_Function_v3int = OpTypePointer Function %v3int
-         %13 = OpConstantNull %v3int
-         %14 = OpConstantNull %int
+         %33 = OpConstantNull %int
       %int_5 = OpConstant %int 5
-         %16 = OpConstantComposite %v3int %14 %int_5 %14
-          %f = OpFunction %void None %1
-          %4 = OpLabel
-          %a = OpVariable %_ptr_Function_v3int Function %13
-          %b = OpVariable %_ptr_Function_v3int Function %13
-               OpStore %a %10
-               OpStore %b %16
-         %18 = OpLoad %v3int %a
-         %19 = OpLoad %v3int %b
-         %20 = OpLoad %v3int %b
-         %21 = OpIAdd %v3int %19 %20
-         %22 = OpSDiv %v3int %18 %21
+         %35 = OpConstantComposite %v3int %33 %int_5 %33
+   %tint_div = OpFunction %v3int None %1
+        %lhs = OpFunctionParameter %v3int
+        %rhs = OpFunctionParameter %v3int
+          %7 = OpLabel
+         %10 = OpIEqual %v3bool %rhs %9
+         %15 = OpIEqual %v3bool %lhs %14
+         %18 = OpIEqual %v3bool %rhs %17
+         %19 = OpLogicalAnd %v3bool %15 %18
+         %20 = OpLogicalOr %v3bool %10 %19
+          %8 = OpSelect %v3int %20 %22 %rhs
+         %23 = OpSDiv %v3int %lhs %8
+               OpReturnValue %23
+               OpFunctionEnd
+          %f = OpFunction %void None %24
+         %27 = OpLabel
+          %a = OpVariable %_ptr_Function_v3int Function %9
+          %b = OpVariable %_ptr_Function_v3int Function %9
+               OpStore %a %30
+               OpStore %b %35
+         %38 = OpLoad %v3int %a
+         %39 = OpLoad %v3int %b
+         %40 = OpLoad %v3int %b
+         %41 = OpIAdd %v3int %39 %40
+         %37 = OpFunctionCall %v3int %tint_div %38 %41
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/expressions/binary/div_by_zero/by_expression/vec3-vec3/u32.wgsl.expected.dxc.hlsl b/test/tint/expressions/binary/div_by_zero/by_expression/vec3-vec3/u32.wgsl.expected.dxc.hlsl
index 841bf62..d8a010e 100644
--- a/test/tint/expressions/binary/div_by_zero/by_expression/vec3-vec3/u32.wgsl.expected.dxc.hlsl
+++ b/test/tint/expressions/binary/div_by_zero/by_expression/vec3-vec3/u32.wgsl.expected.dxc.hlsl
@@ -1,11 +1,11 @@
-uint3 value_or_one_if_zero_uint3(uint3 value) {
-  return value == uint3(0u, 0u, 0u) ? uint3(1u, 1u, 1u) : value;
+uint3 tint_div(uint3 lhs, uint3 rhs) {
+  return (lhs / ((rhs == (0u).xxx) ? (1u).xxx : rhs));
 }
 
 [numthreads(1, 1, 1)]
 void f() {
   uint3 a = uint3(1u, 2u, 3u);
   uint3 b = uint3(0u, 5u, 0u);
-  const uint3 r = (a / value_or_one_if_zero_uint3((b + b)));
+  const uint3 r = tint_div(a, (b + b));
   return;
 }
diff --git a/test/tint/expressions/binary/div_by_zero/by_expression/vec3-vec3/u32.wgsl.expected.fxc.hlsl b/test/tint/expressions/binary/div_by_zero/by_expression/vec3-vec3/u32.wgsl.expected.fxc.hlsl
index 841bf62..d8a010e 100644
--- a/test/tint/expressions/binary/div_by_zero/by_expression/vec3-vec3/u32.wgsl.expected.fxc.hlsl
+++ b/test/tint/expressions/binary/div_by_zero/by_expression/vec3-vec3/u32.wgsl.expected.fxc.hlsl
@@ -1,11 +1,11 @@
-uint3 value_or_one_if_zero_uint3(uint3 value) {
-  return value == uint3(0u, 0u, 0u) ? uint3(1u, 1u, 1u) : value;
+uint3 tint_div(uint3 lhs, uint3 rhs) {
+  return (lhs / ((rhs == (0u).xxx) ? (1u).xxx : rhs));
 }
 
 [numthreads(1, 1, 1)]
 void f() {
   uint3 a = uint3(1u, 2u, 3u);
   uint3 b = uint3(0u, 5u, 0u);
-  const uint3 r = (a / value_or_one_if_zero_uint3((b + b)));
+  const uint3 r = tint_div(a, (b + b));
   return;
 }
diff --git a/test/tint/expressions/binary/div_by_zero/by_expression/vec3-vec3/u32.wgsl.expected.glsl b/test/tint/expressions/binary/div_by_zero/by_expression/vec3-vec3/u32.wgsl.expected.glsl
index 567059c..22846e6 100644
--- a/test/tint/expressions/binary/div_by_zero/by_expression/vec3-vec3/u32.wgsl.expected.glsl
+++ b/test/tint/expressions/binary/div_by_zero/by_expression/vec3-vec3/u32.wgsl.expected.glsl
@@ -1,9 +1,13 @@
 #version 310 es
 
+uvec3 tint_div(uvec3 lhs, uvec3 rhs) {
+  return (lhs / mix(rhs, uvec3(1u), equal(rhs, uvec3(0u))));
+}
+
 void f() {
   uvec3 a = uvec3(1u, 2u, 3u);
   uvec3 b = uvec3(0u, 5u, 0u);
-  uvec3 r = (a / (b + b));
+  uvec3 r = tint_div(a, (b + b));
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/expressions/binary/div_by_zero/by_expression/vec3-vec3/u32.wgsl.expected.msl b/test/tint/expressions/binary/div_by_zero/by_expression/vec3-vec3/u32.wgsl.expected.msl
index e055047..781eb55 100644
--- a/test/tint/expressions/binary/div_by_zero/by_expression/vec3-vec3/u32.wgsl.expected.msl
+++ b/test/tint/expressions/binary/div_by_zero/by_expression/vec3-vec3/u32.wgsl.expected.msl
@@ -1,10 +1,14 @@
 #include <metal_stdlib>
 
 using namespace metal;
+uint3 tint_div(uint3 lhs, uint3 rhs) {
+  return (lhs / select(rhs, uint3(1u), (rhs == uint3(0u))));
+}
+
 kernel void f() {
   uint3 a = uint3(1u, 2u, 3u);
   uint3 b = uint3(0u, 5u, 0u);
-  uint3 const r = (a / (b + b));
+  uint3 const r = tint_div(a, (b + b));
   return;
 }
 
diff --git a/test/tint/expressions/binary/div_by_zero/by_expression/vec3-vec3/u32.wgsl.expected.spvasm b/test/tint/expressions/binary/div_by_zero/by_expression/vec3-vec3/u32.wgsl.expected.spvasm
index 9cde60a..56eee5f 100644
--- a/test/tint/expressions/binary/div_by_zero/by_expression/vec3-vec3/u32.wgsl.expected.spvasm
+++ b/test/tint/expressions/binary/div_by_zero/by_expression/vec3-vec3/u32.wgsl.expected.spvasm
@@ -1,38 +1,54 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 23
+; Bound: 34
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %f "f"
                OpExecutionMode %f LocalSize 1 1 1
+               OpName %tint_div "tint_div"
+               OpName %lhs "lhs"
+               OpName %rhs "rhs"
                OpName %f "f"
                OpName %a "a"
                OpName %b "b"
-       %void = OpTypeVoid
-          %1 = OpTypeFunction %void
        %uint = OpTypeInt 32 0
      %v3uint = OpTypeVector %uint 3
+          %1 = OpTypeFunction %v3uint %v3uint %v3uint
+          %9 = OpConstantNull %v3uint
+       %bool = OpTypeBool
+     %v3bool = OpTypeVector %bool 3
      %uint_1 = OpConstant %uint 1
+         %14 = OpConstantComposite %v3uint %uint_1 %uint_1 %uint_1
+       %void = OpTypeVoid
+         %16 = OpTypeFunction %void
      %uint_2 = OpConstant %uint 2
      %uint_3 = OpConstant %uint 3
-         %10 = OpConstantComposite %v3uint %uint_1 %uint_2 %uint_3
+         %22 = OpConstantComposite %v3uint %uint_1 %uint_2 %uint_3
 %_ptr_Function_v3uint = OpTypePointer Function %v3uint
-         %13 = OpConstantNull %v3uint
-         %14 = OpConstantNull %uint
+         %25 = OpConstantNull %uint
      %uint_5 = OpConstant %uint 5
-         %16 = OpConstantComposite %v3uint %14 %uint_5 %14
-          %f = OpFunction %void None %1
-          %4 = OpLabel
-          %a = OpVariable %_ptr_Function_v3uint Function %13
-          %b = OpVariable %_ptr_Function_v3uint Function %13
-               OpStore %a %10
-               OpStore %b %16
-         %18 = OpLoad %v3uint %a
-         %19 = OpLoad %v3uint %b
-         %20 = OpLoad %v3uint %b
-         %21 = OpIAdd %v3uint %19 %20
-         %22 = OpUDiv %v3uint %18 %21
+         %27 = OpConstantComposite %v3uint %25 %uint_5 %25
+   %tint_div = OpFunction %v3uint None %1
+        %lhs = OpFunctionParameter %v3uint
+        %rhs = OpFunctionParameter %v3uint
+          %7 = OpLabel
+         %10 = OpIEqual %v3bool %rhs %9
+          %8 = OpSelect %v3uint %10 %14 %rhs
+         %15 = OpUDiv %v3uint %lhs %8
+               OpReturnValue %15
+               OpFunctionEnd
+          %f = OpFunction %void None %16
+         %19 = OpLabel
+          %a = OpVariable %_ptr_Function_v3uint Function %9
+          %b = OpVariable %_ptr_Function_v3uint Function %9
+               OpStore %a %22
+               OpStore %b %27
+         %30 = OpLoad %v3uint %a
+         %31 = OpLoad %v3uint %b
+         %32 = OpLoad %v3uint %b
+         %33 = OpIAdd %v3uint %31 %32
+         %29 = OpFunctionCall %v3uint %tint_div %30 %33
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/expressions/binary/div_by_zero/by_identifier/scalar-scalar/i32.wgsl.expected.dxc.hlsl b/test/tint/expressions/binary/div_by_zero/by_identifier/scalar-scalar/i32.wgsl.expected.dxc.hlsl
index 111cfc9..dcf5a24 100644
--- a/test/tint/expressions/binary/div_by_zero/by_identifier/scalar-scalar/i32.wgsl.expected.dxc.hlsl
+++ b/test/tint/expressions/binary/div_by_zero/by_identifier/scalar-scalar/i32.wgsl.expected.dxc.hlsl
@@ -1,7 +1,11 @@
+int tint_div(int lhs, int rhs) {
+  return (lhs / (((rhs == 0) | ((lhs == -2147483648) & (rhs == -1))) ? 1 : rhs));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   int a = 1;
   int b = 0;
-  const int r = (a / (b == 0 ? 1 : b));
+  const int r = tint_div(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/div_by_zero/by_identifier/scalar-scalar/i32.wgsl.expected.fxc.hlsl b/test/tint/expressions/binary/div_by_zero/by_identifier/scalar-scalar/i32.wgsl.expected.fxc.hlsl
index 111cfc9..dcf5a24 100644
--- a/test/tint/expressions/binary/div_by_zero/by_identifier/scalar-scalar/i32.wgsl.expected.fxc.hlsl
+++ b/test/tint/expressions/binary/div_by_zero/by_identifier/scalar-scalar/i32.wgsl.expected.fxc.hlsl
@@ -1,7 +1,11 @@
+int tint_div(int lhs, int rhs) {
+  return (lhs / (((rhs == 0) | ((lhs == -2147483648) & (rhs == -1))) ? 1 : rhs));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   int a = 1;
   int b = 0;
-  const int r = (a / (b == 0 ? 1 : b));
+  const int r = tint_div(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/div_by_zero/by_identifier/scalar-scalar/i32.wgsl.expected.glsl b/test/tint/expressions/binary/div_by_zero/by_identifier/scalar-scalar/i32.wgsl.expected.glsl
index 8ec81fd..5cdd988 100644
--- a/test/tint/expressions/binary/div_by_zero/by_identifier/scalar-scalar/i32.wgsl.expected.glsl
+++ b/test/tint/expressions/binary/div_by_zero/by_identifier/scalar-scalar/i32.wgsl.expected.glsl
@@ -1,9 +1,13 @@
 #version 310 es
 
+int tint_div(int lhs, int rhs) {
+  return (lhs / (bool(uint((rhs == 0)) | uint(bool(uint((lhs == -2147483648)) & uint((rhs == -1))))) ? 1 : rhs));
+}
+
 void f() {
   int a = 1;
   int b = 0;
-  int r = (a / b);
+  int r = tint_div(a, b);
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/expressions/binary/div_by_zero/by_identifier/scalar-scalar/i32.wgsl.expected.msl b/test/tint/expressions/binary/div_by_zero/by_identifier/scalar-scalar/i32.wgsl.expected.msl
index a3201dc..4968408 100644
--- a/test/tint/expressions/binary/div_by_zero/by_identifier/scalar-scalar/i32.wgsl.expected.msl
+++ b/test/tint/expressions/binary/div_by_zero/by_identifier/scalar-scalar/i32.wgsl.expected.msl
@@ -1,10 +1,14 @@
 #include <metal_stdlib>
 
 using namespace metal;
+int tint_div(int lhs, int rhs) {
+  return (lhs / select(rhs, 1, bool((rhs == 0) | bool((lhs == (-2147483647 - 1)) & (rhs == -1)))));
+}
+
 kernel void f() {
   int a = 1;
   int b = 0;
-  int const r = (a / b);
+  int const r = tint_div(a, b);
   return;
 }
 
diff --git a/test/tint/expressions/binary/div_by_zero/by_identifier/scalar-scalar/i32.wgsl.expected.spvasm b/test/tint/expressions/binary/div_by_zero/by_identifier/scalar-scalar/i32.wgsl.expected.spvasm
index 96e1544..dbb1acf 100644
--- a/test/tint/expressions/binary/div_by_zero/by_identifier/scalar-scalar/i32.wgsl.expected.spvasm
+++ b/test/tint/expressions/binary/div_by_zero/by_identifier/scalar-scalar/i32.wgsl.expected.spvasm
@@ -1,29 +1,49 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 14
+; Bound: 29
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %f "f"
                OpExecutionMode %f LocalSize 1 1 1
+               OpName %tint_div "tint_div"
+               OpName %lhs "lhs"
+               OpName %rhs "rhs"
                OpName %f "f"
                OpName %a "a"
                OpName %b "b"
-       %void = OpTypeVoid
-          %1 = OpTypeFunction %void
         %int = OpTypeInt 32 1
+          %1 = OpTypeFunction %int %int %int
+          %8 = OpConstantNull %int
+       %bool = OpTypeBool
+%int_n2147483648 = OpConstant %int -2147483648
+     %int_n1 = OpConstant %int -1
       %int_1 = OpConstant %int 1
+       %void = OpTypeVoid
+         %19 = OpTypeFunction %void
 %_ptr_Function_int = OpTypePointer Function %int
-          %9 = OpConstantNull %int
-          %f = OpFunction %void None %1
-          %4 = OpLabel
-          %a = OpVariable %_ptr_Function_int Function %9
-          %b = OpVariable %_ptr_Function_int Function %9
+   %tint_div = OpFunction %int None %1
+        %lhs = OpFunctionParameter %int
+        %rhs = OpFunctionParameter %int
+          %6 = OpLabel
+          %9 = OpIEqual %bool %rhs %8
+         %12 = OpIEqual %bool %lhs %int_n2147483648
+         %14 = OpIEqual %bool %rhs %int_n1
+         %15 = OpLogicalAnd %bool %12 %14
+         %16 = OpLogicalOr %bool %9 %15
+          %7 = OpSelect %int %16 %int_1 %rhs
+         %18 = OpSDiv %int %lhs %7
+               OpReturnValue %18
+               OpFunctionEnd
+          %f = OpFunction %void None %19
+         %22 = OpLabel
+          %a = OpVariable %_ptr_Function_int Function %8
+          %b = OpVariable %_ptr_Function_int Function %8
                OpStore %a %int_1
-               OpStore %b %9
-         %11 = OpLoad %int %a
-         %12 = OpLoad %int %b
-         %13 = OpSDiv %int %11 %12
+               OpStore %b %8
+         %27 = OpLoad %int %a
+         %28 = OpLoad %int %b
+         %26 = OpFunctionCall %int %tint_div %27 %28
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/expressions/binary/div_by_zero/by_identifier/scalar-scalar/u32.wgsl.expected.dxc.hlsl b/test/tint/expressions/binary/div_by_zero/by_identifier/scalar-scalar/u32.wgsl.expected.dxc.hlsl
index 289c446..ffaaaba 100644
--- a/test/tint/expressions/binary/div_by_zero/by_identifier/scalar-scalar/u32.wgsl.expected.dxc.hlsl
+++ b/test/tint/expressions/binary/div_by_zero/by_identifier/scalar-scalar/u32.wgsl.expected.dxc.hlsl
@@ -1,7 +1,11 @@
+uint tint_div(uint lhs, uint rhs) {
+  return (lhs / ((rhs == 0u) ? 1u : rhs));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   uint a = 1u;
   uint b = 0u;
-  const uint r = (a / (b == 0u ? 1u : b));
+  const uint r = tint_div(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/div_by_zero/by_identifier/scalar-scalar/u32.wgsl.expected.fxc.hlsl b/test/tint/expressions/binary/div_by_zero/by_identifier/scalar-scalar/u32.wgsl.expected.fxc.hlsl
index 289c446..ffaaaba 100644
--- a/test/tint/expressions/binary/div_by_zero/by_identifier/scalar-scalar/u32.wgsl.expected.fxc.hlsl
+++ b/test/tint/expressions/binary/div_by_zero/by_identifier/scalar-scalar/u32.wgsl.expected.fxc.hlsl
@@ -1,7 +1,11 @@
+uint tint_div(uint lhs, uint rhs) {
+  return (lhs / ((rhs == 0u) ? 1u : rhs));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   uint a = 1u;
   uint b = 0u;
-  const uint r = (a / (b == 0u ? 1u : b));
+  const uint r = tint_div(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/div_by_zero/by_identifier/scalar-scalar/u32.wgsl.expected.glsl b/test/tint/expressions/binary/div_by_zero/by_identifier/scalar-scalar/u32.wgsl.expected.glsl
index aee0413..30a1f0c 100644
--- a/test/tint/expressions/binary/div_by_zero/by_identifier/scalar-scalar/u32.wgsl.expected.glsl
+++ b/test/tint/expressions/binary/div_by_zero/by_identifier/scalar-scalar/u32.wgsl.expected.glsl
@@ -1,9 +1,13 @@
 #version 310 es
 
+uint tint_div(uint lhs, uint rhs) {
+  return (lhs / ((rhs == 0u) ? 1u : rhs));
+}
+
 void f() {
   uint a = 1u;
   uint b = 0u;
-  uint r = (a / b);
+  uint r = tint_div(a, b);
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/expressions/binary/div_by_zero/by_identifier/scalar-scalar/u32.wgsl.expected.msl b/test/tint/expressions/binary/div_by_zero/by_identifier/scalar-scalar/u32.wgsl.expected.msl
index bf7517d..7c6233a 100644
--- a/test/tint/expressions/binary/div_by_zero/by_identifier/scalar-scalar/u32.wgsl.expected.msl
+++ b/test/tint/expressions/binary/div_by_zero/by_identifier/scalar-scalar/u32.wgsl.expected.msl
@@ -1,10 +1,14 @@
 #include <metal_stdlib>
 
 using namespace metal;
+uint tint_div(uint lhs, uint rhs) {
+  return (lhs / select(rhs, 1u, (rhs == 0u)));
+}
+
 kernel void f() {
   uint a = 1u;
   uint b = 0u;
-  uint const r = (a / b);
+  uint const r = tint_div(a, b);
   return;
 }
 
diff --git a/test/tint/expressions/binary/div_by_zero/by_identifier/scalar-scalar/u32.wgsl.expected.spvasm b/test/tint/expressions/binary/div_by_zero/by_identifier/scalar-scalar/u32.wgsl.expected.spvasm
index ce40e45..6ce20d2 100644
--- a/test/tint/expressions/binary/div_by_zero/by_identifier/scalar-scalar/u32.wgsl.expected.spvasm
+++ b/test/tint/expressions/binary/div_by_zero/by_identifier/scalar-scalar/u32.wgsl.expected.spvasm
@@ -1,29 +1,43 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 14
+; Bound: 23
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %f "f"
                OpExecutionMode %f LocalSize 1 1 1
+               OpName %tint_div "tint_div"
+               OpName %lhs "lhs"
+               OpName %rhs "rhs"
                OpName %f "f"
                OpName %a "a"
                OpName %b "b"
-       %void = OpTypeVoid
-          %1 = OpTypeFunction %void
        %uint = OpTypeInt 32 0
+          %1 = OpTypeFunction %uint %uint %uint
+          %8 = OpConstantNull %uint
+       %bool = OpTypeBool
      %uint_1 = OpConstant %uint 1
+       %void = OpTypeVoid
+         %13 = OpTypeFunction %void
 %_ptr_Function_uint = OpTypePointer Function %uint
-          %9 = OpConstantNull %uint
-          %f = OpFunction %void None %1
-          %4 = OpLabel
-          %a = OpVariable %_ptr_Function_uint Function %9
-          %b = OpVariable %_ptr_Function_uint Function %9
+   %tint_div = OpFunction %uint None %1
+        %lhs = OpFunctionParameter %uint
+        %rhs = OpFunctionParameter %uint
+          %6 = OpLabel
+          %9 = OpIEqual %bool %rhs %8
+          %7 = OpSelect %uint %9 %uint_1 %rhs
+         %12 = OpUDiv %uint %lhs %7
+               OpReturnValue %12
+               OpFunctionEnd
+          %f = OpFunction %void None %13
+         %16 = OpLabel
+          %a = OpVariable %_ptr_Function_uint Function %8
+          %b = OpVariable %_ptr_Function_uint Function %8
                OpStore %a %uint_1
-               OpStore %b %9
-         %11 = OpLoad %uint %a
-         %12 = OpLoad %uint %b
-         %13 = OpUDiv %uint %11 %12
+               OpStore %b %8
+         %21 = OpLoad %uint %a
+         %22 = OpLoad %uint %b
+         %20 = OpFunctionCall %uint %tint_div %21 %22
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/expressions/binary/div_by_zero/by_identifier/scalar-vec3/i32.wgsl.expected.dxc.hlsl b/test/tint/expressions/binary/div_by_zero/by_identifier/scalar-vec3/i32.wgsl.expected.dxc.hlsl
index 24f0e8f..afaf8fa 100644
--- a/test/tint/expressions/binary/div_by_zero/by_identifier/scalar-vec3/i32.wgsl.expected.dxc.hlsl
+++ b/test/tint/expressions/binary/div_by_zero/by_identifier/scalar-vec3/i32.wgsl.expected.dxc.hlsl
@@ -1,7 +1,12 @@
+int3 tint_div(int lhs, int3 rhs) {
+  const int3 l = int3((lhs).xxx);
+  return (l / (((rhs == (0).xxx) | ((l == (-2147483648).xxx) & (rhs == (-1).xxx))) ? (1).xxx : rhs));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   int a = 4;
   int3 b = int3(0, 2, 0);
-  const int3 r = (a / (b == int3(0, 0, 0) ? int3(1, 1, 1) : b));
+  const int3 r = tint_div(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/div_by_zero/by_identifier/scalar-vec3/i32.wgsl.expected.fxc.hlsl b/test/tint/expressions/binary/div_by_zero/by_identifier/scalar-vec3/i32.wgsl.expected.fxc.hlsl
index 24f0e8f..afaf8fa 100644
--- a/test/tint/expressions/binary/div_by_zero/by_identifier/scalar-vec3/i32.wgsl.expected.fxc.hlsl
+++ b/test/tint/expressions/binary/div_by_zero/by_identifier/scalar-vec3/i32.wgsl.expected.fxc.hlsl
@@ -1,7 +1,12 @@
+int3 tint_div(int lhs, int3 rhs) {
+  const int3 l = int3((lhs).xxx);
+  return (l / (((rhs == (0).xxx) | ((l == (-2147483648).xxx) & (rhs == (-1).xxx))) ? (1).xxx : rhs));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   int a = 4;
   int3 b = int3(0, 2, 0);
-  const int3 r = (a / (b == int3(0, 0, 0) ? int3(1, 1, 1) : b));
+  const int3 r = tint_div(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/div_by_zero/by_identifier/scalar-vec3/i32.wgsl.expected.glsl b/test/tint/expressions/binary/div_by_zero/by_identifier/scalar-vec3/i32.wgsl.expected.glsl
index 2fdf8fe..a33eaa7 100644
--- a/test/tint/expressions/binary/div_by_zero/by_identifier/scalar-vec3/i32.wgsl.expected.glsl
+++ b/test/tint/expressions/binary/div_by_zero/by_identifier/scalar-vec3/i32.wgsl.expected.glsl
@@ -1,9 +1,14 @@
 #version 310 es
 
+ivec3 tint_div(int lhs, ivec3 rhs) {
+  ivec3 l = ivec3(lhs);
+  return (l / mix(rhs, ivec3(1), bvec3(uvec3(equal(rhs, ivec3(0))) | uvec3(bvec3(uvec3(equal(l, ivec3(-2147483648))) & uvec3(equal(rhs, ivec3(-1))))))));
+}
+
 void f() {
   int a = 4;
   ivec3 b = ivec3(0, 2, 0);
-  ivec3 r = (a / b);
+  ivec3 r = tint_div(a, b);
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/expressions/binary/div_by_zero/by_identifier/scalar-vec3/i32.wgsl.expected.msl b/test/tint/expressions/binary/div_by_zero/by_identifier/scalar-vec3/i32.wgsl.expected.msl
index 03ac311..f65bafb 100644
--- a/test/tint/expressions/binary/div_by_zero/by_identifier/scalar-vec3/i32.wgsl.expected.msl
+++ b/test/tint/expressions/binary/div_by_zero/by_identifier/scalar-vec3/i32.wgsl.expected.msl
@@ -1,10 +1,15 @@
 #include <metal_stdlib>
 
 using namespace metal;
+int3 tint_div(int lhs, int3 rhs) {
+  int3 const l = int3(lhs);
+  return (l / select(rhs, int3(1), ((rhs == int3(0)) | ((l == int3((-2147483647 - 1))) & (rhs == int3(-1))))));
+}
+
 kernel void f() {
   int a = 4;
   int3 b = int3(0, 2, 0);
-  int3 const r = (a / b);
+  int3 const r = tint_div(a, b);
   return;
 }
 
diff --git a/test/tint/expressions/binary/div_by_zero/by_identifier/scalar-vec3/i32.wgsl.expected.spvasm b/test/tint/expressions/binary/div_by_zero/by_identifier/scalar-vec3/i32.wgsl.expected.spvasm
index 34cd2cf..95c8583 100644
--- a/test/tint/expressions/binary/div_by_zero/by_identifier/scalar-vec3/i32.wgsl.expected.spvasm
+++ b/test/tint/expressions/binary/div_by_zero/by_identifier/scalar-vec3/i32.wgsl.expected.spvasm
@@ -1,36 +1,60 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 21
+; Bound: 40
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %f "f"
                OpExecutionMode %f LocalSize 1 1 1
+               OpName %tint_div "tint_div"
+               OpName %lhs "lhs"
+               OpName %rhs "rhs"
                OpName %f "f"
                OpName %a "a"
                OpName %b "b"
-       %void = OpTypeVoid
-          %1 = OpTypeFunction %void
         %int = OpTypeInt 32 1
+      %v3int = OpTypeVector %int 3
+          %1 = OpTypeFunction %v3int %int %v3int
+         %10 = OpConstantNull %v3int
+       %bool = OpTypeBool
+     %v3bool = OpTypeVector %bool 3
+%int_n2147483648 = OpConstant %int -2147483648
+         %15 = OpConstantComposite %v3int %int_n2147483648 %int_n2147483648 %int_n2147483648
+     %int_n1 = OpConstant %int -1
+         %18 = OpConstantComposite %v3int %int_n1 %int_n1 %int_n1
+      %int_1 = OpConstant %int 1
+         %23 = OpConstantComposite %v3int %int_1 %int_1 %int_1
+       %void = OpTypeVoid
+         %25 = OpTypeFunction %void
       %int_4 = OpConstant %int 4
 %_ptr_Function_int = OpTypePointer Function %int
-          %9 = OpConstantNull %int
-      %v3int = OpTypeVector %int 3
+         %32 = OpConstantNull %int
       %int_2 = OpConstant %int 2
-         %12 = OpConstantComposite %v3int %9 %int_2 %9
+         %34 = OpConstantComposite %v3int %32 %int_2 %32
 %_ptr_Function_v3int = OpTypePointer Function %v3int
-         %15 = OpConstantNull %v3int
-          %f = OpFunction %void None %1
-          %4 = OpLabel
-          %a = OpVariable %_ptr_Function_int Function %9
-          %b = OpVariable %_ptr_Function_v3int Function %15
-         %19 = OpVariable %_ptr_Function_v3int Function %15
+   %tint_div = OpFunction %v3int None %1
+        %lhs = OpFunctionParameter %int
+        %rhs = OpFunctionParameter %v3int
+          %7 = OpLabel
+          %8 = OpCompositeConstruct %v3int %lhs %lhs %lhs
+         %11 = OpIEqual %v3bool %rhs %10
+         %16 = OpIEqual %v3bool %8 %15
+         %19 = OpIEqual %v3bool %rhs %18
+         %20 = OpLogicalAnd %v3bool %16 %19
+         %21 = OpLogicalOr %v3bool %11 %20
+          %9 = OpSelect %v3int %21 %23 %rhs
+         %24 = OpSDiv %v3int %8 %9
+               OpReturnValue %24
+               OpFunctionEnd
+          %f = OpFunction %void None %25
+         %28 = OpLabel
+          %a = OpVariable %_ptr_Function_int Function %32
+          %b = OpVariable %_ptr_Function_v3int Function %10
                OpStore %a %int_4
-               OpStore %b %12
-         %16 = OpLoad %int %a
-         %17 = OpLoad %v3int %b
-         %20 = OpCompositeConstruct %v3int %16 %16 %16
-         %18 = OpSDiv %v3int %20 %17
+               OpStore %b %34
+         %38 = OpLoad %int %a
+         %39 = OpLoad %v3int %b
+         %37 = OpFunctionCall %v3int %tint_div %38 %39
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/expressions/binary/div_by_zero/by_identifier/scalar-vec3/u32.wgsl.expected.dxc.hlsl b/test/tint/expressions/binary/div_by_zero/by_identifier/scalar-vec3/u32.wgsl.expected.dxc.hlsl
index 0692d21..930f742 100644
--- a/test/tint/expressions/binary/div_by_zero/by_identifier/scalar-vec3/u32.wgsl.expected.dxc.hlsl
+++ b/test/tint/expressions/binary/div_by_zero/by_identifier/scalar-vec3/u32.wgsl.expected.dxc.hlsl
@@ -1,7 +1,12 @@
+uint3 tint_div(uint lhs, uint3 rhs) {
+  const uint3 l = uint3((lhs).xxx);
+  return (l / ((rhs == (0u).xxx) ? (1u).xxx : rhs));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   uint a = 4u;
   uint3 b = uint3(0u, 2u, 0u);
-  const uint3 r = (a / (b == uint3(0u, 0u, 0u) ? uint3(1u, 1u, 1u) : b));
+  const uint3 r = tint_div(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/div_by_zero/by_identifier/scalar-vec3/u32.wgsl.expected.fxc.hlsl b/test/tint/expressions/binary/div_by_zero/by_identifier/scalar-vec3/u32.wgsl.expected.fxc.hlsl
index 0692d21..930f742 100644
--- a/test/tint/expressions/binary/div_by_zero/by_identifier/scalar-vec3/u32.wgsl.expected.fxc.hlsl
+++ b/test/tint/expressions/binary/div_by_zero/by_identifier/scalar-vec3/u32.wgsl.expected.fxc.hlsl
@@ -1,7 +1,12 @@
+uint3 tint_div(uint lhs, uint3 rhs) {
+  const uint3 l = uint3((lhs).xxx);
+  return (l / ((rhs == (0u).xxx) ? (1u).xxx : rhs));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   uint a = 4u;
   uint3 b = uint3(0u, 2u, 0u);
-  const uint3 r = (a / (b == uint3(0u, 0u, 0u) ? uint3(1u, 1u, 1u) : b));
+  const uint3 r = tint_div(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/div_by_zero/by_identifier/scalar-vec3/u32.wgsl.expected.glsl b/test/tint/expressions/binary/div_by_zero/by_identifier/scalar-vec3/u32.wgsl.expected.glsl
index 6d14d8f..50ab5b3 100644
--- a/test/tint/expressions/binary/div_by_zero/by_identifier/scalar-vec3/u32.wgsl.expected.glsl
+++ b/test/tint/expressions/binary/div_by_zero/by_identifier/scalar-vec3/u32.wgsl.expected.glsl
@@ -1,9 +1,14 @@
 #version 310 es
 
+uvec3 tint_div(uint lhs, uvec3 rhs) {
+  uvec3 l = uvec3(lhs);
+  return (l / mix(rhs, uvec3(1u), equal(rhs, uvec3(0u))));
+}
+
 void f() {
   uint a = 4u;
   uvec3 b = uvec3(0u, 2u, 0u);
-  uvec3 r = (a / b);
+  uvec3 r = tint_div(a, b);
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/expressions/binary/div_by_zero/by_identifier/scalar-vec3/u32.wgsl.expected.msl b/test/tint/expressions/binary/div_by_zero/by_identifier/scalar-vec3/u32.wgsl.expected.msl
index b7bf1d7..c318ec4 100644
--- a/test/tint/expressions/binary/div_by_zero/by_identifier/scalar-vec3/u32.wgsl.expected.msl
+++ b/test/tint/expressions/binary/div_by_zero/by_identifier/scalar-vec3/u32.wgsl.expected.msl
@@ -1,10 +1,15 @@
 #include <metal_stdlib>
 
 using namespace metal;
+uint3 tint_div(uint lhs, uint3 rhs) {
+  uint3 const l = uint3(lhs);
+  return (l / select(rhs, uint3(1u), (rhs == uint3(0u))));
+}
+
 kernel void f() {
   uint a = 4u;
   uint3 b = uint3(0u, 2u, 0u);
-  uint3 const r = (a / b);
+  uint3 const r = tint_div(a, b);
   return;
 }
 
diff --git a/test/tint/expressions/binary/div_by_zero/by_identifier/scalar-vec3/u32.wgsl.expected.spvasm b/test/tint/expressions/binary/div_by_zero/by_identifier/scalar-vec3/u32.wgsl.expected.spvasm
index 9f6d5d5..5d6ee99 100644
--- a/test/tint/expressions/binary/div_by_zero/by_identifier/scalar-vec3/u32.wgsl.expected.spvasm
+++ b/test/tint/expressions/binary/div_by_zero/by_identifier/scalar-vec3/u32.wgsl.expected.spvasm
@@ -1,36 +1,52 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 21
+; Bound: 32
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %f "f"
                OpExecutionMode %f LocalSize 1 1 1
+               OpName %tint_div "tint_div"
+               OpName %lhs "lhs"
+               OpName %rhs "rhs"
                OpName %f "f"
                OpName %a "a"
                OpName %b "b"
-       %void = OpTypeVoid
-          %1 = OpTypeFunction %void
        %uint = OpTypeInt 32 0
+     %v3uint = OpTypeVector %uint 3
+          %1 = OpTypeFunction %v3uint %uint %v3uint
+         %10 = OpConstantNull %v3uint
+       %bool = OpTypeBool
+     %v3bool = OpTypeVector %bool 3
+     %uint_1 = OpConstant %uint 1
+         %15 = OpConstantComposite %v3uint %uint_1 %uint_1 %uint_1
+       %void = OpTypeVoid
+         %17 = OpTypeFunction %void
      %uint_4 = OpConstant %uint 4
 %_ptr_Function_uint = OpTypePointer Function %uint
-          %9 = OpConstantNull %uint
-     %v3uint = OpTypeVector %uint 3
+         %24 = OpConstantNull %uint
      %uint_2 = OpConstant %uint 2
-         %12 = OpConstantComposite %v3uint %9 %uint_2 %9
+         %26 = OpConstantComposite %v3uint %24 %uint_2 %24
 %_ptr_Function_v3uint = OpTypePointer Function %v3uint
-         %15 = OpConstantNull %v3uint
-          %f = OpFunction %void None %1
-          %4 = OpLabel
-          %a = OpVariable %_ptr_Function_uint Function %9
-          %b = OpVariable %_ptr_Function_v3uint Function %15
-         %19 = OpVariable %_ptr_Function_v3uint Function %15
+   %tint_div = OpFunction %v3uint None %1
+        %lhs = OpFunctionParameter %uint
+        %rhs = OpFunctionParameter %v3uint
+          %7 = OpLabel
+          %8 = OpCompositeConstruct %v3uint %lhs %lhs %lhs
+         %11 = OpIEqual %v3bool %rhs %10
+          %9 = OpSelect %v3uint %11 %15 %rhs
+         %16 = OpUDiv %v3uint %8 %9
+               OpReturnValue %16
+               OpFunctionEnd
+          %f = OpFunction %void None %17
+         %20 = OpLabel
+          %a = OpVariable %_ptr_Function_uint Function %24
+          %b = OpVariable %_ptr_Function_v3uint Function %10
                OpStore %a %uint_4
-               OpStore %b %12
-         %16 = OpLoad %uint %a
-         %17 = OpLoad %v3uint %b
-         %20 = OpCompositeConstruct %v3uint %16 %16 %16
-         %18 = OpUDiv %v3uint %20 %17
+               OpStore %b %26
+         %30 = OpLoad %uint %a
+         %31 = OpLoad %v3uint %b
+         %29 = OpFunctionCall %v3uint %tint_div %30 %31
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/expressions/binary/div_by_zero/by_identifier/vec3-scalar/i32.wgsl.expected.dxc.hlsl b/test/tint/expressions/binary/div_by_zero/by_identifier/vec3-scalar/i32.wgsl.expected.dxc.hlsl
index 4f87f70..5418cb1 100644
--- a/test/tint/expressions/binary/div_by_zero/by_identifier/vec3-scalar/i32.wgsl.expected.dxc.hlsl
+++ b/test/tint/expressions/binary/div_by_zero/by_identifier/vec3-scalar/i32.wgsl.expected.dxc.hlsl
@@ -1,7 +1,12 @@
+int3 tint_div(int3 lhs, int rhs) {
+  const int3 r = int3((rhs).xxx);
+  return (lhs / (((r == (0).xxx) | ((lhs == (-2147483648).xxx) & (r == (-1).xxx))) ? (1).xxx : r));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   int3 a = int3(1, 2, 3);
   int b = 0;
-  const int3 r = (a / (b == 0 ? 1 : b));
+  const int3 r = tint_div(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/div_by_zero/by_identifier/vec3-scalar/i32.wgsl.expected.fxc.hlsl b/test/tint/expressions/binary/div_by_zero/by_identifier/vec3-scalar/i32.wgsl.expected.fxc.hlsl
index 4f87f70..5418cb1 100644
--- a/test/tint/expressions/binary/div_by_zero/by_identifier/vec3-scalar/i32.wgsl.expected.fxc.hlsl
+++ b/test/tint/expressions/binary/div_by_zero/by_identifier/vec3-scalar/i32.wgsl.expected.fxc.hlsl
@@ -1,7 +1,12 @@
+int3 tint_div(int3 lhs, int rhs) {
+  const int3 r = int3((rhs).xxx);
+  return (lhs / (((r == (0).xxx) | ((lhs == (-2147483648).xxx) & (r == (-1).xxx))) ? (1).xxx : r));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   int3 a = int3(1, 2, 3);
   int b = 0;
-  const int3 r = (a / (b == 0 ? 1 : b));
+  const int3 r = tint_div(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/div_by_zero/by_identifier/vec3-scalar/i32.wgsl.expected.glsl b/test/tint/expressions/binary/div_by_zero/by_identifier/vec3-scalar/i32.wgsl.expected.glsl
index 0c7f6a9..28ba692 100644
--- a/test/tint/expressions/binary/div_by_zero/by_identifier/vec3-scalar/i32.wgsl.expected.glsl
+++ b/test/tint/expressions/binary/div_by_zero/by_identifier/vec3-scalar/i32.wgsl.expected.glsl
@@ -1,9 +1,14 @@
 #version 310 es
 
+ivec3 tint_div(ivec3 lhs, int rhs) {
+  ivec3 r = ivec3(rhs);
+  return (lhs / mix(r, ivec3(1), bvec3(uvec3(equal(r, ivec3(0))) | uvec3(bvec3(uvec3(equal(lhs, ivec3(-2147483648))) & uvec3(equal(r, ivec3(-1))))))));
+}
+
 void f() {
   ivec3 a = ivec3(1, 2, 3);
   int b = 0;
-  ivec3 r = (a / b);
+  ivec3 r = tint_div(a, b);
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/expressions/binary/div_by_zero/by_identifier/vec3-scalar/i32.wgsl.expected.msl b/test/tint/expressions/binary/div_by_zero/by_identifier/vec3-scalar/i32.wgsl.expected.msl
index 8e25431..2282152 100644
--- a/test/tint/expressions/binary/div_by_zero/by_identifier/vec3-scalar/i32.wgsl.expected.msl
+++ b/test/tint/expressions/binary/div_by_zero/by_identifier/vec3-scalar/i32.wgsl.expected.msl
@@ -1,10 +1,15 @@
 #include <metal_stdlib>
 
 using namespace metal;
+int3 tint_div(int3 lhs, int rhs) {
+  int3 const r = int3(rhs);
+  return (lhs / select(r, int3(1), ((r == int3(0)) | ((lhs == int3((-2147483647 - 1))) & (r == int3(-1))))));
+}
+
 kernel void f() {
   int3 a = int3(1, 2, 3);
   int b = 0;
-  int3 const r = (a / b);
+  int3 const r = tint_div(a, b);
   return;
 }
 
diff --git a/test/tint/expressions/binary/div_by_zero/by_identifier/vec3-scalar/i32.wgsl.expected.spvasm b/test/tint/expressions/binary/div_by_zero/by_identifier/vec3-scalar/i32.wgsl.expected.spvasm
index 88da037..3a2d07d 100644
--- a/test/tint/expressions/binary/div_by_zero/by_identifier/vec3-scalar/i32.wgsl.expected.spvasm
+++ b/test/tint/expressions/binary/div_by_zero/by_identifier/vec3-scalar/i32.wgsl.expected.spvasm
@@ -1,37 +1,60 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 22
+; Bound: 40
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %f "f"
                OpExecutionMode %f LocalSize 1 1 1
+               OpName %tint_div "tint_div"
+               OpName %lhs "lhs"
+               OpName %rhs "rhs"
                OpName %f "f"
                OpName %a "a"
                OpName %b "b"
-       %void = OpTypeVoid
-          %1 = OpTypeFunction %void
         %int = OpTypeInt 32 1
       %v3int = OpTypeVector %int 3
+          %1 = OpTypeFunction %v3int %v3int %int
+         %10 = OpConstantNull %v3int
+       %bool = OpTypeBool
+     %v3bool = OpTypeVector %bool 3
+%int_n2147483648 = OpConstant %int -2147483648
+         %15 = OpConstantComposite %v3int %int_n2147483648 %int_n2147483648 %int_n2147483648
+     %int_n1 = OpConstant %int -1
+         %18 = OpConstantComposite %v3int %int_n1 %int_n1 %int_n1
       %int_1 = OpConstant %int 1
+         %23 = OpConstantComposite %v3int %int_1 %int_1 %int_1
+       %void = OpTypeVoid
+         %25 = OpTypeFunction %void
       %int_2 = OpConstant %int 2
       %int_3 = OpConstant %int 3
-         %10 = OpConstantComposite %v3int %int_1 %int_2 %int_3
+         %31 = OpConstantComposite %v3int %int_1 %int_2 %int_3
 %_ptr_Function_v3int = OpTypePointer Function %v3int
-         %13 = OpConstantNull %v3int
-         %14 = OpConstantNull %int
+         %34 = OpConstantNull %int
 %_ptr_Function_int = OpTypePointer Function %int
-          %f = OpFunction %void None %1
-          %4 = OpLabel
-          %a = OpVariable %_ptr_Function_v3int Function %13
-          %b = OpVariable %_ptr_Function_int Function %14
-         %20 = OpVariable %_ptr_Function_v3int Function %13
-               OpStore %a %10
-               OpStore %b %14
-         %17 = OpLoad %v3int %a
-         %18 = OpLoad %int %b
-         %21 = OpCompositeConstruct %v3int %18 %18 %18
-         %19 = OpSDiv %v3int %17 %21
+   %tint_div = OpFunction %v3int None %1
+        %lhs = OpFunctionParameter %v3int
+        %rhs = OpFunctionParameter %int
+          %7 = OpLabel
+          %8 = OpCompositeConstruct %v3int %rhs %rhs %rhs
+         %11 = OpIEqual %v3bool %8 %10
+         %16 = OpIEqual %v3bool %lhs %15
+         %19 = OpIEqual %v3bool %8 %18
+         %20 = OpLogicalAnd %v3bool %16 %19
+         %21 = OpLogicalOr %v3bool %11 %20
+          %9 = OpSelect %v3int %21 %23 %8
+         %24 = OpSDiv %v3int %lhs %9
+               OpReturnValue %24
+               OpFunctionEnd
+          %f = OpFunction %void None %25
+         %28 = OpLabel
+          %a = OpVariable %_ptr_Function_v3int Function %10
+          %b = OpVariable %_ptr_Function_int Function %34
+               OpStore %a %31
+               OpStore %b %34
+         %38 = OpLoad %v3int %a
+         %39 = OpLoad %int %b
+         %37 = OpFunctionCall %v3int %tint_div %38 %39
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/expressions/binary/div_by_zero/by_identifier/vec3-scalar/u32.wgsl.expected.dxc.hlsl b/test/tint/expressions/binary/div_by_zero/by_identifier/vec3-scalar/u32.wgsl.expected.dxc.hlsl
index 012cb29..6be2d0a 100644
--- a/test/tint/expressions/binary/div_by_zero/by_identifier/vec3-scalar/u32.wgsl.expected.dxc.hlsl
+++ b/test/tint/expressions/binary/div_by_zero/by_identifier/vec3-scalar/u32.wgsl.expected.dxc.hlsl
@@ -1,7 +1,12 @@
+uint3 tint_div(uint3 lhs, uint rhs) {
+  const uint3 r = uint3((rhs).xxx);
+  return (lhs / ((r == (0u).xxx) ? (1u).xxx : r));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   uint3 a = uint3(1u, 2u, 3u);
   uint b = 0u;
-  const uint3 r = (a / (b == 0u ? 1u : b));
+  const uint3 r = tint_div(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/div_by_zero/by_identifier/vec3-scalar/u32.wgsl.expected.fxc.hlsl b/test/tint/expressions/binary/div_by_zero/by_identifier/vec3-scalar/u32.wgsl.expected.fxc.hlsl
index 012cb29..6be2d0a 100644
--- a/test/tint/expressions/binary/div_by_zero/by_identifier/vec3-scalar/u32.wgsl.expected.fxc.hlsl
+++ b/test/tint/expressions/binary/div_by_zero/by_identifier/vec3-scalar/u32.wgsl.expected.fxc.hlsl
@@ -1,7 +1,12 @@
+uint3 tint_div(uint3 lhs, uint rhs) {
+  const uint3 r = uint3((rhs).xxx);
+  return (lhs / ((r == (0u).xxx) ? (1u).xxx : r));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   uint3 a = uint3(1u, 2u, 3u);
   uint b = 0u;
-  const uint3 r = (a / (b == 0u ? 1u : b));
+  const uint3 r = tint_div(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/div_by_zero/by_identifier/vec3-scalar/u32.wgsl.expected.glsl b/test/tint/expressions/binary/div_by_zero/by_identifier/vec3-scalar/u32.wgsl.expected.glsl
index 05bca8a..926d784 100644
--- a/test/tint/expressions/binary/div_by_zero/by_identifier/vec3-scalar/u32.wgsl.expected.glsl
+++ b/test/tint/expressions/binary/div_by_zero/by_identifier/vec3-scalar/u32.wgsl.expected.glsl
@@ -1,9 +1,14 @@
 #version 310 es
 
+uvec3 tint_div(uvec3 lhs, uint rhs) {
+  uvec3 r = uvec3(rhs);
+  return (lhs / mix(r, uvec3(1u), equal(r, uvec3(0u))));
+}
+
 void f() {
   uvec3 a = uvec3(1u, 2u, 3u);
   uint b = 0u;
-  uvec3 r = (a / b);
+  uvec3 r = tint_div(a, b);
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/expressions/binary/div_by_zero/by_identifier/vec3-scalar/u32.wgsl.expected.msl b/test/tint/expressions/binary/div_by_zero/by_identifier/vec3-scalar/u32.wgsl.expected.msl
index 126ec2a..3c19181 100644
--- a/test/tint/expressions/binary/div_by_zero/by_identifier/vec3-scalar/u32.wgsl.expected.msl
+++ b/test/tint/expressions/binary/div_by_zero/by_identifier/vec3-scalar/u32.wgsl.expected.msl
@@ -1,10 +1,15 @@
 #include <metal_stdlib>
 
 using namespace metal;
+uint3 tint_div(uint3 lhs, uint rhs) {
+  uint3 const r = uint3(rhs);
+  return (lhs / select(r, uint3(1u), (r == uint3(0u))));
+}
+
 kernel void f() {
   uint3 a = uint3(1u, 2u, 3u);
   uint b = 0u;
-  uint3 const r = (a / b);
+  uint3 const r = tint_div(a, b);
   return;
 }
 
diff --git a/test/tint/expressions/binary/div_by_zero/by_identifier/vec3-scalar/u32.wgsl.expected.spvasm b/test/tint/expressions/binary/div_by_zero/by_identifier/vec3-scalar/u32.wgsl.expected.spvasm
index 759be2a..fcff670 100644
--- a/test/tint/expressions/binary/div_by_zero/by_identifier/vec3-scalar/u32.wgsl.expected.spvasm
+++ b/test/tint/expressions/binary/div_by_zero/by_identifier/vec3-scalar/u32.wgsl.expected.spvasm
@@ -1,37 +1,52 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 22
+; Bound: 32
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %f "f"
                OpExecutionMode %f LocalSize 1 1 1
+               OpName %tint_div "tint_div"
+               OpName %lhs "lhs"
+               OpName %rhs "rhs"
                OpName %f "f"
                OpName %a "a"
                OpName %b "b"
-       %void = OpTypeVoid
-          %1 = OpTypeFunction %void
        %uint = OpTypeInt 32 0
      %v3uint = OpTypeVector %uint 3
+          %1 = OpTypeFunction %v3uint %v3uint %uint
+         %10 = OpConstantNull %v3uint
+       %bool = OpTypeBool
+     %v3bool = OpTypeVector %bool 3
      %uint_1 = OpConstant %uint 1
+         %15 = OpConstantComposite %v3uint %uint_1 %uint_1 %uint_1
+       %void = OpTypeVoid
+         %17 = OpTypeFunction %void
      %uint_2 = OpConstant %uint 2
      %uint_3 = OpConstant %uint 3
-         %10 = OpConstantComposite %v3uint %uint_1 %uint_2 %uint_3
+         %23 = OpConstantComposite %v3uint %uint_1 %uint_2 %uint_3
 %_ptr_Function_v3uint = OpTypePointer Function %v3uint
-         %13 = OpConstantNull %v3uint
-         %14 = OpConstantNull %uint
+         %26 = OpConstantNull %uint
 %_ptr_Function_uint = OpTypePointer Function %uint
-          %f = OpFunction %void None %1
-          %4 = OpLabel
-          %a = OpVariable %_ptr_Function_v3uint Function %13
-          %b = OpVariable %_ptr_Function_uint Function %14
-         %20 = OpVariable %_ptr_Function_v3uint Function %13
-               OpStore %a %10
-               OpStore %b %14
-         %17 = OpLoad %v3uint %a
-         %18 = OpLoad %uint %b
-         %21 = OpCompositeConstruct %v3uint %18 %18 %18
-         %19 = OpUDiv %v3uint %17 %21
+   %tint_div = OpFunction %v3uint None %1
+        %lhs = OpFunctionParameter %v3uint
+        %rhs = OpFunctionParameter %uint
+          %7 = OpLabel
+          %8 = OpCompositeConstruct %v3uint %rhs %rhs %rhs
+         %11 = OpIEqual %v3bool %8 %10
+          %9 = OpSelect %v3uint %11 %15 %8
+         %16 = OpUDiv %v3uint %lhs %9
+               OpReturnValue %16
+               OpFunctionEnd
+          %f = OpFunction %void None %17
+         %20 = OpLabel
+          %a = OpVariable %_ptr_Function_v3uint Function %10
+          %b = OpVariable %_ptr_Function_uint Function %26
+               OpStore %a %23
+               OpStore %b %26
+         %30 = OpLoad %v3uint %a
+         %31 = OpLoad %uint %b
+         %29 = OpFunctionCall %v3uint %tint_div %30 %31
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/expressions/binary/div_by_zero/by_identifier/vec3-vec3/i32.wgsl.expected.dxc.hlsl b/test/tint/expressions/binary/div_by_zero/by_identifier/vec3-vec3/i32.wgsl.expected.dxc.hlsl
index 3e1ba7f..c7a531b 100644
--- a/test/tint/expressions/binary/div_by_zero/by_identifier/vec3-vec3/i32.wgsl.expected.dxc.hlsl
+++ b/test/tint/expressions/binary/div_by_zero/by_identifier/vec3-vec3/i32.wgsl.expected.dxc.hlsl
@@ -1,7 +1,11 @@
+int3 tint_div(int3 lhs, int3 rhs) {
+  return (lhs / (((rhs == (0).xxx) | ((lhs == (-2147483648).xxx) & (rhs == (-1).xxx))) ? (1).xxx : rhs));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   int3 a = int3(1, 2, 3);
   int3 b = int3(0, 5, 0);
-  const int3 r = (a / (b == int3(0, 0, 0) ? int3(1, 1, 1) : b));
+  const int3 r = tint_div(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/div_by_zero/by_identifier/vec3-vec3/i32.wgsl.expected.fxc.hlsl b/test/tint/expressions/binary/div_by_zero/by_identifier/vec3-vec3/i32.wgsl.expected.fxc.hlsl
index 3e1ba7f..c7a531b 100644
--- a/test/tint/expressions/binary/div_by_zero/by_identifier/vec3-vec3/i32.wgsl.expected.fxc.hlsl
+++ b/test/tint/expressions/binary/div_by_zero/by_identifier/vec3-vec3/i32.wgsl.expected.fxc.hlsl
@@ -1,7 +1,11 @@
+int3 tint_div(int3 lhs, int3 rhs) {
+  return (lhs / (((rhs == (0).xxx) | ((lhs == (-2147483648).xxx) & (rhs == (-1).xxx))) ? (1).xxx : rhs));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   int3 a = int3(1, 2, 3);
   int3 b = int3(0, 5, 0);
-  const int3 r = (a / (b == int3(0, 0, 0) ? int3(1, 1, 1) : b));
+  const int3 r = tint_div(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/div_by_zero/by_identifier/vec3-vec3/i32.wgsl.expected.glsl b/test/tint/expressions/binary/div_by_zero/by_identifier/vec3-vec3/i32.wgsl.expected.glsl
index 6e11b34..2ea6128 100644
--- a/test/tint/expressions/binary/div_by_zero/by_identifier/vec3-vec3/i32.wgsl.expected.glsl
+++ b/test/tint/expressions/binary/div_by_zero/by_identifier/vec3-vec3/i32.wgsl.expected.glsl
@@ -1,9 +1,13 @@
 #version 310 es
 
+ivec3 tint_div(ivec3 lhs, ivec3 rhs) {
+  return (lhs / mix(rhs, ivec3(1), bvec3(uvec3(equal(rhs, ivec3(0))) | uvec3(bvec3(uvec3(equal(lhs, ivec3(-2147483648))) & uvec3(equal(rhs, ivec3(-1))))))));
+}
+
 void f() {
   ivec3 a = ivec3(1, 2, 3);
   ivec3 b = ivec3(0, 5, 0);
-  ivec3 r = (a / b);
+  ivec3 r = tint_div(a, b);
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/expressions/binary/div_by_zero/by_identifier/vec3-vec3/i32.wgsl.expected.msl b/test/tint/expressions/binary/div_by_zero/by_identifier/vec3-vec3/i32.wgsl.expected.msl
index 298e7fa..82eed13 100644
--- a/test/tint/expressions/binary/div_by_zero/by_identifier/vec3-vec3/i32.wgsl.expected.msl
+++ b/test/tint/expressions/binary/div_by_zero/by_identifier/vec3-vec3/i32.wgsl.expected.msl
@@ -1,10 +1,14 @@
 #include <metal_stdlib>
 
 using namespace metal;
+int3 tint_div(int3 lhs, int3 rhs) {
+  return (lhs / select(rhs, int3(1), ((rhs == int3(0)) | ((lhs == int3((-2147483647 - 1))) & (rhs == int3(-1))))));
+}
+
 kernel void f() {
   int3 a = int3(1, 2, 3);
   int3 b = int3(0, 5, 0);
-  int3 const r = (a / b);
+  int3 const r = tint_div(a, b);
   return;
 }
 
diff --git a/test/tint/expressions/binary/div_by_zero/by_identifier/vec3-vec3/i32.wgsl.expected.spvasm b/test/tint/expressions/binary/div_by_zero/by_identifier/vec3-vec3/i32.wgsl.expected.spvasm
index 575bfe6..cd02515 100644
--- a/test/tint/expressions/binary/div_by_zero/by_identifier/vec3-vec3/i32.wgsl.expected.spvasm
+++ b/test/tint/expressions/binary/div_by_zero/by_identifier/vec3-vec3/i32.wgsl.expected.spvasm
@@ -1,36 +1,60 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 21
+; Bound: 40
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %f "f"
                OpExecutionMode %f LocalSize 1 1 1
+               OpName %tint_div "tint_div"
+               OpName %lhs "lhs"
+               OpName %rhs "rhs"
                OpName %f "f"
                OpName %a "a"
                OpName %b "b"
-       %void = OpTypeVoid
-          %1 = OpTypeFunction %void
         %int = OpTypeInt 32 1
       %v3int = OpTypeVector %int 3
+          %1 = OpTypeFunction %v3int %v3int %v3int
+          %9 = OpConstantNull %v3int
+       %bool = OpTypeBool
+     %v3bool = OpTypeVector %bool 3
+%int_n2147483648 = OpConstant %int -2147483648
+         %14 = OpConstantComposite %v3int %int_n2147483648 %int_n2147483648 %int_n2147483648
+     %int_n1 = OpConstant %int -1
+         %17 = OpConstantComposite %v3int %int_n1 %int_n1 %int_n1
       %int_1 = OpConstant %int 1
+         %22 = OpConstantComposite %v3int %int_1 %int_1 %int_1
+       %void = OpTypeVoid
+         %24 = OpTypeFunction %void
       %int_2 = OpConstant %int 2
       %int_3 = OpConstant %int 3
-         %10 = OpConstantComposite %v3int %int_1 %int_2 %int_3
+         %30 = OpConstantComposite %v3int %int_1 %int_2 %int_3
 %_ptr_Function_v3int = OpTypePointer Function %v3int
-         %13 = OpConstantNull %v3int
-         %14 = OpConstantNull %int
+         %33 = OpConstantNull %int
       %int_5 = OpConstant %int 5
-         %16 = OpConstantComposite %v3int %14 %int_5 %14
-          %f = OpFunction %void None %1
-          %4 = OpLabel
-          %a = OpVariable %_ptr_Function_v3int Function %13
-          %b = OpVariable %_ptr_Function_v3int Function %13
-               OpStore %a %10
-               OpStore %b %16
-         %18 = OpLoad %v3int %a
-         %19 = OpLoad %v3int %b
-         %20 = OpSDiv %v3int %18 %19
+         %35 = OpConstantComposite %v3int %33 %int_5 %33
+   %tint_div = OpFunction %v3int None %1
+        %lhs = OpFunctionParameter %v3int
+        %rhs = OpFunctionParameter %v3int
+          %7 = OpLabel
+         %10 = OpIEqual %v3bool %rhs %9
+         %15 = OpIEqual %v3bool %lhs %14
+         %18 = OpIEqual %v3bool %rhs %17
+         %19 = OpLogicalAnd %v3bool %15 %18
+         %20 = OpLogicalOr %v3bool %10 %19
+          %8 = OpSelect %v3int %20 %22 %rhs
+         %23 = OpSDiv %v3int %lhs %8
+               OpReturnValue %23
+               OpFunctionEnd
+          %f = OpFunction %void None %24
+         %27 = OpLabel
+          %a = OpVariable %_ptr_Function_v3int Function %9
+          %b = OpVariable %_ptr_Function_v3int Function %9
+               OpStore %a %30
+               OpStore %b %35
+         %38 = OpLoad %v3int %a
+         %39 = OpLoad %v3int %b
+         %37 = OpFunctionCall %v3int %tint_div %38 %39
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/expressions/binary/div_by_zero/by_identifier/vec3-vec3/u32.wgsl.expected.dxc.hlsl b/test/tint/expressions/binary/div_by_zero/by_identifier/vec3-vec3/u32.wgsl.expected.dxc.hlsl
index 5f022e4..ccdc79c 100644
--- a/test/tint/expressions/binary/div_by_zero/by_identifier/vec3-vec3/u32.wgsl.expected.dxc.hlsl
+++ b/test/tint/expressions/binary/div_by_zero/by_identifier/vec3-vec3/u32.wgsl.expected.dxc.hlsl
@@ -1,7 +1,11 @@
+uint3 tint_div(uint3 lhs, uint3 rhs) {
+  return (lhs / ((rhs == (0u).xxx) ? (1u).xxx : rhs));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   uint3 a = uint3(1u, 2u, 3u);
   uint3 b = uint3(0u, 5u, 0u);
-  const uint3 r = (a / (b == uint3(0u, 0u, 0u) ? uint3(1u, 1u, 1u) : b));
+  const uint3 r = tint_div(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/div_by_zero/by_identifier/vec3-vec3/u32.wgsl.expected.fxc.hlsl b/test/tint/expressions/binary/div_by_zero/by_identifier/vec3-vec3/u32.wgsl.expected.fxc.hlsl
index 5f022e4..ccdc79c 100644
--- a/test/tint/expressions/binary/div_by_zero/by_identifier/vec3-vec3/u32.wgsl.expected.fxc.hlsl
+++ b/test/tint/expressions/binary/div_by_zero/by_identifier/vec3-vec3/u32.wgsl.expected.fxc.hlsl
@@ -1,7 +1,11 @@
+uint3 tint_div(uint3 lhs, uint3 rhs) {
+  return (lhs / ((rhs == (0u).xxx) ? (1u).xxx : rhs));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   uint3 a = uint3(1u, 2u, 3u);
   uint3 b = uint3(0u, 5u, 0u);
-  const uint3 r = (a / (b == uint3(0u, 0u, 0u) ? uint3(1u, 1u, 1u) : b));
+  const uint3 r = tint_div(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/div_by_zero/by_identifier/vec3-vec3/u32.wgsl.expected.glsl b/test/tint/expressions/binary/div_by_zero/by_identifier/vec3-vec3/u32.wgsl.expected.glsl
index 657cdb4..000bf89 100644
--- a/test/tint/expressions/binary/div_by_zero/by_identifier/vec3-vec3/u32.wgsl.expected.glsl
+++ b/test/tint/expressions/binary/div_by_zero/by_identifier/vec3-vec3/u32.wgsl.expected.glsl
@@ -1,9 +1,13 @@
 #version 310 es
 
+uvec3 tint_div(uvec3 lhs, uvec3 rhs) {
+  return (lhs / mix(rhs, uvec3(1u), equal(rhs, uvec3(0u))));
+}
+
 void f() {
   uvec3 a = uvec3(1u, 2u, 3u);
   uvec3 b = uvec3(0u, 5u, 0u);
-  uvec3 r = (a / b);
+  uvec3 r = tint_div(a, b);
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/expressions/binary/div_by_zero/by_identifier/vec3-vec3/u32.wgsl.expected.msl b/test/tint/expressions/binary/div_by_zero/by_identifier/vec3-vec3/u32.wgsl.expected.msl
index d300954..b6c9993 100644
--- a/test/tint/expressions/binary/div_by_zero/by_identifier/vec3-vec3/u32.wgsl.expected.msl
+++ b/test/tint/expressions/binary/div_by_zero/by_identifier/vec3-vec3/u32.wgsl.expected.msl
@@ -1,10 +1,14 @@
 #include <metal_stdlib>
 
 using namespace metal;
+uint3 tint_div(uint3 lhs, uint3 rhs) {
+  return (lhs / select(rhs, uint3(1u), (rhs == uint3(0u))));
+}
+
 kernel void f() {
   uint3 a = uint3(1u, 2u, 3u);
   uint3 b = uint3(0u, 5u, 0u);
-  uint3 const r = (a / b);
+  uint3 const r = tint_div(a, b);
   return;
 }
 
diff --git a/test/tint/expressions/binary/div_by_zero/by_identifier/vec3-vec3/u32.wgsl.expected.spvasm b/test/tint/expressions/binary/div_by_zero/by_identifier/vec3-vec3/u32.wgsl.expected.spvasm
index 0336127..8d1b38f 100644
--- a/test/tint/expressions/binary/div_by_zero/by_identifier/vec3-vec3/u32.wgsl.expected.spvasm
+++ b/test/tint/expressions/binary/div_by_zero/by_identifier/vec3-vec3/u32.wgsl.expected.spvasm
@@ -1,36 +1,52 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 21
+; Bound: 32
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %f "f"
                OpExecutionMode %f LocalSize 1 1 1
+               OpName %tint_div "tint_div"
+               OpName %lhs "lhs"
+               OpName %rhs "rhs"
                OpName %f "f"
                OpName %a "a"
                OpName %b "b"
-       %void = OpTypeVoid
-          %1 = OpTypeFunction %void
        %uint = OpTypeInt 32 0
      %v3uint = OpTypeVector %uint 3
+          %1 = OpTypeFunction %v3uint %v3uint %v3uint
+          %9 = OpConstantNull %v3uint
+       %bool = OpTypeBool
+     %v3bool = OpTypeVector %bool 3
      %uint_1 = OpConstant %uint 1
+         %14 = OpConstantComposite %v3uint %uint_1 %uint_1 %uint_1
+       %void = OpTypeVoid
+         %16 = OpTypeFunction %void
      %uint_2 = OpConstant %uint 2
      %uint_3 = OpConstant %uint 3
-         %10 = OpConstantComposite %v3uint %uint_1 %uint_2 %uint_3
+         %22 = OpConstantComposite %v3uint %uint_1 %uint_2 %uint_3
 %_ptr_Function_v3uint = OpTypePointer Function %v3uint
-         %13 = OpConstantNull %v3uint
-         %14 = OpConstantNull %uint
+         %25 = OpConstantNull %uint
      %uint_5 = OpConstant %uint 5
-         %16 = OpConstantComposite %v3uint %14 %uint_5 %14
-          %f = OpFunction %void None %1
-          %4 = OpLabel
-          %a = OpVariable %_ptr_Function_v3uint Function %13
-          %b = OpVariable %_ptr_Function_v3uint Function %13
-               OpStore %a %10
-               OpStore %b %16
-         %18 = OpLoad %v3uint %a
-         %19 = OpLoad %v3uint %b
-         %20 = OpUDiv %v3uint %18 %19
+         %27 = OpConstantComposite %v3uint %25 %uint_5 %25
+   %tint_div = OpFunction %v3uint None %1
+        %lhs = OpFunctionParameter %v3uint
+        %rhs = OpFunctionParameter %v3uint
+          %7 = OpLabel
+         %10 = OpIEqual %v3bool %rhs %9
+          %8 = OpSelect %v3uint %10 %14 %rhs
+         %15 = OpUDiv %v3uint %lhs %8
+               OpReturnValue %15
+               OpFunctionEnd
+          %f = OpFunction %void None %16
+         %19 = OpLabel
+          %a = OpVariable %_ptr_Function_v3uint Function %9
+          %b = OpVariable %_ptr_Function_v3uint Function %9
+               OpStore %a %22
+               OpStore %b %27
+         %30 = OpLoad %v3uint %a
+         %31 = OpLoad %v3uint %b
+         %29 = OpFunctionCall %v3uint %tint_div %30 %31
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/expressions/binary/mod/scalar-scalar/i32.wgsl.expected.dxc.hlsl b/test/tint/expressions/binary/mod/scalar-scalar/i32.wgsl.expected.dxc.hlsl
index e5e75d3..8454691 100644
--- a/test/tint/expressions/binary/mod/scalar-scalar/i32.wgsl.expected.dxc.hlsl
+++ b/test/tint/expressions/binary/mod/scalar-scalar/i32.wgsl.expected.dxc.hlsl
@@ -1,7 +1,11 @@
+int tint_mod(int lhs, int rhs) {
+  return (lhs % (((rhs == 0) | ((lhs == -2147483648) & (rhs == -1))) ? 1 : rhs));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   const int a = 1;
   const int b = 2;
-  const int r = (a % (b == 0 ? 1 : b));
+  const int r = tint_mod(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/mod/scalar-scalar/i32.wgsl.expected.fxc.hlsl b/test/tint/expressions/binary/mod/scalar-scalar/i32.wgsl.expected.fxc.hlsl
index e5e75d3..8454691 100644
--- a/test/tint/expressions/binary/mod/scalar-scalar/i32.wgsl.expected.fxc.hlsl
+++ b/test/tint/expressions/binary/mod/scalar-scalar/i32.wgsl.expected.fxc.hlsl
@@ -1,7 +1,11 @@
+int tint_mod(int lhs, int rhs) {
+  return (lhs % (((rhs == 0) | ((lhs == -2147483648) & (rhs == -1))) ? 1 : rhs));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   const int a = 1;
   const int b = 2;
-  const int r = (a % (b == 0 ? 1 : b));
+  const int r = tint_mod(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/mod/scalar-scalar/i32.wgsl.expected.glsl b/test/tint/expressions/binary/mod/scalar-scalar/i32.wgsl.expected.glsl
index 8c12815..70e79dd 100644
--- a/test/tint/expressions/binary/mod/scalar-scalar/i32.wgsl.expected.glsl
+++ b/test/tint/expressions/binary/mod/scalar-scalar/i32.wgsl.expected.glsl
@@ -1,9 +1,13 @@
 #version 310 es
 
+int tint_mod(int lhs, int rhs) {
+  return (lhs % (bool(uint((rhs == 0)) | uint(bool(uint((lhs == -2147483648)) & uint((rhs == -1))))) ? 1 : rhs));
+}
+
 void f() {
   int a = 1;
   int b = 2;
-  int r = (a % b);
+  int r = tint_mod(a, b);
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/expressions/binary/mod/scalar-scalar/i32.wgsl.expected.msl b/test/tint/expressions/binary/mod/scalar-scalar/i32.wgsl.expected.msl
index a67d6fe..15c7815 100644
--- a/test/tint/expressions/binary/mod/scalar-scalar/i32.wgsl.expected.msl
+++ b/test/tint/expressions/binary/mod/scalar-scalar/i32.wgsl.expected.msl
@@ -1,10 +1,14 @@
 #include <metal_stdlib>
 
 using namespace metal;
+int tint_mod(int lhs, int rhs) {
+  return (lhs % select(rhs, 1, bool((rhs == 0) | bool((lhs == (-2147483647 - 1)) & (rhs == -1)))));
+}
+
 kernel void f() {
   int const a = 1;
   int const b = 2;
-  int const r = (a % b);
+  int const r = tint_mod(a, b);
   return;
 }
 
diff --git a/test/tint/expressions/binary/mod/scalar-scalar/i32.wgsl.expected.spvasm b/test/tint/expressions/binary/mod/scalar-scalar/i32.wgsl.expected.spvasm
index 3e9f944..f68a5e6 100644
--- a/test/tint/expressions/binary/mod/scalar-scalar/i32.wgsl.expected.spvasm
+++ b/test/tint/expressions/binary/mod/scalar-scalar/i32.wgsl.expected.spvasm
@@ -1,20 +1,41 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 9
+; Bound: 25
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %f "f"
                OpExecutionMode %f LocalSize 1 1 1
+               OpName %tint_mod "tint_mod"
+               OpName %lhs "lhs"
+               OpName %rhs "rhs"
                OpName %f "f"
-       %void = OpTypeVoid
-          %1 = OpTypeFunction %void
         %int = OpTypeInt 32 1
+          %1 = OpTypeFunction %int %int %int
+          %8 = OpConstantNull %int
+       %bool = OpTypeBool
+%int_n2147483648 = OpConstant %int -2147483648
+     %int_n1 = OpConstant %int -1
       %int_1 = OpConstant %int 1
+       %void = OpTypeVoid
+         %19 = OpTypeFunction %void
       %int_2 = OpConstant %int 2
-          %f = OpFunction %void None %1
-          %4 = OpLabel
-          %8 = OpSMod %int %int_1 %int_2
+   %tint_mod = OpFunction %int None %1
+        %lhs = OpFunctionParameter %int
+        %rhs = OpFunctionParameter %int
+          %6 = OpLabel
+          %9 = OpIEqual %bool %rhs %8
+         %12 = OpIEqual %bool %lhs %int_n2147483648
+         %14 = OpIEqual %bool %rhs %int_n1
+         %15 = OpLogicalAnd %bool %12 %14
+         %16 = OpLogicalOr %bool %9 %15
+          %7 = OpSelect %int %16 %int_1 %rhs
+         %18 = OpSMod %int %lhs %7
+               OpReturnValue %18
+               OpFunctionEnd
+          %f = OpFunction %void None %19
+         %22 = OpLabel
+         %24 = OpFunctionCall %int %tint_mod %int_1 %int_2
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/expressions/binary/mod/scalar-scalar/u32.wgsl.expected.dxc.hlsl b/test/tint/expressions/binary/mod/scalar-scalar/u32.wgsl.expected.dxc.hlsl
index ea912bd..b2cc513 100644
--- a/test/tint/expressions/binary/mod/scalar-scalar/u32.wgsl.expected.dxc.hlsl
+++ b/test/tint/expressions/binary/mod/scalar-scalar/u32.wgsl.expected.dxc.hlsl
@@ -1,7 +1,11 @@
+uint tint_mod(uint lhs, uint rhs) {
+  return (lhs % ((rhs == 0u) ? 1u : rhs));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   const uint a = 1u;
   const uint b = 2u;
-  const uint r = (a % (b == 0u ? 1u : b));
+  const uint r = tint_mod(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/mod/scalar-scalar/u32.wgsl.expected.fxc.hlsl b/test/tint/expressions/binary/mod/scalar-scalar/u32.wgsl.expected.fxc.hlsl
index ea912bd..b2cc513 100644
--- a/test/tint/expressions/binary/mod/scalar-scalar/u32.wgsl.expected.fxc.hlsl
+++ b/test/tint/expressions/binary/mod/scalar-scalar/u32.wgsl.expected.fxc.hlsl
@@ -1,7 +1,11 @@
+uint tint_mod(uint lhs, uint rhs) {
+  return (lhs % ((rhs == 0u) ? 1u : rhs));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   const uint a = 1u;
   const uint b = 2u;
-  const uint r = (a % (b == 0u ? 1u : b));
+  const uint r = tint_mod(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/mod/scalar-scalar/u32.wgsl.expected.glsl b/test/tint/expressions/binary/mod/scalar-scalar/u32.wgsl.expected.glsl
index 485ed72..920fd38 100644
--- a/test/tint/expressions/binary/mod/scalar-scalar/u32.wgsl.expected.glsl
+++ b/test/tint/expressions/binary/mod/scalar-scalar/u32.wgsl.expected.glsl
@@ -1,9 +1,13 @@
 #version 310 es
 
+uint tint_mod(uint lhs, uint rhs) {
+  return (lhs % ((rhs == 0u) ? 1u : rhs));
+}
+
 void f() {
   uint a = 1u;
   uint b = 2u;
-  uint r = (a % b);
+  uint r = tint_mod(a, b);
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/expressions/binary/mod/scalar-scalar/u32.wgsl.expected.msl b/test/tint/expressions/binary/mod/scalar-scalar/u32.wgsl.expected.msl
index 5d4b949..89b2a10 100644
--- a/test/tint/expressions/binary/mod/scalar-scalar/u32.wgsl.expected.msl
+++ b/test/tint/expressions/binary/mod/scalar-scalar/u32.wgsl.expected.msl
@@ -1,10 +1,14 @@
 #include <metal_stdlib>
 
 using namespace metal;
+uint tint_mod(uint lhs, uint rhs) {
+  return (lhs % select(rhs, 1u, (rhs == 0u)));
+}
+
 kernel void f() {
   uint const a = 1u;
   uint const b = 2u;
-  uint const r = (a % b);
+  uint const r = tint_mod(a, b);
   return;
 }
 
diff --git a/test/tint/expressions/binary/mod/scalar-scalar/u32.wgsl.expected.spvasm b/test/tint/expressions/binary/mod/scalar-scalar/u32.wgsl.expected.spvasm
index 57f2d38..13e89ae 100644
--- a/test/tint/expressions/binary/mod/scalar-scalar/u32.wgsl.expected.spvasm
+++ b/test/tint/expressions/binary/mod/scalar-scalar/u32.wgsl.expected.spvasm
@@ -1,20 +1,35 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 9
+; Bound: 19
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %f "f"
                OpExecutionMode %f LocalSize 1 1 1
+               OpName %tint_mod "tint_mod"
+               OpName %lhs "lhs"
+               OpName %rhs "rhs"
                OpName %f "f"
-       %void = OpTypeVoid
-          %1 = OpTypeFunction %void
        %uint = OpTypeInt 32 0
+          %1 = OpTypeFunction %uint %uint %uint
+          %8 = OpConstantNull %uint
+       %bool = OpTypeBool
      %uint_1 = OpConstant %uint 1
+       %void = OpTypeVoid
+         %13 = OpTypeFunction %void
      %uint_2 = OpConstant %uint 2
-          %f = OpFunction %void None %1
-          %4 = OpLabel
-          %8 = OpUMod %uint %uint_1 %uint_2
+   %tint_mod = OpFunction %uint None %1
+        %lhs = OpFunctionParameter %uint
+        %rhs = OpFunctionParameter %uint
+          %6 = OpLabel
+          %9 = OpIEqual %bool %rhs %8
+          %7 = OpSelect %uint %9 %uint_1 %rhs
+         %12 = OpUMod %uint %lhs %7
+               OpReturnValue %12
+               OpFunctionEnd
+          %f = OpFunction %void None %13
+         %16 = OpLabel
+         %18 = OpFunctionCall %uint %tint_mod %uint_1 %uint_2
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/expressions/binary/mod/scalar-vec3/i32.wgsl.expected.dxc.hlsl b/test/tint/expressions/binary/mod/scalar-vec3/i32.wgsl.expected.dxc.hlsl
index 847b0fb..6fc93b7 100644
--- a/test/tint/expressions/binary/mod/scalar-vec3/i32.wgsl.expected.dxc.hlsl
+++ b/test/tint/expressions/binary/mod/scalar-vec3/i32.wgsl.expected.dxc.hlsl
@@ -1,7 +1,12 @@
+int3 tint_mod(int lhs, int3 rhs) {
+  const int3 l = int3((lhs).xxx);
+  return (l % (((rhs == (0).xxx) | ((l == (-2147483648).xxx) & (rhs == (-1).xxx))) ? (1).xxx : rhs));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   const int a = 4;
   const int3 b = int3(1, 2, 3);
-  const int3 r = (a % (b == int3(0, 0, 0) ? int3(1, 1, 1) : b));
+  const int3 r = tint_mod(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/mod/scalar-vec3/i32.wgsl.expected.fxc.hlsl b/test/tint/expressions/binary/mod/scalar-vec3/i32.wgsl.expected.fxc.hlsl
index 847b0fb..6fc93b7 100644
--- a/test/tint/expressions/binary/mod/scalar-vec3/i32.wgsl.expected.fxc.hlsl
+++ b/test/tint/expressions/binary/mod/scalar-vec3/i32.wgsl.expected.fxc.hlsl
@@ -1,7 +1,12 @@
+int3 tint_mod(int lhs, int3 rhs) {
+  const int3 l = int3((lhs).xxx);
+  return (l % (((rhs == (0).xxx) | ((l == (-2147483648).xxx) & (rhs == (-1).xxx))) ? (1).xxx : rhs));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   const int a = 4;
   const int3 b = int3(1, 2, 3);
-  const int3 r = (a % (b == int3(0, 0, 0) ? int3(1, 1, 1) : b));
+  const int3 r = tint_mod(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/mod/scalar-vec3/i32.wgsl.expected.glsl b/test/tint/expressions/binary/mod/scalar-vec3/i32.wgsl.expected.glsl
index 0167016..f9117fb 100644
--- a/test/tint/expressions/binary/mod/scalar-vec3/i32.wgsl.expected.glsl
+++ b/test/tint/expressions/binary/mod/scalar-vec3/i32.wgsl.expected.glsl
@@ -1,9 +1,14 @@
 #version 310 es
 
+ivec3 tint_mod(int lhs, ivec3 rhs) {
+  ivec3 l = ivec3(lhs);
+  return (l % mix(rhs, ivec3(1), bvec3(uvec3(equal(rhs, ivec3(0))) | uvec3(bvec3(uvec3(equal(l, ivec3(-2147483648))) & uvec3(equal(rhs, ivec3(-1))))))));
+}
+
 void f() {
   int a = 4;
   ivec3 b = ivec3(1, 2, 3);
-  ivec3 r = (a % b);
+  ivec3 r = tint_mod(a, b);
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/expressions/binary/mod/scalar-vec3/i32.wgsl.expected.msl b/test/tint/expressions/binary/mod/scalar-vec3/i32.wgsl.expected.msl
index 533d477..9b89ade 100644
--- a/test/tint/expressions/binary/mod/scalar-vec3/i32.wgsl.expected.msl
+++ b/test/tint/expressions/binary/mod/scalar-vec3/i32.wgsl.expected.msl
@@ -1,10 +1,15 @@
 #include <metal_stdlib>
 
 using namespace metal;
+int3 tint_mod(int lhs, int3 rhs) {
+  int3 const l = int3(lhs);
+  return (l % select(rhs, int3(1), ((rhs == int3(0)) | ((l == int3((-2147483647 - 1))) & (rhs == int3(-1))))));
+}
+
 kernel void f() {
   int const a = 4;
   int3 const b = int3(1, 2, 3);
-  int3 const r = (a % b);
+  int3 const r = tint_mod(a, b);
   return;
 }
 
diff --git a/test/tint/expressions/binary/mod/scalar-vec3/i32.wgsl.expected.spvasm b/test/tint/expressions/binary/mod/scalar-vec3/i32.wgsl.expected.spvasm
index 6dd950c..2621d82 100644
--- a/test/tint/expressions/binary/mod/scalar-vec3/i32.wgsl.expected.spvasm
+++ b/test/tint/expressions/binary/mod/scalar-vec3/i32.wgsl.expected.spvasm
@@ -1,28 +1,50 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 17
+; Bound: 34
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %f "f"
                OpExecutionMode %f LocalSize 1 1 1
+               OpName %tint_mod "tint_mod"
+               OpName %lhs "lhs"
+               OpName %rhs "rhs"
                OpName %f "f"
-       %void = OpTypeVoid
-          %1 = OpTypeFunction %void
         %int = OpTypeInt 32 1
-      %int_4 = OpConstant %int 4
       %v3int = OpTypeVector %int 3
+          %1 = OpTypeFunction %v3int %int %v3int
+         %10 = OpConstantNull %v3int
+       %bool = OpTypeBool
+     %v3bool = OpTypeVector %bool 3
+%int_n2147483648 = OpConstant %int -2147483648
+         %15 = OpConstantComposite %v3int %int_n2147483648 %int_n2147483648 %int_n2147483648
+     %int_n1 = OpConstant %int -1
+         %18 = OpConstantComposite %v3int %int_n1 %int_n1 %int_n1
       %int_1 = OpConstant %int 1
+         %23 = OpConstantComposite %v3int %int_1 %int_1 %int_1
+       %void = OpTypeVoid
+         %25 = OpTypeFunction %void
+      %int_4 = OpConstant %int 4
       %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 = OpSMod %v3int %16 %11
+         %32 = OpConstantComposite %v3int %int_1 %int_2 %int_3
+   %tint_mod = OpFunction %v3int None %1
+        %lhs = OpFunctionParameter %int
+        %rhs = OpFunctionParameter %v3int
+          %7 = OpLabel
+          %8 = OpCompositeConstruct %v3int %lhs %lhs %lhs
+         %11 = OpIEqual %v3bool %rhs %10
+         %16 = OpIEqual %v3bool %8 %15
+         %19 = OpIEqual %v3bool %rhs %18
+         %20 = OpLogicalAnd %v3bool %16 %19
+         %21 = OpLogicalOr %v3bool %11 %20
+          %9 = OpSelect %v3int %21 %23 %rhs
+         %24 = OpSMod %v3int %8 %9
+               OpReturnValue %24
+               OpFunctionEnd
+          %f = OpFunction %void None %25
+         %28 = OpLabel
+         %33 = OpFunctionCall %v3int %tint_mod %int_4 %32
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/expressions/binary/mod/scalar-vec3/u32.wgsl.expected.dxc.hlsl b/test/tint/expressions/binary/mod/scalar-vec3/u32.wgsl.expected.dxc.hlsl
index 396d57a..2cbda43 100644
--- a/test/tint/expressions/binary/mod/scalar-vec3/u32.wgsl.expected.dxc.hlsl
+++ b/test/tint/expressions/binary/mod/scalar-vec3/u32.wgsl.expected.dxc.hlsl
@@ -1,7 +1,12 @@
+uint3 tint_mod(uint lhs, uint3 rhs) {
+  const uint3 l = uint3((lhs).xxx);
+  return (l % ((rhs == (0u).xxx) ? (1u).xxx : rhs));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   const uint a = 4u;
   const uint3 b = uint3(1u, 2u, 3u);
-  const uint3 r = (a % (b == uint3(0u, 0u, 0u) ? uint3(1u, 1u, 1u) : b));
+  const uint3 r = tint_mod(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/mod/scalar-vec3/u32.wgsl.expected.fxc.hlsl b/test/tint/expressions/binary/mod/scalar-vec3/u32.wgsl.expected.fxc.hlsl
index 396d57a..2cbda43 100644
--- a/test/tint/expressions/binary/mod/scalar-vec3/u32.wgsl.expected.fxc.hlsl
+++ b/test/tint/expressions/binary/mod/scalar-vec3/u32.wgsl.expected.fxc.hlsl
@@ -1,7 +1,12 @@
+uint3 tint_mod(uint lhs, uint3 rhs) {
+  const uint3 l = uint3((lhs).xxx);
+  return (l % ((rhs == (0u).xxx) ? (1u).xxx : rhs));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   const uint a = 4u;
   const uint3 b = uint3(1u, 2u, 3u);
-  const uint3 r = (a % (b == uint3(0u, 0u, 0u) ? uint3(1u, 1u, 1u) : b));
+  const uint3 r = tint_mod(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/mod/scalar-vec3/u32.wgsl.expected.glsl b/test/tint/expressions/binary/mod/scalar-vec3/u32.wgsl.expected.glsl
index f150a92..f854088 100644
--- a/test/tint/expressions/binary/mod/scalar-vec3/u32.wgsl.expected.glsl
+++ b/test/tint/expressions/binary/mod/scalar-vec3/u32.wgsl.expected.glsl
@@ -1,9 +1,14 @@
 #version 310 es
 
+uvec3 tint_mod(uint lhs, uvec3 rhs) {
+  uvec3 l = uvec3(lhs);
+  return (l % mix(rhs, uvec3(1u), equal(rhs, uvec3(0u))));
+}
+
 void f() {
   uint a = 4u;
   uvec3 b = uvec3(1u, 2u, 3u);
-  uvec3 r = (a % b);
+  uvec3 r = tint_mod(a, b);
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/expressions/binary/mod/scalar-vec3/u32.wgsl.expected.msl b/test/tint/expressions/binary/mod/scalar-vec3/u32.wgsl.expected.msl
index a5e85ce..930bfff 100644
--- a/test/tint/expressions/binary/mod/scalar-vec3/u32.wgsl.expected.msl
+++ b/test/tint/expressions/binary/mod/scalar-vec3/u32.wgsl.expected.msl
@@ -1,10 +1,15 @@
 #include <metal_stdlib>
 
 using namespace metal;
+uint3 tint_mod(uint lhs, uint3 rhs) {
+  uint3 const l = uint3(lhs);
+  return (l % select(rhs, uint3(1u), (rhs == uint3(0u))));
+}
+
 kernel void f() {
   uint const a = 4u;
   uint3 const b = uint3(1u, 2u, 3u);
-  uint3 const r = (a % b);
+  uint3 const r = tint_mod(a, b);
   return;
 }
 
diff --git a/test/tint/expressions/binary/mod/scalar-vec3/u32.wgsl.expected.spvasm b/test/tint/expressions/binary/mod/scalar-vec3/u32.wgsl.expected.spvasm
index 99afb76..97bf152 100644
--- a/test/tint/expressions/binary/mod/scalar-vec3/u32.wgsl.expected.spvasm
+++ b/test/tint/expressions/binary/mod/scalar-vec3/u32.wgsl.expected.spvasm
@@ -1,28 +1,42 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 17
+; Bound: 26
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %f "f"
                OpExecutionMode %f LocalSize 1 1 1
+               OpName %tint_mod "tint_mod"
+               OpName %lhs "lhs"
+               OpName %rhs "rhs"
                OpName %f "f"
-       %void = OpTypeVoid
-          %1 = OpTypeFunction %void
        %uint = OpTypeInt 32 0
-     %uint_4 = OpConstant %uint 4
      %v3uint = OpTypeVector %uint 3
+          %1 = OpTypeFunction %v3uint %uint %v3uint
+         %10 = OpConstantNull %v3uint
+       %bool = OpTypeBool
+     %v3bool = OpTypeVector %bool 3
      %uint_1 = OpConstant %uint 1
+         %15 = OpConstantComposite %v3uint %uint_1 %uint_1 %uint_1
+       %void = OpTypeVoid
+         %17 = OpTypeFunction %void
+     %uint_4 = OpConstant %uint 4
      %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 = OpUMod %v3uint %16 %11
+         %24 = OpConstantComposite %v3uint %uint_1 %uint_2 %uint_3
+   %tint_mod = OpFunction %v3uint None %1
+        %lhs = OpFunctionParameter %uint
+        %rhs = OpFunctionParameter %v3uint
+          %7 = OpLabel
+          %8 = OpCompositeConstruct %v3uint %lhs %lhs %lhs
+         %11 = OpIEqual %v3bool %rhs %10
+          %9 = OpSelect %v3uint %11 %15 %rhs
+         %16 = OpUMod %v3uint %8 %9
+               OpReturnValue %16
+               OpFunctionEnd
+          %f = OpFunction %void None %17
+         %20 = OpLabel
+         %25 = OpFunctionCall %v3uint %tint_mod %uint_4 %24
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/expressions/binary/mod/vec3-scalar/i32.wgsl.expected.dxc.hlsl b/test/tint/expressions/binary/mod/vec3-scalar/i32.wgsl.expected.dxc.hlsl
index 469e7c0..3e147af 100644
--- a/test/tint/expressions/binary/mod/vec3-scalar/i32.wgsl.expected.dxc.hlsl
+++ b/test/tint/expressions/binary/mod/vec3-scalar/i32.wgsl.expected.dxc.hlsl
@@ -1,7 +1,12 @@
+int3 tint_mod(int3 lhs, int rhs) {
+  const int3 r = int3((rhs).xxx);
+  return (lhs % (((r == (0).xxx) | ((lhs == (-2147483648).xxx) & (r == (-1).xxx))) ? (1).xxx : r));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   const int3 a = int3(1, 2, 3);
   const int b = 4;
-  const int3 r = (a % (b == 0 ? 1 : b));
+  const int3 r = tint_mod(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/mod/vec3-scalar/i32.wgsl.expected.fxc.hlsl b/test/tint/expressions/binary/mod/vec3-scalar/i32.wgsl.expected.fxc.hlsl
index 469e7c0..3e147af 100644
--- a/test/tint/expressions/binary/mod/vec3-scalar/i32.wgsl.expected.fxc.hlsl
+++ b/test/tint/expressions/binary/mod/vec3-scalar/i32.wgsl.expected.fxc.hlsl
@@ -1,7 +1,12 @@
+int3 tint_mod(int3 lhs, int rhs) {
+  const int3 r = int3((rhs).xxx);
+  return (lhs % (((r == (0).xxx) | ((lhs == (-2147483648).xxx) & (r == (-1).xxx))) ? (1).xxx : r));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   const int3 a = int3(1, 2, 3);
   const int b = 4;
-  const int3 r = (a % (b == 0 ? 1 : b));
+  const int3 r = tint_mod(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/mod/vec3-scalar/i32.wgsl.expected.glsl b/test/tint/expressions/binary/mod/vec3-scalar/i32.wgsl.expected.glsl
index 3ae9594..5564275 100644
--- a/test/tint/expressions/binary/mod/vec3-scalar/i32.wgsl.expected.glsl
+++ b/test/tint/expressions/binary/mod/vec3-scalar/i32.wgsl.expected.glsl
@@ -1,9 +1,14 @@
 #version 310 es
 
+ivec3 tint_mod(ivec3 lhs, int rhs) {
+  ivec3 r = ivec3(rhs);
+  return (lhs % mix(r, ivec3(1), bvec3(uvec3(equal(r, ivec3(0))) | uvec3(bvec3(uvec3(equal(lhs, ivec3(-2147483648))) & uvec3(equal(r, ivec3(-1))))))));
+}
+
 void f() {
   ivec3 a = ivec3(1, 2, 3);
   int b = 4;
-  ivec3 r = (a % b);
+  ivec3 r = tint_mod(a, b);
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/expressions/binary/mod/vec3-scalar/i32.wgsl.expected.msl b/test/tint/expressions/binary/mod/vec3-scalar/i32.wgsl.expected.msl
index 8df9cbe..9a30326 100644
--- a/test/tint/expressions/binary/mod/vec3-scalar/i32.wgsl.expected.msl
+++ b/test/tint/expressions/binary/mod/vec3-scalar/i32.wgsl.expected.msl
@@ -1,10 +1,15 @@
 #include <metal_stdlib>
 
 using namespace metal;
+int3 tint_mod(int3 lhs, int rhs) {
+  int3 const r = int3(rhs);
+  return (lhs % select(r, int3(1), ((r == int3(0)) | ((lhs == int3((-2147483647 - 1))) & (r == int3(-1))))));
+}
+
 kernel void f() {
   int3 const a = int3(1, 2, 3);
   int const b = 4;
-  int3 const r = (a % b);
+  int3 const r = tint_mod(a, b);
   return;
 }
 
diff --git a/test/tint/expressions/binary/mod/vec3-scalar/i32.wgsl.expected.spvasm b/test/tint/expressions/binary/mod/vec3-scalar/i32.wgsl.expected.spvasm
index 70a8d1e..3be0691 100644
--- a/test/tint/expressions/binary/mod/vec3-scalar/i32.wgsl.expected.spvasm
+++ b/test/tint/expressions/binary/mod/vec3-scalar/i32.wgsl.expected.spvasm
@@ -1,28 +1,50 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 17
+; Bound: 34
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %f "f"
                OpExecutionMode %f LocalSize 1 1 1
+               OpName %tint_mod "tint_mod"
+               OpName %lhs "lhs"
+               OpName %rhs "rhs"
                OpName %f "f"
-       %void = OpTypeVoid
-          %1 = OpTypeFunction %void
         %int = OpTypeInt 32 1
       %v3int = OpTypeVector %int 3
+          %1 = OpTypeFunction %v3int %v3int %int
+         %10 = OpConstantNull %v3int
+       %bool = OpTypeBool
+     %v3bool = OpTypeVector %bool 3
+%int_n2147483648 = OpConstant %int -2147483648
+         %15 = OpConstantComposite %v3int %int_n2147483648 %int_n2147483648 %int_n2147483648
+     %int_n1 = OpConstant %int -1
+         %18 = OpConstantComposite %v3int %int_n1 %int_n1 %int_n1
       %int_1 = OpConstant %int 1
+         %23 = OpConstantComposite %v3int %int_1 %int_1 %int_1
+       %void = OpTypeVoid
+         %25 = OpTypeFunction %void
       %int_2 = OpConstant %int 2
       %int_3 = OpConstant %int 3
-         %10 = OpConstantComposite %v3int %int_1 %int_2 %int_3
+         %31 = 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 = OpSMod %v3int %10 %16
+   %tint_mod = OpFunction %v3int None %1
+        %lhs = OpFunctionParameter %v3int
+        %rhs = OpFunctionParameter %int
+          %7 = OpLabel
+          %8 = OpCompositeConstruct %v3int %rhs %rhs %rhs
+         %11 = OpIEqual %v3bool %8 %10
+         %16 = OpIEqual %v3bool %lhs %15
+         %19 = OpIEqual %v3bool %8 %18
+         %20 = OpLogicalAnd %v3bool %16 %19
+         %21 = OpLogicalOr %v3bool %11 %20
+          %9 = OpSelect %v3int %21 %23 %8
+         %24 = OpSMod %v3int %lhs %9
+               OpReturnValue %24
+               OpFunctionEnd
+          %f = OpFunction %void None %25
+         %28 = OpLabel
+         %33 = OpFunctionCall %v3int %tint_mod %31 %int_4
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/expressions/binary/mod/vec3-scalar/u32.wgsl.expected.dxc.hlsl b/test/tint/expressions/binary/mod/vec3-scalar/u32.wgsl.expected.dxc.hlsl
index 6a481d4..b547711 100644
--- a/test/tint/expressions/binary/mod/vec3-scalar/u32.wgsl.expected.dxc.hlsl
+++ b/test/tint/expressions/binary/mod/vec3-scalar/u32.wgsl.expected.dxc.hlsl
@@ -1,7 +1,12 @@
+uint3 tint_mod(uint3 lhs, uint rhs) {
+  const uint3 r = uint3((rhs).xxx);
+  return (lhs % ((r == (0u).xxx) ? (1u).xxx : r));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   const uint3 a = uint3(1u, 2u, 3u);
   const uint b = 4u;
-  const uint3 r = (a % (b == 0u ? 1u : b));
+  const uint3 r = tint_mod(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/mod/vec3-scalar/u32.wgsl.expected.fxc.hlsl b/test/tint/expressions/binary/mod/vec3-scalar/u32.wgsl.expected.fxc.hlsl
index 6a481d4..b547711 100644
--- a/test/tint/expressions/binary/mod/vec3-scalar/u32.wgsl.expected.fxc.hlsl
+++ b/test/tint/expressions/binary/mod/vec3-scalar/u32.wgsl.expected.fxc.hlsl
@@ -1,7 +1,12 @@
+uint3 tint_mod(uint3 lhs, uint rhs) {
+  const uint3 r = uint3((rhs).xxx);
+  return (lhs % ((r == (0u).xxx) ? (1u).xxx : r));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   const uint3 a = uint3(1u, 2u, 3u);
   const uint b = 4u;
-  const uint3 r = (a % (b == 0u ? 1u : b));
+  const uint3 r = tint_mod(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/mod/vec3-scalar/u32.wgsl.expected.glsl b/test/tint/expressions/binary/mod/vec3-scalar/u32.wgsl.expected.glsl
index 40204d3..f751327 100644
--- a/test/tint/expressions/binary/mod/vec3-scalar/u32.wgsl.expected.glsl
+++ b/test/tint/expressions/binary/mod/vec3-scalar/u32.wgsl.expected.glsl
@@ -1,9 +1,14 @@
 #version 310 es
 
+uvec3 tint_mod(uvec3 lhs, uint rhs) {
+  uvec3 r = uvec3(rhs);
+  return (lhs % mix(r, uvec3(1u), equal(r, uvec3(0u))));
+}
+
 void f() {
   uvec3 a = uvec3(1u, 2u, 3u);
   uint b = 4u;
-  uvec3 r = (a % b);
+  uvec3 r = tint_mod(a, b);
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/expressions/binary/mod/vec3-scalar/u32.wgsl.expected.msl b/test/tint/expressions/binary/mod/vec3-scalar/u32.wgsl.expected.msl
index 3adb345..ad715a8 100644
--- a/test/tint/expressions/binary/mod/vec3-scalar/u32.wgsl.expected.msl
+++ b/test/tint/expressions/binary/mod/vec3-scalar/u32.wgsl.expected.msl
@@ -1,10 +1,15 @@
 #include <metal_stdlib>
 
 using namespace metal;
+uint3 tint_mod(uint3 lhs, uint rhs) {
+  uint3 const r = uint3(rhs);
+  return (lhs % select(r, uint3(1u), (r == uint3(0u))));
+}
+
 kernel void f() {
   uint3 const a = uint3(1u, 2u, 3u);
   uint const b = 4u;
-  uint3 const r = (a % b);
+  uint3 const r = tint_mod(a, b);
   return;
 }
 
diff --git a/test/tint/expressions/binary/mod/vec3-scalar/u32.wgsl.expected.spvasm b/test/tint/expressions/binary/mod/vec3-scalar/u32.wgsl.expected.spvasm
index 3fdde36..01d662c 100644
--- a/test/tint/expressions/binary/mod/vec3-scalar/u32.wgsl.expected.spvasm
+++ b/test/tint/expressions/binary/mod/vec3-scalar/u32.wgsl.expected.spvasm
@@ -1,28 +1,42 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 17
+; Bound: 26
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %f "f"
                OpExecutionMode %f LocalSize 1 1 1
+               OpName %tint_mod "tint_mod"
+               OpName %lhs "lhs"
+               OpName %rhs "rhs"
                OpName %f "f"
-       %void = OpTypeVoid
-          %1 = OpTypeFunction %void
        %uint = OpTypeInt 32 0
      %v3uint = OpTypeVector %uint 3
+          %1 = OpTypeFunction %v3uint %v3uint %uint
+         %10 = OpConstantNull %v3uint
+       %bool = OpTypeBool
+     %v3bool = OpTypeVector %bool 3
      %uint_1 = OpConstant %uint 1
+         %15 = OpConstantComposite %v3uint %uint_1 %uint_1 %uint_1
+       %void = OpTypeVoid
+         %17 = OpTypeFunction %void
      %uint_2 = OpConstant %uint 2
      %uint_3 = OpConstant %uint 3
-         %10 = OpConstantComposite %v3uint %uint_1 %uint_2 %uint_3
+         %23 = 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 = OpUMod %v3uint %10 %16
+   %tint_mod = OpFunction %v3uint None %1
+        %lhs = OpFunctionParameter %v3uint
+        %rhs = OpFunctionParameter %uint
+          %7 = OpLabel
+          %8 = OpCompositeConstruct %v3uint %rhs %rhs %rhs
+         %11 = OpIEqual %v3bool %8 %10
+          %9 = OpSelect %v3uint %11 %15 %8
+         %16 = OpUMod %v3uint %lhs %9
+               OpReturnValue %16
+               OpFunctionEnd
+          %f = OpFunction %void None %17
+         %20 = OpLabel
+         %25 = OpFunctionCall %v3uint %tint_mod %23 %uint_4
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/expressions/binary/mod/vec3-vec3/i32.wgsl.expected.dxc.hlsl b/test/tint/expressions/binary/mod/vec3-vec3/i32.wgsl.expected.dxc.hlsl
index 86d89a5..c12408d 100644
--- a/test/tint/expressions/binary/mod/vec3-vec3/i32.wgsl.expected.dxc.hlsl
+++ b/test/tint/expressions/binary/mod/vec3-vec3/i32.wgsl.expected.dxc.hlsl
@@ -1,7 +1,11 @@
+int3 tint_mod(int3 lhs, int3 rhs) {
+  return (lhs % (((rhs == (0).xxx) | ((lhs == (-2147483648).xxx) & (rhs == (-1).xxx))) ? (1).xxx : rhs));
+}
+
 [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 == int3(0, 0, 0) ? int3(1, 1, 1) : b));
+  const int3 r = tint_mod(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/mod/vec3-vec3/i32.wgsl.expected.fxc.hlsl b/test/tint/expressions/binary/mod/vec3-vec3/i32.wgsl.expected.fxc.hlsl
index 86d89a5..c12408d 100644
--- a/test/tint/expressions/binary/mod/vec3-vec3/i32.wgsl.expected.fxc.hlsl
+++ b/test/tint/expressions/binary/mod/vec3-vec3/i32.wgsl.expected.fxc.hlsl
@@ -1,7 +1,11 @@
+int3 tint_mod(int3 lhs, int3 rhs) {
+  return (lhs % (((rhs == (0).xxx) | ((lhs == (-2147483648).xxx) & (rhs == (-1).xxx))) ? (1).xxx : rhs));
+}
+
 [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 == int3(0, 0, 0) ? int3(1, 1, 1) : b));
+  const int3 r = tint_mod(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/mod/vec3-vec3/i32.wgsl.expected.glsl b/test/tint/expressions/binary/mod/vec3-vec3/i32.wgsl.expected.glsl
index 56d7104..36bb83c 100644
--- a/test/tint/expressions/binary/mod/vec3-vec3/i32.wgsl.expected.glsl
+++ b/test/tint/expressions/binary/mod/vec3-vec3/i32.wgsl.expected.glsl
@@ -1,9 +1,13 @@
 #version 310 es
 
+ivec3 tint_mod(ivec3 lhs, ivec3 rhs) {
+  return (lhs % mix(rhs, ivec3(1), bvec3(uvec3(equal(rhs, ivec3(0))) | uvec3(bvec3(uvec3(equal(lhs, ivec3(-2147483648))) & uvec3(equal(rhs, ivec3(-1))))))));
+}
+
 void f() {
   ivec3 a = ivec3(1, 2, 3);
   ivec3 b = ivec3(4, 5, 6);
-  ivec3 r = (a % b);
+  ivec3 r = tint_mod(a, b);
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/expressions/binary/mod/vec3-vec3/i32.wgsl.expected.msl b/test/tint/expressions/binary/mod/vec3-vec3/i32.wgsl.expected.msl
index 2bd4b5f..770ab3f 100644
--- a/test/tint/expressions/binary/mod/vec3-vec3/i32.wgsl.expected.msl
+++ b/test/tint/expressions/binary/mod/vec3-vec3/i32.wgsl.expected.msl
@@ -1,10 +1,14 @@
 #include <metal_stdlib>
 
 using namespace metal;
+int3 tint_mod(int3 lhs, int3 rhs) {
+  return (lhs % select(rhs, int3(1), ((rhs == int3(0)) | ((lhs == int3((-2147483647 - 1))) & (rhs == int3(-1))))));
+}
+
 kernel void f() {
   int3 const a = int3(1, 2, 3);
   int3 const b = int3(4, 5, 6);
-  int3 const r = (a % b);
+  int3 const r = tint_mod(a, b);
   return;
 }
 
diff --git a/test/tint/expressions/binary/mod/vec3-vec3/i32.wgsl.expected.spvasm b/test/tint/expressions/binary/mod/vec3-vec3/i32.wgsl.expected.spvasm
index af8e454..36e0abb 100644
--- a/test/tint/expressions/binary/mod/vec3-vec3/i32.wgsl.expected.spvasm
+++ b/test/tint/expressions/binary/mod/vec3-vec3/i32.wgsl.expected.spvasm
@@ -1,27 +1,52 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 16
+; Bound: 36
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %f "f"
                OpExecutionMode %f LocalSize 1 1 1
+               OpName %tint_mod "tint_mod"
+               OpName %lhs "lhs"
+               OpName %rhs "rhs"
                OpName %f "f"
-       %void = OpTypeVoid
-          %1 = OpTypeFunction %void
         %int = OpTypeInt 32 1
       %v3int = OpTypeVector %int 3
+          %1 = OpTypeFunction %v3int %v3int %v3int
+          %9 = OpConstantNull %v3int
+       %bool = OpTypeBool
+     %v3bool = OpTypeVector %bool 3
+%int_n2147483648 = OpConstant %int -2147483648
+         %14 = OpConstantComposite %v3int %int_n2147483648 %int_n2147483648 %int_n2147483648
+     %int_n1 = OpConstant %int -1
+         %17 = OpConstantComposite %v3int %int_n1 %int_n1 %int_n1
       %int_1 = OpConstant %int 1
+         %22 = OpConstantComposite %v3int %int_1 %int_1 %int_1
+       %void = OpTypeVoid
+         %24 = OpTypeFunction %void
       %int_2 = OpConstant %int 2
       %int_3 = OpConstant %int 3
-         %10 = OpConstantComposite %v3int %int_1 %int_2 %int_3
+         %30 = 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
+         %34 = OpConstantComposite %v3int %int_4 %int_5 %int_6
+   %tint_mod = OpFunction %v3int None %1
+        %lhs = OpFunctionParameter %v3int
+        %rhs = OpFunctionParameter %v3int
+          %7 = OpLabel
+         %10 = OpIEqual %v3bool %rhs %9
+         %15 = OpIEqual %v3bool %lhs %14
+         %18 = OpIEqual %v3bool %rhs %17
+         %19 = OpLogicalAnd %v3bool %15 %18
+         %20 = OpLogicalOr %v3bool %10 %19
+          %8 = OpSelect %v3int %20 %22 %rhs
+         %23 = OpSMod %v3int %lhs %8
+               OpReturnValue %23
+               OpFunctionEnd
+          %f = OpFunction %void None %24
+         %27 = OpLabel
+         %35 = OpFunctionCall %v3int %tint_mod %30 %34
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/expressions/binary/mod/vec3-vec3/u32.wgsl.expected.dxc.hlsl b/test/tint/expressions/binary/mod/vec3-vec3/u32.wgsl.expected.dxc.hlsl
index 5d234b8..d543c85 100644
--- a/test/tint/expressions/binary/mod/vec3-vec3/u32.wgsl.expected.dxc.hlsl
+++ b/test/tint/expressions/binary/mod/vec3-vec3/u32.wgsl.expected.dxc.hlsl
@@ -1,7 +1,11 @@
+uint3 tint_mod(uint3 lhs, uint3 rhs) {
+  return (lhs % ((rhs == (0u).xxx) ? (1u).xxx : rhs));
+}
+
 [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 == uint3(0u, 0u, 0u) ? uint3(1u, 1u, 1u) : b));
+  const uint3 r = tint_mod(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/mod/vec3-vec3/u32.wgsl.expected.fxc.hlsl b/test/tint/expressions/binary/mod/vec3-vec3/u32.wgsl.expected.fxc.hlsl
index 5d234b8..d543c85 100644
--- a/test/tint/expressions/binary/mod/vec3-vec3/u32.wgsl.expected.fxc.hlsl
+++ b/test/tint/expressions/binary/mod/vec3-vec3/u32.wgsl.expected.fxc.hlsl
@@ -1,7 +1,11 @@
+uint3 tint_mod(uint3 lhs, uint3 rhs) {
+  return (lhs % ((rhs == (0u).xxx) ? (1u).xxx : rhs));
+}
+
 [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 == uint3(0u, 0u, 0u) ? uint3(1u, 1u, 1u) : b));
+  const uint3 r = tint_mod(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/mod/vec3-vec3/u32.wgsl.expected.glsl b/test/tint/expressions/binary/mod/vec3-vec3/u32.wgsl.expected.glsl
index bd85a3e..78f3803 100644
--- a/test/tint/expressions/binary/mod/vec3-vec3/u32.wgsl.expected.glsl
+++ b/test/tint/expressions/binary/mod/vec3-vec3/u32.wgsl.expected.glsl
@@ -1,9 +1,13 @@
 #version 310 es
 
+uvec3 tint_mod(uvec3 lhs, uvec3 rhs) {
+  return (lhs % mix(rhs, uvec3(1u), equal(rhs, uvec3(0u))));
+}
+
 void f() {
   uvec3 a = uvec3(1u, 2u, 3u);
   uvec3 b = uvec3(4u, 5u, 6u);
-  uvec3 r = (a % b);
+  uvec3 r = tint_mod(a, b);
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/expressions/binary/mod/vec3-vec3/u32.wgsl.expected.msl b/test/tint/expressions/binary/mod/vec3-vec3/u32.wgsl.expected.msl
index 954924c..66fe1c5 100644
--- a/test/tint/expressions/binary/mod/vec3-vec3/u32.wgsl.expected.msl
+++ b/test/tint/expressions/binary/mod/vec3-vec3/u32.wgsl.expected.msl
@@ -1,10 +1,14 @@
 #include <metal_stdlib>
 
 using namespace metal;
+uint3 tint_mod(uint3 lhs, uint3 rhs) {
+  return (lhs % select(rhs, uint3(1u), (rhs == uint3(0u))));
+}
+
 kernel void f() {
   uint3 const a = uint3(1u, 2u, 3u);
   uint3 const b = uint3(4u, 5u, 6u);
-  uint3 const r = (a % b);
+  uint3 const r = tint_mod(a, b);
   return;
 }
 
diff --git a/test/tint/expressions/binary/mod/vec3-vec3/u32.wgsl.expected.spvasm b/test/tint/expressions/binary/mod/vec3-vec3/u32.wgsl.expected.spvasm
index 6f69999..bfc25a5 100644
--- a/test/tint/expressions/binary/mod/vec3-vec3/u32.wgsl.expected.spvasm
+++ b/test/tint/expressions/binary/mod/vec3-vec3/u32.wgsl.expected.spvasm
@@ -1,27 +1,44 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 16
+; Bound: 28
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %f "f"
                OpExecutionMode %f LocalSize 1 1 1
+               OpName %tint_mod "tint_mod"
+               OpName %lhs "lhs"
+               OpName %rhs "rhs"
                OpName %f "f"
-       %void = OpTypeVoid
-          %1 = OpTypeFunction %void
        %uint = OpTypeInt 32 0
      %v3uint = OpTypeVector %uint 3
+          %1 = OpTypeFunction %v3uint %v3uint %v3uint
+          %9 = OpConstantNull %v3uint
+       %bool = OpTypeBool
+     %v3bool = OpTypeVector %bool 3
      %uint_1 = OpConstant %uint 1
+         %14 = OpConstantComposite %v3uint %uint_1 %uint_1 %uint_1
+       %void = OpTypeVoid
+         %16 = OpTypeFunction %void
      %uint_2 = OpConstant %uint 2
      %uint_3 = OpConstant %uint 3
-         %10 = OpConstantComposite %v3uint %uint_1 %uint_2 %uint_3
+         %22 = 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
+         %26 = OpConstantComposite %v3uint %uint_4 %uint_5 %uint_6
+   %tint_mod = OpFunction %v3uint None %1
+        %lhs = OpFunctionParameter %v3uint
+        %rhs = OpFunctionParameter %v3uint
+          %7 = OpLabel
+         %10 = OpIEqual %v3bool %rhs %9
+          %8 = OpSelect %v3uint %10 %14 %rhs
+         %15 = OpUMod %v3uint %lhs %8
+               OpReturnValue %15
+               OpFunctionEnd
+          %f = OpFunction %void None %16
+         %19 = OpLabel
+         %27 = OpFunctionCall %v3uint %tint_mod %22 %26
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-scalar/i32.wgsl.expected.dxc.hlsl b/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-scalar/i32.wgsl.expected.dxc.hlsl
index 7511c96..a5f5597 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-scalar/i32.wgsl.expected.dxc.hlsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-scalar/i32.wgsl.expected.dxc.hlsl
@@ -1,7 +1,11 @@
+int tint_mod(int lhs, int rhs) {
+  return (lhs % (((rhs == 0) | ((lhs == -2147483648) & (rhs == -1))) ? 1 : rhs));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   const int a = 1;
   const int b = 0;
-  const int r = (a % (b == 0 ? 1 : b));
+  const int r = tint_mod(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-scalar/i32.wgsl.expected.fxc.hlsl b/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-scalar/i32.wgsl.expected.fxc.hlsl
index 7511c96..a5f5597 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-scalar/i32.wgsl.expected.fxc.hlsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-scalar/i32.wgsl.expected.fxc.hlsl
@@ -1,7 +1,11 @@
+int tint_mod(int lhs, int rhs) {
+  return (lhs % (((rhs == 0) | ((lhs == -2147483648) & (rhs == -1))) ? 1 : rhs));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   const int a = 1;
   const int b = 0;
-  const int r = (a % (b == 0 ? 1 : b));
+  const int r = tint_mod(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-scalar/i32.wgsl.expected.glsl b/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-scalar/i32.wgsl.expected.glsl
index 1f7158f..ddb6a6b 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-scalar/i32.wgsl.expected.glsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-scalar/i32.wgsl.expected.glsl
@@ -1,9 +1,13 @@
 #version 310 es
 
+int tint_mod(int lhs, int rhs) {
+  return (lhs % (bool(uint((rhs == 0)) | uint(bool(uint((lhs == -2147483648)) & uint((rhs == -1))))) ? 1 : rhs));
+}
+
 void f() {
   int a = 1;
   int b = 0;
-  int r = (a % b);
+  int r = tint_mod(a, b);
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-scalar/i32.wgsl.expected.msl b/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-scalar/i32.wgsl.expected.msl
index 98f1698..8d879ce 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-scalar/i32.wgsl.expected.msl
+++ b/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-scalar/i32.wgsl.expected.msl
@@ -1,10 +1,14 @@
 #include <metal_stdlib>
 
 using namespace metal;
+int tint_mod(int lhs, int rhs) {
+  return (lhs % select(rhs, 1, bool((rhs == 0) | bool((lhs == (-2147483647 - 1)) & (rhs == -1)))));
+}
+
 kernel void f() {
   int const a = 1;
   int const b = 0;
-  int const r = (a % b);
+  int const r = tint_mod(a, b);
   return;
 }
 
diff --git a/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-scalar/i32.wgsl.expected.spvasm b/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-scalar/i32.wgsl.expected.spvasm
index bf9393f..a384178 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-scalar/i32.wgsl.expected.spvasm
+++ b/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-scalar/i32.wgsl.expected.spvasm
@@ -1,20 +1,40 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 9
+; Bound: 24
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %f "f"
                OpExecutionMode %f LocalSize 1 1 1
+               OpName %tint_mod "tint_mod"
+               OpName %lhs "lhs"
+               OpName %rhs "rhs"
                OpName %f "f"
-       %void = OpTypeVoid
-          %1 = OpTypeFunction %void
         %int = OpTypeInt 32 1
+          %1 = OpTypeFunction %int %int %int
+          %8 = OpConstantNull %int
+       %bool = OpTypeBool
+%int_n2147483648 = OpConstant %int -2147483648
+     %int_n1 = OpConstant %int -1
       %int_1 = OpConstant %int 1
-          %7 = OpConstantNull %int
-          %f = OpFunction %void None %1
-          %4 = OpLabel
-          %8 = OpSMod %int %int_1 %7
+       %void = OpTypeVoid
+         %19 = OpTypeFunction %void
+   %tint_mod = OpFunction %int None %1
+        %lhs = OpFunctionParameter %int
+        %rhs = OpFunctionParameter %int
+          %6 = OpLabel
+          %9 = OpIEqual %bool %rhs %8
+         %12 = OpIEqual %bool %lhs %int_n2147483648
+         %14 = OpIEqual %bool %rhs %int_n1
+         %15 = OpLogicalAnd %bool %12 %14
+         %16 = OpLogicalOr %bool %9 %15
+          %7 = OpSelect %int %16 %int_1 %rhs
+         %18 = OpSMod %int %lhs %7
+               OpReturnValue %18
+               OpFunctionEnd
+          %f = OpFunction %void None %19
+         %22 = OpLabel
+         %23 = OpFunctionCall %int %tint_mod %int_1 %8
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-scalar/u32.wgsl.expected.dxc.hlsl b/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-scalar/u32.wgsl.expected.dxc.hlsl
index 16b133d..cf35054 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-scalar/u32.wgsl.expected.dxc.hlsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-scalar/u32.wgsl.expected.dxc.hlsl
@@ -1,7 +1,11 @@
+uint tint_mod(uint lhs, uint rhs) {
+  return (lhs % ((rhs == 0u) ? 1u : rhs));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   const uint a = 1u;
   const uint b = 0u;
-  const uint r = (a % (b == 0u ? 1u : b));
+  const uint r = tint_mod(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-scalar/u32.wgsl.expected.fxc.hlsl b/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-scalar/u32.wgsl.expected.fxc.hlsl
index 16b133d..cf35054 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-scalar/u32.wgsl.expected.fxc.hlsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-scalar/u32.wgsl.expected.fxc.hlsl
@@ -1,7 +1,11 @@
+uint tint_mod(uint lhs, uint rhs) {
+  return (lhs % ((rhs == 0u) ? 1u : rhs));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   const uint a = 1u;
   const uint b = 0u;
-  const uint r = (a % (b == 0u ? 1u : b));
+  const uint r = tint_mod(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-scalar/u32.wgsl.expected.glsl b/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-scalar/u32.wgsl.expected.glsl
index d30fde8..9fd11d7 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-scalar/u32.wgsl.expected.glsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-scalar/u32.wgsl.expected.glsl
@@ -1,9 +1,13 @@
 #version 310 es
 
+uint tint_mod(uint lhs, uint rhs) {
+  return (lhs % ((rhs == 0u) ? 1u : rhs));
+}
+
 void f() {
   uint a = 1u;
   uint b = 0u;
-  uint r = (a % b);
+  uint r = tint_mod(a, b);
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-scalar/u32.wgsl.expected.msl b/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-scalar/u32.wgsl.expected.msl
index 456e3b9..5ab74b7 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-scalar/u32.wgsl.expected.msl
+++ b/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-scalar/u32.wgsl.expected.msl
@@ -1,10 +1,14 @@
 #include <metal_stdlib>
 
 using namespace metal;
+uint tint_mod(uint lhs, uint rhs) {
+  return (lhs % select(rhs, 1u, (rhs == 0u)));
+}
+
 kernel void f() {
   uint const a = 1u;
   uint const b = 0u;
-  uint const r = (a % b);
+  uint const r = tint_mod(a, b);
   return;
 }
 
diff --git a/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-scalar/u32.wgsl.expected.spvasm b/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-scalar/u32.wgsl.expected.spvasm
index 94d2263..f429d84 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-scalar/u32.wgsl.expected.spvasm
+++ b/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-scalar/u32.wgsl.expected.spvasm
@@ -1,20 +1,34 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 9
+; Bound: 18
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %f "f"
                OpExecutionMode %f LocalSize 1 1 1
+               OpName %tint_mod "tint_mod"
+               OpName %lhs "lhs"
+               OpName %rhs "rhs"
                OpName %f "f"
-       %void = OpTypeVoid
-          %1 = OpTypeFunction %void
        %uint = OpTypeInt 32 0
+          %1 = OpTypeFunction %uint %uint %uint
+          %8 = OpConstantNull %uint
+       %bool = OpTypeBool
      %uint_1 = OpConstant %uint 1
-          %7 = OpConstantNull %uint
-          %f = OpFunction %void None %1
-          %4 = OpLabel
-          %8 = OpUMod %uint %uint_1 %7
+       %void = OpTypeVoid
+         %13 = OpTypeFunction %void
+   %tint_mod = OpFunction %uint None %1
+        %lhs = OpFunctionParameter %uint
+        %rhs = OpFunctionParameter %uint
+          %6 = OpLabel
+          %9 = OpIEqual %bool %rhs %8
+          %7 = OpSelect %uint %9 %uint_1 %rhs
+         %12 = OpUMod %uint %lhs %7
+               OpReturnValue %12
+               OpFunctionEnd
+          %f = OpFunction %void None %13
+         %16 = OpLabel
+         %17 = OpFunctionCall %uint %tint_mod %uint_1 %8
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-vec3/i32.wgsl.expected.dxc.hlsl b/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-vec3/i32.wgsl.expected.dxc.hlsl
index dfe722c..f199262 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-vec3/i32.wgsl.expected.dxc.hlsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-vec3/i32.wgsl.expected.dxc.hlsl
@@ -1,7 +1,12 @@
+int3 tint_mod(int lhs, int3 rhs) {
+  const int3 l = int3((lhs).xxx);
+  return (l % (((rhs == (0).xxx) | ((l == (-2147483648).xxx) & (rhs == (-1).xxx))) ? (1).xxx : rhs));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   const int a = 4;
   const int3 b = int3(0, 2, 0);
-  const int3 r = (a % (b == int3(0, 0, 0) ? int3(1, 1, 1) : b));
+  const int3 r = tint_mod(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-vec3/i32.wgsl.expected.fxc.hlsl b/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-vec3/i32.wgsl.expected.fxc.hlsl
index dfe722c..f199262 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-vec3/i32.wgsl.expected.fxc.hlsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-vec3/i32.wgsl.expected.fxc.hlsl
@@ -1,7 +1,12 @@
+int3 tint_mod(int lhs, int3 rhs) {
+  const int3 l = int3((lhs).xxx);
+  return (l % (((rhs == (0).xxx) | ((l == (-2147483648).xxx) & (rhs == (-1).xxx))) ? (1).xxx : rhs));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   const int a = 4;
   const int3 b = int3(0, 2, 0);
-  const int3 r = (a % (b == int3(0, 0, 0) ? int3(1, 1, 1) : b));
+  const int3 r = tint_mod(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-vec3/i32.wgsl.expected.glsl b/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-vec3/i32.wgsl.expected.glsl
index e19dc46..412aedf 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-vec3/i32.wgsl.expected.glsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-vec3/i32.wgsl.expected.glsl
@@ -1,9 +1,14 @@
 #version 310 es
 
+ivec3 tint_mod(int lhs, ivec3 rhs) {
+  ivec3 l = ivec3(lhs);
+  return (l % mix(rhs, ivec3(1), bvec3(uvec3(equal(rhs, ivec3(0))) | uvec3(bvec3(uvec3(equal(l, ivec3(-2147483648))) & uvec3(equal(rhs, ivec3(-1))))))));
+}
+
 void f() {
   int a = 4;
   ivec3 b = ivec3(0, 2, 0);
-  ivec3 r = (a % b);
+  ivec3 r = tint_mod(a, b);
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-vec3/i32.wgsl.expected.msl b/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-vec3/i32.wgsl.expected.msl
index 95a93f7..49b1bee 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-vec3/i32.wgsl.expected.msl
+++ b/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-vec3/i32.wgsl.expected.msl
@@ -1,10 +1,15 @@
 #include <metal_stdlib>
 
 using namespace metal;
+int3 tint_mod(int lhs, int3 rhs) {
+  int3 const l = int3(lhs);
+  return (l % select(rhs, int3(1), ((rhs == int3(0)) | ((l == int3((-2147483647 - 1))) & (rhs == int3(-1))))));
+}
+
 kernel void f() {
   int const a = 4;
   int3 const b = int3(0, 2, 0);
-  int3 const r = (a % b);
+  int3 const r = tint_mod(a, b);
   return;
 }
 
diff --git a/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-vec3/i32.wgsl.expected.spvasm b/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-vec3/i32.wgsl.expected.spvasm
index 65d27ce..860c94d 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-vec3/i32.wgsl.expected.spvasm
+++ b/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-vec3/i32.wgsl.expected.spvasm
@@ -1,27 +1,50 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 16
+; Bound: 34
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %f "f"
                OpExecutionMode %f LocalSize 1 1 1
+               OpName %tint_mod "tint_mod"
+               OpName %lhs "lhs"
+               OpName %rhs "rhs"
                OpName %f "f"
-       %void = OpTypeVoid
-          %1 = OpTypeFunction %void
         %int = OpTypeInt 32 1
-      %int_4 = OpConstant %int 4
       %v3int = OpTypeVector %int 3
-          %8 = OpConstantNull %int
+          %1 = OpTypeFunction %v3int %int %v3int
+         %10 = OpConstantNull %v3int
+       %bool = OpTypeBool
+     %v3bool = OpTypeVector %bool 3
+%int_n2147483648 = OpConstant %int -2147483648
+         %15 = OpConstantComposite %v3int %int_n2147483648 %int_n2147483648 %int_n2147483648
+     %int_n1 = OpConstant %int -1
+         %18 = OpConstantComposite %v3int %int_n1 %int_n1 %int_n1
+      %int_1 = OpConstant %int 1
+         %23 = OpConstantComposite %v3int %int_1 %int_1 %int_1
+       %void = OpTypeVoid
+         %25 = OpTypeFunction %void
+      %int_4 = OpConstant %int 4
+         %30 = OpConstantNull %int
       %int_2 = OpConstant %int 2
-         %10 = OpConstantComposite %v3int %8 %int_2 %8
-%_ptr_Function_v3int = OpTypePointer Function %v3int
-         %14 = OpConstantNull %v3int
-          %f = OpFunction %void None %1
-          %4 = OpLabel
-         %12 = OpVariable %_ptr_Function_v3int Function %14
-         %15 = OpCompositeConstruct %v3int %int_4 %int_4 %int_4
-         %11 = OpSMod %v3int %15 %10
+         %32 = OpConstantComposite %v3int %30 %int_2 %30
+   %tint_mod = OpFunction %v3int None %1
+        %lhs = OpFunctionParameter %int
+        %rhs = OpFunctionParameter %v3int
+          %7 = OpLabel
+          %8 = OpCompositeConstruct %v3int %lhs %lhs %lhs
+         %11 = OpIEqual %v3bool %rhs %10
+         %16 = OpIEqual %v3bool %8 %15
+         %19 = OpIEqual %v3bool %rhs %18
+         %20 = OpLogicalAnd %v3bool %16 %19
+         %21 = OpLogicalOr %v3bool %11 %20
+          %9 = OpSelect %v3int %21 %23 %rhs
+         %24 = OpSMod %v3int %8 %9
+               OpReturnValue %24
+               OpFunctionEnd
+          %f = OpFunction %void None %25
+         %28 = OpLabel
+         %33 = OpFunctionCall %v3int %tint_mod %int_4 %32
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-vec3/u32.wgsl.expected.dxc.hlsl b/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-vec3/u32.wgsl.expected.dxc.hlsl
index 5583772..1866409 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-vec3/u32.wgsl.expected.dxc.hlsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-vec3/u32.wgsl.expected.dxc.hlsl
@@ -1,7 +1,12 @@
+uint3 tint_mod(uint lhs, uint3 rhs) {
+  const uint3 l = uint3((lhs).xxx);
+  return (l % ((rhs == (0u).xxx) ? (1u).xxx : rhs));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   const uint a = 4u;
   const uint3 b = uint3(0u, 2u, 0u);
-  const uint3 r = (a % (b == uint3(0u, 0u, 0u) ? uint3(1u, 1u, 1u) : b));
+  const uint3 r = tint_mod(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-vec3/u32.wgsl.expected.fxc.hlsl b/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-vec3/u32.wgsl.expected.fxc.hlsl
index 5583772..1866409 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-vec3/u32.wgsl.expected.fxc.hlsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-vec3/u32.wgsl.expected.fxc.hlsl
@@ -1,7 +1,12 @@
+uint3 tint_mod(uint lhs, uint3 rhs) {
+  const uint3 l = uint3((lhs).xxx);
+  return (l % ((rhs == (0u).xxx) ? (1u).xxx : rhs));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   const uint a = 4u;
   const uint3 b = uint3(0u, 2u, 0u);
-  const uint3 r = (a % (b == uint3(0u, 0u, 0u) ? uint3(1u, 1u, 1u) : b));
+  const uint3 r = tint_mod(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-vec3/u32.wgsl.expected.glsl b/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-vec3/u32.wgsl.expected.glsl
index 633b9ed..534cab7 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-vec3/u32.wgsl.expected.glsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-vec3/u32.wgsl.expected.glsl
@@ -1,9 +1,14 @@
 #version 310 es
 
+uvec3 tint_mod(uint lhs, uvec3 rhs) {
+  uvec3 l = uvec3(lhs);
+  return (l % mix(rhs, uvec3(1u), equal(rhs, uvec3(0u))));
+}
+
 void f() {
   uint a = 4u;
   uvec3 b = uvec3(0u, 2u, 0u);
-  uvec3 r = (a % b);
+  uvec3 r = tint_mod(a, b);
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-vec3/u32.wgsl.expected.msl b/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-vec3/u32.wgsl.expected.msl
index 16fa025..1b3131f 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-vec3/u32.wgsl.expected.msl
+++ b/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-vec3/u32.wgsl.expected.msl
@@ -1,10 +1,15 @@
 #include <metal_stdlib>
 
 using namespace metal;
+uint3 tint_mod(uint lhs, uint3 rhs) {
+  uint3 const l = uint3(lhs);
+  return (l % select(rhs, uint3(1u), (rhs == uint3(0u))));
+}
+
 kernel void f() {
   uint const a = 4u;
   uint3 const b = uint3(0u, 2u, 0u);
-  uint3 const r = (a % b);
+  uint3 const r = tint_mod(a, b);
   return;
 }
 
diff --git a/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-vec3/u32.wgsl.expected.spvasm b/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-vec3/u32.wgsl.expected.spvasm
index 03b0409..f5f8925 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-vec3/u32.wgsl.expected.spvasm
+++ b/test/tint/expressions/binary/mod_by_zero/by_constant/scalar-vec3/u32.wgsl.expected.spvasm
@@ -1,27 +1,42 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 16
+; Bound: 26
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %f "f"
                OpExecutionMode %f LocalSize 1 1 1
+               OpName %tint_mod "tint_mod"
+               OpName %lhs "lhs"
+               OpName %rhs "rhs"
                OpName %f "f"
-       %void = OpTypeVoid
-          %1 = OpTypeFunction %void
        %uint = OpTypeInt 32 0
-     %uint_4 = OpConstant %uint 4
      %v3uint = OpTypeVector %uint 3
-          %8 = OpConstantNull %uint
+          %1 = OpTypeFunction %v3uint %uint %v3uint
+         %10 = OpConstantNull %v3uint
+       %bool = OpTypeBool
+     %v3bool = OpTypeVector %bool 3
+     %uint_1 = OpConstant %uint 1
+         %15 = OpConstantComposite %v3uint %uint_1 %uint_1 %uint_1
+       %void = OpTypeVoid
+         %17 = OpTypeFunction %void
+     %uint_4 = OpConstant %uint 4
+         %22 = OpConstantNull %uint
      %uint_2 = OpConstant %uint 2
-         %10 = OpConstantComposite %v3uint %8 %uint_2 %8
-%_ptr_Function_v3uint = OpTypePointer Function %v3uint
-         %14 = OpConstantNull %v3uint
-          %f = OpFunction %void None %1
-          %4 = OpLabel
-         %12 = OpVariable %_ptr_Function_v3uint Function %14
-         %15 = OpCompositeConstruct %v3uint %uint_4 %uint_4 %uint_4
-         %11 = OpUMod %v3uint %15 %10
+         %24 = OpConstantComposite %v3uint %22 %uint_2 %22
+   %tint_mod = OpFunction %v3uint None %1
+        %lhs = OpFunctionParameter %uint
+        %rhs = OpFunctionParameter %v3uint
+          %7 = OpLabel
+          %8 = OpCompositeConstruct %v3uint %lhs %lhs %lhs
+         %11 = OpIEqual %v3bool %rhs %10
+          %9 = OpSelect %v3uint %11 %15 %rhs
+         %16 = OpUMod %v3uint %8 %9
+               OpReturnValue %16
+               OpFunctionEnd
+          %f = OpFunction %void None %17
+         %20 = OpLabel
+         %25 = OpFunctionCall %v3uint %tint_mod %uint_4 %24
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-scalar/i32.wgsl.expected.dxc.hlsl b/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-scalar/i32.wgsl.expected.dxc.hlsl
index 63e5792..418539b 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-scalar/i32.wgsl.expected.dxc.hlsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-scalar/i32.wgsl.expected.dxc.hlsl
@@ -1,7 +1,12 @@
+int3 tint_mod(int3 lhs, int rhs) {
+  const int3 r = int3((rhs).xxx);
+  return (lhs % (((r == (0).xxx) | ((lhs == (-2147483648).xxx) & (r == (-1).xxx))) ? (1).xxx : r));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   const int3 a = int3(1, 2, 3);
   const int b = 0;
-  const int3 r = (a % (b == 0 ? 1 : b));
+  const int3 r = tint_mod(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-scalar/i32.wgsl.expected.fxc.hlsl b/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-scalar/i32.wgsl.expected.fxc.hlsl
index 63e5792..418539b 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-scalar/i32.wgsl.expected.fxc.hlsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-scalar/i32.wgsl.expected.fxc.hlsl
@@ -1,7 +1,12 @@
+int3 tint_mod(int3 lhs, int rhs) {
+  const int3 r = int3((rhs).xxx);
+  return (lhs % (((r == (0).xxx) | ((lhs == (-2147483648).xxx) & (r == (-1).xxx))) ? (1).xxx : r));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   const int3 a = int3(1, 2, 3);
   const int b = 0;
-  const int3 r = (a % (b == 0 ? 1 : b));
+  const int3 r = tint_mod(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-scalar/i32.wgsl.expected.glsl b/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-scalar/i32.wgsl.expected.glsl
index d74047a..788c7fe 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-scalar/i32.wgsl.expected.glsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-scalar/i32.wgsl.expected.glsl
@@ -1,9 +1,14 @@
 #version 310 es
 
+ivec3 tint_mod(ivec3 lhs, int rhs) {
+  ivec3 r = ivec3(rhs);
+  return (lhs % mix(r, ivec3(1), bvec3(uvec3(equal(r, ivec3(0))) | uvec3(bvec3(uvec3(equal(lhs, ivec3(-2147483648))) & uvec3(equal(r, ivec3(-1))))))));
+}
+
 void f() {
   ivec3 a = ivec3(1, 2, 3);
   int b = 0;
-  ivec3 r = (a % b);
+  ivec3 r = tint_mod(a, b);
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-scalar/i32.wgsl.expected.msl b/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-scalar/i32.wgsl.expected.msl
index cbac4c7..a3b8e52 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-scalar/i32.wgsl.expected.msl
+++ b/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-scalar/i32.wgsl.expected.msl
@@ -1,10 +1,15 @@
 #include <metal_stdlib>
 
 using namespace metal;
+int3 tint_mod(int3 lhs, int rhs) {
+  int3 const r = int3(rhs);
+  return (lhs % select(r, int3(1), ((r == int3(0)) | ((lhs == int3((-2147483647 - 1))) & (r == int3(-1))))));
+}
+
 kernel void f() {
   int3 const a = int3(1, 2, 3);
   int const b = 0;
-  int3 const r = (a % b);
+  int3 const r = tint_mod(a, b);
   return;
 }
 
diff --git a/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-scalar/i32.wgsl.expected.spvasm b/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-scalar/i32.wgsl.expected.spvasm
index 64592c9..bef3e02 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-scalar/i32.wgsl.expected.spvasm
+++ b/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-scalar/i32.wgsl.expected.spvasm
@@ -1,28 +1,50 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 17
+; Bound: 34
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %f "f"
                OpExecutionMode %f LocalSize 1 1 1
+               OpName %tint_mod "tint_mod"
+               OpName %lhs "lhs"
+               OpName %rhs "rhs"
                OpName %f "f"
-       %void = OpTypeVoid
-          %1 = OpTypeFunction %void
         %int = OpTypeInt 32 1
       %v3int = OpTypeVector %int 3
+          %1 = OpTypeFunction %v3int %v3int %int
+         %10 = OpConstantNull %v3int
+       %bool = OpTypeBool
+     %v3bool = OpTypeVector %bool 3
+%int_n2147483648 = OpConstant %int -2147483648
+         %15 = OpConstantComposite %v3int %int_n2147483648 %int_n2147483648 %int_n2147483648
+     %int_n1 = OpConstant %int -1
+         %18 = OpConstantComposite %v3int %int_n1 %int_n1 %int_n1
       %int_1 = OpConstant %int 1
+         %23 = OpConstantComposite %v3int %int_1 %int_1 %int_1
+       %void = OpTypeVoid
+         %25 = OpTypeFunction %void
       %int_2 = OpConstant %int 2
       %int_3 = OpConstant %int 3
-         %10 = OpConstantComposite %v3int %int_1 %int_2 %int_3
-         %11 = OpConstantNull %int
-%_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 %11 %11 %11
-         %12 = OpSMod %v3int %10 %16
+         %31 = OpConstantComposite %v3int %int_1 %int_2 %int_3
+         %32 = OpConstantNull %int
+   %tint_mod = OpFunction %v3int None %1
+        %lhs = OpFunctionParameter %v3int
+        %rhs = OpFunctionParameter %int
+          %7 = OpLabel
+          %8 = OpCompositeConstruct %v3int %rhs %rhs %rhs
+         %11 = OpIEqual %v3bool %8 %10
+         %16 = OpIEqual %v3bool %lhs %15
+         %19 = OpIEqual %v3bool %8 %18
+         %20 = OpLogicalAnd %v3bool %16 %19
+         %21 = OpLogicalOr %v3bool %11 %20
+          %9 = OpSelect %v3int %21 %23 %8
+         %24 = OpSMod %v3int %lhs %9
+               OpReturnValue %24
+               OpFunctionEnd
+          %f = OpFunction %void None %25
+         %28 = OpLabel
+         %33 = OpFunctionCall %v3int %tint_mod %31 %32
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-scalar/u32.wgsl.expected.dxc.hlsl b/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-scalar/u32.wgsl.expected.dxc.hlsl
index 4da3d28..3274f28 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-scalar/u32.wgsl.expected.dxc.hlsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-scalar/u32.wgsl.expected.dxc.hlsl
@@ -1,7 +1,12 @@
+uint3 tint_mod(uint3 lhs, uint rhs) {
+  const uint3 r = uint3((rhs).xxx);
+  return (lhs % ((r == (0u).xxx) ? (1u).xxx : r));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   const uint3 a = uint3(1u, 2u, 3u);
   const uint b = 0u;
-  const uint3 r = (a % (b == 0u ? 1u : b));
+  const uint3 r = tint_mod(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-scalar/u32.wgsl.expected.fxc.hlsl b/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-scalar/u32.wgsl.expected.fxc.hlsl
index 4da3d28..3274f28 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-scalar/u32.wgsl.expected.fxc.hlsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-scalar/u32.wgsl.expected.fxc.hlsl
@@ -1,7 +1,12 @@
+uint3 tint_mod(uint3 lhs, uint rhs) {
+  const uint3 r = uint3((rhs).xxx);
+  return (lhs % ((r == (0u).xxx) ? (1u).xxx : r));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   const uint3 a = uint3(1u, 2u, 3u);
   const uint b = 0u;
-  const uint3 r = (a % (b == 0u ? 1u : b));
+  const uint3 r = tint_mod(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-scalar/u32.wgsl.expected.glsl b/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-scalar/u32.wgsl.expected.glsl
index d84b14b1..03f7867 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-scalar/u32.wgsl.expected.glsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-scalar/u32.wgsl.expected.glsl
@@ -1,9 +1,14 @@
 #version 310 es
 
+uvec3 tint_mod(uvec3 lhs, uint rhs) {
+  uvec3 r = uvec3(rhs);
+  return (lhs % mix(r, uvec3(1u), equal(r, uvec3(0u))));
+}
+
 void f() {
   uvec3 a = uvec3(1u, 2u, 3u);
   uint b = 0u;
-  uvec3 r = (a % b);
+  uvec3 r = tint_mod(a, b);
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-scalar/u32.wgsl.expected.msl b/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-scalar/u32.wgsl.expected.msl
index 78398ec..ff6d8d1 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-scalar/u32.wgsl.expected.msl
+++ b/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-scalar/u32.wgsl.expected.msl
@@ -1,10 +1,15 @@
 #include <metal_stdlib>
 
 using namespace metal;
+uint3 tint_mod(uint3 lhs, uint rhs) {
+  uint3 const r = uint3(rhs);
+  return (lhs % select(r, uint3(1u), (r == uint3(0u))));
+}
+
 kernel void f() {
   uint3 const a = uint3(1u, 2u, 3u);
   uint const b = 0u;
-  uint3 const r = (a % b);
+  uint3 const r = tint_mod(a, b);
   return;
 }
 
diff --git a/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-scalar/u32.wgsl.expected.spvasm b/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-scalar/u32.wgsl.expected.spvasm
index 79e64e8..e60c38b 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-scalar/u32.wgsl.expected.spvasm
+++ b/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-scalar/u32.wgsl.expected.spvasm
@@ -1,28 +1,42 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 17
+; Bound: 26
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %f "f"
                OpExecutionMode %f LocalSize 1 1 1
+               OpName %tint_mod "tint_mod"
+               OpName %lhs "lhs"
+               OpName %rhs "rhs"
                OpName %f "f"
-       %void = OpTypeVoid
-          %1 = OpTypeFunction %void
        %uint = OpTypeInt 32 0
      %v3uint = OpTypeVector %uint 3
+          %1 = OpTypeFunction %v3uint %v3uint %uint
+         %10 = OpConstantNull %v3uint
+       %bool = OpTypeBool
+     %v3bool = OpTypeVector %bool 3
      %uint_1 = OpConstant %uint 1
+         %15 = OpConstantComposite %v3uint %uint_1 %uint_1 %uint_1
+       %void = OpTypeVoid
+         %17 = OpTypeFunction %void
      %uint_2 = OpConstant %uint 2
      %uint_3 = OpConstant %uint 3
-         %10 = OpConstantComposite %v3uint %uint_1 %uint_2 %uint_3
-         %11 = OpConstantNull %uint
-%_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 %11 %11 %11
-         %12 = OpUMod %v3uint %10 %16
+         %23 = OpConstantComposite %v3uint %uint_1 %uint_2 %uint_3
+         %24 = OpConstantNull %uint
+   %tint_mod = OpFunction %v3uint None %1
+        %lhs = OpFunctionParameter %v3uint
+        %rhs = OpFunctionParameter %uint
+          %7 = OpLabel
+          %8 = OpCompositeConstruct %v3uint %rhs %rhs %rhs
+         %11 = OpIEqual %v3bool %8 %10
+          %9 = OpSelect %v3uint %11 %15 %8
+         %16 = OpUMod %v3uint %lhs %9
+               OpReturnValue %16
+               OpFunctionEnd
+          %f = OpFunction %void None %17
+         %20 = OpLabel
+         %25 = OpFunctionCall %v3uint %tint_mod %23 %24
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-vec3/i32.wgsl.expected.dxc.hlsl b/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-vec3/i32.wgsl.expected.dxc.hlsl
index ce3cfca..f561307 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-vec3/i32.wgsl.expected.dxc.hlsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-vec3/i32.wgsl.expected.dxc.hlsl
@@ -1,7 +1,11 @@
+int3 tint_mod(int3 lhs, int3 rhs) {
+  return (lhs % (((rhs == (0).xxx) | ((lhs == (-2147483648).xxx) & (rhs == (-1).xxx))) ? (1).xxx : rhs));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   const int3 a = int3(1, 2, 3);
   const int3 b = int3(0, 5, 0);
-  const int3 r = (a % (b == int3(0, 0, 0) ? int3(1, 1, 1) : b));
+  const int3 r = tint_mod(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-vec3/i32.wgsl.expected.fxc.hlsl b/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-vec3/i32.wgsl.expected.fxc.hlsl
index ce3cfca..f561307 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-vec3/i32.wgsl.expected.fxc.hlsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-vec3/i32.wgsl.expected.fxc.hlsl
@@ -1,7 +1,11 @@
+int3 tint_mod(int3 lhs, int3 rhs) {
+  return (lhs % (((rhs == (0).xxx) | ((lhs == (-2147483648).xxx) & (rhs == (-1).xxx))) ? (1).xxx : rhs));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   const int3 a = int3(1, 2, 3);
   const int3 b = int3(0, 5, 0);
-  const int3 r = (a % (b == int3(0, 0, 0) ? int3(1, 1, 1) : b));
+  const int3 r = tint_mod(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-vec3/i32.wgsl.expected.glsl b/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-vec3/i32.wgsl.expected.glsl
index 809b454..e1da394 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-vec3/i32.wgsl.expected.glsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-vec3/i32.wgsl.expected.glsl
@@ -1,9 +1,13 @@
 #version 310 es
 
+ivec3 tint_mod(ivec3 lhs, ivec3 rhs) {
+  return (lhs % mix(rhs, ivec3(1), bvec3(uvec3(equal(rhs, ivec3(0))) | uvec3(bvec3(uvec3(equal(lhs, ivec3(-2147483648))) & uvec3(equal(rhs, ivec3(-1))))))));
+}
+
 void f() {
   ivec3 a = ivec3(1, 2, 3);
   ivec3 b = ivec3(0, 5, 0);
-  ivec3 r = (a % b);
+  ivec3 r = tint_mod(a, b);
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-vec3/i32.wgsl.expected.msl b/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-vec3/i32.wgsl.expected.msl
index 7619c9c..cc6b827 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-vec3/i32.wgsl.expected.msl
+++ b/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-vec3/i32.wgsl.expected.msl
@@ -1,10 +1,14 @@
 #include <metal_stdlib>
 
 using namespace metal;
+int3 tint_mod(int3 lhs, int3 rhs) {
+  return (lhs % select(rhs, int3(1), ((rhs == int3(0)) | ((lhs == int3((-2147483647 - 1))) & (rhs == int3(-1))))));
+}
+
 kernel void f() {
   int3 const a = int3(1, 2, 3);
   int3 const b = int3(0, 5, 0);
-  int3 const r = (a % b);
+  int3 const r = tint_mod(a, b);
   return;
 }
 
diff --git a/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-vec3/i32.wgsl.expected.spvasm b/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-vec3/i32.wgsl.expected.spvasm
index 64e929a..d7f2971 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-vec3/i32.wgsl.expected.spvasm
+++ b/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-vec3/i32.wgsl.expected.spvasm
@@ -1,26 +1,51 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 15
+; Bound: 35
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %f "f"
                OpExecutionMode %f LocalSize 1 1 1
+               OpName %tint_mod "tint_mod"
+               OpName %lhs "lhs"
+               OpName %rhs "rhs"
                OpName %f "f"
-       %void = OpTypeVoid
-          %1 = OpTypeFunction %void
         %int = OpTypeInt 32 1
       %v3int = OpTypeVector %int 3
+          %1 = OpTypeFunction %v3int %v3int %v3int
+          %9 = OpConstantNull %v3int
+       %bool = OpTypeBool
+     %v3bool = OpTypeVector %bool 3
+%int_n2147483648 = OpConstant %int -2147483648
+         %14 = OpConstantComposite %v3int %int_n2147483648 %int_n2147483648 %int_n2147483648
+     %int_n1 = OpConstant %int -1
+         %17 = OpConstantComposite %v3int %int_n1 %int_n1 %int_n1
       %int_1 = OpConstant %int 1
+         %22 = OpConstantComposite %v3int %int_1 %int_1 %int_1
+       %void = OpTypeVoid
+         %24 = OpTypeFunction %void
       %int_2 = OpConstant %int 2
       %int_3 = OpConstant %int 3
-         %10 = OpConstantComposite %v3int %int_1 %int_2 %int_3
-         %11 = OpConstantNull %int
+         %30 = OpConstantComposite %v3int %int_1 %int_2 %int_3
+         %31 = OpConstantNull %int
       %int_5 = OpConstant %int 5
-         %13 = OpConstantComposite %v3int %11 %int_5 %11
-          %f = OpFunction %void None %1
-          %4 = OpLabel
-         %14 = OpSMod %v3int %10 %13
+         %33 = OpConstantComposite %v3int %31 %int_5 %31
+   %tint_mod = OpFunction %v3int None %1
+        %lhs = OpFunctionParameter %v3int
+        %rhs = OpFunctionParameter %v3int
+          %7 = OpLabel
+         %10 = OpIEqual %v3bool %rhs %9
+         %15 = OpIEqual %v3bool %lhs %14
+         %18 = OpIEqual %v3bool %rhs %17
+         %19 = OpLogicalAnd %v3bool %15 %18
+         %20 = OpLogicalOr %v3bool %10 %19
+          %8 = OpSelect %v3int %20 %22 %rhs
+         %23 = OpSMod %v3int %lhs %8
+               OpReturnValue %23
+               OpFunctionEnd
+          %f = OpFunction %void None %24
+         %27 = OpLabel
+         %34 = OpFunctionCall %v3int %tint_mod %30 %33
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-vec3/u32.wgsl.expected.dxc.hlsl b/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-vec3/u32.wgsl.expected.dxc.hlsl
index ef3ed45..31e3caa 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-vec3/u32.wgsl.expected.dxc.hlsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-vec3/u32.wgsl.expected.dxc.hlsl
@@ -1,7 +1,11 @@
+uint3 tint_mod(uint3 lhs, uint3 rhs) {
+  return (lhs % ((rhs == (0u).xxx) ? (1u).xxx : rhs));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   const uint3 a = uint3(1u, 2u, 3u);
   const uint3 b = uint3(0u, 5u, 0u);
-  const uint3 r = (a % (b == uint3(0u, 0u, 0u) ? uint3(1u, 1u, 1u) : b));
+  const uint3 r = tint_mod(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-vec3/u32.wgsl.expected.fxc.hlsl b/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-vec3/u32.wgsl.expected.fxc.hlsl
index ef3ed45..31e3caa 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-vec3/u32.wgsl.expected.fxc.hlsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-vec3/u32.wgsl.expected.fxc.hlsl
@@ -1,7 +1,11 @@
+uint3 tint_mod(uint3 lhs, uint3 rhs) {
+  return (lhs % ((rhs == (0u).xxx) ? (1u).xxx : rhs));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   const uint3 a = uint3(1u, 2u, 3u);
   const uint3 b = uint3(0u, 5u, 0u);
-  const uint3 r = (a % (b == uint3(0u, 0u, 0u) ? uint3(1u, 1u, 1u) : b));
+  const uint3 r = tint_mod(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-vec3/u32.wgsl.expected.glsl b/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-vec3/u32.wgsl.expected.glsl
index af4c44f..e6cd33b 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-vec3/u32.wgsl.expected.glsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-vec3/u32.wgsl.expected.glsl
@@ -1,9 +1,13 @@
 #version 310 es
 
+uvec3 tint_mod(uvec3 lhs, uvec3 rhs) {
+  return (lhs % mix(rhs, uvec3(1u), equal(rhs, uvec3(0u))));
+}
+
 void f() {
   uvec3 a = uvec3(1u, 2u, 3u);
   uvec3 b = uvec3(0u, 5u, 0u);
-  uvec3 r = (a % b);
+  uvec3 r = tint_mod(a, b);
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-vec3/u32.wgsl.expected.msl b/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-vec3/u32.wgsl.expected.msl
index 028424a..dc39ae4 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-vec3/u32.wgsl.expected.msl
+++ b/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-vec3/u32.wgsl.expected.msl
@@ -1,10 +1,14 @@
 #include <metal_stdlib>
 
 using namespace metal;
+uint3 tint_mod(uint3 lhs, uint3 rhs) {
+  return (lhs % select(rhs, uint3(1u), (rhs == uint3(0u))));
+}
+
 kernel void f() {
   uint3 const a = uint3(1u, 2u, 3u);
   uint3 const b = uint3(0u, 5u, 0u);
-  uint3 const r = (a % b);
+  uint3 const r = tint_mod(a, b);
   return;
 }
 
diff --git a/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-vec3/u32.wgsl.expected.spvasm b/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-vec3/u32.wgsl.expected.spvasm
index 1dd5605..8084654 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-vec3/u32.wgsl.expected.spvasm
+++ b/test/tint/expressions/binary/mod_by_zero/by_constant/vec3-vec3/u32.wgsl.expected.spvasm
@@ -1,26 +1,43 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 15
+; Bound: 27
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %f "f"
                OpExecutionMode %f LocalSize 1 1 1
+               OpName %tint_mod "tint_mod"
+               OpName %lhs "lhs"
+               OpName %rhs "rhs"
                OpName %f "f"
-       %void = OpTypeVoid
-          %1 = OpTypeFunction %void
        %uint = OpTypeInt 32 0
      %v3uint = OpTypeVector %uint 3
+          %1 = OpTypeFunction %v3uint %v3uint %v3uint
+          %9 = OpConstantNull %v3uint
+       %bool = OpTypeBool
+     %v3bool = OpTypeVector %bool 3
      %uint_1 = OpConstant %uint 1
+         %14 = OpConstantComposite %v3uint %uint_1 %uint_1 %uint_1
+       %void = OpTypeVoid
+         %16 = OpTypeFunction %void
      %uint_2 = OpConstant %uint 2
      %uint_3 = OpConstant %uint 3
-         %10 = OpConstantComposite %v3uint %uint_1 %uint_2 %uint_3
-         %11 = OpConstantNull %uint
+         %22 = OpConstantComposite %v3uint %uint_1 %uint_2 %uint_3
+         %23 = OpConstantNull %uint
      %uint_5 = OpConstant %uint 5
-         %13 = OpConstantComposite %v3uint %11 %uint_5 %11
-          %f = OpFunction %void None %1
-          %4 = OpLabel
-         %14 = OpUMod %v3uint %10 %13
+         %25 = OpConstantComposite %v3uint %23 %uint_5 %23
+   %tint_mod = OpFunction %v3uint None %1
+        %lhs = OpFunctionParameter %v3uint
+        %rhs = OpFunctionParameter %v3uint
+          %7 = OpLabel
+         %10 = OpIEqual %v3bool %rhs %9
+          %8 = OpSelect %v3uint %10 %14 %rhs
+         %15 = OpUMod %v3uint %lhs %8
+               OpReturnValue %15
+               OpFunctionEnd
+          %f = OpFunction %void None %16
+         %19 = OpLabel
+         %26 = OpFunctionCall %v3uint %tint_mod %22 %25
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-scalar/i32.wgsl.expected.dxc.hlsl b/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-scalar/i32.wgsl.expected.dxc.hlsl
index fd4f932..ee8f777 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-scalar/i32.wgsl.expected.dxc.hlsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-scalar/i32.wgsl.expected.dxc.hlsl
@@ -1,11 +1,11 @@
-int value_or_one_if_zero_int(int value) {
-  return value == 0 ? 1 : value;
+int tint_mod(int lhs, int rhs) {
+  return (lhs % (((rhs == 0) | ((lhs == -2147483648) & (rhs == -1))) ? 1 : rhs));
 }
 
 [numthreads(1, 1, 1)]
 void f() {
   int a = 1;
   int b = 0;
-  const int r = (a % value_or_one_if_zero_int((b + b)));
+  const int r = tint_mod(a, (b + b));
   return;
 }
diff --git a/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-scalar/i32.wgsl.expected.fxc.hlsl b/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-scalar/i32.wgsl.expected.fxc.hlsl
index fd4f932..ee8f777 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-scalar/i32.wgsl.expected.fxc.hlsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-scalar/i32.wgsl.expected.fxc.hlsl
@@ -1,11 +1,11 @@
-int value_or_one_if_zero_int(int value) {
-  return value == 0 ? 1 : value;
+int tint_mod(int lhs, int rhs) {
+  return (lhs % (((rhs == 0) | ((lhs == -2147483648) & (rhs == -1))) ? 1 : rhs));
 }
 
 [numthreads(1, 1, 1)]
 void f() {
   int a = 1;
   int b = 0;
-  const int r = (a % value_or_one_if_zero_int((b + b)));
+  const int r = tint_mod(a, (b + b));
   return;
 }
diff --git a/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-scalar/i32.wgsl.expected.glsl b/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-scalar/i32.wgsl.expected.glsl
index e5b1401..7edd167 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-scalar/i32.wgsl.expected.glsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-scalar/i32.wgsl.expected.glsl
@@ -1,9 +1,13 @@
 #version 310 es
 
+int tint_mod(int lhs, int rhs) {
+  return (lhs % (bool(uint((rhs == 0)) | uint(bool(uint((lhs == -2147483648)) & uint((rhs == -1))))) ? 1 : rhs));
+}
+
 void f() {
   int a = 1;
   int b = 0;
-  int r = (a % (b + b));
+  int r = tint_mod(a, (b + b));
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-scalar/i32.wgsl.expected.msl b/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-scalar/i32.wgsl.expected.msl
index ead2dce..8bd7973 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-scalar/i32.wgsl.expected.msl
+++ b/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-scalar/i32.wgsl.expected.msl
@@ -1,10 +1,14 @@
 #include <metal_stdlib>
 
 using namespace metal;
+int tint_mod(int lhs, int rhs) {
+  return (lhs % select(rhs, 1, bool((rhs == 0) | bool((lhs == (-2147483647 - 1)) & (rhs == -1)))));
+}
+
 kernel void f() {
   int a = 1;
   int b = 0;
-  int const r = (a % as_type<int>((as_type<uint>(b) + as_type<uint>(b))));
+  int const r = tint_mod(a, as_type<int>((as_type<uint>(b) + as_type<uint>(b))));
   return;
 }
 
diff --git a/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-scalar/i32.wgsl.expected.spvasm b/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-scalar/i32.wgsl.expected.spvasm
index fac854f..6fb330e 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-scalar/i32.wgsl.expected.spvasm
+++ b/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-scalar/i32.wgsl.expected.spvasm
@@ -1,31 +1,51 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 16
+; Bound: 31
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %f "f"
                OpExecutionMode %f LocalSize 1 1 1
+               OpName %tint_mod "tint_mod"
+               OpName %lhs "lhs"
+               OpName %rhs "rhs"
                OpName %f "f"
                OpName %a "a"
                OpName %b "b"
-       %void = OpTypeVoid
-          %1 = OpTypeFunction %void
         %int = OpTypeInt 32 1
+          %1 = OpTypeFunction %int %int %int
+          %8 = OpConstantNull %int
+       %bool = OpTypeBool
+%int_n2147483648 = OpConstant %int -2147483648
+     %int_n1 = OpConstant %int -1
       %int_1 = OpConstant %int 1
+       %void = OpTypeVoid
+         %19 = OpTypeFunction %void
 %_ptr_Function_int = OpTypePointer Function %int
-          %9 = OpConstantNull %int
-          %f = OpFunction %void None %1
-          %4 = OpLabel
-          %a = OpVariable %_ptr_Function_int Function %9
-          %b = OpVariable %_ptr_Function_int Function %9
+   %tint_mod = OpFunction %int None %1
+        %lhs = OpFunctionParameter %int
+        %rhs = OpFunctionParameter %int
+          %6 = OpLabel
+          %9 = OpIEqual %bool %rhs %8
+         %12 = OpIEqual %bool %lhs %int_n2147483648
+         %14 = OpIEqual %bool %rhs %int_n1
+         %15 = OpLogicalAnd %bool %12 %14
+         %16 = OpLogicalOr %bool %9 %15
+          %7 = OpSelect %int %16 %int_1 %rhs
+         %18 = OpSMod %int %lhs %7
+               OpReturnValue %18
+               OpFunctionEnd
+          %f = OpFunction %void None %19
+         %22 = OpLabel
+          %a = OpVariable %_ptr_Function_int Function %8
+          %b = OpVariable %_ptr_Function_int Function %8
                OpStore %a %int_1
-               OpStore %b %9
-         %11 = OpLoad %int %a
-         %12 = OpLoad %int %b
-         %13 = OpLoad %int %b
-         %14 = OpIAdd %int %12 %13
-         %15 = OpSMod %int %11 %14
+               OpStore %b %8
+         %27 = OpLoad %int %a
+         %28 = OpLoad %int %b
+         %29 = OpLoad %int %b
+         %30 = OpIAdd %int %28 %29
+         %26 = OpFunctionCall %int %tint_mod %27 %30
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-scalar/u32.wgsl.expected.dxc.hlsl b/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-scalar/u32.wgsl.expected.dxc.hlsl
index f8f7511..2373dcf9 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-scalar/u32.wgsl.expected.dxc.hlsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-scalar/u32.wgsl.expected.dxc.hlsl
@@ -1,11 +1,11 @@
-uint value_or_one_if_zero_uint(uint value) {
-  return value == 0u ? 1u : value;
+uint tint_mod(uint lhs, uint rhs) {
+  return (lhs % ((rhs == 0u) ? 1u : rhs));
 }
 
 [numthreads(1, 1, 1)]
 void f() {
   uint a = 1u;
   uint b = 0u;
-  const uint r = (a % value_or_one_if_zero_uint((b + b)));
+  const uint r = tint_mod(a, (b + b));
   return;
 }
diff --git a/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-scalar/u32.wgsl.expected.fxc.hlsl b/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-scalar/u32.wgsl.expected.fxc.hlsl
index f8f7511..2373dcf9 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-scalar/u32.wgsl.expected.fxc.hlsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-scalar/u32.wgsl.expected.fxc.hlsl
@@ -1,11 +1,11 @@
-uint value_or_one_if_zero_uint(uint value) {
-  return value == 0u ? 1u : value;
+uint tint_mod(uint lhs, uint rhs) {
+  return (lhs % ((rhs == 0u) ? 1u : rhs));
 }
 
 [numthreads(1, 1, 1)]
 void f() {
   uint a = 1u;
   uint b = 0u;
-  const uint r = (a % value_or_one_if_zero_uint((b + b)));
+  const uint r = tint_mod(a, (b + b));
   return;
 }
diff --git a/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-scalar/u32.wgsl.expected.glsl b/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-scalar/u32.wgsl.expected.glsl
index 7b7c6b3..23248d3 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-scalar/u32.wgsl.expected.glsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-scalar/u32.wgsl.expected.glsl
@@ -1,9 +1,13 @@
 #version 310 es
 
+uint tint_mod(uint lhs, uint rhs) {
+  return (lhs % ((rhs == 0u) ? 1u : rhs));
+}
+
 void f() {
   uint a = 1u;
   uint b = 0u;
-  uint r = (a % (b + b));
+  uint r = tint_mod(a, (b + b));
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-scalar/u32.wgsl.expected.msl b/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-scalar/u32.wgsl.expected.msl
index 33bf9ab..96b1555c 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-scalar/u32.wgsl.expected.msl
+++ b/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-scalar/u32.wgsl.expected.msl
@@ -1,10 +1,14 @@
 #include <metal_stdlib>
 
 using namespace metal;
+uint tint_mod(uint lhs, uint rhs) {
+  return (lhs % select(rhs, 1u, (rhs == 0u)));
+}
+
 kernel void f() {
   uint a = 1u;
   uint b = 0u;
-  uint const r = (a % (b + b));
+  uint const r = tint_mod(a, (b + b));
   return;
 }
 
diff --git a/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-scalar/u32.wgsl.expected.spvasm b/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-scalar/u32.wgsl.expected.spvasm
index ca8d7a5..db8c7df 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-scalar/u32.wgsl.expected.spvasm
+++ b/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-scalar/u32.wgsl.expected.spvasm
@@ -1,31 +1,45 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 16
+; Bound: 25
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %f "f"
                OpExecutionMode %f LocalSize 1 1 1
+               OpName %tint_mod "tint_mod"
+               OpName %lhs "lhs"
+               OpName %rhs "rhs"
                OpName %f "f"
                OpName %a "a"
                OpName %b "b"
-       %void = OpTypeVoid
-          %1 = OpTypeFunction %void
        %uint = OpTypeInt 32 0
+          %1 = OpTypeFunction %uint %uint %uint
+          %8 = OpConstantNull %uint
+       %bool = OpTypeBool
      %uint_1 = OpConstant %uint 1
+       %void = OpTypeVoid
+         %13 = OpTypeFunction %void
 %_ptr_Function_uint = OpTypePointer Function %uint
-          %9 = OpConstantNull %uint
-          %f = OpFunction %void None %1
-          %4 = OpLabel
-          %a = OpVariable %_ptr_Function_uint Function %9
-          %b = OpVariable %_ptr_Function_uint Function %9
+   %tint_mod = OpFunction %uint None %1
+        %lhs = OpFunctionParameter %uint
+        %rhs = OpFunctionParameter %uint
+          %6 = OpLabel
+          %9 = OpIEqual %bool %rhs %8
+          %7 = OpSelect %uint %9 %uint_1 %rhs
+         %12 = OpUMod %uint %lhs %7
+               OpReturnValue %12
+               OpFunctionEnd
+          %f = OpFunction %void None %13
+         %16 = OpLabel
+          %a = OpVariable %_ptr_Function_uint Function %8
+          %b = OpVariable %_ptr_Function_uint Function %8
                OpStore %a %uint_1
-               OpStore %b %9
-         %11 = OpLoad %uint %a
-         %12 = OpLoad %uint %b
-         %13 = OpLoad %uint %b
-         %14 = OpIAdd %uint %12 %13
-         %15 = OpUMod %uint %11 %14
+               OpStore %b %8
+         %21 = OpLoad %uint %a
+         %22 = OpLoad %uint %b
+         %23 = OpLoad %uint %b
+         %24 = OpIAdd %uint %22 %23
+         %20 = OpFunctionCall %uint %tint_mod %21 %24
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-vec3/i32.wgsl.expected.dxc.hlsl b/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-vec3/i32.wgsl.expected.dxc.hlsl
index 8e8a7d0..7186ef9a 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-vec3/i32.wgsl.expected.dxc.hlsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-vec3/i32.wgsl.expected.dxc.hlsl
@@ -1,11 +1,12 @@
-int3 value_or_one_if_zero_int3(int3 value) {
-  return value == int3(0, 0, 0) ? int3(1, 1, 1) : value;
+int3 tint_mod(int lhs, int3 rhs) {
+  const int3 l = int3((lhs).xxx);
+  return (l % (((rhs == (0).xxx) | ((l == (-2147483648).xxx) & (rhs == (-1).xxx))) ? (1).xxx : rhs));
 }
 
 [numthreads(1, 1, 1)]
 void f() {
   int a = 4;
   int3 b = int3(0, 2, 0);
-  const int3 r = (a % value_or_one_if_zero_int3((b + b)));
+  const int3 r = tint_mod(a, (b + b));
   return;
 }
diff --git a/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-vec3/i32.wgsl.expected.fxc.hlsl b/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-vec3/i32.wgsl.expected.fxc.hlsl
index 8e8a7d0..7186ef9a 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-vec3/i32.wgsl.expected.fxc.hlsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-vec3/i32.wgsl.expected.fxc.hlsl
@@ -1,11 +1,12 @@
-int3 value_or_one_if_zero_int3(int3 value) {
-  return value == int3(0, 0, 0) ? int3(1, 1, 1) : value;
+int3 tint_mod(int lhs, int3 rhs) {
+  const int3 l = int3((lhs).xxx);
+  return (l % (((rhs == (0).xxx) | ((l == (-2147483648).xxx) & (rhs == (-1).xxx))) ? (1).xxx : rhs));
 }
 
 [numthreads(1, 1, 1)]
 void f() {
   int a = 4;
   int3 b = int3(0, 2, 0);
-  const int3 r = (a % value_or_one_if_zero_int3((b + b)));
+  const int3 r = tint_mod(a, (b + b));
   return;
 }
diff --git a/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-vec3/i32.wgsl.expected.glsl b/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-vec3/i32.wgsl.expected.glsl
index d633601..e2aa4af 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-vec3/i32.wgsl.expected.glsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-vec3/i32.wgsl.expected.glsl
@@ -1,9 +1,14 @@
 #version 310 es
 
+ivec3 tint_mod(int lhs, ivec3 rhs) {
+  ivec3 l = ivec3(lhs);
+  return (l % mix(rhs, ivec3(1), bvec3(uvec3(equal(rhs, ivec3(0))) | uvec3(bvec3(uvec3(equal(l, ivec3(-2147483648))) & uvec3(equal(rhs, ivec3(-1))))))));
+}
+
 void f() {
   int a = 4;
   ivec3 b = ivec3(0, 2, 0);
-  ivec3 r = (a % (b + b));
+  ivec3 r = tint_mod(a, (b + b));
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-vec3/i32.wgsl.expected.msl b/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-vec3/i32.wgsl.expected.msl
index 12f1a72..2a01a50 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-vec3/i32.wgsl.expected.msl
+++ b/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-vec3/i32.wgsl.expected.msl
@@ -1,10 +1,15 @@
 #include <metal_stdlib>
 
 using namespace metal;
+int3 tint_mod(int lhs, int3 rhs) {
+  int3 const l = int3(lhs);
+  return (l % select(rhs, int3(1), ((rhs == int3(0)) | ((l == int3((-2147483647 - 1))) & (rhs == int3(-1))))));
+}
+
 kernel void f() {
   int a = 4;
   int3 b = int3(0, 2, 0);
-  int3 const r = (a % as_type<int3>((as_type<uint3>(b) + as_type<uint3>(b))));
+  int3 const r = tint_mod(a, as_type<int3>((as_type<uint3>(b) + as_type<uint3>(b))));
   return;
 }
 
diff --git a/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-vec3/i32.wgsl.expected.spvasm b/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-vec3/i32.wgsl.expected.spvasm
index a4acd72..07eb4e7 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-vec3/i32.wgsl.expected.spvasm
+++ b/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-vec3/i32.wgsl.expected.spvasm
@@ -1,38 +1,62 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 23
+; Bound: 42
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %f "f"
                OpExecutionMode %f LocalSize 1 1 1
+               OpName %tint_mod "tint_mod"
+               OpName %lhs "lhs"
+               OpName %rhs "rhs"
                OpName %f "f"
                OpName %a "a"
                OpName %b "b"
-       %void = OpTypeVoid
-          %1 = OpTypeFunction %void
         %int = OpTypeInt 32 1
+      %v3int = OpTypeVector %int 3
+          %1 = OpTypeFunction %v3int %int %v3int
+         %10 = OpConstantNull %v3int
+       %bool = OpTypeBool
+     %v3bool = OpTypeVector %bool 3
+%int_n2147483648 = OpConstant %int -2147483648
+         %15 = OpConstantComposite %v3int %int_n2147483648 %int_n2147483648 %int_n2147483648
+     %int_n1 = OpConstant %int -1
+         %18 = OpConstantComposite %v3int %int_n1 %int_n1 %int_n1
+      %int_1 = OpConstant %int 1
+         %23 = OpConstantComposite %v3int %int_1 %int_1 %int_1
+       %void = OpTypeVoid
+         %25 = OpTypeFunction %void
       %int_4 = OpConstant %int 4
 %_ptr_Function_int = OpTypePointer Function %int
-          %9 = OpConstantNull %int
-      %v3int = OpTypeVector %int 3
+         %32 = OpConstantNull %int
       %int_2 = OpConstant %int 2
-         %12 = OpConstantComposite %v3int %9 %int_2 %9
+         %34 = OpConstantComposite %v3int %32 %int_2 %32
 %_ptr_Function_v3int = OpTypePointer Function %v3int
-         %15 = OpConstantNull %v3int
-          %f = OpFunction %void None %1
-          %4 = OpLabel
-          %a = OpVariable %_ptr_Function_int Function %9
-          %b = OpVariable %_ptr_Function_v3int Function %15
-         %21 = OpVariable %_ptr_Function_v3int Function %15
+   %tint_mod = OpFunction %v3int None %1
+        %lhs = OpFunctionParameter %int
+        %rhs = OpFunctionParameter %v3int
+          %7 = OpLabel
+          %8 = OpCompositeConstruct %v3int %lhs %lhs %lhs
+         %11 = OpIEqual %v3bool %rhs %10
+         %16 = OpIEqual %v3bool %8 %15
+         %19 = OpIEqual %v3bool %rhs %18
+         %20 = OpLogicalAnd %v3bool %16 %19
+         %21 = OpLogicalOr %v3bool %11 %20
+          %9 = OpSelect %v3int %21 %23 %rhs
+         %24 = OpSMod %v3int %8 %9
+               OpReturnValue %24
+               OpFunctionEnd
+          %f = OpFunction %void None %25
+         %28 = OpLabel
+          %a = OpVariable %_ptr_Function_int Function %32
+          %b = OpVariable %_ptr_Function_v3int Function %10
                OpStore %a %int_4
-               OpStore %b %12
-         %16 = OpLoad %int %a
-         %17 = OpLoad %v3int %b
-         %18 = OpLoad %v3int %b
-         %19 = OpIAdd %v3int %17 %18
-         %22 = OpCompositeConstruct %v3int %16 %16 %16
-         %20 = OpSMod %v3int %22 %19
+               OpStore %b %34
+         %38 = OpLoad %int %a
+         %39 = OpLoad %v3int %b
+         %40 = OpLoad %v3int %b
+         %41 = OpIAdd %v3int %39 %40
+         %37 = OpFunctionCall %v3int %tint_mod %38 %41
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-vec3/u32.wgsl.expected.dxc.hlsl b/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-vec3/u32.wgsl.expected.dxc.hlsl
index 2330363..046ce3a 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-vec3/u32.wgsl.expected.dxc.hlsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-vec3/u32.wgsl.expected.dxc.hlsl
@@ -1,11 +1,12 @@
-uint3 value_or_one_if_zero_uint3(uint3 value) {
-  return value == uint3(0u, 0u, 0u) ? uint3(1u, 1u, 1u) : value;
+uint3 tint_mod(uint lhs, uint3 rhs) {
+  const uint3 l = uint3((lhs).xxx);
+  return (l % ((rhs == (0u).xxx) ? (1u).xxx : rhs));
 }
 
 [numthreads(1, 1, 1)]
 void f() {
   uint a = 4u;
   uint3 b = uint3(0u, 2u, 0u);
-  const uint3 r = (a % value_or_one_if_zero_uint3((b + b)));
+  const uint3 r = tint_mod(a, (b + b));
   return;
 }
diff --git a/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-vec3/u32.wgsl.expected.fxc.hlsl b/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-vec3/u32.wgsl.expected.fxc.hlsl
index 2330363..046ce3a 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-vec3/u32.wgsl.expected.fxc.hlsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-vec3/u32.wgsl.expected.fxc.hlsl
@@ -1,11 +1,12 @@
-uint3 value_or_one_if_zero_uint3(uint3 value) {
-  return value == uint3(0u, 0u, 0u) ? uint3(1u, 1u, 1u) : value;
+uint3 tint_mod(uint lhs, uint3 rhs) {
+  const uint3 l = uint3((lhs).xxx);
+  return (l % ((rhs == (0u).xxx) ? (1u).xxx : rhs));
 }
 
 [numthreads(1, 1, 1)]
 void f() {
   uint a = 4u;
   uint3 b = uint3(0u, 2u, 0u);
-  const uint3 r = (a % value_or_one_if_zero_uint3((b + b)));
+  const uint3 r = tint_mod(a, (b + b));
   return;
 }
diff --git a/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-vec3/u32.wgsl.expected.glsl b/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-vec3/u32.wgsl.expected.glsl
index aa981b7..47e9d7e 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-vec3/u32.wgsl.expected.glsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-vec3/u32.wgsl.expected.glsl
@@ -1,9 +1,14 @@
 #version 310 es
 
+uvec3 tint_mod(uint lhs, uvec3 rhs) {
+  uvec3 l = uvec3(lhs);
+  return (l % mix(rhs, uvec3(1u), equal(rhs, uvec3(0u))));
+}
+
 void f() {
   uint a = 4u;
   uvec3 b = uvec3(0u, 2u, 0u);
-  uvec3 r = (a % (b + b));
+  uvec3 r = tint_mod(a, (b + b));
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-vec3/u32.wgsl.expected.msl b/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-vec3/u32.wgsl.expected.msl
index a7511f2..6b16b4a 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-vec3/u32.wgsl.expected.msl
+++ b/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-vec3/u32.wgsl.expected.msl
@@ -1,10 +1,15 @@
 #include <metal_stdlib>
 
 using namespace metal;
+uint3 tint_mod(uint lhs, uint3 rhs) {
+  uint3 const l = uint3(lhs);
+  return (l % select(rhs, uint3(1u), (rhs == uint3(0u))));
+}
+
 kernel void f() {
   uint a = 4u;
   uint3 b = uint3(0u, 2u, 0u);
-  uint3 const r = (a % (b + b));
+  uint3 const r = tint_mod(a, (b + b));
   return;
 }
 
diff --git a/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-vec3/u32.wgsl.expected.spvasm b/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-vec3/u32.wgsl.expected.spvasm
index 296cc5c..23a8288 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-vec3/u32.wgsl.expected.spvasm
+++ b/test/tint/expressions/binary/mod_by_zero/by_expression/scalar-vec3/u32.wgsl.expected.spvasm
@@ -1,38 +1,54 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 23
+; Bound: 34
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %f "f"
                OpExecutionMode %f LocalSize 1 1 1
+               OpName %tint_mod "tint_mod"
+               OpName %lhs "lhs"
+               OpName %rhs "rhs"
                OpName %f "f"
                OpName %a "a"
                OpName %b "b"
-       %void = OpTypeVoid
-          %1 = OpTypeFunction %void
        %uint = OpTypeInt 32 0
+     %v3uint = OpTypeVector %uint 3
+          %1 = OpTypeFunction %v3uint %uint %v3uint
+         %10 = OpConstantNull %v3uint
+       %bool = OpTypeBool
+     %v3bool = OpTypeVector %bool 3
+     %uint_1 = OpConstant %uint 1
+         %15 = OpConstantComposite %v3uint %uint_1 %uint_1 %uint_1
+       %void = OpTypeVoid
+         %17 = OpTypeFunction %void
      %uint_4 = OpConstant %uint 4
 %_ptr_Function_uint = OpTypePointer Function %uint
-          %9 = OpConstantNull %uint
-     %v3uint = OpTypeVector %uint 3
+         %24 = OpConstantNull %uint
      %uint_2 = OpConstant %uint 2
-         %12 = OpConstantComposite %v3uint %9 %uint_2 %9
+         %26 = OpConstantComposite %v3uint %24 %uint_2 %24
 %_ptr_Function_v3uint = OpTypePointer Function %v3uint
-         %15 = OpConstantNull %v3uint
-          %f = OpFunction %void None %1
-          %4 = OpLabel
-          %a = OpVariable %_ptr_Function_uint Function %9
-          %b = OpVariable %_ptr_Function_v3uint Function %15
-         %21 = OpVariable %_ptr_Function_v3uint Function %15
+   %tint_mod = OpFunction %v3uint None %1
+        %lhs = OpFunctionParameter %uint
+        %rhs = OpFunctionParameter %v3uint
+          %7 = OpLabel
+          %8 = OpCompositeConstruct %v3uint %lhs %lhs %lhs
+         %11 = OpIEqual %v3bool %rhs %10
+          %9 = OpSelect %v3uint %11 %15 %rhs
+         %16 = OpUMod %v3uint %8 %9
+               OpReturnValue %16
+               OpFunctionEnd
+          %f = OpFunction %void None %17
+         %20 = OpLabel
+          %a = OpVariable %_ptr_Function_uint Function %24
+          %b = OpVariable %_ptr_Function_v3uint Function %10
                OpStore %a %uint_4
-               OpStore %b %12
-         %16 = OpLoad %uint %a
-         %17 = OpLoad %v3uint %b
-         %18 = OpLoad %v3uint %b
-         %19 = OpIAdd %v3uint %17 %18
-         %22 = OpCompositeConstruct %v3uint %16 %16 %16
-         %20 = OpUMod %v3uint %22 %19
+               OpStore %b %26
+         %30 = OpLoad %uint %a
+         %31 = OpLoad %v3uint %b
+         %32 = OpLoad %v3uint %b
+         %33 = OpIAdd %v3uint %31 %32
+         %29 = OpFunctionCall %v3uint %tint_mod %30 %33
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-scalar/i32.wgsl.expected.dxc.hlsl b/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-scalar/i32.wgsl.expected.dxc.hlsl
index ea6b4cb..8eebf87 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-scalar/i32.wgsl.expected.dxc.hlsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-scalar/i32.wgsl.expected.dxc.hlsl
@@ -1,11 +1,12 @@
-int value_or_one_if_zero_int(int value) {
-  return value == 0 ? 1 : value;
+int3 tint_mod(int3 lhs, int rhs) {
+  const int3 r = int3((rhs).xxx);
+  return (lhs % (((r == (0).xxx) | ((lhs == (-2147483648).xxx) & (r == (-1).xxx))) ? (1).xxx : r));
 }
 
 [numthreads(1, 1, 1)]
 void f() {
   int3 a = int3(1, 2, 3);
   int b = 0;
-  const int3 r = (a % value_or_one_if_zero_int((b + b)));
+  const int3 r = tint_mod(a, (b + b));
   return;
 }
diff --git a/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-scalar/i32.wgsl.expected.fxc.hlsl b/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-scalar/i32.wgsl.expected.fxc.hlsl
index ea6b4cb..8eebf87 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-scalar/i32.wgsl.expected.fxc.hlsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-scalar/i32.wgsl.expected.fxc.hlsl
@@ -1,11 +1,12 @@
-int value_or_one_if_zero_int(int value) {
-  return value == 0 ? 1 : value;
+int3 tint_mod(int3 lhs, int rhs) {
+  const int3 r = int3((rhs).xxx);
+  return (lhs % (((r == (0).xxx) | ((lhs == (-2147483648).xxx) & (r == (-1).xxx))) ? (1).xxx : r));
 }
 
 [numthreads(1, 1, 1)]
 void f() {
   int3 a = int3(1, 2, 3);
   int b = 0;
-  const int3 r = (a % value_or_one_if_zero_int((b + b)));
+  const int3 r = tint_mod(a, (b + b));
   return;
 }
diff --git a/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-scalar/i32.wgsl.expected.glsl b/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-scalar/i32.wgsl.expected.glsl
index 5b6590c..8d0fbcc 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-scalar/i32.wgsl.expected.glsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-scalar/i32.wgsl.expected.glsl
@@ -1,9 +1,14 @@
 #version 310 es
 
+ivec3 tint_mod(ivec3 lhs, int rhs) {
+  ivec3 r = ivec3(rhs);
+  return (lhs % mix(r, ivec3(1), bvec3(uvec3(equal(r, ivec3(0))) | uvec3(bvec3(uvec3(equal(lhs, ivec3(-2147483648))) & uvec3(equal(r, ivec3(-1))))))));
+}
+
 void f() {
   ivec3 a = ivec3(1, 2, 3);
   int b = 0;
-  ivec3 r = (a % (b + b));
+  ivec3 r = tint_mod(a, (b + b));
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-scalar/i32.wgsl.expected.msl b/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-scalar/i32.wgsl.expected.msl
index ba6626b..ccd2c1e 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-scalar/i32.wgsl.expected.msl
+++ b/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-scalar/i32.wgsl.expected.msl
@@ -1,10 +1,15 @@
 #include <metal_stdlib>
 
 using namespace metal;
+int3 tint_mod(int3 lhs, int rhs) {
+  int3 const r = int3(rhs);
+  return (lhs % select(r, int3(1), ((r == int3(0)) | ((lhs == int3((-2147483647 - 1))) & (r == int3(-1))))));
+}
+
 kernel void f() {
   int3 a = int3(1, 2, 3);
   int b = 0;
-  int3 const r = (a % as_type<int>((as_type<uint>(b) + as_type<uint>(b))));
+  int3 const r = tint_mod(a, as_type<int>((as_type<uint>(b) + as_type<uint>(b))));
   return;
 }
 
diff --git a/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-scalar/i32.wgsl.expected.spvasm b/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-scalar/i32.wgsl.expected.spvasm
index 1b579c4..6fc00bd 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-scalar/i32.wgsl.expected.spvasm
+++ b/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-scalar/i32.wgsl.expected.spvasm
@@ -1,39 +1,62 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 24
+; Bound: 42
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %f "f"
                OpExecutionMode %f LocalSize 1 1 1
+               OpName %tint_mod "tint_mod"
+               OpName %lhs "lhs"
+               OpName %rhs "rhs"
                OpName %f "f"
                OpName %a "a"
                OpName %b "b"
-       %void = OpTypeVoid
-          %1 = OpTypeFunction %void
         %int = OpTypeInt 32 1
       %v3int = OpTypeVector %int 3
+          %1 = OpTypeFunction %v3int %v3int %int
+         %10 = OpConstantNull %v3int
+       %bool = OpTypeBool
+     %v3bool = OpTypeVector %bool 3
+%int_n2147483648 = OpConstant %int -2147483648
+         %15 = OpConstantComposite %v3int %int_n2147483648 %int_n2147483648 %int_n2147483648
+     %int_n1 = OpConstant %int -1
+         %18 = OpConstantComposite %v3int %int_n1 %int_n1 %int_n1
       %int_1 = OpConstant %int 1
+         %23 = OpConstantComposite %v3int %int_1 %int_1 %int_1
+       %void = OpTypeVoid
+         %25 = OpTypeFunction %void
       %int_2 = OpConstant %int 2
       %int_3 = OpConstant %int 3
-         %10 = OpConstantComposite %v3int %int_1 %int_2 %int_3
+         %31 = OpConstantComposite %v3int %int_1 %int_2 %int_3
 %_ptr_Function_v3int = OpTypePointer Function %v3int
-         %13 = OpConstantNull %v3int
-         %14 = OpConstantNull %int
+         %34 = OpConstantNull %int
 %_ptr_Function_int = OpTypePointer Function %int
-          %f = OpFunction %void None %1
-          %4 = OpLabel
-          %a = OpVariable %_ptr_Function_v3int Function %13
-          %b = OpVariable %_ptr_Function_int Function %14
-         %22 = OpVariable %_ptr_Function_v3int Function %13
-               OpStore %a %10
-               OpStore %b %14
-         %17 = OpLoad %v3int %a
-         %18 = OpLoad %int %b
-         %19 = OpLoad %int %b
-         %20 = OpIAdd %int %18 %19
-         %23 = OpCompositeConstruct %v3int %20 %20 %20
-         %21 = OpSMod %v3int %17 %23
+   %tint_mod = OpFunction %v3int None %1
+        %lhs = OpFunctionParameter %v3int
+        %rhs = OpFunctionParameter %int
+          %7 = OpLabel
+          %8 = OpCompositeConstruct %v3int %rhs %rhs %rhs
+         %11 = OpIEqual %v3bool %8 %10
+         %16 = OpIEqual %v3bool %lhs %15
+         %19 = OpIEqual %v3bool %8 %18
+         %20 = OpLogicalAnd %v3bool %16 %19
+         %21 = OpLogicalOr %v3bool %11 %20
+          %9 = OpSelect %v3int %21 %23 %8
+         %24 = OpSMod %v3int %lhs %9
+               OpReturnValue %24
+               OpFunctionEnd
+          %f = OpFunction %void None %25
+         %28 = OpLabel
+          %a = OpVariable %_ptr_Function_v3int Function %10
+          %b = OpVariable %_ptr_Function_int Function %34
+               OpStore %a %31
+               OpStore %b %34
+         %38 = OpLoad %v3int %a
+         %39 = OpLoad %int %b
+         %40 = OpLoad %int %b
+         %41 = OpIAdd %int %39 %40
+         %37 = OpFunctionCall %v3int %tint_mod %38 %41
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-scalar/u32.wgsl.expected.dxc.hlsl b/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-scalar/u32.wgsl.expected.dxc.hlsl
index dca1662..b3a498d 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-scalar/u32.wgsl.expected.dxc.hlsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-scalar/u32.wgsl.expected.dxc.hlsl
@@ -1,11 +1,12 @@
-uint value_or_one_if_zero_uint(uint value) {
-  return value == 0u ? 1u : value;
+uint3 tint_mod(uint3 lhs, uint rhs) {
+  const uint3 r = uint3((rhs).xxx);
+  return (lhs % ((r == (0u).xxx) ? (1u).xxx : r));
 }
 
 [numthreads(1, 1, 1)]
 void f() {
   uint3 a = uint3(1u, 2u, 3u);
   uint b = 0u;
-  const uint3 r = (a % value_or_one_if_zero_uint((b + b)));
+  const uint3 r = tint_mod(a, (b + b));
   return;
 }
diff --git a/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-scalar/u32.wgsl.expected.fxc.hlsl b/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-scalar/u32.wgsl.expected.fxc.hlsl
index dca1662..b3a498d 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-scalar/u32.wgsl.expected.fxc.hlsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-scalar/u32.wgsl.expected.fxc.hlsl
@@ -1,11 +1,12 @@
-uint value_or_one_if_zero_uint(uint value) {
-  return value == 0u ? 1u : value;
+uint3 tint_mod(uint3 lhs, uint rhs) {
+  const uint3 r = uint3((rhs).xxx);
+  return (lhs % ((r == (0u).xxx) ? (1u).xxx : r));
 }
 
 [numthreads(1, 1, 1)]
 void f() {
   uint3 a = uint3(1u, 2u, 3u);
   uint b = 0u;
-  const uint3 r = (a % value_or_one_if_zero_uint((b + b)));
+  const uint3 r = tint_mod(a, (b + b));
   return;
 }
diff --git a/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-scalar/u32.wgsl.expected.glsl b/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-scalar/u32.wgsl.expected.glsl
index f388f00..82a5991 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-scalar/u32.wgsl.expected.glsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-scalar/u32.wgsl.expected.glsl
@@ -1,9 +1,14 @@
 #version 310 es
 
+uvec3 tint_mod(uvec3 lhs, uint rhs) {
+  uvec3 r = uvec3(rhs);
+  return (lhs % mix(r, uvec3(1u), equal(r, uvec3(0u))));
+}
+
 void f() {
   uvec3 a = uvec3(1u, 2u, 3u);
   uint b = 0u;
-  uvec3 r = (a % (b + b));
+  uvec3 r = tint_mod(a, (b + b));
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-scalar/u32.wgsl.expected.msl b/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-scalar/u32.wgsl.expected.msl
index 96dba81..95cf580 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-scalar/u32.wgsl.expected.msl
+++ b/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-scalar/u32.wgsl.expected.msl
@@ -1,10 +1,15 @@
 #include <metal_stdlib>
 
 using namespace metal;
+uint3 tint_mod(uint3 lhs, uint rhs) {
+  uint3 const r = uint3(rhs);
+  return (lhs % select(r, uint3(1u), (r == uint3(0u))));
+}
+
 kernel void f() {
   uint3 a = uint3(1u, 2u, 3u);
   uint b = 0u;
-  uint3 const r = (a % (b + b));
+  uint3 const r = tint_mod(a, (b + b));
   return;
 }
 
diff --git a/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-scalar/u32.wgsl.expected.spvasm b/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-scalar/u32.wgsl.expected.spvasm
index 4676fea..20a784d 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-scalar/u32.wgsl.expected.spvasm
+++ b/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-scalar/u32.wgsl.expected.spvasm
@@ -1,39 +1,54 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 24
+; Bound: 34
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %f "f"
                OpExecutionMode %f LocalSize 1 1 1
+               OpName %tint_mod "tint_mod"
+               OpName %lhs "lhs"
+               OpName %rhs "rhs"
                OpName %f "f"
                OpName %a "a"
                OpName %b "b"
-       %void = OpTypeVoid
-          %1 = OpTypeFunction %void
        %uint = OpTypeInt 32 0
      %v3uint = OpTypeVector %uint 3
+          %1 = OpTypeFunction %v3uint %v3uint %uint
+         %10 = OpConstantNull %v3uint
+       %bool = OpTypeBool
+     %v3bool = OpTypeVector %bool 3
      %uint_1 = OpConstant %uint 1
+         %15 = OpConstantComposite %v3uint %uint_1 %uint_1 %uint_1
+       %void = OpTypeVoid
+         %17 = OpTypeFunction %void
      %uint_2 = OpConstant %uint 2
      %uint_3 = OpConstant %uint 3
-         %10 = OpConstantComposite %v3uint %uint_1 %uint_2 %uint_3
+         %23 = OpConstantComposite %v3uint %uint_1 %uint_2 %uint_3
 %_ptr_Function_v3uint = OpTypePointer Function %v3uint
-         %13 = OpConstantNull %v3uint
-         %14 = OpConstantNull %uint
+         %26 = OpConstantNull %uint
 %_ptr_Function_uint = OpTypePointer Function %uint
-          %f = OpFunction %void None %1
-          %4 = OpLabel
-          %a = OpVariable %_ptr_Function_v3uint Function %13
-          %b = OpVariable %_ptr_Function_uint Function %14
-         %22 = OpVariable %_ptr_Function_v3uint Function %13
-               OpStore %a %10
-               OpStore %b %14
-         %17 = OpLoad %v3uint %a
-         %18 = OpLoad %uint %b
-         %19 = OpLoad %uint %b
-         %20 = OpIAdd %uint %18 %19
-         %23 = OpCompositeConstruct %v3uint %20 %20 %20
-         %21 = OpUMod %v3uint %17 %23
+   %tint_mod = OpFunction %v3uint None %1
+        %lhs = OpFunctionParameter %v3uint
+        %rhs = OpFunctionParameter %uint
+          %7 = OpLabel
+          %8 = OpCompositeConstruct %v3uint %rhs %rhs %rhs
+         %11 = OpIEqual %v3bool %8 %10
+          %9 = OpSelect %v3uint %11 %15 %8
+         %16 = OpUMod %v3uint %lhs %9
+               OpReturnValue %16
+               OpFunctionEnd
+          %f = OpFunction %void None %17
+         %20 = OpLabel
+          %a = OpVariable %_ptr_Function_v3uint Function %10
+          %b = OpVariable %_ptr_Function_uint Function %26
+               OpStore %a %23
+               OpStore %b %26
+         %30 = OpLoad %v3uint %a
+         %31 = OpLoad %uint %b
+         %32 = OpLoad %uint %b
+         %33 = OpIAdd %uint %31 %32
+         %29 = OpFunctionCall %v3uint %tint_mod %30 %33
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-vec3/i32.wgsl.expected.dxc.hlsl b/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-vec3/i32.wgsl.expected.dxc.hlsl
index f33a43d..6b63195 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-vec3/i32.wgsl.expected.dxc.hlsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-vec3/i32.wgsl.expected.dxc.hlsl
@@ -1,11 +1,11 @@
-int3 value_or_one_if_zero_int3(int3 value) {
-  return value == int3(0, 0, 0) ? int3(1, 1, 1) : value;
+int3 tint_mod(int3 lhs, int3 rhs) {
+  return (lhs % (((rhs == (0).xxx) | ((lhs == (-2147483648).xxx) & (rhs == (-1).xxx))) ? (1).xxx : rhs));
 }
 
 [numthreads(1, 1, 1)]
 void f() {
   int3 a = int3(1, 2, 3);
   int3 b = int3(0, 5, 0);
-  const int3 r = (a % value_or_one_if_zero_int3((b + b)));
+  const int3 r = tint_mod(a, (b + b));
   return;
 }
diff --git a/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-vec3/i32.wgsl.expected.fxc.hlsl b/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-vec3/i32.wgsl.expected.fxc.hlsl
index f33a43d..6b63195 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-vec3/i32.wgsl.expected.fxc.hlsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-vec3/i32.wgsl.expected.fxc.hlsl
@@ -1,11 +1,11 @@
-int3 value_or_one_if_zero_int3(int3 value) {
-  return value == int3(0, 0, 0) ? int3(1, 1, 1) : value;
+int3 tint_mod(int3 lhs, int3 rhs) {
+  return (lhs % (((rhs == (0).xxx) | ((lhs == (-2147483648).xxx) & (rhs == (-1).xxx))) ? (1).xxx : rhs));
 }
 
 [numthreads(1, 1, 1)]
 void f() {
   int3 a = int3(1, 2, 3);
   int3 b = int3(0, 5, 0);
-  const int3 r = (a % value_or_one_if_zero_int3((b + b)));
+  const int3 r = tint_mod(a, (b + b));
   return;
 }
diff --git a/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-vec3/i32.wgsl.expected.glsl b/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-vec3/i32.wgsl.expected.glsl
index f97a7fa..fab3241 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-vec3/i32.wgsl.expected.glsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-vec3/i32.wgsl.expected.glsl
@@ -1,9 +1,13 @@
 #version 310 es
 
+ivec3 tint_mod(ivec3 lhs, ivec3 rhs) {
+  return (lhs % mix(rhs, ivec3(1), bvec3(uvec3(equal(rhs, ivec3(0))) | uvec3(bvec3(uvec3(equal(lhs, ivec3(-2147483648))) & uvec3(equal(rhs, ivec3(-1))))))));
+}
+
 void f() {
   ivec3 a = ivec3(1, 2, 3);
   ivec3 b = ivec3(0, 5, 0);
-  ivec3 r = (a % (b + b));
+  ivec3 r = tint_mod(a, (b + b));
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-vec3/i32.wgsl.expected.msl b/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-vec3/i32.wgsl.expected.msl
index 61356dc..4686268 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-vec3/i32.wgsl.expected.msl
+++ b/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-vec3/i32.wgsl.expected.msl
@@ -1,10 +1,14 @@
 #include <metal_stdlib>
 
 using namespace metal;
+int3 tint_mod(int3 lhs, int3 rhs) {
+  return (lhs % select(rhs, int3(1), ((rhs == int3(0)) | ((lhs == int3((-2147483647 - 1))) & (rhs == int3(-1))))));
+}
+
 kernel void f() {
   int3 a = int3(1, 2, 3);
   int3 b = int3(0, 5, 0);
-  int3 const r = (a % as_type<int3>((as_type<uint3>(b) + as_type<uint3>(b))));
+  int3 const r = tint_mod(a, as_type<int3>((as_type<uint3>(b) + as_type<uint3>(b))));
   return;
 }
 
diff --git a/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-vec3/i32.wgsl.expected.spvasm b/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-vec3/i32.wgsl.expected.spvasm
index 0a116e0..352b6fd 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-vec3/i32.wgsl.expected.spvasm
+++ b/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-vec3/i32.wgsl.expected.spvasm
@@ -1,38 +1,62 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 23
+; Bound: 42
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %f "f"
                OpExecutionMode %f LocalSize 1 1 1
+               OpName %tint_mod "tint_mod"
+               OpName %lhs "lhs"
+               OpName %rhs "rhs"
                OpName %f "f"
                OpName %a "a"
                OpName %b "b"
-       %void = OpTypeVoid
-          %1 = OpTypeFunction %void
         %int = OpTypeInt 32 1
       %v3int = OpTypeVector %int 3
+          %1 = OpTypeFunction %v3int %v3int %v3int
+          %9 = OpConstantNull %v3int
+       %bool = OpTypeBool
+     %v3bool = OpTypeVector %bool 3
+%int_n2147483648 = OpConstant %int -2147483648
+         %14 = OpConstantComposite %v3int %int_n2147483648 %int_n2147483648 %int_n2147483648
+     %int_n1 = OpConstant %int -1
+         %17 = OpConstantComposite %v3int %int_n1 %int_n1 %int_n1
       %int_1 = OpConstant %int 1
+         %22 = OpConstantComposite %v3int %int_1 %int_1 %int_1
+       %void = OpTypeVoid
+         %24 = OpTypeFunction %void
       %int_2 = OpConstant %int 2
       %int_3 = OpConstant %int 3
-         %10 = OpConstantComposite %v3int %int_1 %int_2 %int_3
+         %30 = OpConstantComposite %v3int %int_1 %int_2 %int_3
 %_ptr_Function_v3int = OpTypePointer Function %v3int
-         %13 = OpConstantNull %v3int
-         %14 = OpConstantNull %int
+         %33 = OpConstantNull %int
       %int_5 = OpConstant %int 5
-         %16 = OpConstantComposite %v3int %14 %int_5 %14
-          %f = OpFunction %void None %1
-          %4 = OpLabel
-          %a = OpVariable %_ptr_Function_v3int Function %13
-          %b = OpVariable %_ptr_Function_v3int Function %13
-               OpStore %a %10
-               OpStore %b %16
-         %18 = OpLoad %v3int %a
-         %19 = OpLoad %v3int %b
-         %20 = OpLoad %v3int %b
-         %21 = OpIAdd %v3int %19 %20
-         %22 = OpSMod %v3int %18 %21
+         %35 = OpConstantComposite %v3int %33 %int_5 %33
+   %tint_mod = OpFunction %v3int None %1
+        %lhs = OpFunctionParameter %v3int
+        %rhs = OpFunctionParameter %v3int
+          %7 = OpLabel
+         %10 = OpIEqual %v3bool %rhs %9
+         %15 = OpIEqual %v3bool %lhs %14
+         %18 = OpIEqual %v3bool %rhs %17
+         %19 = OpLogicalAnd %v3bool %15 %18
+         %20 = OpLogicalOr %v3bool %10 %19
+          %8 = OpSelect %v3int %20 %22 %rhs
+         %23 = OpSMod %v3int %lhs %8
+               OpReturnValue %23
+               OpFunctionEnd
+          %f = OpFunction %void None %24
+         %27 = OpLabel
+          %a = OpVariable %_ptr_Function_v3int Function %9
+          %b = OpVariable %_ptr_Function_v3int Function %9
+               OpStore %a %30
+               OpStore %b %35
+         %38 = OpLoad %v3int %a
+         %39 = OpLoad %v3int %b
+         %40 = OpLoad %v3int %b
+         %41 = OpIAdd %v3int %39 %40
+         %37 = OpFunctionCall %v3int %tint_mod %38 %41
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-vec3/u32.wgsl.expected.dxc.hlsl b/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-vec3/u32.wgsl.expected.dxc.hlsl
index f112cf8..1cb142e 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-vec3/u32.wgsl.expected.dxc.hlsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-vec3/u32.wgsl.expected.dxc.hlsl
@@ -1,11 +1,11 @@
-uint3 value_or_one_if_zero_uint3(uint3 value) {
-  return value == uint3(0u, 0u, 0u) ? uint3(1u, 1u, 1u) : value;
+uint3 tint_mod(uint3 lhs, uint3 rhs) {
+  return (lhs % ((rhs == (0u).xxx) ? (1u).xxx : rhs));
 }
 
 [numthreads(1, 1, 1)]
 void f() {
   uint3 a = uint3(1u, 2u, 3u);
   uint3 b = uint3(0u, 5u, 0u);
-  const uint3 r = (a % value_or_one_if_zero_uint3((b + b)));
+  const uint3 r = tint_mod(a, (b + b));
   return;
 }
diff --git a/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-vec3/u32.wgsl.expected.fxc.hlsl b/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-vec3/u32.wgsl.expected.fxc.hlsl
index f112cf8..1cb142e 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-vec3/u32.wgsl.expected.fxc.hlsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-vec3/u32.wgsl.expected.fxc.hlsl
@@ -1,11 +1,11 @@
-uint3 value_or_one_if_zero_uint3(uint3 value) {
-  return value == uint3(0u, 0u, 0u) ? uint3(1u, 1u, 1u) : value;
+uint3 tint_mod(uint3 lhs, uint3 rhs) {
+  return (lhs % ((rhs == (0u).xxx) ? (1u).xxx : rhs));
 }
 
 [numthreads(1, 1, 1)]
 void f() {
   uint3 a = uint3(1u, 2u, 3u);
   uint3 b = uint3(0u, 5u, 0u);
-  const uint3 r = (a % value_or_one_if_zero_uint3((b + b)));
+  const uint3 r = tint_mod(a, (b + b));
   return;
 }
diff --git a/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-vec3/u32.wgsl.expected.glsl b/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-vec3/u32.wgsl.expected.glsl
index a2f09b1..2f2985a 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-vec3/u32.wgsl.expected.glsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-vec3/u32.wgsl.expected.glsl
@@ -1,9 +1,13 @@
 #version 310 es
 
+uvec3 tint_mod(uvec3 lhs, uvec3 rhs) {
+  return (lhs % mix(rhs, uvec3(1u), equal(rhs, uvec3(0u))));
+}
+
 void f() {
   uvec3 a = uvec3(1u, 2u, 3u);
   uvec3 b = uvec3(0u, 5u, 0u);
-  uvec3 r = (a % (b + b));
+  uvec3 r = tint_mod(a, (b + b));
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-vec3/u32.wgsl.expected.msl b/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-vec3/u32.wgsl.expected.msl
index c6d0db5..d40182b 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-vec3/u32.wgsl.expected.msl
+++ b/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-vec3/u32.wgsl.expected.msl
@@ -1,10 +1,14 @@
 #include <metal_stdlib>
 
 using namespace metal;
+uint3 tint_mod(uint3 lhs, uint3 rhs) {
+  return (lhs % select(rhs, uint3(1u), (rhs == uint3(0u))));
+}
+
 kernel void f() {
   uint3 a = uint3(1u, 2u, 3u);
   uint3 b = uint3(0u, 5u, 0u);
-  uint3 const r = (a % (b + b));
+  uint3 const r = tint_mod(a, (b + b));
   return;
 }
 
diff --git a/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-vec3/u32.wgsl.expected.spvasm b/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-vec3/u32.wgsl.expected.spvasm
index 92c1718..55eb5ab 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-vec3/u32.wgsl.expected.spvasm
+++ b/test/tint/expressions/binary/mod_by_zero/by_expression/vec3-vec3/u32.wgsl.expected.spvasm
@@ -1,38 +1,54 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 23
+; Bound: 34
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %f "f"
                OpExecutionMode %f LocalSize 1 1 1
+               OpName %tint_mod "tint_mod"
+               OpName %lhs "lhs"
+               OpName %rhs "rhs"
                OpName %f "f"
                OpName %a "a"
                OpName %b "b"
-       %void = OpTypeVoid
-          %1 = OpTypeFunction %void
        %uint = OpTypeInt 32 0
      %v3uint = OpTypeVector %uint 3
+          %1 = OpTypeFunction %v3uint %v3uint %v3uint
+          %9 = OpConstantNull %v3uint
+       %bool = OpTypeBool
+     %v3bool = OpTypeVector %bool 3
      %uint_1 = OpConstant %uint 1
+         %14 = OpConstantComposite %v3uint %uint_1 %uint_1 %uint_1
+       %void = OpTypeVoid
+         %16 = OpTypeFunction %void
      %uint_2 = OpConstant %uint 2
      %uint_3 = OpConstant %uint 3
-         %10 = OpConstantComposite %v3uint %uint_1 %uint_2 %uint_3
+         %22 = OpConstantComposite %v3uint %uint_1 %uint_2 %uint_3
 %_ptr_Function_v3uint = OpTypePointer Function %v3uint
-         %13 = OpConstantNull %v3uint
-         %14 = OpConstantNull %uint
+         %25 = OpConstantNull %uint
      %uint_5 = OpConstant %uint 5
-         %16 = OpConstantComposite %v3uint %14 %uint_5 %14
-          %f = OpFunction %void None %1
-          %4 = OpLabel
-          %a = OpVariable %_ptr_Function_v3uint Function %13
-          %b = OpVariable %_ptr_Function_v3uint Function %13
-               OpStore %a %10
-               OpStore %b %16
-         %18 = OpLoad %v3uint %a
-         %19 = OpLoad %v3uint %b
-         %20 = OpLoad %v3uint %b
-         %21 = OpIAdd %v3uint %19 %20
-         %22 = OpUMod %v3uint %18 %21
+         %27 = OpConstantComposite %v3uint %25 %uint_5 %25
+   %tint_mod = OpFunction %v3uint None %1
+        %lhs = OpFunctionParameter %v3uint
+        %rhs = OpFunctionParameter %v3uint
+          %7 = OpLabel
+         %10 = OpIEqual %v3bool %rhs %9
+          %8 = OpSelect %v3uint %10 %14 %rhs
+         %15 = OpUMod %v3uint %lhs %8
+               OpReturnValue %15
+               OpFunctionEnd
+          %f = OpFunction %void None %16
+         %19 = OpLabel
+          %a = OpVariable %_ptr_Function_v3uint Function %9
+          %b = OpVariable %_ptr_Function_v3uint Function %9
+               OpStore %a %22
+               OpStore %b %27
+         %30 = OpLoad %v3uint %a
+         %31 = OpLoad %v3uint %b
+         %32 = OpLoad %v3uint %b
+         %33 = OpIAdd %v3uint %31 %32
+         %29 = OpFunctionCall %v3uint %tint_mod %30 %33
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-scalar/i32.wgsl.expected.dxc.hlsl b/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-scalar/i32.wgsl.expected.dxc.hlsl
index 9f27720..dcafd63 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-scalar/i32.wgsl.expected.dxc.hlsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-scalar/i32.wgsl.expected.dxc.hlsl
@@ -1,7 +1,11 @@
+int tint_mod(int lhs, int rhs) {
+  return (lhs % (((rhs == 0) | ((lhs == -2147483648) & (rhs == -1))) ? 1 : rhs));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   int a = 1;
   int b = 0;
-  const int r = (a % (b == 0 ? 1 : b));
+  const int r = tint_mod(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-scalar/i32.wgsl.expected.fxc.hlsl b/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-scalar/i32.wgsl.expected.fxc.hlsl
index 9f27720..dcafd63 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-scalar/i32.wgsl.expected.fxc.hlsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-scalar/i32.wgsl.expected.fxc.hlsl
@@ -1,7 +1,11 @@
+int tint_mod(int lhs, int rhs) {
+  return (lhs % (((rhs == 0) | ((lhs == -2147483648) & (rhs == -1))) ? 1 : rhs));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   int a = 1;
   int b = 0;
-  const int r = (a % (b == 0 ? 1 : b));
+  const int r = tint_mod(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-scalar/i32.wgsl.expected.glsl b/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-scalar/i32.wgsl.expected.glsl
index 1f7158f..ddb6a6b 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-scalar/i32.wgsl.expected.glsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-scalar/i32.wgsl.expected.glsl
@@ -1,9 +1,13 @@
 #version 310 es
 
+int tint_mod(int lhs, int rhs) {
+  return (lhs % (bool(uint((rhs == 0)) | uint(bool(uint((lhs == -2147483648)) & uint((rhs == -1))))) ? 1 : rhs));
+}
+
 void f() {
   int a = 1;
   int b = 0;
-  int r = (a % b);
+  int r = tint_mod(a, b);
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-scalar/i32.wgsl.expected.msl b/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-scalar/i32.wgsl.expected.msl
index 4a51c54..56de74d 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-scalar/i32.wgsl.expected.msl
+++ b/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-scalar/i32.wgsl.expected.msl
@@ -1,10 +1,14 @@
 #include <metal_stdlib>
 
 using namespace metal;
+int tint_mod(int lhs, int rhs) {
+  return (lhs % select(rhs, 1, bool((rhs == 0) | bool((lhs == (-2147483647 - 1)) & (rhs == -1)))));
+}
+
 kernel void f() {
   int a = 1;
   int b = 0;
-  int const r = (a % b);
+  int const r = tint_mod(a, b);
   return;
 }
 
diff --git a/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-scalar/i32.wgsl.expected.spvasm b/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-scalar/i32.wgsl.expected.spvasm
index 68aabf4..9519959 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-scalar/i32.wgsl.expected.spvasm
+++ b/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-scalar/i32.wgsl.expected.spvasm
@@ -1,29 +1,49 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 14
+; Bound: 29
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %f "f"
                OpExecutionMode %f LocalSize 1 1 1
+               OpName %tint_mod "tint_mod"
+               OpName %lhs "lhs"
+               OpName %rhs "rhs"
                OpName %f "f"
                OpName %a "a"
                OpName %b "b"
-       %void = OpTypeVoid
-          %1 = OpTypeFunction %void
         %int = OpTypeInt 32 1
+          %1 = OpTypeFunction %int %int %int
+          %8 = OpConstantNull %int
+       %bool = OpTypeBool
+%int_n2147483648 = OpConstant %int -2147483648
+     %int_n1 = OpConstant %int -1
       %int_1 = OpConstant %int 1
+       %void = OpTypeVoid
+         %19 = OpTypeFunction %void
 %_ptr_Function_int = OpTypePointer Function %int
-          %9 = OpConstantNull %int
-          %f = OpFunction %void None %1
-          %4 = OpLabel
-          %a = OpVariable %_ptr_Function_int Function %9
-          %b = OpVariable %_ptr_Function_int Function %9
+   %tint_mod = OpFunction %int None %1
+        %lhs = OpFunctionParameter %int
+        %rhs = OpFunctionParameter %int
+          %6 = OpLabel
+          %9 = OpIEqual %bool %rhs %8
+         %12 = OpIEqual %bool %lhs %int_n2147483648
+         %14 = OpIEqual %bool %rhs %int_n1
+         %15 = OpLogicalAnd %bool %12 %14
+         %16 = OpLogicalOr %bool %9 %15
+          %7 = OpSelect %int %16 %int_1 %rhs
+         %18 = OpSMod %int %lhs %7
+               OpReturnValue %18
+               OpFunctionEnd
+          %f = OpFunction %void None %19
+         %22 = OpLabel
+          %a = OpVariable %_ptr_Function_int Function %8
+          %b = OpVariable %_ptr_Function_int Function %8
                OpStore %a %int_1
-               OpStore %b %9
-         %11 = OpLoad %int %a
-         %12 = OpLoad %int %b
-         %13 = OpSMod %int %11 %12
+               OpStore %b %8
+         %27 = OpLoad %int %a
+         %28 = OpLoad %int %b
+         %26 = OpFunctionCall %int %tint_mod %27 %28
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-scalar/u32.wgsl.expected.dxc.hlsl b/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-scalar/u32.wgsl.expected.dxc.hlsl
index cc3d3c1..d2cfc63 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-scalar/u32.wgsl.expected.dxc.hlsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-scalar/u32.wgsl.expected.dxc.hlsl
@@ -1,7 +1,11 @@
+uint tint_mod(uint lhs, uint rhs) {
+  return (lhs % ((rhs == 0u) ? 1u : rhs));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   uint a = 1u;
   uint b = 0u;
-  const uint r = (a % (b == 0u ? 1u : b));
+  const uint r = tint_mod(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-scalar/u32.wgsl.expected.fxc.hlsl b/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-scalar/u32.wgsl.expected.fxc.hlsl
index cc3d3c1..d2cfc63 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-scalar/u32.wgsl.expected.fxc.hlsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-scalar/u32.wgsl.expected.fxc.hlsl
@@ -1,7 +1,11 @@
+uint tint_mod(uint lhs, uint rhs) {
+  return (lhs % ((rhs == 0u) ? 1u : rhs));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   uint a = 1u;
   uint b = 0u;
-  const uint r = (a % (b == 0u ? 1u : b));
+  const uint r = tint_mod(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-scalar/u32.wgsl.expected.glsl b/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-scalar/u32.wgsl.expected.glsl
index d30fde8..9fd11d7 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-scalar/u32.wgsl.expected.glsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-scalar/u32.wgsl.expected.glsl
@@ -1,9 +1,13 @@
 #version 310 es
 
+uint tint_mod(uint lhs, uint rhs) {
+  return (lhs % ((rhs == 0u) ? 1u : rhs));
+}
+
 void f() {
   uint a = 1u;
   uint b = 0u;
-  uint r = (a % b);
+  uint r = tint_mod(a, b);
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-scalar/u32.wgsl.expected.msl b/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-scalar/u32.wgsl.expected.msl
index 8849d0d..98aa108 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-scalar/u32.wgsl.expected.msl
+++ b/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-scalar/u32.wgsl.expected.msl
@@ -1,10 +1,14 @@
 #include <metal_stdlib>
 
 using namespace metal;
+uint tint_mod(uint lhs, uint rhs) {
+  return (lhs % select(rhs, 1u, (rhs == 0u)));
+}
+
 kernel void f() {
   uint a = 1u;
   uint b = 0u;
-  uint const r = (a % b);
+  uint const r = tint_mod(a, b);
   return;
 }
 
diff --git a/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-scalar/u32.wgsl.expected.spvasm b/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-scalar/u32.wgsl.expected.spvasm
index 62435a1..c5ec4da 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-scalar/u32.wgsl.expected.spvasm
+++ b/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-scalar/u32.wgsl.expected.spvasm
@@ -1,29 +1,43 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 14
+; Bound: 23
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %f "f"
                OpExecutionMode %f LocalSize 1 1 1
+               OpName %tint_mod "tint_mod"
+               OpName %lhs "lhs"
+               OpName %rhs "rhs"
                OpName %f "f"
                OpName %a "a"
                OpName %b "b"
-       %void = OpTypeVoid
-          %1 = OpTypeFunction %void
        %uint = OpTypeInt 32 0
+          %1 = OpTypeFunction %uint %uint %uint
+          %8 = OpConstantNull %uint
+       %bool = OpTypeBool
      %uint_1 = OpConstant %uint 1
+       %void = OpTypeVoid
+         %13 = OpTypeFunction %void
 %_ptr_Function_uint = OpTypePointer Function %uint
-          %9 = OpConstantNull %uint
-          %f = OpFunction %void None %1
-          %4 = OpLabel
-          %a = OpVariable %_ptr_Function_uint Function %9
-          %b = OpVariable %_ptr_Function_uint Function %9
+   %tint_mod = OpFunction %uint None %1
+        %lhs = OpFunctionParameter %uint
+        %rhs = OpFunctionParameter %uint
+          %6 = OpLabel
+          %9 = OpIEqual %bool %rhs %8
+          %7 = OpSelect %uint %9 %uint_1 %rhs
+         %12 = OpUMod %uint %lhs %7
+               OpReturnValue %12
+               OpFunctionEnd
+          %f = OpFunction %void None %13
+         %16 = OpLabel
+          %a = OpVariable %_ptr_Function_uint Function %8
+          %b = OpVariable %_ptr_Function_uint Function %8
                OpStore %a %uint_1
-               OpStore %b %9
-         %11 = OpLoad %uint %a
-         %12 = OpLoad %uint %b
-         %13 = OpUMod %uint %11 %12
+               OpStore %b %8
+         %21 = OpLoad %uint %a
+         %22 = OpLoad %uint %b
+         %20 = OpFunctionCall %uint %tint_mod %21 %22
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-vec3/i32.wgsl.expected.dxc.hlsl b/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-vec3/i32.wgsl.expected.dxc.hlsl
index 0b14c77..4c97839 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-vec3/i32.wgsl.expected.dxc.hlsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-vec3/i32.wgsl.expected.dxc.hlsl
@@ -1,7 +1,12 @@
+int3 tint_mod(int lhs, int3 rhs) {
+  const int3 l = int3((lhs).xxx);
+  return (l % (((rhs == (0).xxx) | ((l == (-2147483648).xxx) & (rhs == (-1).xxx))) ? (1).xxx : rhs));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   int a = 4;
   int3 b = int3(0, 2, 0);
-  const int3 r = (a % (b == int3(0, 0, 0) ? int3(1, 1, 1) : b));
+  const int3 r = tint_mod(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-vec3/i32.wgsl.expected.fxc.hlsl b/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-vec3/i32.wgsl.expected.fxc.hlsl
index 0b14c77..4c97839 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-vec3/i32.wgsl.expected.fxc.hlsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-vec3/i32.wgsl.expected.fxc.hlsl
@@ -1,7 +1,12 @@
+int3 tint_mod(int lhs, int3 rhs) {
+  const int3 l = int3((lhs).xxx);
+  return (l % (((rhs == (0).xxx) | ((l == (-2147483648).xxx) & (rhs == (-1).xxx))) ? (1).xxx : rhs));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   int a = 4;
   int3 b = int3(0, 2, 0);
-  const int3 r = (a % (b == int3(0, 0, 0) ? int3(1, 1, 1) : b));
+  const int3 r = tint_mod(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-vec3/i32.wgsl.expected.glsl b/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-vec3/i32.wgsl.expected.glsl
index e19dc46..412aedf 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-vec3/i32.wgsl.expected.glsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-vec3/i32.wgsl.expected.glsl
@@ -1,9 +1,14 @@
 #version 310 es
 
+ivec3 tint_mod(int lhs, ivec3 rhs) {
+  ivec3 l = ivec3(lhs);
+  return (l % mix(rhs, ivec3(1), bvec3(uvec3(equal(rhs, ivec3(0))) | uvec3(bvec3(uvec3(equal(l, ivec3(-2147483648))) & uvec3(equal(rhs, ivec3(-1))))))));
+}
+
 void f() {
   int a = 4;
   ivec3 b = ivec3(0, 2, 0);
-  ivec3 r = (a % b);
+  ivec3 r = tint_mod(a, b);
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-vec3/i32.wgsl.expected.msl b/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-vec3/i32.wgsl.expected.msl
index ae32a86..143e92e 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-vec3/i32.wgsl.expected.msl
+++ b/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-vec3/i32.wgsl.expected.msl
@@ -1,10 +1,15 @@
 #include <metal_stdlib>
 
 using namespace metal;
+int3 tint_mod(int lhs, int3 rhs) {
+  int3 const l = int3(lhs);
+  return (l % select(rhs, int3(1), ((rhs == int3(0)) | ((l == int3((-2147483647 - 1))) & (rhs == int3(-1))))));
+}
+
 kernel void f() {
   int a = 4;
   int3 b = int3(0, 2, 0);
-  int3 const r = (a % b);
+  int3 const r = tint_mod(a, b);
   return;
 }
 
diff --git a/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-vec3/i32.wgsl.expected.spvasm b/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-vec3/i32.wgsl.expected.spvasm
index 4ceb097..43fb605 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-vec3/i32.wgsl.expected.spvasm
+++ b/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-vec3/i32.wgsl.expected.spvasm
@@ -1,36 +1,60 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 21
+; Bound: 40
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %f "f"
                OpExecutionMode %f LocalSize 1 1 1
+               OpName %tint_mod "tint_mod"
+               OpName %lhs "lhs"
+               OpName %rhs "rhs"
                OpName %f "f"
                OpName %a "a"
                OpName %b "b"
-       %void = OpTypeVoid
-          %1 = OpTypeFunction %void
         %int = OpTypeInt 32 1
+      %v3int = OpTypeVector %int 3
+          %1 = OpTypeFunction %v3int %int %v3int
+         %10 = OpConstantNull %v3int
+       %bool = OpTypeBool
+     %v3bool = OpTypeVector %bool 3
+%int_n2147483648 = OpConstant %int -2147483648
+         %15 = OpConstantComposite %v3int %int_n2147483648 %int_n2147483648 %int_n2147483648
+     %int_n1 = OpConstant %int -1
+         %18 = OpConstantComposite %v3int %int_n1 %int_n1 %int_n1
+      %int_1 = OpConstant %int 1
+         %23 = OpConstantComposite %v3int %int_1 %int_1 %int_1
+       %void = OpTypeVoid
+         %25 = OpTypeFunction %void
       %int_4 = OpConstant %int 4
 %_ptr_Function_int = OpTypePointer Function %int
-          %9 = OpConstantNull %int
-      %v3int = OpTypeVector %int 3
+         %32 = OpConstantNull %int
       %int_2 = OpConstant %int 2
-         %12 = OpConstantComposite %v3int %9 %int_2 %9
+         %34 = OpConstantComposite %v3int %32 %int_2 %32
 %_ptr_Function_v3int = OpTypePointer Function %v3int
-         %15 = OpConstantNull %v3int
-          %f = OpFunction %void None %1
-          %4 = OpLabel
-          %a = OpVariable %_ptr_Function_int Function %9
-          %b = OpVariable %_ptr_Function_v3int Function %15
-         %19 = OpVariable %_ptr_Function_v3int Function %15
+   %tint_mod = OpFunction %v3int None %1
+        %lhs = OpFunctionParameter %int
+        %rhs = OpFunctionParameter %v3int
+          %7 = OpLabel
+          %8 = OpCompositeConstruct %v3int %lhs %lhs %lhs
+         %11 = OpIEqual %v3bool %rhs %10
+         %16 = OpIEqual %v3bool %8 %15
+         %19 = OpIEqual %v3bool %rhs %18
+         %20 = OpLogicalAnd %v3bool %16 %19
+         %21 = OpLogicalOr %v3bool %11 %20
+          %9 = OpSelect %v3int %21 %23 %rhs
+         %24 = OpSMod %v3int %8 %9
+               OpReturnValue %24
+               OpFunctionEnd
+          %f = OpFunction %void None %25
+         %28 = OpLabel
+          %a = OpVariable %_ptr_Function_int Function %32
+          %b = OpVariable %_ptr_Function_v3int Function %10
                OpStore %a %int_4
-               OpStore %b %12
-         %16 = OpLoad %int %a
-         %17 = OpLoad %v3int %b
-         %20 = OpCompositeConstruct %v3int %16 %16 %16
-         %18 = OpSMod %v3int %20 %17
+               OpStore %b %34
+         %38 = OpLoad %int %a
+         %39 = OpLoad %v3int %b
+         %37 = OpFunctionCall %v3int %tint_mod %38 %39
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-vec3/u32.wgsl.expected.dxc.hlsl b/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-vec3/u32.wgsl.expected.dxc.hlsl
index fa88822..bc7a07e 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-vec3/u32.wgsl.expected.dxc.hlsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-vec3/u32.wgsl.expected.dxc.hlsl
@@ -1,7 +1,12 @@
+uint3 tint_mod(uint lhs, uint3 rhs) {
+  const uint3 l = uint3((lhs).xxx);
+  return (l % ((rhs == (0u).xxx) ? (1u).xxx : rhs));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   uint a = 4u;
   uint3 b = uint3(0u, 2u, 0u);
-  const uint3 r = (a % (b == uint3(0u, 0u, 0u) ? uint3(1u, 1u, 1u) : b));
+  const uint3 r = tint_mod(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-vec3/u32.wgsl.expected.fxc.hlsl b/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-vec3/u32.wgsl.expected.fxc.hlsl
index fa88822..bc7a07e 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-vec3/u32.wgsl.expected.fxc.hlsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-vec3/u32.wgsl.expected.fxc.hlsl
@@ -1,7 +1,12 @@
+uint3 tint_mod(uint lhs, uint3 rhs) {
+  const uint3 l = uint3((lhs).xxx);
+  return (l % ((rhs == (0u).xxx) ? (1u).xxx : rhs));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   uint a = 4u;
   uint3 b = uint3(0u, 2u, 0u);
-  const uint3 r = (a % (b == uint3(0u, 0u, 0u) ? uint3(1u, 1u, 1u) : b));
+  const uint3 r = tint_mod(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-vec3/u32.wgsl.expected.glsl b/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-vec3/u32.wgsl.expected.glsl
index 633b9ed..534cab7 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-vec3/u32.wgsl.expected.glsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-vec3/u32.wgsl.expected.glsl
@@ -1,9 +1,14 @@
 #version 310 es
 
+uvec3 tint_mod(uint lhs, uvec3 rhs) {
+  uvec3 l = uvec3(lhs);
+  return (l % mix(rhs, uvec3(1u), equal(rhs, uvec3(0u))));
+}
+
 void f() {
   uint a = 4u;
   uvec3 b = uvec3(0u, 2u, 0u);
-  uvec3 r = (a % b);
+  uvec3 r = tint_mod(a, b);
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-vec3/u32.wgsl.expected.msl b/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-vec3/u32.wgsl.expected.msl
index bc4bada..0de3b76 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-vec3/u32.wgsl.expected.msl
+++ b/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-vec3/u32.wgsl.expected.msl
@@ -1,10 +1,15 @@
 #include <metal_stdlib>
 
 using namespace metal;
+uint3 tint_mod(uint lhs, uint3 rhs) {
+  uint3 const l = uint3(lhs);
+  return (l % select(rhs, uint3(1u), (rhs == uint3(0u))));
+}
+
 kernel void f() {
   uint a = 4u;
   uint3 b = uint3(0u, 2u, 0u);
-  uint3 const r = (a % b);
+  uint3 const r = tint_mod(a, b);
   return;
 }
 
diff --git a/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-vec3/u32.wgsl.expected.spvasm b/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-vec3/u32.wgsl.expected.spvasm
index 3c1d47c..7adf383 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-vec3/u32.wgsl.expected.spvasm
+++ b/test/tint/expressions/binary/mod_by_zero/by_identifier/scalar-vec3/u32.wgsl.expected.spvasm
@@ -1,36 +1,52 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 21
+; Bound: 32
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %f "f"
                OpExecutionMode %f LocalSize 1 1 1
+               OpName %tint_mod "tint_mod"
+               OpName %lhs "lhs"
+               OpName %rhs "rhs"
                OpName %f "f"
                OpName %a "a"
                OpName %b "b"
-       %void = OpTypeVoid
-          %1 = OpTypeFunction %void
        %uint = OpTypeInt 32 0
+     %v3uint = OpTypeVector %uint 3
+          %1 = OpTypeFunction %v3uint %uint %v3uint
+         %10 = OpConstantNull %v3uint
+       %bool = OpTypeBool
+     %v3bool = OpTypeVector %bool 3
+     %uint_1 = OpConstant %uint 1
+         %15 = OpConstantComposite %v3uint %uint_1 %uint_1 %uint_1
+       %void = OpTypeVoid
+         %17 = OpTypeFunction %void
      %uint_4 = OpConstant %uint 4
 %_ptr_Function_uint = OpTypePointer Function %uint
-          %9 = OpConstantNull %uint
-     %v3uint = OpTypeVector %uint 3
+         %24 = OpConstantNull %uint
      %uint_2 = OpConstant %uint 2
-         %12 = OpConstantComposite %v3uint %9 %uint_2 %9
+         %26 = OpConstantComposite %v3uint %24 %uint_2 %24
 %_ptr_Function_v3uint = OpTypePointer Function %v3uint
-         %15 = OpConstantNull %v3uint
-          %f = OpFunction %void None %1
-          %4 = OpLabel
-          %a = OpVariable %_ptr_Function_uint Function %9
-          %b = OpVariable %_ptr_Function_v3uint Function %15
-         %19 = OpVariable %_ptr_Function_v3uint Function %15
+   %tint_mod = OpFunction %v3uint None %1
+        %lhs = OpFunctionParameter %uint
+        %rhs = OpFunctionParameter %v3uint
+          %7 = OpLabel
+          %8 = OpCompositeConstruct %v3uint %lhs %lhs %lhs
+         %11 = OpIEqual %v3bool %rhs %10
+          %9 = OpSelect %v3uint %11 %15 %rhs
+         %16 = OpUMod %v3uint %8 %9
+               OpReturnValue %16
+               OpFunctionEnd
+          %f = OpFunction %void None %17
+         %20 = OpLabel
+          %a = OpVariable %_ptr_Function_uint Function %24
+          %b = OpVariable %_ptr_Function_v3uint Function %10
                OpStore %a %uint_4
-               OpStore %b %12
-         %16 = OpLoad %uint %a
-         %17 = OpLoad %v3uint %b
-         %20 = OpCompositeConstruct %v3uint %16 %16 %16
-         %18 = OpUMod %v3uint %20 %17
+               OpStore %b %26
+         %30 = OpLoad %uint %a
+         %31 = OpLoad %v3uint %b
+         %29 = OpFunctionCall %v3uint %tint_mod %30 %31
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-scalar/i32.wgsl.expected.dxc.hlsl b/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-scalar/i32.wgsl.expected.dxc.hlsl
index 208637e..fc3af83 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-scalar/i32.wgsl.expected.dxc.hlsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-scalar/i32.wgsl.expected.dxc.hlsl
@@ -1,7 +1,12 @@
+int3 tint_mod(int3 lhs, int rhs) {
+  const int3 r = int3((rhs).xxx);
+  return (lhs % (((r == (0).xxx) | ((lhs == (-2147483648).xxx) & (r == (-1).xxx))) ? (1).xxx : r));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   int3 a = int3(1, 2, 3);
   int b = 0;
-  const int3 r = (a % (b == 0 ? 1 : b));
+  const int3 r = tint_mod(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-scalar/i32.wgsl.expected.fxc.hlsl b/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-scalar/i32.wgsl.expected.fxc.hlsl
index 208637e..fc3af83 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-scalar/i32.wgsl.expected.fxc.hlsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-scalar/i32.wgsl.expected.fxc.hlsl
@@ -1,7 +1,12 @@
+int3 tint_mod(int3 lhs, int rhs) {
+  const int3 r = int3((rhs).xxx);
+  return (lhs % (((r == (0).xxx) | ((lhs == (-2147483648).xxx) & (r == (-1).xxx))) ? (1).xxx : r));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   int3 a = int3(1, 2, 3);
   int b = 0;
-  const int3 r = (a % (b == 0 ? 1 : b));
+  const int3 r = tint_mod(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-scalar/i32.wgsl.expected.glsl b/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-scalar/i32.wgsl.expected.glsl
index d74047a..788c7fe 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-scalar/i32.wgsl.expected.glsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-scalar/i32.wgsl.expected.glsl
@@ -1,9 +1,14 @@
 #version 310 es
 
+ivec3 tint_mod(ivec3 lhs, int rhs) {
+  ivec3 r = ivec3(rhs);
+  return (lhs % mix(r, ivec3(1), bvec3(uvec3(equal(r, ivec3(0))) | uvec3(bvec3(uvec3(equal(lhs, ivec3(-2147483648))) & uvec3(equal(r, ivec3(-1))))))));
+}
+
 void f() {
   ivec3 a = ivec3(1, 2, 3);
   int b = 0;
-  ivec3 r = (a % b);
+  ivec3 r = tint_mod(a, b);
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-scalar/i32.wgsl.expected.msl b/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-scalar/i32.wgsl.expected.msl
index 39d00f8..e84bf2f 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-scalar/i32.wgsl.expected.msl
+++ b/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-scalar/i32.wgsl.expected.msl
@@ -1,10 +1,15 @@
 #include <metal_stdlib>
 
 using namespace metal;
+int3 tint_mod(int3 lhs, int rhs) {
+  int3 const r = int3(rhs);
+  return (lhs % select(r, int3(1), ((r == int3(0)) | ((lhs == int3((-2147483647 - 1))) & (r == int3(-1))))));
+}
+
 kernel void f() {
   int3 a = int3(1, 2, 3);
   int b = 0;
-  int3 const r = (a % b);
+  int3 const r = tint_mod(a, b);
   return;
 }
 
diff --git a/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-scalar/i32.wgsl.expected.spvasm b/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-scalar/i32.wgsl.expected.spvasm
index d5f44f4..703e72d 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-scalar/i32.wgsl.expected.spvasm
+++ b/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-scalar/i32.wgsl.expected.spvasm
@@ -1,37 +1,60 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 22
+; Bound: 40
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %f "f"
                OpExecutionMode %f LocalSize 1 1 1
+               OpName %tint_mod "tint_mod"
+               OpName %lhs "lhs"
+               OpName %rhs "rhs"
                OpName %f "f"
                OpName %a "a"
                OpName %b "b"
-       %void = OpTypeVoid
-          %1 = OpTypeFunction %void
         %int = OpTypeInt 32 1
       %v3int = OpTypeVector %int 3
+          %1 = OpTypeFunction %v3int %v3int %int
+         %10 = OpConstantNull %v3int
+       %bool = OpTypeBool
+     %v3bool = OpTypeVector %bool 3
+%int_n2147483648 = OpConstant %int -2147483648
+         %15 = OpConstantComposite %v3int %int_n2147483648 %int_n2147483648 %int_n2147483648
+     %int_n1 = OpConstant %int -1
+         %18 = OpConstantComposite %v3int %int_n1 %int_n1 %int_n1
       %int_1 = OpConstant %int 1
+         %23 = OpConstantComposite %v3int %int_1 %int_1 %int_1
+       %void = OpTypeVoid
+         %25 = OpTypeFunction %void
       %int_2 = OpConstant %int 2
       %int_3 = OpConstant %int 3
-         %10 = OpConstantComposite %v3int %int_1 %int_2 %int_3
+         %31 = OpConstantComposite %v3int %int_1 %int_2 %int_3
 %_ptr_Function_v3int = OpTypePointer Function %v3int
-         %13 = OpConstantNull %v3int
-         %14 = OpConstantNull %int
+         %34 = OpConstantNull %int
 %_ptr_Function_int = OpTypePointer Function %int
-          %f = OpFunction %void None %1
-          %4 = OpLabel
-          %a = OpVariable %_ptr_Function_v3int Function %13
-          %b = OpVariable %_ptr_Function_int Function %14
-         %20 = OpVariable %_ptr_Function_v3int Function %13
-               OpStore %a %10
-               OpStore %b %14
-         %17 = OpLoad %v3int %a
-         %18 = OpLoad %int %b
-         %21 = OpCompositeConstruct %v3int %18 %18 %18
-         %19 = OpSMod %v3int %17 %21
+   %tint_mod = OpFunction %v3int None %1
+        %lhs = OpFunctionParameter %v3int
+        %rhs = OpFunctionParameter %int
+          %7 = OpLabel
+          %8 = OpCompositeConstruct %v3int %rhs %rhs %rhs
+         %11 = OpIEqual %v3bool %8 %10
+         %16 = OpIEqual %v3bool %lhs %15
+         %19 = OpIEqual %v3bool %8 %18
+         %20 = OpLogicalAnd %v3bool %16 %19
+         %21 = OpLogicalOr %v3bool %11 %20
+          %9 = OpSelect %v3int %21 %23 %8
+         %24 = OpSMod %v3int %lhs %9
+               OpReturnValue %24
+               OpFunctionEnd
+          %f = OpFunction %void None %25
+         %28 = OpLabel
+          %a = OpVariable %_ptr_Function_v3int Function %10
+          %b = OpVariable %_ptr_Function_int Function %34
+               OpStore %a %31
+               OpStore %b %34
+         %38 = OpLoad %v3int %a
+         %39 = OpLoad %int %b
+         %37 = OpFunctionCall %v3int %tint_mod %38 %39
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-scalar/u32.wgsl.expected.dxc.hlsl b/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-scalar/u32.wgsl.expected.dxc.hlsl
index 0cb79cf..b9e649a 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-scalar/u32.wgsl.expected.dxc.hlsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-scalar/u32.wgsl.expected.dxc.hlsl
@@ -1,7 +1,12 @@
+uint3 tint_mod(uint3 lhs, uint rhs) {
+  const uint3 r = uint3((rhs).xxx);
+  return (lhs % ((r == (0u).xxx) ? (1u).xxx : r));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   uint3 a = uint3(1u, 2u, 3u);
   uint b = 0u;
-  const uint3 r = (a % (b == 0u ? 1u : b));
+  const uint3 r = tint_mod(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-scalar/u32.wgsl.expected.fxc.hlsl b/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-scalar/u32.wgsl.expected.fxc.hlsl
index 0cb79cf..b9e649a 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-scalar/u32.wgsl.expected.fxc.hlsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-scalar/u32.wgsl.expected.fxc.hlsl
@@ -1,7 +1,12 @@
+uint3 tint_mod(uint3 lhs, uint rhs) {
+  const uint3 r = uint3((rhs).xxx);
+  return (lhs % ((r == (0u).xxx) ? (1u).xxx : r));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   uint3 a = uint3(1u, 2u, 3u);
   uint b = 0u;
-  const uint3 r = (a % (b == 0u ? 1u : b));
+  const uint3 r = tint_mod(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-scalar/u32.wgsl.expected.glsl b/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-scalar/u32.wgsl.expected.glsl
index d84b14b1..03f7867 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-scalar/u32.wgsl.expected.glsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-scalar/u32.wgsl.expected.glsl
@@ -1,9 +1,14 @@
 #version 310 es
 
+uvec3 tint_mod(uvec3 lhs, uint rhs) {
+  uvec3 r = uvec3(rhs);
+  return (lhs % mix(r, uvec3(1u), equal(r, uvec3(0u))));
+}
+
 void f() {
   uvec3 a = uvec3(1u, 2u, 3u);
   uint b = 0u;
-  uvec3 r = (a % b);
+  uvec3 r = tint_mod(a, b);
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-scalar/u32.wgsl.expected.msl b/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-scalar/u32.wgsl.expected.msl
index 3c8b16e..c6a3362 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-scalar/u32.wgsl.expected.msl
+++ b/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-scalar/u32.wgsl.expected.msl
@@ -1,10 +1,15 @@
 #include <metal_stdlib>
 
 using namespace metal;
+uint3 tint_mod(uint3 lhs, uint rhs) {
+  uint3 const r = uint3(rhs);
+  return (lhs % select(r, uint3(1u), (r == uint3(0u))));
+}
+
 kernel void f() {
   uint3 a = uint3(1u, 2u, 3u);
   uint b = 0u;
-  uint3 const r = (a % b);
+  uint3 const r = tint_mod(a, b);
   return;
 }
 
diff --git a/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-scalar/u32.wgsl.expected.spvasm b/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-scalar/u32.wgsl.expected.spvasm
index 36e5909..a1b3a0e 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-scalar/u32.wgsl.expected.spvasm
+++ b/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-scalar/u32.wgsl.expected.spvasm
@@ -1,37 +1,52 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 22
+; Bound: 32
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %f "f"
                OpExecutionMode %f LocalSize 1 1 1
+               OpName %tint_mod "tint_mod"
+               OpName %lhs "lhs"
+               OpName %rhs "rhs"
                OpName %f "f"
                OpName %a "a"
                OpName %b "b"
-       %void = OpTypeVoid
-          %1 = OpTypeFunction %void
        %uint = OpTypeInt 32 0
      %v3uint = OpTypeVector %uint 3
+          %1 = OpTypeFunction %v3uint %v3uint %uint
+         %10 = OpConstantNull %v3uint
+       %bool = OpTypeBool
+     %v3bool = OpTypeVector %bool 3
      %uint_1 = OpConstant %uint 1
+         %15 = OpConstantComposite %v3uint %uint_1 %uint_1 %uint_1
+       %void = OpTypeVoid
+         %17 = OpTypeFunction %void
      %uint_2 = OpConstant %uint 2
      %uint_3 = OpConstant %uint 3
-         %10 = OpConstantComposite %v3uint %uint_1 %uint_2 %uint_3
+         %23 = OpConstantComposite %v3uint %uint_1 %uint_2 %uint_3
 %_ptr_Function_v3uint = OpTypePointer Function %v3uint
-         %13 = OpConstantNull %v3uint
-         %14 = OpConstantNull %uint
+         %26 = OpConstantNull %uint
 %_ptr_Function_uint = OpTypePointer Function %uint
-          %f = OpFunction %void None %1
-          %4 = OpLabel
-          %a = OpVariable %_ptr_Function_v3uint Function %13
-          %b = OpVariable %_ptr_Function_uint Function %14
-         %20 = OpVariable %_ptr_Function_v3uint Function %13
-               OpStore %a %10
-               OpStore %b %14
-         %17 = OpLoad %v3uint %a
-         %18 = OpLoad %uint %b
-         %21 = OpCompositeConstruct %v3uint %18 %18 %18
-         %19 = OpUMod %v3uint %17 %21
+   %tint_mod = OpFunction %v3uint None %1
+        %lhs = OpFunctionParameter %v3uint
+        %rhs = OpFunctionParameter %uint
+          %7 = OpLabel
+          %8 = OpCompositeConstruct %v3uint %rhs %rhs %rhs
+         %11 = OpIEqual %v3bool %8 %10
+          %9 = OpSelect %v3uint %11 %15 %8
+         %16 = OpUMod %v3uint %lhs %9
+               OpReturnValue %16
+               OpFunctionEnd
+          %f = OpFunction %void None %17
+         %20 = OpLabel
+          %a = OpVariable %_ptr_Function_v3uint Function %10
+          %b = OpVariable %_ptr_Function_uint Function %26
+               OpStore %a %23
+               OpStore %b %26
+         %30 = OpLoad %v3uint %a
+         %31 = OpLoad %uint %b
+         %29 = OpFunctionCall %v3uint %tint_mod %30 %31
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-vec3/i32.wgsl.expected.dxc.hlsl b/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-vec3/i32.wgsl.expected.dxc.hlsl
index 97e59e6..6369536 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-vec3/i32.wgsl.expected.dxc.hlsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-vec3/i32.wgsl.expected.dxc.hlsl
@@ -1,7 +1,11 @@
+int3 tint_mod(int3 lhs, int3 rhs) {
+  return (lhs % (((rhs == (0).xxx) | ((lhs == (-2147483648).xxx) & (rhs == (-1).xxx))) ? (1).xxx : rhs));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   int3 a = int3(1, 2, 3);
   int3 b = int3(0, 5, 0);
-  const int3 r = (a % (b == int3(0, 0, 0) ? int3(1, 1, 1) : b));
+  const int3 r = tint_mod(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-vec3/i32.wgsl.expected.fxc.hlsl b/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-vec3/i32.wgsl.expected.fxc.hlsl
index 97e59e6..6369536 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-vec3/i32.wgsl.expected.fxc.hlsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-vec3/i32.wgsl.expected.fxc.hlsl
@@ -1,7 +1,11 @@
+int3 tint_mod(int3 lhs, int3 rhs) {
+  return (lhs % (((rhs == (0).xxx) | ((lhs == (-2147483648).xxx) & (rhs == (-1).xxx))) ? (1).xxx : rhs));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   int3 a = int3(1, 2, 3);
   int3 b = int3(0, 5, 0);
-  const int3 r = (a % (b == int3(0, 0, 0) ? int3(1, 1, 1) : b));
+  const int3 r = tint_mod(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-vec3/i32.wgsl.expected.glsl b/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-vec3/i32.wgsl.expected.glsl
index 809b454..e1da394 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-vec3/i32.wgsl.expected.glsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-vec3/i32.wgsl.expected.glsl
@@ -1,9 +1,13 @@
 #version 310 es
 
+ivec3 tint_mod(ivec3 lhs, ivec3 rhs) {
+  return (lhs % mix(rhs, ivec3(1), bvec3(uvec3(equal(rhs, ivec3(0))) | uvec3(bvec3(uvec3(equal(lhs, ivec3(-2147483648))) & uvec3(equal(rhs, ivec3(-1))))))));
+}
+
 void f() {
   ivec3 a = ivec3(1, 2, 3);
   ivec3 b = ivec3(0, 5, 0);
-  ivec3 r = (a % b);
+  ivec3 r = tint_mod(a, b);
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-vec3/i32.wgsl.expected.msl b/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-vec3/i32.wgsl.expected.msl
index e6b07ad..847e9f6 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-vec3/i32.wgsl.expected.msl
+++ b/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-vec3/i32.wgsl.expected.msl
@@ -1,10 +1,14 @@
 #include <metal_stdlib>
 
 using namespace metal;
+int3 tint_mod(int3 lhs, int3 rhs) {
+  return (lhs % select(rhs, int3(1), ((rhs == int3(0)) | ((lhs == int3((-2147483647 - 1))) & (rhs == int3(-1))))));
+}
+
 kernel void f() {
   int3 a = int3(1, 2, 3);
   int3 b = int3(0, 5, 0);
-  int3 const r = (a % b);
+  int3 const r = tint_mod(a, b);
   return;
 }
 
diff --git a/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-vec3/i32.wgsl.expected.spvasm b/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-vec3/i32.wgsl.expected.spvasm
index fe57bb5..bb96ac7 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-vec3/i32.wgsl.expected.spvasm
+++ b/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-vec3/i32.wgsl.expected.spvasm
@@ -1,36 +1,60 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 21
+; Bound: 40
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %f "f"
                OpExecutionMode %f LocalSize 1 1 1
+               OpName %tint_mod "tint_mod"
+               OpName %lhs "lhs"
+               OpName %rhs "rhs"
                OpName %f "f"
                OpName %a "a"
                OpName %b "b"
-       %void = OpTypeVoid
-          %1 = OpTypeFunction %void
         %int = OpTypeInt 32 1
       %v3int = OpTypeVector %int 3
+          %1 = OpTypeFunction %v3int %v3int %v3int
+          %9 = OpConstantNull %v3int
+       %bool = OpTypeBool
+     %v3bool = OpTypeVector %bool 3
+%int_n2147483648 = OpConstant %int -2147483648
+         %14 = OpConstantComposite %v3int %int_n2147483648 %int_n2147483648 %int_n2147483648
+     %int_n1 = OpConstant %int -1
+         %17 = OpConstantComposite %v3int %int_n1 %int_n1 %int_n1
       %int_1 = OpConstant %int 1
+         %22 = OpConstantComposite %v3int %int_1 %int_1 %int_1
+       %void = OpTypeVoid
+         %24 = OpTypeFunction %void
       %int_2 = OpConstant %int 2
       %int_3 = OpConstant %int 3
-         %10 = OpConstantComposite %v3int %int_1 %int_2 %int_3
+         %30 = OpConstantComposite %v3int %int_1 %int_2 %int_3
 %_ptr_Function_v3int = OpTypePointer Function %v3int
-         %13 = OpConstantNull %v3int
-         %14 = OpConstantNull %int
+         %33 = OpConstantNull %int
       %int_5 = OpConstant %int 5
-         %16 = OpConstantComposite %v3int %14 %int_5 %14
-          %f = OpFunction %void None %1
-          %4 = OpLabel
-          %a = OpVariable %_ptr_Function_v3int Function %13
-          %b = OpVariable %_ptr_Function_v3int Function %13
-               OpStore %a %10
-               OpStore %b %16
-         %18 = OpLoad %v3int %a
-         %19 = OpLoad %v3int %b
-         %20 = OpSMod %v3int %18 %19
+         %35 = OpConstantComposite %v3int %33 %int_5 %33
+   %tint_mod = OpFunction %v3int None %1
+        %lhs = OpFunctionParameter %v3int
+        %rhs = OpFunctionParameter %v3int
+          %7 = OpLabel
+         %10 = OpIEqual %v3bool %rhs %9
+         %15 = OpIEqual %v3bool %lhs %14
+         %18 = OpIEqual %v3bool %rhs %17
+         %19 = OpLogicalAnd %v3bool %15 %18
+         %20 = OpLogicalOr %v3bool %10 %19
+          %8 = OpSelect %v3int %20 %22 %rhs
+         %23 = OpSMod %v3int %lhs %8
+               OpReturnValue %23
+               OpFunctionEnd
+          %f = OpFunction %void None %24
+         %27 = OpLabel
+          %a = OpVariable %_ptr_Function_v3int Function %9
+          %b = OpVariable %_ptr_Function_v3int Function %9
+               OpStore %a %30
+               OpStore %b %35
+         %38 = OpLoad %v3int %a
+         %39 = OpLoad %v3int %b
+         %37 = OpFunctionCall %v3int %tint_mod %38 %39
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-vec3/u32.wgsl.expected.dxc.hlsl b/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-vec3/u32.wgsl.expected.dxc.hlsl
index b041731..1411197 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-vec3/u32.wgsl.expected.dxc.hlsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-vec3/u32.wgsl.expected.dxc.hlsl
@@ -1,7 +1,11 @@
+uint3 tint_mod(uint3 lhs, uint3 rhs) {
+  return (lhs % ((rhs == (0u).xxx) ? (1u).xxx : rhs));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   uint3 a = uint3(1u, 2u, 3u);
   uint3 b = uint3(0u, 5u, 0u);
-  const uint3 r = (a % (b == uint3(0u, 0u, 0u) ? uint3(1u, 1u, 1u) : b));
+  const uint3 r = tint_mod(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-vec3/u32.wgsl.expected.fxc.hlsl b/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-vec3/u32.wgsl.expected.fxc.hlsl
index b041731..1411197 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-vec3/u32.wgsl.expected.fxc.hlsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-vec3/u32.wgsl.expected.fxc.hlsl
@@ -1,7 +1,11 @@
+uint3 tint_mod(uint3 lhs, uint3 rhs) {
+  return (lhs % ((rhs == (0u).xxx) ? (1u).xxx : rhs));
+}
+
 [numthreads(1, 1, 1)]
 void f() {
   uint3 a = uint3(1u, 2u, 3u);
   uint3 b = uint3(0u, 5u, 0u);
-  const uint3 r = (a % (b == uint3(0u, 0u, 0u) ? uint3(1u, 1u, 1u) : b));
+  const uint3 r = tint_mod(a, b);
   return;
 }
diff --git a/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-vec3/u32.wgsl.expected.glsl b/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-vec3/u32.wgsl.expected.glsl
index af4c44f..e6cd33b 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-vec3/u32.wgsl.expected.glsl
+++ b/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-vec3/u32.wgsl.expected.glsl
@@ -1,9 +1,13 @@
 #version 310 es
 
+uvec3 tint_mod(uvec3 lhs, uvec3 rhs) {
+  return (lhs % mix(rhs, uvec3(1u), equal(rhs, uvec3(0u))));
+}
+
 void f() {
   uvec3 a = uvec3(1u, 2u, 3u);
   uvec3 b = uvec3(0u, 5u, 0u);
-  uvec3 r = (a % b);
+  uvec3 r = tint_mod(a, b);
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-vec3/u32.wgsl.expected.msl b/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-vec3/u32.wgsl.expected.msl
index 46e36b0..db9d1c9 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-vec3/u32.wgsl.expected.msl
+++ b/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-vec3/u32.wgsl.expected.msl
@@ -1,10 +1,14 @@
 #include <metal_stdlib>
 
 using namespace metal;
+uint3 tint_mod(uint3 lhs, uint3 rhs) {
+  return (lhs % select(rhs, uint3(1u), (rhs == uint3(0u))));
+}
+
 kernel void f() {
   uint3 a = uint3(1u, 2u, 3u);
   uint3 b = uint3(0u, 5u, 0u);
-  uint3 const r = (a % b);
+  uint3 const r = tint_mod(a, b);
   return;
 }
 
diff --git a/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-vec3/u32.wgsl.expected.spvasm b/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-vec3/u32.wgsl.expected.spvasm
index 2c87495..c5096e6 100644
--- a/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-vec3/u32.wgsl.expected.spvasm
+++ b/test/tint/expressions/binary/mod_by_zero/by_identifier/vec3-vec3/u32.wgsl.expected.spvasm
@@ -1,36 +1,52 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 21
+; Bound: 32
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %f "f"
                OpExecutionMode %f LocalSize 1 1 1
+               OpName %tint_mod "tint_mod"
+               OpName %lhs "lhs"
+               OpName %rhs "rhs"
                OpName %f "f"
                OpName %a "a"
                OpName %b "b"
-       %void = OpTypeVoid
-          %1 = OpTypeFunction %void
        %uint = OpTypeInt 32 0
      %v3uint = OpTypeVector %uint 3
+          %1 = OpTypeFunction %v3uint %v3uint %v3uint
+          %9 = OpConstantNull %v3uint
+       %bool = OpTypeBool
+     %v3bool = OpTypeVector %bool 3
      %uint_1 = OpConstant %uint 1
+         %14 = OpConstantComposite %v3uint %uint_1 %uint_1 %uint_1
+       %void = OpTypeVoid
+         %16 = OpTypeFunction %void
      %uint_2 = OpConstant %uint 2
      %uint_3 = OpConstant %uint 3
-         %10 = OpConstantComposite %v3uint %uint_1 %uint_2 %uint_3
+         %22 = OpConstantComposite %v3uint %uint_1 %uint_2 %uint_3
 %_ptr_Function_v3uint = OpTypePointer Function %v3uint
-         %13 = OpConstantNull %v3uint
-         %14 = OpConstantNull %uint
+         %25 = OpConstantNull %uint
      %uint_5 = OpConstant %uint 5
-         %16 = OpConstantComposite %v3uint %14 %uint_5 %14
-          %f = OpFunction %void None %1
-          %4 = OpLabel
-          %a = OpVariable %_ptr_Function_v3uint Function %13
-          %b = OpVariable %_ptr_Function_v3uint Function %13
-               OpStore %a %10
-               OpStore %b %16
-         %18 = OpLoad %v3uint %a
-         %19 = OpLoad %v3uint %b
-         %20 = OpUMod %v3uint %18 %19
+         %27 = OpConstantComposite %v3uint %25 %uint_5 %25
+   %tint_mod = OpFunction %v3uint None %1
+        %lhs = OpFunctionParameter %v3uint
+        %rhs = OpFunctionParameter %v3uint
+          %7 = OpLabel
+         %10 = OpIEqual %v3bool %rhs %9
+          %8 = OpSelect %v3uint %10 %14 %rhs
+         %15 = OpUMod %v3uint %lhs %8
+               OpReturnValue %15
+               OpFunctionEnd
+          %f = OpFunction %void None %16
+         %19 = OpLabel
+          %a = OpVariable %_ptr_Function_v3uint Function %9
+          %b = OpVariable %_ptr_Function_v3uint Function %9
+               OpStore %a %22
+               OpStore %b %27
+         %30 = OpLoad %v3uint %a
+         %31 = OpLoad %v3uint %b
+         %29 = OpFunctionCall %v3uint %tint_mod %30 %31
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/statements/compound_assign/complex_lhs.wgsl.expected.dxc.hlsl b/test/tint/statements/compound_assign/complex_lhs.wgsl.expected.dxc.hlsl
index c9c2c3d..2edcd67 100644
--- a/test/tint/statements/compound_assign/complex_lhs.wgsl.expected.dxc.hlsl
+++ b/test/tint/statements/compound_assign/complex_lhs.wgsl.expected.dxc.hlsl
@@ -25,8 +25,11 @@
 
 void main() {
   S x = (S)0;
-  const int tint_symbol_2 = foo();
-  const int tint_symbol_save = tint_symbol_2;
+  const int tint_symbol_save = foo();
   const int tint_symbol_1 = bar();
-  set_int4(x.a[tint_symbol_save], tint_symbol_1, (x.a[tint_symbol_save][tint_symbol_1] + 5));
+  {
+    int4 tint_symbol_3[4] = x.a;
+    set_int4(tint_symbol_3[tint_symbol_save], tint_symbol_1, (x.a[tint_symbol_save][tint_symbol_1] + 5));
+    x.a = tint_symbol_3;
+  }
 }
diff --git a/test/tint/statements/compound_assign/complex_lhs.wgsl.expected.fxc.hlsl b/test/tint/statements/compound_assign/complex_lhs.wgsl.expected.fxc.hlsl
index c9c2c3d..2edcd67 100644
--- a/test/tint/statements/compound_assign/complex_lhs.wgsl.expected.fxc.hlsl
+++ b/test/tint/statements/compound_assign/complex_lhs.wgsl.expected.fxc.hlsl
@@ -25,8 +25,11 @@
 
 void main() {
   S x = (S)0;
-  const int tint_symbol_2 = foo();
-  const int tint_symbol_save = tint_symbol_2;
+  const int tint_symbol_save = foo();
   const int tint_symbol_1 = bar();
-  set_int4(x.a[tint_symbol_save], tint_symbol_1, (x.a[tint_symbol_save][tint_symbol_1] + 5));
+  {
+    int4 tint_symbol_3[4] = x.a;
+    set_int4(tint_symbol_3[tint_symbol_save], tint_symbol_1, (x.a[tint_symbol_save][tint_symbol_1] + 5));
+    x.a = tint_symbol_3;
+  }
 }
diff --git a/test/tint/statements/compound_assign/divide_by_zero.wgsl.expected.dxc.hlsl b/test/tint/statements/compound_assign/divide_by_zero.wgsl.expected.dxc.hlsl
index b90f357..35dd311 100644
--- a/test/tint/statements/compound_assign/divide_by_zero.wgsl.expected.dxc.hlsl
+++ b/test/tint/statements/compound_assign/divide_by_zero.wgsl.expected.dxc.hlsl
@@ -3,14 +3,22 @@
   return;
 }
 
+int tint_div(int lhs, int rhs) {
+  return (lhs / (((rhs == 0) | ((lhs == -2147483648) & (rhs == -1))) ? 1 : rhs));
+}
+
+int tint_mod(int lhs, int rhs) {
+  return (lhs % (((rhs == 0) | ((lhs == -2147483648) & (rhs == -1))) ? 1 : rhs));
+}
+
 static int a = 0;
 static float b = 0.0f;
 
 void foo(int maybe_zero) {
-  a = (a / 1);
-  a = (a % 1);
-  a = (a / (maybe_zero == 0 ? 1 : maybe_zero));
-  a = (a % (maybe_zero == 0 ? 1 : maybe_zero));
+  a = tint_div(a, 0);
+  a = tint_mod(a, 0);
+  a = tint_div(a, maybe_zero);
+  a = tint_mod(a, maybe_zero);
   b = (b / 0.0f);
   b = (b % 0.0f);
   b = (b / float(maybe_zero));
diff --git a/test/tint/statements/compound_assign/divide_by_zero.wgsl.expected.fxc.hlsl b/test/tint/statements/compound_assign/divide_by_zero.wgsl.expected.fxc.hlsl
index b90f357..35dd311 100644
--- a/test/tint/statements/compound_assign/divide_by_zero.wgsl.expected.fxc.hlsl
+++ b/test/tint/statements/compound_assign/divide_by_zero.wgsl.expected.fxc.hlsl
@@ -3,14 +3,22 @@
   return;
 }
 
+int tint_div(int lhs, int rhs) {
+  return (lhs / (((rhs == 0) | ((lhs == -2147483648) & (rhs == -1))) ? 1 : rhs));
+}
+
+int tint_mod(int lhs, int rhs) {
+  return (lhs % (((rhs == 0) | ((lhs == -2147483648) & (rhs == -1))) ? 1 : rhs));
+}
+
 static int a = 0;
 static float b = 0.0f;
 
 void foo(int maybe_zero) {
-  a = (a / 1);
-  a = (a % 1);
-  a = (a / (maybe_zero == 0 ? 1 : maybe_zero));
-  a = (a % (maybe_zero == 0 ? 1 : maybe_zero));
+  a = tint_div(a, 0);
+  a = tint_mod(a, 0);
+  a = tint_div(a, maybe_zero);
+  a = tint_mod(a, maybe_zero);
   b = (b / 0.0f);
   b = (b % 0.0f);
   b = (b / float(maybe_zero));
diff --git a/test/tint/statements/compound_assign/divide_by_zero.wgsl.expected.glsl b/test/tint/statements/compound_assign/divide_by_zero.wgsl.expected.glsl
index 5a32830..3af799e 100644
--- a/test/tint/statements/compound_assign/divide_by_zero.wgsl.expected.glsl
+++ b/test/tint/statements/compound_assign/divide_by_zero.wgsl.expected.glsl
@@ -9,13 +9,21 @@
 void unused_entry_point() {
   return;
 }
+int tint_div(int lhs, int rhs) {
+  return (lhs / (bool(uint((rhs == 0)) | uint(bool(uint((lhs == -2147483648)) & uint((rhs == -1))))) ? 1 : rhs));
+}
+
+int tint_mod(int lhs, int rhs) {
+  return (lhs % (bool(uint((rhs == 0)) | uint(bool(uint((lhs == -2147483648)) & uint((rhs == -1))))) ? 1 : rhs));
+}
+
 int a = 0;
 float b = 0.0f;
 void foo(int maybe_zero) {
-  a = (a / 0);
-  a = (a % 0);
-  a = (a / maybe_zero);
-  a = (a % maybe_zero);
+  a = tint_div(a, 0);
+  a = tint_mod(a, 0);
+  a = tint_div(a, maybe_zero);
+  a = tint_mod(a, maybe_zero);
   b = (b / 0.0f);
   b = tint_float_modulo(b, 0.0f);
   b = (b / float(maybe_zero));
diff --git a/test/tint/statements/compound_assign/divide_by_zero.wgsl.expected.msl b/test/tint/statements/compound_assign/divide_by_zero.wgsl.expected.msl
index aa0605f..0a90401 100644
--- a/test/tint/statements/compound_assign/divide_by_zero.wgsl.expected.msl
+++ b/test/tint/statements/compound_assign/divide_by_zero.wgsl.expected.msl
@@ -1,13 +1,21 @@
 #include <metal_stdlib>
 
 using namespace metal;
+int tint_div(int lhs, int rhs) {
+  return (lhs / select(rhs, 1, bool((rhs == 0) | bool((lhs == (-2147483647 - 1)) & (rhs == -1)))));
+}
+
+int tint_mod(int lhs, int rhs) {
+  return (lhs % select(rhs, 1, bool((rhs == 0) | bool((lhs == (-2147483647 - 1)) & (rhs == -1)))));
+}
+
 void foo(int maybe_zero) {
   thread int tint_symbol = 0;
   thread float tint_symbol_1 = 0.0f;
-  tint_symbol = (tint_symbol / 0);
-  tint_symbol = (tint_symbol % 0);
-  tint_symbol = (tint_symbol / maybe_zero);
-  tint_symbol = (tint_symbol % maybe_zero);
+  tint_symbol = tint_div(tint_symbol, 0);
+  tint_symbol = tint_mod(tint_symbol, 0);
+  tint_symbol = tint_div(tint_symbol, maybe_zero);
+  tint_symbol = tint_mod(tint_symbol, maybe_zero);
   tint_symbol_1 = (tint_symbol_1 / 0.0f);
   tint_symbol_1 = fmod(tint_symbol_1, 0.0f);
   tint_symbol_1 = (tint_symbol_1 / float(maybe_zero));
diff --git a/test/tint/statements/compound_assign/divide_by_zero.wgsl.expected.spvasm b/test/tint/statements/compound_assign/divide_by_zero.wgsl.expected.spvasm
index c5bc009..af5ae1f 100644
--- a/test/tint/statements/compound_assign/divide_by_zero.wgsl.expected.spvasm
+++ b/test/tint/statements/compound_assign/divide_by_zero.wgsl.expected.spvasm
@@ -1,7 +1,7 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 35
+; Bound: 62
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
@@ -10,6 +10,12 @@
                OpName %a "a"
                OpName %b "b"
                OpName %unused_entry_point "unused_entry_point"
+               OpName %tint_div "tint_div"
+               OpName %lhs "lhs"
+               OpName %rhs "rhs"
+               OpName %tint_mod "tint_mod"
+               OpName %lhs_0 "lhs"
+               OpName %rhs_0 "rhs"
                OpName %foo "foo"
                OpName %maybe_zero "maybe_zero"
         %int = OpTypeInt 32 1
@@ -22,39 +28,70 @@
           %b = OpVariable %_ptr_Private_float Private %8
        %void = OpTypeVoid
           %9 = OpTypeFunction %void
-         %13 = OpTypeFunction %void %int
+         %13 = OpTypeFunction %int %int %int
+       %bool = OpTypeBool
+%int_n2147483648 = OpConstant %int -2147483648
+     %int_n1 = OpConstant %int -1
+      %int_1 = OpConstant %int 1
+         %40 = OpTypeFunction %void %int
 %unused_entry_point = OpFunction %void None %9
          %12 = OpLabel
                OpReturn
                OpFunctionEnd
-        %foo = OpFunction %void None %13
+   %tint_div = OpFunction %int None %13
+        %lhs = OpFunctionParameter %int
+        %rhs = OpFunctionParameter %int
+         %17 = OpLabel
+         %19 = OpIEqual %bool %rhs %4
+         %22 = OpIEqual %bool %lhs %int_n2147483648
+         %24 = OpIEqual %bool %rhs %int_n1
+         %25 = OpLogicalAnd %bool %22 %24
+         %26 = OpLogicalOr %bool %19 %25
+         %18 = OpSelect %int %26 %int_1 %rhs
+         %28 = OpSDiv %int %lhs %18
+               OpReturnValue %28
+               OpFunctionEnd
+   %tint_mod = OpFunction %int None %13
+      %lhs_0 = OpFunctionParameter %int
+      %rhs_0 = OpFunctionParameter %int
+         %32 = OpLabel
+         %34 = OpIEqual %bool %rhs_0 %4
+         %35 = OpIEqual %bool %lhs_0 %int_n2147483648
+         %36 = OpIEqual %bool %rhs_0 %int_n1
+         %37 = OpLogicalAnd %bool %35 %36
+         %38 = OpLogicalOr %bool %34 %37
+         %33 = OpSelect %int %38 %int_1 %rhs_0
+         %39 = OpSMod %int %lhs_0 %33
+               OpReturnValue %39
+               OpFunctionEnd
+        %foo = OpFunction %void None %40
  %maybe_zero = OpFunctionParameter %int
-         %16 = OpLabel
-         %17 = OpLoad %int %a
-         %18 = OpSDiv %int %17 %4
-               OpStore %a %18
-         %19 = OpLoad %int %a
-         %20 = OpSMod %int %19 %4
-               OpStore %a %20
-         %21 = OpLoad %int %a
-         %22 = OpSDiv %int %21 %maybe_zero
-               OpStore %a %22
-         %23 = OpLoad %int %a
-         %24 = OpSMod %int %23 %maybe_zero
-               OpStore %a %24
-         %25 = OpLoad %float %b
-         %26 = OpFDiv %float %25 %8
-               OpStore %b %26
-         %27 = OpLoad %float %b
-         %28 = OpFRem %float %27 %8
-               OpStore %b %28
-         %29 = OpLoad %float %b
-         %30 = OpConvertSToF %float %maybe_zero
-         %31 = OpFDiv %float %29 %30
-               OpStore %b %31
-         %32 = OpLoad %float %b
-         %33 = OpConvertSToF %float %maybe_zero
-         %34 = OpFRem %float %32 %33
-               OpStore %b %34
+         %43 = OpLabel
+         %45 = OpLoad %int %a
+         %44 = OpFunctionCall %int %tint_div %45 %4
+               OpStore %a %44
+         %47 = OpLoad %int %a
+         %46 = OpFunctionCall %int %tint_mod %47 %4
+               OpStore %a %46
+         %49 = OpLoad %int %a
+         %48 = OpFunctionCall %int %tint_div %49 %maybe_zero
+               OpStore %a %48
+         %51 = OpLoad %int %a
+         %50 = OpFunctionCall %int %tint_mod %51 %maybe_zero
+               OpStore %a %50
+         %52 = OpLoad %float %b
+         %53 = OpFDiv %float %52 %8
+               OpStore %b %53
+         %54 = OpLoad %float %b
+         %55 = OpFRem %float %54 %8
+               OpStore %b %55
+         %56 = OpLoad %float %b
+         %57 = OpConvertSToF %float %maybe_zero
+         %58 = OpFDiv %float %56 %57
+               OpStore %b %58
+         %59 = OpLoad %float %b
+         %60 = OpConvertSToF %float %maybe_zero
+         %61 = OpFRem %float %59 %60
+               OpStore %b %61
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/statements/compound_assign/for_loop.wgsl.expected.dxc.hlsl b/test/tint/statements/compound_assign/for_loop.wgsl.expected.dxc.hlsl
index 828cc6e..3c72263 100644
--- a/test/tint/statements/compound_assign/for_loop.wgsl.expected.dxc.hlsl
+++ b/test/tint/statements/compound_assign/for_loop.wgsl.expected.dxc.hlsl
@@ -23,20 +23,18 @@
 
 void foo() {
   float a[4] = (float[4])0;
-  const int tint_symbol_2 = idx1();
-  const int tint_symbol_save = tint_symbol_2;
+  const int tint_symbol_save = idx1();
   {
     a[tint_symbol_save] = (a[tint_symbol_save] * 2.0f);
     while (true) {
-      const int tint_symbol_3 = idx2();
-      if (!((a[tint_symbol_3] < 10.0f))) {
+      const int tint_symbol_2 = idx2();
+      if (!((a[tint_symbol_2] < 10.0f))) {
         break;
       }
       {
       }
       {
-        const int tint_symbol_4 = idx3();
-        const int tint_symbol_1_save = tint_symbol_4;
+        const int tint_symbol_1_save = idx3();
         a[tint_symbol_1_save] = (a[tint_symbol_1_save] + 1.0f);
       }
     }
diff --git a/test/tint/statements/compound_assign/for_loop.wgsl.expected.fxc.hlsl b/test/tint/statements/compound_assign/for_loop.wgsl.expected.fxc.hlsl
index 828cc6e..3c72263 100644
--- a/test/tint/statements/compound_assign/for_loop.wgsl.expected.fxc.hlsl
+++ b/test/tint/statements/compound_assign/for_loop.wgsl.expected.fxc.hlsl
@@ -23,20 +23,18 @@
 
 void foo() {
   float a[4] = (float[4])0;
-  const int tint_symbol_2 = idx1();
-  const int tint_symbol_save = tint_symbol_2;
+  const int tint_symbol_save = idx1();
   {
     a[tint_symbol_save] = (a[tint_symbol_save] * 2.0f);
     while (true) {
-      const int tint_symbol_3 = idx2();
-      if (!((a[tint_symbol_3] < 10.0f))) {
+      const int tint_symbol_2 = idx2();
+      if (!((a[tint_symbol_2] < 10.0f))) {
         break;
       }
       {
       }
       {
-        const int tint_symbol_4 = idx3();
-        const int tint_symbol_1_save = tint_symbol_4;
+        const int tint_symbol_1_save = idx3();
         a[tint_symbol_1_save] = (a[tint_symbol_1_save] + 1.0f);
       }
     }
diff --git a/test/tint/statements/compound_assign/function.wgsl.expected.dxc.hlsl b/test/tint/statements/compound_assign/function.wgsl.expected.dxc.hlsl
index bfdebdb..04f0a97 100644
--- a/test/tint/statements/compound_assign/function.wgsl.expected.dxc.hlsl
+++ b/test/tint/statements/compound_assign/function.wgsl.expected.dxc.hlsl
@@ -3,11 +3,15 @@
   return;
 }
 
+int tint_div(int lhs, int rhs) {
+  return (lhs / (((rhs == 0) | ((lhs == -2147483648) & (rhs == -1))) ? 1 : rhs));
+}
+
 void foo() {
   int a = 0;
   float4 b = float4(0.0f, 0.0f, 0.0f, 0.0f);
   float2x2 c = float2x2(0.0f, 0.0f, 0.0f, 0.0f);
-  a = (a / 2);
+  a = tint_div(a, 2);
   b = mul(float4x4((0.0f).xxxx, (0.0f).xxxx, (0.0f).xxxx, (0.0f).xxxx), b);
   c = (c * 2.0f);
 }
diff --git a/test/tint/statements/compound_assign/function.wgsl.expected.fxc.hlsl b/test/tint/statements/compound_assign/function.wgsl.expected.fxc.hlsl
index bfdebdb..04f0a97 100644
--- a/test/tint/statements/compound_assign/function.wgsl.expected.fxc.hlsl
+++ b/test/tint/statements/compound_assign/function.wgsl.expected.fxc.hlsl
@@ -3,11 +3,15 @@
   return;
 }
 
+int tint_div(int lhs, int rhs) {
+  return (lhs / (((rhs == 0) | ((lhs == -2147483648) & (rhs == -1))) ? 1 : rhs));
+}
+
 void foo() {
   int a = 0;
   float4 b = float4(0.0f, 0.0f, 0.0f, 0.0f);
   float2x2 c = float2x2(0.0f, 0.0f, 0.0f, 0.0f);
-  a = (a / 2);
+  a = tint_div(a, 2);
   b = mul(float4x4((0.0f).xxxx, (0.0f).xxxx, (0.0f).xxxx, (0.0f).xxxx), b);
   c = (c * 2.0f);
 }
diff --git a/test/tint/statements/compound_assign/function.wgsl.expected.glsl b/test/tint/statements/compound_assign/function.wgsl.expected.glsl
index 7b4c01c..5c71b85 100644
--- a/test/tint/statements/compound_assign/function.wgsl.expected.glsl
+++ b/test/tint/statements/compound_assign/function.wgsl.expected.glsl
@@ -4,11 +4,15 @@
 void unused_entry_point() {
   return;
 }
+int tint_div(int lhs, int rhs) {
+  return (lhs / (bool(uint((rhs == 0)) | uint(bool(uint((lhs == -2147483648)) & uint((rhs == -1))))) ? 1 : rhs));
+}
+
 void foo() {
   int a = 0;
   vec4 b = vec4(0.0f, 0.0f, 0.0f, 0.0f);
   mat2 c = mat2(0.0f, 0.0f, 0.0f, 0.0f);
-  a = (a / 2);
+  a = tint_div(a, 2);
   b = (b * mat4(vec4(0.0f), vec4(0.0f), vec4(0.0f), vec4(0.0f)));
   c = (c * 2.0f);
 }
diff --git a/test/tint/statements/compound_assign/function.wgsl.expected.msl b/test/tint/statements/compound_assign/function.wgsl.expected.msl
index 3acbce9..bbe0262 100644
--- a/test/tint/statements/compound_assign/function.wgsl.expected.msl
+++ b/test/tint/statements/compound_assign/function.wgsl.expected.msl
@@ -1,11 +1,15 @@
 #include <metal_stdlib>
 
 using namespace metal;
+int tint_div(int lhs, int rhs) {
+  return (lhs / select(rhs, 1, bool((rhs == 0) | bool((lhs == (-2147483647 - 1)) & (rhs == -1)))));
+}
+
 void foo() {
   int a = 0;
   float4 b = 0.0f;
   float2x2 c = float2x2(0.0f);
-  a = (a / 2);
+  a = tint_div(a, 2);
   b = (b * float4x4(float4(0.0f), float4(0.0f), float4(0.0f), float4(0.0f)));
   c = (c * 2.0f);
 }
diff --git a/test/tint/statements/compound_assign/function.wgsl.expected.spvasm b/test/tint/statements/compound_assign/function.wgsl.expected.spvasm
index eee2383..d01700d 100644
--- a/test/tint/statements/compound_assign/function.wgsl.expected.spvasm
+++ b/test/tint/statements/compound_assign/function.wgsl.expected.spvasm
@@ -1,13 +1,16 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 31
+; Bound: 47
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %unused_entry_point "unused_entry_point"
                OpExecutionMode %unused_entry_point LocalSize 1 1 1
                OpName %unused_entry_point "unused_entry_point"
+               OpName %tint_div "tint_div"
+               OpName %lhs "lhs"
+               OpName %rhs "rhs"
                OpName %foo "foo"
                OpName %a "a"
                OpName %b "b"
@@ -15,37 +18,55 @@
        %void = OpTypeVoid
           %1 = OpTypeFunction %void
         %int = OpTypeInt 32 1
+          %5 = OpTypeFunction %int %int %int
+         %12 = OpConstantNull %int
+       %bool = OpTypeBool
+%int_n2147483648 = OpConstant %int -2147483648
+     %int_n1 = OpConstant %int -1
+      %int_1 = OpConstant %int 1
 %_ptr_Function_int = OpTypePointer Function %int
-         %10 = OpConstantNull %int
       %float = OpTypeFloat 32
     %v4float = OpTypeVector %float 4
 %_ptr_Function_v4float = OpTypePointer Function %v4float
-         %15 = OpConstantNull %v4float
+         %31 = OpConstantNull %v4float
     %v2float = OpTypeVector %float 2
 %mat2v2float = OpTypeMatrix %v2float 2
 %_ptr_Function_mat2v2float = OpTypePointer Function %mat2v2float
-         %20 = OpConstantNull %mat2v2float
+         %36 = OpConstantNull %mat2v2float
       %int_2 = OpConstant %int 2
 %mat4v4float = OpTypeMatrix %v4float 4
-         %26 = OpConstantNull %mat4v4float
+         %42 = OpConstantNull %mat4v4float
     %float_2 = OpConstant %float 2
 %unused_entry_point = OpFunction %void None %1
           %4 = OpLabel
                OpReturn
                OpFunctionEnd
+   %tint_div = OpFunction %int None %5
+        %lhs = OpFunctionParameter %int
+        %rhs = OpFunctionParameter %int
+         %10 = OpLabel
+         %13 = OpIEqual %bool %rhs %12
+         %16 = OpIEqual %bool %lhs %int_n2147483648
+         %18 = OpIEqual %bool %rhs %int_n1
+         %19 = OpLogicalAnd %bool %16 %18
+         %20 = OpLogicalOr %bool %13 %19
+         %11 = OpSelect %int %20 %int_1 %rhs
+         %22 = OpSDiv %int %lhs %11
+               OpReturnValue %22
+               OpFunctionEnd
         %foo = OpFunction %void None %1
-          %6 = OpLabel
-          %a = OpVariable %_ptr_Function_int Function %10
-          %b = OpVariable %_ptr_Function_v4float Function %15
-          %c = OpVariable %_ptr_Function_mat2v2float Function %20
-         %21 = OpLoad %int %a
-         %23 = OpSDiv %int %21 %int_2
-               OpStore %a %23
-         %24 = OpLoad %v4float %b
-         %27 = OpVectorTimesMatrix %v4float %24 %26
-               OpStore %b %27
-         %28 = OpLoad %mat2v2float %c
-         %30 = OpMatrixTimesScalar %mat2v2float %28 %float_2
-               OpStore %c %30
+         %24 = OpLabel
+          %a = OpVariable %_ptr_Function_int Function %12
+          %b = OpVariable %_ptr_Function_v4float Function %31
+          %c = OpVariable %_ptr_Function_mat2v2float Function %36
+         %38 = OpLoad %int %a
+         %37 = OpFunctionCall %int %tint_div %38 %int_2
+               OpStore %a %37
+         %40 = OpLoad %v4float %b
+         %43 = OpVectorTimesMatrix %v4float %40 %42
+               OpStore %b %43
+         %44 = OpLoad %mat2v2float %c
+         %46 = OpMatrixTimesScalar %mat2v2float %44 %float_2
+               OpStore %c %46
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/statements/compound_assign/private.wgsl.expected.dxc.hlsl b/test/tint/statements/compound_assign/private.wgsl.expected.dxc.hlsl
index f01cc42..2de2195 100644
--- a/test/tint/statements/compound_assign/private.wgsl.expected.dxc.hlsl
+++ b/test/tint/statements/compound_assign/private.wgsl.expected.dxc.hlsl
@@ -3,12 +3,16 @@
   return;
 }
 
+int tint_div(int lhs, int rhs) {
+  return (lhs / (((rhs == 0) | ((lhs == -2147483648) & (rhs == -1))) ? 1 : rhs));
+}
+
 static int a = 0;
 static float4 b = float4(0.0f, 0.0f, 0.0f, 0.0f);
 static float2x2 c = float2x2(0.0f, 0.0f, 0.0f, 0.0f);
 
 void foo() {
-  a = (a / 2);
+  a = tint_div(a, 2);
   b = mul(float4x4((0.0f).xxxx, (0.0f).xxxx, (0.0f).xxxx, (0.0f).xxxx), b);
   c = (c * 2.0f);
 }
diff --git a/test/tint/statements/compound_assign/private.wgsl.expected.fxc.hlsl b/test/tint/statements/compound_assign/private.wgsl.expected.fxc.hlsl
index f01cc42..2de2195 100644
--- a/test/tint/statements/compound_assign/private.wgsl.expected.fxc.hlsl
+++ b/test/tint/statements/compound_assign/private.wgsl.expected.fxc.hlsl
@@ -3,12 +3,16 @@
   return;
 }
 
+int tint_div(int lhs, int rhs) {
+  return (lhs / (((rhs == 0) | ((lhs == -2147483648) & (rhs == -1))) ? 1 : rhs));
+}
+
 static int a = 0;
 static float4 b = float4(0.0f, 0.0f, 0.0f, 0.0f);
 static float2x2 c = float2x2(0.0f, 0.0f, 0.0f, 0.0f);
 
 void foo() {
-  a = (a / 2);
+  a = tint_div(a, 2);
   b = mul(float4x4((0.0f).xxxx, (0.0f).xxxx, (0.0f).xxxx, (0.0f).xxxx), b);
   c = (c * 2.0f);
 }
diff --git a/test/tint/statements/compound_assign/private.wgsl.expected.glsl b/test/tint/statements/compound_assign/private.wgsl.expected.glsl
index 33efe42..4efe337 100644
--- a/test/tint/statements/compound_assign/private.wgsl.expected.glsl
+++ b/test/tint/statements/compound_assign/private.wgsl.expected.glsl
@@ -4,11 +4,15 @@
 void unused_entry_point() {
   return;
 }
+int tint_div(int lhs, int rhs) {
+  return (lhs / (bool(uint((rhs == 0)) | uint(bool(uint((lhs == -2147483648)) & uint((rhs == -1))))) ? 1 : rhs));
+}
+
 int a = 0;
 vec4 b = vec4(0.0f, 0.0f, 0.0f, 0.0f);
 mat2 c = mat2(0.0f, 0.0f, 0.0f, 0.0f);
 void foo() {
-  a = (a / 2);
+  a = tint_div(a, 2);
   b = (b * mat4(vec4(0.0f), vec4(0.0f), vec4(0.0f), vec4(0.0f)));
   c = (c * 2.0f);
 }
diff --git a/test/tint/statements/compound_assign/private.wgsl.expected.msl b/test/tint/statements/compound_assign/private.wgsl.expected.msl
index 327107f..f573620 100644
--- a/test/tint/statements/compound_assign/private.wgsl.expected.msl
+++ b/test/tint/statements/compound_assign/private.wgsl.expected.msl
@@ -1,11 +1,15 @@
 #include <metal_stdlib>
 
 using namespace metal;
+int tint_div(int lhs, int rhs) {
+  return (lhs / select(rhs, 1, bool((rhs == 0) | bool((lhs == (-2147483647 - 1)) & (rhs == -1)))));
+}
+
 void foo() {
   thread int tint_symbol = 0;
   thread float4 tint_symbol_1 = 0.0f;
   thread float2x2 tint_symbol_2 = float2x2(0.0f);
-  tint_symbol = (tint_symbol / 2);
+  tint_symbol = tint_div(tint_symbol, 2);
   tint_symbol_1 = (tint_symbol_1 * float4x4(float4(0.0f), float4(0.0f), float4(0.0f), float4(0.0f)));
   tint_symbol_2 = (tint_symbol_2 * 2.0f);
 }
diff --git a/test/tint/statements/compound_assign/private.wgsl.expected.spvasm b/test/tint/statements/compound_assign/private.wgsl.expected.spvasm
index 473958d..7294863 100644
--- a/test/tint/statements/compound_assign/private.wgsl.expected.spvasm
+++ b/test/tint/statements/compound_assign/private.wgsl.expected.spvasm
@@ -1,7 +1,7 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 31
+; Bound: 47
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
@@ -11,6 +11,9 @@
                OpName %b "b"
                OpName %c "c"
                OpName %unused_entry_point "unused_entry_point"
+               OpName %tint_div "tint_div"
+               OpName %lhs "lhs"
+               OpName %rhs "rhs"
                OpName %foo "foo"
         %int = OpTypeInt 32 1
 %_ptr_Private_int = OpTypePointer Private %int
@@ -28,24 +31,42 @@
           %c = OpVariable %_ptr_Private_mat2v2float Private %14
        %void = OpTypeVoid
          %15 = OpTypeFunction %void
+         %19 = OpTypeFunction %int %int %int
+       %bool = OpTypeBool
+%int_n2147483648 = OpConstant %int -2147483648
+     %int_n1 = OpConstant %int -1
+      %int_1 = OpConstant %int 1
       %int_2 = OpConstant %int 2
 %mat4v4float = OpTypeMatrix %v4float 4
-         %26 = OpConstantNull %mat4v4float
+         %42 = OpConstantNull %mat4v4float
     %float_2 = OpConstant %float 2
 %unused_entry_point = OpFunction %void None %15
          %18 = OpLabel
                OpReturn
                OpFunctionEnd
+   %tint_div = OpFunction %int None %19
+        %lhs = OpFunctionParameter %int
+        %rhs = OpFunctionParameter %int
+         %23 = OpLabel
+         %25 = OpIEqual %bool %rhs %4
+         %28 = OpIEqual %bool %lhs %int_n2147483648
+         %30 = OpIEqual %bool %rhs %int_n1
+         %31 = OpLogicalAnd %bool %28 %30
+         %32 = OpLogicalOr %bool %25 %31
+         %24 = OpSelect %int %32 %int_1 %rhs
+         %34 = OpSDiv %int %lhs %24
+               OpReturnValue %34
+               OpFunctionEnd
         %foo = OpFunction %void None %15
-         %20 = OpLabel
-         %21 = OpLoad %int %a
-         %23 = OpSDiv %int %21 %int_2
-               OpStore %a %23
-         %24 = OpLoad %v4float %b
-         %27 = OpVectorTimesMatrix %v4float %24 %26
-               OpStore %b %27
-         %28 = OpLoad %mat2v2float %c
-         %30 = OpMatrixTimesScalar %mat2v2float %28 %float_2
-               OpStore %c %30
+         %36 = OpLabel
+         %38 = OpLoad %int %a
+         %37 = OpFunctionCall %int %tint_div %38 %int_2
+               OpStore %a %37
+         %40 = OpLoad %v4float %b
+         %43 = OpVectorTimesMatrix %v4float %40 %42
+               OpStore %b %43
+         %44 = OpLoad %mat2v2float %c
+         %46 = OpMatrixTimesScalar %mat2v2float %44 %float_2
+               OpStore %c %46
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/statements/compound_assign/scalar/divide.wgsl.expected.dxc.hlsl b/test/tint/statements/compound_assign/scalar/divide.wgsl.expected.dxc.hlsl
index affbb2b..e84dd9a 100644
--- a/test/tint/statements/compound_assign/scalar/divide.wgsl.expected.dxc.hlsl
+++ b/test/tint/statements/compound_assign/scalar/divide.wgsl.expected.dxc.hlsl
@@ -3,8 +3,13 @@
   return;
 }
 
+int tint_div(int lhs, int rhs) {
+  return (lhs / (((rhs == 0) | ((lhs == -2147483648) & (rhs == -1))) ? 1 : rhs));
+}
+
 RWByteAddressBuffer v : register(u0, space0);
 
 void foo() {
-  v.Store(0u, asuint((asint(v.Load(0u)) / 2)));
+  const int tint_symbol = tint_div(asint(v.Load(0u)), 2);
+  v.Store(0u, asuint(tint_symbol));
 }
diff --git a/test/tint/statements/compound_assign/scalar/divide.wgsl.expected.fxc.hlsl b/test/tint/statements/compound_assign/scalar/divide.wgsl.expected.fxc.hlsl
index affbb2b..e84dd9a 100644
--- a/test/tint/statements/compound_assign/scalar/divide.wgsl.expected.fxc.hlsl
+++ b/test/tint/statements/compound_assign/scalar/divide.wgsl.expected.fxc.hlsl
@@ -3,8 +3,13 @@
   return;
 }
 
+int tint_div(int lhs, int rhs) {
+  return (lhs / (((rhs == 0) | ((lhs == -2147483648) & (rhs == -1))) ? 1 : rhs));
+}
+
 RWByteAddressBuffer v : register(u0, space0);
 
 void foo() {
-  v.Store(0u, asuint((asint(v.Load(0u)) / 2)));
+  const int tint_symbol = tint_div(asint(v.Load(0u)), 2);
+  v.Store(0u, asuint(tint_symbol));
 }
diff --git a/test/tint/statements/compound_assign/scalar/divide.wgsl.expected.glsl b/test/tint/statements/compound_assign/scalar/divide.wgsl.expected.glsl
index 369c989..43823fc 100644
--- a/test/tint/statements/compound_assign/scalar/divide.wgsl.expected.glsl
+++ b/test/tint/statements/compound_assign/scalar/divide.wgsl.expected.glsl
@@ -4,6 +4,10 @@
 void unused_entry_point() {
   return;
 }
+int tint_div(int lhs, int rhs) {
+  return (lhs / (bool(uint((rhs == 0)) | uint(bool(uint((lhs == -2147483648)) & uint((rhs == -1))))) ? 1 : rhs));
+}
+
 struct S {
   int a;
 };
@@ -13,6 +17,7 @@
 } v;
 
 void foo() {
-  v.inner.a = (v.inner.a / 2);
+  int tint_symbol = tint_div(v.inner.a, 2);
+  v.inner.a = tint_symbol;
 }
 
diff --git a/test/tint/statements/compound_assign/scalar/divide.wgsl.expected.msl b/test/tint/statements/compound_assign/scalar/divide.wgsl.expected.msl
index 9c19724..855cb61 100644
--- a/test/tint/statements/compound_assign/scalar/divide.wgsl.expected.msl
+++ b/test/tint/statements/compound_assign/scalar/divide.wgsl.expected.msl
@@ -1,11 +1,16 @@
 #include <metal_stdlib>
 
 using namespace metal;
+int tint_div(int lhs, int rhs) {
+  return (lhs / select(rhs, 1, bool((rhs == 0) | bool((lhs == (-2147483647 - 1)) & (rhs == -1)))));
+}
+
 struct S {
   /* 0x0000 */ int a;
 };
 
-void foo(device S* const tint_symbol) {
-  (*(tint_symbol)).a = ((*(tint_symbol)).a / 2);
+void foo(device S* const tint_symbol_1) {
+  int const tint_symbol = tint_div((*(tint_symbol_1)).a, 2);
+  (*(tint_symbol_1)).a = tint_symbol;
 }
 
diff --git a/test/tint/statements/compound_assign/scalar/divide.wgsl.expected.spvasm b/test/tint/statements/compound_assign/scalar/divide.wgsl.expected.spvasm
index e4078d1..e1c28b2 100644
--- a/test/tint/statements/compound_assign/scalar/divide.wgsl.expected.spvasm
+++ b/test/tint/statements/compound_assign/scalar/divide.wgsl.expected.spvasm
@@ -1,7 +1,7 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 20
+; Bound: 37
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
@@ -13,6 +13,9 @@
                OpMemberName %S 0 "a"
                OpName %v "v"
                OpName %unused_entry_point "unused_entry_point"
+               OpName %tint_div "tint_div"
+               OpName %lhs "lhs"
+               OpName %rhs "rhs"
                OpName %foo "foo"
                OpDecorate %v_block Block
                OpMemberDecorate %v_block 0 Offset 0
@@ -26,6 +29,12 @@
           %v = OpVariable %_ptr_StorageBuffer_v_block StorageBuffer
        %void = OpTypeVoid
           %6 = OpTypeFunction %void
+         %10 = OpTypeFunction %int %int %int
+         %16 = OpConstantNull %int
+       %bool = OpTypeBool
+%int_n2147483648 = OpConstant %int -2147483648
+     %int_n1 = OpConstant %int -1
+      %int_1 = OpConstant %int 1
        %uint = OpTypeInt 32 0
      %uint_0 = OpConstant %uint 0
 %_ptr_StorageBuffer_int = OpTypePointer StorageBuffer %int
@@ -34,12 +43,25 @@
           %9 = OpLabel
                OpReturn
                OpFunctionEnd
+   %tint_div = OpFunction %int None %10
+        %lhs = OpFunctionParameter %int
+        %rhs = OpFunctionParameter %int
+         %14 = OpLabel
+         %17 = OpIEqual %bool %rhs %16
+         %20 = OpIEqual %bool %lhs %int_n2147483648
+         %22 = OpIEqual %bool %rhs %int_n1
+         %23 = OpLogicalAnd %bool %20 %22
+         %24 = OpLogicalOr %bool %17 %23
+         %15 = OpSelect %int %24 %int_1 %rhs
+         %26 = OpSDiv %int %lhs %15
+               OpReturnValue %26
+               OpFunctionEnd
         %foo = OpFunction %void None %6
-         %11 = OpLabel
-         %15 = OpAccessChain %_ptr_StorageBuffer_int %v %uint_0 %uint_0
-         %16 = OpAccessChain %_ptr_StorageBuffer_int %v %uint_0 %uint_0
-         %17 = OpLoad %int %16
-         %19 = OpSDiv %int %17 %int_2
-               OpStore %15 %19
+         %28 = OpLabel
+         %33 = OpAccessChain %_ptr_StorageBuffer_int %v %uint_0 %uint_0
+         %34 = OpLoad %int %33
+         %29 = OpFunctionCall %int %tint_div %34 %int_2
+         %36 = OpAccessChain %_ptr_StorageBuffer_int %v %uint_0 %uint_0
+               OpStore %36 %29
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/statements/compound_assign/scalar/modulo.wgsl.expected.dxc.hlsl b/test/tint/statements/compound_assign/scalar/modulo.wgsl.expected.dxc.hlsl
index fec5816..92912b2 100644
--- a/test/tint/statements/compound_assign/scalar/modulo.wgsl.expected.dxc.hlsl
+++ b/test/tint/statements/compound_assign/scalar/modulo.wgsl.expected.dxc.hlsl
@@ -3,8 +3,13 @@
   return;
 }
 
+int tint_mod(int lhs, int rhs) {
+  return (lhs % (((rhs == 0) | ((lhs == -2147483648) & (rhs == -1))) ? 1 : rhs));
+}
+
 RWByteAddressBuffer v : register(u0, space0);
 
 void foo() {
-  v.Store(0u, asuint((asint(v.Load(0u)) % 2)));
+  const int tint_symbol = tint_mod(asint(v.Load(0u)), 2);
+  v.Store(0u, asuint(tint_symbol));
 }
diff --git a/test/tint/statements/compound_assign/scalar/modulo.wgsl.expected.fxc.hlsl b/test/tint/statements/compound_assign/scalar/modulo.wgsl.expected.fxc.hlsl
index fec5816..92912b2 100644
--- a/test/tint/statements/compound_assign/scalar/modulo.wgsl.expected.fxc.hlsl
+++ b/test/tint/statements/compound_assign/scalar/modulo.wgsl.expected.fxc.hlsl
@@ -3,8 +3,13 @@
   return;
 }
 
+int tint_mod(int lhs, int rhs) {
+  return (lhs % (((rhs == 0) | ((lhs == -2147483648) & (rhs == -1))) ? 1 : rhs));
+}
+
 RWByteAddressBuffer v : register(u0, space0);
 
 void foo() {
-  v.Store(0u, asuint((asint(v.Load(0u)) % 2)));
+  const int tint_symbol = tint_mod(asint(v.Load(0u)), 2);
+  v.Store(0u, asuint(tint_symbol));
 }
diff --git a/test/tint/statements/compound_assign/scalar/modulo.wgsl.expected.glsl b/test/tint/statements/compound_assign/scalar/modulo.wgsl.expected.glsl
index 8e34ac7..f3cf594 100644
--- a/test/tint/statements/compound_assign/scalar/modulo.wgsl.expected.glsl
+++ b/test/tint/statements/compound_assign/scalar/modulo.wgsl.expected.glsl
@@ -4,6 +4,10 @@
 void unused_entry_point() {
   return;
 }
+int tint_mod(int lhs, int rhs) {
+  return (lhs % (bool(uint((rhs == 0)) | uint(bool(uint((lhs == -2147483648)) & uint((rhs == -1))))) ? 1 : rhs));
+}
+
 struct S {
   int a;
 };
@@ -13,6 +17,7 @@
 } v;
 
 void foo() {
-  v.inner.a = (v.inner.a % 2);
+  int tint_symbol = tint_mod(v.inner.a, 2);
+  v.inner.a = tint_symbol;
 }
 
diff --git a/test/tint/statements/compound_assign/scalar/modulo.wgsl.expected.msl b/test/tint/statements/compound_assign/scalar/modulo.wgsl.expected.msl
index 74cbbf7..978e630 100644
--- a/test/tint/statements/compound_assign/scalar/modulo.wgsl.expected.msl
+++ b/test/tint/statements/compound_assign/scalar/modulo.wgsl.expected.msl
@@ -1,11 +1,16 @@
 #include <metal_stdlib>
 
 using namespace metal;
+int tint_mod(int lhs, int rhs) {
+  return (lhs % select(rhs, 1, bool((rhs == 0) | bool((lhs == (-2147483647 - 1)) & (rhs == -1)))));
+}
+
 struct S {
   /* 0x0000 */ int a;
 };
 
-void foo(device S* const tint_symbol) {
-  (*(tint_symbol)).a = ((*(tint_symbol)).a % 2);
+void foo(device S* const tint_symbol_1) {
+  int const tint_symbol = tint_mod((*(tint_symbol_1)).a, 2);
+  (*(tint_symbol_1)).a = tint_symbol;
 }
 
diff --git a/test/tint/statements/compound_assign/scalar/modulo.wgsl.expected.spvasm b/test/tint/statements/compound_assign/scalar/modulo.wgsl.expected.spvasm
index 4c9f181..395fc70 100644
--- a/test/tint/statements/compound_assign/scalar/modulo.wgsl.expected.spvasm
+++ b/test/tint/statements/compound_assign/scalar/modulo.wgsl.expected.spvasm
@@ -1,7 +1,7 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 20
+; Bound: 37
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
@@ -13,6 +13,9 @@
                OpMemberName %S 0 "a"
                OpName %v "v"
                OpName %unused_entry_point "unused_entry_point"
+               OpName %tint_mod "tint_mod"
+               OpName %lhs "lhs"
+               OpName %rhs "rhs"
                OpName %foo "foo"
                OpDecorate %v_block Block
                OpMemberDecorate %v_block 0 Offset 0
@@ -26,6 +29,12 @@
           %v = OpVariable %_ptr_StorageBuffer_v_block StorageBuffer
        %void = OpTypeVoid
           %6 = OpTypeFunction %void
+         %10 = OpTypeFunction %int %int %int
+         %16 = OpConstantNull %int
+       %bool = OpTypeBool
+%int_n2147483648 = OpConstant %int -2147483648
+     %int_n1 = OpConstant %int -1
+      %int_1 = OpConstant %int 1
        %uint = OpTypeInt 32 0
      %uint_0 = OpConstant %uint 0
 %_ptr_StorageBuffer_int = OpTypePointer StorageBuffer %int
@@ -34,12 +43,25 @@
           %9 = OpLabel
                OpReturn
                OpFunctionEnd
+   %tint_mod = OpFunction %int None %10
+        %lhs = OpFunctionParameter %int
+        %rhs = OpFunctionParameter %int
+         %14 = OpLabel
+         %17 = OpIEqual %bool %rhs %16
+         %20 = OpIEqual %bool %lhs %int_n2147483648
+         %22 = OpIEqual %bool %rhs %int_n1
+         %23 = OpLogicalAnd %bool %20 %22
+         %24 = OpLogicalOr %bool %17 %23
+         %15 = OpSelect %int %24 %int_1 %rhs
+         %26 = OpSMod %int %lhs %15
+               OpReturnValue %26
+               OpFunctionEnd
         %foo = OpFunction %void None %6
-         %11 = OpLabel
-         %15 = OpAccessChain %_ptr_StorageBuffer_int %v %uint_0 %uint_0
-         %16 = OpAccessChain %_ptr_StorageBuffer_int %v %uint_0 %uint_0
-         %17 = OpLoad %int %16
-         %19 = OpSMod %int %17 %int_2
-               OpStore %15 %19
+         %28 = OpLabel
+         %33 = OpAccessChain %_ptr_StorageBuffer_int %v %uint_0 %uint_0
+         %34 = OpLoad %int %33
+         %29 = OpFunctionCall %int %tint_mod %34 %int_2
+         %36 = OpAccessChain %_ptr_StorageBuffer_int %v %uint_0 %uint_0
+               OpStore %36 %29
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/statements/compound_assign/vector/divide.wgsl.expected.dxc.hlsl b/test/tint/statements/compound_assign/vector/divide.wgsl.expected.dxc.hlsl
index 0e66d73..d519f35 100644
--- a/test/tint/statements/compound_assign/vector/divide.wgsl.expected.dxc.hlsl
+++ b/test/tint/statements/compound_assign/vector/divide.wgsl.expected.dxc.hlsl
@@ -3,8 +3,13 @@
   return;
 }
 
+int4 tint_div(int4 lhs, int4 rhs) {
+  return (lhs / (((rhs == (0).xxxx) | ((lhs == (-2147483648).xxxx) & (rhs == (-1).xxxx))) ? (1).xxxx : rhs));
+}
+
 RWByteAddressBuffer v : register(u0, space0);
 
 void foo() {
-  v.Store4(0u, asuint((asint(v.Load4(0u)) / (2).xxxx)));
+  const int4 tint_symbol = tint_div(asint(v.Load4(0u)), (2).xxxx);
+  v.Store4(0u, asuint(tint_symbol));
 }
diff --git a/test/tint/statements/compound_assign/vector/divide.wgsl.expected.fxc.hlsl b/test/tint/statements/compound_assign/vector/divide.wgsl.expected.fxc.hlsl
index 0e66d73..d519f35 100644
--- a/test/tint/statements/compound_assign/vector/divide.wgsl.expected.fxc.hlsl
+++ b/test/tint/statements/compound_assign/vector/divide.wgsl.expected.fxc.hlsl
@@ -3,8 +3,13 @@
   return;
 }
 
+int4 tint_div(int4 lhs, int4 rhs) {
+  return (lhs / (((rhs == (0).xxxx) | ((lhs == (-2147483648).xxxx) & (rhs == (-1).xxxx))) ? (1).xxxx : rhs));
+}
+
 RWByteAddressBuffer v : register(u0, space0);
 
 void foo() {
-  v.Store4(0u, asuint((asint(v.Load4(0u)) / (2).xxxx)));
+  const int4 tint_symbol = tint_div(asint(v.Load4(0u)), (2).xxxx);
+  v.Store4(0u, asuint(tint_symbol));
 }
diff --git a/test/tint/statements/compound_assign/vector/divide.wgsl.expected.glsl b/test/tint/statements/compound_assign/vector/divide.wgsl.expected.glsl
index 5f6f244..aa704fe 100644
--- a/test/tint/statements/compound_assign/vector/divide.wgsl.expected.glsl
+++ b/test/tint/statements/compound_assign/vector/divide.wgsl.expected.glsl
@@ -4,6 +4,10 @@
 void unused_entry_point() {
   return;
 }
+ivec4 tint_div(ivec4 lhs, ivec4 rhs) {
+  return (lhs / mix(rhs, ivec4(1), bvec4(uvec4(equal(rhs, ivec4(0))) | uvec4(bvec4(uvec4(equal(lhs, ivec4(-2147483648))) & uvec4(equal(rhs, ivec4(-1))))))));
+}
+
 struct S {
   ivec4 a;
 };
@@ -13,6 +17,7 @@
 } v;
 
 void foo() {
-  v.inner.a = (v.inner.a / ivec4(2));
+  ivec4 tint_symbol = tint_div(v.inner.a, ivec4(2));
+  v.inner.a = tint_symbol;
 }
 
diff --git a/test/tint/statements/compound_assign/vector/divide.wgsl.expected.msl b/test/tint/statements/compound_assign/vector/divide.wgsl.expected.msl
index ace4828..782112c 100644
--- a/test/tint/statements/compound_assign/vector/divide.wgsl.expected.msl
+++ b/test/tint/statements/compound_assign/vector/divide.wgsl.expected.msl
@@ -1,11 +1,16 @@
 #include <metal_stdlib>
 
 using namespace metal;
+int4 tint_div(int4 lhs, int4 rhs) {
+  return (lhs / select(rhs, int4(1), ((rhs == int4(0)) | ((lhs == int4((-2147483647 - 1))) & (rhs == int4(-1))))));
+}
+
 struct S {
   /* 0x0000 */ int4 a;
 };
 
-void foo(device S* const tint_symbol) {
-  (*(tint_symbol)).a = ((*(tint_symbol)).a / int4(2));
+void foo(device S* const tint_symbol_1) {
+  int4 const tint_symbol = tint_div((*(tint_symbol_1)).a, int4(2));
+  (*(tint_symbol_1)).a = tint_symbol;
 }
 
diff --git a/test/tint/statements/compound_assign/vector/divide.wgsl.expected.spvasm b/test/tint/statements/compound_assign/vector/divide.wgsl.expected.spvasm
index 9b7ff51..cfca72a 100644
--- a/test/tint/statements/compound_assign/vector/divide.wgsl.expected.spvasm
+++ b/test/tint/statements/compound_assign/vector/divide.wgsl.expected.spvasm
@@ -1,7 +1,7 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 22
+; Bound: 43
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
@@ -13,6 +13,9 @@
                OpMemberName %S 0 "a"
                OpName %v "v"
                OpName %unused_entry_point "unused_entry_point"
+               OpName %tint_div "tint_div"
+               OpName %lhs "lhs"
+               OpName %rhs "rhs"
                OpName %foo "foo"
                OpDecorate %v_block Block
                OpMemberDecorate %v_block 0 Offset 0
@@ -27,21 +30,44 @@
           %v = OpVariable %_ptr_StorageBuffer_v_block StorageBuffer
        %void = OpTypeVoid
           %7 = OpTypeFunction %void
+         %11 = OpTypeFunction %v4int %v4int %v4int
+         %17 = OpConstantNull %v4int
+       %bool = OpTypeBool
+     %v4bool = OpTypeVector %bool 4
+%int_n2147483648 = OpConstant %int -2147483648
+         %22 = OpConstantComposite %v4int %int_n2147483648 %int_n2147483648 %int_n2147483648 %int_n2147483648
+     %int_n1 = OpConstant %int -1
+         %25 = OpConstantComposite %v4int %int_n1 %int_n1 %int_n1 %int_n1
+      %int_1 = OpConstant %int 1
+         %30 = OpConstantComposite %v4int %int_1 %int_1 %int_1 %int_1
        %uint = OpTypeInt 32 0
      %uint_0 = OpConstant %uint 0
 %_ptr_StorageBuffer_v4int = OpTypePointer StorageBuffer %v4int
       %int_2 = OpConstant %int 2
-         %20 = OpConstantComposite %v4int %int_2 %int_2 %int_2 %int_2
+         %41 = OpConstantComposite %v4int %int_2 %int_2 %int_2 %int_2
 %unused_entry_point = OpFunction %void None %7
          %10 = OpLabel
                OpReturn
                OpFunctionEnd
+   %tint_div = OpFunction %v4int None %11
+        %lhs = OpFunctionParameter %v4int
+        %rhs = OpFunctionParameter %v4int
+         %15 = OpLabel
+         %18 = OpIEqual %v4bool %rhs %17
+         %23 = OpIEqual %v4bool %lhs %22
+         %26 = OpIEqual %v4bool %rhs %25
+         %27 = OpLogicalAnd %v4bool %23 %26
+         %28 = OpLogicalOr %v4bool %18 %27
+         %16 = OpSelect %v4int %28 %30 %rhs
+         %31 = OpSDiv %v4int %lhs %16
+               OpReturnValue %31
+               OpFunctionEnd
         %foo = OpFunction %void None %7
-         %12 = OpLabel
-         %16 = OpAccessChain %_ptr_StorageBuffer_v4int %v %uint_0 %uint_0
-         %17 = OpAccessChain %_ptr_StorageBuffer_v4int %v %uint_0 %uint_0
-         %18 = OpLoad %v4int %17
-         %21 = OpSDiv %v4int %18 %20
-               OpStore %16 %21
+         %33 = OpLabel
+         %38 = OpAccessChain %_ptr_StorageBuffer_v4int %v %uint_0 %uint_0
+         %39 = OpLoad %v4int %38
+         %34 = OpFunctionCall %v4int %tint_div %39 %41
+         %42 = OpAccessChain %_ptr_StorageBuffer_v4int %v %uint_0 %uint_0
+               OpStore %42 %34
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/statements/compound_assign/vector/modulo-scalar.wgsl.expected.dxc.hlsl b/test/tint/statements/compound_assign/vector/modulo-scalar.wgsl.expected.dxc.hlsl
index f5f8675..e0195aa 100644
--- a/test/tint/statements/compound_assign/vector/modulo-scalar.wgsl.expected.dxc.hlsl
+++ b/test/tint/statements/compound_assign/vector/modulo-scalar.wgsl.expected.dxc.hlsl
@@ -3,8 +3,14 @@
   return;
 }
 
+int4 tint_mod(int4 lhs, int rhs) {
+  const int4 r = int4((rhs).xxxx);
+  return (lhs % (((r == (0).xxxx) | ((lhs == (-2147483648).xxxx) & (r == (-1).xxxx))) ? (1).xxxx : r));
+}
+
 RWByteAddressBuffer v : register(u0, space0);
 
 void foo() {
-  v.Store4(0u, asuint((asint(v.Load4(0u)) % 2)));
+  const int4 tint_symbol = tint_mod(asint(v.Load4(0u)), 2);
+  v.Store4(0u, asuint(tint_symbol));
 }
diff --git a/test/tint/statements/compound_assign/vector/modulo-scalar.wgsl.expected.fxc.hlsl b/test/tint/statements/compound_assign/vector/modulo-scalar.wgsl.expected.fxc.hlsl
index f5f8675..e0195aa 100644
--- a/test/tint/statements/compound_assign/vector/modulo-scalar.wgsl.expected.fxc.hlsl
+++ b/test/tint/statements/compound_assign/vector/modulo-scalar.wgsl.expected.fxc.hlsl
@@ -3,8 +3,14 @@
   return;
 }
 
+int4 tint_mod(int4 lhs, int rhs) {
+  const int4 r = int4((rhs).xxxx);
+  return (lhs % (((r == (0).xxxx) | ((lhs == (-2147483648).xxxx) & (r == (-1).xxxx))) ? (1).xxxx : r));
+}
+
 RWByteAddressBuffer v : register(u0, space0);
 
 void foo() {
-  v.Store4(0u, asuint((asint(v.Load4(0u)) % 2)));
+  const int4 tint_symbol = tint_mod(asint(v.Load4(0u)), 2);
+  v.Store4(0u, asuint(tint_symbol));
 }
diff --git a/test/tint/statements/compound_assign/vector/modulo-scalar.wgsl.expected.glsl b/test/tint/statements/compound_assign/vector/modulo-scalar.wgsl.expected.glsl
index 53e18c8..ed2d419 100644
--- a/test/tint/statements/compound_assign/vector/modulo-scalar.wgsl.expected.glsl
+++ b/test/tint/statements/compound_assign/vector/modulo-scalar.wgsl.expected.glsl
@@ -4,6 +4,11 @@
 void unused_entry_point() {
   return;
 }
+ivec4 tint_mod(ivec4 lhs, int rhs) {
+  ivec4 r = ivec4(rhs);
+  return (lhs % mix(r, ivec4(1), bvec4(uvec4(equal(r, ivec4(0))) | uvec4(bvec4(uvec4(equal(lhs, ivec4(-2147483648))) & uvec4(equal(r, ivec4(-1))))))));
+}
+
 struct S {
   ivec4 a;
 };
@@ -13,6 +18,7 @@
 } v;
 
 void foo() {
-  v.inner.a = (v.inner.a % 2);
+  ivec4 tint_symbol = tint_mod(v.inner.a, 2);
+  v.inner.a = tint_symbol;
 }
 
diff --git a/test/tint/statements/compound_assign/vector/modulo-scalar.wgsl.expected.msl b/test/tint/statements/compound_assign/vector/modulo-scalar.wgsl.expected.msl
index 697323b..db65802 100644
--- a/test/tint/statements/compound_assign/vector/modulo-scalar.wgsl.expected.msl
+++ b/test/tint/statements/compound_assign/vector/modulo-scalar.wgsl.expected.msl
@@ -1,11 +1,17 @@
 #include <metal_stdlib>
 
 using namespace metal;
+int4 tint_mod(int4 lhs, int rhs) {
+  int4 const r = int4(rhs);
+  return (lhs % select(r, int4(1), ((r == int4(0)) | ((lhs == int4((-2147483647 - 1))) & (r == int4(-1))))));
+}
+
 struct S {
   /* 0x0000 */ int4 a;
 };
 
-void foo(device S* const tint_symbol) {
-  (*(tint_symbol)).a = ((*(tint_symbol)).a % 2);
+void foo(device S* const tint_symbol_1) {
+  int4 const tint_symbol = tint_mod((*(tint_symbol_1)).a, 2);
+  (*(tint_symbol_1)).a = tint_symbol;
 }
 
diff --git a/test/tint/statements/compound_assign/vector/modulo-scalar.wgsl.expected.spvasm b/test/tint/statements/compound_assign/vector/modulo-scalar.wgsl.expected.spvasm
index 137c568..1467a4b 100644
--- a/test/tint/statements/compound_assign/vector/modulo-scalar.wgsl.expected.spvasm
+++ b/test/tint/statements/compound_assign/vector/modulo-scalar.wgsl.expected.spvasm
@@ -1,7 +1,7 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 25
+; Bound: 43
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
@@ -13,6 +13,9 @@
                OpMemberName %S 0 "a"
                OpName %v "v"
                OpName %unused_entry_point "unused_entry_point"
+               OpName %tint_mod "tint_mod"
+               OpName %lhs "lhs"
+               OpName %rhs "rhs"
                OpName %foo "foo"
                OpDecorate %v_block Block
                OpMemberDecorate %v_block 0 Offset 0
@@ -27,24 +30,44 @@
           %v = OpVariable %_ptr_StorageBuffer_v_block StorageBuffer
        %void = OpTypeVoid
           %7 = OpTypeFunction %void
+         %11 = OpTypeFunction %v4int %v4int %int
+         %18 = OpConstantNull %v4int
+       %bool = OpTypeBool
+     %v4bool = OpTypeVector %bool 4
+%int_n2147483648 = OpConstant %int -2147483648
+         %23 = OpConstantComposite %v4int %int_n2147483648 %int_n2147483648 %int_n2147483648 %int_n2147483648
+     %int_n1 = OpConstant %int -1
+         %26 = OpConstantComposite %v4int %int_n1 %int_n1 %int_n1 %int_n1
+      %int_1 = OpConstant %int 1
+         %31 = OpConstantComposite %v4int %int_1 %int_1 %int_1 %int_1
        %uint = OpTypeInt 32 0
      %uint_0 = OpConstant %uint 0
 %_ptr_StorageBuffer_v4int = OpTypePointer StorageBuffer %v4int
       %int_2 = OpConstant %int 2
-%_ptr_Function_v4int = OpTypePointer Function %v4int
-         %23 = OpConstantNull %v4int
 %unused_entry_point = OpFunction %void None %7
          %10 = OpLabel
                OpReturn
                OpFunctionEnd
+   %tint_mod = OpFunction %v4int None %11
+        %lhs = OpFunctionParameter %v4int
+        %rhs = OpFunctionParameter %int
+         %15 = OpLabel
+         %16 = OpCompositeConstruct %v4int %rhs %rhs %rhs %rhs
+         %19 = OpIEqual %v4bool %16 %18
+         %24 = OpIEqual %v4bool %lhs %23
+         %27 = OpIEqual %v4bool %16 %26
+         %28 = OpLogicalAnd %v4bool %24 %27
+         %29 = OpLogicalOr %v4bool %19 %28
+         %17 = OpSelect %v4int %29 %31 %16
+         %32 = OpSMod %v4int %lhs %17
+               OpReturnValue %32
+               OpFunctionEnd
         %foo = OpFunction %void None %7
-         %12 = OpLabel
-         %21 = OpVariable %_ptr_Function_v4int Function %23
-         %16 = OpAccessChain %_ptr_StorageBuffer_v4int %v %uint_0 %uint_0
-         %17 = OpAccessChain %_ptr_StorageBuffer_v4int %v %uint_0 %uint_0
-         %18 = OpLoad %v4int %17
-         %24 = OpCompositeConstruct %v4int %int_2 %int_2 %int_2 %int_2
-         %20 = OpSMod %v4int %18 %24
-               OpStore %16 %20
+         %34 = OpLabel
+         %39 = OpAccessChain %_ptr_StorageBuffer_v4int %v %uint_0 %uint_0
+         %40 = OpLoad %v4int %39
+         %35 = OpFunctionCall %v4int %tint_mod %40 %int_2
+         %42 = OpAccessChain %_ptr_StorageBuffer_v4int %v %uint_0 %uint_0
+               OpStore %42 %35
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/statements/compound_assign/vector/modulo.wgsl.expected.dxc.hlsl b/test/tint/statements/compound_assign/vector/modulo.wgsl.expected.dxc.hlsl
index b54d980..f413ff6 100644
--- a/test/tint/statements/compound_assign/vector/modulo.wgsl.expected.dxc.hlsl
+++ b/test/tint/statements/compound_assign/vector/modulo.wgsl.expected.dxc.hlsl
@@ -3,8 +3,13 @@
   return;
 }
 
+int4 tint_mod(int4 lhs, int4 rhs) {
+  return (lhs % (((rhs == (0).xxxx) | ((lhs == (-2147483648).xxxx) & (rhs == (-1).xxxx))) ? (1).xxxx : rhs));
+}
+
 RWByteAddressBuffer v : register(u0, space0);
 
 void foo() {
-  v.Store4(0u, asuint((asint(v.Load4(0u)) % (2).xxxx)));
+  const int4 tint_symbol = tint_mod(asint(v.Load4(0u)), (2).xxxx);
+  v.Store4(0u, asuint(tint_symbol));
 }
diff --git a/test/tint/statements/compound_assign/vector/modulo.wgsl.expected.fxc.hlsl b/test/tint/statements/compound_assign/vector/modulo.wgsl.expected.fxc.hlsl
index b54d980..f413ff6 100644
--- a/test/tint/statements/compound_assign/vector/modulo.wgsl.expected.fxc.hlsl
+++ b/test/tint/statements/compound_assign/vector/modulo.wgsl.expected.fxc.hlsl
@@ -3,8 +3,13 @@
   return;
 }
 
+int4 tint_mod(int4 lhs, int4 rhs) {
+  return (lhs % (((rhs == (0).xxxx) | ((lhs == (-2147483648).xxxx) & (rhs == (-1).xxxx))) ? (1).xxxx : rhs));
+}
+
 RWByteAddressBuffer v : register(u0, space0);
 
 void foo() {
-  v.Store4(0u, asuint((asint(v.Load4(0u)) % (2).xxxx)));
+  const int4 tint_symbol = tint_mod(asint(v.Load4(0u)), (2).xxxx);
+  v.Store4(0u, asuint(tint_symbol));
 }
diff --git a/test/tint/statements/compound_assign/vector/modulo.wgsl.expected.glsl b/test/tint/statements/compound_assign/vector/modulo.wgsl.expected.glsl
index d837a08..1f5c0c4 100644
--- a/test/tint/statements/compound_assign/vector/modulo.wgsl.expected.glsl
+++ b/test/tint/statements/compound_assign/vector/modulo.wgsl.expected.glsl
@@ -4,6 +4,10 @@
 void unused_entry_point() {
   return;
 }
+ivec4 tint_mod(ivec4 lhs, ivec4 rhs) {
+  return (lhs % mix(rhs, ivec4(1), bvec4(uvec4(equal(rhs, ivec4(0))) | uvec4(bvec4(uvec4(equal(lhs, ivec4(-2147483648))) & uvec4(equal(rhs, ivec4(-1))))))));
+}
+
 struct S {
   ivec4 a;
 };
@@ -13,6 +17,7 @@
 } v;
 
 void foo() {
-  v.inner.a = (v.inner.a % ivec4(2));
+  ivec4 tint_symbol = tint_mod(v.inner.a, ivec4(2));
+  v.inner.a = tint_symbol;
 }
 
diff --git a/test/tint/statements/compound_assign/vector/modulo.wgsl.expected.msl b/test/tint/statements/compound_assign/vector/modulo.wgsl.expected.msl
index fafddb8..2435db2 100644
--- a/test/tint/statements/compound_assign/vector/modulo.wgsl.expected.msl
+++ b/test/tint/statements/compound_assign/vector/modulo.wgsl.expected.msl
@@ -1,11 +1,16 @@
 #include <metal_stdlib>
 
 using namespace metal;
+int4 tint_mod(int4 lhs, int4 rhs) {
+  return (lhs % select(rhs, int4(1), ((rhs == int4(0)) | ((lhs == int4((-2147483647 - 1))) & (rhs == int4(-1))))));
+}
+
 struct S {
   /* 0x0000 */ int4 a;
 };
 
-void foo(device S* const tint_symbol) {
-  (*(tint_symbol)).a = ((*(tint_symbol)).a % int4(2));
+void foo(device S* const tint_symbol_1) {
+  int4 const tint_symbol = tint_mod((*(tint_symbol_1)).a, int4(2));
+  (*(tint_symbol_1)).a = tint_symbol;
 }
 
diff --git a/test/tint/statements/compound_assign/vector/modulo.wgsl.expected.spvasm b/test/tint/statements/compound_assign/vector/modulo.wgsl.expected.spvasm
index 74e9f79..220fe57 100644
--- a/test/tint/statements/compound_assign/vector/modulo.wgsl.expected.spvasm
+++ b/test/tint/statements/compound_assign/vector/modulo.wgsl.expected.spvasm
@@ -1,7 +1,7 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 22
+; Bound: 43
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
@@ -13,6 +13,9 @@
                OpMemberName %S 0 "a"
                OpName %v "v"
                OpName %unused_entry_point "unused_entry_point"
+               OpName %tint_mod "tint_mod"
+               OpName %lhs "lhs"
+               OpName %rhs "rhs"
                OpName %foo "foo"
                OpDecorate %v_block Block
                OpMemberDecorate %v_block 0 Offset 0
@@ -27,21 +30,44 @@
           %v = OpVariable %_ptr_StorageBuffer_v_block StorageBuffer
        %void = OpTypeVoid
           %7 = OpTypeFunction %void
+         %11 = OpTypeFunction %v4int %v4int %v4int
+         %17 = OpConstantNull %v4int
+       %bool = OpTypeBool
+     %v4bool = OpTypeVector %bool 4
+%int_n2147483648 = OpConstant %int -2147483648
+         %22 = OpConstantComposite %v4int %int_n2147483648 %int_n2147483648 %int_n2147483648 %int_n2147483648
+     %int_n1 = OpConstant %int -1
+         %25 = OpConstantComposite %v4int %int_n1 %int_n1 %int_n1 %int_n1
+      %int_1 = OpConstant %int 1
+         %30 = OpConstantComposite %v4int %int_1 %int_1 %int_1 %int_1
        %uint = OpTypeInt 32 0
      %uint_0 = OpConstant %uint 0
 %_ptr_StorageBuffer_v4int = OpTypePointer StorageBuffer %v4int
       %int_2 = OpConstant %int 2
-         %20 = OpConstantComposite %v4int %int_2 %int_2 %int_2 %int_2
+         %41 = OpConstantComposite %v4int %int_2 %int_2 %int_2 %int_2
 %unused_entry_point = OpFunction %void None %7
          %10 = OpLabel
                OpReturn
                OpFunctionEnd
+   %tint_mod = OpFunction %v4int None %11
+        %lhs = OpFunctionParameter %v4int
+        %rhs = OpFunctionParameter %v4int
+         %15 = OpLabel
+         %18 = OpIEqual %v4bool %rhs %17
+         %23 = OpIEqual %v4bool %lhs %22
+         %26 = OpIEqual %v4bool %rhs %25
+         %27 = OpLogicalAnd %v4bool %23 %26
+         %28 = OpLogicalOr %v4bool %18 %27
+         %16 = OpSelect %v4int %28 %30 %rhs
+         %31 = OpSMod %v4int %lhs %16
+               OpReturnValue %31
+               OpFunctionEnd
         %foo = OpFunction %void None %7
-         %12 = OpLabel
-         %16 = OpAccessChain %_ptr_StorageBuffer_v4int %v %uint_0 %uint_0
-         %17 = OpAccessChain %_ptr_StorageBuffer_v4int %v %uint_0 %uint_0
-         %18 = OpLoad %v4int %17
-         %21 = OpSMod %v4int %18 %20
-               OpStore %16 %21
+         %33 = OpLabel
+         %38 = OpAccessChain %_ptr_StorageBuffer_v4int %v %uint_0 %uint_0
+         %39 = OpLoad %v4int %38
+         %34 = OpFunctionCall %v4int %tint_mod %39 %41
+         %42 = OpAccessChain %_ptr_StorageBuffer_v4int %v %uint_0 %uint_0
+               OpStore %42 %34
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/statements/compound_assign/workgroup.wgsl.expected.dxc.hlsl b/test/tint/statements/compound_assign/workgroup.wgsl.expected.dxc.hlsl
index dae8e54..d6246e4 100644
--- a/test/tint/statements/compound_assign/workgroup.wgsl.expected.dxc.hlsl
+++ b/test/tint/statements/compound_assign/workgroup.wgsl.expected.dxc.hlsl
@@ -3,12 +3,16 @@
   return;
 }
 
+int tint_div(int lhs, int rhs) {
+  return (lhs / (((rhs == 0) | ((lhs == -2147483648) & (rhs == -1))) ? 1 : rhs));
+}
+
 groupshared int a;
 groupshared float4 b;
 groupshared float2x2 c;
 
 void foo() {
-  a = (a / 2);
+  a = tint_div(a, 2);
   b = mul(float4x4((0.0f).xxxx, (0.0f).xxxx, (0.0f).xxxx, (0.0f).xxxx), b);
   c = (c * 2.0f);
 }
diff --git a/test/tint/statements/compound_assign/workgroup.wgsl.expected.fxc.hlsl b/test/tint/statements/compound_assign/workgroup.wgsl.expected.fxc.hlsl
index dae8e54..d6246e4 100644
--- a/test/tint/statements/compound_assign/workgroup.wgsl.expected.fxc.hlsl
+++ b/test/tint/statements/compound_assign/workgroup.wgsl.expected.fxc.hlsl
@@ -3,12 +3,16 @@
   return;
 }
 
+int tint_div(int lhs, int rhs) {
+  return (lhs / (((rhs == 0) | ((lhs == -2147483648) & (rhs == -1))) ? 1 : rhs));
+}
+
 groupshared int a;
 groupshared float4 b;
 groupshared float2x2 c;
 
 void foo() {
-  a = (a / 2);
+  a = tint_div(a, 2);
   b = mul(float4x4((0.0f).xxxx, (0.0f).xxxx, (0.0f).xxxx, (0.0f).xxxx), b);
   c = (c * 2.0f);
 }
diff --git a/test/tint/statements/compound_assign/workgroup.wgsl.expected.glsl b/test/tint/statements/compound_assign/workgroup.wgsl.expected.glsl
index d762d8f..3b920a2 100644
--- a/test/tint/statements/compound_assign/workgroup.wgsl.expected.glsl
+++ b/test/tint/statements/compound_assign/workgroup.wgsl.expected.glsl
@@ -4,11 +4,15 @@
 void unused_entry_point() {
   return;
 }
+int tint_div(int lhs, int rhs) {
+  return (lhs / (bool(uint((rhs == 0)) | uint(bool(uint((lhs == -2147483648)) & uint((rhs == -1))))) ? 1 : rhs));
+}
+
 shared int a;
 shared vec4 b;
 shared mat2 c;
 void foo() {
-  a = (a / 2);
+  a = tint_div(a, 2);
   b = (b * mat4(vec4(0.0f), vec4(0.0f), vec4(0.0f), vec4(0.0f)));
   c = (c * 2.0f);
 }
diff --git a/test/tint/statements/compound_assign/workgroup.wgsl.expected.msl b/test/tint/statements/compound_assign/workgroup.wgsl.expected.msl
index 4335b15..588738a 100644
--- a/test/tint/statements/compound_assign/workgroup.wgsl.expected.msl
+++ b/test/tint/statements/compound_assign/workgroup.wgsl.expected.msl
@@ -1,8 +1,12 @@
 #include <metal_stdlib>
 
 using namespace metal;
+int tint_div(int lhs, int rhs) {
+  return (lhs / select(rhs, 1, bool((rhs == 0) | bool((lhs == (-2147483647 - 1)) & (rhs == -1)))));
+}
+
 void foo(threadgroup int* const tint_symbol, threadgroup float4* const tint_symbol_1, threadgroup float2x2* const tint_symbol_2) {
-  *(tint_symbol) = (*(tint_symbol) / 2);
+  *(tint_symbol) = tint_div(*(tint_symbol), 2);
   *(tint_symbol_1) = (*(tint_symbol_1) * float4x4(float4(0.0f), float4(0.0f), float4(0.0f), float4(0.0f)));
   *(tint_symbol_2) = (*(tint_symbol_2) * 2.0f);
 }
diff --git a/test/tint/statements/compound_assign/workgroup.wgsl.expected.spvasm b/test/tint/statements/compound_assign/workgroup.wgsl.expected.spvasm
index ddf0b14..18be544 100644
--- a/test/tint/statements/compound_assign/workgroup.wgsl.expected.spvasm
+++ b/test/tint/statements/compound_assign/workgroup.wgsl.expected.spvasm
@@ -1,7 +1,7 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 28
+; Bound: 45
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
@@ -11,6 +11,9 @@
                OpName %b "b"
                OpName %c "c"
                OpName %unused_entry_point "unused_entry_point"
+               OpName %tint_div "tint_div"
+               OpName %lhs "lhs"
+               OpName %rhs "rhs"
                OpName %foo "foo"
         %int = OpTypeInt 32 1
 %_ptr_Workgroup_int = OpTypePointer Workgroup %int
@@ -25,24 +28,43 @@
           %c = OpVariable %_ptr_Workgroup_mat2v2float Workgroup
        %void = OpTypeVoid
          %12 = OpTypeFunction %void
+         %16 = OpTypeFunction %int %int %int
+         %22 = OpConstantNull %int
+       %bool = OpTypeBool
+%int_n2147483648 = OpConstant %int -2147483648
+     %int_n1 = OpConstant %int -1
+      %int_1 = OpConstant %int 1
       %int_2 = OpConstant %int 2
 %mat4v4float = OpTypeMatrix %v4float 4
-         %23 = OpConstantNull %mat4v4float
+         %40 = OpConstantNull %mat4v4float
     %float_2 = OpConstant %float 2
 %unused_entry_point = OpFunction %void None %12
          %15 = OpLabel
                OpReturn
                OpFunctionEnd
+   %tint_div = OpFunction %int None %16
+        %lhs = OpFunctionParameter %int
+        %rhs = OpFunctionParameter %int
+         %20 = OpLabel
+         %23 = OpIEqual %bool %rhs %22
+         %26 = OpIEqual %bool %lhs %int_n2147483648
+         %28 = OpIEqual %bool %rhs %int_n1
+         %29 = OpLogicalAnd %bool %26 %28
+         %30 = OpLogicalOr %bool %23 %29
+         %21 = OpSelect %int %30 %int_1 %rhs
+         %32 = OpSDiv %int %lhs %21
+               OpReturnValue %32
+               OpFunctionEnd
         %foo = OpFunction %void None %12
-         %17 = OpLabel
-         %18 = OpLoad %int %a
-         %20 = OpSDiv %int %18 %int_2
-               OpStore %a %20
-         %21 = OpLoad %v4float %b
-         %24 = OpVectorTimesMatrix %v4float %21 %23
-               OpStore %b %24
-         %25 = OpLoad %mat2v2float %c
-         %27 = OpMatrixTimesScalar %mat2v2float %25 %float_2
-               OpStore %c %27
+         %34 = OpLabel
+         %36 = OpLoad %int %a
+         %35 = OpFunctionCall %int %tint_div %36 %int_2
+               OpStore %a %35
+         %38 = OpLoad %v4float %b
+         %41 = OpVectorTimesMatrix %v4float %38 %40
+               OpStore %b %41
+         %42 = OpLoad %mat2v2float %c
+         %44 = OpMatrixTimesScalar %mat2v2float %42 %float_2
+               OpStore %c %44
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/statements/decrement/complex.wgsl.expected.dxc.hlsl b/test/tint/statements/decrement/complex.wgsl.expected.dxc.hlsl
index 94574a1..ad26e2f 100644
--- a/test/tint/statements/decrement/complex.wgsl.expected.dxc.hlsl
+++ b/test/tint/statements/decrement/complex.wgsl.expected.dxc.hlsl
@@ -37,10 +37,8 @@
 }
 
 void main() {
-  const int tint_symbol_4 = idx1();
-  const int tint_symbol_5 = idx2();
-  const int tint_symbol_save = tint_symbol_4;
-  const int tint_symbol_save_1 = tint_symbol_5;
+  const int tint_symbol_save = idx1();
+  const int tint_symbol_save_1 = idx2();
   const int tint_symbol_1 = idx3();
   {
     buffer.Store((((64u * uint(tint_symbol_save)) + (16u * uint(tint_symbol_save_1))) + (4u * uint(tint_symbol_1))), asuint((asint(buffer.Load((((64u * uint(tint_symbol_save)) + (16u * uint(tint_symbol_save_1))) + (4u * uint(tint_symbol_1))))) - 1)));
@@ -51,10 +49,8 @@
       {
       }
       {
-        const int tint_symbol_6 = idx4();
-        const int tint_symbol_7 = idx5();
-        const int tint_symbol_2_save = tint_symbol_6;
-        const int tint_symbol_2_save_1 = tint_symbol_7;
+        const int tint_symbol_2_save = idx4();
+        const int tint_symbol_2_save_1 = idx5();
         const int tint_symbol_3 = idx6();
         buffer.Store((((64u * uint(tint_symbol_2_save)) + (16u * uint(tint_symbol_2_save_1))) + (4u * uint(tint_symbol_3))), asuint((asint(buffer.Load((((64u * uint(tint_symbol_2_save)) + (16u * uint(tint_symbol_2_save_1))) + (4u * uint(tint_symbol_3))))) - 1)));
       }
diff --git a/test/tint/statements/decrement/complex.wgsl.expected.fxc.hlsl b/test/tint/statements/decrement/complex.wgsl.expected.fxc.hlsl
index 94574a1..ad26e2f 100644
--- a/test/tint/statements/decrement/complex.wgsl.expected.fxc.hlsl
+++ b/test/tint/statements/decrement/complex.wgsl.expected.fxc.hlsl
@@ -37,10 +37,8 @@
 }
 
 void main() {
-  const int tint_symbol_4 = idx1();
-  const int tint_symbol_5 = idx2();
-  const int tint_symbol_save = tint_symbol_4;
-  const int tint_symbol_save_1 = tint_symbol_5;
+  const int tint_symbol_save = idx1();
+  const int tint_symbol_save_1 = idx2();
   const int tint_symbol_1 = idx3();
   {
     buffer.Store((((64u * uint(tint_symbol_save)) + (16u * uint(tint_symbol_save_1))) + (4u * uint(tint_symbol_1))), asuint((asint(buffer.Load((((64u * uint(tint_symbol_save)) + (16u * uint(tint_symbol_save_1))) + (4u * uint(tint_symbol_1))))) - 1)));
@@ -51,10 +49,8 @@
       {
       }
       {
-        const int tint_symbol_6 = idx4();
-        const int tint_symbol_7 = idx5();
-        const int tint_symbol_2_save = tint_symbol_6;
-        const int tint_symbol_2_save_1 = tint_symbol_7;
+        const int tint_symbol_2_save = idx4();
+        const int tint_symbol_2_save_1 = idx5();
         const int tint_symbol_3 = idx6();
         buffer.Store((((64u * uint(tint_symbol_2_save)) + (16u * uint(tint_symbol_2_save_1))) + (4u * uint(tint_symbol_3))), asuint((asint(buffer.Load((((64u * uint(tint_symbol_2_save)) + (16u * uint(tint_symbol_2_save_1))) + (4u * uint(tint_symbol_3))))) - 1)));
       }
diff --git a/test/tint/statements/increment/complex.wgsl.expected.dxc.hlsl b/test/tint/statements/increment/complex.wgsl.expected.dxc.hlsl
index 74aa1b7..dc0b8b1 100644
--- a/test/tint/statements/increment/complex.wgsl.expected.dxc.hlsl
+++ b/test/tint/statements/increment/complex.wgsl.expected.dxc.hlsl
@@ -37,10 +37,8 @@
 }
 
 void main() {
-  const int tint_symbol_4 = idx1();
-  const int tint_symbol_5 = idx2();
-  const int tint_symbol_save = tint_symbol_4;
-  const int tint_symbol_save_1 = tint_symbol_5;
+  const int tint_symbol_save = idx1();
+  const int tint_symbol_save_1 = idx2();
   const int tint_symbol_1 = idx3();
   {
     buffer.Store((((64u * uint(tint_symbol_save)) + (16u * uint(tint_symbol_save_1))) + (4u * uint(tint_symbol_1))), asuint((asint(buffer.Load((((64u * uint(tint_symbol_save)) + (16u * uint(tint_symbol_save_1))) + (4u * uint(tint_symbol_1))))) + 1)));
@@ -51,10 +49,8 @@
       {
       }
       {
-        const int tint_symbol_6 = idx4();
-        const int tint_symbol_7 = idx5();
-        const int tint_symbol_2_save = tint_symbol_6;
-        const int tint_symbol_2_save_1 = tint_symbol_7;
+        const int tint_symbol_2_save = idx4();
+        const int tint_symbol_2_save_1 = idx5();
         const int tint_symbol_3 = idx6();
         buffer.Store((((64u * uint(tint_symbol_2_save)) + (16u * uint(tint_symbol_2_save_1))) + (4u * uint(tint_symbol_3))), asuint((asint(buffer.Load((((64u * uint(tint_symbol_2_save)) + (16u * uint(tint_symbol_2_save_1))) + (4u * uint(tint_symbol_3))))) + 1)));
       }
diff --git a/test/tint/statements/increment/complex.wgsl.expected.fxc.hlsl b/test/tint/statements/increment/complex.wgsl.expected.fxc.hlsl
index 74aa1b7..dc0b8b1 100644
--- a/test/tint/statements/increment/complex.wgsl.expected.fxc.hlsl
+++ b/test/tint/statements/increment/complex.wgsl.expected.fxc.hlsl
@@ -37,10 +37,8 @@
 }
 
 void main() {
-  const int tint_symbol_4 = idx1();
-  const int tint_symbol_5 = idx2();
-  const int tint_symbol_save = tint_symbol_4;
-  const int tint_symbol_save_1 = tint_symbol_5;
+  const int tint_symbol_save = idx1();
+  const int tint_symbol_save_1 = idx2();
   const int tint_symbol_1 = idx3();
   {
     buffer.Store((((64u * uint(tint_symbol_save)) + (16u * uint(tint_symbol_save_1))) + (4u * uint(tint_symbol_1))), asuint((asint(buffer.Load((((64u * uint(tint_symbol_save)) + (16u * uint(tint_symbol_save_1))) + (4u * uint(tint_symbol_1))))) + 1)));
@@ -51,10 +49,8 @@
       {
       }
       {
-        const int tint_symbol_6 = idx4();
-        const int tint_symbol_7 = idx5();
-        const int tint_symbol_2_save = tint_symbol_6;
-        const int tint_symbol_2_save_1 = tint_symbol_7;
+        const int tint_symbol_2_save = idx4();
+        const int tint_symbol_2_save_1 = idx5();
         const int tint_symbol_3 = idx6();
         buffer.Store((((64u * uint(tint_symbol_2_save)) + (16u * uint(tint_symbol_2_save_1))) + (4u * uint(tint_symbol_3))), asuint((asint(buffer.Load((((64u * uint(tint_symbol_2_save)) + (16u * uint(tint_symbol_2_save_1))) + (4u * uint(tint_symbol_3))))) + 1)));
       }