tint/transform: Polyfill f32 conversion to i32 or u32

And vectors of those types.

Fixed: tint:1866
Change-Id: Ic0b5061232c5eb5a67d43dde1cd9599c580f4388
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/123201
Reviewed-by: Dan Sinclair <dsinclair@chromium.org>
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: David Neto <dneto@google.com>
Commit-Queue: Ben Clayton <bclayton@chromium.org>
Kokoro: Ben Clayton <bclayton@chromium.org>
diff --git a/src/tint/transform/builtin_polyfill.cc b/src/tint/transform/builtin_polyfill.cc
index ba7c5d2..c242521 100644
--- a/src/tint/transform/builtin_polyfill.cc
+++ b/src/tint/transform/builtin_polyfill.cc
@@ -23,6 +23,7 @@
 #include "src/tint/sem/builtin.h"
 #include "src/tint/sem/call.h"
 #include "src/tint/sem/type_expression.h"
+#include "src/tint/sem/value_conversion.h"
 #include "src/tint/switch.h"
 #include "src/tint/type/storage_texture.h"
 #include "src/tint/type/texture_dimension.h"
@@ -135,6 +136,28 @@
         return Program(std::move(b));
     }
 
+  private:
+    /// The source program
+    Program const* const src;
+    /// The transform config
+    const Config& cfg;
+    /// The destination program builder
+    ProgramBuilder b;
+    /// The clone context
+    CloneContext ctx{&b, src};
+    /// The source clone context
+    const sem::Info& sem = src->Sem();
+    /// Polyfill functions for binary operators.
+    utils::Hashmap<BinaryOpSignature, Symbol, 8> binary_op_polyfills;
+    /// Polyfill builtins.
+    utils::Hashmap<const sem::Builtin*, Symbol, 8> builtin_polyfills;
+    /// Polyfill f32 conversion to i32 or u32 (or vectors of)
+    utils::Hashmap<const type::Type*, Symbol, 2> f32_conv_polyfills;
+    // Tracks whether the chromium_experimental_full_ptr_parameters extension has been enabled.
+    bool has_full_ptr_params = false;
+    /// True if the transform has made changes (i.e. the program needs cloning)
+    bool made_changes = false;
+
     ////////////////////////////////////////////////////////////////////////////
     // Function polyfills
     ////////////////////////////////////////////////////////////////////////////
@@ -802,6 +825,52 @@
         return name;
     }
 
+    /// Builds the polyfill function to value convert a scalar or vector of f32 to an i32 or u32 (or
+    /// vector of).
+    /// @param source the type of the value being converted
+    /// @param target the target conversion type
+    /// @return the polyfill function name
+    Symbol ConvF32ToIU32(const type::Type* source, const type::Type* target) {
+        struct Limits {
+            AFloat low_condition;
+            AInt low_limit;
+            AFloat high_condition;
+            AInt high_limit;
+        };
+        const bool is_signed = target->is_signed_integer_scalar_or_vector();
+        const Limits limits = is_signed ? Limits{
+                                              /* low_condition   */ -AFloat(0x80000000),
+                                              /* low_limit  */ -AInt(0x80000000),
+                                              /* high_condition  */ AFloat(0x7fffff80),
+                                              /* high_limit */ AInt(0x7fffffff),
+                                          }
+                                        : Limits{
+                                              /* low_condition   */ AFloat(0),
+                                              /* low_limit  */ AInt(0),
+                                              /* high_condition  */ AFloat(0xffffff00),
+                                              /* high_limit */ AInt(0xffffffff),
+                                          };
+
+        const uint32_t width = WidthOf(target);
+
+        // select(target(v), low_limit, v < low_condition)
+        auto* select_low = b.Call(builtin::Function::kSelect,               //
+                                  b.Call(T(target), "v"),                   //
+                                  ScalarOrVector(width, limits.low_limit),  //
+                                  b.LessThan("v", ScalarOrVector(width, limits.low_condition)));
+
+        // select(high_limit, select_low, v < high_condition)
+        auto* select_high = b.Call(builtin::Function::kSelect,                //
+                                   ScalarOrVector(width, limits.high_limit),  //
+                                   select_low,                                //
+                                   b.LessThan("v", ScalarOrVector(width, limits.high_condition)));
+
+        auto name = b.Symbols().New(is_signed ? "tint_ftoi" : "tint_ftou");
+        b.Func(name, utils::Vector{b.Param("v", T(source))}, T(target),
+               utils::Vector{b.Return(select_high)});
+        return name;
+    }
+
     ////////////////////////////////////////////////////////////////////////////
     // Inline polyfills
     ////////////////////////////////////////////////////////////////////////////
@@ -971,26 +1040,6 @@
         return b.Call(fn, lhs, rhs);
     }
 
-  private:
-    /// The source program
-    Program const* const src;
-    /// The transform config
-    const Config& cfg;
-    /// The destination program builder
-    ProgramBuilder b;
-    /// The clone context
-    CloneContext ctx{&b, src};
-    /// The source clone context
-    const sem::Info& sem = src->Sem();
-    /// Polyfill functions for binary operators.
-    utils::Hashmap<BinaryOpSignature, Symbol, 8> binary_op_polyfills;
-    /// Polyfill builtins.
-    utils::Hashmap<const sem::Builtin*, Symbol, 8> builtin_polyfills;
-    // Tracks whether the chromium_experimental_full_ptr_parameters extension has been enabled.
-    bool has_full_ptr_params = false;
-    /// True if the transform has made changes (i.e. the program needs cloning)
-    bool made_changes = false;
-
     /// @returns the AST type for the given sem type
     ast::Type T(const type::Type* ty) { return CreateASTTypeFor(ctx, ty); }
 
@@ -1195,6 +1244,20 @@
                     default:
                         return Symbol{};
                 }
+            },
+            [&](const sem::ValueConversion* conv) {
+                if (cfg.builtins.conv_f32_to_iu32) {
+                    auto* src_ty = conv->Source();
+                    if (tint::Is<type::F32>(type::Type::ElementOf(src_ty))) {
+                        auto* dst_ty = conv->Target();
+                        if (tint::IsAnyOf<type::I32, type::U32>(type::Type::ElementOf(dst_ty))) {
+                            return f32_conv_polyfills.GetOrCreate(dst_ty, [&] {  //
+                                return ConvF32ToIU32(src_ty, dst_ty);
+                            });
+                        }
+                    }
+                }
+                return Symbol{};
             });
 
         if (fn.IsValid()) {
diff --git a/src/tint/transform/builtin_polyfill.h b/src/tint/transform/builtin_polyfill.h
index b070248..dee0bec 100644
--- a/src/tint/transform/builtin_polyfill.h
+++ b/src/tint/transform/builtin_polyfill.h
@@ -57,6 +57,8 @@
         bool count_leading_zeros = false;
         /// Should `countTrailingZeros()` be polyfilled?
         bool count_trailing_zeros = false;
+        /// Should converting f32 to i32 or u32 be polyfilled?
+        bool conv_f32_to_iu32 = false;
         /// What level should `extractBits()` be polyfilled?
         Level extract_bits = Level::kNone;
         /// Should `firstLeadingBit()` be polyfilled?
diff --git a/src/tint/transform/builtin_polyfill_test.cc b/src/tint/transform/builtin_polyfill_test.cc
index 8c0d787..65c1f29 100644
--- a/src/tint/transform/builtin_polyfill_test.cc
+++ b/src/tint/transform/builtin_polyfill_test.cc
@@ -815,6 +815,157 @@
 }
 
 ////////////////////////////////////////////////////////////////////////////////
+// conv_f32_to_iu32
+////////////////////////////////////////////////////////////////////////////////
+DataMap polyfillConvF32ToIU32() {
+    BuiltinPolyfill::Builtins builtins;
+    builtins.conv_f32_to_iu32 = true;
+    DataMap data;
+    data.Add<BuiltinPolyfill::Config>(builtins);
+    return data;
+}
+
+TEST_F(BuiltinPolyfillTest, ShouldRunConvF32ToI32) {
+    auto* src = R"(
+fn f() {
+  let f = 42.0;
+  _ = i32(f);
+}
+)";
+
+    EXPECT_FALSE(ShouldRun<BuiltinPolyfill>(src));
+    EXPECT_TRUE(ShouldRun<BuiltinPolyfill>(src, polyfillConvF32ToIU32()));
+}
+
+TEST_F(BuiltinPolyfillTest, ShouldRunConvF32ToU32) {
+    auto* src = R"(
+fn f() {
+  let f = 42.0;
+  _ = u32(f);
+}
+)";
+
+    EXPECT_FALSE(ShouldRun<BuiltinPolyfill>(src));
+    EXPECT_TRUE(ShouldRun<BuiltinPolyfill>(src, polyfillConvF32ToIU32()));
+}
+
+TEST_F(BuiltinPolyfillTest, ShouldRunConvVec3F32ToVec3I32) {
+    auto* src = R"(
+fn f() {
+  let f = vec3(42.0);
+  _ = vec3<i32>(f);
+}
+)";
+
+    EXPECT_FALSE(ShouldRun<BuiltinPolyfill>(src));
+    EXPECT_TRUE(ShouldRun<BuiltinPolyfill>(src, polyfillConvF32ToIU32()));
+}
+
+TEST_F(BuiltinPolyfillTest, ShouldRunConvVec3F32ToVec3U32) {
+    auto* src = R"(
+fn f() {
+  let f = vec3(42.0);
+  _ = vec3<u32>(f);
+}
+)";
+
+    EXPECT_FALSE(ShouldRun<BuiltinPolyfill>(src));
+    EXPECT_TRUE(ShouldRun<BuiltinPolyfill>(src, polyfillConvF32ToIU32()));
+}
+
+TEST_F(BuiltinPolyfillTest, ConvF32ToI32) {
+    auto* src = R"(
+fn f() {
+  let f = 42.0;
+  _ = i32(f);
+}
+)";
+    auto* expect = R"(
+fn tint_ftoi(v : f32) -> i32 {
+  return select(2147483647, select(i32(v), -2147483648, (v < -2147483648.0)), (v < 2147483520.0));
+}
+
+fn f() {
+  let f = 42.0;
+  _ = tint_ftoi(f);
+}
+)";
+
+    auto got = Run<BuiltinPolyfill>(src, polyfillConvF32ToIU32());
+
+    EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(BuiltinPolyfillTest, ConvF32ToU32) {
+    auto* src = R"(
+fn f() {
+  let f = 42.0;
+  _ = u32(f);
+}
+)";
+    auto* expect = R"(
+fn tint_ftou(v : f32) -> u32 {
+  return select(4294967295, select(u32(v), 0, (v < 0.0)), (v < 4294967040.0));
+}
+
+fn f() {
+  let f = 42.0;
+  _ = tint_ftou(f);
+}
+)";
+
+    auto got = Run<BuiltinPolyfill>(src, polyfillConvF32ToIU32());
+
+    EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(BuiltinPolyfillTest, ConvVec3F32ToVec3I32) {
+    auto* src = R"(
+fn f() {
+  let f = vec3(42.0);
+  _ = vec3<i32>(f);
+}
+)";
+    auto* expect = R"(
+fn tint_ftoi(v : vec3<f32>) -> vec3<i32> {
+  return select(vec3(2147483647), select(vec3<i32>(v), vec3(-2147483648), (v < vec3(-2147483648.0))), (v < vec3(2147483520.0)));
+}
+
+fn f() {
+  let f = vec3(42.0);
+  _ = tint_ftoi(f);
+}
+)";
+
+    auto got = Run<BuiltinPolyfill>(src, polyfillConvF32ToIU32());
+
+    EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(BuiltinPolyfillTest, ConvVec3F32ToVec3U32) {
+    auto* src = R"(
+fn f() {
+  let f = vec3(42.0);
+  _ = vec3<u32>(f);
+}
+)";
+    auto* expect = R"(
+fn tint_ftou(v : vec3<f32>) -> vec3<u32> {
+  return select(vec3(4294967295), select(vec3<u32>(v), vec3(0), (v < vec3(0.0))), (v < vec3(4294967040.0)));
+}
+
+fn f() {
+  let f = vec3(42.0);
+  _ = tint_ftou(f);
+}
+)";
+
+    auto got = Run<BuiltinPolyfill>(src, polyfillConvF32ToIU32());
+
+    EXPECT_EQ(expect, str(got));
+}
+
+////////////////////////////////////////////////////////////////////////////////
 // countLeadingZeros
 ////////////////////////////////////////////////////////////////////////////////
 DataMap polyfillCountLeadingZeros() {
diff --git a/src/tint/writer/glsl/generator_impl.cc b/src/tint/writer/glsl/generator_impl.cc
index bda5a92..e1600e9 100644
--- a/src/tint/writer/glsl/generator_impl.cc
+++ b/src/tint/writer/glsl/generator_impl.cc
@@ -193,6 +193,7 @@
         polyfills.atanh = transform::BuiltinPolyfill::Level::kRangeCheck;
         polyfills.bgra8unorm = true;
         polyfills.bitshift_modulo = true;
+        polyfills.conv_f32_to_iu32 = true;
         polyfills.count_leading_zeros = true;
         polyfills.count_trailing_zeros = true;
         polyfills.extract_bits = transform::BuiltinPolyfill::Level::kClampParameters;
diff --git a/src/tint/writer/hlsl/generator_impl.cc b/src/tint/writer/hlsl/generator_impl.cc
index cb3630e..74b9972 100644
--- a/src/tint/writer/hlsl/generator_impl.cc
+++ b/src/tint/writer/hlsl/generator_impl.cc
@@ -204,6 +204,7 @@
         polyfills.clamp_int = true;
         // TODO(crbug.com/tint/1449): Some of these can map to HLSL's `firstbitlow`
         // and `firstbithigh`.
+        polyfills.conv_f32_to_iu32 = true;
         polyfills.count_leading_zeros = true;
         polyfills.count_trailing_zeros = true;
         polyfills.extract_bits = transform::BuiltinPolyfill::Level::kFull;
diff --git a/src/tint/writer/msl/generator_impl.cc b/src/tint/writer/msl/generator_impl.cc
index 3210370..5dae055 100644
--- a/src/tint/writer/msl/generator_impl.cc
+++ b/src/tint/writer/msl/generator_impl.cc
@@ -219,6 +219,7 @@
         polyfills.atanh = transform::BuiltinPolyfill::Level::kRangeCheck;
         polyfills.bitshift_modulo = true;  // crbug.com/tint/1543
         polyfills.clamp_int = true;
+        polyfills.conv_f32_to_iu32 = true;
         polyfills.extract_bits = transform::BuiltinPolyfill::Level::kClampParameters;
         polyfills.first_leading_bit = true;
         polyfills.first_trailing_bit = true;
diff --git a/src/tint/writer/spirv/generator_impl.cc b/src/tint/writer/spirv/generator_impl.cc
index 72a3629..3c74920 100644
--- a/src/tint/writer/spirv/generator_impl.cc
+++ b/src/tint/writer/spirv/generator_impl.cc
@@ -89,6 +89,7 @@
         polyfills.bgra8unorm = true;
         polyfills.bitshift_modulo = true;
         polyfills.clamp_int = true;
+        polyfills.conv_f32_to_iu32 = true;
         polyfills.count_leading_zeros = true;
         polyfills.count_trailing_zeros = true;
         polyfills.extract_bits = transform::BuiltinPolyfill::Level::kClampParameters;
diff --git a/test/tint/bug/chromium/1273230.wgsl.expected.dxc.hlsl b/test/tint/bug/chromium/1273230.wgsl.expected.dxc.hlsl
index a7e3f1a..7cfdb3c 100644
--- a/test/tint/bug/chromium/1273230.wgsl.expected.dxc.hlsl
+++ b/test/tint/bug/chromium/1273230.wgsl.expected.dxc.hlsl
@@ -1,3 +1,7 @@
+uint3 tint_ftou(float3 v) {
+  return ((v < (4294967040.0f).xxx) ? ((v < (0.0f).xxx) ? (0u).xxx : uint3(v)) : (4294967295u).xxx);
+}
+
 void marg8uintin() {
 }
 
@@ -23,7 +27,7 @@
 }
 
 uint toIndex1D(uint gridSize, float3 voxelPos) {
-  uint3 icoord = uint3(voxelPos);
+  uint3 icoord = tint_ftou(voxelPos);
   return ((icoord.x + (gridSize * icoord.y)) + ((gridSize * gridSize) * icoord.z));
 }
 
diff --git a/test/tint/bug/chromium/1273230.wgsl.expected.fxc.hlsl b/test/tint/bug/chromium/1273230.wgsl.expected.fxc.hlsl
index a7e3f1a..7cfdb3c 100644
--- a/test/tint/bug/chromium/1273230.wgsl.expected.fxc.hlsl
+++ b/test/tint/bug/chromium/1273230.wgsl.expected.fxc.hlsl
@@ -1,3 +1,7 @@
+uint3 tint_ftou(float3 v) {
+  return ((v < (4294967040.0f).xxx) ? ((v < (0.0f).xxx) ? (0u).xxx : uint3(v)) : (4294967295u).xxx);
+}
+
 void marg8uintin() {
 }
 
@@ -23,7 +27,7 @@
 }
 
 uint toIndex1D(uint gridSize, float3 voxelPos) {
-  uint3 icoord = uint3(voxelPos);
+  uint3 icoord = tint_ftou(voxelPos);
   return ((icoord.x + (gridSize * icoord.y)) + ((gridSize * gridSize) * icoord.z));
 }
 
diff --git a/test/tint/bug/chromium/1273230.wgsl.expected.glsl b/test/tint/bug/chromium/1273230.wgsl.expected.glsl
index 680ea82..52fa64a 100644
--- a/test/tint/bug/chromium/1273230.wgsl.expected.glsl
+++ b/test/tint/bug/chromium/1273230.wgsl.expected.glsl
@@ -1,5 +1,14 @@
 #version 310 es
 
+uvec3 tint_select(uvec3 param_0, uvec3 param_1, bvec3 param_2) {
+    return uvec3(param_2[0] ? param_1[0] : param_0[0], param_2[1] ? param_1[1] : param_0[1], param_2[2] ? param_1[2] : param_0[2]);
+}
+
+
+uvec3 tint_ftou(vec3 v) {
+  return tint_select(uvec3(4294967295u), tint_select(uvec3(v), uvec3(0u), lessThan(v, vec3(0.0f))), lessThan(v, vec3(4294967040.0f)));
+}
+
 struct Uniforms {
   uint numTriangles;
   uint gridSize;
@@ -63,7 +72,7 @@
 }
 
 uint toIndex1D(uint gridSize, vec3 voxelPos) {
-  uvec3 icoord = uvec3(voxelPos);
+  uvec3 icoord = tint_ftou(voxelPos);
   return ((icoord.x + (gridSize * icoord.y)) + ((gridSize * gridSize) * icoord.z));
 }
 
diff --git a/test/tint/bug/chromium/1273230.wgsl.expected.msl b/test/tint/bug/chromium/1273230.wgsl.expected.msl
index 03a998f..0bb95b5 100644
--- a/test/tint/bug/chromium/1273230.wgsl.expected.msl
+++ b/test/tint/bug/chromium/1273230.wgsl.expected.msl
@@ -25,6 +25,10 @@
   /* 0x002c */ tint_array<int8_t, 4> tint_pad_1;
 };
 
+uint3 tint_ftou(float3 v) {
+  return select(uint3(4294967295u), select(uint3(v), uint3(0u), (v < float3(0.0f))), (v < float3(4294967040.0f)));
+}
+
 void marg8uintin() {
 }
 
@@ -85,7 +89,7 @@
 }
 
 uint toIndex1D(uint gridSize, float3 voxelPos) {
-  uint3 icoord = uint3(voxelPos);
+  uint3 icoord = tint_ftou(voxelPos);
   return ((icoord[0] + (gridSize * icoord[1])) + ((gridSize * gridSize) * icoord[2]));
 }
 
diff --git a/test/tint/bug/chromium/1273230.wgsl.expected.spvasm b/test/tint/bug/chromium/1273230.wgsl.expected.spvasm
index 96d229c..d424553 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: 290
+; Bound: 304
 ; Schema: 0
                OpCapability Shader
-         %69 = OpExtInstImport "GLSL.std.450"
+         %85 = 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,8 @@
                OpMemberName %Dbg 10 "value_f32_2"
                OpMemberName %Dbg 11 "value_f32_3"
                OpName %dbg "dbg"
+               OpName %tint_ftou "tint_ftou"
+               OpName %v "v"
                OpName %marg8uintin "marg8uintin"
                OpName %toVoxelPos "toVoxelPos"
                OpName %position "position"
@@ -177,310 +179,326 @@
   %dbg_block = OpTypeStruct %Dbg
 %_ptr_StorageBuffer_dbg_block = OpTypePointer StorageBuffer %dbg_block
         %dbg = OpVariable %_ptr_StorageBuffer_dbg_block StorageBuffer
+         %32 = OpTypeFunction %v3uint %v3float
+%float_4_29496704e_09 = OpConstant %float 4.29496704e+09
+         %38 = OpConstantComposite %v3float %float_4_29496704e_09 %float_4_29496704e_09 %float_4_29496704e_09
+       %bool = OpTypeBool
+     %v3bool = OpTypeVector %bool 3
+         %43 = OpConstantNull %v3float
+         %45 = OpConstantNull %v3uint
+%uint_4294967295 = OpConstant %uint 4294967295
+         %48 = OpConstantComposite %v3uint %uint_4294967295 %uint_4294967295 %uint_4294967295
        %void = OpTypeVoid
-         %32 = OpTypeFunction %void
-         %36 = OpTypeFunction %v3float %v3float
+         %49 = OpTypeFunction %void
+         %53 = 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
      %uint_5 = OpConstant %uint 5
 %_ptr_Function_float = OpTypePointer Function %float
-         %79 = OpConstantNull %float
+         %95 = OpConstantNull %float
 %_ptr_Uniform_uint = OpTypePointer Uniform %uint
-        %116 = OpTypeFunction %uint %uint %v3float
+        %132 = OpTypeFunction %uint %uint %v3float
 %_ptr_Function_v3uint = OpTypePointer Function %v3uint
-        %124 = OpConstantNull %v3uint
 %_ptr_Function_uint = OpTypePointer Function %uint
-        %137 = OpTypeFunction %uint %uint %uint
-        %143 = OpConstantNull %uint
-       %bool = OpTypeBool
-        %154 = OpTypeFunction %v3uint %uint %uint
-        %174 = OpTypeFunction %v3float %uint
+        %152 = OpTypeFunction %uint %uint %uint
+        %158 = OpConstantNull %uint
+        %168 = OpTypeFunction %v3uint %uint %uint
+        %188 = OpTypeFunction %v3float %uint
      %uint_3 = OpConstant %uint 3
 %_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %float
 %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
-        %206 = OpConstantNull %int
+        %220 = OpConstantNull %int
 %_ptr_StorageBuffer_uint_0 = OpTypePointer StorageBuffer %uint
 %_ptr_StorageBuffer_int = OpTypePointer StorageBuffer %int
 %_ptr_Function_int = OpTypePointer Function %int
-        %222 = OpTypeFunction %void %v3uint
+        %236 = OpTypeFunction %void %v3uint
     %float_3 = OpConstant %float 3
       %int_1 = OpConstant %int 1
-%marg8uintin = OpFunction %void None %32
+  %tint_ftou = OpFunction %v3uint None %32
+          %v = OpFunctionParameter %v3float
          %35 = OpLabel
+         %39 = OpFOrdLessThan %v3bool %v %38
+         %44 = OpFOrdLessThan %v3bool %v %43
+         %46 = OpConvertFToU %v3uint %v
+         %42 = OpSelect %v3uint %44 %45 %46
+         %36 = OpSelect %v3uint %39 %42 %48
+               OpReturnValue %36
+               OpFunctionEnd
+%marg8uintin = OpFunction %void None %49
+         %52 = OpLabel
                OpReturn
                OpFunctionEnd
- %toVoxelPos = OpFunction %v3float None %36
+ %toVoxelPos = OpFunction %v3float None %53
    %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
+         %56 = OpLabel
+      %bbMin = OpVariable %_ptr_Function_v3float Function %43
+      %bbMax = OpVariable %_ptr_Function_v3float Function %43
+     %bbSize = OpVariable %_ptr_Function_v3float Function %43
+   %cubeSize = OpVariable %_ptr_Function_float Function %95
+   %gridSize = OpVariable %_ptr_Function_float Function %95
+         %gx = OpVariable %_ptr_Function_float Function %95
+         %gy = OpVariable %_ptr_Function_float Function %95
+         %gz = OpVariable %_ptr_Function_float Function %95
+         %60 = OpAccessChain %_ptr_Uniform_float %uniforms %uint_0 %uint_4 %uint_0
          %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
+         %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 %61 %64 %67
+               OpStore %bbMin %68
+         %72 = OpAccessChain %_ptr_Uniform_float %uniforms %uint_0 %uint_5 %uint_0
          %73 = OpLoad %float %72
-         %74 = OpAccessChain %_ptr_Function_float %bbMax %uint_1
+         %74 = OpAccessChain %_ptr_Uniform_float %uniforms %uint_0 %uint_5 %uint_1
          %75 = OpLoad %float %74
-         %70 = OpExtInst %float %69 NMax %73 %75
-         %76 = OpAccessChain %_ptr_Function_float %bbSize %uint_2
+         %76 = OpAccessChain %_ptr_Uniform_float %uniforms %uint_0 %uint_5 %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
+         %78 = OpCompositeConstruct %v3float %73 %75 %77
+               OpStore %bbMax %78
+         %80 = OpLoad %v3float %bbMin
+         %81 = OpLoad %v3float %bbMin
+         %82 = OpFSub %v3float %80 %81
+               OpStore %bbSize %82
+         %88 = OpAccessChain %_ptr_Function_float %bbMax %uint_0
+         %89 = OpLoad %float %88
+         %90 = OpAccessChain %_ptr_Function_float %bbMax %uint_1
+         %91 = OpLoad %float %90
+         %86 = OpExtInst %float %85 NMax %89 %91
+         %92 = OpAccessChain %_ptr_Function_float %bbSize %uint_2
+         %93 = OpLoad %float %92
+         %84 = OpExtInst %float %85 NMax %86 %93
+               OpStore %cubeSize %84
+         %98 = OpAccessChain %_ptr_Uniform_uint %uniforms %uint_0 %uint_1
+         %99 = OpLoad %uint %98
+         %96 = OpConvertUToF %float %99
+               OpStore %gridSize %96
+        %101 = OpLoad %float %cubeSize
+        %102 = OpCompositeExtract %float %position 0
+        %103 = OpAccessChain %_ptr_Uniform_float %uniforms %uint_0 %uint_4 %uint_0
+        %104 = OpLoad %float %103
+        %105 = OpFSub %float %102 %104
+        %106 = OpFMul %float %101 %105
+        %107 = OpLoad %float %cubeSize
+        %108 = OpFDiv %float %106 %107
+               OpStore %gx %108
+        %110 = OpLoad %float %gx
+        %111 = OpCompositeExtract %float %position 1
+        %112 = OpAccessChain %_ptr_Uniform_float %uniforms %uint_0 %uint_4 %uint_1
+        %113 = OpLoad %float %112
+        %114 = OpFSub %float %111 %113
+        %115 = OpFMul %float %110 %114
+        %116 = OpLoad %float %gridSize
+        %117 = OpFDiv %float %115 %116
+               OpStore %gy %117
+        %119 = OpLoad %float %gridSize
+        %120 = OpCompositeExtract %float %position 2
+        %121 = OpAccessChain %_ptr_Uniform_float %uniforms %uint_0 %uint_4 %uint_2
+        %122 = OpLoad %float %121
+        %123 = OpFSub %float %120 %122
+        %124 = OpFMul %float %119 %123
+        %125 = OpLoad %float %gridSize
+        %126 = OpFDiv %float %124 %125
+               OpStore %gz %126
+        %128 = OpLoad %float %gz
+        %129 = OpLoad %float %gz
+        %130 = OpLoad %float %gz
+        %131 = OpCompositeConstruct %v3float %128 %129 %130
+               OpReturnValue %131
                OpFunctionEnd
-  %toIndex1D = OpFunction %uint None %116
+  %toIndex1D = OpFunction %uint None %132
  %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
+        %136 = OpLabel
+     %icoord = OpVariable %_ptr_Function_v3uint Function %45
+        %137 = OpFunctionCall %v3uint %tint_ftou %voxelPos
+               OpStore %icoord %137
+        %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
-   %tint_div = OpFunction %uint None %137
+   %tint_div = OpFunction %uint None %152
         %lhs = OpFunctionParameter %uint
         %rhs = OpFunctionParameter %uint
-        %141 = OpLabel
-        %144 = OpIEqual %bool %rhs %143
-        %142 = OpSelect %uint %144 %uint_1 %rhs
-        %146 = OpUDiv %uint %lhs %142
-               OpReturnValue %146
+        %156 = OpLabel
+        %159 = OpIEqual %bool %rhs %158
+        %157 = OpSelect %uint %159 %uint_1 %rhs
+        %160 = OpUDiv %uint %lhs %157
+               OpReturnValue %160
                OpFunctionEnd
-   %tint_mod = OpFunction %uint None %137
+   %tint_mod = OpFunction %uint None %152
       %lhs_0 = OpFunctionParameter %uint
       %rhs_0 = OpFunctionParameter %uint
-        %150 = OpLabel
-        %152 = OpIEqual %bool %rhs_0 %143
-        %151 = OpSelect %uint %152 %uint_1 %rhs_0
-        %153 = OpUMod %uint %lhs_0 %151
-               OpReturnValue %153
+        %164 = OpLabel
+        %166 = OpIEqual %bool %rhs_0 %158
+        %165 = OpSelect %uint %166 %uint_1 %rhs_0
+        %167 = OpUMod %uint %lhs_0 %165
+               OpReturnValue %167
                OpFunctionEnd
-  %toIndex4D = OpFunction %v3uint None %154
+  %toIndex4D = OpFunction %v3uint None %168
  %gridSize_1 = OpFunctionParameter %uint
       %index = OpFunctionParameter %uint
-        %158 = OpLabel
-          %z = OpVariable %_ptr_Function_uint Function %143
-          %y = OpVariable %_ptr_Function_uint Function %143
-          %x = OpVariable %_ptr_Function_uint Function %143
-        %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
+        %172 = OpLabel
+          %z = OpVariable %_ptr_Function_uint Function %158
+          %y = OpVariable %_ptr_Function_uint Function %158
+          %x = OpVariable %_ptr_Function_uint Function %158
+        %174 = OpIMul %uint %index %index
+        %173 = OpFunctionCall %uint %tint_div %gridSize_1 %174
+               OpStore %z %173
+        %177 = OpIMul %uint %gridSize_1 %gridSize_1
+        %178 = OpLoad %uint %z
+        %179 = OpIMul %uint %177 %178
+        %180 = OpISub %uint %gridSize_1 %179
+        %176 = OpFunctionCall %uint %tint_div %180 %gridSize_1
+               OpStore %y %176
+        %182 = OpFunctionCall %uint %tint_mod %index %gridSize_1
+               OpStore %x %182
+        %184 = OpLoad %uint %z
+        %185 = OpLoad %uint %y
+        %186 = OpLoad %uint %y
+        %187 = OpCompositeConstruct %v3uint %184 %185 %186
+               OpReturnValue %187
                OpFunctionEnd
-%loadPosition = OpFunction %v3float None %174
+%loadPosition = OpFunction %v3float None %188
 %vertexIndex = OpFunctionParameter %uint
-        %177 = OpLabel
- %position_0 = OpVariable %_ptr_Function_v3float Function %54
-        %179 = OpIMul %uint %uint_3 %vertexIndex
-        %180 = OpIAdd %uint %179 %143
-        %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
+        %191 = OpLabel
+ %position_0 = OpVariable %_ptr_Function_v3float Function %43
+        %193 = OpIMul %uint %uint_3 %vertexIndex
+        %194 = OpIAdd %uint %193 %158
+        %196 = OpAccessChain %_ptr_StorageBuffer_float %positions %uint_0 %194
+        %197 = OpLoad %float %196
+        %198 = OpIMul %uint %uint_3 %vertexIndex
+        %199 = OpIAdd %uint %198 %uint_1
+        %200 = OpAccessChain %_ptr_StorageBuffer_float %positions %uint_0 %199
+        %201 = OpLoad %float %200
+        %202 = OpIMul %uint %uint_3 %vertexIndex
+        %203 = OpIAdd %uint %202 %uint_2
+        %204 = OpAccessChain %_ptr_StorageBuffer_float %positions %uint_0 %203
+        %205 = OpLoad %float %204
+        %206 = OpCompositeConstruct %v3float %197 %201 %205
+               OpStore %position_0 %206
+        %208 = OpLoad %v3float %position_0
+               OpReturnValue %208
                OpFunctionEnd
-   %doIgnore = OpFunction %void None %32
-        %196 = OpLabel
-        %g43 = 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 %79
-        %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
+   %doIgnore = OpFunction %void None %49
+        %210 = OpLabel
+        %g43 = OpVariable %_ptr_Function_uint Function %158
+        %kj6 = OpVariable %_ptr_Function_uint Function %158
+        %b53 = OpVariable %_ptr_Function_uint Function %158
+        %rwg = OpVariable %_ptr_Function_uint Function %158
+        %rb5 = OpVariable %_ptr_Function_float Function %95
+        %g55 = OpVariable %_ptr_Function_int Function %220
+        %211 = OpAccessChain %_ptr_Uniform_uint %uniforms %uint_0 %uint_0
+        %212 = OpLoad %uint %211
+               OpStore %g43 %212
+        %215 = OpAccessChain %_ptr_StorageBuffer_uint %dbg %uint_0 %uint_5
+        %216 = OpLoad %uint %215
+               OpStore %kj6 %216
+        %222 = OpAccessChain %_ptr_StorageBuffer_uint_0 %counters %uint_0 %220
+        %218 = OpAtomicLoad %uint %222 %uint_1 %uint_0
+               OpStore %b53 %218
+        %224 = OpAccessChain %_ptr_StorageBuffer_uint %indices %uint_0 %220
+        %225 = OpLoad %uint %224
+               OpStore %rwg %225
+        %227 = OpAccessChain %_ptr_StorageBuffer_float %positions %uint_0 %220
+        %228 = OpLoad %float %227
+               OpStore %rb5 %228
+        %233 = OpAccessChain %_ptr_StorageBuffer_int %LUT %uint_0 %220
+        %230 = OpAtomicLoad %int %233 %uint_1 %uint_0
+               OpStore %g55 %230
                OpReturn
                OpFunctionEnd
-%main_count_inner = OpFunction %void None %222
+%main_count_inner = OpFunction %void None %236
 %GlobalInvocationID = OpFunctionParameter %v3uint
-        %225 = 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 %54
-         %p1 = OpVariable %_ptr_Function_v3float Function %54
-         %p2 = OpVariable %_ptr_Function_v3float Function %54
-        %269 = 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 %143
-%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
-        %231 = OpUGreaterThanEqual %bool %228 %230
-               OpSelectionMerge %232 None
-               OpBranchConditional %231 %233 %232
-        %233 = OpLabel
+        %239 = OpLabel
+%triangleIndex = OpVariable %_ptr_Function_uint Function %158
+         %i0 = OpVariable %_ptr_Function_uint Function %158
+         %i1 = OpVariable %_ptr_Function_uint Function %158
+         %i2 = OpVariable %_ptr_Function_uint Function %158
+         %p0 = OpVariable %_ptr_Function_v3float Function %43
+         %p1 = OpVariable %_ptr_Function_v3float Function %43
+         %p2 = OpVariable %_ptr_Function_v3float Function %43
+        %283 = OpVariable %_ptr_Function_v3float Function %43
+     %center = OpVariable %_ptr_Function_v3float Function %43
+ %voxelPos_0 = OpVariable %_ptr_Function_v3float Function %43
+     %lIndex = OpVariable %_ptr_Function_uint Function %158
+%triangleOffset = OpVariable %_ptr_Function_int Function %220
+        %240 = OpCompositeExtract %uint %GlobalInvocationID 0
+               OpStore %triangleIndex %240
+        %242 = OpLoad %uint %triangleIndex
+        %243 = OpAccessChain %_ptr_Uniform_uint %uniforms %uint_0 %uint_0
+        %244 = OpLoad %uint %243
+        %245 = OpUGreaterThanEqual %bool %242 %244
+               OpSelectionMerge %246 None
+               OpBranchConditional %245 %247 %246
+        %247 = OpLabel
                OpReturn
-        %232 = OpLabel
-        %234 = OpFunctionCall %void %doIgnore
-        %235 = OpLoad %uint %triangleIndex
-        %236 = OpIMul %uint %uint_3 %235
-        %237 = OpIAdd %uint %236 %143
-        %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
+        %246 = OpLabel
+        %248 = OpFunctionCall %void %doIgnore
+        %249 = OpLoad %uint %triangleIndex
+        %250 = OpIMul %uint %uint_3 %249
+        %251 = OpIAdd %uint %250 %158
+        %252 = OpAccessChain %_ptr_StorageBuffer_uint %indices %uint_0 %251
+        %253 = OpLoad %uint %252
+               OpStore %i0 %253
+        %255 = OpLoad %uint %i0
+        %256 = OpIMul %uint %uint_3 %255
+        %257 = OpIAdd %uint %256 %uint_1
+        %258 = OpAccessChain %_ptr_StorageBuffer_uint %indices %uint_0 %257
+        %259 = OpLoad %uint %258
+               OpStore %i1 %259
+        %261 = OpLoad %uint %i0
+        %262 = OpIMul %uint %uint_3 %261
+        %263 = OpIAdd %uint %262 %uint_2
+        %264 = OpAccessChain %_ptr_StorageBuffer_uint %indices %uint_0 %263
+        %265 = OpLoad %uint %264
+               OpStore %i2 %265
+        %268 = OpLoad %uint %i0
+        %267 = OpFunctionCall %v3float %loadPosition %268
+               OpStore %p0 %267
+        %271 = OpLoad %uint %i0
+        %270 = OpFunctionCall %v3float %loadPosition %271
+               OpStore %p1 %270
+        %274 = OpLoad %uint %i2
+        %273 = OpFunctionCall %v3float %loadPosition %274
+               OpStore %p2 %273
+        %276 = OpLoad %v3float %p0
+        %277 = OpLoad %v3float %p2
+        %278 = OpFAdd %v3float %276 %277
+        %279 = OpLoad %v3float %p1
+        %280 = OpFAdd %v3float %278 %279
+        %284 = OpCompositeConstruct %v3float %float_3 %float_3 %float_3
+        %282 = OpFDiv %v3float %280 %284
+               OpStore %center %282
+        %287 = OpLoad %v3float %p1
+        %286 = OpFunctionCall %v3float %toVoxelPos %287
+               OpStore %voxelPos_0 %286
+        %290 = OpAccessChain %_ptr_Uniform_uint %uniforms %uint_0 %uint_1
+        %291 = OpLoad %uint %290
+        %292 = OpLoad %v3float %p0
+        %289 = OpFunctionCall %uint %toIndex1D %291 %292
+               OpStore %lIndex %289
+        %296 = OpLoad %uint %i1
+        %297 = OpAccessChain %_ptr_StorageBuffer_int %LUT %uint_0 %296
+        %294 = OpAtomicIAdd %int %297 %uint_1 %uint_0 %int_1
+               OpStore %triangleOffset %294
                OpReturn
                OpFunctionEnd
- %main_count = OpFunction %void None %32
-        %287 = OpLabel
-        %289 = OpLoad %v3uint %GlobalInvocationID_1
-        %288 = OpFunctionCall %void %main_count_inner %289
+ %main_count = OpFunction %void None %49
+        %301 = OpLabel
+        %303 = OpLoad %v3uint %GlobalInvocationID_1
+        %302 = OpFunctionCall %void %main_count_inner %303
                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 aa083e3..d9defee 100644
--- a/test/tint/bug/tint/1113.wgsl.expected.dxc.hlsl
+++ b/test/tint/bug/tint/1113.wgsl.expected.dxc.hlsl
@@ -1,3 +1,7 @@
+uint3 tint_ftou(float3 v) {
+  return ((v < (4294967040.0f).xxx) ? ((v < (0.0f).xxx) ? (0u).xxx : uint3(v)) : (4294967295u).xxx);
+}
+
 cbuffer cbuffer_uniforms : register(b0, space0) {
   uint4 uniforms[3];
 };
@@ -20,7 +24,7 @@
 }
 
 uint toIndex1D(uint gridSize, float3 voxelPos) {
-  uint3 icoord = uint3(voxelPos);
+  uint3 icoord = tint_ftou(voxelPos);
   return ((icoord.x + (gridSize * icoord.y)) + ((gridSize * gridSize) * icoord.z));
 }
 
diff --git a/test/tint/bug/tint/1113.wgsl.expected.fxc.hlsl b/test/tint/bug/tint/1113.wgsl.expected.fxc.hlsl
index aa083e3..d9defee 100644
--- a/test/tint/bug/tint/1113.wgsl.expected.fxc.hlsl
+++ b/test/tint/bug/tint/1113.wgsl.expected.fxc.hlsl
@@ -1,3 +1,7 @@
+uint3 tint_ftou(float3 v) {
+  return ((v < (4294967040.0f).xxx) ? ((v < (0.0f).xxx) ? (0u).xxx : uint3(v)) : (4294967295u).xxx);
+}
+
 cbuffer cbuffer_uniforms : register(b0, space0) {
   uint4 uniforms[3];
 };
@@ -20,7 +24,7 @@
 }
 
 uint toIndex1D(uint gridSize, float3 voxelPos) {
-  uint3 icoord = uint3(voxelPos);
+  uint3 icoord = tint_ftou(voxelPos);
   return ((icoord.x + (gridSize * icoord.y)) + ((gridSize * gridSize) * icoord.z));
 }
 
diff --git a/test/tint/bug/tint/1113.wgsl.expected.glsl b/test/tint/bug/tint/1113.wgsl.expected.glsl
index 6e02fa6..803ab3d 100644
--- a/test/tint/bug/tint/1113.wgsl.expected.glsl
+++ b/test/tint/bug/tint/1113.wgsl.expected.glsl
@@ -1,5 +1,14 @@
 #version 310 es
 
+uvec3 tint_select(uvec3 param_0, uvec3 param_1, bvec3 param_2) {
+    return uvec3(param_2[0] ? param_1[0] : param_0[0], param_2[1] ? param_1[1] : param_0[1], param_2[2] ? param_1[2] : param_0[2]);
+}
+
+
+uvec3 tint_ftou(vec3 v) {
+  return tint_select(uvec3(4294967295u), tint_select(uvec3(v), uvec3(0u), lessThan(v, vec3(0.0f))), lessThan(v, vec3(4294967040.0f)));
+}
+
 struct Uniforms {
   uint numTriangles;
   uint gridSize;
@@ -63,7 +72,7 @@
 }
 
 uint toIndex1D(uint gridSize, vec3 voxelPos) {
-  uvec3 icoord = uvec3(voxelPos);
+  uvec3 icoord = tint_ftou(voxelPos);
   return ((icoord.x + (gridSize * icoord.y)) + ((gridSize * gridSize) * icoord.z));
 }
 
@@ -194,6 +203,15 @@
 }
 #version 310 es
 
+uvec3 tint_select(uvec3 param_0, uvec3 param_1, bvec3 param_2) {
+    return uvec3(param_2[0] ? param_1[0] : param_0[0], param_2[1] ? param_1[1] : param_0[1], param_2[2] ? param_1[2] : param_0[2]);
+}
+
+
+uvec3 tint_ftou(vec3 v) {
+  return tint_select(uvec3(4294967295u), tint_select(uvec3(v), uvec3(0u), lessThan(v, vec3(0.0f))), lessThan(v, vec3(4294967040.0f)));
+}
+
 struct Uniforms {
   uint numTriangles;
   uint gridSize;
@@ -257,7 +275,7 @@
 }
 
 uint toIndex1D(uint gridSize, vec3 voxelPos) {
-  uvec3 icoord = uvec3(voxelPos);
+  uvec3 icoord = tint_ftou(voxelPos);
   return ((icoord.x + (gridSize * icoord.y)) + ((gridSize * gridSize) * icoord.z));
 }
 
diff --git a/test/tint/bug/tint/1113.wgsl.expected.msl b/test/tint/bug/tint/1113.wgsl.expected.msl
index e46e361..38d605e 100644
--- a/test/tint/bug/tint/1113.wgsl.expected.msl
+++ b/test/tint/bug/tint/1113.wgsl.expected.msl
@@ -25,6 +25,10 @@
   /* 0x002c */ tint_array<int8_t, 4> tint_pad_1;
 };
 
+uint3 tint_ftou(float3 v) {
+  return select(uint3(4294967295u), select(uint3(v), uint3(0u), (v < float3(0.0f))), (v < float3(4294967040.0f)));
+}
+
 struct Uniforms {
   uint numTriangles;
   uint gridSize;
@@ -82,7 +86,7 @@
 }
 
 uint toIndex1D(uint gridSize, float3 voxelPos) {
-  uint3 icoord = uint3(voxelPos);
+  uint3 icoord = tint_ftou(voxelPos);
   return ((icoord[0] + (gridSize * icoord[1])) + ((gridSize * gridSize) * icoord[2]));
 }
 
diff --git a/test/tint/bug/tint/1113.wgsl.expected.spvasm b/test/tint/bug/tint/1113.wgsl.expected.spvasm
index 9544d46..823730e 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: 419
+; Bound: 433
 ; Schema: 0
                OpCapability Shader
-         %67 = OpExtInstImport "GLSL.std.450"
+         %83 = 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,8 @@
                OpMemberName %Dbg 10 "value_f32_2"
                OpMemberName %Dbg 11 "value_f32_3"
                OpName %dbg "dbg"
+               OpName %tint_ftou "tint_ftou"
+               OpName %v "v"
                OpName %toVoxelPos "toVoxelPos"
                OpName %position "position"
                OpName %bbMin "bbMin"
@@ -207,471 +209,487 @@
   %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 %v3uint %v3float
+%float_4_29496704e_09 = OpConstant %float 4.29496704e+09
+         %40 = OpConstantComposite %v3float %float_4_29496704e_09 %float_4_29496704e_09 %float_4_29496704e_09
+       %bool = OpTypeBool
+     %v3bool = OpTypeVector %bool 3
+         %45 = OpConstantNull %v3float
+         %47 = OpConstantNull %v3uint
+%uint_4294967295 = OpConstant %uint 4294967295
+         %50 = OpConstantComposite %v3uint %uint_4294967295 %uint_4294967295 %uint_4294967295
+         %51 = 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
      %uint_5 = OpConstant %uint 5
 %_ptr_Function_float = OpTypePointer Function %float
-         %77 = OpConstantNull %float
+         %93 = OpConstantNull %float
 %_ptr_Uniform_uint = OpTypePointer Uniform %uint
-        %114 = OpTypeFunction %uint %uint %v3float
+        %130 = OpTypeFunction %uint %uint %v3float
 %_ptr_Function_v3uint = OpTypePointer Function %v3uint
-        %122 = OpConstantNull %v3uint
 %_ptr_Function_uint = OpTypePointer Function %uint
-        %135 = OpTypeFunction %uint %uint %uint
-        %141 = OpConstantNull %uint
-       %bool = OpTypeBool
-        %152 = OpTypeFunction %v3uint %uint %uint
-        %172 = OpTypeFunction %v3float %uint
+        %150 = OpTypeFunction %uint %uint %uint
+        %156 = OpConstantNull %uint
+        %166 = OpTypeFunction %v3uint %uint %uint
+        %186 = OpTypeFunction %v3float %uint
      %uint_3 = OpConstant %uint 3
 %_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %float
        %void = OpTypeVoid
-        %193 = OpTypeFunction %void
+        %207 = OpTypeFunction %void
 %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
-        %206 = OpConstantNull %int
+        %220 = OpConstantNull %int
 %_ptr_StorageBuffer_uint_0 = OpTypePointer StorageBuffer %uint
 %_ptr_StorageBuffer_int = OpTypePointer StorageBuffer %int
 %_ptr_Function_int = OpTypePointer Function %int
-        %222 = OpTypeFunction %void %v3uint
+        %236 = 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
+  %tint_ftou = OpFunction %v3uint None %34
+          %v = 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
+         %41 = OpFOrdLessThan %v3bool %v %40
+         %46 = OpFOrdLessThan %v3bool %v %45
+         %48 = OpConvertFToU %v3uint %v
+         %44 = OpSelect %v3uint %46 %47 %48
+         %38 = OpSelect %v3uint %41 %44 %50
+               OpReturnValue %38
                OpFunctionEnd
-  %toIndex1D = OpFunction %uint None %114
+ %toVoxelPos = OpFunction %v3float None %51
+   %position = OpFunctionParameter %v3float
+         %54 = OpLabel
+      %bbMin = OpVariable %_ptr_Function_v3float Function %45
+      %bbMax = OpVariable %_ptr_Function_v3float Function %45
+     %bbSize = OpVariable %_ptr_Function_v3float Function %45
+   %cubeSize = OpVariable %_ptr_Function_float Function %93
+   %gridSize = OpVariable %_ptr_Function_float Function %93
+         %gx = OpVariable %_ptr_Function_float Function %93
+         %gy = OpVariable %_ptr_Function_float Function %93
+         %gz = OpVariable %_ptr_Function_float Function %93
+         %58 = OpAccessChain %_ptr_Uniform_float %uniforms %uint_0 %uint_4 %uint_0
+         %59 = OpLoad %float %58
+         %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 %59 %62 %65
+               OpStore %bbMin %66
+         %70 = OpAccessChain %_ptr_Uniform_float %uniforms %uint_0 %uint_5 %uint_0
+         %71 = OpLoad %float %70
+         %72 = OpAccessChain %_ptr_Uniform_float %uniforms %uint_0 %uint_5 %uint_1
+         %73 = OpLoad %float %72
+         %74 = OpAccessChain %_ptr_Uniform_float %uniforms %uint_0 %uint_5 %uint_2
+         %75 = OpLoad %float %74
+         %76 = OpCompositeConstruct %v3float %71 %73 %75
+               OpStore %bbMax %76
+         %78 = OpLoad %v3float %bbMax
+         %79 = OpLoad %v3float %bbMin
+         %80 = OpFSub %v3float %78 %79
+               OpStore %bbSize %80
+         %86 = OpAccessChain %_ptr_Function_float %bbSize %uint_0
+         %87 = OpLoad %float %86
+         %88 = OpAccessChain %_ptr_Function_float %bbSize %uint_1
+         %89 = OpLoad %float %88
+         %84 = OpExtInst %float %83 NMax %87 %89
+         %90 = OpAccessChain %_ptr_Function_float %bbSize %uint_2
+         %91 = OpLoad %float %90
+         %82 = OpExtInst %float %83 NMax %84 %91
+               OpStore %cubeSize %82
+         %96 = OpAccessChain %_ptr_Uniform_uint %uniforms %uint_0 %uint_1
+         %97 = OpLoad %uint %96
+         %94 = OpConvertUToF %float %97
+               OpStore %gridSize %94
+         %99 = OpLoad %float %gridSize
+        %100 = OpCompositeExtract %float %position 0
+        %101 = OpAccessChain %_ptr_Uniform_float %uniforms %uint_0 %uint_4 %uint_0
+        %102 = OpLoad %float %101
+        %103 = OpFSub %float %100 %102
+        %104 = OpFMul %float %99 %103
+        %105 = OpLoad %float %cubeSize
+        %106 = OpFDiv %float %104 %105
+               OpStore %gx %106
+        %108 = OpLoad %float %gridSize
+        %109 = OpCompositeExtract %float %position 1
+        %110 = OpAccessChain %_ptr_Uniform_float %uniforms %uint_0 %uint_4 %uint_1
+        %111 = OpLoad %float %110
+        %112 = OpFSub %float %109 %111
+        %113 = OpFMul %float %108 %112
+        %114 = OpLoad %float %cubeSize
+        %115 = OpFDiv %float %113 %114
+               OpStore %gy %115
+        %117 = OpLoad %float %gridSize
+        %118 = OpCompositeExtract %float %position 2
+        %119 = OpAccessChain %_ptr_Uniform_float %uniforms %uint_0 %uint_4 %uint_2
+        %120 = OpLoad %float %119
+        %121 = OpFSub %float %118 %120
+        %122 = OpFMul %float %117 %121
+        %123 = OpLoad %float %cubeSize
+        %124 = OpFDiv %float %122 %123
+               OpStore %gz %124
+        %126 = OpLoad %float %gx
+        %127 = OpLoad %float %gy
+        %128 = OpLoad %float %gz
+        %129 = OpCompositeConstruct %v3float %126 %127 %128
+               OpReturnValue %129
+               OpFunctionEnd
+  %toIndex1D = OpFunction %uint None %130
  %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
+        %134 = OpLabel
+     %icoord = OpVariable %_ptr_Function_v3uint Function %47
+        %135 = OpFunctionCall %v3uint %tint_ftou %voxelPos
+               OpStore %icoord %135
+        %139 = OpAccessChain %_ptr_Function_uint %icoord %uint_0
+        %140 = OpLoad %uint %139
+        %141 = OpAccessChain %_ptr_Function_uint %icoord %uint_1
+        %142 = OpLoad %uint %141
+        %143 = OpIMul %uint %gridSize_0 %142
+        %144 = OpIAdd %uint %140 %143
+        %145 = OpIMul %uint %gridSize_0 %gridSize_0
+        %146 = OpAccessChain %_ptr_Function_uint %icoord %uint_2
+        %147 = OpLoad %uint %146
+        %148 = OpIMul %uint %145 %147
+        %149 = OpIAdd %uint %144 %148
+               OpReturnValue %149
                OpFunctionEnd
-   %tint_div = OpFunction %uint None %135
+   %tint_div = OpFunction %uint None %150
         %lhs = OpFunctionParameter %uint
         %rhs = OpFunctionParameter %uint
-        %139 = OpLabel
-        %142 = OpIEqual %bool %rhs %141
-        %140 = OpSelect %uint %142 %uint_1 %rhs
-        %144 = OpUDiv %uint %lhs %140
-               OpReturnValue %144
+        %154 = OpLabel
+        %157 = OpIEqual %bool %rhs %156
+        %155 = OpSelect %uint %157 %uint_1 %rhs
+        %158 = OpUDiv %uint %lhs %155
+               OpReturnValue %158
                OpFunctionEnd
-   %tint_mod = OpFunction %uint None %135
+   %tint_mod = OpFunction %uint None %150
       %lhs_0 = OpFunctionParameter %uint
       %rhs_0 = OpFunctionParameter %uint
-        %148 = OpLabel
-        %150 = OpIEqual %bool %rhs_0 %141
-        %149 = OpSelect %uint %150 %uint_1 %rhs_0
-        %151 = OpUMod %uint %lhs_0 %149
-               OpReturnValue %151
+        %162 = OpLabel
+        %164 = OpIEqual %bool %rhs_0 %156
+        %163 = OpSelect %uint %164 %uint_1 %rhs_0
+        %165 = OpUMod %uint %lhs_0 %163
+               OpReturnValue %165
                OpFunctionEnd
-  %toIndex3D = OpFunction %v3uint None %152
+  %toIndex3D = OpFunction %v3uint None %166
  %gridSize_1 = OpFunctionParameter %uint
       %index = OpFunctionParameter %uint
-        %156 = OpLabel
-          %z = OpVariable %_ptr_Function_uint Function %141
-          %y = OpVariable %_ptr_Function_uint Function %141
-          %x = OpVariable %_ptr_Function_uint Function %141
-        %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
+        %170 = OpLabel
+          %z = OpVariable %_ptr_Function_uint Function %156
+          %y = OpVariable %_ptr_Function_uint Function %156
+          %x = OpVariable %_ptr_Function_uint Function %156
+        %172 = OpIMul %uint %gridSize_1 %gridSize_1
+        %171 = OpFunctionCall %uint %tint_div %index %172
+               OpStore %z %171
+        %175 = OpIMul %uint %gridSize_1 %gridSize_1
+        %176 = OpLoad %uint %z
+        %177 = OpIMul %uint %175 %176
+        %178 = OpISub %uint %index %177
+        %174 = OpFunctionCall %uint %tint_div %178 %gridSize_1
+               OpStore %y %174
+        %180 = OpFunctionCall %uint %tint_mod %index %gridSize_1
+               OpStore %x %180
+        %182 = OpLoad %uint %x
+        %183 = OpLoad %uint %y
+        %184 = OpLoad %uint %z
+        %185 = OpCompositeConstruct %v3uint %182 %183 %184
+               OpReturnValue %185
                OpFunctionEnd
-%loadPosition = OpFunction %v3float None %172
+%loadPosition = OpFunction %v3float None %186
 %vertexIndex = OpFunctionParameter %uint
-        %175 = OpLabel
- %position_0 = OpVariable %_ptr_Function_v3float Function %52
-        %177 = OpIMul %uint %uint_3 %vertexIndex
-        %178 = OpIAdd %uint %177 %141
-        %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
+        %189 = OpLabel
+ %position_0 = OpVariable %_ptr_Function_v3float Function %45
+        %191 = OpIMul %uint %uint_3 %vertexIndex
+        %192 = OpIAdd %uint %191 %156
+        %194 = OpAccessChain %_ptr_StorageBuffer_float %positions %uint_0 %192
+        %195 = OpLoad %float %194
+        %196 = OpIMul %uint %uint_3 %vertexIndex
+        %197 = OpIAdd %uint %196 %uint_1
+        %198 = OpAccessChain %_ptr_StorageBuffer_float %positions %uint_0 %197
+        %199 = OpLoad %float %198
+        %200 = OpIMul %uint %uint_3 %vertexIndex
+        %201 = OpIAdd %uint %200 %uint_2
+        %202 = OpAccessChain %_ptr_StorageBuffer_float %positions %uint_0 %201
+        %203 = OpLoad %float %202
+        %204 = OpCompositeConstruct %v3float %195 %199 %203
+               OpStore %position_0 %204
+        %206 = OpLoad %v3float %position_0
+               OpReturnValue %206
                OpFunctionEnd
-   %doIgnore = OpFunction %void None %193
-        %196 = OpLabel
-        %g42 = OpVariable %_ptr_Function_uint Function %141
-        %kj6 = OpVariable %_ptr_Function_uint Function %141
-        %b53 = OpVariable %_ptr_Function_uint Function %141
-        %rwg = OpVariable %_ptr_Function_uint Function %141
-        %rb5 = OpVariable %_ptr_Function_float Function %77
-        %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
+   %doIgnore = OpFunction %void None %207
+        %210 = OpLabel
+        %g42 = OpVariable %_ptr_Function_uint Function %156
+        %kj6 = OpVariable %_ptr_Function_uint Function %156
+        %b53 = OpVariable %_ptr_Function_uint Function %156
+        %rwg = OpVariable %_ptr_Function_uint Function %156
+        %rb5 = OpVariable %_ptr_Function_float Function %93
+        %g55 = OpVariable %_ptr_Function_int Function %220
+        %211 = OpAccessChain %_ptr_Uniform_uint %uniforms %uint_0 %uint_0
+        %212 = OpLoad %uint %211
+               OpStore %g42 %212
+        %215 = OpAccessChain %_ptr_StorageBuffer_uint %dbg %uint_0 %uint_5
+        %216 = OpLoad %uint %215
+               OpStore %kj6 %216
+        %222 = OpAccessChain %_ptr_StorageBuffer_uint_0 %counters %uint_0 %220
+        %218 = OpAtomicLoad %uint %222 %uint_1 %uint_0
+               OpStore %b53 %218
+        %224 = OpAccessChain %_ptr_StorageBuffer_uint %indices %uint_0 %220
+        %225 = OpLoad %uint %224
+               OpStore %rwg %225
+        %227 = OpAccessChain %_ptr_StorageBuffer_float %positions %uint_0 %220
+        %228 = OpLoad %float %227
+               OpStore %rb5 %228
+        %233 = OpAccessChain %_ptr_StorageBuffer_int %LUT %uint_0 %220
+        %230 = OpAtomicLoad %int %233 %uint_1 %uint_0
+               OpStore %g55 %230
                OpReturn
                OpFunctionEnd
-%main_count_inner = OpFunction %void None %222
+%main_count_inner = OpFunction %void None %236
 %GlobalInvocationID = OpFunctionParameter %v3uint
-        %225 = OpLabel
-%triangleIndex = OpVariable %_ptr_Function_uint Function %141
-         %i0 = OpVariable %_ptr_Function_uint Function %141
-         %i1 = OpVariable %_ptr_Function_uint Function %141
-         %i2 = OpVariable %_ptr_Function_uint Function %141
-         %p0 = OpVariable %_ptr_Function_v3float Function %52
-         %p1 = OpVariable %_ptr_Function_v3float Function %52
-         %p2 = OpVariable %_ptr_Function_v3float Function %52
-        %269 = 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 %141
-      %acefg = OpVariable %_ptr_Function_uint Function %141
-        %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
-        %231 = OpUGreaterThanEqual %bool %228 %230
-               OpSelectionMerge %232 None
-               OpBranchConditional %231 %233 %232
-        %233 = OpLabel
+        %239 = OpLabel
+%triangleIndex = OpVariable %_ptr_Function_uint Function %156
+         %i0 = OpVariable %_ptr_Function_uint Function %156
+         %i1 = OpVariable %_ptr_Function_uint Function %156
+         %i2 = OpVariable %_ptr_Function_uint Function %156
+         %p0 = OpVariable %_ptr_Function_v3float Function %45
+         %p1 = OpVariable %_ptr_Function_v3float Function %45
+         %p2 = OpVariable %_ptr_Function_v3float Function %45
+        %283 = OpVariable %_ptr_Function_v3float Function %45
+     %center = OpVariable %_ptr_Function_v3float Function %45
+ %voxelPos_0 = OpVariable %_ptr_Function_v3float Function %45
+ %voxelIndex = OpVariable %_ptr_Function_uint Function %156
+      %acefg = OpVariable %_ptr_Function_uint Function %156
+        %240 = OpCompositeExtract %uint %GlobalInvocationID 0
+               OpStore %triangleIndex %240
+        %242 = OpLoad %uint %triangleIndex
+        %243 = OpAccessChain %_ptr_Uniform_uint %uniforms %uint_0 %uint_0
+        %244 = OpLoad %uint %243
+        %245 = OpUGreaterThanEqual %bool %242 %244
+               OpSelectionMerge %246 None
+               OpBranchConditional %245 %247 %246
+        %247 = OpLabel
                OpReturn
-        %232 = OpLabel
-        %234 = OpFunctionCall %void %doIgnore
-        %235 = OpLoad %uint %triangleIndex
-        %236 = OpIMul %uint %uint_3 %235
-        %237 = OpIAdd %uint %236 %141
-        %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 %141
-               OpSelectionMerge %287 None
-               OpBranchConditional %286 %288 %287
-        %288 = OpLabel
-        %289 = OpAccessChain %_ptr_StorageBuffer_uint %dbg %uint_0 %uint_4
+        %246 = OpLabel
+        %248 = OpFunctionCall %void %doIgnore
+        %249 = OpLoad %uint %triangleIndex
+        %250 = OpIMul %uint %uint_3 %249
+        %251 = OpIAdd %uint %250 %156
+        %252 = OpAccessChain %_ptr_StorageBuffer_uint %indices %uint_0 %251
+        %253 = OpLoad %uint %252
+               OpStore %i0 %253
+        %255 = OpLoad %uint %triangleIndex
+        %256 = OpIMul %uint %uint_3 %255
+        %257 = OpIAdd %uint %256 %uint_1
+        %258 = OpAccessChain %_ptr_StorageBuffer_uint %indices %uint_0 %257
+        %259 = OpLoad %uint %258
+               OpStore %i1 %259
+        %261 = OpLoad %uint %triangleIndex
+        %262 = OpIMul %uint %uint_3 %261
+        %263 = OpIAdd %uint %262 %uint_2
+        %264 = OpAccessChain %_ptr_StorageBuffer_uint %indices %uint_0 %263
+        %265 = OpLoad %uint %264
+               OpStore %i2 %265
+        %268 = OpLoad %uint %i0
+        %267 = OpFunctionCall %v3float %loadPosition %268
+               OpStore %p0 %267
+        %271 = OpLoad %uint %i1
+        %270 = OpFunctionCall %v3float %loadPosition %271
+               OpStore %p1 %270
+        %274 = OpLoad %uint %i2
+        %273 = OpFunctionCall %v3float %loadPosition %274
+               OpStore %p2 %273
+        %276 = OpLoad %v3float %p0
+        %277 = OpLoad %v3float %p1
+        %278 = OpFAdd %v3float %276 %277
+        %279 = OpLoad %v3float %p2
+        %280 = OpFAdd %v3float %278 %279
+        %284 = OpCompositeConstruct %v3float %float_3 %float_3 %float_3
+        %282 = OpFDiv %v3float %280 %284
+               OpStore %center %282
+        %287 = OpLoad %v3float %center
+        %286 = OpFunctionCall %v3float %toVoxelPos %287
+               OpStore %voxelPos_0 %286
         %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
+        %292 = OpLoad %v3float %voxelPos_0
+        %289 = OpFunctionCall %uint %toIndex1D %291 %292
+               OpStore %voxelIndex %289
+        %296 = OpLoad %uint %voxelIndex
+        %297 = OpAccessChain %_ptr_StorageBuffer_uint_0 %counters %uint_0 %296
+        %294 = OpAtomicIAdd %uint %297 %uint_1 %uint_0 %uint_1
+               OpStore %acefg %294
+        %299 = OpLoad %uint %triangleIndex
+        %300 = OpIEqual %bool %299 %156
+               OpSelectionMerge %301 None
+               OpBranchConditional %300 %302 %301
+        %302 = OpLabel
+        %303 = OpAccessChain %_ptr_StorageBuffer_uint %dbg %uint_0 %uint_4
+        %304 = OpAccessChain %_ptr_Uniform_uint %uniforms %uint_0 %uint_1
+        %305 = OpLoad %uint %304
+               OpStore %303 %305
+        %307 = OpAccessChain %_ptr_StorageBuffer_float %dbg %uint_0 %uint_8
+        %308 = OpAccessChain %_ptr_Function_float %center %uint_0
+        %309 = OpLoad %float %308
+               OpStore %307 %309
+        %311 = OpAccessChain %_ptr_StorageBuffer_float %dbg %uint_0 %uint_9
+        %312 = OpAccessChain %_ptr_Function_float %center %uint_1
+        %313 = OpLoad %float %312
+               OpStore %311 %313
+        %315 = OpAccessChain %_ptr_StorageBuffer_float %dbg %uint_0 %uint_10
+        %316 = OpAccessChain %_ptr_Function_float %center %uint_2
+        %317 = OpLoad %float %316
+               OpStore %315 %317
+               OpBranch %301
+        %301 = OpLabel
                OpReturn
                OpFunctionEnd
- %main_count = OpFunction %void None %193
-        %305 = OpLabel
-        %307 = OpLoad %v3uint %GlobalInvocationID_1
-        %306 = OpFunctionCall %void %main_count_inner %307
+ %main_count = OpFunction %void None %207
+        %319 = OpLabel
+        %321 = OpLoad %v3uint %GlobalInvocationID_1
+        %320 = OpFunctionCall %void %main_count_inner %321
                OpReturn
                OpFunctionEnd
-%main_create_lut_inner = OpFunction %void None %222
+%main_create_lut_inner = OpFunction %void None %236
 %GlobalInvocationID_0 = OpFunctionParameter %v3uint
-        %310 = OpLabel
-%voxelIndex_0 = OpVariable %_ptr_Function_uint Function %141
-  %maxVoxels = OpVariable %_ptr_Function_uint Function %141
-%numTriangles = OpVariable %_ptr_Function_uint Function %141
-     %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
+        %324 = OpLabel
+%voxelIndex_0 = OpVariable %_ptr_Function_uint Function %156
+  %maxVoxels = OpVariable %_ptr_Function_uint Function %156
+%numTriangles = OpVariable %_ptr_Function_uint Function %156
+     %offset = OpVariable %_ptr_Function_int Function %220
+        %325 = OpCompositeExtract %uint %GlobalInvocationID_0 0
+               OpStore %voxelIndex_0 %325
+        %327 = OpFunctionCall %void %doIgnore
+        %328 = OpAccessChain %_ptr_Uniform_uint %uniforms %uint_0 %uint_1
+        %329 = OpLoad %uint %328
+        %330 = OpAccessChain %_ptr_Uniform_uint %uniforms %uint_0 %uint_1
+        %331 = OpLoad %uint %330
+        %332 = OpIMul %uint %329 %331
+        %333 = OpAccessChain %_ptr_Uniform_uint %uniforms %uint_0 %uint_1
+        %334 = OpLoad %uint %333
+        %335 = OpIMul %uint %332 %334
+               OpStore %maxVoxels %335
+        %337 = OpLoad %uint %voxelIndex_0
+        %338 = OpLoad %uint %maxVoxels
+        %339 = OpUGreaterThanEqual %bool %337 %338
+               OpSelectionMerge %340 None
+               OpBranchConditional %339 %341 %340
+        %341 = OpLabel
                OpReturn
-        %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
+        %340 = OpLabel
+        %344 = OpLoad %uint %voxelIndex_0
+        %345 = OpAccessChain %_ptr_StorageBuffer_uint_0 %counters %uint_0 %344
+        %342 = OpAtomicLoad %uint %345 %uint_1 %uint_0
+               OpStore %numTriangles %342
                OpStore %offset %int_n1
-        %335 = OpLoad %uint %numTriangles
-        %336 = OpUGreaterThan %bool %335 %141
-               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
+        %349 = OpLoad %uint %numTriangles
+        %350 = OpUGreaterThan %bool %349 %156
+               OpSelectionMerge %351 None
+               OpBranchConditional %350 %352 %351
+        %352 = OpLabel
+        %355 = OpAccessChain %_ptr_StorageBuffer_uint_0 %dbg %uint_0 %uint_0
+        %356 = OpLoad %uint %numTriangles
+        %353 = OpAtomicIAdd %uint %355 %uint_1 %uint_0 %356
+        %357 = OpBitcast %int %353
+               OpStore %offset %357
+               OpBranch %351
+        %351 = OpLabel
+        %360 = OpLoad %uint %voxelIndex_0
+        %361 = OpAccessChain %_ptr_StorageBuffer_int %LUT %uint_0 %360
+        %362 = OpLoad %int %offset
+               OpAtomicStore %361 %uint_1 %uint_0 %362
                OpReturn
                OpFunctionEnd
-%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 %222
-%GlobalInvocationID_4 = OpFunctionParameter %v3uint
-        %355 = OpLabel
-%triangleIndex_0 = OpVariable %_ptr_Function_uint Function %141
-       %i0_0 = OpVariable %_ptr_Function_uint Function %141
-       %i1_0 = OpVariable %_ptr_Function_uint Function %141
-       %i2_0 = OpVariable %_ptr_Function_uint Function %141
-       %p0_0 = OpVariable %_ptr_Function_v3float Function %52
-       %p1_0 = OpVariable %_ptr_Function_v3float Function %52
-       %p2_0 = OpVariable %_ptr_Function_v3float Function %52
-        %398 = 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 %141
-%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
+%main_create_lut = OpFunction %void None %207
         %364 = OpLabel
-               OpReturn
-        %363 = OpLabel
-        %365 = OpLoad %uint %triangleIndex_0
-        %366 = OpIMul %uint %uint_3 %365
-        %367 = OpIAdd %uint %366 %141
-        %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
+        %366 = OpLoad %v3uint %GlobalInvocationID_2
+        %365 = OpFunctionCall %void %main_create_lut_inner %366
                OpReturn
                OpFunctionEnd
-%main_sort_triangles = OpFunction %void None %193
-        %416 = OpLabel
-        %418 = OpLoad %v3uint %GlobalInvocationID_3
-        %417 = OpFunctionCall %void %main_sort_triangles_inner %418
+%main_sort_triangles_inner = OpFunction %void None %236
+%GlobalInvocationID_4 = OpFunctionParameter %v3uint
+        %369 = OpLabel
+%triangleIndex_0 = OpVariable %_ptr_Function_uint Function %156
+       %i0_0 = OpVariable %_ptr_Function_uint Function %156
+       %i1_0 = OpVariable %_ptr_Function_uint Function %156
+       %i2_0 = OpVariable %_ptr_Function_uint Function %156
+       %p0_0 = OpVariable %_ptr_Function_v3float Function %45
+       %p1_0 = OpVariable %_ptr_Function_v3float Function %45
+       %p2_0 = OpVariable %_ptr_Function_v3float Function %45
+        %412 = OpVariable %_ptr_Function_v3float Function %45
+   %center_0 = OpVariable %_ptr_Function_v3float Function %45
+ %voxelPos_1 = OpVariable %_ptr_Function_v3float Function %45
+%voxelIndex_1 = OpVariable %_ptr_Function_uint Function %156
+%triangleOffset = OpVariable %_ptr_Function_int Function %220
+        %370 = OpCompositeExtract %uint %GlobalInvocationID_4 0
+               OpStore %triangleIndex_0 %370
+        %372 = OpFunctionCall %void %doIgnore
+        %373 = OpLoad %uint %triangleIndex_0
+        %374 = OpAccessChain %_ptr_Uniform_uint %uniforms %uint_0 %uint_0
+        %375 = OpLoad %uint %374
+        %376 = OpUGreaterThanEqual %bool %373 %375
+               OpSelectionMerge %377 None
+               OpBranchConditional %376 %378 %377
+        %378 = OpLabel
+               OpReturn
+        %377 = OpLabel
+        %379 = OpLoad %uint %triangleIndex_0
+        %380 = OpIMul %uint %uint_3 %379
+        %381 = OpIAdd %uint %380 %156
+        %382 = OpAccessChain %_ptr_StorageBuffer_uint %indices %uint_0 %381
+        %383 = OpLoad %uint %382
+               OpStore %i0_0 %383
+        %385 = OpLoad %uint %triangleIndex_0
+        %386 = OpIMul %uint %uint_3 %385
+        %387 = OpIAdd %uint %386 %uint_1
+        %388 = OpAccessChain %_ptr_StorageBuffer_uint %indices %uint_0 %387
+        %389 = OpLoad %uint %388
+               OpStore %i1_0 %389
+        %391 = OpLoad %uint %triangleIndex_0
+        %392 = OpIMul %uint %uint_3 %391
+        %393 = OpIAdd %uint %392 %uint_2
+        %394 = OpAccessChain %_ptr_StorageBuffer_uint %indices %uint_0 %393
+        %395 = OpLoad %uint %394
+               OpStore %i2_0 %395
+        %398 = OpLoad %uint %i0_0
+        %397 = OpFunctionCall %v3float %loadPosition %398
+               OpStore %p0_0 %397
+        %401 = OpLoad %uint %i1_0
+        %400 = OpFunctionCall %v3float %loadPosition %401
+               OpStore %p1_0 %400
+        %404 = OpLoad %uint %i2_0
+        %403 = OpFunctionCall %v3float %loadPosition %404
+               OpStore %p2_0 %403
+        %406 = OpLoad %v3float %p0_0
+        %407 = OpLoad %v3float %p1_0
+        %408 = OpFAdd %v3float %406 %407
+        %409 = OpLoad %v3float %p2_0
+        %410 = OpFAdd %v3float %408 %409
+        %413 = OpCompositeConstruct %v3float %float_3 %float_3 %float_3
+        %411 = OpFDiv %v3float %410 %413
+               OpStore %center_0 %411
+        %416 = OpLoad %v3float %center_0
+        %415 = OpFunctionCall %v3float %toVoxelPos %416
+               OpStore %voxelPos_1 %415
+        %419 = OpAccessChain %_ptr_Uniform_uint %uniforms %uint_0 %uint_1
+        %420 = OpLoad %uint %419
+        %421 = OpLoad %v3float %voxelPos_1
+        %418 = OpFunctionCall %uint %toIndex1D %420 %421
+               OpStore %voxelIndex_1 %418
+        %425 = OpLoad %uint %voxelIndex_1
+        %426 = OpAccessChain %_ptr_StorageBuffer_int %LUT %uint_0 %425
+        %423 = OpAtomicIAdd %int %426 %uint_1 %uint_0 %int_1
+               OpStore %triangleOffset %423
+               OpReturn
+               OpFunctionEnd
+%main_sort_triangles = OpFunction %void None %207
+        %430 = OpLabel
+        %432 = OpLoad %v3uint %GlobalInvocationID_3
+        %431 = OpFunctionCall %void %main_sort_triangles_inner %432
                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 33d4b13..554a05b 100644
--- a/test/tint/bug/tint/1520.spvasm.expected.dxc.hlsl
+++ b/test/tint/bug/tint/1520.spvasm.expected.dxc.hlsl
@@ -1,3 +1,7 @@
+int tint_ftoi(float v) {
+  return ((v < 2147483520.0f) ? ((v < -2147483648.0f) ? -2147483648 : int(v)) : 2147483647);
+}
+
 cbuffer cbuffer_x_4 : register(b0, space0) {
   uint4 x_4[7];
 };
@@ -20,7 +24,7 @@
   bool x_65 = false;
   bool x_66 = false;
   const float x_26 = asfloat(x_4[1].x);
-  const int x_27 = int(x_26);
+  const int x_27 = tint_ftoi(x_26);
   unknown = x_27;
   ok = true;
   x_41 = false;
diff --git a/test/tint/bug/tint/1520.spvasm.expected.fxc.hlsl b/test/tint/bug/tint/1520.spvasm.expected.fxc.hlsl
index 33d4b13..554a05b 100644
--- a/test/tint/bug/tint/1520.spvasm.expected.fxc.hlsl
+++ b/test/tint/bug/tint/1520.spvasm.expected.fxc.hlsl
@@ -1,3 +1,7 @@
+int tint_ftoi(float v) {
+  return ((v < 2147483520.0f) ? ((v < -2147483648.0f) ? -2147483648 : int(v)) : 2147483647);
+}
+
 cbuffer cbuffer_x_4 : register(b0, space0) {
   uint4 x_4[7];
 };
@@ -20,7 +24,7 @@
   bool x_65 = false;
   bool x_66 = false;
   const float x_26 = asfloat(x_4[1].x);
-  const int x_27 = int(x_26);
+  const int x_27 = tint_ftoi(x_26);
   unknown = x_27;
   ok = true;
   x_41 = false;
diff --git a/test/tint/bug/tint/1520.spvasm.expected.glsl b/test/tint/bug/tint/1520.spvasm.expected.glsl
index c0fccf5..e202b60 100644
--- a/test/tint/bug/tint/1520.spvasm.expected.glsl
+++ b/test/tint/bug/tint/1520.spvasm.expected.glsl
@@ -8,6 +8,10 @@
 
 layout(location = 0) in vec4 vcolor_S0_param_1;
 layout(location = 0) out vec4 sk_FragColor_1_1;
+int tint_ftoi(float v) {
+  return ((v < 2147483520.0f) ? ((v < -2147483648.0f) ? (-2147483647 - 1) : int(v)) : 2147483647);
+}
+
 struct UniformBuffer {
   uint pad;
   uint pad_1;
@@ -44,7 +48,7 @@
   bool x_65 = false;
   bool x_66 = false;
   float x_26 = x_4.inner.unknownInput_S1_c0;
-  int x_27 = int(x_26);
+  int x_27 = tint_ftoi(x_26);
   unknown = x_27;
   ok = true;
   x_41 = false;
diff --git a/test/tint/bug/tint/1520.spvasm.expected.msl b/test/tint/bug/tint/1520.spvasm.expected.msl
index d03b423..d3244ac 100644
--- a/test/tint/bug/tint/1520.spvasm.expected.msl
+++ b/test/tint/bug/tint/1520.spvasm.expected.msl
@@ -28,6 +28,10 @@
   /* 0x0040 */ tint_array<tint_packed_vec3_f32_array_element, 3> umatrix_S1;
 };
 
+int tint_ftoi(float v) {
+  return select(2147483647, select(int(v), (-2147483647 - 1), (v < -2147483648.0f)), (v < 2147483520.0f));
+}
+
 struct UniformBuffer {
   float unknownInput_S1_c0;
   float4 ucolorRed_S1_c0;
@@ -50,7 +54,7 @@
   bool x_65 = false;
   bool x_66 = false;
   float const x_26 = (*(tint_symbol_5)).unknownInput_S1_c0;
-  int const x_27 = int(x_26);
+  int const x_27 = tint_ftoi(x_26);
   unknown = x_27;
   ok = true;
   x_41 = false;
diff --git a/test/tint/bug/tint/1520.spvasm.expected.spvasm b/test/tint/bug/tint/1520.spvasm.expected.spvasm
index 98e5816..96a940d 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: 193
+; Bound: 205
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
@@ -21,6 +21,8 @@
                OpName %sk_FragColor "sk_FragColor"
                OpName %sk_Clockwise "sk_Clockwise"
                OpName %vcolor_S0 "vcolor_S0"
+               OpName %tint_ftoi "tint_ftoi"
+               OpName %v "v"
                OpName %tint_div "tint_div"
                OpName %lhs "lhs"
                OpName %rhs "rhs"
@@ -93,19 +95,23 @@
 %sk_Clockwise = OpVariable %_ptr_Private_bool Private %21
   %vcolor_S0 = OpVariable %_ptr_Private_v4float Private %10
         %int = OpTypeInt 32 1
-      %v4int = OpTypeVector %int 4
-         %23 = OpTypeFunction %v4int %v4int %v4int
-         %31 = OpConstantNull %v4int
-     %v4bool = OpTypeVector %bool 4
+         %23 = OpTypeFunction %int %float
+%float_2_14748352e_09 = OpConstant %float 2.14748352e+09
+%float_n2_14748365e_09 = OpConstant %float -2.14748365e+09
 %int_n2147483648 = OpConstant %int -2147483648
-         %35 = OpConstantComposite %v4int %int_n2147483648 %int_n2147483648 %int_n2147483648 %int_n2147483648
+%int_2147483647 = OpConstant %int 2147483647
+      %v4int = OpTypeVector %int 4
+         %37 = OpTypeFunction %v4int %v4int %v4int
+         %44 = OpConstantNull %v4int
+     %v4bool = OpTypeVector %bool 4
+         %47 = 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
+         %50 = 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
+         %55 = OpConstantComposite %v4int %int_1 %int_1 %int_1 %int_1
+         %57 = OpTypeFunction %bool
 %_ptr_Function_int = OpTypePointer Function %int
-         %50 = OpConstantNull %int
+         %62 = OpConstantNull %int
 %_ptr_Function_bool = OpTypePointer Function %bool
 %_ptr_Function_v4int = OpTypePointer Function %v4int
        %uint = OpTypeInt 32 0
@@ -113,119 +119,129 @@
 %_ptr_Uniform_float = OpTypePointer Uniform %float
        %true = OpConstantTrue %bool
       %int_2 = OpConstant %int 2
-         %89 = OpConstantComposite %v4int %int_2 %int_2 %int_2 %int_2
+        %101 = OpConstantComposite %v4int %int_2 %int_2 %int_2 %int_2
        %void = OpTypeVoid
-        %102 = OpTypeFunction %void
+        %114 = OpTypeFunction %void
 %_ptr_Function_v4float = OpTypePointer Function %v4float
 %_ptr_Function_float = OpTypePointer Function %float
-        %111 = OpConstantNull %float
+        %123 = OpConstantNull %float
     %float_1 = OpConstant %float 1
-        %136 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
+        %148 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
     %float_2 = OpConstant %float 2
-        %149 = OpConstantComposite %v4float %float_2 %float_2 %float_2 %float_2
+        %161 = 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
-        %178 = OpTypeFunction %main_out %bool %v4float
-   %tint_div = OpFunction %v4int None %23
+        %190 = OpTypeFunction %main_out %bool %v4float
+  %tint_ftoi = OpFunction %int None %23
+          %v = OpFunctionParameter %float
+         %27 = OpLabel
+         %30 = OpFOrdLessThan %bool %v %float_2_14748352e_09
+         %33 = OpFOrdLessThan %bool %v %float_n2_14748365e_09
+         %35 = OpConvertFToS %int %v
+         %31 = OpSelect %int %33 %int_n2147483648 %35
+         %28 = OpSelect %int %30 %31 %int_2147483647
+               OpReturnValue %28
+               OpFunctionEnd
+   %tint_div = OpFunction %v4int None %37
         %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
+         %42 = OpLabel
+         %45 = OpIEqual %v4bool %rhs %44
+         %48 = OpIEqual %v4bool %lhs %47
+         %51 = OpIEqual %v4bool %rhs %50
+         %52 = OpLogicalAnd %v4bool %48 %51
+         %53 = OpLogicalOr %v4bool %45 %52
+         %43 = OpSelect %v4int %53 %55 %rhs
+         %56 = OpSDiv %v4int %lhs %43
+               OpReturnValue %56
                OpFunctionEnd
-%test_int_S1_c0_b = OpFunction %bool None %45
-         %47 = OpLabel
-    %unknown = OpVariable %_ptr_Function_int Function %50
+%test_int_S1_c0_b = OpFunction %bool None %57
+         %59 = OpLabel
+    %unknown = OpVariable %_ptr_Function_int Function %62
          %ok = OpVariable %_ptr_Function_bool Function %21
-        %val = OpVariable %_ptr_Function_v4int Function %31
+        %val = OpVariable %_ptr_Function_v4int Function %44
        %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
-         %64 = OpAccessChain %_ptr_Uniform_float %x_4 %uint_0 %uint_0
-         %65 = OpLoad %float %64
-         %66 = OpConvertFToS %int %65
-               OpStore %unknown %66
+         %76 = OpAccessChain %_ptr_Uniform_float %x_4 %uint_0 %uint_0
+         %77 = OpLoad %float %76
+         %78 = OpFunctionCall %int %tint_ftoi %77
+               OpStore %unknown %78
                OpStore %ok %true
                OpStore %x_41 %21
-               OpSelectionMerge %68 None
-               OpBranchConditional %true %69 %68
-         %69 = OpLabel
-         %72 = OpCompositeConstruct %v4int %66 %66 %66 %66
-         %71 = OpFunctionCall %v4int %tint_div %31 %72
-         %73 = OpIEqual %v4bool %71 %31
-         %70 = OpAll %bool %73
-               OpStore %x_40 %70
-         %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 = 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
+               OpSelectionMerge %80 None
+               OpBranchConditional %true %81 %80
+         %81 = OpLabel
+         %84 = OpCompositeConstruct %v4int %78 %78 %78 %78
+         %83 = OpFunctionCall %v4int %tint_div %44 %84
+         %85 = OpIEqual %v4bool %83 %44
+         %82 = OpAll %bool %85
+               OpStore %x_40 %82
+         %86 = OpLoad %bool %x_40
+               OpStore %x_41 %86
+               OpBranch %80
+         %80 = OpLabel
+         %87 = OpLoad %bool %x_41
                OpStore %ok %87
-         %90 = OpIMul %v4int %80 %89
+         %88 = OpCompositeConstruct %v4int %78 %78 %78 %78
+               OpStore %val %88
+         %89 = OpIAdd %v4int %88 %55
+               OpStore %val %89
+         %90 = OpISub %v4int %89 %55
                OpStore %val %90
-         %91 = OpFunctionCall %v4int %tint_div %90 %89
+         %91 = OpIAdd %v4int %90 %55
                OpStore %val %91
-         %92 = OpIMul %v4int %91 %89
+         %92 = OpISub %v4int %91 %55
                OpStore %val %92
-         %93 = OpFunctionCall %v4int %tint_div %92 %89
-               OpStore %val %93
-               OpStore %x_66 %21
-         %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
+               OpStore %x_55 %21
+         %93 = OpLoad %bool %x_41
+               OpSelectionMerge %94 None
+               OpBranchConditional %93 %95 %94
          %95 = OpLabel
-        %100 = OpLoad %bool %x_66
-               OpStore %ok %100
-        %101 = OpLoad %bool %x_66
-               OpReturnValue %101
+         %97 = OpIEqual %v4bool %92 %88
+         %96 = OpAll %bool %97
+               OpStore %x_54 %96
+         %98 = OpLoad %bool %x_54
+               OpStore %x_55 %98
+               OpBranch %94
+         %94 = OpLabel
+         %99 = OpLoad %bool %x_55
+               OpStore %ok %99
+        %102 = OpIMul %v4int %92 %101
+               OpStore %val %102
+        %103 = OpFunctionCall %v4int %tint_div %102 %101
+               OpStore %val %103
+        %104 = OpIMul %v4int %103 %101
+               OpStore %val %104
+        %105 = OpFunctionCall %v4int %tint_div %104 %101
+               OpStore %val %105
+               OpStore %x_66 %21
+        %106 = OpLoad %bool %x_55
+               OpSelectionMerge %107 None
+               OpBranchConditional %106 %108 %107
+        %108 = OpLabel
+        %110 = OpIEqual %v4bool %105 %88
+        %109 = OpAll %bool %110
+               OpStore %x_65 %109
+        %111 = OpLoad %bool %x_65
+               OpStore %x_66 %111
+               OpBranch %107
+        %107 = OpLabel
+        %112 = OpLoad %bool %x_66
+               OpStore %ok %112
+        %113 = OpLoad %bool %x_66
+               OpReturnValue %113
                OpFunctionEnd
-     %main_1 = OpFunction %void None %102
-        %105 = OpLabel
+     %main_1 = OpFunction %void None %114
+        %117 = 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 %111
+%x_8_unknown = OpVariable %_ptr_Function_float Function %123
      %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
@@ -237,120 +253,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
-        %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
+        %135 = OpLoad %v4float %vcolor_S0
+               OpStore %outputColor_S0 %135
+        %136 = OpAccessChain %_ptr_Uniform_float %x_4 %uint_0 %uint_0
+        %137 = OpLoad %float %136
+               OpStore %x_8_unknown %137
                OpStore %x_9_ok %true
                OpStore %x_87 %21
-               OpSelectionMerge %126 None
-               OpBranchConditional %true %127 %126
-        %127 = OpLabel
-        %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
-        %133 = OpLoad %bool %x_87
-               OpStore %x_9_ok %133
-        %134 = OpCompositeConstruct %v4float %125 %125 %125 %125
-               OpStore %x_10_val %134
-        %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
+               OpSelectionMerge %138 None
+               OpBranchConditional %true %139 %138
+        %139 = OpLabel
+        %141 = OpCompositeConstruct %v4float %137 %137 %137 %137
+        %142 = OpFDiv %v4float %10 %141
+        %143 = OpFOrdEqual %v4bool %142 %10
+        %140 = OpAll %bool %143
+               OpStore %x_86 %140
+        %144 = OpLoad %bool %x_86
+               OpStore %x_87 %144
+               OpBranch %138
+        %138 = OpLabel
+        %145 = OpLoad %bool %x_87
+               OpStore %x_9_ok %145
+        %146 = OpCompositeConstruct %v4float %137 %137 %137 %137
+               OpStore %x_10_val %146
+        %149 = OpFAdd %v4float %146 %148
+               OpStore %x_10_val %149
+        %150 = OpFSub %v4float %149 %148
                OpStore %x_10_val %150
-        %151 = OpFDiv %v4float %150 %149
+        %151 = OpFAdd %v4float %150 %148
                OpStore %x_10_val %151
-        %152 = OpFMul %v4float %151 %149
+        %152 = OpFSub %v4float %151 %148
                OpStore %x_10_val %152
-        %153 = OpFDiv %v4float %152 %149
-               OpStore %x_10_val %153
-               OpStore %x_111 %21
-        %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
+               OpStore %x_100 %21
+        %153 = OpLoad %bool %x_87
+               OpSelectionMerge %154 None
+               OpBranchConditional %153 %155 %154
         %155 = OpLabel
-        %160 = OpLoad %bool %x_111
-               OpStore %x_9_ok %160
-               OpStore %x_115 %21
-        %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
+        %157 = OpFOrdEqual %v4bool %152 %146
+        %156 = OpAll %bool %157
+               OpStore %x_99 %156
+        %158 = OpLoad %bool %x_99
+               OpStore %x_100 %158
+               OpBranch %154
+        %154 = OpLabel
+        %159 = OpLoad %bool %x_100
+               OpStore %x_9_ok %159
+        %162 = OpFMul %v4float %152 %161
+               OpStore %x_10_val %162
+        %163 = OpFDiv %v4float %162 %161
+               OpStore %x_10_val %163
+        %164 = OpFMul %v4float %163 %161
+               OpStore %x_10_val %164
+        %165 = OpFDiv %v4float %164 %161
+               OpStore %x_10_val %165
+               OpStore %x_111 %21
+        %166 = OpLoad %bool %x_100
                OpSelectionMerge %167 None
-               OpBranchConditional %166 %168 %169
+               OpBranchConditional %166 %168 %167
         %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
+        %170 = OpFOrdEqual %v4bool %165 %146
+        %169 = OpAll %bool %170
+               OpStore %x_110 %169
+        %171 = OpLoad %bool %x_110
+               OpStore %x_111 %171
                OpBranch %167
         %167 = OpLabel
-        %177 = OpLoad %v4float %x_116
-               OpStore %output_S1 %177
-               OpStore %sk_FragColor %177
+        %172 = OpLoad %bool %x_111
+               OpStore %x_9_ok %172
+               OpStore %x_115 %21
+        %173 = OpLoad %bool %x_111
+               OpSelectionMerge %174 None
+               OpBranchConditional %173 %175 %174
+        %175 = OpLabel
+        %176 = OpFunctionCall %bool %test_int_S1_c0_b
+               OpStore %x_114 %176
+        %177 = OpLoad %bool %x_114
+               OpStore %x_115 %177
+               OpBranch %174
+        %174 = OpLabel
+        %178 = OpLoad %bool %x_115
+               OpSelectionMerge %179 None
+               OpBranchConditional %178 %180 %181
+        %180 = OpLabel
+        %184 = OpAccessChain %_ptr_Uniform_v4float %x_4 %uint_0 %uint_2
+        %185 = OpLoad %v4float %184
+               OpStore %x_116 %185
+               OpBranch %179
+        %181 = OpLabel
+        %187 = OpAccessChain %_ptr_Uniform_v4float %x_4 %uint_0 %uint_1
+        %188 = OpLoad %v4float %187
+               OpStore %x_116 %188
+               OpBranch %179
+        %179 = OpLabel
+        %189 = OpLoad %v4float %x_116
+               OpStore %output_S1 %189
+               OpStore %sk_FragColor %189
                OpReturn
                OpFunctionEnd
- %main_inner = OpFunction %main_out None %178
+ %main_inner = OpFunction %main_out None %190
 %sk_Clockwise_param = OpFunctionParameter %bool
 %vcolor_S0_param = OpFunctionParameter %v4float
-        %183 = OpLabel
+        %195 = OpLabel
                OpStore %sk_Clockwise %sk_Clockwise_param
                OpStore %vcolor_S0 %vcolor_S0_param
-        %184 = OpFunctionCall %void %main_1
-        %185 = OpLoad %v4float %sk_FragColor
-        %186 = OpCompositeConstruct %main_out %185
-               OpReturnValue %186
+        %196 = OpFunctionCall %void %main_1
+        %197 = OpLoad %v4float %sk_FragColor
+        %198 = OpCompositeConstruct %main_out %197
+               OpReturnValue %198
                OpFunctionEnd
-       %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
+       %main = OpFunction %void None %114
+        %200 = OpLabel
+        %202 = OpLoad %bool %sk_Clockwise_param_1
+        %203 = OpLoad %v4float %vcolor_S0_param_1
+        %201 = OpFunctionCall %main_out %main_inner %202 %203
+        %204 = OpCompositeExtract %v4float %201 0
+               OpStore %sk_FragColor_1_1 %204
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/bug/tint/1820.wgsl.expected.dxc.hlsl b/test/tint/bug/tint/1820.wgsl.expected.dxc.hlsl
index 5e7dc39..4f3f659 100644
--- a/test/tint/bug/tint/1820.wgsl.expected.dxc.hlsl
+++ b/test/tint/bug/tint/1820.wgsl.expected.dxc.hlsl
@@ -3,7 +3,12 @@
   return;
 }
 
+int tint_ftoi(float v) {
+  return ((v < 2147483520.0f) ? ((v < -2147483648.0f) ? -2147483648 : int(v)) : 2147483647);
+}
+
 void foo(float x) {
+  tint_ftoi(x);
   do {
   } while (false);
 }
@@ -16,7 +21,7 @@
 }
 
 void bar(float x) {
-  baz(int(x));
+  baz(tint_ftoi(x));
   do {
   } while (false);
 }
diff --git a/test/tint/bug/tint/1820.wgsl.expected.fxc.hlsl b/test/tint/bug/tint/1820.wgsl.expected.fxc.hlsl
index 5e7dc39..4f3f659 100644
--- a/test/tint/bug/tint/1820.wgsl.expected.fxc.hlsl
+++ b/test/tint/bug/tint/1820.wgsl.expected.fxc.hlsl
@@ -3,7 +3,12 @@
   return;
 }
 
+int tint_ftoi(float v) {
+  return ((v < 2147483520.0f) ? ((v < -2147483648.0f) ? -2147483648 : int(v)) : 2147483647);
+}
+
 void foo(float x) {
+  tint_ftoi(x);
   do {
   } while (false);
 }
@@ -16,7 +21,7 @@
 }
 
 void bar(float x) {
-  baz(int(x));
+  baz(tint_ftoi(x));
   do {
   } while (false);
 }
diff --git a/test/tint/bug/tint/1820.wgsl.expected.glsl b/test/tint/bug/tint/1820.wgsl.expected.glsl
index 9fa7dd0..8a84afa 100644
--- a/test/tint/bug/tint/1820.wgsl.expected.glsl
+++ b/test/tint/bug/tint/1820.wgsl.expected.glsl
@@ -4,8 +4,12 @@
 void unused_entry_point() {
   return;
 }
+int tint_ftoi(float v) {
+  return ((v < 2147483520.0f) ? ((v < -2147483648.0f) ? (-2147483647 - 1) : int(v)) : 2147483647);
+}
+
 void foo(float x) {
-  switch(int(x)) {
+  switch(tint_ftoi(x)) {
     default: {
       break;
     }
@@ -19,7 +23,7 @@
 }
 
 void bar(float x) {
-  switch(baz(int(x))) {
+  switch(baz(tint_ftoi(x))) {
     default: {
       break;
     }
diff --git a/test/tint/bug/tint/1820.wgsl.expected.msl b/test/tint/bug/tint/1820.wgsl.expected.msl
index e811b1b..4c26583 100644
--- a/test/tint/bug/tint/1820.wgsl.expected.msl
+++ b/test/tint/bug/tint/1820.wgsl.expected.msl
@@ -1,8 +1,12 @@
 #include <metal_stdlib>
 
 using namespace metal;
+int tint_ftoi(float v) {
+  return select(2147483647, select(int(v), (-2147483647 - 1), (v < -2147483648.0f)), (v < 2147483520.0f));
+}
+
 void foo(float x) {
-  switch(int(x)) {
+  switch(tint_ftoi(x)) {
     default: {
       break;
     }
@@ -16,7 +20,7 @@
 }
 
 void bar(float x) {
-  switch(baz(int(x))) {
+  switch(baz(tint_ftoi(x))) {
     default: {
       break;
     }
diff --git a/test/tint/bug/tint/1820.wgsl.expected.spvasm b/test/tint/bug/tint/1820.wgsl.expected.spvasm
index 1a4bc10..309df1f 100644
--- a/test/tint/bug/tint/1820.wgsl.expected.spvasm
+++ b/test/tint/bug/tint/1820.wgsl.expected.spvasm
@@ -1,7 +1,7 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 31
+; Bound: 45
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
@@ -9,6 +9,8 @@
                OpExecutionMode %unused_entry_point LocalSize 1 1 1
                OpName %global "global"
                OpName %unused_entry_point "unused_entry_point"
+               OpName %tint_ftoi "tint_ftoi"
+               OpName %v "v"
                OpName %foo "foo"
                OpName %x "x"
                OpName %baz "baz"
@@ -23,43 +25,59 @@
        %void = OpTypeVoid
           %5 = OpTypeFunction %void
       %float = OpTypeFloat 32
-          %9 = OpTypeFunction %void %float
-         %17 = OpTypeFunction %int %int
+          %9 = OpTypeFunction %int %float
+%float_2_14748352e_09 = OpConstant %float 2.14748352e+09
+       %bool = OpTypeBool
+%float_n2_14748365e_09 = OpConstant %float -2.14748365e+09
+%int_n2147483648 = OpConstant %int -2147483648
+%int_2147483647 = OpConstant %int 2147483647
+         %24 = OpTypeFunction %void %float
+         %31 = OpTypeFunction %int %int
      %int_42 = OpConstant %int 42
 %unused_entry_point = OpFunction %void None %5
           %8 = OpLabel
                OpReturn
                OpFunctionEnd
-        %foo = OpFunction %void None %9
-          %x = OpFunctionParameter %float
+  %tint_ftoi = OpFunction %int None %9
+          %v = OpFunctionParameter %float
          %13 = OpLabel
-         %15 = OpConvertFToS %int %x
-               OpSelectionMerge %14 None
-               OpSwitch %15 %16
-         %16 = OpLabel
-               OpBranch %14
-         %14 = OpLabel
+         %16 = OpFOrdLessThan %bool %v %float_2_14748352e_09
+         %20 = OpFOrdLessThan %bool %v %float_n2_14748365e_09
+         %22 = OpConvertFToS %int %v
+         %18 = OpSelect %int %20 %int_n2147483648 %22
+         %14 = OpSelect %int %16 %18 %int_2147483647
+               OpReturnValue %14
+               OpFunctionEnd
+        %foo = OpFunction %void None %24
+          %x = OpFunctionParameter %float
+         %27 = OpLabel
+         %29 = OpFunctionCall %int %tint_ftoi %x
+               OpSelectionMerge %28 None
+               OpSwitch %29 %30
+         %30 = OpLabel
+               OpBranch %28
+         %28 = OpLabel
                OpReturn
                OpFunctionEnd
-        %baz = OpFunction %int None %17
+        %baz = OpFunction %int None %31
         %x_0 = OpFunctionParameter %int
-         %20 = OpLabel
+         %34 = OpLabel
                OpStore %global %int_42
                OpReturnValue %x_0
                OpFunctionEnd
-        %bar = OpFunction %void None %9
+        %bar = OpFunction %void None %24
         %x_1 = OpFunctionParameter %float
-         %24 = OpLabel
-         %27 = OpConvertFToS %int %x_1
-         %26 = OpFunctionCall %int %baz %27
-               OpSelectionMerge %25 None
-               OpSwitch %26 %28
-         %28 = OpLabel
-               OpBranch %25
-         %25 = OpLabel
+         %38 = OpLabel
+         %41 = OpFunctionCall %int %tint_ftoi %x_1
+         %40 = OpFunctionCall %int %baz %41
+               OpSelectionMerge %39 None
+               OpSwitch %40 %42
+         %42 = OpLabel
+               OpBranch %39
+         %39 = OpLabel
                OpReturn
                OpFunctionEnd
        %main = OpFunction %void None %5
-         %30 = OpLabel
+         %44 = OpLabel
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/bug/tint/534.wgsl.expected.dxc.hlsl b/test/tint/bug/tint/534.wgsl.expected.dxc.hlsl
index 19231d7..4bc8c01 100644
--- a/test/tint/bug/tint/534.wgsl.expected.dxc.hlsl
+++ b/test/tint/bug/tint/534.wgsl.expected.dxc.hlsl
@@ -2,6 +2,10 @@
   vec = (idx.xxxx == int4(0, 1, 2, 3)) ? val.xxxx : vec;
 }
 
+uint4 tint_ftou(float4 v) {
+  return ((v < (4294967040.0f).xxxx) ? ((v < (0.0f).xxxx) ? (0u).xxxx : uint4(v)) : (4294967295u).xxxx);
+}
+
 Texture2D<float4> src : register(t0, space0);
 Texture2D<float4> tint_symbol : register(t1, space0);
 RWByteAddressBuffer output : register(u2, space0);
@@ -30,7 +34,7 @@
   float4 dstColor = tint_symbol.Load(uint3(dstTexCoord, uint(0)));
   bool success = true;
   uint4 srcColorBits = uint4(0u, 0u, 0u, 0u);
-  uint4 dstColorBits = uint4(dstColor);
+  uint4 dstColorBits = tint_ftou(dstColor);
   {
     for(uint i = 0u; (i < uniforms[0].w); i = (i + 1u)) {
       const uint tint_symbol_1 = i;
diff --git a/test/tint/bug/tint/534.wgsl.expected.fxc.hlsl b/test/tint/bug/tint/534.wgsl.expected.fxc.hlsl
index 19231d7..4bc8c01 100644
--- a/test/tint/bug/tint/534.wgsl.expected.fxc.hlsl
+++ b/test/tint/bug/tint/534.wgsl.expected.fxc.hlsl
@@ -2,6 +2,10 @@
   vec = (idx.xxxx == int4(0, 1, 2, 3)) ? val.xxxx : vec;
 }
 
+uint4 tint_ftou(float4 v) {
+  return ((v < (4294967040.0f).xxxx) ? ((v < (0.0f).xxxx) ? (0u).xxxx : uint4(v)) : (4294967295u).xxxx);
+}
+
 Texture2D<float4> src : register(t0, space0);
 Texture2D<float4> tint_symbol : register(t1, space0);
 RWByteAddressBuffer output : register(u2, space0);
@@ -30,7 +34,7 @@
   float4 dstColor = tint_symbol.Load(uint3(dstTexCoord, uint(0)));
   bool success = true;
   uint4 srcColorBits = uint4(0u, 0u, 0u, 0u);
-  uint4 dstColorBits = uint4(dstColor);
+  uint4 dstColorBits = tint_ftou(dstColor);
   {
     for(uint i = 0u; (i < uniforms[0].w); i = (i + 1u)) {
       const uint tint_symbol_1 = i;
diff --git a/test/tint/bug/tint/534.wgsl.expected.glsl b/test/tint/bug/tint/534.wgsl.expected.glsl
index 8766dc1..49eb0a4 100644
--- a/test/tint/bug/tint/534.wgsl.expected.glsl
+++ b/test/tint/bug/tint/534.wgsl.expected.glsl
@@ -1,5 +1,14 @@
 #version 310 es
 
+uvec4 tint_select(uvec4 param_0, uvec4 param_1, bvec4 param_2) {
+    return uvec4(param_2[0] ? param_1[0] : param_0[0], param_2[1] ? param_1[1] : param_0[1], param_2[2] ? param_1[2] : param_0[2], param_2[3] ? param_1[3] : param_0[3]);
+}
+
+
+uvec4 tint_ftou(vec4 v) {
+  return tint_select(uvec4(4294967295u), tint_select(uvec4(v), uvec4(0u), lessThan(v, vec4(0.0f))), lessThan(v, vec4(4294967040.0f)));
+}
+
 struct Uniforms {
   uint dstTextureFlipY;
   uint isFloat16;
@@ -32,7 +41,7 @@
   vec4 dstColor = texelFetch(dst_1, ivec2(dstTexCoord), 0);
   bool success = true;
   uvec4 srcColorBits = uvec4(0u, 0u, 0u, 0u);
-  uvec4 dstColorBits = uvec4(dstColor);
+  uvec4 dstColorBits = tint_ftou(dstColor);
   {
     for(uint i = 0u; (i < uniforms.inner.channelCount); i = (i + 1u)) {
       uint tint_symbol_2 = i;
diff --git a/test/tint/bug/tint/534.wgsl.expected.msl b/test/tint/bug/tint/534.wgsl.expected.msl
index 89afccd..bd4ec92 100644
--- a/test/tint/bug/tint/534.wgsl.expected.msl
+++ b/test/tint/bug/tint/534.wgsl.expected.msl
@@ -14,6 +14,10 @@
     T elements[N];
 };
 
+uint4 tint_ftou(float4 v) {
+  return select(uint4(4294967295u), select(uint4(v), uint4(0u), (v < float4(0.0f))), (v < float4(4294967040.0f)));
+}
+
 struct Uniforms {
   /* 0x0000 */ uint dstTextureFlipY;
   /* 0x0004 */ uint isFloat16;
@@ -40,7 +44,7 @@
   float4 dstColor = tint_symbol_4.read(uint2(dstTexCoord), 0);
   bool success = true;
   uint4 srcColorBits = 0u;
-  uint4 dstColorBits = uint4(dstColor);
+  uint4 dstColorBits = tint_ftou(dstColor);
   for(uint i = 0u; (i < (*(tint_symbol_3)).channelCount); i = (i + 1u)) {
     uint const tint_symbol_1 = i;
     srcColorBits[tint_symbol_1] = ConvertToFp16FloatValue(srcColor[i]);
diff --git a/test/tint/bug/tint/534.wgsl.expected.spvasm b/test/tint/bug/tint/534.wgsl.expected.spvasm
index 9b373fd..719fbf2 100644
--- a/test/tint/bug/tint/534.wgsl.expected.spvasm
+++ b/test/tint/bug/tint/534.wgsl.expected.spvasm
@@ -1,7 +1,7 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 135
+; Bound: 149
 ; Schema: 0
                OpCapability Shader
                OpCapability ImageQuery
@@ -22,6 +22,8 @@
                OpMemberName %Uniforms 2 "isRGB10A2Unorm"
                OpMemberName %Uniforms 3 "channelCount"
                OpName %uniforms "uniforms"
+               OpName %tint_ftou "tint_ftou"
+               OpName %v "v"
                OpName %ConvertToFp16FloatValue "ConvertToFp16FloatValue"
                OpName %fp32 "fp32"
                OpName %main_inner "main_inner"
@@ -73,158 +75,174 @@
 %uniforms_block = OpTypeStruct %Uniforms
 %_ptr_Uniform_uniforms_block = OpTypePointer Uniform %uniforms_block
    %uniforms = OpVariable %_ptr_Uniform_uniforms_block Uniform
-         %18 = OpTypeFunction %uint %float
+     %v4uint = OpTypeVector %uint 4
+    %v4float = OpTypeVector %float 4
+         %18 = OpTypeFunction %v4uint %v4float
+%float_4_29496704e_09 = OpConstant %float 4.29496704e+09
+         %26 = OpConstantComposite %v4float %float_4_29496704e_09 %float_4_29496704e_09 %float_4_29496704e_09 %float_4_29496704e_09
+       %bool = OpTypeBool
+     %v4bool = OpTypeVector %bool 4
+         %31 = OpConstantNull %v4float
+         %33 = OpConstantNull %v4uint
+%uint_4294967295 = OpConstant %uint 4294967295
+         %36 = OpConstantComposite %v4uint %uint_4294967295 %uint_4294967295 %uint_4294967295 %uint_4294967295
+         %37 = OpTypeFunction %uint %float
      %uint_1 = OpConstant %uint 1
        %void = OpTypeVoid
-         %23 = OpTypeFunction %void %v3uint
+         %42 = OpTypeFunction %void %v3uint
      %v2uint = OpTypeVector %uint 2
         %int = OpTypeInt 32 1
       %int_0 = OpConstant %int 0
 %_ptr_Function_v2uint = OpTypePointer Function %v2uint
-         %35 = OpConstantNull %v2uint
+         %54 = OpConstantNull %v2uint
      %uint_0 = OpConstant %uint 0
 %_ptr_Uniform_uint = OpTypePointer Uniform %uint
-       %bool = OpTypeBool
 %_ptr_Function_uint = OpTypePointer Function %uint
-    %v4float = OpTypeVector %float 4
-         %60 = OpConstantNull %int
+         %77 = OpConstantNull %int
 %_ptr_Function_v4float = OpTypePointer Function %v4float
-         %63 = OpConstantNull %v4float
        %true = OpConstantTrue %bool
 %_ptr_Function_bool = OpTypePointer Function %bool
-         %71 = OpConstantNull %bool
-     %v4uint = OpTypeVector %uint 4
+         %87 = OpConstantNull %bool
 %_ptr_Function_v4uint = OpTypePointer Function %v4uint
-         %75 = OpConstantNull %v4uint
-         %79 = OpConstantNull %uint
+         %93 = OpConstantNull %uint
      %uint_3 = OpConstant %uint 3
 %_ptr_Function_float = OpTypePointer Function %float
 %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
-        %130 = OpTypeFunction %void
-%ConvertToFp16FloatValue = OpFunction %uint None %18
+        %144 = OpTypeFunction %void
+  %tint_ftou = OpFunction %v4uint None %18
+          %v = OpFunctionParameter %v4float
+         %23 = OpLabel
+         %27 = OpFOrdLessThan %v4bool %v %26
+         %32 = OpFOrdLessThan %v4bool %v %31
+         %34 = OpConvertFToU %v4uint %v
+         %30 = OpSelect %v4uint %32 %33 %34
+         %24 = OpSelect %v4uint %27 %30 %36
+               OpReturnValue %24
+               OpFunctionEnd
+%ConvertToFp16FloatValue = OpFunction %uint None %37
        %fp32 = OpFunctionParameter %float
-         %21 = OpLabel
+         %40 = OpLabel
                OpReturnValue %uint_1
                OpFunctionEnd
- %main_inner = OpFunction %void None %23
+ %main_inner = OpFunction %void None %42
 %GlobalInvocationID = OpFunctionParameter %v3uint
-         %27 = OpLabel
-       %size = OpVariable %_ptr_Function_v2uint Function %35
-%dstTexCoord = OpVariable %_ptr_Function_v2uint Function %35
-%srcTexCoord = OpVariable %_ptr_Function_v2uint Function %35
-   %srcColor = OpVariable %_ptr_Function_v4float Function %63
-   %dstColor = OpVariable %_ptr_Function_v4float Function %63
-    %success = OpVariable %_ptr_Function_bool Function %71
-%srcColorBits = OpVariable %_ptr_Function_v4uint Function %75
-%dstColorBits = OpVariable %_ptr_Function_v4uint Function %75
-          %i = OpVariable %_ptr_Function_uint Function %79
-%outputIndex = OpVariable %_ptr_Function_uint Function %79
-         %30 = OpLoad %7 %src
-         %28 = OpImageQuerySizeLod %v2uint %30 %int_0
-               OpStore %size %28
-         %36 = OpVectorShuffle %v2uint %GlobalInvocationID %GlobalInvocationID 0 1
-               OpStore %dstTexCoord %36
-         %38 = OpLoad %v2uint %dstTexCoord
-               OpStore %srcTexCoord %38
-         %42 = OpAccessChain %_ptr_Uniform_uint %uniforms %uint_0 %uint_0
-         %43 = OpLoad %uint %42
-         %44 = OpIEqual %bool %43 %uint_1
-               OpSelectionMerge %46 None
-               OpBranchConditional %44 %47 %46
-         %47 = OpLabel
-         %49 = OpAccessChain %_ptr_Function_uint %srcTexCoord %uint_1
-         %50 = OpAccessChain %_ptr_Function_uint %size %uint_1
-         %51 = OpLoad %uint %50
-         %52 = OpAccessChain %_ptr_Function_uint %dstTexCoord %uint_1
-         %53 = OpLoad %uint %52
-         %54 = OpISub %uint %51 %53
-         %55 = OpISub %uint %54 %uint_1
-               OpStore %49 %55
-               OpBranch %46
          %46 = OpLabel
-         %58 = OpLoad %7 %src
-         %59 = OpLoad %v2uint %srcTexCoord
-         %56 = OpImageFetch %v4float %58 %59 Lod %60
-               OpStore %srcColor %56
-         %65 = OpLoad %7 %dst
-         %66 = OpLoad %v2uint %dstTexCoord
-         %64 = OpImageFetch %v4float %65 %66 Lod %60
-               OpStore %dstColor %64
+       %size = OpVariable %_ptr_Function_v2uint Function %54
+%dstTexCoord = OpVariable %_ptr_Function_v2uint Function %54
+%srcTexCoord = OpVariable %_ptr_Function_v2uint Function %54
+   %srcColor = OpVariable %_ptr_Function_v4float Function %31
+   %dstColor = OpVariable %_ptr_Function_v4float Function %31
+    %success = OpVariable %_ptr_Function_bool Function %87
+%srcColorBits = OpVariable %_ptr_Function_v4uint Function %33
+%dstColorBits = OpVariable %_ptr_Function_v4uint Function %33
+          %i = OpVariable %_ptr_Function_uint Function %93
+%outputIndex = OpVariable %_ptr_Function_uint Function %93
+         %49 = OpLoad %7 %src
+         %47 = OpImageQuerySizeLod %v2uint %49 %int_0
+               OpStore %size %47
+         %55 = OpVectorShuffle %v2uint %GlobalInvocationID %GlobalInvocationID 0 1
+               OpStore %dstTexCoord %55
+         %57 = OpLoad %v2uint %dstTexCoord
+               OpStore %srcTexCoord %57
+         %61 = OpAccessChain %_ptr_Uniform_uint %uniforms %uint_0 %uint_0
+         %62 = OpLoad %uint %61
+         %63 = OpIEqual %bool %62 %uint_1
+               OpSelectionMerge %64 None
+               OpBranchConditional %63 %65 %64
+         %65 = OpLabel
+         %67 = OpAccessChain %_ptr_Function_uint %srcTexCoord %uint_1
+         %68 = OpAccessChain %_ptr_Function_uint %size %uint_1
+         %69 = OpLoad %uint %68
+         %70 = OpAccessChain %_ptr_Function_uint %dstTexCoord %uint_1
+         %71 = OpLoad %uint %70
+         %72 = OpISub %uint %69 %71
+         %73 = OpISub %uint %72 %uint_1
+               OpStore %67 %73
+               OpBranch %64
+         %64 = OpLabel
+         %75 = OpLoad %7 %src
+         %76 = OpLoad %v2uint %srcTexCoord
+         %74 = OpImageFetch %v4float %75 %76 Lod %77
+               OpStore %srcColor %74
+         %81 = OpLoad %7 %dst
+         %82 = OpLoad %v2uint %dstTexCoord
+         %80 = OpImageFetch %v4float %81 %82 Lod %77
+               OpStore %dstColor %80
                OpStore %success %true
-         %77 = OpLoad %v4float %dstColor
-         %76 = OpConvertFToU %v4uint %77
-               OpStore %dstColorBits %76
-               OpStore %i %79
-               OpBranch %81
-         %81 = OpLabel
-               OpLoopMerge %82 %83 None
-               OpBranch %84
-         %84 = OpLabel
-         %86 = OpLoad %uint %i
-         %88 = OpAccessChain %_ptr_Uniform_uint %uniforms %uint_0 %uint_3
-         %89 = OpLoad %uint %88
-         %90 = OpULessThan %bool %86 %89
-         %85 = OpLogicalNot %bool %90
-               OpSelectionMerge %91 None
-               OpBranchConditional %85 %92 %91
-         %92 = OpLabel
-               OpBranch %82
-         %91 = OpLabel
-         %93 = OpLoad %uint %i
-         %94 = OpAccessChain %_ptr_Function_uint %srcColorBits %93
-         %96 = OpLoad %uint %i
-         %98 = OpAccessChain %_ptr_Function_float %srcColor %96
-         %99 = OpLoad %float %98
-         %95 = OpFunctionCall %uint %ConvertToFp16FloatValue %99
-               OpStore %94 %95
-        %100 = OpLoad %bool %success
-               OpSelectionMerge %101 None
-               OpBranchConditional %100 %102 %101
-        %102 = OpLabel
-        %103 = OpLoad %uint %i
-        %104 = OpAccessChain %_ptr_Function_uint %srcColorBits %103
-        %105 = OpLoad %uint %104
-        %106 = OpLoad %uint %i
-        %107 = OpAccessChain %_ptr_Function_uint %dstColorBits %106
-        %108 = OpLoad %uint %107
-        %109 = OpIEqual %bool %105 %108
-               OpBranch %101
-        %101 = OpLabel
-        %110 = OpPhi %bool %100 %91 %109 %102
-               OpStore %success %110
-               OpBranch %83
-         %83 = OpLabel
-        %111 = OpLoad %uint %i
-        %112 = OpIAdd %uint %111 %uint_1
-               OpStore %i %112
-               OpBranch %81
-         %82 = OpLabel
-        %113 = OpCompositeExtract %uint %GlobalInvocationID 1
-        %115 = OpAccessChain %_ptr_Function_uint %size %uint_0
-        %116 = OpLoad %uint %115
-        %117 = OpIMul %uint %113 %116
-        %118 = OpCompositeExtract %uint %GlobalInvocationID 0
-        %119 = OpIAdd %uint %117 %118
-               OpStore %outputIndex %119
-        %121 = OpLoad %bool %success
-               OpSelectionMerge %122 None
-               OpBranchConditional %121 %123 %124
-        %123 = OpLabel
-        %125 = OpLoad %uint %outputIndex
-        %127 = OpAccessChain %_ptr_StorageBuffer_uint %output %uint_0 %125
-               OpStore %127 %uint_1
-               OpBranch %122
-        %124 = OpLabel
-        %128 = OpLoad %uint %outputIndex
-        %129 = OpAccessChain %_ptr_StorageBuffer_uint %output %uint_0 %128
-               OpStore %129 %79
-               OpBranch %122
-        %122 = OpLabel
+         %91 = OpLoad %v4float %dstColor
+         %90 = OpFunctionCall %v4uint %tint_ftou %91
+               OpStore %dstColorBits %90
+               OpStore %i %93
+               OpBranch %95
+         %95 = OpLabel
+               OpLoopMerge %96 %97 None
+               OpBranch %98
+         %98 = OpLabel
+        %100 = OpLoad %uint %i
+        %102 = OpAccessChain %_ptr_Uniform_uint %uniforms %uint_0 %uint_3
+        %103 = OpLoad %uint %102
+        %104 = OpULessThan %bool %100 %103
+         %99 = OpLogicalNot %bool %104
+               OpSelectionMerge %105 None
+               OpBranchConditional %99 %106 %105
+        %106 = OpLabel
+               OpBranch %96
+        %105 = OpLabel
+        %107 = OpLoad %uint %i
+        %108 = OpAccessChain %_ptr_Function_uint %srcColorBits %107
+        %110 = OpLoad %uint %i
+        %112 = OpAccessChain %_ptr_Function_float %srcColor %110
+        %113 = OpLoad %float %112
+        %109 = OpFunctionCall %uint %ConvertToFp16FloatValue %113
+               OpStore %108 %109
+        %114 = OpLoad %bool %success
+               OpSelectionMerge %115 None
+               OpBranchConditional %114 %116 %115
+        %116 = OpLabel
+        %117 = OpLoad %uint %i
+        %118 = OpAccessChain %_ptr_Function_uint %srcColorBits %117
+        %119 = OpLoad %uint %118
+        %120 = OpLoad %uint %i
+        %121 = OpAccessChain %_ptr_Function_uint %dstColorBits %120
+        %122 = OpLoad %uint %121
+        %123 = OpIEqual %bool %119 %122
+               OpBranch %115
+        %115 = OpLabel
+        %124 = OpPhi %bool %114 %105 %123 %116
+               OpStore %success %124
+               OpBranch %97
+         %97 = OpLabel
+        %125 = OpLoad %uint %i
+        %126 = OpIAdd %uint %125 %uint_1
+               OpStore %i %126
+               OpBranch %95
+         %96 = OpLabel
+        %127 = OpCompositeExtract %uint %GlobalInvocationID 1
+        %129 = OpAccessChain %_ptr_Function_uint %size %uint_0
+        %130 = OpLoad %uint %129
+        %131 = OpIMul %uint %127 %130
+        %132 = OpCompositeExtract %uint %GlobalInvocationID 0
+        %133 = OpIAdd %uint %131 %132
+               OpStore %outputIndex %133
+        %135 = OpLoad %bool %success
+               OpSelectionMerge %136 None
+               OpBranchConditional %135 %137 %138
+        %137 = OpLabel
+        %139 = OpLoad %uint %outputIndex
+        %141 = OpAccessChain %_ptr_StorageBuffer_uint %output %uint_0 %139
+               OpStore %141 %uint_1
+               OpBranch %136
+        %138 = OpLabel
+        %142 = OpLoad %uint %outputIndex
+        %143 = OpAccessChain %_ptr_StorageBuffer_uint %output %uint_0 %142
+               OpStore %143 %93
+               OpBranch %136
+        %136 = OpLabel
                OpReturn
                OpFunctionEnd
-       %main = OpFunction %void None %130
-        %132 = OpLabel
-        %134 = OpLoad %v3uint %GlobalInvocationID_1
-        %133 = OpFunctionCall %void %main_inner %134
+       %main = OpFunction %void None %144
+        %146 = OpLabel
+        %148 = OpLoad %v3uint %GlobalInvocationID_1
+        %147 = OpFunctionCall %void %main_inner %148
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/bug/tint/922.wgsl.expected.dxc.hlsl b/test/tint/bug/tint/922.wgsl.expected.dxc.hlsl
index ff0591f..430197e 100644
--- a/test/tint/bug/tint/922.wgsl.expected.dxc.hlsl
+++ b/test/tint/bug/tint/922.wgsl.expected.dxc.hlsl
@@ -1,3 +1,7 @@
+int tint_ftoi(float v) {
+  return ((v < 2147483520.0f) ? ((v < -2147483648.0f) ? -2147483648 : int(v)) : 2147483647);
+}
+
 struct Mat4x4_ {
   float4 mx;
   float4 my;
@@ -237,7 +241,7 @@
   Mat4x3_ t_PosMtx = (Mat4x3_)0;
   float2 t_TexSpaceCoord = float2(0.0f, 0.0f);
   const float x_e15 = a_PosMtxIdx1;
-  const Mat4x3_ x_e18 = global2_load((48u * uint(int(x_e15))));
+  const Mat4x3_ x_e18 = global2_load((48u * uint(tint_ftoi(x_e15))));
   t_PosMtx = x_e18;
   const Mat4x3_ x_e23 = t_PosMtx;
   const Mat4x4_ x_e24 = x_Mat4x4_1(x_e23);
diff --git a/test/tint/bug/tint/922.wgsl.expected.fxc.hlsl b/test/tint/bug/tint/922.wgsl.expected.fxc.hlsl
index ff0591f..430197e 100644
--- a/test/tint/bug/tint/922.wgsl.expected.fxc.hlsl
+++ b/test/tint/bug/tint/922.wgsl.expected.fxc.hlsl
@@ -1,3 +1,7 @@
+int tint_ftoi(float v) {
+  return ((v < 2147483520.0f) ? ((v < -2147483648.0f) ? -2147483648 : int(v)) : 2147483647);
+}
+
 struct Mat4x4_ {
   float4 mx;
   float4 my;
@@ -237,7 +241,7 @@
   Mat4x3_ t_PosMtx = (Mat4x3_)0;
   float2 t_TexSpaceCoord = float2(0.0f, 0.0f);
   const float x_e15 = a_PosMtxIdx1;
-  const Mat4x3_ x_e18 = global2_load((48u * uint(int(x_e15))));
+  const Mat4x3_ x_e18 = global2_load((48u * uint(tint_ftoi(x_e15))));
   t_PosMtx = x_e18;
   const Mat4x3_ x_e23 = t_PosMtx;
   const Mat4x4_ x_e24 = x_Mat4x4_1(x_e23);
diff --git a/test/tint/bug/tint/922.wgsl.expected.glsl b/test/tint/bug/tint/922.wgsl.expected.glsl
index 8b0bb79..d67d923 100644
--- a/test/tint/bug/tint/922.wgsl.expected.glsl
+++ b/test/tint/bug/tint/922.wgsl.expected.glsl
@@ -7,6 +7,10 @@
 layout(location = 4) in float a_PosMtxIdx_1;
 layout(location = 0) out vec4 v_Color_1;
 layout(location = 1) out vec2 v_TexCoord_1;
+int tint_ftoi(float v) {
+  return ((v < 2147483520.0f) ? ((v < -2147483648.0f) ? (-2147483647 - 1) : int(v)) : 2147483647);
+}
+
 struct Mat4x4_ {
   vec4 mx;
   vec4 my;
@@ -128,7 +132,7 @@
   Mat4x3_ t_PosMtx = Mat4x3_(vec4(0.0f, 0.0f, 0.0f, 0.0f), vec4(0.0f, 0.0f, 0.0f, 0.0f), vec4(0.0f, 0.0f, 0.0f, 0.0f));
   vec2 t_TexSpaceCoord = vec2(0.0f, 0.0f);
   float x_e15 = a_PosMtxIdx1;
-  Mat4x3_ x_e18 = global2.inner.u_PosMtx[int(x_e15)];
+  Mat4x3_ x_e18 = global2.inner.u_PosMtx[tint_ftoi(x_e15)];
   t_PosMtx = x_e18;
   Mat4x3_ x_e23 = t_PosMtx;
   Mat4x4_ x_e24 = x_Mat4x4_1(x_e23);
diff --git a/test/tint/bug/tint/922.wgsl.expected.msl b/test/tint/bug/tint/922.wgsl.expected.msl
index 11c4319..71503ce 100644
--- a/test/tint/bug/tint/922.wgsl.expected.msl
+++ b/test/tint/bug/tint/922.wgsl.expected.msl
@@ -14,6 +14,10 @@
     T elements[N];
 };
 
+int tint_ftoi(float v) {
+  return select(2147483647, select(int(v), (-2147483647 - 1), (v < -2147483648.0f)), (v < 2147483520.0f));
+}
+
 struct Mat4x4_ {
   /* 0x0000 */ float4 mx;
   /* 0x0010 */ float4 my;
@@ -227,7 +231,7 @@
   Mat4x3_ t_PosMtx = {};
   float2 t_TexSpaceCoord = 0.0f;
   float const x_e15 = *(tint_symbol_5);
-  Mat4x3_ const x_e18 = (*(tint_symbol_6)).u_PosMtx[int(x_e15)];
+  Mat4x3_ const x_e18 = (*(tint_symbol_6)).u_PosMtx[tint_ftoi(x_e15)];
   t_PosMtx = x_e18;
   Mat4x3_ const x_e23 = t_PosMtx;
   Mat4x4_ const x_e24 = x_Mat4x4_1(x_e23);
diff --git a/test/tint/bug/tint/922.wgsl.expected.spvasm b/test/tint/bug/tint/922.wgsl.expected.spvasm
index 69a7d4d..a66b0fd 100644
--- a/test/tint/bug/tint/922.wgsl.expected.spvasm
+++ b/test/tint/bug/tint/922.wgsl.expected.spvasm
@@ -1,7 +1,7 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 393
+; Bound: 406
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
@@ -51,6 +51,8 @@
                OpName %v_Color "v_Color"
                OpName %v_TexCoord "v_TexCoord"
                OpName %gl_Position "gl_Position"
+               OpName %tint_ftoi "tint_ftoi"
+               OpName %v "v"
                OpName %Mat4x3GetCol0_ "Mat4x3GetCol0_"
                OpName %m "m"
                OpName %m1 "m1"
@@ -65,7 +67,7 @@
                OpName %m7 "m7"
                OpName %Mul "Mul"
                OpName %m8 "m8"
-               OpName %v "v"
+               OpName %v_0 "v"
                OpName %m9 "m9"
                OpName %v1 "v1"
                OpName %Mul1 "Mul1"
@@ -216,425 +218,440 @@
     %v_Color = OpVariable %_ptr_Private_v4float Private %16
  %v_TexCoord = OpVariable %_ptr_Private_v2float Private %19
 %gl_Position = OpVariable %_ptr_Private_v4float Private %16
-         %57 = OpTypeFunction %v3float %Mat4x3_
+        %int = OpTypeInt 32 1
+         %57 = OpTypeFunction %int %float
+%float_2_14748352e_09 = OpConstant %float 2.14748352e+09
+       %bool = OpTypeBool
+%float_n2_14748365e_09 = OpConstant %float -2.14748365e+09
+%int_n2147483648 = OpConstant %int -2147483648
+%int_2147483647 = OpConstant %int 2147483647
+         %72 = OpTypeFunction %v3float %Mat4x3_
 %_ptr_Function_Mat4x3_ = OpTypePointer Function %Mat4x3_
-         %63 = OpConstantNull %Mat4x3_
-        %116 = OpTypeFunction %v4float %Mat4x4_ %v4float
+         %78 = OpConstantNull %Mat4x3_
+        %131 = OpTypeFunction %v4float %Mat4x4_ %v4float
 %_ptr_Function_Mat4x4_ = OpTypePointer Function %Mat4x4_
-        %123 = OpConstantNull %Mat4x4_
+        %138 = OpConstantNull %Mat4x4_
 %_ptr_Function_v4float = OpTypePointer Function %v4float
-        %143 = OpTypeFunction %v3float %Mat4x3_ %v4float
-        %163 = OpTypeFunction %v2float %Mat4x2_ %v4float
+        %158 = OpTypeFunction %v3float %Mat4x3_ %v4float
+        %178 = OpTypeFunction %v2float %Mat4x2_ %v4float
 %_ptr_Function_Mat4x2_ = OpTypePointer Function %Mat4x2_
-        %170 = OpConstantNull %Mat4x2_
-        %181 = OpTypeFunction %v4float %v3float %Mat4x3_
+        %185 = OpConstantNull %Mat4x2_
+        %196 = OpTypeFunction %v4float %v3float %Mat4x3_
 %_ptr_Function_v3float = OpTypePointer Function %v3float
-        %206 = OpTypeFunction %Mat4x4_ %float
+        %221 = OpTypeFunction %Mat4x4_ %float
 %_ptr_Function_float = OpTypePointer Function %float
      %uint_0 = OpConstant %uint 0
      %uint_2 = OpConstant %uint 2
      %uint_3 = OpConstant %uint 3
-        %229 = OpTypeFunction %Mat4x4_ %Mat4x3_
+        %244 = OpTypeFunction %Mat4x4_ %Mat4x3_
     %float_1 = OpConstant %float 1
-        %247 = OpTypeFunction %Mat4x4_ %Mat4x2_
-        %261 = OpTypeFunction %Mat4x3_ %float
-        %277 = OpTypeFunction %Mat4x3_ %Mat4x4_
+        %262 = OpTypeFunction %Mat4x4_ %Mat4x2_
+        %276 = OpTypeFunction %Mat4x3_ %float
+        %292 = OpTypeFunction %Mat4x3_ %Mat4x4_
        %void = OpTypeVoid
-        %293 = OpTypeFunction %void
-       %bool = OpTypeBool
+        %308 = OpTypeFunction %void
 %_ptr_Function_bool = OpTypePointer Function %bool
-        %300 = OpConstantNull %bool
+        %314 = OpConstantNull %bool
 %_ptr_Function_v2float = OpTypePointer Function %v2float
-        %int = OpTypeInt 32 1
 %_ptr_Uniform_Mat4x3_ = OpTypePointer Uniform %Mat4x3_
 %_ptr_Uniform_Mat4x4_ = OpTypePointer Uniform %Mat4x4_
 %_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
     %float_2 = OpConstant %float 2
-        %347 = OpConstantNull %int
+        %360 = OpConstantNull %int
 %_ptr_Uniform_Mat4x2_ = OpTypePointer Uniform %Mat4x2_
        %true = OpConstantTrue %bool
 %VertexOutput = OpTypeStruct %v4float %v2float %v4float
-        %368 = OpTypeFunction %VertexOutput %v3float %v2float %v4float %v3float %float
-%Mat4x3GetCol0_ = OpFunction %v3float None %57
+        %381 = OpTypeFunction %VertexOutput %v3float %v2float %v4float %v3float %float
+  %tint_ftoi = OpFunction %int None %57
+          %v = OpFunctionParameter %float
+         %61 = OpLabel
+         %64 = OpFOrdLessThan %bool %v %float_2_14748352e_09
+         %68 = OpFOrdLessThan %bool %v %float_n2_14748365e_09
+         %70 = OpConvertFToS %int %v
+         %66 = OpSelect %int %68 %int_n2147483648 %70
+         %62 = OpSelect %int %64 %66 %int_2147483647
+               OpReturnValue %62
+               OpFunctionEnd
+%Mat4x3GetCol0_ = OpFunction %v3float None %72
           %m = OpFunctionParameter %Mat4x3_
-         %60 = OpLabel
-         %m1 = OpVariable %_ptr_Function_Mat4x3_ Function %63
+         %75 = OpLabel
+         %m1 = OpVariable %_ptr_Function_Mat4x3_ Function %78
                OpStore %m1 %m
-         %64 = OpLoad %Mat4x3_ %m1
-         %65 = OpLoad %Mat4x3_ %m1
-         %66 = OpLoad %Mat4x3_ %m1
-         %67 = OpCompositeExtract %v4float %64 0
-         %68 = OpCompositeExtract %float %67 0
-         %69 = OpCompositeExtract %v4float %65 1
-         %70 = OpCompositeExtract %float %69 0
-         %71 = OpCompositeExtract %v4float %66 2
-         %72 = OpCompositeExtract %float %71 0
-         %73 = OpCompositeConstruct %v3float %68 %70 %72
-               OpReturnValue %73
+         %79 = OpLoad %Mat4x3_ %m1
+         %80 = OpLoad %Mat4x3_ %m1
+         %81 = OpLoad %Mat4x3_ %m1
+         %82 = OpCompositeExtract %v4float %79 0
+         %83 = OpCompositeExtract %float %82 0
+         %84 = OpCompositeExtract %v4float %80 1
+         %85 = OpCompositeExtract %float %84 0
+         %86 = OpCompositeExtract %v4float %81 2
+         %87 = OpCompositeExtract %float %86 0
+         %88 = OpCompositeConstruct %v3float %83 %85 %87
+               OpReturnValue %88
                OpFunctionEnd
-%Mat4x3GetCol1_ = OpFunction %v3float None %57
+%Mat4x3GetCol1_ = OpFunction %v3float None %72
          %m2 = OpFunctionParameter %Mat4x3_
-         %76 = OpLabel
-         %m3 = OpVariable %_ptr_Function_Mat4x3_ Function %63
+         %91 = OpLabel
+         %m3 = OpVariable %_ptr_Function_Mat4x3_ Function %78
                OpStore %m3 %m2
-         %78 = OpLoad %Mat4x3_ %m3
-         %79 = OpLoad %Mat4x3_ %m3
-         %80 = OpLoad %Mat4x3_ %m3
-         %81 = OpCompositeExtract %v4float %78 0
-         %82 = OpCompositeExtract %float %81 1
-         %83 = OpCompositeExtract %v4float %79 1
-         %84 = OpCompositeExtract %float %83 1
-         %85 = OpCompositeExtract %v4float %80 2
-         %86 = OpCompositeExtract %float %85 1
-         %87 = OpCompositeConstruct %v3float %82 %84 %86
-               OpReturnValue %87
+         %93 = OpLoad %Mat4x3_ %m3
+         %94 = OpLoad %Mat4x3_ %m3
+         %95 = OpLoad %Mat4x3_ %m3
+         %96 = OpCompositeExtract %v4float %93 0
+         %97 = OpCompositeExtract %float %96 1
+         %98 = OpCompositeExtract %v4float %94 1
+         %99 = OpCompositeExtract %float %98 1
+        %100 = OpCompositeExtract %v4float %95 2
+        %101 = OpCompositeExtract %float %100 1
+        %102 = OpCompositeConstruct %v3float %97 %99 %101
+               OpReturnValue %102
                OpFunctionEnd
-%Mat4x3GetCol2_ = OpFunction %v3float None %57
+%Mat4x3GetCol2_ = OpFunction %v3float None %72
          %m4 = OpFunctionParameter %Mat4x3_
-         %90 = OpLabel
-         %m5 = OpVariable %_ptr_Function_Mat4x3_ Function %63
+        %105 = OpLabel
+         %m5 = OpVariable %_ptr_Function_Mat4x3_ Function %78
                OpStore %m5 %m4
-         %92 = OpLoad %Mat4x3_ %m5
-         %93 = OpLoad %Mat4x3_ %m5
-         %94 = OpLoad %Mat4x3_ %m5
-         %95 = OpCompositeExtract %v4float %92 0
-         %96 = OpCompositeExtract %float %95 2
-         %97 = OpCompositeExtract %v4float %93 1
-         %98 = OpCompositeExtract %float %97 2
-         %99 = OpCompositeExtract %v4float %94 2
-        %100 = OpCompositeExtract %float %99 2
-        %101 = OpCompositeConstruct %v3float %96 %98 %100
-               OpReturnValue %101
+        %107 = OpLoad %Mat4x3_ %m5
+        %108 = OpLoad %Mat4x3_ %m5
+        %109 = OpLoad %Mat4x3_ %m5
+        %110 = OpCompositeExtract %v4float %107 0
+        %111 = OpCompositeExtract %float %110 2
+        %112 = OpCompositeExtract %v4float %108 1
+        %113 = OpCompositeExtract %float %112 2
+        %114 = OpCompositeExtract %v4float %109 2
+        %115 = OpCompositeExtract %float %114 2
+        %116 = OpCompositeConstruct %v3float %111 %113 %115
+               OpReturnValue %116
                OpFunctionEnd
-%Mat4x3GetCol3_ = OpFunction %v3float None %57
+%Mat4x3GetCol3_ = OpFunction %v3float None %72
          %m6 = OpFunctionParameter %Mat4x3_
-        %104 = OpLabel
-         %m7 = OpVariable %_ptr_Function_Mat4x3_ Function %63
+        %119 = OpLabel
+         %m7 = OpVariable %_ptr_Function_Mat4x3_ Function %78
                OpStore %m7 %m6
-        %106 = OpLoad %Mat4x3_ %m7
-        %107 = OpLoad %Mat4x3_ %m7
-        %108 = OpLoad %Mat4x3_ %m7
-        %109 = OpCompositeExtract %v4float %106 0
-        %110 = OpCompositeExtract %float %109 3
-        %111 = OpCompositeExtract %v4float %107 1
-        %112 = OpCompositeExtract %float %111 3
-        %113 = OpCompositeExtract %v4float %108 2
-        %114 = OpCompositeExtract %float %113 3
-        %115 = OpCompositeConstruct %v3float %110 %112 %114
-               OpReturnValue %115
+        %121 = OpLoad %Mat4x3_ %m7
+        %122 = OpLoad %Mat4x3_ %m7
+        %123 = OpLoad %Mat4x3_ %m7
+        %124 = OpCompositeExtract %v4float %121 0
+        %125 = OpCompositeExtract %float %124 3
+        %126 = OpCompositeExtract %v4float %122 1
+        %127 = OpCompositeExtract %float %126 3
+        %128 = OpCompositeExtract %v4float %123 2
+        %129 = OpCompositeExtract %float %128 3
+        %130 = OpCompositeConstruct %v3float %125 %127 %129
+               OpReturnValue %130
                OpFunctionEnd
-        %Mul = OpFunction %v4float None %116
+        %Mul = OpFunction %v4float None %131
          %m8 = OpFunctionParameter %Mat4x4_
-          %v = OpFunctionParameter %v4float
-        %120 = OpLabel
-         %m9 = OpVariable %_ptr_Function_Mat4x4_ Function %123
+        %v_0 = OpFunctionParameter %v4float
+        %135 = OpLabel
+         %m9 = OpVariable %_ptr_Function_Mat4x4_ Function %138
          %v1 = OpVariable %_ptr_Function_v4float Function %16
                OpStore %m9 %m8
-               OpStore %v1 %v
-        %126 = OpLoad %Mat4x4_ %m9
-        %127 = OpLoad %v4float %v1
-        %128 = OpLoad %Mat4x4_ %m9
-        %129 = OpLoad %v4float %v1
-        %130 = OpLoad %Mat4x4_ %m9
-        %131 = OpLoad %v4float %v1
-        %132 = OpLoad %Mat4x4_ %m9
-        %133 = OpLoad %v4float %v1
-        %135 = OpCompositeExtract %v4float %126 0
-        %134 = OpDot %float %135 %127
-        %137 = OpCompositeExtract %v4float %128 1
-        %136 = OpDot %float %137 %129
-        %139 = OpCompositeExtract %v4float %130 2
-        %138 = OpDot %float %139 %131
-        %141 = OpCompositeExtract %v4float %132 3
-        %140 = OpDot %float %141 %133
-        %142 = OpCompositeConstruct %v4float %134 %136 %138 %140
-               OpReturnValue %142
+               OpStore %v1 %v_0
+        %141 = OpLoad %Mat4x4_ %m9
+        %142 = OpLoad %v4float %v1
+        %143 = OpLoad %Mat4x4_ %m9
+        %144 = OpLoad %v4float %v1
+        %145 = OpLoad %Mat4x4_ %m9
+        %146 = OpLoad %v4float %v1
+        %147 = OpLoad %Mat4x4_ %m9
+        %148 = OpLoad %v4float %v1
+        %150 = OpCompositeExtract %v4float %141 0
+        %149 = OpDot %float %150 %142
+        %152 = OpCompositeExtract %v4float %143 1
+        %151 = OpDot %float %152 %144
+        %154 = OpCompositeExtract %v4float %145 2
+        %153 = OpDot %float %154 %146
+        %156 = OpCompositeExtract %v4float %147 3
+        %155 = OpDot %float %156 %148
+        %157 = OpCompositeConstruct %v4float %149 %151 %153 %155
+               OpReturnValue %157
                OpFunctionEnd
-       %Mul1 = OpFunction %v3float None %143
+       %Mul1 = OpFunction %v3float None %158
         %m10 = OpFunctionParameter %Mat4x3_
          %v2 = OpFunctionParameter %v4float
-        %147 = OpLabel
-        %m11 = OpVariable %_ptr_Function_Mat4x3_ Function %63
+        %162 = OpLabel
+        %m11 = OpVariable %_ptr_Function_Mat4x3_ Function %78
          %v3 = OpVariable %_ptr_Function_v4float Function %16
                OpStore %m11 %m10
                OpStore %v3 %v2
-        %150 = OpLoad %Mat4x3_ %m11
-        %151 = OpLoad %v4float %v3
-        %152 = OpLoad %Mat4x3_ %m11
-        %153 = OpLoad %v4float %v3
-        %154 = OpLoad %Mat4x3_ %m11
-        %155 = OpLoad %v4float %v3
-        %157 = OpCompositeExtract %v4float %150 0
-        %156 = OpDot %float %157 %151
-        %159 = OpCompositeExtract %v4float %152 1
-        %158 = OpDot %float %159 %153
-        %161 = OpCompositeExtract %v4float %154 2
-        %160 = OpDot %float %161 %155
-        %162 = OpCompositeConstruct %v3float %156 %158 %160
-               OpReturnValue %162
+        %165 = OpLoad %Mat4x3_ %m11
+        %166 = OpLoad %v4float %v3
+        %167 = OpLoad %Mat4x3_ %m11
+        %168 = OpLoad %v4float %v3
+        %169 = OpLoad %Mat4x3_ %m11
+        %170 = OpLoad %v4float %v3
+        %172 = OpCompositeExtract %v4float %165 0
+        %171 = OpDot %float %172 %166
+        %174 = OpCompositeExtract %v4float %167 1
+        %173 = OpDot %float %174 %168
+        %176 = OpCompositeExtract %v4float %169 2
+        %175 = OpDot %float %176 %170
+        %177 = OpCompositeConstruct %v3float %171 %173 %175
+               OpReturnValue %177
                OpFunctionEnd
-       %Mul2 = OpFunction %v2float None %163
+       %Mul2 = OpFunction %v2float None %178
         %m12 = OpFunctionParameter %Mat4x2_
          %v4 = OpFunctionParameter %v4float
-        %167 = OpLabel
-        %m13 = OpVariable %_ptr_Function_Mat4x2_ Function %170
+        %182 = OpLabel
+        %m13 = OpVariable %_ptr_Function_Mat4x2_ Function %185
          %v5 = OpVariable %_ptr_Function_v4float Function %16
                OpStore %m13 %m12
                OpStore %v5 %v4
-        %172 = OpLoad %Mat4x2_ %m13
-        %173 = OpLoad %v4float %v5
-        %174 = OpLoad %Mat4x2_ %m13
-        %175 = OpLoad %v4float %v5
-        %177 = OpCompositeExtract %v4float %172 0
-        %176 = OpDot %float %177 %173
-        %179 = OpCompositeExtract %v4float %174 1
-        %178 = OpDot %float %179 %175
-        %180 = OpCompositeConstruct %v2float %176 %178
-               OpReturnValue %180
+        %187 = OpLoad %Mat4x2_ %m13
+        %188 = OpLoad %v4float %v5
+        %189 = OpLoad %Mat4x2_ %m13
+        %190 = OpLoad %v4float %v5
+        %192 = OpCompositeExtract %v4float %187 0
+        %191 = OpDot %float %192 %188
+        %194 = OpCompositeExtract %v4float %189 1
+        %193 = OpDot %float %194 %190
+        %195 = OpCompositeConstruct %v2float %191 %193
+               OpReturnValue %195
                OpFunctionEnd
-       %Mul3 = OpFunction %v4float None %181
+       %Mul3 = OpFunction %v4float None %196
          %v6 = OpFunctionParameter %v3float
         %m14 = OpFunctionParameter %Mat4x3_
-        %185 = OpLabel
+        %200 = OpLabel
          %v7 = OpVariable %_ptr_Function_v3float Function %46
-        %m15 = OpVariable %_ptr_Function_Mat4x3_ Function %63
+        %m15 = OpVariable %_ptr_Function_Mat4x3_ Function %78
                OpStore %v7 %v6
                OpStore %m15 %m14
-        %189 = OpLoad %Mat4x3_ %m15
-        %190 = OpFunctionCall %v3float %Mat4x3GetCol0_ %189
-        %191 = OpLoad %v3float %v7
-        %192 = OpLoad %Mat4x3_ %m15
-        %193 = OpFunctionCall %v3float %Mat4x3GetCol1_ %192
-        %194 = OpLoad %v3float %v7
-        %195 = OpLoad %Mat4x3_ %m15
-        %196 = OpFunctionCall %v3float %Mat4x3GetCol2_ %195
-        %197 = OpLoad %v3float %v7
-        %198 = OpLoad %Mat4x3_ %m15
-        %199 = OpFunctionCall %v3float %Mat4x3GetCol3_ %198
-        %200 = OpLoad %v3float %v7
-        %201 = OpDot %float %190 %191
-        %202 = OpDot %float %193 %194
-        %203 = OpDot %float %196 %197
-        %204 = OpDot %float %199 %200
-        %205 = OpCompositeConstruct %v4float %201 %202 %203 %204
-               OpReturnValue %205
+        %204 = OpLoad %Mat4x3_ %m15
+        %205 = OpFunctionCall %v3float %Mat4x3GetCol0_ %204
+        %206 = OpLoad %v3float %v7
+        %207 = OpLoad %Mat4x3_ %m15
+        %208 = OpFunctionCall %v3float %Mat4x3GetCol1_ %207
+        %209 = OpLoad %v3float %v7
+        %210 = OpLoad %Mat4x3_ %m15
+        %211 = OpFunctionCall %v3float %Mat4x3GetCol2_ %210
+        %212 = OpLoad %v3float %v7
+        %213 = OpLoad %Mat4x3_ %m15
+        %214 = OpFunctionCall %v3float %Mat4x3GetCol3_ %213
+        %215 = OpLoad %v3float %v7
+        %216 = OpDot %float %205 %206
+        %217 = OpDot %float %208 %209
+        %218 = OpDot %float %211 %212
+        %219 = OpDot %float %214 %215
+        %220 = OpCompositeConstruct %v4float %216 %217 %218 %219
+               OpReturnValue %220
                OpFunctionEnd
-  %x_Mat4x4_ = OpFunction %Mat4x4_ None %206
+  %x_Mat4x4_ = OpFunction %Mat4x4_ None %221
           %n = OpFunctionParameter %float
-        %209 = OpLabel
+        %224 = OpLabel
          %n1 = OpVariable %_ptr_Function_float Function %23
-          %o = OpVariable %_ptr_Function_Mat4x4_ Function %123
+          %o = OpVariable %_ptr_Function_Mat4x4_ Function %138
                OpStore %n1 %n
-        %213 = OpLoad %float %n1
-        %215 = OpAccessChain %_ptr_Function_v4float %o %uint_0
-        %216 = OpCompositeConstruct %v4float %213 %23 %23 %23
-               OpStore %215 %216
-        %217 = OpLoad %float %n1
-        %218 = OpAccessChain %_ptr_Function_v4float %o %uint_1
-        %219 = OpCompositeConstruct %v4float %23 %217 %23 %23
-               OpStore %218 %219
-        %220 = OpLoad %float %n1
-        %222 = OpAccessChain %_ptr_Function_v4float %o %uint_2
-        %223 = OpCompositeConstruct %v4float %23 %23 %220 %23
-               OpStore %222 %223
-        %224 = OpLoad %float %n1
-        %226 = OpAccessChain %_ptr_Function_v4float %o %uint_3
-        %227 = OpCompositeConstruct %v4float %23 %23 %23 %224
-               OpStore %226 %227
-        %228 = OpLoad %Mat4x4_ %o
-               OpReturnValue %228
-               OpFunctionEnd
- %x_Mat4x4_1 = OpFunction %Mat4x4_ None %229
-        %m16 = OpFunctionParameter %Mat4x3_
-        %232 = OpLabel
-        %m17 = OpVariable %_ptr_Function_Mat4x3_ Function %63
-         %o1 = OpVariable %_ptr_Function_Mat4x4_ Function %123
-               OpStore %m17 %m16
-        %235 = OpFunctionCall %Mat4x4_ %x_Mat4x4_ %float_1
-               OpStore %o1 %235
-        %237 = OpLoad %Mat4x3_ %m17
-        %238 = OpAccessChain %_ptr_Function_v4float %o1 %uint_0
-        %239 = OpCompositeExtract %v4float %237 0
-               OpStore %238 %239
-        %240 = OpLoad %Mat4x3_ %m17
-        %241 = OpAccessChain %_ptr_Function_v4float %o1 %uint_1
-        %242 = OpCompositeExtract %v4float %240 1
+        %228 = OpLoad %float %n1
+        %230 = OpAccessChain %_ptr_Function_v4float %o %uint_0
+        %231 = OpCompositeConstruct %v4float %228 %23 %23 %23
+               OpStore %230 %231
+        %232 = OpLoad %float %n1
+        %233 = OpAccessChain %_ptr_Function_v4float %o %uint_1
+        %234 = OpCompositeConstruct %v4float %23 %232 %23 %23
+               OpStore %233 %234
+        %235 = OpLoad %float %n1
+        %237 = OpAccessChain %_ptr_Function_v4float %o %uint_2
+        %238 = OpCompositeConstruct %v4float %23 %23 %235 %23
+               OpStore %237 %238
+        %239 = OpLoad %float %n1
+        %241 = OpAccessChain %_ptr_Function_v4float %o %uint_3
+        %242 = OpCompositeConstruct %v4float %23 %23 %23 %239
                OpStore %241 %242
-        %243 = OpLoad %Mat4x3_ %m17
-        %244 = OpAccessChain %_ptr_Function_v4float %o1 %uint_2
-        %245 = OpCompositeExtract %v4float %243 2
-               OpStore %244 %245
-        %246 = OpLoad %Mat4x4_ %o1
-               OpReturnValue %246
+        %243 = OpLoad %Mat4x4_ %o
+               OpReturnValue %243
                OpFunctionEnd
- %x_Mat4x4_2 = OpFunction %Mat4x4_ None %247
+ %x_Mat4x4_1 = OpFunction %Mat4x4_ None %244
+        %m16 = OpFunctionParameter %Mat4x3_
+        %247 = OpLabel
+        %m17 = OpVariable %_ptr_Function_Mat4x3_ Function %78
+         %o1 = OpVariable %_ptr_Function_Mat4x4_ Function %138
+               OpStore %m17 %m16
+        %250 = OpFunctionCall %Mat4x4_ %x_Mat4x4_ %float_1
+               OpStore %o1 %250
+        %252 = OpLoad %Mat4x3_ %m17
+        %253 = OpAccessChain %_ptr_Function_v4float %o1 %uint_0
+        %254 = OpCompositeExtract %v4float %252 0
+               OpStore %253 %254
+        %255 = OpLoad %Mat4x3_ %m17
+        %256 = OpAccessChain %_ptr_Function_v4float %o1 %uint_1
+        %257 = OpCompositeExtract %v4float %255 1
+               OpStore %256 %257
+        %258 = OpLoad %Mat4x3_ %m17
+        %259 = OpAccessChain %_ptr_Function_v4float %o1 %uint_2
+        %260 = OpCompositeExtract %v4float %258 2
+               OpStore %259 %260
+        %261 = OpLoad %Mat4x4_ %o1
+               OpReturnValue %261
+               OpFunctionEnd
+ %x_Mat4x4_2 = OpFunction %Mat4x4_ None %262
         %m18 = OpFunctionParameter %Mat4x2_
-        %250 = OpLabel
-        %m19 = OpVariable %_ptr_Function_Mat4x2_ Function %170
-         %o2 = OpVariable %_ptr_Function_Mat4x4_ Function %123
+        %265 = OpLabel
+        %m19 = OpVariable %_ptr_Function_Mat4x2_ Function %185
+         %o2 = OpVariable %_ptr_Function_Mat4x4_ Function %138
                OpStore %m19 %m18
-        %253 = OpFunctionCall %Mat4x4_ %x_Mat4x4_ %float_1
-               OpStore %o2 %253
-        %254 = OpLoad %Mat4x2_ %m19
-        %255 = OpAccessChain %_ptr_Function_v4float %o2 %uint_0
-        %256 = OpCompositeExtract %v4float %254 0
-               OpStore %255 %256
-        %257 = OpLoad %Mat4x2_ %m19
-        %258 = OpAccessChain %_ptr_Function_v4float %o2 %uint_1
-        %259 = OpCompositeExtract %v4float %257 1
-               OpStore %258 %259
-        %260 = OpLoad %Mat4x4_ %o2
-               OpReturnValue %260
+        %268 = OpFunctionCall %Mat4x4_ %x_Mat4x4_ %float_1
+               OpStore %o2 %268
+        %269 = OpLoad %Mat4x2_ %m19
+        %270 = OpAccessChain %_ptr_Function_v4float %o2 %uint_0
+        %271 = OpCompositeExtract %v4float %269 0
+               OpStore %270 %271
+        %272 = OpLoad %Mat4x2_ %m19
+        %273 = OpAccessChain %_ptr_Function_v4float %o2 %uint_1
+        %274 = OpCompositeExtract %v4float %272 1
+               OpStore %273 %274
+        %275 = OpLoad %Mat4x4_ %o2
+               OpReturnValue %275
                OpFunctionEnd
-  %x_Mat4x3_ = OpFunction %Mat4x3_ None %261
+  %x_Mat4x3_ = OpFunction %Mat4x3_ None %276
          %n2 = OpFunctionParameter %float
-        %264 = OpLabel
+        %279 = OpLabel
          %n3 = OpVariable %_ptr_Function_float Function %23
-         %o3 = OpVariable %_ptr_Function_Mat4x3_ Function %63
+         %o3 = OpVariable %_ptr_Function_Mat4x3_ Function %78
                OpStore %n3 %n2
-        %267 = OpLoad %float %n3
-        %268 = OpAccessChain %_ptr_Function_v4float %o3 %uint_0
-        %269 = OpCompositeConstruct %v4float %267 %23 %23 %23
-               OpStore %268 %269
-        %270 = OpLoad %float %n3
-        %271 = OpAccessChain %_ptr_Function_v4float %o3 %uint_1
-        %272 = OpCompositeConstruct %v4float %23 %270 %23 %23
-               OpStore %271 %272
-        %273 = OpLoad %float %n3
-        %274 = OpAccessChain %_ptr_Function_v4float %o3 %uint_2
-        %275 = OpCompositeConstruct %v4float %23 %23 %273 %23
-               OpStore %274 %275
-        %276 = OpLoad %Mat4x3_ %o3
-               OpReturnValue %276
+        %282 = OpLoad %float %n3
+        %283 = OpAccessChain %_ptr_Function_v4float %o3 %uint_0
+        %284 = OpCompositeConstruct %v4float %282 %23 %23 %23
+               OpStore %283 %284
+        %285 = OpLoad %float %n3
+        %286 = OpAccessChain %_ptr_Function_v4float %o3 %uint_1
+        %287 = OpCompositeConstruct %v4float %23 %285 %23 %23
+               OpStore %286 %287
+        %288 = OpLoad %float %n3
+        %289 = OpAccessChain %_ptr_Function_v4float %o3 %uint_2
+        %290 = OpCompositeConstruct %v4float %23 %23 %288 %23
+               OpStore %289 %290
+        %291 = OpLoad %Mat4x3_ %o3
+               OpReturnValue %291
                OpFunctionEnd
- %x_Mat4x3_1 = OpFunction %Mat4x3_ None %277
+ %x_Mat4x3_1 = OpFunction %Mat4x3_ None %292
         %m20 = OpFunctionParameter %Mat4x4_
-        %280 = OpLabel
-        %m21 = OpVariable %_ptr_Function_Mat4x4_ Function %123
-         %o4 = OpVariable %_ptr_Function_Mat4x3_ Function %63
+        %295 = OpLabel
+        %m21 = OpVariable %_ptr_Function_Mat4x4_ Function %138
+         %o4 = OpVariable %_ptr_Function_Mat4x3_ Function %78
                OpStore %m21 %m20
-        %283 = OpLoad %Mat4x4_ %m21
-        %284 = OpAccessChain %_ptr_Function_v4float %o4 %uint_0
-        %285 = OpCompositeExtract %v4float %283 0
-               OpStore %284 %285
-        %286 = OpLoad %Mat4x4_ %m21
-        %287 = OpAccessChain %_ptr_Function_v4float %o4 %uint_1
-        %288 = OpCompositeExtract %v4float %286 1
-               OpStore %287 %288
-        %289 = OpLoad %Mat4x4_ %m21
-        %290 = OpAccessChain %_ptr_Function_v4float %o4 %uint_2
-        %291 = OpCompositeExtract %v4float %289 2
-               OpStore %290 %291
-        %292 = OpLoad %Mat4x3_ %o4
-               OpReturnValue %292
+        %298 = OpLoad %Mat4x4_ %m21
+        %299 = OpAccessChain %_ptr_Function_v4float %o4 %uint_0
+        %300 = OpCompositeExtract %v4float %298 0
+               OpStore %299 %300
+        %301 = OpLoad %Mat4x4_ %m21
+        %302 = OpAccessChain %_ptr_Function_v4float %o4 %uint_1
+        %303 = OpCompositeExtract %v4float %301 1
+               OpStore %302 %303
+        %304 = OpLoad %Mat4x4_ %m21
+        %305 = OpAccessChain %_ptr_Function_v4float %o4 %uint_2
+        %306 = OpCompositeExtract %v4float %304 2
+               OpStore %305 %306
+        %307 = OpLoad %Mat4x3_ %o4
+               OpReturnValue %307
                OpFunctionEnd
-      %main1 = OpFunction %void None %293
-        %296 = OpLabel
-%tint_return_flag = OpVariable %_ptr_Function_bool Function %300
-   %t_PosMtx = OpVariable %_ptr_Function_Mat4x3_ Function %63
+      %main1 = OpFunction %void None %308
+        %311 = OpLabel
+%tint_return_flag = OpVariable %_ptr_Function_bool Function %314
+   %t_PosMtx = OpVariable %_ptr_Function_Mat4x3_ Function %78
 %t_TexSpaceCoord = OpVariable %_ptr_Function_v2float Function %19
-        %304 = OpLoad %float %a_PosMtxIdx1
-        %305 = OpConvertFToS %int %304
-        %308 = OpAccessChain %_ptr_Uniform_Mat4x3_ %global2 %uint_0 %uint_0 %305
-        %309 = OpLoad %Mat4x3_ %308
-               OpStore %t_PosMtx %309
-        %310 = OpLoad %Mat4x3_ %t_PosMtx
-        %311 = OpFunctionCall %Mat4x4_ %x_Mat4x4_1 %310
-        %312 = OpLoad %v3float %a_Position1
-        %313 = OpLoad %Mat4x3_ %t_PosMtx
-        %314 = OpFunctionCall %Mat4x4_ %x_Mat4x4_1 %313
-        %315 = OpLoad %v3float %a_Position1
-        %317 = OpCompositeExtract %float %315 0
-        %318 = OpCompositeExtract %float %315 1
-        %319 = OpCompositeExtract %float %315 2
-        %320 = OpCompositeConstruct %v4float %317 %318 %319 %float_1
-        %316 = OpFunctionCall %v4float %Mul %314 %320
-        %322 = OpAccessChain %_ptr_Uniform_Mat4x4_ %global %uint_0 %uint_0
-        %323 = OpLoad %Mat4x4_ %322
-        %324 = OpLoad %Mat4x3_ %t_PosMtx
-        %325 = OpFunctionCall %Mat4x4_ %x_Mat4x4_1 %324
-        %326 = OpLoad %v3float %a_Position1
-        %327 = OpLoad %Mat4x3_ %t_PosMtx
-        %328 = OpFunctionCall %Mat4x4_ %x_Mat4x4_1 %327
-        %329 = OpLoad %v3float %a_Position1
-        %331 = OpCompositeExtract %float %329 0
-        %332 = OpCompositeExtract %float %329 1
-        %333 = OpCompositeExtract %float %329 2
-        %334 = OpCompositeConstruct %v4float %331 %332 %333 %float_1
-        %330 = OpFunctionCall %v4float %Mul %328 %334
-        %335 = OpFunctionCall %v4float %Mul %323 %330
-               OpStore %gl_Position %335
-        %336 = OpLoad %v4float %a_Color1
-               OpStore %v_Color %336
-        %338 = OpAccessChain %_ptr_Uniform_v4float %global1 %uint_0 %uint_1
-        %339 = OpLoad %v4float %338
-        %340 = OpCompositeExtract %float %339 0
-        %342 = OpFOrdEqual %bool %340 %float_2
-               OpSelectionMerge %343 None
-               OpBranchConditional %342 %344 %345
-        %344 = OpLabel
-        %346 = OpLoad %v3float %a_Normal1
-        %349 = OpAccessChain %_ptr_Uniform_Mat4x2_ %global1 %uint_0 %uint_0 %347
-        %350 = OpLoad %Mat4x2_ %349
-        %351 = OpLoad %v3float %a_Normal1
-        %353 = OpCompositeExtract %float %351 0
-        %354 = OpCompositeExtract %float %351 1
-        %355 = OpCompositeExtract %float %351 2
-        %356 = OpCompositeConstruct %v4float %353 %354 %355 %float_1
-        %352 = OpFunctionCall %v2float %Mul2 %350 %356
-        %357 = OpVectorShuffle %v2float %352 %352 0 1
-               OpStore %v_TexCoord %357
+        %318 = OpLoad %float %a_PosMtxIdx1
+        %319 = OpFunctionCall %int %tint_ftoi %318
+        %321 = OpAccessChain %_ptr_Uniform_Mat4x3_ %global2 %uint_0 %uint_0 %319
+        %322 = OpLoad %Mat4x3_ %321
+               OpStore %t_PosMtx %322
+        %323 = OpLoad %Mat4x3_ %t_PosMtx
+        %324 = OpFunctionCall %Mat4x4_ %x_Mat4x4_1 %323
+        %325 = OpLoad %v3float %a_Position1
+        %326 = OpLoad %Mat4x3_ %t_PosMtx
+        %327 = OpFunctionCall %Mat4x4_ %x_Mat4x4_1 %326
+        %328 = OpLoad %v3float %a_Position1
+        %330 = OpCompositeExtract %float %328 0
+        %331 = OpCompositeExtract %float %328 1
+        %332 = OpCompositeExtract %float %328 2
+        %333 = OpCompositeConstruct %v4float %330 %331 %332 %float_1
+        %329 = OpFunctionCall %v4float %Mul %327 %333
+        %335 = OpAccessChain %_ptr_Uniform_Mat4x4_ %global %uint_0 %uint_0
+        %336 = OpLoad %Mat4x4_ %335
+        %337 = OpLoad %Mat4x3_ %t_PosMtx
+        %338 = OpFunctionCall %Mat4x4_ %x_Mat4x4_1 %337
+        %339 = OpLoad %v3float %a_Position1
+        %340 = OpLoad %Mat4x3_ %t_PosMtx
+        %341 = OpFunctionCall %Mat4x4_ %x_Mat4x4_1 %340
+        %342 = OpLoad %v3float %a_Position1
+        %344 = OpCompositeExtract %float %342 0
+        %345 = OpCompositeExtract %float %342 1
+        %346 = OpCompositeExtract %float %342 2
+        %347 = OpCompositeConstruct %v4float %344 %345 %346 %float_1
+        %343 = OpFunctionCall %v4float %Mul %341 %347
+        %348 = OpFunctionCall %v4float %Mul %336 %343
+               OpStore %gl_Position %348
+        %349 = OpLoad %v4float %a_Color1
+               OpStore %v_Color %349
+        %351 = OpAccessChain %_ptr_Uniform_v4float %global1 %uint_0 %uint_1
+        %352 = OpLoad %v4float %351
+        %353 = OpCompositeExtract %float %352 0
+        %355 = OpFOrdEqual %bool %353 %float_2
+               OpSelectionMerge %356 None
+               OpBranchConditional %355 %357 %358
+        %357 = OpLabel
+        %359 = OpLoad %v3float %a_Normal1
+        %362 = OpAccessChain %_ptr_Uniform_Mat4x2_ %global1 %uint_0 %uint_0 %360
+        %363 = OpLoad %Mat4x2_ %362
+        %364 = OpLoad %v3float %a_Normal1
+        %366 = OpCompositeExtract %float %364 0
+        %367 = OpCompositeExtract %float %364 1
+        %368 = OpCompositeExtract %float %364 2
+        %369 = OpCompositeConstruct %v4float %366 %367 %368 %float_1
+        %365 = OpFunctionCall %v2float %Mul2 %363 %369
+        %370 = OpVectorShuffle %v2float %365 %365 0 1
+               OpStore %v_TexCoord %370
                OpStore %tint_return_flag %true
-               OpBranch %343
-        %345 = OpLabel
-        %359 = OpLoad %v2float %a_UV1
-        %360 = OpAccessChain %_ptr_Uniform_Mat4x2_ %global1 %uint_0 %uint_0 %347
-        %361 = OpLoad %Mat4x2_ %360
-        %362 = OpLoad %v2float %a_UV1
-        %364 = OpCompositeExtract %float %362 0
-        %365 = OpCompositeExtract %float %362 1
-        %366 = OpCompositeConstruct %v4float %364 %365 %float_1 %float_1
-        %363 = OpFunctionCall %v2float %Mul2 %361 %366
-        %367 = OpVectorShuffle %v2float %363 %363 0 1
-               OpStore %v_TexCoord %367
+               OpBranch %356
+        %358 = OpLabel
+        %372 = OpLoad %v2float %a_UV1
+        %373 = OpAccessChain %_ptr_Uniform_Mat4x2_ %global1 %uint_0 %uint_0 %360
+        %374 = OpLoad %Mat4x2_ %373
+        %375 = OpLoad %v2float %a_UV1
+        %377 = OpCompositeExtract %float %375 0
+        %378 = OpCompositeExtract %float %375 1
+        %379 = OpCompositeConstruct %v4float %377 %378 %float_1 %float_1
+        %376 = OpFunctionCall %v2float %Mul2 %374 %379
+        %380 = OpVectorShuffle %v2float %376 %376 0 1
+               OpStore %v_TexCoord %380
                OpStore %tint_return_flag %true
-               OpBranch %343
-        %343 = OpLabel
+               OpBranch %356
+        %356 = OpLabel
                OpReturn
                OpFunctionEnd
- %main_inner = OpFunction %VertexOutput None %368
+ %main_inner = OpFunction %VertexOutput None %381
  %a_Position = OpFunctionParameter %v3float
        %a_UV = OpFunctionParameter %v2float
     %a_Color = OpFunctionParameter %v4float
    %a_Normal = OpFunctionParameter %v3float
 %a_PosMtxIdx = OpFunctionParameter %float
-        %376 = OpLabel
+        %389 = OpLabel
                OpStore %a_Position1 %a_Position
                OpStore %a_UV1 %a_UV
                OpStore %a_Color1 %a_Color
                OpStore %a_Normal1 %a_Normal
                OpStore %a_PosMtxIdx1 %a_PosMtxIdx
-        %377 = OpFunctionCall %void %main1
-        %378 = OpLoad %v4float %v_Color
-        %379 = OpLoad %v2float %v_TexCoord
-        %380 = OpLoad %v4float %gl_Position
-        %381 = OpCompositeConstruct %VertexOutput %378 %379 %380
-               OpReturnValue %381
+        %390 = OpFunctionCall %void %main1
+        %391 = OpLoad %v4float %v_Color
+        %392 = OpLoad %v2float %v_TexCoord
+        %393 = OpLoad %v4float %gl_Position
+        %394 = OpCompositeConstruct %VertexOutput %391 %392 %393
+               OpReturnValue %394
                OpFunctionEnd
-       %main = OpFunction %void None %293
-        %383 = OpLabel
-        %385 = OpLoad %v3float %a_Position_1
-        %386 = OpLoad %v2float %a_UV_1
-        %387 = OpLoad %v4float %a_Color_1
-        %388 = OpLoad %v3float %a_Normal_1
-        %389 = OpLoad %float %a_PosMtxIdx_1
-        %384 = OpFunctionCall %VertexOutput %main_inner %385 %386 %387 %388 %389
-        %390 = OpCompositeExtract %v4float %384 0
-               OpStore %v_Color_1 %390
-        %391 = OpCompositeExtract %v2float %384 1
-               OpStore %v_TexCoord_1 %391
-        %392 = OpCompositeExtract %v4float %384 2
-               OpStore %member_1 %392
+       %main = OpFunction %void None %308
+        %396 = OpLabel
+        %398 = OpLoad %v3float %a_Position_1
+        %399 = OpLoad %v2float %a_UV_1
+        %400 = OpLoad %v4float %a_Color_1
+        %401 = OpLoad %v3float %a_Normal_1
+        %402 = OpLoad %float %a_PosMtxIdx_1
+        %397 = OpFunctionCall %VertexOutput %main_inner %398 %399 %400 %401 %402
+        %403 = OpCompositeExtract %v4float %397 0
+               OpStore %v_Color_1 %403
+        %404 = OpCompositeExtract %v2float %397 1
+               OpStore %v_TexCoord_1 %404
+        %405 = OpCompositeExtract %v4float %397 2
+               OpStore %member_1 %405
                OpStore %vertex_point_size %float_1
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/diagnostic_filtering/case_body_attribute.wgsl.expected.dxc.hlsl b/test/tint/diagnostic_filtering/case_body_attribute.wgsl.expected.dxc.hlsl
index 00ddd47..5c947c9 100644
--- a/test/tint/diagnostic_filtering/case_body_attribute.wgsl.expected.dxc.hlsl
+++ b/test/tint/diagnostic_filtering/case_body_attribute.wgsl.expected.dxc.hlsl
@@ -10,6 +10,10 @@
   switch (i32(x)) {
               ^
 
+int tint_ftoi(float v) {
+  return ((v < 2147483520.0f) ? ((v < -2147483648.0f) ? -2147483648 : int(v)) : 2147483647);
+}
+
 Texture2D<float4> t : register(t1, space0);
 SamplerState s : register(s2, space0);
 
@@ -18,7 +22,7 @@
 };
 
 void main_inner(float x) {
-  switch(int(x)) {
+  switch(tint_ftoi(x)) {
     case 0: {
       break;
     }
diff --git a/test/tint/diagnostic_filtering/case_body_attribute.wgsl.expected.fxc.hlsl b/test/tint/diagnostic_filtering/case_body_attribute.wgsl.expected.fxc.hlsl
index 00ddd47..5c947c9 100644
--- a/test/tint/diagnostic_filtering/case_body_attribute.wgsl.expected.fxc.hlsl
+++ b/test/tint/diagnostic_filtering/case_body_attribute.wgsl.expected.fxc.hlsl
@@ -10,6 +10,10 @@
   switch (i32(x)) {
               ^
 
+int tint_ftoi(float v) {
+  return ((v < 2147483520.0f) ? ((v < -2147483648.0f) ? -2147483648 : int(v)) : 2147483647);
+}
+
 Texture2D<float4> t : register(t1, space0);
 SamplerState s : register(s2, space0);
 
@@ -18,7 +22,7 @@
 };
 
 void main_inner(float x) {
-  switch(int(x)) {
+  switch(tint_ftoi(x)) {
     case 0: {
       break;
     }
diff --git a/test/tint/diagnostic_filtering/case_body_attribute.wgsl.expected.glsl b/test/tint/diagnostic_filtering/case_body_attribute.wgsl.expected.glsl
index 3487c0f..3d60580 100644
--- a/test/tint/diagnostic_filtering/case_body_attribute.wgsl.expected.glsl
+++ b/test/tint/diagnostic_filtering/case_body_attribute.wgsl.expected.glsl
@@ -14,8 +14,12 @@
 precision highp float;
 
 layout(location = 0) in float x_1;
+int tint_ftoi(float v) {
+  return ((v < 2147483520.0f) ? ((v < -2147483648.0f) ? (-2147483647 - 1) : int(v)) : 2147483647);
+}
+
 void tint_symbol(float x) {
-  switch(int(x)) {
+  switch(tint_ftoi(x)) {
     case 0: {
       break;
     }
diff --git a/test/tint/diagnostic_filtering/case_body_attribute.wgsl.expected.msl b/test/tint/diagnostic_filtering/case_body_attribute.wgsl.expected.msl
index e4efe7b..d3df4a5 100644
--- a/test/tint/diagnostic_filtering/case_body_attribute.wgsl.expected.msl
+++ b/test/tint/diagnostic_filtering/case_body_attribute.wgsl.expected.msl
@@ -13,12 +13,16 @@
 #include <metal_stdlib>
 
 using namespace metal;
+int tint_ftoi(float v) {
+  return select(2147483647, select(int(v), (-2147483647 - 1), (v < -2147483648.0f)), (v < 2147483520.0f));
+}
+
 struct tint_symbol_2 {
   float x [[user(locn0)]];
 };
 
 void tint_symbol_inner(float x) {
-  switch(int(x)) {
+  switch(tint_ftoi(x)) {
     case 0: {
       break;
     }
diff --git a/test/tint/diagnostic_filtering/case_body_attribute.wgsl.expected.spvasm b/test/tint/diagnostic_filtering/case_body_attribute.wgsl.expected.spvasm
index c6336b9..2427774 100644
--- a/test/tint/diagnostic_filtering/case_body_attribute.wgsl.expected.spvasm
+++ b/test/tint/diagnostic_filtering/case_body_attribute.wgsl.expected.spvasm
@@ -13,7 +13,7 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 25
+; Bound: 39
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
@@ -22,6 +22,8 @@
                OpName %x_1 "x_1"
                OpName %t "t"
                OpName %s "s"
+               OpName %tint_ftoi "tint_ftoi"
+               OpName %v "v"
                OpName %main_inner "main_inner"
                OpName %x "x"
                OpName %main "main"
@@ -39,26 +41,42 @@
           %9 = OpTypeSampler
 %_ptr_UniformConstant_9 = OpTypePointer UniformConstant %9
           %s = OpVariable %_ptr_UniformConstant_9 UniformConstant
-       %void = OpTypeVoid
-         %10 = OpTypeFunction %void %float
         %int = OpTypeInt 32 1
-         %20 = OpTypeFunction %void
- %main_inner = OpFunction %void None %10
-          %x = OpFunctionParameter %float
+         %10 = OpTypeFunction %int %float
+%float_2_14748352e_09 = OpConstant %float 2.14748352e+09
+       %bool = OpTypeBool
+%float_n2_14748365e_09 = OpConstant %float -2.14748365e+09
+%int_n2147483648 = OpConstant %int -2147483648
+%int_2147483647 = OpConstant %int 2147483647
+       %void = OpTypeVoid
+         %25 = OpTypeFunction %void %float
+         %34 = OpTypeFunction %void
+  %tint_ftoi = OpFunction %int None %10
+          %v = OpFunctionParameter %float
          %14 = OpLabel
-         %16 = OpConvertFToS %int %x
-               OpSelectionMerge %15 None
-               OpSwitch %16 %18 0 %19
-         %19 = OpLabel
-               OpBranch %15
-         %18 = OpLabel
-               OpBranch %15
-         %15 = OpLabel
+         %17 = OpFOrdLessThan %bool %v %float_2_14748352e_09
+         %21 = OpFOrdLessThan %bool %v %float_n2_14748365e_09
+         %23 = OpConvertFToS %int %v
+         %19 = OpSelect %int %21 %int_n2147483648 %23
+         %15 = OpSelect %int %17 %19 %int_2147483647
+               OpReturnValue %15
+               OpFunctionEnd
+ %main_inner = OpFunction %void None %25
+          %x = OpFunctionParameter %float
+         %29 = OpLabel
+         %31 = OpFunctionCall %int %tint_ftoi %x
+               OpSelectionMerge %30 None
+               OpSwitch %31 %32 0 %33
+         %33 = OpLabel
+               OpBranch %30
+         %32 = OpLabel
+               OpBranch %30
+         %30 = OpLabel
                OpReturn
                OpFunctionEnd
-       %main = OpFunction %void None %20
-         %22 = OpLabel
-         %24 = OpLoad %float %x_1
-         %23 = OpFunctionCall %void %main_inner %24
+       %main = OpFunction %void None %34
+         %36 = OpLabel
+         %38 = OpLoad %float %x_1
+         %37 = OpFunctionCall %void %main_inner %38
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/diagnostic_filtering/default_case_body_attribute.wgsl.expected.dxc.hlsl b/test/tint/diagnostic_filtering/default_case_body_attribute.wgsl.expected.dxc.hlsl
index 788662a..e4381ae 100644
--- a/test/tint/diagnostic_filtering/default_case_body_attribute.wgsl.expected.dxc.hlsl
+++ b/test/tint/diagnostic_filtering/default_case_body_attribute.wgsl.expected.dxc.hlsl
@@ -10,6 +10,10 @@
   switch (i32(x)) {
               ^
 
+int tint_ftoi(float v) {
+  return ((v < 2147483520.0f) ? ((v < -2147483648.0f) ? -2147483648 : int(v)) : 2147483647);
+}
+
 Texture2D<float4> t : register(t1, space0);
 SamplerState s : register(s2, space0);
 
@@ -18,6 +22,7 @@
 };
 
 void main_inner(float x) {
+  tint_ftoi(x);
   do {
   } while (false);
 }
diff --git a/test/tint/diagnostic_filtering/default_case_body_attribute.wgsl.expected.fxc.hlsl b/test/tint/diagnostic_filtering/default_case_body_attribute.wgsl.expected.fxc.hlsl
index 788662a..e4381ae 100644
--- a/test/tint/diagnostic_filtering/default_case_body_attribute.wgsl.expected.fxc.hlsl
+++ b/test/tint/diagnostic_filtering/default_case_body_attribute.wgsl.expected.fxc.hlsl
@@ -10,6 +10,10 @@
   switch (i32(x)) {
               ^
 
+int tint_ftoi(float v) {
+  return ((v < 2147483520.0f) ? ((v < -2147483648.0f) ? -2147483648 : int(v)) : 2147483647);
+}
+
 Texture2D<float4> t : register(t1, space0);
 SamplerState s : register(s2, space0);
 
@@ -18,6 +22,7 @@
 };
 
 void main_inner(float x) {
+  tint_ftoi(x);
   do {
   } while (false);
 }
diff --git a/test/tint/diagnostic_filtering/default_case_body_attribute.wgsl.expected.glsl b/test/tint/diagnostic_filtering/default_case_body_attribute.wgsl.expected.glsl
index 46c70b0..7251735 100644
--- a/test/tint/diagnostic_filtering/default_case_body_attribute.wgsl.expected.glsl
+++ b/test/tint/diagnostic_filtering/default_case_body_attribute.wgsl.expected.glsl
@@ -14,8 +14,12 @@
 precision highp float;
 
 layout(location = 0) in float x_1;
+int tint_ftoi(float v) {
+  return ((v < 2147483520.0f) ? ((v < -2147483648.0f) ? (-2147483647 - 1) : int(v)) : 2147483647);
+}
+
 void tint_symbol(float x) {
-  switch(int(x)) {
+  switch(tint_ftoi(x)) {
     default: {
       break;
     }
diff --git a/test/tint/diagnostic_filtering/default_case_body_attribute.wgsl.expected.msl b/test/tint/diagnostic_filtering/default_case_body_attribute.wgsl.expected.msl
index 0df2be1..a7fa4e1 100644
--- a/test/tint/diagnostic_filtering/default_case_body_attribute.wgsl.expected.msl
+++ b/test/tint/diagnostic_filtering/default_case_body_attribute.wgsl.expected.msl
@@ -13,12 +13,16 @@
 #include <metal_stdlib>
 
 using namespace metal;
+int tint_ftoi(float v) {
+  return select(2147483647, select(int(v), (-2147483647 - 1), (v < -2147483648.0f)), (v < 2147483520.0f));
+}
+
 struct tint_symbol_2 {
   float x [[user(locn0)]];
 };
 
 void tint_symbol_inner(float x) {
-  switch(int(x)) {
+  switch(tint_ftoi(x)) {
     default: {
       break;
     }
diff --git a/test/tint/diagnostic_filtering/default_case_body_attribute.wgsl.expected.spvasm b/test/tint/diagnostic_filtering/default_case_body_attribute.wgsl.expected.spvasm
index ca26e9a..d777078 100644
--- a/test/tint/diagnostic_filtering/default_case_body_attribute.wgsl.expected.spvasm
+++ b/test/tint/diagnostic_filtering/default_case_body_attribute.wgsl.expected.spvasm
@@ -13,7 +13,7 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 24
+; Bound: 38
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
@@ -22,6 +22,8 @@
                OpName %x_1 "x_1"
                OpName %t "t"
                OpName %s "s"
+               OpName %tint_ftoi "tint_ftoi"
+               OpName %v "v"
                OpName %main_inner "main_inner"
                OpName %x "x"
                OpName %main "main"
@@ -39,24 +41,40 @@
           %9 = OpTypeSampler
 %_ptr_UniformConstant_9 = OpTypePointer UniformConstant %9
           %s = OpVariable %_ptr_UniformConstant_9 UniformConstant
-       %void = OpTypeVoid
-         %10 = OpTypeFunction %void %float
         %int = OpTypeInt 32 1
-         %19 = OpTypeFunction %void
- %main_inner = OpFunction %void None %10
-          %x = OpFunctionParameter %float
+         %10 = OpTypeFunction %int %float
+%float_2_14748352e_09 = OpConstant %float 2.14748352e+09
+       %bool = OpTypeBool
+%float_n2_14748365e_09 = OpConstant %float -2.14748365e+09
+%int_n2147483648 = OpConstant %int -2147483648
+%int_2147483647 = OpConstant %int 2147483647
+       %void = OpTypeVoid
+         %25 = OpTypeFunction %void %float
+         %33 = OpTypeFunction %void
+  %tint_ftoi = OpFunction %int None %10
+          %v = OpFunctionParameter %float
          %14 = OpLabel
-         %16 = OpConvertFToS %int %x
-               OpSelectionMerge %15 None
-               OpSwitch %16 %18
-         %18 = OpLabel
-               OpBranch %15
-         %15 = OpLabel
+         %17 = OpFOrdLessThan %bool %v %float_2_14748352e_09
+         %21 = OpFOrdLessThan %bool %v %float_n2_14748365e_09
+         %23 = OpConvertFToS %int %v
+         %19 = OpSelect %int %21 %int_n2147483648 %23
+         %15 = OpSelect %int %17 %19 %int_2147483647
+               OpReturnValue %15
+               OpFunctionEnd
+ %main_inner = OpFunction %void None %25
+          %x = OpFunctionParameter %float
+         %29 = OpLabel
+         %31 = OpFunctionCall %int %tint_ftoi %x
+               OpSelectionMerge %30 None
+               OpSwitch %31 %32
+         %32 = OpLabel
+               OpBranch %30
+         %30 = OpLabel
                OpReturn
                OpFunctionEnd
-       %main = OpFunction %void None %19
-         %21 = OpLabel
-         %23 = OpLoad %float %x_1
-         %22 = OpFunctionCall %void %main_inner %23
+       %main = OpFunction %void None %33
+         %35 = OpLabel
+         %37 = OpLoad %float %x_1
+         %36 = OpFunctionCall %void %main_inner %37
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/expressions/type_conv/scalar/function/f32-i32.wgsl.expected.dxc.hlsl b/test/tint/expressions/type_conv/scalar/function/f32-i32.wgsl.expected.dxc.hlsl
index 4fc1559..ca9dcb5 100644
--- a/test/tint/expressions/type_conv/scalar/function/f32-i32.wgsl.expected.dxc.hlsl
+++ b/test/tint/expressions/type_conv/scalar/function/f32-i32.wgsl.expected.dxc.hlsl
@@ -3,6 +3,10 @@
   return;
 }
 
+int tint_ftoi(float v) {
+  return ((v < 2147483520.0f) ? ((v < -2147483648.0f) ? -2147483648 : int(v)) : 2147483647);
+}
+
 static float t = 0.0f;
 
 float m() {
@@ -12,5 +16,5 @@
 
 void f() {
   const float tint_symbol = m();
-  int v = int(tint_symbol);
+  int v = tint_ftoi(tint_symbol);
 }
diff --git a/test/tint/expressions/type_conv/scalar/function/f32-i32.wgsl.expected.fxc.hlsl b/test/tint/expressions/type_conv/scalar/function/f32-i32.wgsl.expected.fxc.hlsl
index 4fc1559..ca9dcb5 100644
--- a/test/tint/expressions/type_conv/scalar/function/f32-i32.wgsl.expected.fxc.hlsl
+++ b/test/tint/expressions/type_conv/scalar/function/f32-i32.wgsl.expected.fxc.hlsl
@@ -3,6 +3,10 @@
   return;
 }
 
+int tint_ftoi(float v) {
+  return ((v < 2147483520.0f) ? ((v < -2147483648.0f) ? -2147483648 : int(v)) : 2147483647);
+}
+
 static float t = 0.0f;
 
 float m() {
@@ -12,5 +16,5 @@
 
 void f() {
   const float tint_symbol = m();
-  int v = int(tint_symbol);
+  int v = tint_ftoi(tint_symbol);
 }
diff --git a/test/tint/expressions/type_conv/scalar/function/f32-i32.wgsl.expected.glsl b/test/tint/expressions/type_conv/scalar/function/f32-i32.wgsl.expected.glsl
index ce31d14..77e0afd 100644
--- a/test/tint/expressions/type_conv/scalar/function/f32-i32.wgsl.expected.glsl
+++ b/test/tint/expressions/type_conv/scalar/function/f32-i32.wgsl.expected.glsl
@@ -4,6 +4,10 @@
 void unused_entry_point() {
   return;
 }
+int tint_ftoi(float v) {
+  return ((v < 2147483520.0f) ? ((v < -2147483648.0f) ? (-2147483647 - 1) : int(v)) : 2147483647);
+}
+
 float t = 0.0f;
 float m() {
   t = 1.0f;
@@ -12,6 +16,6 @@
 
 void f() {
   float tint_symbol = m();
-  int v = int(tint_symbol);
+  int v = tint_ftoi(tint_symbol);
 }
 
diff --git a/test/tint/expressions/type_conv/scalar/function/f32-i32.wgsl.expected.msl b/test/tint/expressions/type_conv/scalar/function/f32-i32.wgsl.expected.msl
index 2b22db5..fe4bcc0 100644
--- a/test/tint/expressions/type_conv/scalar/function/f32-i32.wgsl.expected.msl
+++ b/test/tint/expressions/type_conv/scalar/function/f32-i32.wgsl.expected.msl
@@ -1,6 +1,10 @@
 #include <metal_stdlib>
 
 using namespace metal;
+int tint_ftoi(float v) {
+  return select(2147483647, select(int(v), (-2147483647 - 1), (v < -2147483648.0f)), (v < 2147483520.0f));
+}
+
 float m() {
   thread float tint_symbol_1 = 0.0f;
   tint_symbol_1 = 1.0f;
@@ -9,6 +13,6 @@
 
 void f() {
   float const tint_symbol = m();
-  int v = int(tint_symbol);
+  int v = tint_ftoi(tint_symbol);
 }
 
diff --git a/test/tint/expressions/type_conv/scalar/function/f32-i32.wgsl.expected.spvasm b/test/tint/expressions/type_conv/scalar/function/f32-i32.wgsl.expected.spvasm
index 60009a1..b86fb8e 100644
--- a/test/tint/expressions/type_conv/scalar/function/f32-i32.wgsl.expected.spvasm
+++ b/test/tint/expressions/type_conv/scalar/function/f32-i32.wgsl.expected.spvasm
@@ -1,7 +1,7 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 23
+; Bound: 37
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
@@ -9,35 +9,53 @@
                OpExecutionMode %unused_entry_point LocalSize 1 1 1
                OpName %t "t"
                OpName %unused_entry_point "unused_entry_point"
+               OpName %tint_ftoi "tint_ftoi"
+               OpName %v "v"
                OpName %m "m"
                OpName %f "f"
-               OpName %v "v"
+               OpName %v_0 "v"
       %float = OpTypeFloat 32
 %_ptr_Private_float = OpTypePointer Private %float
           %4 = OpConstantNull %float
           %t = OpVariable %_ptr_Private_float Private %4
        %void = OpTypeVoid
           %5 = OpTypeFunction %void
-          %9 = OpTypeFunction %float
-    %float_1 = OpConstant %float 1
         %int = OpTypeInt 32 1
+          %9 = OpTypeFunction %int %float
+%float_2_14748352e_09 = OpConstant %float 2.14748352e+09
+       %bool = OpTypeBool
+%float_n2_14748365e_09 = OpConstant %float -2.14748365e+09
+%int_n2147483648 = OpConstant %int -2147483648
+%int_2147483647 = OpConstant %int 2147483647
+         %24 = OpTypeFunction %float
+    %float_1 = OpConstant %float 1
 %_ptr_Function_int = OpTypePointer Function %int
-         %22 = OpConstantNull %int
+         %36 = OpConstantNull %int
 %unused_entry_point = OpFunction %void None %5
           %8 = OpLabel
                OpReturn
                OpFunctionEnd
-          %m = OpFunction %float None %9
-         %11 = OpLabel
-               OpStore %t %float_1
-         %14 = OpLoad %float %t
+  %tint_ftoi = OpFunction %int None %9
+          %v = OpFunctionParameter %float
+         %13 = OpLabel
+         %16 = OpFOrdLessThan %bool %v %float_2_14748352e_09
+         %20 = OpFOrdLessThan %bool %v %float_n2_14748365e_09
+         %22 = OpConvertFToS %int %v
+         %18 = OpSelect %int %20 %int_n2147483648 %22
+         %14 = OpSelect %int %16 %18 %int_2147483647
                OpReturnValue %14
                OpFunctionEnd
+          %m = OpFunction %float None %24
+         %26 = OpLabel
+               OpStore %t %float_1
+         %29 = OpLoad %float %t
+               OpReturnValue %29
+               OpFunctionEnd
           %f = OpFunction %void None %5
-         %16 = OpLabel
-          %v = OpVariable %_ptr_Function_int Function %22
-         %17 = OpFunctionCall %float %m
-         %18 = OpConvertFToS %int %17
-               OpStore %v %18
+         %31 = OpLabel
+        %v_0 = OpVariable %_ptr_Function_int Function %36
+         %32 = OpFunctionCall %float %m
+         %33 = OpFunctionCall %int %tint_ftoi %32
+               OpStore %v_0 %33
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/expressions/type_conv/scalar/function/f32-u32.wgsl.expected.dxc.hlsl b/test/tint/expressions/type_conv/scalar/function/f32-u32.wgsl.expected.dxc.hlsl
index 7272ba5..aafd2a3 100644
--- a/test/tint/expressions/type_conv/scalar/function/f32-u32.wgsl.expected.dxc.hlsl
+++ b/test/tint/expressions/type_conv/scalar/function/f32-u32.wgsl.expected.dxc.hlsl
@@ -3,6 +3,10 @@
   return;
 }
 
+uint tint_ftou(float v) {
+  return ((v < 4294967040.0f) ? ((v < 0.0f) ? 0u : uint(v)) : 4294967295u);
+}
+
 static float t = 0.0f;
 
 float m() {
@@ -12,5 +16,5 @@
 
 void f() {
   const float tint_symbol = m();
-  uint v = uint(tint_symbol);
+  uint v = tint_ftou(tint_symbol);
 }
diff --git a/test/tint/expressions/type_conv/scalar/function/f32-u32.wgsl.expected.fxc.hlsl b/test/tint/expressions/type_conv/scalar/function/f32-u32.wgsl.expected.fxc.hlsl
index 7272ba5..aafd2a3 100644
--- a/test/tint/expressions/type_conv/scalar/function/f32-u32.wgsl.expected.fxc.hlsl
+++ b/test/tint/expressions/type_conv/scalar/function/f32-u32.wgsl.expected.fxc.hlsl
@@ -3,6 +3,10 @@
   return;
 }
 
+uint tint_ftou(float v) {
+  return ((v < 4294967040.0f) ? ((v < 0.0f) ? 0u : uint(v)) : 4294967295u);
+}
+
 static float t = 0.0f;
 
 float m() {
@@ -12,5 +16,5 @@
 
 void f() {
   const float tint_symbol = m();
-  uint v = uint(tint_symbol);
+  uint v = tint_ftou(tint_symbol);
 }
diff --git a/test/tint/expressions/type_conv/scalar/function/f32-u32.wgsl.expected.glsl b/test/tint/expressions/type_conv/scalar/function/f32-u32.wgsl.expected.glsl
index c91caf0..3acd592 100644
--- a/test/tint/expressions/type_conv/scalar/function/f32-u32.wgsl.expected.glsl
+++ b/test/tint/expressions/type_conv/scalar/function/f32-u32.wgsl.expected.glsl
@@ -4,6 +4,10 @@
 void unused_entry_point() {
   return;
 }
+uint tint_ftou(float v) {
+  return ((v < 4294967040.0f) ? ((v < 0.0f) ? 0u : uint(v)) : 4294967295u);
+}
+
 float t = 0.0f;
 float m() {
   t = 1.0f;
@@ -12,6 +16,6 @@
 
 void f() {
   float tint_symbol = m();
-  uint v = uint(tint_symbol);
+  uint v = tint_ftou(tint_symbol);
 }
 
diff --git a/test/tint/expressions/type_conv/scalar/function/f32-u32.wgsl.expected.msl b/test/tint/expressions/type_conv/scalar/function/f32-u32.wgsl.expected.msl
index d4324ee..a6a6b55 100644
--- a/test/tint/expressions/type_conv/scalar/function/f32-u32.wgsl.expected.msl
+++ b/test/tint/expressions/type_conv/scalar/function/f32-u32.wgsl.expected.msl
@@ -1,6 +1,10 @@
 #include <metal_stdlib>
 
 using namespace metal;
+uint tint_ftou(float v) {
+  return select(4294967295u, select(uint(v), 0u, (v < 0.0f)), (v < 4294967040.0f));
+}
+
 float m() {
   thread float tint_symbol_1 = 0.0f;
   tint_symbol_1 = 1.0f;
@@ -9,6 +13,6 @@
 
 void f() {
   float const tint_symbol = m();
-  uint v = uint(tint_symbol);
+  uint v = tint_ftou(tint_symbol);
 }
 
diff --git a/test/tint/expressions/type_conv/scalar/function/f32-u32.wgsl.expected.spvasm b/test/tint/expressions/type_conv/scalar/function/f32-u32.wgsl.expected.spvasm
index 1a72c479..fc167d0 100644
--- a/test/tint/expressions/type_conv/scalar/function/f32-u32.wgsl.expected.spvasm
+++ b/test/tint/expressions/type_conv/scalar/function/f32-u32.wgsl.expected.spvasm
@@ -1,7 +1,7 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 23
+; Bound: 35
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
@@ -9,35 +9,51 @@
                OpExecutionMode %unused_entry_point LocalSize 1 1 1
                OpName %t "t"
                OpName %unused_entry_point "unused_entry_point"
+               OpName %tint_ftou "tint_ftou"
+               OpName %v "v"
                OpName %m "m"
                OpName %f "f"
-               OpName %v "v"
+               OpName %v_0 "v"
       %float = OpTypeFloat 32
 %_ptr_Private_float = OpTypePointer Private %float
           %4 = OpConstantNull %float
           %t = OpVariable %_ptr_Private_float Private %4
        %void = OpTypeVoid
           %5 = OpTypeFunction %void
-          %9 = OpTypeFunction %float
-    %float_1 = OpConstant %float 1
        %uint = OpTypeInt 32 0
+          %9 = OpTypeFunction %uint %float
+%float_4_29496704e_09 = OpConstant %float 4.29496704e+09
+       %bool = OpTypeBool
+         %20 = OpConstantNull %uint
+%uint_4294967295 = OpConstant %uint 4294967295
+         %23 = OpTypeFunction %float
+    %float_1 = OpConstant %float 1
 %_ptr_Function_uint = OpTypePointer Function %uint
-         %22 = OpConstantNull %uint
 %unused_entry_point = OpFunction %void None %5
           %8 = OpLabel
                OpReturn
                OpFunctionEnd
-          %m = OpFunction %float None %9
-         %11 = OpLabel
-               OpStore %t %float_1
-         %14 = OpLoad %float %t
+  %tint_ftou = OpFunction %uint None %9
+          %v = OpFunctionParameter %float
+         %13 = OpLabel
+         %16 = OpFOrdLessThan %bool %v %float_4_29496704e_09
+         %19 = OpFOrdLessThan %bool %v %4
+         %21 = OpConvertFToU %uint %v
+         %18 = OpSelect %uint %19 %20 %21
+         %14 = OpSelect %uint %16 %18 %uint_4294967295
                OpReturnValue %14
                OpFunctionEnd
+          %m = OpFunction %float None %23
+         %25 = OpLabel
+               OpStore %t %float_1
+         %28 = OpLoad %float %t
+               OpReturnValue %28
+               OpFunctionEnd
           %f = OpFunction %void None %5
-         %16 = OpLabel
-          %v = OpVariable %_ptr_Function_uint Function %22
-         %17 = OpFunctionCall %float %m
-         %18 = OpConvertFToU %uint %17
-               OpStore %v %18
+         %30 = OpLabel
+        %v_0 = OpVariable %_ptr_Function_uint Function %20
+         %31 = OpFunctionCall %float %m
+         %32 = OpFunctionCall %uint %tint_ftou %31
+               OpStore %v_0 %32
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/expressions/type_conv/scalar/var/f32-i32.wgsl.expected.dxc.hlsl b/test/tint/expressions/type_conv/scalar/var/f32-i32.wgsl.expected.dxc.hlsl
index 3c58ea2..46bcf97 100644
--- a/test/tint/expressions/type_conv/scalar/var/f32-i32.wgsl.expected.dxc.hlsl
+++ b/test/tint/expressions/type_conv/scalar/var/f32-i32.wgsl.expected.dxc.hlsl
@@ -3,8 +3,12 @@
   return;
 }
 
+int tint_ftoi(float v) {
+  return ((v < 2147483520.0f) ? ((v < -2147483648.0f) ? -2147483648 : int(v)) : 2147483647);
+}
+
 static float u = 1.0f;
 
 void f() {
-  const int v = int(u);
+  const int v = tint_ftoi(u);
 }
diff --git a/test/tint/expressions/type_conv/scalar/var/f32-i32.wgsl.expected.fxc.hlsl b/test/tint/expressions/type_conv/scalar/var/f32-i32.wgsl.expected.fxc.hlsl
index 3c58ea2..46bcf97 100644
--- a/test/tint/expressions/type_conv/scalar/var/f32-i32.wgsl.expected.fxc.hlsl
+++ b/test/tint/expressions/type_conv/scalar/var/f32-i32.wgsl.expected.fxc.hlsl
@@ -3,8 +3,12 @@
   return;
 }
 
+int tint_ftoi(float v) {
+  return ((v < 2147483520.0f) ? ((v < -2147483648.0f) ? -2147483648 : int(v)) : 2147483647);
+}
+
 static float u = 1.0f;
 
 void f() {
-  const int v = int(u);
+  const int v = tint_ftoi(u);
 }
diff --git a/test/tint/expressions/type_conv/scalar/var/f32-i32.wgsl.expected.glsl b/test/tint/expressions/type_conv/scalar/var/f32-i32.wgsl.expected.glsl
index 2b93b04..5041e94 100644
--- a/test/tint/expressions/type_conv/scalar/var/f32-i32.wgsl.expected.glsl
+++ b/test/tint/expressions/type_conv/scalar/var/f32-i32.wgsl.expected.glsl
@@ -4,8 +4,12 @@
 void unused_entry_point() {
   return;
 }
+int tint_ftoi(float v) {
+  return ((v < 2147483520.0f) ? ((v < -2147483648.0f) ? (-2147483647 - 1) : int(v)) : 2147483647);
+}
+
 float u = 1.0f;
 void f() {
-  int v = int(u);
+  int v = tint_ftoi(u);
 }
 
diff --git a/test/tint/expressions/type_conv/scalar/var/f32-i32.wgsl.expected.msl b/test/tint/expressions/type_conv/scalar/var/f32-i32.wgsl.expected.msl
index 5e9ae09..8da1016 100644
--- a/test/tint/expressions/type_conv/scalar/var/f32-i32.wgsl.expected.msl
+++ b/test/tint/expressions/type_conv/scalar/var/f32-i32.wgsl.expected.msl
@@ -1,8 +1,12 @@
 #include <metal_stdlib>
 
 using namespace metal;
+int tint_ftoi(float v) {
+  return select(2147483647, select(int(v), (-2147483647 - 1), (v < -2147483648.0f)), (v < 2147483520.0f));
+}
+
 void f() {
   thread float tint_symbol = 1.0f;
-  int const v = int(tint_symbol);
+  int const v = tint_ftoi(tint_symbol);
 }
 
diff --git a/test/tint/expressions/type_conv/scalar/var/f32-i32.wgsl.expected.spvasm b/test/tint/expressions/type_conv/scalar/var/f32-i32.wgsl.expected.spvasm
index fa4ccee..3e5aeb6 100644
--- a/test/tint/expressions/type_conv/scalar/var/f32-i32.wgsl.expected.spvasm
+++ b/test/tint/expressions/type_conv/scalar/var/f32-i32.wgsl.expected.spvasm
@@ -1,7 +1,7 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 14
+; Bound: 28
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
@@ -9,6 +9,8 @@
                OpExecutionMode %unused_entry_point LocalSize 1 1 1
                OpName %u "u"
                OpName %unused_entry_point "unused_entry_point"
+               OpName %tint_ftoi "tint_ftoi"
+               OpName %v "v"
                OpName %f "f"
       %float = OpTypeFloat 32
     %float_1 = OpConstant %float 1
@@ -17,13 +19,29 @@
        %void = OpTypeVoid
           %5 = OpTypeFunction %void
         %int = OpTypeInt 32 1
+          %9 = OpTypeFunction %int %float
+%float_2_14748352e_09 = OpConstant %float 2.14748352e+09
+       %bool = OpTypeBool
+%float_n2_14748365e_09 = OpConstant %float -2.14748365e+09
+%int_n2147483648 = OpConstant %int -2147483648
+%int_2147483647 = OpConstant %int 2147483647
 %unused_entry_point = OpFunction %void None %5
           %8 = OpLabel
                OpReturn
                OpFunctionEnd
+  %tint_ftoi = OpFunction %int None %9
+          %v = OpFunctionParameter %float
+         %13 = OpLabel
+         %16 = OpFOrdLessThan %bool %v %float_2_14748352e_09
+         %20 = OpFOrdLessThan %bool %v %float_n2_14748365e_09
+         %22 = OpConvertFToS %int %v
+         %18 = OpSelect %int %20 %int_n2147483648 %22
+         %14 = OpSelect %int %16 %18 %int_2147483647
+               OpReturnValue %14
+               OpFunctionEnd
           %f = OpFunction %void None %5
-         %10 = OpLabel
-         %13 = OpLoad %float %u
-         %11 = OpConvertFToS %int %13
+         %25 = OpLabel
+         %27 = OpLoad %float %u
+         %26 = OpFunctionCall %int %tint_ftoi %27
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/expressions/type_conv/scalar/var/f32-u32.wgsl.expected.dxc.hlsl b/test/tint/expressions/type_conv/scalar/var/f32-u32.wgsl.expected.dxc.hlsl
index ae1a041..1ae604a 100644
--- a/test/tint/expressions/type_conv/scalar/var/f32-u32.wgsl.expected.dxc.hlsl
+++ b/test/tint/expressions/type_conv/scalar/var/f32-u32.wgsl.expected.dxc.hlsl
@@ -3,8 +3,12 @@
   return;
 }
 
+uint tint_ftou(float v) {
+  return ((v < 4294967040.0f) ? ((v < 0.0f) ? 0u : uint(v)) : 4294967295u);
+}
+
 static float u = 1.0f;
 
 void f() {
-  const uint v = uint(u);
+  const uint v = tint_ftou(u);
 }
diff --git a/test/tint/expressions/type_conv/scalar/var/f32-u32.wgsl.expected.fxc.hlsl b/test/tint/expressions/type_conv/scalar/var/f32-u32.wgsl.expected.fxc.hlsl
index ae1a041..1ae604a 100644
--- a/test/tint/expressions/type_conv/scalar/var/f32-u32.wgsl.expected.fxc.hlsl
+++ b/test/tint/expressions/type_conv/scalar/var/f32-u32.wgsl.expected.fxc.hlsl
@@ -3,8 +3,12 @@
   return;
 }
 
+uint tint_ftou(float v) {
+  return ((v < 4294967040.0f) ? ((v < 0.0f) ? 0u : uint(v)) : 4294967295u);
+}
+
 static float u = 1.0f;
 
 void f() {
-  const uint v = uint(u);
+  const uint v = tint_ftou(u);
 }
diff --git a/test/tint/expressions/type_conv/scalar/var/f32-u32.wgsl.expected.glsl b/test/tint/expressions/type_conv/scalar/var/f32-u32.wgsl.expected.glsl
index 4e8edd9..6905b67 100644
--- a/test/tint/expressions/type_conv/scalar/var/f32-u32.wgsl.expected.glsl
+++ b/test/tint/expressions/type_conv/scalar/var/f32-u32.wgsl.expected.glsl
@@ -4,8 +4,12 @@
 void unused_entry_point() {
   return;
 }
+uint tint_ftou(float v) {
+  return ((v < 4294967040.0f) ? ((v < 0.0f) ? 0u : uint(v)) : 4294967295u);
+}
+
 float u = 1.0f;
 void f() {
-  uint v = uint(u);
+  uint v = tint_ftou(u);
 }
 
diff --git a/test/tint/expressions/type_conv/scalar/var/f32-u32.wgsl.expected.msl b/test/tint/expressions/type_conv/scalar/var/f32-u32.wgsl.expected.msl
index c797446..1066099 100644
--- a/test/tint/expressions/type_conv/scalar/var/f32-u32.wgsl.expected.msl
+++ b/test/tint/expressions/type_conv/scalar/var/f32-u32.wgsl.expected.msl
@@ -1,8 +1,12 @@
 #include <metal_stdlib>
 
 using namespace metal;
+uint tint_ftou(float v) {
+  return select(4294967295u, select(uint(v), 0u, (v < 0.0f)), (v < 4294967040.0f));
+}
+
 void f() {
   thread float tint_symbol = 1.0f;
-  uint const v = uint(tint_symbol);
+  uint const v = tint_ftou(tint_symbol);
 }
 
diff --git a/test/tint/expressions/type_conv/scalar/var/f32-u32.wgsl.expected.spvasm b/test/tint/expressions/type_conv/scalar/var/f32-u32.wgsl.expected.spvasm
index f82b285..2898e5d 100644
--- a/test/tint/expressions/type_conv/scalar/var/f32-u32.wgsl.expected.spvasm
+++ b/test/tint/expressions/type_conv/scalar/var/f32-u32.wgsl.expected.spvasm
@@ -1,7 +1,7 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 14
+; Bound: 28
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
@@ -9,6 +9,8 @@
                OpExecutionMode %unused_entry_point LocalSize 1 1 1
                OpName %u "u"
                OpName %unused_entry_point "unused_entry_point"
+               OpName %tint_ftou "tint_ftou"
+               OpName %v "v"
                OpName %f "f"
       %float = OpTypeFloat 32
     %float_1 = OpConstant %float 1
@@ -17,13 +19,29 @@
        %void = OpTypeVoid
           %5 = OpTypeFunction %void
        %uint = OpTypeInt 32 0
+          %9 = OpTypeFunction %uint %float
+%float_4_29496704e_09 = OpConstant %float 4.29496704e+09
+       %bool = OpTypeBool
+         %19 = OpConstantNull %float
+         %21 = OpConstantNull %uint
+%uint_4294967295 = OpConstant %uint 4294967295
 %unused_entry_point = OpFunction %void None %5
           %8 = OpLabel
                OpReturn
                OpFunctionEnd
+  %tint_ftou = OpFunction %uint None %9
+          %v = OpFunctionParameter %float
+         %13 = OpLabel
+         %16 = OpFOrdLessThan %bool %v %float_4_29496704e_09
+         %20 = OpFOrdLessThan %bool %v %19
+         %22 = OpConvertFToU %uint %v
+         %18 = OpSelect %uint %20 %21 %22
+         %14 = OpSelect %uint %16 %18 %uint_4294967295
+               OpReturnValue %14
+               OpFunctionEnd
           %f = OpFunction %void None %5
-         %10 = OpLabel
-         %13 = OpLoad %float %u
-         %11 = OpConvertFToU %uint %13
+         %25 = OpLabel
+         %27 = OpLoad %float %u
+         %26 = OpFunctionCall %uint %tint_ftou %27
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/expressions/type_conv/vec2/function/f32-i32.wgsl.expected.dxc.hlsl b/test/tint/expressions/type_conv/vec2/function/f32-i32.wgsl.expected.dxc.hlsl
index b8c126f..48c5438 100644
--- a/test/tint/expressions/type_conv/vec2/function/f32-i32.wgsl.expected.dxc.hlsl
+++ b/test/tint/expressions/type_conv/vec2/function/f32-i32.wgsl.expected.dxc.hlsl
@@ -3,6 +3,10 @@
   return;
 }
 
+int2 tint_ftoi(float2 v) {
+  return ((v < (2147483520.0f).xx) ? ((v < (-2147483648.0f).xx) ? (-2147483648).xx : int2(v)) : (2147483647).xx);
+}
+
 static float t = 0.0f;
 
 float2 m() {
@@ -12,5 +16,5 @@
 
 void f() {
   const float2 tint_symbol = m();
-  int2 v = int2(tint_symbol);
+  int2 v = tint_ftoi(tint_symbol);
 }
diff --git a/test/tint/expressions/type_conv/vec2/function/f32-i32.wgsl.expected.fxc.hlsl b/test/tint/expressions/type_conv/vec2/function/f32-i32.wgsl.expected.fxc.hlsl
index b8c126f..48c5438 100644
--- a/test/tint/expressions/type_conv/vec2/function/f32-i32.wgsl.expected.fxc.hlsl
+++ b/test/tint/expressions/type_conv/vec2/function/f32-i32.wgsl.expected.fxc.hlsl
@@ -3,6 +3,10 @@
   return;
 }
 
+int2 tint_ftoi(float2 v) {
+  return ((v < (2147483520.0f).xx) ? ((v < (-2147483648.0f).xx) ? (-2147483648).xx : int2(v)) : (2147483647).xx);
+}
+
 static float t = 0.0f;
 
 float2 m() {
@@ -12,5 +16,5 @@
 
 void f() {
   const float2 tint_symbol = m();
-  int2 v = int2(tint_symbol);
+  int2 v = tint_ftoi(tint_symbol);
 }
diff --git a/test/tint/expressions/type_conv/vec2/function/f32-i32.wgsl.expected.glsl b/test/tint/expressions/type_conv/vec2/function/f32-i32.wgsl.expected.glsl
index d231846..d3afdff 100644
--- a/test/tint/expressions/type_conv/vec2/function/f32-i32.wgsl.expected.glsl
+++ b/test/tint/expressions/type_conv/vec2/function/f32-i32.wgsl.expected.glsl
@@ -1,9 +1,18 @@
 #version 310 es
 
+ivec2 tint_select(ivec2 param_0, ivec2 param_1, bvec2 param_2) {
+    return ivec2(param_2[0] ? param_1[0] : param_0[0], param_2[1] ? param_1[1] : param_0[1]);
+}
+
+
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
 void unused_entry_point() {
   return;
 }
+ivec2 tint_ftoi(vec2 v) {
+  return tint_select(ivec2(2147483647), tint_select(ivec2(v), ivec2((-2147483647 - 1)), lessThan(v, vec2(-2147483648.0f))), lessThan(v, vec2(2147483520.0f)));
+}
+
 float t = 0.0f;
 vec2 m() {
   t = 1.0f;
@@ -12,6 +21,6 @@
 
 void f() {
   vec2 tint_symbol = m();
-  ivec2 v = ivec2(tint_symbol);
+  ivec2 v = tint_ftoi(tint_symbol);
 }
 
diff --git a/test/tint/expressions/type_conv/vec2/function/f32-i32.wgsl.expected.msl b/test/tint/expressions/type_conv/vec2/function/f32-i32.wgsl.expected.msl
index 7e6c678..0a7e0fc 100644
--- a/test/tint/expressions/type_conv/vec2/function/f32-i32.wgsl.expected.msl
+++ b/test/tint/expressions/type_conv/vec2/function/f32-i32.wgsl.expected.msl
@@ -1,6 +1,10 @@
 #include <metal_stdlib>
 
 using namespace metal;
+int2 tint_ftoi(float2 v) {
+  return select(int2(2147483647), select(int2(v), int2((-2147483647 - 1)), (v < float2(-2147483648.0f))), (v < float2(2147483520.0f)));
+}
+
 float2 m() {
   thread float tint_symbol_1 = 0.0f;
   tint_symbol_1 = 1.0f;
@@ -9,6 +13,6 @@
 
 void f() {
   float2 const tint_symbol = m();
-  int2 v = int2(tint_symbol);
+  int2 v = tint_ftoi(tint_symbol);
 }
 
diff --git a/test/tint/expressions/type_conv/vec2/function/f32-i32.wgsl.expected.spvasm b/test/tint/expressions/type_conv/vec2/function/f32-i32.wgsl.expected.spvasm
index 9000a75..458f9b1 100644
--- a/test/tint/expressions/type_conv/vec2/function/f32-i32.wgsl.expected.spvasm
+++ b/test/tint/expressions/type_conv/vec2/function/f32-i32.wgsl.expected.spvasm
@@ -1,7 +1,7 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 25
+; Bound: 44
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
@@ -9,38 +9,61 @@
                OpExecutionMode %unused_entry_point LocalSize 1 1 1
                OpName %t "t"
                OpName %unused_entry_point "unused_entry_point"
+               OpName %tint_ftoi "tint_ftoi"
+               OpName %v "v"
                OpName %m "m"
                OpName %f "f"
-               OpName %v "v"
+               OpName %v_0 "v"
       %float = OpTypeFloat 32
 %_ptr_Private_float = OpTypePointer Private %float
           %4 = OpConstantNull %float
           %t = OpVariable %_ptr_Private_float Private %4
        %void = OpTypeVoid
           %5 = OpTypeFunction %void
-    %v2float = OpTypeVector %float 2
-          %9 = OpTypeFunction %v2float
-    %float_1 = OpConstant %float 1
         %int = OpTypeInt 32 1
       %v2int = OpTypeVector %int 2
+    %v2float = OpTypeVector %float 2
+          %9 = OpTypeFunction %v2int %v2float
+%float_2_14748352e_09 = OpConstant %float 2.14748352e+09
+         %18 = OpConstantComposite %v2float %float_2_14748352e_09 %float_2_14748352e_09
+       %bool = OpTypeBool
+     %v2bool = OpTypeVector %bool 2
+%float_n2_14748365e_09 = OpConstant %float -2.14748365e+09
+         %24 = OpConstantComposite %v2float %float_n2_14748365e_09 %float_n2_14748365e_09
+%int_n2147483648 = OpConstant %int -2147483648
+         %27 = OpConstantComposite %v2int %int_n2147483648 %int_n2147483648
+%int_2147483647 = OpConstant %int 2147483647
+         %30 = OpConstantComposite %v2int %int_2147483647 %int_2147483647
+         %31 = OpTypeFunction %v2float
+    %float_1 = OpConstant %float 1
 %_ptr_Function_v2int = OpTypePointer Function %v2int
-         %24 = OpConstantNull %v2int
+         %43 = OpConstantNull %v2int
 %unused_entry_point = OpFunction %void None %5
           %8 = OpLabel
                OpReturn
                OpFunctionEnd
-          %m = OpFunction %v2float None %9
-         %12 = OpLabel
+  %tint_ftoi = OpFunction %v2int None %9
+          %v = OpFunctionParameter %v2float
+         %15 = OpLabel
+         %19 = OpFOrdLessThan %v2bool %v %18
+         %25 = OpFOrdLessThan %v2bool %v %24
+         %28 = OpConvertFToS %v2int %v
+         %22 = OpSelect %v2int %25 %27 %28
+         %16 = OpSelect %v2int %19 %22 %30
+               OpReturnValue %16
+               OpFunctionEnd
+          %m = OpFunction %v2float None %31
+         %33 = OpLabel
                OpStore %t %float_1
-         %14 = OpLoad %float %t
-         %15 = OpCompositeConstruct %v2float %14 %14
-               OpReturnValue %15
+         %35 = OpLoad %float %t
+         %36 = OpCompositeConstruct %v2float %35 %35
+               OpReturnValue %36
                OpFunctionEnd
           %f = OpFunction %void None %5
-         %17 = OpLabel
-          %v = OpVariable %_ptr_Function_v2int Function %24
-         %18 = OpFunctionCall %v2float %m
-         %19 = OpConvertFToS %v2int %18
-               OpStore %v %19
+         %38 = OpLabel
+        %v_0 = OpVariable %_ptr_Function_v2int Function %43
+         %39 = OpFunctionCall %v2float %m
+         %40 = OpFunctionCall %v2int %tint_ftoi %39
+               OpStore %v_0 %40
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/expressions/type_conv/vec2/function/f32-u32.wgsl.expected.dxc.hlsl b/test/tint/expressions/type_conv/vec2/function/f32-u32.wgsl.expected.dxc.hlsl
index a21b6d2..06586a2 100644
--- a/test/tint/expressions/type_conv/vec2/function/f32-u32.wgsl.expected.dxc.hlsl
+++ b/test/tint/expressions/type_conv/vec2/function/f32-u32.wgsl.expected.dxc.hlsl
@@ -3,6 +3,10 @@
   return;
 }
 
+uint2 tint_ftou(float2 v) {
+  return ((v < (4294967040.0f).xx) ? ((v < (0.0f).xx) ? (0u).xx : uint2(v)) : (4294967295u).xx);
+}
+
 static float t = 0.0f;
 
 float2 m() {
@@ -12,5 +16,5 @@
 
 void f() {
   const float2 tint_symbol = m();
-  uint2 v = uint2(tint_symbol);
+  uint2 v = tint_ftou(tint_symbol);
 }
diff --git a/test/tint/expressions/type_conv/vec2/function/f32-u32.wgsl.expected.fxc.hlsl b/test/tint/expressions/type_conv/vec2/function/f32-u32.wgsl.expected.fxc.hlsl
index a21b6d2..06586a2 100644
--- a/test/tint/expressions/type_conv/vec2/function/f32-u32.wgsl.expected.fxc.hlsl
+++ b/test/tint/expressions/type_conv/vec2/function/f32-u32.wgsl.expected.fxc.hlsl
@@ -3,6 +3,10 @@
   return;
 }
 
+uint2 tint_ftou(float2 v) {
+  return ((v < (4294967040.0f).xx) ? ((v < (0.0f).xx) ? (0u).xx : uint2(v)) : (4294967295u).xx);
+}
+
 static float t = 0.0f;
 
 float2 m() {
@@ -12,5 +16,5 @@
 
 void f() {
   const float2 tint_symbol = m();
-  uint2 v = uint2(tint_symbol);
+  uint2 v = tint_ftou(tint_symbol);
 }
diff --git a/test/tint/expressions/type_conv/vec2/function/f32-u32.wgsl.expected.glsl b/test/tint/expressions/type_conv/vec2/function/f32-u32.wgsl.expected.glsl
index 775f771..fb1d7fd 100644
--- a/test/tint/expressions/type_conv/vec2/function/f32-u32.wgsl.expected.glsl
+++ b/test/tint/expressions/type_conv/vec2/function/f32-u32.wgsl.expected.glsl
@@ -1,9 +1,18 @@
 #version 310 es
 
+uvec2 tint_select(uvec2 param_0, uvec2 param_1, bvec2 param_2) {
+    return uvec2(param_2[0] ? param_1[0] : param_0[0], param_2[1] ? param_1[1] : param_0[1]);
+}
+
+
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
 void unused_entry_point() {
   return;
 }
+uvec2 tint_ftou(vec2 v) {
+  return tint_select(uvec2(4294967295u), tint_select(uvec2(v), uvec2(0u), lessThan(v, vec2(0.0f))), lessThan(v, vec2(4294967040.0f)));
+}
+
 float t = 0.0f;
 vec2 m() {
   t = 1.0f;
@@ -12,6 +21,6 @@
 
 void f() {
   vec2 tint_symbol = m();
-  uvec2 v = uvec2(tint_symbol);
+  uvec2 v = tint_ftou(tint_symbol);
 }
 
diff --git a/test/tint/expressions/type_conv/vec2/function/f32-u32.wgsl.expected.msl b/test/tint/expressions/type_conv/vec2/function/f32-u32.wgsl.expected.msl
index 38d1a0e..cd029ff 100644
--- a/test/tint/expressions/type_conv/vec2/function/f32-u32.wgsl.expected.msl
+++ b/test/tint/expressions/type_conv/vec2/function/f32-u32.wgsl.expected.msl
@@ -1,6 +1,10 @@
 #include <metal_stdlib>
 
 using namespace metal;
+uint2 tint_ftou(float2 v) {
+  return select(uint2(4294967295u), select(uint2(v), uint2(0u), (v < float2(0.0f))), (v < float2(4294967040.0f)));
+}
+
 float2 m() {
   thread float tint_symbol_1 = 0.0f;
   tint_symbol_1 = 1.0f;
@@ -9,6 +13,6 @@
 
 void f() {
   float2 const tint_symbol = m();
-  uint2 v = uint2(tint_symbol);
+  uint2 v = tint_ftou(tint_symbol);
 }
 
diff --git a/test/tint/expressions/type_conv/vec2/function/f32-u32.wgsl.expected.spvasm b/test/tint/expressions/type_conv/vec2/function/f32-u32.wgsl.expected.spvasm
index 23d54f8..aa0ea50 100644
--- a/test/tint/expressions/type_conv/vec2/function/f32-u32.wgsl.expected.spvasm
+++ b/test/tint/expressions/type_conv/vec2/function/f32-u32.wgsl.expected.spvasm
@@ -1,7 +1,7 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 25
+; Bound: 41
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
@@ -9,38 +9,58 @@
                OpExecutionMode %unused_entry_point LocalSize 1 1 1
                OpName %t "t"
                OpName %unused_entry_point "unused_entry_point"
+               OpName %tint_ftou "tint_ftou"
+               OpName %v "v"
                OpName %m "m"
                OpName %f "f"
-               OpName %v "v"
+               OpName %v_0 "v"
       %float = OpTypeFloat 32
 %_ptr_Private_float = OpTypePointer Private %float
           %4 = OpConstantNull %float
           %t = OpVariable %_ptr_Private_float Private %4
        %void = OpTypeVoid
           %5 = OpTypeFunction %void
-    %v2float = OpTypeVector %float 2
-          %9 = OpTypeFunction %v2float
-    %float_1 = OpConstant %float 1
        %uint = OpTypeInt 32 0
      %v2uint = OpTypeVector %uint 2
+    %v2float = OpTypeVector %float 2
+          %9 = OpTypeFunction %v2uint %v2float
+%float_4_29496704e_09 = OpConstant %float 4.29496704e+09
+         %18 = OpConstantComposite %v2float %float_4_29496704e_09 %float_4_29496704e_09
+       %bool = OpTypeBool
+     %v2bool = OpTypeVector %bool 2
+         %23 = OpConstantNull %v2float
+         %25 = OpConstantNull %v2uint
+%uint_4294967295 = OpConstant %uint 4294967295
+         %28 = OpConstantComposite %v2uint %uint_4294967295 %uint_4294967295
+         %29 = OpTypeFunction %v2float
+    %float_1 = OpConstant %float 1
 %_ptr_Function_v2uint = OpTypePointer Function %v2uint
-         %24 = OpConstantNull %v2uint
 %unused_entry_point = OpFunction %void None %5
           %8 = OpLabel
                OpReturn
                OpFunctionEnd
-          %m = OpFunction %v2float None %9
-         %12 = OpLabel
+  %tint_ftou = OpFunction %v2uint None %9
+          %v = OpFunctionParameter %v2float
+         %15 = OpLabel
+         %19 = OpFOrdLessThan %v2bool %v %18
+         %24 = OpFOrdLessThan %v2bool %v %23
+         %26 = OpConvertFToU %v2uint %v
+         %22 = OpSelect %v2uint %24 %25 %26
+         %16 = OpSelect %v2uint %19 %22 %28
+               OpReturnValue %16
+               OpFunctionEnd
+          %m = OpFunction %v2float None %29
+         %31 = OpLabel
                OpStore %t %float_1
-         %14 = OpLoad %float %t
-         %15 = OpCompositeConstruct %v2float %14 %14
-               OpReturnValue %15
+         %33 = OpLoad %float %t
+         %34 = OpCompositeConstruct %v2float %33 %33
+               OpReturnValue %34
                OpFunctionEnd
           %f = OpFunction %void None %5
-         %17 = OpLabel
-          %v = OpVariable %_ptr_Function_v2uint Function %24
-         %18 = OpFunctionCall %v2float %m
-         %19 = OpConvertFToU %v2uint %18
-               OpStore %v %19
+         %36 = OpLabel
+        %v_0 = OpVariable %_ptr_Function_v2uint Function %25
+         %37 = OpFunctionCall %v2float %m
+         %38 = OpFunctionCall %v2uint %tint_ftou %37
+               OpStore %v_0 %38
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/expressions/type_conv/vec2/var/f32-i32.wgsl.expected.dxc.hlsl b/test/tint/expressions/type_conv/vec2/var/f32-i32.wgsl.expected.dxc.hlsl
index 7da1555..73428fc 100644
--- a/test/tint/expressions/type_conv/vec2/var/f32-i32.wgsl.expected.dxc.hlsl
+++ b/test/tint/expressions/type_conv/vec2/var/f32-i32.wgsl.expected.dxc.hlsl
@@ -3,8 +3,12 @@
   return;
 }
 
+int2 tint_ftoi(float2 v) {
+  return ((v < (2147483520.0f).xx) ? ((v < (-2147483648.0f).xx) ? (-2147483648).xx : int2(v)) : (2147483647).xx);
+}
+
 static float2 u = (1.0f).xx;
 
 void f() {
-  const int2 v = int2(u);
+  const int2 v = tint_ftoi(u);
 }
diff --git a/test/tint/expressions/type_conv/vec2/var/f32-i32.wgsl.expected.fxc.hlsl b/test/tint/expressions/type_conv/vec2/var/f32-i32.wgsl.expected.fxc.hlsl
index 7da1555..73428fc 100644
--- a/test/tint/expressions/type_conv/vec2/var/f32-i32.wgsl.expected.fxc.hlsl
+++ b/test/tint/expressions/type_conv/vec2/var/f32-i32.wgsl.expected.fxc.hlsl
@@ -3,8 +3,12 @@
   return;
 }
 
+int2 tint_ftoi(float2 v) {
+  return ((v < (2147483520.0f).xx) ? ((v < (-2147483648.0f).xx) ? (-2147483648).xx : int2(v)) : (2147483647).xx);
+}
+
 static float2 u = (1.0f).xx;
 
 void f() {
-  const int2 v = int2(u);
+  const int2 v = tint_ftoi(u);
 }
diff --git a/test/tint/expressions/type_conv/vec2/var/f32-i32.wgsl.expected.glsl b/test/tint/expressions/type_conv/vec2/var/f32-i32.wgsl.expected.glsl
index 76b5fdb..6c79343 100644
--- a/test/tint/expressions/type_conv/vec2/var/f32-i32.wgsl.expected.glsl
+++ b/test/tint/expressions/type_conv/vec2/var/f32-i32.wgsl.expected.glsl
@@ -1,11 +1,20 @@
 #version 310 es
 
+ivec2 tint_select(ivec2 param_0, ivec2 param_1, bvec2 param_2) {
+    return ivec2(param_2[0] ? param_1[0] : param_0[0], param_2[1] ? param_1[1] : param_0[1]);
+}
+
+
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
 void unused_entry_point() {
   return;
 }
+ivec2 tint_ftoi(vec2 v) {
+  return tint_select(ivec2(2147483647), tint_select(ivec2(v), ivec2((-2147483647 - 1)), lessThan(v, vec2(-2147483648.0f))), lessThan(v, vec2(2147483520.0f)));
+}
+
 vec2 u = vec2(1.0f);
 void f() {
-  ivec2 v = ivec2(u);
+  ivec2 v = tint_ftoi(u);
 }
 
diff --git a/test/tint/expressions/type_conv/vec2/var/f32-i32.wgsl.expected.msl b/test/tint/expressions/type_conv/vec2/var/f32-i32.wgsl.expected.msl
index 34cfc3a..4475d07 100644
--- a/test/tint/expressions/type_conv/vec2/var/f32-i32.wgsl.expected.msl
+++ b/test/tint/expressions/type_conv/vec2/var/f32-i32.wgsl.expected.msl
@@ -1,8 +1,12 @@
 #include <metal_stdlib>
 
 using namespace metal;
+int2 tint_ftoi(float2 v) {
+  return select(int2(2147483647), select(int2(v), int2((-2147483647 - 1)), (v < float2(-2147483648.0f))), (v < float2(2147483520.0f)));
+}
+
 void f() {
   thread float2 tint_symbol = float2(1.0f);
-  int2 const v = int2(tint_symbol);
+  int2 const v = tint_ftoi(tint_symbol);
 }
 
diff --git a/test/tint/expressions/type_conv/vec2/var/f32-i32.wgsl.expected.spvasm b/test/tint/expressions/type_conv/vec2/var/f32-i32.wgsl.expected.spvasm
index 77adb07..7f996e9 100644
--- a/test/tint/expressions/type_conv/vec2/var/f32-i32.wgsl.expected.spvasm
+++ b/test/tint/expressions/type_conv/vec2/var/f32-i32.wgsl.expected.spvasm
@@ -1,7 +1,7 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 17
+; Bound: 36
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
@@ -9,6 +9,8 @@
                OpExecutionMode %unused_entry_point LocalSize 1 1 1
                OpName %u "u"
                OpName %unused_entry_point "unused_entry_point"
+               OpName %tint_ftoi "tint_ftoi"
+               OpName %v "v"
                OpName %f "f"
       %float = OpTypeFloat 32
     %v2float = OpTypeVector %float 2
@@ -20,13 +22,34 @@
           %7 = OpTypeFunction %void
         %int = OpTypeInt 32 1
       %v2int = OpTypeVector %int 2
+         %11 = OpTypeFunction %v2int %v2float
+%float_2_14748352e_09 = OpConstant %float 2.14748352e+09
+         %19 = OpConstantComposite %v2float %float_2_14748352e_09 %float_2_14748352e_09
+       %bool = OpTypeBool
+     %v2bool = OpTypeVector %bool 2
+%float_n2_14748365e_09 = OpConstant %float -2.14748365e+09
+         %25 = OpConstantComposite %v2float %float_n2_14748365e_09 %float_n2_14748365e_09
+%int_n2147483648 = OpConstant %int -2147483648
+         %28 = OpConstantComposite %v2int %int_n2147483648 %int_n2147483648
+%int_2147483647 = OpConstant %int 2147483647
+         %31 = OpConstantComposite %v2int %int_2147483647 %int_2147483647
 %unused_entry_point = OpFunction %void None %7
          %10 = OpLabel
                OpReturn
                OpFunctionEnd
+  %tint_ftoi = OpFunction %v2int None %11
+          %v = OpFunctionParameter %v2float
+         %16 = OpLabel
+         %20 = OpFOrdLessThan %v2bool %v %19
+         %26 = OpFOrdLessThan %v2bool %v %25
+         %29 = OpConvertFToS %v2int %v
+         %23 = OpSelect %v2int %26 %28 %29
+         %17 = OpSelect %v2int %20 %23 %31
+               OpReturnValue %17
+               OpFunctionEnd
           %f = OpFunction %void None %7
-         %12 = OpLabel
-         %16 = OpLoad %v2float %u
-         %13 = OpConvertFToS %v2int %16
+         %33 = OpLabel
+         %35 = OpLoad %v2float %u
+         %34 = OpFunctionCall %v2int %tint_ftoi %35
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/expressions/type_conv/vec2/var/f32-u32.wgsl.expected.dxc.hlsl b/test/tint/expressions/type_conv/vec2/var/f32-u32.wgsl.expected.dxc.hlsl
index cd719e2..e5b3129 100644
--- a/test/tint/expressions/type_conv/vec2/var/f32-u32.wgsl.expected.dxc.hlsl
+++ b/test/tint/expressions/type_conv/vec2/var/f32-u32.wgsl.expected.dxc.hlsl
@@ -3,8 +3,12 @@
   return;
 }
 
+uint2 tint_ftou(float2 v) {
+  return ((v < (4294967040.0f).xx) ? ((v < (0.0f).xx) ? (0u).xx : uint2(v)) : (4294967295u).xx);
+}
+
 static float2 u = (1.0f).xx;
 
 void f() {
-  const uint2 v = uint2(u);
+  const uint2 v = tint_ftou(u);
 }
diff --git a/test/tint/expressions/type_conv/vec2/var/f32-u32.wgsl.expected.fxc.hlsl b/test/tint/expressions/type_conv/vec2/var/f32-u32.wgsl.expected.fxc.hlsl
index cd719e2..e5b3129 100644
--- a/test/tint/expressions/type_conv/vec2/var/f32-u32.wgsl.expected.fxc.hlsl
+++ b/test/tint/expressions/type_conv/vec2/var/f32-u32.wgsl.expected.fxc.hlsl
@@ -3,8 +3,12 @@
   return;
 }
 
+uint2 tint_ftou(float2 v) {
+  return ((v < (4294967040.0f).xx) ? ((v < (0.0f).xx) ? (0u).xx : uint2(v)) : (4294967295u).xx);
+}
+
 static float2 u = (1.0f).xx;
 
 void f() {
-  const uint2 v = uint2(u);
+  const uint2 v = tint_ftou(u);
 }
diff --git a/test/tint/expressions/type_conv/vec2/var/f32-u32.wgsl.expected.glsl b/test/tint/expressions/type_conv/vec2/var/f32-u32.wgsl.expected.glsl
index f02a58b..5ce5803 100644
--- a/test/tint/expressions/type_conv/vec2/var/f32-u32.wgsl.expected.glsl
+++ b/test/tint/expressions/type_conv/vec2/var/f32-u32.wgsl.expected.glsl
@@ -1,11 +1,20 @@
 #version 310 es
 
+uvec2 tint_select(uvec2 param_0, uvec2 param_1, bvec2 param_2) {
+    return uvec2(param_2[0] ? param_1[0] : param_0[0], param_2[1] ? param_1[1] : param_0[1]);
+}
+
+
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
 void unused_entry_point() {
   return;
 }
+uvec2 tint_ftou(vec2 v) {
+  return tint_select(uvec2(4294967295u), tint_select(uvec2(v), uvec2(0u), lessThan(v, vec2(0.0f))), lessThan(v, vec2(4294967040.0f)));
+}
+
 vec2 u = vec2(1.0f);
 void f() {
-  uvec2 v = uvec2(u);
+  uvec2 v = tint_ftou(u);
 }
 
diff --git a/test/tint/expressions/type_conv/vec2/var/f32-u32.wgsl.expected.msl b/test/tint/expressions/type_conv/vec2/var/f32-u32.wgsl.expected.msl
index a536f2e..86a4038 100644
--- a/test/tint/expressions/type_conv/vec2/var/f32-u32.wgsl.expected.msl
+++ b/test/tint/expressions/type_conv/vec2/var/f32-u32.wgsl.expected.msl
@@ -1,8 +1,12 @@
 #include <metal_stdlib>
 
 using namespace metal;
+uint2 tint_ftou(float2 v) {
+  return select(uint2(4294967295u), select(uint2(v), uint2(0u), (v < float2(0.0f))), (v < float2(4294967040.0f)));
+}
+
 void f() {
   thread float2 tint_symbol = float2(1.0f);
-  uint2 const v = uint2(tint_symbol);
+  uint2 const v = tint_ftou(tint_symbol);
 }
 
diff --git a/test/tint/expressions/type_conv/vec2/var/f32-u32.wgsl.expected.spvasm b/test/tint/expressions/type_conv/vec2/var/f32-u32.wgsl.expected.spvasm
index 2d0a5b6..8372e64 100644
--- a/test/tint/expressions/type_conv/vec2/var/f32-u32.wgsl.expected.spvasm
+++ b/test/tint/expressions/type_conv/vec2/var/f32-u32.wgsl.expected.spvasm
@@ -1,7 +1,7 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 17
+; Bound: 34
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
@@ -9,6 +9,8 @@
                OpExecutionMode %unused_entry_point LocalSize 1 1 1
                OpName %u "u"
                OpName %unused_entry_point "unused_entry_point"
+               OpName %tint_ftou "tint_ftou"
+               OpName %v "v"
                OpName %f "f"
       %float = OpTypeFloat 32
     %v2float = OpTypeVector %float 2
@@ -20,13 +22,32 @@
           %7 = OpTypeFunction %void
        %uint = OpTypeInt 32 0
      %v2uint = OpTypeVector %uint 2
+         %11 = OpTypeFunction %v2uint %v2float
+%float_4_29496704e_09 = OpConstant %float 4.29496704e+09
+         %19 = OpConstantComposite %v2float %float_4_29496704e_09 %float_4_29496704e_09
+       %bool = OpTypeBool
+     %v2bool = OpTypeVector %bool 2
+         %24 = OpConstantNull %v2float
+         %26 = OpConstantNull %v2uint
+%uint_4294967295 = OpConstant %uint 4294967295
+         %29 = OpConstantComposite %v2uint %uint_4294967295 %uint_4294967295
 %unused_entry_point = OpFunction %void None %7
          %10 = OpLabel
                OpReturn
                OpFunctionEnd
+  %tint_ftou = OpFunction %v2uint None %11
+          %v = OpFunctionParameter %v2float
+         %16 = OpLabel
+         %20 = OpFOrdLessThan %v2bool %v %19
+         %25 = OpFOrdLessThan %v2bool %v %24
+         %27 = OpConvertFToU %v2uint %v
+         %23 = OpSelect %v2uint %25 %26 %27
+         %17 = OpSelect %v2uint %20 %23 %29
+               OpReturnValue %17
+               OpFunctionEnd
           %f = OpFunction %void None %7
-         %12 = OpLabel
-         %16 = OpLoad %v2float %u
-         %13 = OpConvertFToU %v2uint %16
+         %31 = OpLabel
+         %33 = OpLoad %v2float %u
+         %32 = OpFunctionCall %v2uint %tint_ftou %33
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/expressions/type_conv/vec3/function/f32-i32.wgsl.expected.dxc.hlsl b/test/tint/expressions/type_conv/vec3/function/f32-i32.wgsl.expected.dxc.hlsl
index 696e21e..dc236d8 100644
--- a/test/tint/expressions/type_conv/vec3/function/f32-i32.wgsl.expected.dxc.hlsl
+++ b/test/tint/expressions/type_conv/vec3/function/f32-i32.wgsl.expected.dxc.hlsl
@@ -3,6 +3,10 @@
   return;
 }
 
+int3 tint_ftoi(float3 v) {
+  return ((v < (2147483520.0f).xxx) ? ((v < (-2147483648.0f).xxx) ? (-2147483648).xxx : int3(v)) : (2147483647).xxx);
+}
+
 static float t = 0.0f;
 
 float3 m() {
@@ -12,5 +16,5 @@
 
 void f() {
   const float3 tint_symbol = m();
-  int3 v = int3(tint_symbol);
+  int3 v = tint_ftoi(tint_symbol);
 }
diff --git a/test/tint/expressions/type_conv/vec3/function/f32-i32.wgsl.expected.fxc.hlsl b/test/tint/expressions/type_conv/vec3/function/f32-i32.wgsl.expected.fxc.hlsl
index 696e21e..dc236d8 100644
--- a/test/tint/expressions/type_conv/vec3/function/f32-i32.wgsl.expected.fxc.hlsl
+++ b/test/tint/expressions/type_conv/vec3/function/f32-i32.wgsl.expected.fxc.hlsl
@@ -3,6 +3,10 @@
   return;
 }
 
+int3 tint_ftoi(float3 v) {
+  return ((v < (2147483520.0f).xxx) ? ((v < (-2147483648.0f).xxx) ? (-2147483648).xxx : int3(v)) : (2147483647).xxx);
+}
+
 static float t = 0.0f;
 
 float3 m() {
@@ -12,5 +16,5 @@
 
 void f() {
   const float3 tint_symbol = m();
-  int3 v = int3(tint_symbol);
+  int3 v = tint_ftoi(tint_symbol);
 }
diff --git a/test/tint/expressions/type_conv/vec3/function/f32-i32.wgsl.expected.glsl b/test/tint/expressions/type_conv/vec3/function/f32-i32.wgsl.expected.glsl
index 9b1de1c..4941250 100644
--- a/test/tint/expressions/type_conv/vec3/function/f32-i32.wgsl.expected.glsl
+++ b/test/tint/expressions/type_conv/vec3/function/f32-i32.wgsl.expected.glsl
@@ -1,9 +1,18 @@
 #version 310 es
 
+ivec3 tint_select(ivec3 param_0, ivec3 param_1, bvec3 param_2) {
+    return ivec3(param_2[0] ? param_1[0] : param_0[0], param_2[1] ? param_1[1] : param_0[1], param_2[2] ? param_1[2] : param_0[2]);
+}
+
+
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
 void unused_entry_point() {
   return;
 }
+ivec3 tint_ftoi(vec3 v) {
+  return tint_select(ivec3(2147483647), tint_select(ivec3(v), ivec3((-2147483647 - 1)), lessThan(v, vec3(-2147483648.0f))), lessThan(v, vec3(2147483520.0f)));
+}
+
 float t = 0.0f;
 vec3 m() {
   t = 1.0f;
@@ -12,6 +21,6 @@
 
 void f() {
   vec3 tint_symbol = m();
-  ivec3 v = ivec3(tint_symbol);
+  ivec3 v = tint_ftoi(tint_symbol);
 }
 
diff --git a/test/tint/expressions/type_conv/vec3/function/f32-i32.wgsl.expected.msl b/test/tint/expressions/type_conv/vec3/function/f32-i32.wgsl.expected.msl
index 9234be0..17b35db 100644
--- a/test/tint/expressions/type_conv/vec3/function/f32-i32.wgsl.expected.msl
+++ b/test/tint/expressions/type_conv/vec3/function/f32-i32.wgsl.expected.msl
@@ -1,6 +1,10 @@
 #include <metal_stdlib>
 
 using namespace metal;
+int3 tint_ftoi(float3 v) {
+  return select(int3(2147483647), select(int3(v), int3((-2147483647 - 1)), (v < float3(-2147483648.0f))), (v < float3(2147483520.0f)));
+}
+
 float3 m() {
   thread float tint_symbol_1 = 0.0f;
   tint_symbol_1 = 1.0f;
@@ -9,6 +13,6 @@
 
 void f() {
   float3 const tint_symbol = m();
-  int3 v = int3(tint_symbol);
+  int3 v = tint_ftoi(tint_symbol);
 }
 
diff --git a/test/tint/expressions/type_conv/vec3/function/f32-i32.wgsl.expected.spvasm b/test/tint/expressions/type_conv/vec3/function/f32-i32.wgsl.expected.spvasm
index 7874a36..979f1f1 100644
--- a/test/tint/expressions/type_conv/vec3/function/f32-i32.wgsl.expected.spvasm
+++ b/test/tint/expressions/type_conv/vec3/function/f32-i32.wgsl.expected.spvasm
@@ -1,7 +1,7 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 25
+; Bound: 44
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
@@ -9,38 +9,61 @@
                OpExecutionMode %unused_entry_point LocalSize 1 1 1
                OpName %t "t"
                OpName %unused_entry_point "unused_entry_point"
+               OpName %tint_ftoi "tint_ftoi"
+               OpName %v "v"
                OpName %m "m"
                OpName %f "f"
-               OpName %v "v"
+               OpName %v_0 "v"
       %float = OpTypeFloat 32
 %_ptr_Private_float = OpTypePointer Private %float
           %4 = OpConstantNull %float
           %t = OpVariable %_ptr_Private_float Private %4
        %void = OpTypeVoid
           %5 = OpTypeFunction %void
-    %v3float = OpTypeVector %float 3
-          %9 = OpTypeFunction %v3float
-    %float_1 = OpConstant %float 1
         %int = OpTypeInt 32 1
       %v3int = OpTypeVector %int 3
+    %v3float = OpTypeVector %float 3
+          %9 = OpTypeFunction %v3int %v3float
+%float_2_14748352e_09 = OpConstant %float 2.14748352e+09
+         %18 = OpConstantComposite %v3float %float_2_14748352e_09 %float_2_14748352e_09 %float_2_14748352e_09
+       %bool = OpTypeBool
+     %v3bool = OpTypeVector %bool 3
+%float_n2_14748365e_09 = OpConstant %float -2.14748365e+09
+         %24 = OpConstantComposite %v3float %float_n2_14748365e_09 %float_n2_14748365e_09 %float_n2_14748365e_09
+%int_n2147483648 = OpConstant %int -2147483648
+         %27 = OpConstantComposite %v3int %int_n2147483648 %int_n2147483648 %int_n2147483648
+%int_2147483647 = OpConstant %int 2147483647
+         %30 = OpConstantComposite %v3int %int_2147483647 %int_2147483647 %int_2147483647
+         %31 = OpTypeFunction %v3float
+    %float_1 = OpConstant %float 1
 %_ptr_Function_v3int = OpTypePointer Function %v3int
-         %24 = OpConstantNull %v3int
+         %43 = OpConstantNull %v3int
 %unused_entry_point = OpFunction %void None %5
           %8 = OpLabel
                OpReturn
                OpFunctionEnd
-          %m = OpFunction %v3float None %9
-         %12 = OpLabel
+  %tint_ftoi = OpFunction %v3int None %9
+          %v = OpFunctionParameter %v3float
+         %15 = OpLabel
+         %19 = OpFOrdLessThan %v3bool %v %18
+         %25 = OpFOrdLessThan %v3bool %v %24
+         %28 = OpConvertFToS %v3int %v
+         %22 = OpSelect %v3int %25 %27 %28
+         %16 = OpSelect %v3int %19 %22 %30
+               OpReturnValue %16
+               OpFunctionEnd
+          %m = OpFunction %v3float None %31
+         %33 = OpLabel
                OpStore %t %float_1
-         %14 = OpLoad %float %t
-         %15 = OpCompositeConstruct %v3float %14 %14 %14
-               OpReturnValue %15
+         %35 = OpLoad %float %t
+         %36 = OpCompositeConstruct %v3float %35 %35 %35
+               OpReturnValue %36
                OpFunctionEnd
           %f = OpFunction %void None %5
-         %17 = OpLabel
-          %v = OpVariable %_ptr_Function_v3int Function %24
-         %18 = OpFunctionCall %v3float %m
-         %19 = OpConvertFToS %v3int %18
-               OpStore %v %19
+         %38 = OpLabel
+        %v_0 = OpVariable %_ptr_Function_v3int Function %43
+         %39 = OpFunctionCall %v3float %m
+         %40 = OpFunctionCall %v3int %tint_ftoi %39
+               OpStore %v_0 %40
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/expressions/type_conv/vec3/function/f32-u32.wgsl.expected.dxc.hlsl b/test/tint/expressions/type_conv/vec3/function/f32-u32.wgsl.expected.dxc.hlsl
index 33e2c8d..aef28a2 100644
--- a/test/tint/expressions/type_conv/vec3/function/f32-u32.wgsl.expected.dxc.hlsl
+++ b/test/tint/expressions/type_conv/vec3/function/f32-u32.wgsl.expected.dxc.hlsl
@@ -3,6 +3,10 @@
   return;
 }
 
+uint3 tint_ftou(float3 v) {
+  return ((v < (4294967040.0f).xxx) ? ((v < (0.0f).xxx) ? (0u).xxx : uint3(v)) : (4294967295u).xxx);
+}
+
 static float t = 0.0f;
 
 float3 m() {
@@ -12,5 +16,5 @@
 
 void f() {
   const float3 tint_symbol = m();
-  uint3 v = uint3(tint_symbol);
+  uint3 v = tint_ftou(tint_symbol);
 }
diff --git a/test/tint/expressions/type_conv/vec3/function/f32-u32.wgsl.expected.fxc.hlsl b/test/tint/expressions/type_conv/vec3/function/f32-u32.wgsl.expected.fxc.hlsl
index 33e2c8d..aef28a2 100644
--- a/test/tint/expressions/type_conv/vec3/function/f32-u32.wgsl.expected.fxc.hlsl
+++ b/test/tint/expressions/type_conv/vec3/function/f32-u32.wgsl.expected.fxc.hlsl
@@ -3,6 +3,10 @@
   return;
 }
 
+uint3 tint_ftou(float3 v) {
+  return ((v < (4294967040.0f).xxx) ? ((v < (0.0f).xxx) ? (0u).xxx : uint3(v)) : (4294967295u).xxx);
+}
+
 static float t = 0.0f;
 
 float3 m() {
@@ -12,5 +16,5 @@
 
 void f() {
   const float3 tint_symbol = m();
-  uint3 v = uint3(tint_symbol);
+  uint3 v = tint_ftou(tint_symbol);
 }
diff --git a/test/tint/expressions/type_conv/vec3/function/f32-u32.wgsl.expected.glsl b/test/tint/expressions/type_conv/vec3/function/f32-u32.wgsl.expected.glsl
index aeadc11..8e1b3c1 100644
--- a/test/tint/expressions/type_conv/vec3/function/f32-u32.wgsl.expected.glsl
+++ b/test/tint/expressions/type_conv/vec3/function/f32-u32.wgsl.expected.glsl
@@ -1,9 +1,18 @@
 #version 310 es
 
+uvec3 tint_select(uvec3 param_0, uvec3 param_1, bvec3 param_2) {
+    return uvec3(param_2[0] ? param_1[0] : param_0[0], param_2[1] ? param_1[1] : param_0[1], param_2[2] ? param_1[2] : param_0[2]);
+}
+
+
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
 void unused_entry_point() {
   return;
 }
+uvec3 tint_ftou(vec3 v) {
+  return tint_select(uvec3(4294967295u), tint_select(uvec3(v), uvec3(0u), lessThan(v, vec3(0.0f))), lessThan(v, vec3(4294967040.0f)));
+}
+
 float t = 0.0f;
 vec3 m() {
   t = 1.0f;
@@ -12,6 +21,6 @@
 
 void f() {
   vec3 tint_symbol = m();
-  uvec3 v = uvec3(tint_symbol);
+  uvec3 v = tint_ftou(tint_symbol);
 }
 
diff --git a/test/tint/expressions/type_conv/vec3/function/f32-u32.wgsl.expected.msl b/test/tint/expressions/type_conv/vec3/function/f32-u32.wgsl.expected.msl
index ab5d331..f5e5a53 100644
--- a/test/tint/expressions/type_conv/vec3/function/f32-u32.wgsl.expected.msl
+++ b/test/tint/expressions/type_conv/vec3/function/f32-u32.wgsl.expected.msl
@@ -1,6 +1,10 @@
 #include <metal_stdlib>
 
 using namespace metal;
+uint3 tint_ftou(float3 v) {
+  return select(uint3(4294967295u), select(uint3(v), uint3(0u), (v < float3(0.0f))), (v < float3(4294967040.0f)));
+}
+
 float3 m() {
   thread float tint_symbol_1 = 0.0f;
   tint_symbol_1 = 1.0f;
@@ -9,6 +13,6 @@
 
 void f() {
   float3 const tint_symbol = m();
-  uint3 v = uint3(tint_symbol);
+  uint3 v = tint_ftou(tint_symbol);
 }
 
diff --git a/test/tint/expressions/type_conv/vec3/function/f32-u32.wgsl.expected.spvasm b/test/tint/expressions/type_conv/vec3/function/f32-u32.wgsl.expected.spvasm
index 3f57b52..8c0acde 100644
--- a/test/tint/expressions/type_conv/vec3/function/f32-u32.wgsl.expected.spvasm
+++ b/test/tint/expressions/type_conv/vec3/function/f32-u32.wgsl.expected.spvasm
@@ -1,7 +1,7 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 25
+; Bound: 41
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
@@ -9,38 +9,58 @@
                OpExecutionMode %unused_entry_point LocalSize 1 1 1
                OpName %t "t"
                OpName %unused_entry_point "unused_entry_point"
+               OpName %tint_ftou "tint_ftou"
+               OpName %v "v"
                OpName %m "m"
                OpName %f "f"
-               OpName %v "v"
+               OpName %v_0 "v"
       %float = OpTypeFloat 32
 %_ptr_Private_float = OpTypePointer Private %float
           %4 = OpConstantNull %float
           %t = OpVariable %_ptr_Private_float Private %4
        %void = OpTypeVoid
           %5 = OpTypeFunction %void
-    %v3float = OpTypeVector %float 3
-          %9 = OpTypeFunction %v3float
-    %float_1 = OpConstant %float 1
        %uint = OpTypeInt 32 0
      %v3uint = OpTypeVector %uint 3
+    %v3float = OpTypeVector %float 3
+          %9 = OpTypeFunction %v3uint %v3float
+%float_4_29496704e_09 = OpConstant %float 4.29496704e+09
+         %18 = OpConstantComposite %v3float %float_4_29496704e_09 %float_4_29496704e_09 %float_4_29496704e_09
+       %bool = OpTypeBool
+     %v3bool = OpTypeVector %bool 3
+         %23 = OpConstantNull %v3float
+         %25 = OpConstantNull %v3uint
+%uint_4294967295 = OpConstant %uint 4294967295
+         %28 = OpConstantComposite %v3uint %uint_4294967295 %uint_4294967295 %uint_4294967295
+         %29 = OpTypeFunction %v3float
+    %float_1 = OpConstant %float 1
 %_ptr_Function_v3uint = OpTypePointer Function %v3uint
-         %24 = OpConstantNull %v3uint
 %unused_entry_point = OpFunction %void None %5
           %8 = OpLabel
                OpReturn
                OpFunctionEnd
-          %m = OpFunction %v3float None %9
-         %12 = OpLabel
+  %tint_ftou = OpFunction %v3uint None %9
+          %v = OpFunctionParameter %v3float
+         %15 = OpLabel
+         %19 = OpFOrdLessThan %v3bool %v %18
+         %24 = OpFOrdLessThan %v3bool %v %23
+         %26 = OpConvertFToU %v3uint %v
+         %22 = OpSelect %v3uint %24 %25 %26
+         %16 = OpSelect %v3uint %19 %22 %28
+               OpReturnValue %16
+               OpFunctionEnd
+          %m = OpFunction %v3float None %29
+         %31 = OpLabel
                OpStore %t %float_1
-         %14 = OpLoad %float %t
-         %15 = OpCompositeConstruct %v3float %14 %14 %14
-               OpReturnValue %15
+         %33 = OpLoad %float %t
+         %34 = OpCompositeConstruct %v3float %33 %33 %33
+               OpReturnValue %34
                OpFunctionEnd
           %f = OpFunction %void None %5
-         %17 = OpLabel
-          %v = OpVariable %_ptr_Function_v3uint Function %24
-         %18 = OpFunctionCall %v3float %m
-         %19 = OpConvertFToU %v3uint %18
-               OpStore %v %19
+         %36 = OpLabel
+        %v_0 = OpVariable %_ptr_Function_v3uint Function %25
+         %37 = OpFunctionCall %v3float %m
+         %38 = OpFunctionCall %v3uint %tint_ftou %37
+               OpStore %v_0 %38
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/expressions/type_conv/vec3/var/f32-i32.wgsl.expected.dxc.hlsl b/test/tint/expressions/type_conv/vec3/var/f32-i32.wgsl.expected.dxc.hlsl
index cb31dc6..bb8d289 100644
--- a/test/tint/expressions/type_conv/vec3/var/f32-i32.wgsl.expected.dxc.hlsl
+++ b/test/tint/expressions/type_conv/vec3/var/f32-i32.wgsl.expected.dxc.hlsl
@@ -3,8 +3,12 @@
   return;
 }
 
+int3 tint_ftoi(float3 v) {
+  return ((v < (2147483520.0f).xxx) ? ((v < (-2147483648.0f).xxx) ? (-2147483648).xxx : int3(v)) : (2147483647).xxx);
+}
+
 static float3 u = (1.0f).xxx;
 
 void f() {
-  const int3 v = int3(u);
+  const int3 v = tint_ftoi(u);
 }
diff --git a/test/tint/expressions/type_conv/vec3/var/f32-i32.wgsl.expected.fxc.hlsl b/test/tint/expressions/type_conv/vec3/var/f32-i32.wgsl.expected.fxc.hlsl
index cb31dc6..bb8d289 100644
--- a/test/tint/expressions/type_conv/vec3/var/f32-i32.wgsl.expected.fxc.hlsl
+++ b/test/tint/expressions/type_conv/vec3/var/f32-i32.wgsl.expected.fxc.hlsl
@@ -3,8 +3,12 @@
   return;
 }
 
+int3 tint_ftoi(float3 v) {
+  return ((v < (2147483520.0f).xxx) ? ((v < (-2147483648.0f).xxx) ? (-2147483648).xxx : int3(v)) : (2147483647).xxx);
+}
+
 static float3 u = (1.0f).xxx;
 
 void f() {
-  const int3 v = int3(u);
+  const int3 v = tint_ftoi(u);
 }
diff --git a/test/tint/expressions/type_conv/vec3/var/f32-i32.wgsl.expected.glsl b/test/tint/expressions/type_conv/vec3/var/f32-i32.wgsl.expected.glsl
index 9387762..83cd400 100644
--- a/test/tint/expressions/type_conv/vec3/var/f32-i32.wgsl.expected.glsl
+++ b/test/tint/expressions/type_conv/vec3/var/f32-i32.wgsl.expected.glsl
@@ -1,11 +1,20 @@
 #version 310 es
 
+ivec3 tint_select(ivec3 param_0, ivec3 param_1, bvec3 param_2) {
+    return ivec3(param_2[0] ? param_1[0] : param_0[0], param_2[1] ? param_1[1] : param_0[1], param_2[2] ? param_1[2] : param_0[2]);
+}
+
+
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
 void unused_entry_point() {
   return;
 }
+ivec3 tint_ftoi(vec3 v) {
+  return tint_select(ivec3(2147483647), tint_select(ivec3(v), ivec3((-2147483647 - 1)), lessThan(v, vec3(-2147483648.0f))), lessThan(v, vec3(2147483520.0f)));
+}
+
 vec3 u = vec3(1.0f);
 void f() {
-  ivec3 v = ivec3(u);
+  ivec3 v = tint_ftoi(u);
 }
 
diff --git a/test/tint/expressions/type_conv/vec3/var/f32-i32.wgsl.expected.msl b/test/tint/expressions/type_conv/vec3/var/f32-i32.wgsl.expected.msl
index 26733a9..1a4621f 100644
--- a/test/tint/expressions/type_conv/vec3/var/f32-i32.wgsl.expected.msl
+++ b/test/tint/expressions/type_conv/vec3/var/f32-i32.wgsl.expected.msl
@@ -1,8 +1,12 @@
 #include <metal_stdlib>
 
 using namespace metal;
+int3 tint_ftoi(float3 v) {
+  return select(int3(2147483647), select(int3(v), int3((-2147483647 - 1)), (v < float3(-2147483648.0f))), (v < float3(2147483520.0f)));
+}
+
 void f() {
   thread float3 tint_symbol = float3(1.0f);
-  int3 const v = int3(tint_symbol);
+  int3 const v = tint_ftoi(tint_symbol);
 }
 
diff --git a/test/tint/expressions/type_conv/vec3/var/f32-i32.wgsl.expected.spvasm b/test/tint/expressions/type_conv/vec3/var/f32-i32.wgsl.expected.spvasm
index 5e130df..cb952f7 100644
--- a/test/tint/expressions/type_conv/vec3/var/f32-i32.wgsl.expected.spvasm
+++ b/test/tint/expressions/type_conv/vec3/var/f32-i32.wgsl.expected.spvasm
@@ -1,7 +1,7 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 17
+; Bound: 36
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
@@ -9,6 +9,8 @@
                OpExecutionMode %unused_entry_point LocalSize 1 1 1
                OpName %u "u"
                OpName %unused_entry_point "unused_entry_point"
+               OpName %tint_ftoi "tint_ftoi"
+               OpName %v "v"
                OpName %f "f"
       %float = OpTypeFloat 32
     %v3float = OpTypeVector %float 3
@@ -20,13 +22,34 @@
           %7 = OpTypeFunction %void
         %int = OpTypeInt 32 1
       %v3int = OpTypeVector %int 3
+         %11 = OpTypeFunction %v3int %v3float
+%float_2_14748352e_09 = OpConstant %float 2.14748352e+09
+         %19 = OpConstantComposite %v3float %float_2_14748352e_09 %float_2_14748352e_09 %float_2_14748352e_09
+       %bool = OpTypeBool
+     %v3bool = OpTypeVector %bool 3
+%float_n2_14748365e_09 = OpConstant %float -2.14748365e+09
+         %25 = OpConstantComposite %v3float %float_n2_14748365e_09 %float_n2_14748365e_09 %float_n2_14748365e_09
+%int_n2147483648 = OpConstant %int -2147483648
+         %28 = OpConstantComposite %v3int %int_n2147483648 %int_n2147483648 %int_n2147483648
+%int_2147483647 = OpConstant %int 2147483647
+         %31 = OpConstantComposite %v3int %int_2147483647 %int_2147483647 %int_2147483647
 %unused_entry_point = OpFunction %void None %7
          %10 = OpLabel
                OpReturn
                OpFunctionEnd
+  %tint_ftoi = OpFunction %v3int None %11
+          %v = OpFunctionParameter %v3float
+         %16 = OpLabel
+         %20 = OpFOrdLessThan %v3bool %v %19
+         %26 = OpFOrdLessThan %v3bool %v %25
+         %29 = OpConvertFToS %v3int %v
+         %23 = OpSelect %v3int %26 %28 %29
+         %17 = OpSelect %v3int %20 %23 %31
+               OpReturnValue %17
+               OpFunctionEnd
           %f = OpFunction %void None %7
-         %12 = OpLabel
-         %16 = OpLoad %v3float %u
-         %13 = OpConvertFToS %v3int %16
+         %33 = OpLabel
+         %35 = OpLoad %v3float %u
+         %34 = OpFunctionCall %v3int %tint_ftoi %35
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/expressions/type_conv/vec3/var/f32-u32.wgsl.expected.dxc.hlsl b/test/tint/expressions/type_conv/vec3/var/f32-u32.wgsl.expected.dxc.hlsl
index 0a43c89..3cd24a6 100644
--- a/test/tint/expressions/type_conv/vec3/var/f32-u32.wgsl.expected.dxc.hlsl
+++ b/test/tint/expressions/type_conv/vec3/var/f32-u32.wgsl.expected.dxc.hlsl
@@ -3,8 +3,12 @@
   return;
 }
 
+uint3 tint_ftou(float3 v) {
+  return ((v < (4294967040.0f).xxx) ? ((v < (0.0f).xxx) ? (0u).xxx : uint3(v)) : (4294967295u).xxx);
+}
+
 static float3 u = (1.0f).xxx;
 
 void f() {
-  const uint3 v = uint3(u);
+  const uint3 v = tint_ftou(u);
 }
diff --git a/test/tint/expressions/type_conv/vec3/var/f32-u32.wgsl.expected.fxc.hlsl b/test/tint/expressions/type_conv/vec3/var/f32-u32.wgsl.expected.fxc.hlsl
index 0a43c89..3cd24a6 100644
--- a/test/tint/expressions/type_conv/vec3/var/f32-u32.wgsl.expected.fxc.hlsl
+++ b/test/tint/expressions/type_conv/vec3/var/f32-u32.wgsl.expected.fxc.hlsl
@@ -3,8 +3,12 @@
   return;
 }
 
+uint3 tint_ftou(float3 v) {
+  return ((v < (4294967040.0f).xxx) ? ((v < (0.0f).xxx) ? (0u).xxx : uint3(v)) : (4294967295u).xxx);
+}
+
 static float3 u = (1.0f).xxx;
 
 void f() {
-  const uint3 v = uint3(u);
+  const uint3 v = tint_ftou(u);
 }
diff --git a/test/tint/expressions/type_conv/vec3/var/f32-u32.wgsl.expected.glsl b/test/tint/expressions/type_conv/vec3/var/f32-u32.wgsl.expected.glsl
index df8584b..7b3dee0 100644
--- a/test/tint/expressions/type_conv/vec3/var/f32-u32.wgsl.expected.glsl
+++ b/test/tint/expressions/type_conv/vec3/var/f32-u32.wgsl.expected.glsl
@@ -1,11 +1,20 @@
 #version 310 es
 
+uvec3 tint_select(uvec3 param_0, uvec3 param_1, bvec3 param_2) {
+    return uvec3(param_2[0] ? param_1[0] : param_0[0], param_2[1] ? param_1[1] : param_0[1], param_2[2] ? param_1[2] : param_0[2]);
+}
+
+
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
 void unused_entry_point() {
   return;
 }
+uvec3 tint_ftou(vec3 v) {
+  return tint_select(uvec3(4294967295u), tint_select(uvec3(v), uvec3(0u), lessThan(v, vec3(0.0f))), lessThan(v, vec3(4294967040.0f)));
+}
+
 vec3 u = vec3(1.0f);
 void f() {
-  uvec3 v = uvec3(u);
+  uvec3 v = tint_ftou(u);
 }
 
diff --git a/test/tint/expressions/type_conv/vec3/var/f32-u32.wgsl.expected.msl b/test/tint/expressions/type_conv/vec3/var/f32-u32.wgsl.expected.msl
index 0dfd1be..bf292cb 100644
--- a/test/tint/expressions/type_conv/vec3/var/f32-u32.wgsl.expected.msl
+++ b/test/tint/expressions/type_conv/vec3/var/f32-u32.wgsl.expected.msl
@@ -1,8 +1,12 @@
 #include <metal_stdlib>
 
 using namespace metal;
+uint3 tint_ftou(float3 v) {
+  return select(uint3(4294967295u), select(uint3(v), uint3(0u), (v < float3(0.0f))), (v < float3(4294967040.0f)));
+}
+
 void f() {
   thread float3 tint_symbol = float3(1.0f);
-  uint3 const v = uint3(tint_symbol);
+  uint3 const v = tint_ftou(tint_symbol);
 }
 
diff --git a/test/tint/expressions/type_conv/vec3/var/f32-u32.wgsl.expected.spvasm b/test/tint/expressions/type_conv/vec3/var/f32-u32.wgsl.expected.spvasm
index cd46d1e..6f11a77 100644
--- a/test/tint/expressions/type_conv/vec3/var/f32-u32.wgsl.expected.spvasm
+++ b/test/tint/expressions/type_conv/vec3/var/f32-u32.wgsl.expected.spvasm
@@ -1,7 +1,7 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 17
+; Bound: 34
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
@@ -9,6 +9,8 @@
                OpExecutionMode %unused_entry_point LocalSize 1 1 1
                OpName %u "u"
                OpName %unused_entry_point "unused_entry_point"
+               OpName %tint_ftou "tint_ftou"
+               OpName %v "v"
                OpName %f "f"
       %float = OpTypeFloat 32
     %v3float = OpTypeVector %float 3
@@ -20,13 +22,32 @@
           %7 = OpTypeFunction %void
        %uint = OpTypeInt 32 0
      %v3uint = OpTypeVector %uint 3
+         %11 = OpTypeFunction %v3uint %v3float
+%float_4_29496704e_09 = OpConstant %float 4.29496704e+09
+         %19 = OpConstantComposite %v3float %float_4_29496704e_09 %float_4_29496704e_09 %float_4_29496704e_09
+       %bool = OpTypeBool
+     %v3bool = OpTypeVector %bool 3
+         %24 = OpConstantNull %v3float
+         %26 = OpConstantNull %v3uint
+%uint_4294967295 = OpConstant %uint 4294967295
+         %29 = OpConstantComposite %v3uint %uint_4294967295 %uint_4294967295 %uint_4294967295
 %unused_entry_point = OpFunction %void None %7
          %10 = OpLabel
                OpReturn
                OpFunctionEnd
+  %tint_ftou = OpFunction %v3uint None %11
+          %v = OpFunctionParameter %v3float
+         %16 = OpLabel
+         %20 = OpFOrdLessThan %v3bool %v %19
+         %25 = OpFOrdLessThan %v3bool %v %24
+         %27 = OpConvertFToU %v3uint %v
+         %23 = OpSelect %v3uint %25 %26 %27
+         %17 = OpSelect %v3uint %20 %23 %29
+               OpReturnValue %17
+               OpFunctionEnd
           %f = OpFunction %void None %7
-         %12 = OpLabel
-         %16 = OpLoad %v3float %u
-         %13 = OpConvertFToU %v3uint %16
+         %31 = OpLabel
+         %33 = OpLoad %v3float %u
+         %32 = OpFunctionCall %v3uint %tint_ftou %33
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/expressions/type_conv/vec4/function/f32-i32.wgsl.expected.dxc.hlsl b/test/tint/expressions/type_conv/vec4/function/f32-i32.wgsl.expected.dxc.hlsl
index 2ee04df..60a89b8 100644
--- a/test/tint/expressions/type_conv/vec4/function/f32-i32.wgsl.expected.dxc.hlsl
+++ b/test/tint/expressions/type_conv/vec4/function/f32-i32.wgsl.expected.dxc.hlsl
@@ -3,6 +3,10 @@
   return;
 }
 
+int4 tint_ftoi(float4 v) {
+  return ((v < (2147483520.0f).xxxx) ? ((v < (-2147483648.0f).xxxx) ? (-2147483648).xxxx : int4(v)) : (2147483647).xxxx);
+}
+
 static float t = 0.0f;
 
 float4 m() {
@@ -12,5 +16,5 @@
 
 void f() {
   const float4 tint_symbol = m();
-  int4 v = int4(tint_symbol);
+  int4 v = tint_ftoi(tint_symbol);
 }
diff --git a/test/tint/expressions/type_conv/vec4/function/f32-i32.wgsl.expected.fxc.hlsl b/test/tint/expressions/type_conv/vec4/function/f32-i32.wgsl.expected.fxc.hlsl
index 2ee04df..60a89b8 100644
--- a/test/tint/expressions/type_conv/vec4/function/f32-i32.wgsl.expected.fxc.hlsl
+++ b/test/tint/expressions/type_conv/vec4/function/f32-i32.wgsl.expected.fxc.hlsl
@@ -3,6 +3,10 @@
   return;
 }
 
+int4 tint_ftoi(float4 v) {
+  return ((v < (2147483520.0f).xxxx) ? ((v < (-2147483648.0f).xxxx) ? (-2147483648).xxxx : int4(v)) : (2147483647).xxxx);
+}
+
 static float t = 0.0f;
 
 float4 m() {
@@ -12,5 +16,5 @@
 
 void f() {
   const float4 tint_symbol = m();
-  int4 v = int4(tint_symbol);
+  int4 v = tint_ftoi(tint_symbol);
 }
diff --git a/test/tint/expressions/type_conv/vec4/function/f32-i32.wgsl.expected.glsl b/test/tint/expressions/type_conv/vec4/function/f32-i32.wgsl.expected.glsl
index 7f69604..4dbbae9 100644
--- a/test/tint/expressions/type_conv/vec4/function/f32-i32.wgsl.expected.glsl
+++ b/test/tint/expressions/type_conv/vec4/function/f32-i32.wgsl.expected.glsl
@@ -1,9 +1,18 @@
 #version 310 es
 
+ivec4 tint_select(ivec4 param_0, ivec4 param_1, bvec4 param_2) {
+    return ivec4(param_2[0] ? param_1[0] : param_0[0], param_2[1] ? param_1[1] : param_0[1], param_2[2] ? param_1[2] : param_0[2], param_2[3] ? param_1[3] : param_0[3]);
+}
+
+
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
 void unused_entry_point() {
   return;
 }
+ivec4 tint_ftoi(vec4 v) {
+  return tint_select(ivec4(2147483647), tint_select(ivec4(v), ivec4((-2147483647 - 1)), lessThan(v, vec4(-2147483648.0f))), lessThan(v, vec4(2147483520.0f)));
+}
+
 float t = 0.0f;
 vec4 m() {
   t = 1.0f;
@@ -12,6 +21,6 @@
 
 void f() {
   vec4 tint_symbol = m();
-  ivec4 v = ivec4(tint_symbol);
+  ivec4 v = tint_ftoi(tint_symbol);
 }
 
diff --git a/test/tint/expressions/type_conv/vec4/function/f32-i32.wgsl.expected.msl b/test/tint/expressions/type_conv/vec4/function/f32-i32.wgsl.expected.msl
index e43ebcf..1f04e5e 100644
--- a/test/tint/expressions/type_conv/vec4/function/f32-i32.wgsl.expected.msl
+++ b/test/tint/expressions/type_conv/vec4/function/f32-i32.wgsl.expected.msl
@@ -1,6 +1,10 @@
 #include <metal_stdlib>
 
 using namespace metal;
+int4 tint_ftoi(float4 v) {
+  return select(int4(2147483647), select(int4(v), int4((-2147483647 - 1)), (v < float4(-2147483648.0f))), (v < float4(2147483520.0f)));
+}
+
 float4 m() {
   thread float tint_symbol_1 = 0.0f;
   tint_symbol_1 = 1.0f;
@@ -9,6 +13,6 @@
 
 void f() {
   float4 const tint_symbol = m();
-  int4 v = int4(tint_symbol);
+  int4 v = tint_ftoi(tint_symbol);
 }
 
diff --git a/test/tint/expressions/type_conv/vec4/function/f32-i32.wgsl.expected.spvasm b/test/tint/expressions/type_conv/vec4/function/f32-i32.wgsl.expected.spvasm
index 8fd4226..6043ff1 100644
--- a/test/tint/expressions/type_conv/vec4/function/f32-i32.wgsl.expected.spvasm
+++ b/test/tint/expressions/type_conv/vec4/function/f32-i32.wgsl.expected.spvasm
@@ -1,7 +1,7 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 25
+; Bound: 44
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
@@ -9,38 +9,61 @@
                OpExecutionMode %unused_entry_point LocalSize 1 1 1
                OpName %t "t"
                OpName %unused_entry_point "unused_entry_point"
+               OpName %tint_ftoi "tint_ftoi"
+               OpName %v "v"
                OpName %m "m"
                OpName %f "f"
-               OpName %v "v"
+               OpName %v_0 "v"
       %float = OpTypeFloat 32
 %_ptr_Private_float = OpTypePointer Private %float
           %4 = OpConstantNull %float
           %t = OpVariable %_ptr_Private_float Private %4
        %void = OpTypeVoid
           %5 = OpTypeFunction %void
-    %v4float = OpTypeVector %float 4
-          %9 = OpTypeFunction %v4float
-    %float_1 = OpConstant %float 1
         %int = OpTypeInt 32 1
       %v4int = OpTypeVector %int 4
+    %v4float = OpTypeVector %float 4
+          %9 = OpTypeFunction %v4int %v4float
+%float_2_14748352e_09 = OpConstant %float 2.14748352e+09
+         %18 = OpConstantComposite %v4float %float_2_14748352e_09 %float_2_14748352e_09 %float_2_14748352e_09 %float_2_14748352e_09
+       %bool = OpTypeBool
+     %v4bool = OpTypeVector %bool 4
+%float_n2_14748365e_09 = OpConstant %float -2.14748365e+09
+         %24 = OpConstantComposite %v4float %float_n2_14748365e_09 %float_n2_14748365e_09 %float_n2_14748365e_09 %float_n2_14748365e_09
+%int_n2147483648 = OpConstant %int -2147483648
+         %27 = OpConstantComposite %v4int %int_n2147483648 %int_n2147483648 %int_n2147483648 %int_n2147483648
+%int_2147483647 = OpConstant %int 2147483647
+         %30 = OpConstantComposite %v4int %int_2147483647 %int_2147483647 %int_2147483647 %int_2147483647
+         %31 = OpTypeFunction %v4float
+    %float_1 = OpConstant %float 1
 %_ptr_Function_v4int = OpTypePointer Function %v4int
-         %24 = OpConstantNull %v4int
+         %43 = OpConstantNull %v4int
 %unused_entry_point = OpFunction %void None %5
           %8 = OpLabel
                OpReturn
                OpFunctionEnd
-          %m = OpFunction %v4float None %9
-         %12 = OpLabel
+  %tint_ftoi = OpFunction %v4int None %9
+          %v = OpFunctionParameter %v4float
+         %15 = OpLabel
+         %19 = OpFOrdLessThan %v4bool %v %18
+         %25 = OpFOrdLessThan %v4bool %v %24
+         %28 = OpConvertFToS %v4int %v
+         %22 = OpSelect %v4int %25 %27 %28
+         %16 = OpSelect %v4int %19 %22 %30
+               OpReturnValue %16
+               OpFunctionEnd
+          %m = OpFunction %v4float None %31
+         %33 = OpLabel
                OpStore %t %float_1
-         %14 = OpLoad %float %t
-         %15 = OpCompositeConstruct %v4float %14 %14 %14 %14
-               OpReturnValue %15
+         %35 = OpLoad %float %t
+         %36 = OpCompositeConstruct %v4float %35 %35 %35 %35
+               OpReturnValue %36
                OpFunctionEnd
           %f = OpFunction %void None %5
-         %17 = OpLabel
-          %v = OpVariable %_ptr_Function_v4int Function %24
-         %18 = OpFunctionCall %v4float %m
-         %19 = OpConvertFToS %v4int %18
-               OpStore %v %19
+         %38 = OpLabel
+        %v_0 = OpVariable %_ptr_Function_v4int Function %43
+         %39 = OpFunctionCall %v4float %m
+         %40 = OpFunctionCall %v4int %tint_ftoi %39
+               OpStore %v_0 %40
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/expressions/type_conv/vec4/function/f32-u32.wgsl.expected.dxc.hlsl b/test/tint/expressions/type_conv/vec4/function/f32-u32.wgsl.expected.dxc.hlsl
index 8b64a91..4d6a26e 100644
--- a/test/tint/expressions/type_conv/vec4/function/f32-u32.wgsl.expected.dxc.hlsl
+++ b/test/tint/expressions/type_conv/vec4/function/f32-u32.wgsl.expected.dxc.hlsl
@@ -3,6 +3,10 @@
   return;
 }
 
+uint4 tint_ftou(float4 v) {
+  return ((v < (4294967040.0f).xxxx) ? ((v < (0.0f).xxxx) ? (0u).xxxx : uint4(v)) : (4294967295u).xxxx);
+}
+
 static float t = 0.0f;
 
 float4 m() {
@@ -12,5 +16,5 @@
 
 void f() {
   const float4 tint_symbol = m();
-  uint4 v = uint4(tint_symbol);
+  uint4 v = tint_ftou(tint_symbol);
 }
diff --git a/test/tint/expressions/type_conv/vec4/function/f32-u32.wgsl.expected.fxc.hlsl b/test/tint/expressions/type_conv/vec4/function/f32-u32.wgsl.expected.fxc.hlsl
index 8b64a91..4d6a26e 100644
--- a/test/tint/expressions/type_conv/vec4/function/f32-u32.wgsl.expected.fxc.hlsl
+++ b/test/tint/expressions/type_conv/vec4/function/f32-u32.wgsl.expected.fxc.hlsl
@@ -3,6 +3,10 @@
   return;
 }
 
+uint4 tint_ftou(float4 v) {
+  return ((v < (4294967040.0f).xxxx) ? ((v < (0.0f).xxxx) ? (0u).xxxx : uint4(v)) : (4294967295u).xxxx);
+}
+
 static float t = 0.0f;
 
 float4 m() {
@@ -12,5 +16,5 @@
 
 void f() {
   const float4 tint_symbol = m();
-  uint4 v = uint4(tint_symbol);
+  uint4 v = tint_ftou(tint_symbol);
 }
diff --git a/test/tint/expressions/type_conv/vec4/function/f32-u32.wgsl.expected.glsl b/test/tint/expressions/type_conv/vec4/function/f32-u32.wgsl.expected.glsl
index 59158b9..58174fb 100644
--- a/test/tint/expressions/type_conv/vec4/function/f32-u32.wgsl.expected.glsl
+++ b/test/tint/expressions/type_conv/vec4/function/f32-u32.wgsl.expected.glsl
@@ -1,9 +1,18 @@
 #version 310 es
 
+uvec4 tint_select(uvec4 param_0, uvec4 param_1, bvec4 param_2) {
+    return uvec4(param_2[0] ? param_1[0] : param_0[0], param_2[1] ? param_1[1] : param_0[1], param_2[2] ? param_1[2] : param_0[2], param_2[3] ? param_1[3] : param_0[3]);
+}
+
+
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
 void unused_entry_point() {
   return;
 }
+uvec4 tint_ftou(vec4 v) {
+  return tint_select(uvec4(4294967295u), tint_select(uvec4(v), uvec4(0u), lessThan(v, vec4(0.0f))), lessThan(v, vec4(4294967040.0f)));
+}
+
 float t = 0.0f;
 vec4 m() {
   t = 1.0f;
@@ -12,6 +21,6 @@
 
 void f() {
   vec4 tint_symbol = m();
-  uvec4 v = uvec4(tint_symbol);
+  uvec4 v = tint_ftou(tint_symbol);
 }
 
diff --git a/test/tint/expressions/type_conv/vec4/function/f32-u32.wgsl.expected.msl b/test/tint/expressions/type_conv/vec4/function/f32-u32.wgsl.expected.msl
index 5f87293..e0cad92 100644
--- a/test/tint/expressions/type_conv/vec4/function/f32-u32.wgsl.expected.msl
+++ b/test/tint/expressions/type_conv/vec4/function/f32-u32.wgsl.expected.msl
@@ -1,6 +1,10 @@
 #include <metal_stdlib>
 
 using namespace metal;
+uint4 tint_ftou(float4 v) {
+  return select(uint4(4294967295u), select(uint4(v), uint4(0u), (v < float4(0.0f))), (v < float4(4294967040.0f)));
+}
+
 float4 m() {
   thread float tint_symbol_1 = 0.0f;
   tint_symbol_1 = 1.0f;
@@ -9,6 +13,6 @@
 
 void f() {
   float4 const tint_symbol = m();
-  uint4 v = uint4(tint_symbol);
+  uint4 v = tint_ftou(tint_symbol);
 }
 
diff --git a/test/tint/expressions/type_conv/vec4/function/f32-u32.wgsl.expected.spvasm b/test/tint/expressions/type_conv/vec4/function/f32-u32.wgsl.expected.spvasm
index 8655677..6f62e94 100644
--- a/test/tint/expressions/type_conv/vec4/function/f32-u32.wgsl.expected.spvasm
+++ b/test/tint/expressions/type_conv/vec4/function/f32-u32.wgsl.expected.spvasm
@@ -1,7 +1,7 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 25
+; Bound: 41
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
@@ -9,38 +9,58 @@
                OpExecutionMode %unused_entry_point LocalSize 1 1 1
                OpName %t "t"
                OpName %unused_entry_point "unused_entry_point"
+               OpName %tint_ftou "tint_ftou"
+               OpName %v "v"
                OpName %m "m"
                OpName %f "f"
-               OpName %v "v"
+               OpName %v_0 "v"
       %float = OpTypeFloat 32
 %_ptr_Private_float = OpTypePointer Private %float
           %4 = OpConstantNull %float
           %t = OpVariable %_ptr_Private_float Private %4
        %void = OpTypeVoid
           %5 = OpTypeFunction %void
-    %v4float = OpTypeVector %float 4
-          %9 = OpTypeFunction %v4float
-    %float_1 = OpConstant %float 1
        %uint = OpTypeInt 32 0
      %v4uint = OpTypeVector %uint 4
+    %v4float = OpTypeVector %float 4
+          %9 = OpTypeFunction %v4uint %v4float
+%float_4_29496704e_09 = OpConstant %float 4.29496704e+09
+         %18 = OpConstantComposite %v4float %float_4_29496704e_09 %float_4_29496704e_09 %float_4_29496704e_09 %float_4_29496704e_09
+       %bool = OpTypeBool
+     %v4bool = OpTypeVector %bool 4
+         %23 = OpConstantNull %v4float
+         %25 = OpConstantNull %v4uint
+%uint_4294967295 = OpConstant %uint 4294967295
+         %28 = OpConstantComposite %v4uint %uint_4294967295 %uint_4294967295 %uint_4294967295 %uint_4294967295
+         %29 = OpTypeFunction %v4float
+    %float_1 = OpConstant %float 1
 %_ptr_Function_v4uint = OpTypePointer Function %v4uint
-         %24 = OpConstantNull %v4uint
 %unused_entry_point = OpFunction %void None %5
           %8 = OpLabel
                OpReturn
                OpFunctionEnd
-          %m = OpFunction %v4float None %9
-         %12 = OpLabel
+  %tint_ftou = OpFunction %v4uint None %9
+          %v = OpFunctionParameter %v4float
+         %15 = OpLabel
+         %19 = OpFOrdLessThan %v4bool %v %18
+         %24 = OpFOrdLessThan %v4bool %v %23
+         %26 = OpConvertFToU %v4uint %v
+         %22 = OpSelect %v4uint %24 %25 %26
+         %16 = OpSelect %v4uint %19 %22 %28
+               OpReturnValue %16
+               OpFunctionEnd
+          %m = OpFunction %v4float None %29
+         %31 = OpLabel
                OpStore %t %float_1
-         %14 = OpLoad %float %t
-         %15 = OpCompositeConstruct %v4float %14 %14 %14 %14
-               OpReturnValue %15
+         %33 = OpLoad %float %t
+         %34 = OpCompositeConstruct %v4float %33 %33 %33 %33
+               OpReturnValue %34
                OpFunctionEnd
           %f = OpFunction %void None %5
-         %17 = OpLabel
-          %v = OpVariable %_ptr_Function_v4uint Function %24
-         %18 = OpFunctionCall %v4float %m
-         %19 = OpConvertFToU %v4uint %18
-               OpStore %v %19
+         %36 = OpLabel
+        %v_0 = OpVariable %_ptr_Function_v4uint Function %25
+         %37 = OpFunctionCall %v4float %m
+         %38 = OpFunctionCall %v4uint %tint_ftou %37
+               OpStore %v_0 %38
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/expressions/type_conv/vec4/var/f32-i32.wgsl.expected.dxc.hlsl b/test/tint/expressions/type_conv/vec4/var/f32-i32.wgsl.expected.dxc.hlsl
index 18aa48a..401b25f 100644
--- a/test/tint/expressions/type_conv/vec4/var/f32-i32.wgsl.expected.dxc.hlsl
+++ b/test/tint/expressions/type_conv/vec4/var/f32-i32.wgsl.expected.dxc.hlsl
@@ -3,8 +3,12 @@
   return;
 }
 
+int4 tint_ftoi(float4 v) {
+  return ((v < (2147483520.0f).xxxx) ? ((v < (-2147483648.0f).xxxx) ? (-2147483648).xxxx : int4(v)) : (2147483647).xxxx);
+}
+
 static float4 u = (1.0f).xxxx;
 
 void f() {
-  const int4 v = int4(u);
+  const int4 v = tint_ftoi(u);
 }
diff --git a/test/tint/expressions/type_conv/vec4/var/f32-i32.wgsl.expected.fxc.hlsl b/test/tint/expressions/type_conv/vec4/var/f32-i32.wgsl.expected.fxc.hlsl
index 18aa48a..401b25f 100644
--- a/test/tint/expressions/type_conv/vec4/var/f32-i32.wgsl.expected.fxc.hlsl
+++ b/test/tint/expressions/type_conv/vec4/var/f32-i32.wgsl.expected.fxc.hlsl
@@ -3,8 +3,12 @@
   return;
 }
 
+int4 tint_ftoi(float4 v) {
+  return ((v < (2147483520.0f).xxxx) ? ((v < (-2147483648.0f).xxxx) ? (-2147483648).xxxx : int4(v)) : (2147483647).xxxx);
+}
+
 static float4 u = (1.0f).xxxx;
 
 void f() {
-  const int4 v = int4(u);
+  const int4 v = tint_ftoi(u);
 }
diff --git a/test/tint/expressions/type_conv/vec4/var/f32-i32.wgsl.expected.glsl b/test/tint/expressions/type_conv/vec4/var/f32-i32.wgsl.expected.glsl
index 8d1d35c..5aae484 100644
--- a/test/tint/expressions/type_conv/vec4/var/f32-i32.wgsl.expected.glsl
+++ b/test/tint/expressions/type_conv/vec4/var/f32-i32.wgsl.expected.glsl
@@ -1,11 +1,20 @@
 #version 310 es
 
+ivec4 tint_select(ivec4 param_0, ivec4 param_1, bvec4 param_2) {
+    return ivec4(param_2[0] ? param_1[0] : param_0[0], param_2[1] ? param_1[1] : param_0[1], param_2[2] ? param_1[2] : param_0[2], param_2[3] ? param_1[3] : param_0[3]);
+}
+
+
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
 void unused_entry_point() {
   return;
 }
+ivec4 tint_ftoi(vec4 v) {
+  return tint_select(ivec4(2147483647), tint_select(ivec4(v), ivec4((-2147483647 - 1)), lessThan(v, vec4(-2147483648.0f))), lessThan(v, vec4(2147483520.0f)));
+}
+
 vec4 u = vec4(1.0f);
 void f() {
-  ivec4 v = ivec4(u);
+  ivec4 v = tint_ftoi(u);
 }
 
diff --git a/test/tint/expressions/type_conv/vec4/var/f32-i32.wgsl.expected.msl b/test/tint/expressions/type_conv/vec4/var/f32-i32.wgsl.expected.msl
index 297888b..f9824a4 100644
--- a/test/tint/expressions/type_conv/vec4/var/f32-i32.wgsl.expected.msl
+++ b/test/tint/expressions/type_conv/vec4/var/f32-i32.wgsl.expected.msl
@@ -1,8 +1,12 @@
 #include <metal_stdlib>
 
 using namespace metal;
+int4 tint_ftoi(float4 v) {
+  return select(int4(2147483647), select(int4(v), int4((-2147483647 - 1)), (v < float4(-2147483648.0f))), (v < float4(2147483520.0f)));
+}
+
 void f() {
   thread float4 tint_symbol = float4(1.0f);
-  int4 const v = int4(tint_symbol);
+  int4 const v = tint_ftoi(tint_symbol);
 }
 
diff --git a/test/tint/expressions/type_conv/vec4/var/f32-i32.wgsl.expected.spvasm b/test/tint/expressions/type_conv/vec4/var/f32-i32.wgsl.expected.spvasm
index 9a3607a..426b65e 100644
--- a/test/tint/expressions/type_conv/vec4/var/f32-i32.wgsl.expected.spvasm
+++ b/test/tint/expressions/type_conv/vec4/var/f32-i32.wgsl.expected.spvasm
@@ -1,7 +1,7 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 17
+; Bound: 36
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
@@ -9,6 +9,8 @@
                OpExecutionMode %unused_entry_point LocalSize 1 1 1
                OpName %u "u"
                OpName %unused_entry_point "unused_entry_point"
+               OpName %tint_ftoi "tint_ftoi"
+               OpName %v "v"
                OpName %f "f"
       %float = OpTypeFloat 32
     %v4float = OpTypeVector %float 4
@@ -20,13 +22,34 @@
           %7 = OpTypeFunction %void
         %int = OpTypeInt 32 1
       %v4int = OpTypeVector %int 4
+         %11 = OpTypeFunction %v4int %v4float
+%float_2_14748352e_09 = OpConstant %float 2.14748352e+09
+         %19 = OpConstantComposite %v4float %float_2_14748352e_09 %float_2_14748352e_09 %float_2_14748352e_09 %float_2_14748352e_09
+       %bool = OpTypeBool
+     %v4bool = OpTypeVector %bool 4
+%float_n2_14748365e_09 = OpConstant %float -2.14748365e+09
+         %25 = OpConstantComposite %v4float %float_n2_14748365e_09 %float_n2_14748365e_09 %float_n2_14748365e_09 %float_n2_14748365e_09
+%int_n2147483648 = OpConstant %int -2147483648
+         %28 = OpConstantComposite %v4int %int_n2147483648 %int_n2147483648 %int_n2147483648 %int_n2147483648
+%int_2147483647 = OpConstant %int 2147483647
+         %31 = OpConstantComposite %v4int %int_2147483647 %int_2147483647 %int_2147483647 %int_2147483647
 %unused_entry_point = OpFunction %void None %7
          %10 = OpLabel
                OpReturn
                OpFunctionEnd
+  %tint_ftoi = OpFunction %v4int None %11
+          %v = OpFunctionParameter %v4float
+         %16 = OpLabel
+         %20 = OpFOrdLessThan %v4bool %v %19
+         %26 = OpFOrdLessThan %v4bool %v %25
+         %29 = OpConvertFToS %v4int %v
+         %23 = OpSelect %v4int %26 %28 %29
+         %17 = OpSelect %v4int %20 %23 %31
+               OpReturnValue %17
+               OpFunctionEnd
           %f = OpFunction %void None %7
-         %12 = OpLabel
-         %16 = OpLoad %v4float %u
-         %13 = OpConvertFToS %v4int %16
+         %33 = OpLabel
+         %35 = OpLoad %v4float %u
+         %34 = OpFunctionCall %v4int %tint_ftoi %35
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/expressions/type_conv/vec4/var/f32-u32.wgsl.expected.dxc.hlsl b/test/tint/expressions/type_conv/vec4/var/f32-u32.wgsl.expected.dxc.hlsl
index f69250f..4fa5b72 100644
--- a/test/tint/expressions/type_conv/vec4/var/f32-u32.wgsl.expected.dxc.hlsl
+++ b/test/tint/expressions/type_conv/vec4/var/f32-u32.wgsl.expected.dxc.hlsl
@@ -3,8 +3,12 @@
   return;
 }
 
+uint4 tint_ftou(float4 v) {
+  return ((v < (4294967040.0f).xxxx) ? ((v < (0.0f).xxxx) ? (0u).xxxx : uint4(v)) : (4294967295u).xxxx);
+}
+
 static float4 u = (1.0f).xxxx;
 
 void f() {
-  const uint4 v = uint4(u);
+  const uint4 v = tint_ftou(u);
 }
diff --git a/test/tint/expressions/type_conv/vec4/var/f32-u32.wgsl.expected.fxc.hlsl b/test/tint/expressions/type_conv/vec4/var/f32-u32.wgsl.expected.fxc.hlsl
index f69250f..4fa5b72 100644
--- a/test/tint/expressions/type_conv/vec4/var/f32-u32.wgsl.expected.fxc.hlsl
+++ b/test/tint/expressions/type_conv/vec4/var/f32-u32.wgsl.expected.fxc.hlsl
@@ -3,8 +3,12 @@
   return;
 }
 
+uint4 tint_ftou(float4 v) {
+  return ((v < (4294967040.0f).xxxx) ? ((v < (0.0f).xxxx) ? (0u).xxxx : uint4(v)) : (4294967295u).xxxx);
+}
+
 static float4 u = (1.0f).xxxx;
 
 void f() {
-  const uint4 v = uint4(u);
+  const uint4 v = tint_ftou(u);
 }
diff --git a/test/tint/expressions/type_conv/vec4/var/f32-u32.wgsl.expected.glsl b/test/tint/expressions/type_conv/vec4/var/f32-u32.wgsl.expected.glsl
index 3dc90b6..983c0b9 100644
--- a/test/tint/expressions/type_conv/vec4/var/f32-u32.wgsl.expected.glsl
+++ b/test/tint/expressions/type_conv/vec4/var/f32-u32.wgsl.expected.glsl
@@ -1,11 +1,20 @@
 #version 310 es
 
+uvec4 tint_select(uvec4 param_0, uvec4 param_1, bvec4 param_2) {
+    return uvec4(param_2[0] ? param_1[0] : param_0[0], param_2[1] ? param_1[1] : param_0[1], param_2[2] ? param_1[2] : param_0[2], param_2[3] ? param_1[3] : param_0[3]);
+}
+
+
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
 void unused_entry_point() {
   return;
 }
+uvec4 tint_ftou(vec4 v) {
+  return tint_select(uvec4(4294967295u), tint_select(uvec4(v), uvec4(0u), lessThan(v, vec4(0.0f))), lessThan(v, vec4(4294967040.0f)));
+}
+
 vec4 u = vec4(1.0f);
 void f() {
-  uvec4 v = uvec4(u);
+  uvec4 v = tint_ftou(u);
 }
 
diff --git a/test/tint/expressions/type_conv/vec4/var/f32-u32.wgsl.expected.msl b/test/tint/expressions/type_conv/vec4/var/f32-u32.wgsl.expected.msl
index ed3bb12..8586cef 100644
--- a/test/tint/expressions/type_conv/vec4/var/f32-u32.wgsl.expected.msl
+++ b/test/tint/expressions/type_conv/vec4/var/f32-u32.wgsl.expected.msl
@@ -1,8 +1,12 @@
 #include <metal_stdlib>
 
 using namespace metal;
+uint4 tint_ftou(float4 v) {
+  return select(uint4(4294967295u), select(uint4(v), uint4(0u), (v < float4(0.0f))), (v < float4(4294967040.0f)));
+}
+
 void f() {
   thread float4 tint_symbol = float4(1.0f);
-  uint4 const v = uint4(tint_symbol);
+  uint4 const v = tint_ftou(tint_symbol);
 }
 
diff --git a/test/tint/expressions/type_conv/vec4/var/f32-u32.wgsl.expected.spvasm b/test/tint/expressions/type_conv/vec4/var/f32-u32.wgsl.expected.spvasm
index 3916cbd..f5c2a40 100644
--- a/test/tint/expressions/type_conv/vec4/var/f32-u32.wgsl.expected.spvasm
+++ b/test/tint/expressions/type_conv/vec4/var/f32-u32.wgsl.expected.spvasm
@@ -1,7 +1,7 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 17
+; Bound: 34
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
@@ -9,6 +9,8 @@
                OpExecutionMode %unused_entry_point LocalSize 1 1 1
                OpName %u "u"
                OpName %unused_entry_point "unused_entry_point"
+               OpName %tint_ftou "tint_ftou"
+               OpName %v "v"
                OpName %f "f"
       %float = OpTypeFloat 32
     %v4float = OpTypeVector %float 4
@@ -20,13 +22,32 @@
           %7 = OpTypeFunction %void
        %uint = OpTypeInt 32 0
      %v4uint = OpTypeVector %uint 4
+         %11 = OpTypeFunction %v4uint %v4float
+%float_4_29496704e_09 = OpConstant %float 4.29496704e+09
+         %19 = OpConstantComposite %v4float %float_4_29496704e_09 %float_4_29496704e_09 %float_4_29496704e_09 %float_4_29496704e_09
+       %bool = OpTypeBool
+     %v4bool = OpTypeVector %bool 4
+         %24 = OpConstantNull %v4float
+         %26 = OpConstantNull %v4uint
+%uint_4294967295 = OpConstant %uint 4294967295
+         %29 = OpConstantComposite %v4uint %uint_4294967295 %uint_4294967295 %uint_4294967295 %uint_4294967295
 %unused_entry_point = OpFunction %void None %7
          %10 = OpLabel
                OpReturn
                OpFunctionEnd
+  %tint_ftou = OpFunction %v4uint None %11
+          %v = OpFunctionParameter %v4float
+         %16 = OpLabel
+         %20 = OpFOrdLessThan %v4bool %v %19
+         %25 = OpFOrdLessThan %v4bool %v %24
+         %27 = OpConvertFToU %v4uint %v
+         %23 = OpSelect %v4uint %25 %26 %27
+         %17 = OpSelect %v4uint %20 %23 %29
+               OpReturnValue %17
+               OpFunctionEnd
           %f = OpFunction %void None %7
-         %12 = OpLabel
-         %16 = OpLoad %v4float %u
-         %13 = OpConvertFToU %v4uint %16
+         %31 = OpLabel
+         %33 = OpLoad %v4float %u
+         %32 = OpFunctionCall %v4uint %tint_ftou %33
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/statements/discard/atomic_in_for_loop_continuing.wgsl.expected.dxc.hlsl b/test/tint/statements/discard/atomic_in_for_loop_continuing.wgsl.expected.dxc.hlsl
index abd1ed8..d03ef94 100644
--- a/test/tint/statements/discard/atomic_in_for_loop_continuing.wgsl.expected.dxc.hlsl
+++ b/test/tint/statements/discard/atomic_in_for_loop_continuing.wgsl.expected.dxc.hlsl
@@ -1,4 +1,9 @@
 static bool tint_discarded = false;
+
+int tint_ftoi(float v) {
+  return ((v < 2147483520.0f) ? ((v < -2147483648.0f) ? -2147483648 : int(v)) : 2147483647);
+}
+
 Texture2D<float4> t : register(t0, space0);
 SamplerState s : register(s1, space0);
 RWByteAddressBuffer a : register(u2, space0);
@@ -22,7 +27,7 @@
   if ((tint_symbol == 0.0f)) {
     tint_discarded = true;
   }
-  int result = int(t.Sample(s, coord).x);
+  int result = tint_ftoi(t.Sample(s, coord).x);
   {
     int i = 0;
     while (true) {
diff --git a/test/tint/statements/discard/atomic_in_for_loop_continuing.wgsl.expected.fxc.hlsl b/test/tint/statements/discard/atomic_in_for_loop_continuing.wgsl.expected.fxc.hlsl
index abd1ed8..d03ef94 100644
--- a/test/tint/statements/discard/atomic_in_for_loop_continuing.wgsl.expected.fxc.hlsl
+++ b/test/tint/statements/discard/atomic_in_for_loop_continuing.wgsl.expected.fxc.hlsl
@@ -1,4 +1,9 @@
 static bool tint_discarded = false;
+
+int tint_ftoi(float v) {
+  return ((v < 2147483520.0f) ? ((v < -2147483648.0f) ? -2147483648 : int(v)) : 2147483647);
+}
+
 Texture2D<float4> t : register(t0, space0);
 SamplerState s : register(s1, space0);
 RWByteAddressBuffer a : register(u2, space0);
@@ -22,7 +27,7 @@
   if ((tint_symbol == 0.0f)) {
     tint_discarded = true;
   }
-  int result = int(t.Sample(s, coord).x);
+  int result = tint_ftoi(t.Sample(s, coord).x);
   {
     int i = 0;
     while (true) {
diff --git a/test/tint/statements/discard/atomic_in_for_loop_continuing.wgsl.expected.glsl b/test/tint/statements/discard/atomic_in_for_loop_continuing.wgsl.expected.glsl
index ad8f111..514f72a9 100644
--- a/test/tint/statements/discard/atomic_in_for_loop_continuing.wgsl.expected.glsl
+++ b/test/tint/statements/discard/atomic_in_for_loop_continuing.wgsl.expected.glsl
@@ -5,6 +5,10 @@
 layout(location = 0) in float tint_symbol_1;
 layout(location = 1) in vec2 coord_1;
 layout(location = 0) out int value;
+int tint_ftoi(float v) {
+  return ((v < 2147483520.0f) ? ((v < -2147483648.0f) ? (-2147483647 - 1) : int(v)) : 2147483647);
+}
+
 layout(binding = 2, std430) buffer a_block_ssbo {
   int inner;
 } a;
@@ -15,7 +19,7 @@
   if ((tint_symbol == 0.0f)) {
     tint_discarded = true;
   }
-  int result = int(texture(t_s, coord).x);
+  int result = tint_ftoi(texture(t_s, coord).x);
   {
     int i = 0;
     while (true) {
diff --git a/test/tint/statements/discard/atomic_in_for_loop_continuing.wgsl.expected.msl b/test/tint/statements/discard/atomic_in_for_loop_continuing.wgsl.expected.msl
index 1da2b90..73ffeac 100644
--- a/test/tint/statements/discard/atomic_in_for_loop_continuing.wgsl.expected.msl
+++ b/test/tint/statements/discard/atomic_in_for_loop_continuing.wgsl.expected.msl
@@ -1,6 +1,10 @@
 #include <metal_stdlib>
 
 using namespace metal;
+int tint_ftoi(float v) {
+  return select(2147483647, select(int(v), (-2147483647 - 1), (v < -2147483648.0f)), (v < 2147483520.0f));
+}
+
 struct tint_symbol_1 {
   float in [[user(locn0)]];
   float2 coord [[user(locn1)]];
@@ -14,7 +18,7 @@
   if ((in == 0.0f)) {
     *(tint_symbol_4) = true;
   }
-  int result = int(tint_symbol_5.sample(tint_symbol_6, coord)[0]);
+  int result = tint_ftoi(tint_symbol_5.sample(tint_symbol_6, coord)[0]);
   {
     int i = 0;
     while (true) {
diff --git a/test/tint/statements/discard/atomic_in_for_loop_continuing.wgsl.expected.spvasm b/test/tint/statements/discard/atomic_in_for_loop_continuing.wgsl.expected.spvasm
index c482728..7aca938 100644
--- a/test/tint/statements/discard/atomic_in_for_loop_continuing.wgsl.expected.spvasm
+++ b/test/tint/statements/discard/atomic_in_for_loop_continuing.wgsl.expected.spvasm
@@ -1,7 +1,7 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 83
+; Bound: 96
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
@@ -16,6 +16,8 @@
                OpName %a_block "a_block"
                OpMemberName %a_block 0 "inner"
                OpName %a "a"
+               OpName %tint_ftoi "tint_ftoi"
+               OpName %v "v"
                OpName %foo_inner "foo_inner"
                OpName %in "in"
                OpName %coord "coord"
@@ -57,11 +59,16 @@
     %a_block = OpTypeStruct %int
 %_ptr_StorageBuffer_a_block = OpTypePointer StorageBuffer %a_block
           %a = OpVariable %_ptr_StorageBuffer_a_block StorageBuffer
-         %24 = OpTypeFunction %int %float %v2float
-         %29 = OpConstantNull %float
+         %24 = OpTypeFunction %int %float
+%float_2_14748352e_09 = OpConstant %float 2.14748352e+09
+%float_n2_14748365e_09 = OpConstant %float -2.14748365e+09
+%int_n2147483648 = OpConstant %int -2147483648
+%int_2147483647 = OpConstant %int 2147483647
+         %37 = OpTypeFunction %int %float %v2float
+         %42 = OpConstantNull %float
        %true = OpConstantTrue %bool
     %v4float = OpTypeVector %float 4
-         %39 = OpTypeSampledImage %17
+         %52 = OpTypeSampledImage %17
 %_ptr_Function_int = OpTypePointer Function %int
      %int_10 = OpConstant %int 10
        %uint = OpTypeInt 32 0
@@ -70,76 +77,86 @@
 %_ptr_StorageBuffer_int = OpTypePointer StorageBuffer %int
       %int_1 = OpConstant %int 1
        %void = OpTypeVoid
-         %73 = OpTypeFunction %void
-  %foo_inner = OpFunction %int None %24
+         %86 = OpTypeFunction %void
+  %tint_ftoi = OpFunction %int None %24
+          %v = OpFunctionParameter %float
+         %27 = OpLabel
+         %30 = OpFOrdLessThan %bool %v %float_2_14748352e_09
+         %33 = OpFOrdLessThan %bool %v %float_n2_14748365e_09
+         %35 = OpConvertFToS %int %v
+         %31 = OpSelect %int %33 %int_n2147483648 %35
+         %28 = OpSelect %int %30 %31 %int_2147483647
+               OpReturnValue %28
+               OpFunctionEnd
+  %foo_inner = OpFunction %int None %37
          %in = OpFunctionParameter %float
       %coord = OpFunctionParameter %v2float
-         %28 = OpLabel
+         %41 = OpLabel
      %result = OpVariable %_ptr_Function_int Function %14
           %i = OpVariable %_ptr_Function_int Function %14
 %tint_symbol = OpVariable %_ptr_Function_int Function %14
-         %30 = OpFOrdEqual %bool %in %29
-               OpSelectionMerge %31 None
-               OpBranchConditional %30 %32 %31
-         %32 = OpLabel
-               OpStore %tint_discarded %true
-               OpBranch %31
-         %31 = OpLabel
-         %37 = OpLoad %20 %s
-         %38 = OpLoad %17 %t
-         %40 = OpSampledImage %39 %38 %37
-         %35 = OpImageSampleImplicitLod %v4float %40 %coord
-         %41 = OpCompositeExtract %float %35 0
-         %34 = OpConvertFToS %int %41
-               OpStore %result %34
-               OpStore %i %14
-               OpBranch %45
+         %43 = OpFOrdEqual %bool %in %42
+               OpSelectionMerge %44 None
+               OpBranchConditional %43 %45 %44
          %45 = OpLabel
-               OpLoopMerge %46 %47 None
-               OpBranch %48
-         %48 = OpLabel
-         %50 = OpLoad %int %i
-         %52 = OpSLessThan %bool %50 %int_10
-         %49 = OpLogicalNot %bool %52
-               OpSelectionMerge %53 None
-               OpBranchConditional %49 %54 %53
-         %54 = OpLabel
-               OpBranch %46
-         %53 = OpLabel
-         %55 = OpLoad %int %result
-         %56 = OpLoad %int %i
-         %57 = OpIAdd %int %55 %56
-               OpStore %result %57
-               OpBranch %47
-         %47 = OpLabel
-         %60 = OpLoad %bool %tint_discarded
-         %59 = OpLogicalNot %bool %60
-               OpSelectionMerge %61 None
-               OpBranchConditional %59 %62 %61
-         %62 = OpLabel
-         %69 = OpAccessChain %_ptr_StorageBuffer_int %a %uint_0
-         %63 = OpAtomicIAdd %int %69 %uint_1 %uint_0 %int_1
-               OpStore %tint_symbol %63
+               OpStore %tint_discarded %true
+               OpBranch %44
+         %44 = OpLabel
+         %50 = OpLoad %20 %s
+         %51 = OpLoad %17 %t
+         %53 = OpSampledImage %52 %51 %50
+         %48 = OpImageSampleImplicitLod %v4float %53 %coord
+         %54 = OpCompositeExtract %float %48 0
+         %47 = OpFunctionCall %int %tint_ftoi %54
+               OpStore %result %47
+               OpStore %i %14
+               OpBranch %58
+         %58 = OpLabel
+               OpLoopMerge %59 %60 None
                OpBranch %61
          %61 = OpLabel
-         %71 = OpLoad %int %tint_symbol
-               OpStore %i %71
-               OpBranch %45
-         %46 = OpLabel
-         %72 = OpLoad %int %result
-               OpReturnValue %72
+         %63 = OpLoad %int %i
+         %65 = OpSLessThan %bool %63 %int_10
+         %62 = OpLogicalNot %bool %65
+               OpSelectionMerge %66 None
+               OpBranchConditional %62 %67 %66
+         %67 = OpLabel
+               OpBranch %59
+         %66 = OpLabel
+         %68 = OpLoad %int %result
+         %69 = OpLoad %int %i
+         %70 = OpIAdd %int %68 %69
+               OpStore %result %70
+               OpBranch %60
+         %60 = OpLabel
+         %73 = OpLoad %bool %tint_discarded
+         %72 = OpLogicalNot %bool %73
+               OpSelectionMerge %74 None
+               OpBranchConditional %72 %75 %74
+         %75 = OpLabel
+         %82 = OpAccessChain %_ptr_StorageBuffer_int %a %uint_0
+         %76 = OpAtomicIAdd %int %82 %uint_1 %uint_0 %int_1
+               OpStore %tint_symbol %76
+               OpBranch %74
+         %74 = OpLabel
+         %84 = OpLoad %int %tint_symbol
+               OpStore %i %84
+               OpBranch %58
+         %59 = OpLabel
+         %85 = OpLoad %int %result
+               OpReturnValue %85
                OpFunctionEnd
-        %foo = OpFunction %void None %73
-         %76 = OpLabel
-         %78 = OpLoad %float %in_1
-         %79 = OpLoad %v2float %coord_1
-         %77 = OpFunctionCall %int %foo_inner %78 %79
-               OpStore %value %77
-         %80 = OpLoad %bool %tint_discarded
-               OpSelectionMerge %81 None
-               OpBranchConditional %80 %82 %81
-         %82 = OpLabel
+        %foo = OpFunction %void None %86
+         %89 = OpLabel
+         %91 = OpLoad %float %in_1
+         %92 = OpLoad %v2float %coord_1
+         %90 = OpFunctionCall %int %foo_inner %91 %92
+               OpStore %value %90
+         %93 = OpLoad %bool %tint_discarded
+               OpSelectionMerge %94 None
+               OpBranchConditional %93 %95 %94
+         %95 = OpLabel
                OpKill
-         %81 = OpLabel
+         %94 = OpLabel
                OpReturn
                OpFunctionEnd