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