Fix overflow when negating INT_MIN. (#2293)
When doing (-INT_MIN) is considered overflow, so we cannot fold it by
actually performing the negation.
Fixes https://crbug.com/917991
diff --git a/source/opt/fold.cpp b/source/opt/fold.cpp
index 0604da2..944f438 100644
--- a/source/opt/fold.cpp
+++ b/source/opt/fold.cpp
@@ -45,8 +45,13 @@
uint32_t InstructionFolder::UnaryOperate(SpvOp opcode, uint32_t operand) const {
switch (opcode) {
// Arthimetics
- case SpvOp::SpvOpSNegate:
- return -static_cast<int32_t>(operand);
+ case SpvOp::SpvOpSNegate: {
+ int32_t s_operand = static_cast<int32_t>(operand);
+ if (s_operand == std::numeric_limits<int32_t>::min()) {
+ return s_operand;
+ }
+ return -s_operand;
+ }
case SpvOp::SpvOpNot:
return ~operand;
case SpvOp::SpvOpLogicalNot:
diff --git a/test/opt/fold_test.cpp b/test/opt/fold_test.cpp
index 88248ba..487c18a 100644
--- a/test/opt/fold_test.cpp
+++ b/test/opt/fold_test.cpp
@@ -538,7 +538,15 @@
"%2 = OpShiftLeftLogical %int %int_2 %uint_32\n" +
"OpReturn\n" +
"OpFunctionEnd",
- 2, 0)
+ 2, 0),
+ // Test case 29: fold -INT_MIN
+ InstructionFoldingCase<uint32_t>(
+ Header() + "%main = OpFunction %void None %void_func\n" +
+ "%main_lab = OpLabel\n" +
+ "%2 = OpSNegate %int %int_min\n" +
+ "OpReturn\n" +
+ "OpFunctionEnd",
+ 2, std::numeric_limits<int32_t>::min())
));
// clang-format on