[Tint] Validate partial eval of divby0
Validate against division by zero for cases where only the rhs is an
integral type and can be constant-evaluated.
Related CTS fixes: https://github.com/gpuweb/cts/pull/3873
Fixes: 42251274
Change-Id: I43498423a1826f0f16707587fc9c5f47b68dadaf
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/199776
Reviewed-by: Antonio Maiorano <amaiorano@google.com>
Commit-Queue: Natalie Chouinard <chouinard@google.com>
diff --git a/src/tint/lang/core/constant/eval_binary_op_test.cc b/src/tint/lang/core/constant/eval_binary_op_test.cc
index 520791d..812d633 100644
--- a/src/tint/lang/core/constant/eval_binary_op_test.cc
+++ b/src/tint/lang/core/constant/eval_binary_op_test.cc
@@ -454,9 +454,9 @@
C(T{0}, T::Highest(), T{0}),
// Divide by zero
- E(T{123}, T{0}, error_msg(T{123}, T{0})),
- E(T::Highest(), T{0}, error_msg(T::Highest(), T{0})),
- E(T::Lowest(), T{0}, error_msg(T::Lowest(), T{0})),
+ E(T{123}, T{0}, "12:34 error: integer division by zero is invalid"),
+ E(T::Highest(), T{0}, "12:34 error: integer division by zero is invalid"),
+ E(T::Lowest(), T{0}, "12:34 error: integer division by zero is invalid"),
};
// Error on most negative divided by -1
@@ -526,9 +526,15 @@
C(T{10}, T{10}, T{0}), //
// Error on divide by zero
- E(T{123}, T{0}, error_msg(T{123}, T{0})),
- E(T::Highest(), T{0}, error_msg(T::Highest(), T{0})),
- E(T::Lowest(), T{0}, error_msg(T::Lowest(), T{0})),
+ E(T{123}, T{0},
+ IsIntegral<T> ? "12:34 error: integer division by zero is invalid"
+ : error_msg(T{123}, T{0})),
+ E(T::Highest(), T{0},
+ IsIntegral<T> ? "12:34 error: integer division by zero is invalid"
+ : error_msg(T::Highest(), T{0})),
+ E(T::Lowest(), T{0},
+ IsIntegral<T> ? "12:34 error: integer division by zero is invalid"
+ : error_msg(T::Lowest(), T{0})),
};
if constexpr (IsIntegral<T>) {
@@ -1564,7 +1570,7 @@
GlobalConst("result", binary);
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), "12:34 error: '2 / 0' cannot be represented as 'abstract-int'");
+ EXPECT_EQ(r()->error(), "12:34 error: integer division by zero is invalid");
}
TEST_F(ConstEvalTest, ShortCircuit_And_Error_Binary) {
@@ -1608,7 +1614,7 @@
GlobalConst("result", binary);
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(), "12:34 error: '2 / 0' cannot be represented as 'abstract-int'");
+ EXPECT_EQ(r()->error(), "12:34 error: integer division by zero is invalid");
}
TEST_F(ConstEvalTest, ShortCircuit_Or_Error_Binary) {
diff --git a/src/tint/lang/wgsl/resolver/validator.cc b/src/tint/lang/wgsl/resolver/validator.cc
index f8b75f1..c7fc01f 100644
--- a/src/tint/lang/wgsl/resolver/validator.cc
+++ b/src/tint/lang/wgsl/resolver/validator.cc
@@ -1698,6 +1698,20 @@
}
return true;
}
+ case core::BinaryOp::kDivide:
+ case core::BinaryOp::kModulo: {
+ // Integer division by zero should be checked for the partial evaluation case (only rhs
+ // is const). FP division by zero is only invalid when the whole expression is
+ // constant-evaluated.
+ if (rhs->Type()->is_integer_scalar_or_vector() &&
+ rhs->Stage() == core::EvaluationStage::kConstant) {
+ if (rhs->ConstantValue()->AnyZero()) {
+ AddError(node->source) << "integer division by zero is invalid";
+ return false;
+ }
+ }
+ return true;
+ }
default: {
return true;
}
diff --git a/test/tint/statements/compound_assign/divide_by_zero.wgsl b/test/tint/statements/compound_assign/divide_by_zero.wgsl
index 7ff3454..5e340f9 100644
--- a/test/tint/statements/compound_assign/divide_by_zero.wgsl
+++ b/test/tint/statements/compound_assign/divide_by_zero.wgsl
@@ -2,8 +2,6 @@
var<private> b : f32;
fn foo(maybe_zero : i32) {
- a /= 0;
- a %= 0;
a /= maybe_zero;
a %= maybe_zero;
diff --git a/test/tint/statements/compound_assign/divide_by_zero.wgsl.expected.dxc.hlsl b/test/tint/statements/compound_assign/divide_by_zero.wgsl.expected.dxc.hlsl
index aeb066f..2f80743 100644
--- a/test/tint/statements/compound_assign/divide_by_zero.wgsl.expected.dxc.hlsl
+++ b/test/tint/statements/compound_assign/divide_by_zero.wgsl.expected.dxc.hlsl
@@ -28,8 +28,6 @@
}
void foo(int maybe_zero) {
- a = tint_div(a, 0);
- a = tint_mod(a, 0);
a = tint_div(a, maybe_zero);
a = tint_mod(a, maybe_zero);
b = (b / 0.0f);
diff --git a/test/tint/statements/compound_assign/divide_by_zero.wgsl.expected.fxc.hlsl b/test/tint/statements/compound_assign/divide_by_zero.wgsl.expected.fxc.hlsl
index aeb066f..2f80743 100644
--- a/test/tint/statements/compound_assign/divide_by_zero.wgsl.expected.fxc.hlsl
+++ b/test/tint/statements/compound_assign/divide_by_zero.wgsl.expected.fxc.hlsl
@@ -28,8 +28,6 @@
}
void foo(int maybe_zero) {
- a = tint_div(a, 0);
- a = tint_mod(a, 0);
a = tint_div(a, maybe_zero);
a = tint_mod(a, maybe_zero);
b = (b / 0.0f);
diff --git a/test/tint/statements/compound_assign/divide_by_zero.wgsl.expected.glsl b/test/tint/statements/compound_assign/divide_by_zero.wgsl.expected.glsl
index 2bd98b6..68edcef 100644
--- a/test/tint/statements/compound_assign/divide_by_zero.wgsl.expected.glsl
+++ b/test/tint/statements/compound_assign/divide_by_zero.wgsl.expected.glsl
@@ -25,8 +25,6 @@
}
void foo(int maybe_zero) {
- a = tint_div(a, 0);
- a = tint_mod(a, 0);
a = tint_div(a, maybe_zero);
a = tint_mod(a, maybe_zero);
b = (b / 0.0f);
diff --git a/test/tint/statements/compound_assign/divide_by_zero.wgsl.expected.msl b/test/tint/statements/compound_assign/divide_by_zero.wgsl.expected.msl
index 47a5e29..8133694 100644
--- a/test/tint/statements/compound_assign/divide_by_zero.wgsl.expected.msl
+++ b/test/tint/statements/compound_assign/divide_by_zero.wgsl.expected.msl
@@ -20,8 +20,6 @@
}
void foo(int maybe_zero, thread tint_private_vars_struct* const tint_private_vars) {
- (*(tint_private_vars)).a = tint_div((*(tint_private_vars)).a, 0);
- (*(tint_private_vars)).a = tint_mod((*(tint_private_vars)).a, 0);
(*(tint_private_vars)).a = tint_div((*(tint_private_vars)).a, maybe_zero);
(*(tint_private_vars)).a = tint_mod((*(tint_private_vars)).a, maybe_zero);
(*(tint_private_vars)).b = ((*(tint_private_vars)).b / 0.0f);
diff --git a/test/tint/statements/compound_assign/divide_by_zero.wgsl.expected.spvasm b/test/tint/statements/compound_assign/divide_by_zero.wgsl.expected.spvasm
index c7ab06b..97dcaa7 100644
--- a/test/tint/statements/compound_assign/divide_by_zero.wgsl.expected.spvasm
+++ b/test/tint/statements/compound_assign/divide_by_zero.wgsl.expected.spvasm
@@ -1,7 +1,7 @@
; SPIR-V
; Version: 1.3
; Generator: Google Tint Compiler; 0
-; Bound: 76
+; Bound: 72
; Schema: 0
OpCapability Shader
OpMemoryModel Logical GLSL450
@@ -85,30 +85,24 @@
%maybe_zero = OpFunctionParameter %int
%57 = OpLabel
%59 = OpLoad %int %a
- %58 = OpFunctionCall %int %tint_div %59 %4
+ %58 = OpFunctionCall %int %tint_div %59 %maybe_zero
OpStore %a %58
%61 = OpLoad %int %a
- %60 = OpFunctionCall %int %tint_mod %61 %4
+ %60 = OpFunctionCall %int %tint_mod %61 %maybe_zero
OpStore %a %60
- %63 = OpLoad %int %a
- %62 = OpFunctionCall %int %tint_div %63 %maybe_zero
- OpStore %a %62
- %65 = OpLoad %int %a
- %64 = OpFunctionCall %int %tint_mod %65 %maybe_zero
- OpStore %a %64
+ %62 = OpLoad %float %b
+ %63 = OpFDiv %float %62 %8
+ OpStore %b %63
+ %64 = OpLoad %float %b
+ %65 = OpFRem %float %64 %8
+ OpStore %b %65
%66 = OpLoad %float %b
- %67 = OpFDiv %float %66 %8
- OpStore %b %67
- %68 = OpLoad %float %b
- %69 = OpFRem %float %68 %8
- OpStore %b %69
- %70 = OpLoad %float %b
- %71 = OpConvertSToF %float %maybe_zero
- %72 = OpFDiv %float %70 %71
- OpStore %b %72
- %73 = OpLoad %float %b
- %74 = OpConvertSToF %float %maybe_zero
- %75 = OpFRem %float %73 %74
- OpStore %b %75
+ %67 = OpConvertSToF %float %maybe_zero
+ %68 = OpFDiv %float %66 %67
+ OpStore %b %68
+ %69 = OpLoad %float %b
+ %70 = OpConvertSToF %float %maybe_zero
+ %71 = OpFRem %float %69 %70
+ OpStore %b %71
OpReturn
OpFunctionEnd
diff --git a/test/tint/statements/compound_assign/divide_by_zero.wgsl.expected.wgsl b/test/tint/statements/compound_assign/divide_by_zero.wgsl.expected.wgsl
index 6a6bc58..2a63fc2 100644
--- a/test/tint/statements/compound_assign/divide_by_zero.wgsl.expected.wgsl
+++ b/test/tint/statements/compound_assign/divide_by_zero.wgsl.expected.wgsl
@@ -3,8 +3,6 @@
var<private> b : f32;
fn foo(maybe_zero : i32) {
- a /= 0;
- a %= 0;
a /= maybe_zero;
a %= maybe_zero;
b /= 0.0;