tint/const-eval: Fix runtime semantics for (x % 0)

The result of integer mod is defined to be zero when the RHS is zero
and for (MOST_NEGATIVE / -1). Floating point is expected to be
implementation defined, so also return zero in this case.

Change-Id: Ic25250d637ccb93ba62a5fc0bcebe670d5cd4e3b
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/121544
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: James Price <jrprice@google.com>
Reviewed-by: Antonio Maiorano <amaiorano@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
Auto-Submit: James Price <jrprice@google.com>
diff --git a/src/tint/resolver/const_eval.cc b/src/tint/resolver/const_eval.cc
index dc59ccd..e516732 100644
--- a/src/tint/resolver/const_eval.cc
+++ b/src/tint/resolver/const_eval.cc
@@ -714,7 +714,7 @@
         } else {
             AddError(OverflowErrorMessage(a, "%", b), source);
             if (use_runtime_semantics_) {
-                return a;
+                return NumberT{0};
             } else {
                 return utils::Failure;
             }
@@ -727,7 +727,7 @@
             // lhs % 0 is an error
             AddError(OverflowErrorMessage(a, "%", b), source);
             if (use_runtime_semantics_) {
-                return a;
+                return NumberT{0};
             } else {
                 return utils::Failure;
             }
@@ -738,7 +738,7 @@
             if (rhs == -1 && lhs == std::numeric_limits<T>::min()) {
                 AddError(OverflowErrorMessage(a, "%", b), source);
                 if (use_runtime_semantics_) {
-                    return a;
+                    return NumberT{0};
                 } else {
                     return utils::Failure;
                 }
diff --git a/src/tint/resolver/const_eval_runtime_semantics_test.cc b/src/tint/resolver/const_eval_runtime_semantics_test.cc
index 9de1866..bc7f3c8 100644
--- a/src/tint/resolver/const_eval_runtime_semantics_test.cc
+++ b/src/tint/resolver/const_eval_runtime_semantics_test.cc
@@ -212,7 +212,7 @@
     auto* b = Scalar(AInt(0));
     auto result = const_eval.OpModulo(a->Type(), utils::Vector{a, b}, {});
     ASSERT_TRUE(result);
-    EXPECT_EQ(result.Get()->ValueAs<AInt>(), 42);
+    EXPECT_EQ(result.Get()->ValueAs<AInt>(), 0);
     EXPECT_EQ(error(), R"(warning: '42 % 0' cannot be represented as 'abstract-int')");
 }
 
@@ -221,7 +221,7 @@
     auto* b = Scalar(i32(0));
     auto result = const_eval.OpModulo(a->Type(), utils::Vector{a, b}, {});
     ASSERT_TRUE(result);
-    EXPECT_EQ(result.Get()->ValueAs<i32>(), 42);
+    EXPECT_EQ(result.Get()->ValueAs<i32>(), 0);
     EXPECT_EQ(error(), R"(warning: '42 % 0' cannot be represented as 'i32')");
 }
 
@@ -230,7 +230,7 @@
     auto* b = Scalar(u32(0));
     auto result = const_eval.OpModulo(a->Type(), utils::Vector{a, b}, {});
     ASSERT_TRUE(result);
-    EXPECT_EQ(result.Get()->ValueAs<u32>(), 42);
+    EXPECT_EQ(result.Get()->ValueAs<u32>(), 0);
     EXPECT_EQ(error(), R"(warning: '42 % 0' cannot be represented as 'u32')");
 }
 
@@ -239,7 +239,7 @@
     auto* b = Scalar(AFloat(0));
     auto result = const_eval.OpModulo(a->Type(), utils::Vector{a, b}, {});
     ASSERT_TRUE(result);
-    EXPECT_EQ(result.Get()->ValueAs<AFloat>(), 42.f);
+    EXPECT_EQ(result.Get()->ValueAs<AFloat>(), 0.f);
     EXPECT_EQ(error(), R"(warning: '42 % 0' cannot be represented as 'abstract-float')");
 }
 
@@ -248,7 +248,7 @@
     auto* b = Scalar(f32(0));
     auto result = const_eval.OpModulo(a->Type(), utils::Vector{a, b}, {});
     ASSERT_TRUE(result);
-    EXPECT_EQ(result.Get()->ValueAs<f32>(), 42.f);
+    EXPECT_EQ(result.Get()->ValueAs<f32>(), 0.f);
     EXPECT_EQ(error(), R"(warning: '42 % 0' cannot be represented as 'f32')");
 }
 
@@ -257,7 +257,7 @@
     auto* b = Scalar(i32(-1));
     auto result = const_eval.OpModulo(a->Type(), utils::Vector{a, b}, {});
     ASSERT_TRUE(result);
-    EXPECT_EQ(result.Get()->ValueAs<i32>(), i32::Lowest());
+    EXPECT_EQ(result.Get()->ValueAs<i32>(), 0);
     EXPECT_EQ(error(), R"(warning: '-2147483648 % -1' cannot be represented as 'i32')");
 }