mirror of
https://github.com/KhronosGroup/SPIRV-Tools
synced 2024-12-26 01:31:06 +00:00
Fold divisions by 0. (#1963)
The current implementation in the folder when seeing a division by zero is to assert. In the release build, the compiler will attempt to compute the value, which causes its own problems. The solution I will go with is to fold the division, and just give it the value of 0. The same goes for remainder and mod operations. Fixes #1961.
This commit is contained in:
parent
fae1e61ab8
commit
4e266f775a
@ -69,29 +69,49 @@ uint32_t InstructionFolder::BinaryOperate(SpvOp opcode, uint32_t a,
|
||||
case SpvOp::SpvOpIMul:
|
||||
return a * b;
|
||||
case SpvOp::SpvOpUDiv:
|
||||
assert(b != 0);
|
||||
if (b != 0) {
|
||||
return a / b;
|
||||
} else {
|
||||
// Dividing by 0 is undefined, so we will just pick 0.
|
||||
return 0;
|
||||
}
|
||||
case SpvOp::SpvOpSDiv:
|
||||
assert(b != 0u);
|
||||
if (b != 0u) {
|
||||
return (static_cast<int32_t>(a)) / (static_cast<int32_t>(b));
|
||||
} else {
|
||||
// Dividing by 0 is undefined, so we will just pick 0.
|
||||
return 0;
|
||||
}
|
||||
case SpvOp::SpvOpSRem: {
|
||||
// The sign of non-zero result comes from the first operand: a. This is
|
||||
// guaranteed by C++11 rules for integer division operator. The division
|
||||
// result is rounded toward zero, so the result of '%' has the sign of
|
||||
// the first operand.
|
||||
assert(b != 0u);
|
||||
if (b != 0u) {
|
||||
return static_cast<int32_t>(a) % static_cast<int32_t>(b);
|
||||
} else {
|
||||
// Remainder when dividing with 0 is undefined, so we will just pick 0.
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
case SpvOp::SpvOpSMod: {
|
||||
// The sign of non-zero result comes from the second operand: b
|
||||
assert(b != 0u);
|
||||
if (b != 0u) {
|
||||
int32_t rem = BinaryOperate(SpvOp::SpvOpSRem, a, b);
|
||||
int32_t b_prim = static_cast<int32_t>(b);
|
||||
return (rem + b_prim) % b_prim;
|
||||
} else {
|
||||
// Mod with 0 is undefined, so we will just pick 0.
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
case SpvOp::SpvOpUMod:
|
||||
assert(b != 0u);
|
||||
if (b != 0u) {
|
||||
return (a % b);
|
||||
} else {
|
||||
// Mod with 0 is undefined, so we will just pick 0.
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Shifting
|
||||
case SpvOp::SpvOpShiftRightLogical: {
|
||||
|
@ -434,6 +434,46 @@ INSTANTIATE_TEST_CASE_P(TestCase, IntegerInstructionFoldingTest,
|
||||
"%2 = OpBitwiseAnd %uint %load %uint_0\n" +
|
||||
"OpReturn\n" +
|
||||
"OpFunctionEnd",
|
||||
2, 0),
|
||||
// Test case 17: fold 1/0 (signed)
|
||||
InstructionFoldingCase<uint32_t>(
|
||||
Header() + "%main = OpFunction %void None %void_func\n" +
|
||||
"%main_lab = OpLabel\n" +
|
||||
"%2 = OpSDiv %int %int_1 %int_0\n" +
|
||||
"OpReturn\n" +
|
||||
"OpFunctionEnd",
|
||||
2, 0),
|
||||
// Test case 18: fold 1/0 (unsigned)
|
||||
InstructionFoldingCase<uint32_t>(
|
||||
Header() + "%main = OpFunction %void None %void_func\n" +
|
||||
"%main_lab = OpLabel\n" +
|
||||
"%2 = OpUDiv %uint %uint_1 %uint_0\n" +
|
||||
"OpReturn\n" +
|
||||
"OpFunctionEnd",
|
||||
2, 0),
|
||||
// Test case 19: fold OpSRem 1 0 (signed)
|
||||
InstructionFoldingCase<uint32_t>(
|
||||
Header() + "%main = OpFunction %void None %void_func\n" +
|
||||
"%main_lab = OpLabel\n" +
|
||||
"%2 = OpSRem %int %int_1 %int_0\n" +
|
||||
"OpReturn\n" +
|
||||
"OpFunctionEnd",
|
||||
2, 0),
|
||||
// Test case 20: fold 1%0 (signed)
|
||||
InstructionFoldingCase<uint32_t>(
|
||||
Header() + "%main = OpFunction %void None %void_func\n" +
|
||||
"%main_lab = OpLabel\n" +
|
||||
"%2 = OpSMod %int %int_1 %int_0\n" +
|
||||
"OpReturn\n" +
|
||||
"OpFunctionEnd",
|
||||
2, 0),
|
||||
// Test case 21: fold 1%0 (unsigned)
|
||||
InstructionFoldingCase<uint32_t>(
|
||||
Header() + "%main = OpFunction %void None %void_func\n" +
|
||||
"%main_lab = OpLabel\n" +
|
||||
"%2 = OpUMod %uint %uint_1 %uint_0\n" +
|
||||
"OpReturn\n" +
|
||||
"OpFunctionEnd",
|
||||
2, 0)
|
||||
));
|
||||
// clang-format on
|
||||
|
Loading…
Reference in New Issue
Block a user