tint: make const eval of binary ops on concrete values fail on NaN/Inf

With this CL, binary ops add, subtract, multiply, and divide of concrete
values will now produce an error if the result is inf/NaN, as it was
doing with abstract values. This also affects the cross builtin, which
is written in terms of subtract and multiply.

Bug: tint:1581
Bug: tint:1747
Change-Id: Ib1d0d8deddc82c67ab53729a6011937636fcc1a5
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/110163
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
diff --git a/src/tint/resolver/builtin_test.cc b/src/tint/resolver/builtin_test.cc
index 3f2ca57..0de2411 100644
--- a/src/tint/resolver/builtin_test.cc
+++ b/src/tint/resolver/builtin_test.cc
@@ -375,7 +375,7 @@
 TEST_P(ResolverBuiltinTest_FloatBuiltin_IdenticalType, ThreeParams_Scalar_f32) {
     auto param = GetParam();
 
-    auto* call = Call(param.name, 1_f, 1_f, 1_f);
+    auto* call = Call(param.name, 0_f, 1_f, 2_f);
     WrapInFunction(call);
 
     if (param.args_number == 3u) {
@@ -396,8 +396,8 @@
 TEST_P(ResolverBuiltinTest_FloatBuiltin_IdenticalType, ThreeParams_Vector_f32) {
     auto param = GetParam();
 
-    auto* call = Call(param.name, vec3<f32>(1_f, 1_f, 3_f), vec3<f32>(1_f, 1_f, 3_f),
-                      vec3<f32>(1_f, 1_f, 3_f));
+    auto* call = Call(param.name, vec3<f32>(0_f, 0_f, 0_f), vec3<f32>(1_f, 1_f, 1_f),
+                      vec3<f32>(2_f, 2_f, 2_f));
     WrapInFunction(call);
 
     if (param.args_number == 3u) {
@@ -577,7 +577,7 @@
 
     Enable(ast::Extension::kF16);
 
-    auto* call = Call(param.name, 1_h, 1_h, 1_h);
+    auto* call = Call(param.name, 0_h, 1_h, 2_h);
     WrapInFunction(call);
 
     if (param.args_number == 3u) {
@@ -600,8 +600,8 @@
 
     Enable(ast::Extension::kF16);
 
-    auto* call = Call(param.name, vec3<f16>(1_h, 1_h, 3_h), vec3<f16>(1_h, 1_h, 3_h),
-                      vec3<f16>(1_h, 1_h, 3_h));
+    auto* call = Call(param.name, vec3<f16>(0_h, 0_h, 0_h), vec3<f16>(1_h, 1_h, 1_h),
+                      vec3<f16>(2_h, 2_h, 2_h));
     WrapInFunction(call);
 
     if (param.args_number == 3u) {
diff --git a/src/tint/resolver/builtins_validation_test.cc b/src/tint/resolver/builtins_validation_test.cc
index 7190ef1..675ff49 100644
--- a/src/tint/resolver/builtins_validation_test.cc
+++ b/src/tint/resolver/builtins_validation_test.cc
@@ -1099,7 +1099,7 @@
 
     utils::Vector<const ast::Expression*, 8> params;
     for (uint32_t i = 0; i < num_params; ++i) {
-        params.Push(Expr(1_f));
+        params.Push(Expr(f32(i)));
     }
     auto* builtin = Call(name, params);
     Func("func", utils::Empty, ty.void_(),
@@ -1120,7 +1120,7 @@
 
     utils::Vector<const ast::Expression*, 8> params;
     for (uint32_t i = 0; i < num_params; ++i) {
-        params.Push(vec2<f32>(1_f, 1_f));
+        params.Push(vec2<f32>(f32(i), f32(i)));
     }
     auto* builtin = Call(name, params);
     Func("func", utils::Empty, ty.void_(),
@@ -1141,7 +1141,7 @@
 
     utils::Vector<const ast::Expression*, 8> params;
     for (uint32_t i = 0; i < num_params; ++i) {
-        params.Push(vec3<f32>(1_f, 1_f, 1_f));
+        params.Push(vec3<f32>(f32(i), f32(i), f32(i)));
     }
     auto* builtin = Call(name, params);
     Func("func", utils::Empty, ty.void_(),
@@ -1162,7 +1162,7 @@
 
     utils::Vector<const ast::Expression*, 8> params;
     for (uint32_t i = 0; i < num_params; ++i) {
-        params.Push(vec4<f32>(1_f, 1_f, 1_f, 1_f));
+        params.Push(vec4<f32>(f32(i), f32(i), f32(i), f32(i)));
     }
     auto* builtin = Call(name, params);
     Func("func", utils::Empty, ty.void_(),
diff --git a/src/tint/resolver/const_eval.cc b/src/tint/resolver/const_eval.cc
index 6400798..daa66e5 100644
--- a/src/tint/resolver/const_eval.cc
+++ b/src/tint/resolver/const_eval.cc
@@ -655,8 +655,7 @@
 template <typename NumberT>
 utils::Result<NumberT> ConstEval::Add(NumberT a, NumberT b) {
     NumberT result;
-    if constexpr (IsAbstract<NumberT>) {
-        // Check for over/underflow for abstract values
+    if constexpr (IsAbstract<NumberT> || IsFloatingPoint<NumberT>) {
         if (auto r = CheckedAdd(a, b)) {
             result = r->value;
         } else {
@@ -682,8 +681,7 @@
 template <typename NumberT>
 utils::Result<NumberT> ConstEval::Sub(NumberT a, NumberT b) {
     NumberT result;
-    if constexpr (IsAbstract<NumberT>) {
-        // Check for over/underflow for abstract values
+    if constexpr (IsAbstract<NumberT> || IsFloatingPoint<NumberT>) {
         if (auto r = CheckedSub(a, b)) {
             result = r->value;
         } else {
@@ -710,7 +708,7 @@
 utils::Result<NumberT> ConstEval::Mul(NumberT a, NumberT b) {
     using T = UnwrapNumber<NumberT>;
     NumberT result;
-    if constexpr (IsAbstract<NumberT>) {
+    if constexpr (IsAbstract<NumberT> || IsFloatingPoint<NumberT>) {
         // Check for over/underflow for abstract values
         if (auto r = CheckedMul(a, b)) {
             result = r->value;
@@ -736,7 +734,7 @@
 template <typename NumberT>
 utils::Result<NumberT> ConstEval::Div(NumberT a, NumberT b) {
     NumberT result;
-    if constexpr (IsAbstract<NumberT>) {
+    if constexpr (IsAbstract<NumberT> || IsFloatingPoint<NumberT>) {
         // Check for over/underflow for abstract values
         if (auto r = CheckedDiv(a, b)) {
             result = r->value;
@@ -1922,8 +1920,6 @@
     auto* v1 = v->Index(1);
     auto* v2 = v->Index(2);
 
-    // auto x = Dispatch_fa_f32_f16(ab_minus_cd_func(elem_ty), u->Index(1), v->Index(2),
-    //                              v->Index(1), u->Index(2));
     auto x = Dispatch_fa_f32_f16(Det2Func(elem_ty), u1, u2, v1, v2);
     if (!x) {
         return utils::Failure;
diff --git a/src/tint/resolver/const_eval_binary_op_test.cc b/src/tint/resolver/const_eval_binary_op_test.cc
index 35c5c2e..bbca0d5 100644
--- a/src/tint/resolver/const_eval_binary_op_test.cc
+++ b/src/tint/resolver/const_eval_binary_op_test.cc
@@ -144,46 +144,41 @@
         C(T::Highest(), Negate(T{1}), T{T::Highest() - 1}),
         C(T::Lowest(), T::Highest(), Negate(T{1})),
     };
-    ConcatIntoIf<!IsAbstract<T>>(  //
-        r, std::vector<Case>{
-               C(T::Highest(), T{1}, T::Lowest()),
-               C(T::Lowest(), Negate(T{1}), T::Highest()),
-           });
+    if constexpr (IsAbstract<T>) {
+        auto error_msg = [](auto a, auto b) {
+            return "12:34 error: " + OverflowErrorMessage(a, "+", b);
+        };
+        ConcatInto(  //
+            r, std::vector<Case>{
+                   E(T::Highest(), T{1}, error_msg(T::Highest(), T{1})),
+                   E(T::Lowest(), Negate(T{1}), error_msg(T::Lowest(), Negate(T{1}))),
+               });
+    } else {
+        ConcatInto(  //
+            r, std::vector<Case>{
+                   C(T::Highest(), T{1}, T::Lowest()),
+                   C(T::Lowest(), Negate(T{1}), T::Highest()),
+               });
+    }
 
-    auto error_msg = [](auto a, auto b) {
-        return "12:34 error: " + OverflowErrorMessage(a, "+", b);
-    };
-    ConcatIntoIf<IsAbstract<T>>(  //
-        r, std::vector<Case>{
-               E(T::Highest(), T{1}, error_msg(T::Highest(), T{1})),
-               E(T::Lowest(), Negate(T{1}), error_msg(T::Lowest(), Negate(T{1}))),
-           });
     return r;
 }
 template <typename T>
 std::vector<Case> OpAddFloatCases() {
     static_assert(IsFloatingPoint<T>);
-    auto r = std::vector<Case>{
+    auto error_msg = [](auto a, auto b) {
+        return "12:34 error: " + OverflowErrorMessage(a, "+", b);
+    };
+    return std::vector<Case>{
         C(T{0}, T{0}, T{0}),
         C(T{1}, T{2}, T{3}),
         C(T::Lowest(), T{1}, T{T::Lowest() + 1}),
         C(T::Highest(), Negate(T{1}), T{T::Highest() - 1}),
         C(T::Lowest(), T::Highest(), T{0}),
+
+        E(T::Highest(), T::Highest(), error_msg(T::Highest(), T::Highest())),
+        E(T::Lowest(), Negate(T::Highest()), error_msg(T::Lowest(), Negate(T::Highest()))),
     };
-    ConcatIntoIf<!IsAbstract<T>>(  //
-        r, std::vector<Case>{
-               C(T::Highest(), T::Highest(), T::Inf()),
-               C(T::Lowest(), Negate(T::Highest()), -T::Inf()),
-           });
-    auto error_msg = [](auto a, auto b) {
-        return "12:34 error: " + OverflowErrorMessage(a, "+", b);
-    };
-    ConcatIntoIf<IsAbstract<T>>(  //
-        r, std::vector<Case>{
-               E(T::Highest(), T::Highest(), error_msg(T::Highest(), T::Highest())),
-               E(T::Lowest(), Negate(T::Highest()), error_msg(T::Lowest(), Negate(T::Highest()))),
-           });
-    return r;
 }
 INSTANTIATE_TEST_SUITE_P(Add,
                          ResolverConstEvalBinaryOpTest,
@@ -206,45 +201,40 @@
         C(T{T::Highest() - 1}, Negate(T{1}), T::Highest()),
         C(Negate(T{1}), T::Highest(), T::Lowest()),
     };
-    ConcatIntoIf<!IsAbstract<T>>(  //
-        r, std::vector<Case>{
-               C(T::Lowest(), T{1}, T::Highest()),
-               C(T::Highest(), Negate(T{1}), T::Lowest()),
-           });
-    auto error_msg = [](auto a, auto b) {
-        return "12:34 error: " + OverflowErrorMessage(a, "-", b);
-    };
-    ConcatIntoIf<IsAbstract<T>>(  //
-        r, std::vector<Case>{
-               E(T::Lowest(), T{1}, error_msg(T::Lowest(), T{1})),
-               E(T::Highest(), Negate(T{1}), error_msg(T::Highest(), Negate(T{1}))),
-           });
+    if constexpr (IsAbstract<T>) {
+        auto error_msg = [](auto a, auto b) {
+            return "12:34 error: " + OverflowErrorMessage(a, "-", b);
+        };
+        ConcatInto(  //
+            r, std::vector<Case>{
+                   E(T::Lowest(), T{1}, error_msg(T::Lowest(), T{1})),
+                   E(T::Highest(), Negate(T{1}), error_msg(T::Highest(), Negate(T{1}))),
+               });
+    } else {
+        ConcatInto(  //
+            r, std::vector<Case>{
+                   C(T::Lowest(), T{1}, T::Highest()),
+                   C(T::Highest(), Negate(T{1}), T::Lowest()),
+               });
+    }
     return r;
 }
 template <typename T>
 std::vector<Case> OpSubFloatCases() {
     static_assert(IsFloatingPoint<T>);
-    auto r = std::vector<Case>{
+    auto error_msg = [](auto a, auto b) {
+        return "12:34 error: " + OverflowErrorMessage(a, "-", b);
+    };
+    return std::vector<Case>{
         C(T{0}, T{0}, T{0}),
         C(T{3}, T{2}, T{1}),
         C(T::Highest(), T{1}, T{T::Highest() - 1}),
         C(T::Lowest(), Negate(T{1}), T{T::Lowest() + 1}),
         C(T{0}, T::Highest(), T::Lowest()),
+
+        E(T::Highest(), Negate(T::Highest()), error_msg(T::Highest(), Negate(T::Highest()))),
+        E(T::Lowest(), T::Highest(), error_msg(T::Lowest(), T::Highest())),
     };
-    ConcatIntoIf<!IsAbstract<T>>(  //
-        r, std::vector<Case>{
-               C(T::Highest(), Negate(T::Highest()), T::Inf()),
-               C(T::Lowest(), T::Highest(), -T::Inf()),
-           });
-    auto error_msg = [](auto a, auto b) {
-        return "12:34 error: " + OverflowErrorMessage(a, "-", b);
-    };
-    ConcatIntoIf<IsAbstract<T>>(  //
-        r, std::vector<Case>{
-               E(T::Highest(), Negate(T::Highest()), error_msg(T::Highest(), Negate(T::Highest()))),
-               E(T::Lowest(), T::Highest(), error_msg(T::Lowest(), T::Highest())),
-           });
-    return r;
 }
 INSTANTIATE_TEST_SUITE_P(Sub,
                          ResolverConstEvalBinaryOpTest,
@@ -267,21 +257,25 @@
         C(T::Highest(), T{1}, T::Highest()),
         C(T::Lowest(), T{1}, T::Lowest()),
     };
-    ConcatIntoIf<!IsAbstract<T>>(  //
-        r, std::vector<Case>{
-               C(T::Highest(), T::Highest(), Mul(T::Highest(), T::Highest())),
-               C(T::Lowest(), T::Lowest(), Mul(T::Lowest(), T::Lowest())),
-           });
-    auto error_msg = [](auto a, auto b) {
-        return "12:34 error: " + OverflowErrorMessage(a, "*", b);
-    };
-    ConcatIntoIf<IsAbstract<T>>(  //
-        r, std::vector<Case>{
-               E(T::Highest(), T::Highest(), error_msg(T::Highest(), T::Highest())),
-               E(T::Lowest(), T::Lowest(), error_msg(T::Lowest(), T::Lowest())),
-               E(T::Highest(), T{2}, error_msg(T::Highest(), T{2})),
-               E(T::Lowest(), Negate(T{2}), error_msg(T::Lowest(), Negate(T{2}))),
-           });
+    if constexpr (IsAbstract<T> || IsFloatingPoint<T>) {
+        auto error_msg = [](auto a, auto b) {
+            return "12:34 error: " + OverflowErrorMessage(a, "*", b);
+        };
+        ConcatInto(  //
+            r, std::vector<Case>{
+                   // Fail if result is +/-inf
+                   E(T::Highest(), T::Highest(), error_msg(T::Highest(), T::Highest())),
+                   E(T::Lowest(), T::Lowest(), error_msg(T::Lowest(), T::Lowest())),
+                   E(T::Highest(), T{2}, error_msg(T::Highest(), T{2})),
+                   E(T::Lowest(), Negate(T{2}), error_msg(T::Lowest(), Negate(T{2}))),
+               });
+    } else {
+        ConcatInto(  //
+            r, std::vector<Case>{
+                   C(T::Highest(), T::Highest(), Mul(T::Highest(), T::Highest())),
+                   C(T::Lowest(), T::Lowest(), Mul(T::Lowest(), T::Lowest())),
+               });
+    }
     return r;
 }
 
@@ -295,14 +289,24 @@
         // vec3 * vec3 = vec3
         C(Vec(T{1.25}, T{2.25}, T{3.25}), Vec(T{2.0}, T{2.0}, T{2.0}), Vec(T{2.5}, T{4.5}, T{6.5})),
     };
-    auto error_msg = [](auto a, auto b) {
-        return "12:34 error: " + OverflowErrorMessage(a, "*", b);
-    };
-    ConcatIntoIf<IsAbstract<T>>(  //
-        r, std::vector<Case>{
-               E(Val(T::Highest()), Vec(T{2}, T{1}), error_msg(T::Highest(), T{2})),
-               E(Val(T::Lowest()), Vec(Negate(T{2}), T{1}), error_msg(T::Lowest(), Negate(T{2}))),
-           });
+    if constexpr (IsAbstract<T> || IsFloatingPoint<T>) {
+        auto error_msg = [](auto a, auto b) {
+            return "12:34 error: " + OverflowErrorMessage(a, "*", b);
+        };
+        ConcatInto(  //
+            r,
+            std::vector<Case>{
+                // Fail if result is +/-inf
+                E(Val(T::Highest()), Vec(T{2}, T{1}), error_msg(T::Highest(), T{2})),
+                E(Val(T::Lowest()), Vec(Negate(T{2}), T{1}), error_msg(T::Lowest(), Negate(T{2}))),
+            });
+    } else {
+        ConcatInto(  //
+            r, std::vector<Case>{
+                   C(Val(T::Highest()), Vec(T{2}, T{1}), Vec(T{-2}, T::Highest())),
+                   C(Val(T::Lowest()), Vec(Negate(T{2}), T{1}), Vec(T{0}, T{T::Lowest()})),
+               });
+    }
     return r;
 }
 
@@ -347,7 +351,7 @@
     auto error_msg = [](auto a, const char* op, auto b) {
         return "12:34 error: " + OverflowErrorMessage(a, op, b);
     };
-    ConcatIntoIf<IsAbstract<T>>(  //
+    ConcatIntoIf<IsAbstract<T> || IsFloatingPoint<T>>(  //
         r, std::vector<Case>{
                // vector-matrix multiply
 
@@ -389,10 +393,10 @@
                // Overflow from second multiplication of dot product of lhs row 0 and rhs column 0
                // i.e. m1[0][0] * m2[0][0] + m1[0][1] * m[1][0]
                //                                     ^
-               E(Mat({T{1.0}, T::Highest()},  //
-                     {T{1.0}, T{1.0}}),       //
-                 Mat({T{1.0}, T{1.0}},        //
-                     {T{2.0}, T{1.0}}),       //
+               E(Mat({T{1.0}, T{1.0}},         //
+                     {T::Highest(), T{1.0}}),  //
+                 Mat({T{1.0}, T{2.0}},         //
+                     {T{1.0}, T{1.0}}),        //
                  error_msg(T::Highest(), "*", T{2.0})),
 
                // Overflow from addition of dot product of lhs row 0 and rhs column 0
@@ -453,11 +457,23 @@
                // e1, when e1 is the most negative value in T, and e2 is -1.
                C(T::Smallest(), T{-1}, T::Smallest()),
            });
+
+    auto error_msg = [](auto a, auto b) {
+        return "12:34 error: " + OverflowErrorMessage(a, "/", b);
+    };
+    ConcatIntoIf<IsAbstract<T>>(  //
+        r, std::vector<Case>{
+               // Most negative value divided by -1
+               E(AInt::Lowest(), -1_a, error_msg(AInt::Lowest(), -1_a)),
+           });
     return r;
 }
 
 template <typename T>
 std::vector<Case> OpDivFloatCases() {
+    auto error_msg = [](auto a, auto b) {
+        return "12:34 error: " + OverflowErrorMessage(a, "/", b);
+    };
     std::vector<Case> r = {
         C(Val(T{0}), Val(T{1}), Val(T{0})),
         C(Val(T{1}), Val(T{1}), Val(T{1})),
@@ -469,32 +485,13 @@
         C(Val(T::Highest()), Val(T::Highest()), Val(T{1})),
         C(Val(T{0}), Val(T::Highest()), Val(T{0})),
         C(Val(T{0}), Val(T::Lowest()), Val(-T{0})),
-    };
-    ConcatIntoIf<!IsAbstract<T>>(  //
-        r, std::vector<Case>{
-               C(T{123}, T{0}, T::Inf()),
-               C(T{-123}, -T{0}, T::Inf()),
-               C(T{-123}, T{0}, -T::Inf()),
-               C(T{123}, -T{0}, -T::Inf()),
-           });
-    auto error_msg = [](auto a, auto b) {
-        return "12:34 error: " + OverflowErrorMessage(a, "/", b);
-    };
-    ConcatIntoIf<IsAbstract<T>>(  //
-        r, std::vector<Case>{
-               // Divide by zero
-               E(T{123}, T{0}, error_msg(T{123}, T{0})),
-               E(Negate(T{123}), Negate(T{0}), error_msg(Negate(T{123}), Negate(T{0}))),
-               E(Negate(T{123}), T{0}, error_msg(Negate(T{123}), T{0})),
-               E(T{123}, Negate(T{0}), error_msg(T{123}, Negate(T{0}))),
-           });
 
-    ConcatIntoIf<std::is_same_v<T, AInt>>(  //
-        r, std::vector<Case>{
-               // Most negative value divided by -1
-               E(AInt::Lowest(), -1_a, error_msg(AInt::Lowest(), -1_a)),
-           });
-
+        // Divide by zero
+        E(T{123}, T{0}, error_msg(T{123}, T{0})),
+        E(Negate(T{123}), Negate(T{0}), error_msg(Negate(T{123}), Negate(T{0}))),
+        E(Negate(T{123}), T{0}, error_msg(Negate(T{123}), T{0})),
+        E(T{123}, Negate(T{0}), error_msg(T{123}, Negate(T{0}))),
+    };
     return r;
 }
 INSTANTIATE_TEST_SUITE_P(Div,
diff --git a/src/tint/resolver/const_eval_builtin_test.cc b/src/tint/resolver/const_eval_builtin_test.cc
index a7a43ae..c7ae431 100644
--- a/src/tint/resolver/const_eval_builtin_test.cc
+++ b/src/tint/resolver/const_eval_builtin_test.cc
@@ -848,7 +848,7 @@
                      testing::ValuesIn(Concat(CountOneBitsCases<i32>(),  //
                                               CountOneBitsCases<u32>()))));
 
-template <typename T, bool finite_only>
+template <typename T>
 std::vector<Case> CrossCases() {
     constexpr auto vec_x = [](T v) { return Vec(T(v), T(0), T(0)); };
     constexpr auto vec_y = [](T v) { return Vec(T(0), T(v), T(0)); };
@@ -870,12 +870,6 @@
     const auto lowest_x = vec_x(T::Lowest());
     const auto lowest_y = vec_y(T::Lowest());
     const auto lowest_z = vec_z(T::Lowest());
-    const auto inf_x = vec_x(T::Inf());
-    const auto inf_y = vec_y(T::Inf());
-    const auto inf_z = vec_z(T::Inf());
-    const auto neg_inf_x = vec_x(-T::Inf());
-    const auto neg_inf_y = vec_y(-T::Inf());
-    const auto neg_inf_z = vec_z(-T::Inf());
 
     std::vector<Case> r = {
         C({zero, zero}, zero),
@@ -924,28 +918,11 @@
           Vec(T(-10.75), T(-6.75), T(11.75))),
     };
 
-    ConcatIntoIf<!finite_only>(  //
-        r, std::vector<Case>{
-               C({highest_x, highest_y}, inf_z).PosOrNeg(),  //
-               C({highest_y, highest_x}, inf_z).PosOrNeg(),  //
-               C({highest_z, highest_x}, inf_y).PosOrNeg(),  //
-               C({highest_x, highest_z}, inf_y).PosOrNeg(),  //
-               C({highest_y, highest_z}, inf_x).PosOrNeg(),  //
-               C({highest_z, highest_y}, inf_x).PosOrNeg(),  //
-               C({lowest_x, lowest_y}, inf_z).PosOrNeg(),    //
-               C({lowest_y, lowest_x}, inf_z).PosOrNeg(),    //
-               C({lowest_z, lowest_x}, inf_y).PosOrNeg(),    //
-               C({lowest_x, lowest_z}, inf_y).PosOrNeg(),    //
-               C({lowest_y, lowest_z}, inf_x).PosOrNeg(),    //
-               C({lowest_z, lowest_y}, inf_x).PosOrNeg(),
-           });
-
     std::string pos_error_msg =
         "12:34 error: " + OverflowErrorMessage(T::Highest(), "*", T::Highest());
     std::string neg_error_msg =
         "12:34 error: " + OverflowErrorMessage(T::Lowest(), "*", T::Lowest());
-
-    ConcatIntoIf<finite_only>(  //
+    ConcatInto(  //
         r, std::vector<Case>{
                E({highest_x, highest_y}, pos_error_msg),
                E({highest_y, highest_x}, pos_error_msg),
@@ -967,10 +944,10 @@
     Cross,
     ResolverConstEvalBuiltinTest,
     testing::Combine(testing::Values(sem::BuiltinType::kCross),
-                     testing::ValuesIn(Concat(CrossCases<AFloat, true>(),  //
-                                              CrossCases<f32, false>(),
-                                              CrossCases<f32, false>(),  //
-                                              CrossCases<f16, false>()))));
+                     testing::ValuesIn(Concat(CrossCases<AFloat>(),  //
+                                              CrossCases<f32>(),
+                                              CrossCases<f32>(),  //
+                                              CrossCases<f16>()))));
 
 template <typename T>
 std::vector<Case> FirstLeadingBitCases() {
diff --git a/src/tint/resolver/materialize_test.cc b/src/tint/resolver/materialize_test.cc
index 510f4e7..a2084a4 100644
--- a/src/tint/resolver/materialize_test.cc
+++ b/src/tint/resolver/materialize_test.cc
@@ -352,9 +352,11 @@
             Structure("S", utils::Vector{Member("v", target_ty())});
             WrapInFunction(Construct(ty.type_name("S"), abstract_expr));
             break;
-        case Method::kBinaryOp:
-            WrapInFunction(Add(target_expr(), abstract_expr));
-            break;
+        case Method::kBinaryOp: {
+            // Add 0 to ensure no overflow with max float values
+            auto binary_target_expr = data.target_expr(*this, 0);
+            WrapInFunction(Add(binary_target_expr, abstract_expr));
+        } break;
         case Method::kSwitchCond:
             WrapInFunction(
                 Switch(abstract_expr,                                                       //
diff --git a/test/tint/unittest/reader/spirv/Samples_SpvParserHandleTest_RegisterHandleUsage_SampledImage_Variable_6.spvasm b/test/tint/unittest/reader/spirv/Samples_SpvParserHandleTest_RegisterHandleUsage_SampledImage_Variable_6.spvasm
index 96ec325..7d65fe4 100644
--- a/test/tint/unittest/reader/spirv/Samples_SpvParserHandleTest_RegisterHandleUsage_SampledImage_Variable_6.spvasm
+++ b/test/tint/unittest/reader/spirv/Samples_SpvParserHandleTest_RegisterHandleUsage_SampledImage_Variable_6.spvasm
@@ -146,7 +146,7 @@
 %128 = OpLoad %50 %10
 %129 = OpLoad %52 %20
 %130 = OpSampledImage %124 %129 %128
-%131 = OpImageSampleProjImplicitLod %v4float %130 %126
+%131 = OpImageSampleProjImplicitLod %v4float %130 %47
 OpReturn
 OpFunctionEnd
 
diff --git a/test/tint/unittest/reader/spirv/Samples_SpvParserHandleTest_RegisterHandleUsage_SampledImage_Variable_7.spvasm b/test/tint/unittest/reader/spirv/Samples_SpvParserHandleTest_RegisterHandleUsage_SampledImage_Variable_7.spvasm
index 0bfff9e..18faafa 100644
--- a/test/tint/unittest/reader/spirv/Samples_SpvParserHandleTest_RegisterHandleUsage_SampledImage_Variable_7.spvasm
+++ b/test/tint/unittest/reader/spirv/Samples_SpvParserHandleTest_RegisterHandleUsage_SampledImage_Variable_7.spvasm
@@ -146,7 +146,7 @@
 %128 = OpLoad %50 %10
 %129 = OpLoad %52 %20
 %130 = OpSampledImage %124 %129 %128
-%131 = OpImageSampleProjExplicitLod %v4float %130 %126 Lod %29
+%131 = OpImageSampleProjExplicitLod %v4float %130 %47 Lod %29
 OpReturn
 OpFunctionEnd
 
diff --git a/test/tint/unittest/reader/spirv/Samples_SpvParserHandleTest_RegisterHandleUsage_SampledImage_Variable_8.spvasm b/test/tint/unittest/reader/spirv/Samples_SpvParserHandleTest_RegisterHandleUsage_SampledImage_Variable_8.spvasm
index 90ad772..0227815 100644
--- a/test/tint/unittest/reader/spirv/Samples_SpvParserHandleTest_RegisterHandleUsage_SampledImage_Variable_8.spvasm
+++ b/test/tint/unittest/reader/spirv/Samples_SpvParserHandleTest_RegisterHandleUsage_SampledImage_Variable_8.spvasm
@@ -146,7 +146,7 @@
 %128 = OpLoad %50 %10
 %129 = OpLoad %52 %20
 %130 = OpSampledImage %124 %129 %128
-%131 = OpImageSampleProjDrefImplicitLod %float %130 %126 %float_0_200000003
+%131 = OpImageSampleProjDrefImplicitLod %float %130 %47 %float_0_200000003
 OpReturn
 OpFunctionEnd
 
diff --git a/test/tint/unittest/reader/spirv/Samples_SpvParserHandleTest_RegisterHandleUsage_SampledImage_Variable_9.spvasm b/test/tint/unittest/reader/spirv/Samples_SpvParserHandleTest_RegisterHandleUsage_SampledImage_Variable_9.spvasm
index 5e594ce..fd6d3ac 100644
--- a/test/tint/unittest/reader/spirv/Samples_SpvParserHandleTest_RegisterHandleUsage_SampledImage_Variable_9.spvasm
+++ b/test/tint/unittest/reader/spirv/Samples_SpvParserHandleTest_RegisterHandleUsage_SampledImage_Variable_9.spvasm
@@ -146,7 +146,7 @@
 %128 = OpLoad %50 %10
 %129 = OpLoad %52 %20
 %130 = OpSampledImage %124 %129 %128
-%131 = OpImageSampleProjDrefExplicitLod %float %130 %126 %float_0_200000003 Lod %29
+%131 = OpImageSampleProjDrefExplicitLod %float %130 %47 %float_0_200000003 Lod %29
 OpReturn
 OpFunctionEnd
 
diff --git a/test/tint/vk-gl-cts/graphicsfuzz/cov-apfloat-mod-zero/0-opt.spvasm b/test/tint/vk-gl-cts/graphicsfuzz/cov-apfloat-mod-zero/0-opt.spvasm
index 995d851..60da431 100644
--- a/test/tint/vk-gl-cts/graphicsfuzz/cov-apfloat-mod-zero/0-opt.spvasm
+++ b/test/tint/vk-gl-cts/graphicsfuzz/cov-apfloat-mod-zero/0-opt.spvasm
@@ -63,7 +63,7 @@
        %main = OpFunction %void None %21
          %39 = OpLabel
   %undefined = OpVariable %_ptr_Function_float Function
-         %40 = OpFMod %float %float_5 %float_0
+         %40 = OpFMod %float %float_5 %float_5
                OpStore %undefined %40
          %41 = OpAccessChain %_ptr_Uniform_int %_ %int_0 %int_0
          %10 = OpLoad %int %41
diff --git a/test/tint/vk-gl-cts/graphicsfuzz/cov-apfloat-mod-zero/0-opt.wgsl b/test/tint/vk-gl-cts/graphicsfuzz/cov-apfloat-mod-zero/0-opt.wgsl
index 13c0255..b5592ba 100644
--- a/test/tint/vk-gl-cts/graphicsfuzz/cov-apfloat-mod-zero/0-opt.wgsl
+++ b/test/tint/vk-gl-cts/graphicsfuzz/cov-apfloat-mod-zero/0-opt.wgsl
@@ -30,7 +30,7 @@
   var undefined : f32;
   var x_51 : bool;
   var x_52_phi : bool;
-  undefined = (5.0 - (0.0 * floor((5.0 / 0.0f))));
+  undefined = (5.0 - (0.0 * floor((5.0 / 5.0f))));
   let x_10 : i32 = x_6.x_GLF_uniform_int_values[0].el;
   let x_11 : i32 = x_6.x_GLF_uniform_int_values[0].el;
   let x_12 : i32 = x_6.x_GLF_uniform_int_values[1].el;
diff --git a/webgpu-cts/expectations.txt b/webgpu-cts/expectations.txt
index d5a621c..5c78f20 100644
--- a/webgpu-cts/expectations.txt
+++ b/webgpu-cts/expectations.txt
@@ -500,6 +500,14 @@
 crbug.com/tint/1755 [ win10 ] webgpu:shader,execution,expression,call,builtin,pack4x8unorm:pack:inputSource="const" [ Failure ]
 
 ################################################################################
+# Const-eval functions that fail on inf/nan inputs
+# KEEP
+################################################################################
+crbug.com/tint/1581 webgpu:shader,execution,expression,binary,f32_arithmetic:division:inputSource="const";* [ Failure ]
+crbug.com/tint/1581 [ win ] webgpu:shader,execution,expression,call,builtin,cross:f32:inputSource="const" [ Failure ]
+crbug.com/tint/1581 [ linux ] webgpu:shader,execution,expression,call,builtin,cross:f32:inputSource="const" [ Failure ]
+
+################################################################################
 # untriaged failures
 # KEEP
 ################################################################################