Implement integer binary arithmetic instructions.

Change-Id: I55f1336182e91996d55d1665bda87c75bb972c64
diff --git a/src/compiler_llvm/method_compiler.cc b/src/compiler_llvm/method_compiler.cc
index 37da618..0e5618f 100644
--- a/src/compiler_llvm/method_compiler.cc
+++ b/src/compiler_llvm/method_compiler.cc
@@ -1839,7 +1839,28 @@
                                         IntArithmKind arithm,
                                         JType op_jty,
                                         bool is_2addr) {
-  // UNIMPLEMENTED(WARNING);
+
+  Instruction::DecodedInstruction dec_insn(insn);
+
+  DCHECK(op_jty == kInt || op_jty == kLong) << op_jty;
+
+  llvm::Value* src1_value;
+  llvm::Value* src2_value;
+
+  if (is_2addr) {
+    src1_value = EmitLoadDalvikReg(dec_insn.vA_, op_jty, kAccurate);
+    src2_value = EmitLoadDalvikReg(dec_insn.vB_, op_jty, kAccurate);
+  } else {
+    src1_value = EmitLoadDalvikReg(dec_insn.vB_, op_jty, kAccurate);
+    src2_value = EmitLoadDalvikReg(dec_insn.vC_, op_jty, kAccurate);
+  }
+
+  llvm::Value* result_value =
+    EmitIntArithmResultComputation(dex_pc, src1_value, src2_value,
+                                   arithm, op_jty);
+
+  EmitStoreDalvikReg(dec_insn.vA_, op_jty, kAccurate, result_value);
+
   irb_.CreateBr(GetNextBasicBlock(dex_pc));
 }
 
@@ -1847,11 +1868,85 @@
 void MethodCompiler::EmitInsn_IntArithmImmediate(uint32_t dex_pc,
                                                  Instruction const* insn,
                                                  IntArithmKind arithm) {
-  // UNIMPLEMENTED(WARNING);
+
+  Instruction::DecodedInstruction dec_insn(insn);
+
+  llvm::Value* src_value = EmitLoadDalvikReg(dec_insn.vB_, kInt, kAccurate);
+
+  llvm::Value* imm_value = irb_.getInt32(dec_insn.vC_);
+
+  llvm::Value* result_value =
+    EmitIntArithmResultComputation(dex_pc, src_value, imm_value, arithm, kInt);
+
+  EmitStoreDalvikReg(dec_insn.vA_, kInt, kAccurate, result_value);
+
   irb_.CreateBr(GetNextBasicBlock(dex_pc));
 }
 
 
+llvm::Value*
+MethodCompiler::EmitIntArithmResultComputation(uint32_t dex_pc,
+                                               llvm::Value* lhs,
+                                               llvm::Value* rhs,
+                                               IntArithmKind arithm,
+                                               JType op_jty) {
+  DCHECK(op_jty == kInt || op_jty == kLong) << op_jty;
+
+  switch (arithm) {
+  case kIntArithm_Add:
+    return irb_.CreateAdd(lhs, rhs);
+
+  case kIntArithm_Sub:
+    return irb_.CreateSub(lhs, rhs);
+
+  case kIntArithm_Mul:
+    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);
+
+  case kIntArithm_And:
+    return irb_.CreateAnd(lhs, rhs);
+
+  case kIntArithm_Or:
+    return irb_.CreateOr(lhs, rhs);
+
+  case kIntArithm_Xor:
+    return irb_.CreateXor(lhs, rhs);
+
+  case kIntArithm_Shl:
+    if (op_jty == kLong) {
+      return irb_.CreateShl(lhs, irb_.CreateAnd(rhs, 0x3f));
+    } else {
+      return irb_.CreateShl(lhs, irb_.CreateAnd(rhs, 0x1f));
+    }
+
+  case kIntArithm_Shr:
+    if (op_jty == kLong) {
+      return irb_.CreateAShr(lhs, irb_.CreateAnd(rhs, 0x3f));
+    } else {
+      return irb_.CreateAShr(lhs, irb_.CreateAnd(rhs, 0x1f));
+    }
+
+  case kIntArithm_UShr:
+    if (op_jty == kLong) {
+      return irb_.CreateLShr(lhs, irb_.CreateAnd(rhs, 0x3f));
+    } else {
+      return irb_.CreateLShr(lhs, irb_.CreateAnd(rhs, 0x1f));
+    }
+
+  default:
+    LOG(FATAL) << "Unknown integer arithmetic kind: " << arithm;
+    return NULL;
+  }
+}
+
+
 void MethodCompiler::EmitInsn_RSubImmediate(uint32_t dex_pc,
                                             Instruction const* insn) {
   // UNIMPLEMENTED(WARNING);
@@ -1869,6 +1964,29 @@
 }
 
 
+void MethodCompiler::EmitGuard_DivZeroException(uint32_t dex_pc,
+                                                llvm::Value* denominator,
+                                                JType op_jty) {
+  DCHECK(op_jty == kInt || op_jty == kLong) << op_jty;
+
+  llvm::Constant* zero = irb_.getJZero(op_jty);
+
+  llvm::Value* equal_zero = irb_.CreateICmpEQ(denominator, zero);
+
+  llvm::BasicBlock* block_exception = CreateBasicBlockWithDexPC(dex_pc, "div0");
+
+  llvm::BasicBlock* block_continue = CreateBasicBlockWithDexPC(dex_pc, "cont");
+
+  irb_.CreateCondBr(equal_zero, block_exception, block_continue);
+
+  irb_.SetInsertPoint(block_exception);
+  irb_.CreateCall(irb_.GetRuntime(ThrowDivZeroException));
+  EmitBranchExceptionLandingPad(dex_pc);
+
+  irb_.SetInsertPoint(block_continue);
+}
+
+
 CompiledMethod *MethodCompiler::Compile() {
   // Code generation
   CreateFunction();