Fix the division overflow.

Passing IntMath test.

Change-Id: I807858515a802f2efaa4802460e5f507eb944772
diff --git a/src/compiler_llvm/method_compiler.cc b/src/compiler_llvm/method_compiler.cc
index 09b84ad..0ab8871 100644
--- a/src/compiler_llvm/method_compiler.cc
+++ b/src/compiler_llvm/method_compiler.cc
@@ -3284,12 +3284,8 @@
     return irb_.CreateMul(lhs, rhs);
 
   case kIntArithm_Div:
-    EmitGuard_DivZeroException(dex_pc, rhs, op_jty);
-    return irb_.CreateSDiv(lhs, rhs);
-
   case kIntArithm_Rem:
-    EmitGuard_DivZeroException(dex_pc, rhs, op_jty);
-    return irb_.CreateSRem(lhs, rhs);
+    return EmitIntDivRemResultComputation(dex_pc, lhs, rhs, arithm, op_jty);
 
   case kIntArithm_And:
     return irb_.CreateAnd(lhs, rhs);
@@ -3307,6 +3303,67 @@
 }
 
 
+llvm::Value*
+MethodCompiler::EmitIntDivRemResultComputation(uint32_t dex_pc,
+                                               llvm::Value* dividend,
+                                               llvm::Value* divisor,
+                                               IntArithmKind arithm,
+                                               JType op_jty) {
+  // Throw exception if the divisor is 0.
+  EmitGuard_DivZeroException(dex_pc, divisor, op_jty);
+
+  // Check the special case: MININT / -1 = MININT
+  // That case will cause overflow, which is undefined behavior in llvm.
+  // So we check the divisor is -1 or not, if the divisor is -1, we do
+  // the special path to avoid undefined behavior.
+  llvm::Type* op_type = irb_.getJType(op_jty, kAccurate);
+  llvm::Value* zero = irb_.getJZero(op_jty);
+  llvm::Value* neg_one = llvm::ConstantInt::getSigned(op_type, -1);
+  llvm::Value* result = irb_.CreateAlloca(op_type);
+
+  llvm::BasicBlock* eq_neg_one = CreateBasicBlockWithDexPC(dex_pc, "eq_neg_one");
+  llvm::BasicBlock* ne_neg_one = CreateBasicBlockWithDexPC(dex_pc, "ne_neg_one");
+  llvm::BasicBlock* neg_one_cont = CreateBasicBlockWithDexPC(dex_pc, "neg_one_cont");
+
+  llvm::Value* is_equal_neg_one = EmitConditionResult(divisor, neg_one, kCondBranch_EQ);
+  irb_.CreateCondBr(is_equal_neg_one, eq_neg_one, ne_neg_one);
+
+  // If divisor == -1
+  irb_.SetInsertPoint(eq_neg_one);
+  llvm::Value* eq_result;
+  if (arithm == kIntArithm_Div) {
+    // We can just change from "dividend div -1" to "neg dividend".
+    // The sub don't care the sign/unsigned because of two's complement representation.
+    // And the behavior is what we want:
+    //  -(2^n)        (2^n)-1
+    //  MININT  < k <= MAXINT    ->     mul k -1  =  -k
+    //  MININT == k              ->     mul k -1  =   k
+    //
+    // LLVM use sub to represent 'neg'
+    eq_result = irb_.CreateSub(zero, dividend);
+  } else {
+    // Everything modulo -1 will be 0.
+    eq_result = zero;
+  }
+  irb_.CreateStore(eq_result, result);
+  irb_.CreateBr(neg_one_cont);
+
+  // If divisor != -1, just do the division.
+  irb_.SetInsertPoint(ne_neg_one);
+  llvm::Value* ne_result;
+  if (arithm == kIntArithm_Div) {
+    ne_result = irb_.CreateSDiv(dividend, divisor);
+  } else {
+    ne_result = irb_.CreateSRem(dividend, divisor);
+  }
+  irb_.CreateStore(ne_result, result);
+  irb_.CreateBr(neg_one_cont);
+
+  irb_.SetInsertPoint(neg_one_cont);
+  return irb_.CreateLoad(result);
+}
+
+
 void MethodCompiler::EmitInsn_IntShiftArithm(uint32_t dex_pc,
                                              Instruction const* insn,
                                              IntShiftArithmKind arithm,
diff --git a/src/compiler_llvm/method_compiler.h b/src/compiler_llvm/method_compiler.h
index 7e56046..6f24799 100644
--- a/src/compiler_llvm/method_compiler.h
+++ b/src/compiler_llvm/method_compiler.h
@@ -284,6 +284,12 @@
                                               IntArithmKind arithm,
                                               JType op_jty);
 
+  llvm::Value* EmitIntDivRemResultComputation(uint32_t dex_pc,
+                                              llvm::Value* dividend,
+                                              llvm::Value* divisor,
+                                              IntArithmKind arithm,
+                                              JType op_jty);
+
   llvm::Value* EmitIntShiftArithmResultComputation(uint32_t dex_pc,
                                                    llvm::Value* lhs,
                                                    llvm::Value* rhs,
diff --git a/test/IntMath/IntMath.java b/test/IntMath/IntMath.java
index 7491e0b..c1cb976 100644
--- a/test/IntMath/IntMath.java
+++ b/test/IntMath/IntMath.java
@@ -338,6 +338,7 @@
         int negOne = -results[5];
         int plusOne = 1;
         int result = (((minInt + plusOne) - plusOne) / negOne) / negOne;
+        int shouldBeZero = minInt % negOne;
 
         if (result != minInt) { return 1;};
         if (results[0] != 69997) { return 2;};
@@ -350,6 +351,7 @@
         if (results[7] != -3) { return 9;};
         if (results[8] != -70003) { return 10;};
         if (results[9] != 70000) { return 11;};
+        if (shouldBeZero != 0) { return 12;};
 
         return 0;
     }