Fix SHL, SHR, USHR implementation bug.
Change-Id: I506469f69087759b4ae30fad084f9fe3c559c2d6
diff --git a/src/compiler_llvm/method_compiler.cc b/src/compiler_llvm/method_compiler.cc
index 890eeab..09b84ad 100644
--- a/src/compiler_llvm/method_compiler.cc
+++ b/src/compiler_llvm/method_compiler.cc
@@ -804,15 +804,15 @@
break;
case Instruction::SHL_INT:
- EmitInsn_IntArithm(ARGS, kIntArithm_Shl, kInt, false);
+ EmitInsn_IntShiftArithm(ARGS, kIntArithm_Shl, kInt, false);
break;
case Instruction::SHR_INT:
- EmitInsn_IntArithm(ARGS, kIntArithm_Shr, kInt, false);
+ EmitInsn_IntShiftArithm(ARGS, kIntArithm_Shr, kInt, false);
break;
case Instruction::USHR_INT:
- EmitInsn_IntArithm(ARGS, kIntArithm_UShr, kInt, false);
+ EmitInsn_IntShiftArithm(ARGS, kIntArithm_UShr, kInt, false);
break;
case Instruction::ADD_LONG:
@@ -848,15 +848,15 @@
break;
case Instruction::SHL_LONG:
- EmitInsn_IntArithm(ARGS, kIntArithm_Shl, kLong, false);
+ EmitInsn_IntShiftArithm(ARGS, kIntArithm_Shl, kLong, false);
break;
case Instruction::SHR_LONG:
- EmitInsn_IntArithm(ARGS, kIntArithm_Shr, kLong, false);
+ EmitInsn_IntShiftArithm(ARGS, kIntArithm_Shr, kLong, false);
break;
case Instruction::USHR_LONG:
- EmitInsn_IntArithm(ARGS, kIntArithm_UShr, kLong, false);
+ EmitInsn_IntShiftArithm(ARGS, kIntArithm_UShr, kLong, false);
break;
case Instruction::ADD_FLOAT:
@@ -932,15 +932,15 @@
break;
case Instruction::SHL_INT_2ADDR:
- EmitInsn_IntArithm(ARGS, kIntArithm_Shl, kInt, true);
+ EmitInsn_IntShiftArithm(ARGS, kIntArithm_Shl, kInt, true);
break;
case Instruction::SHR_INT_2ADDR:
- EmitInsn_IntArithm(ARGS, kIntArithm_Shr, kInt, true);
+ EmitInsn_IntShiftArithm(ARGS, kIntArithm_Shr, kInt, true);
break;
case Instruction::USHR_INT_2ADDR:
- EmitInsn_IntArithm(ARGS, kIntArithm_UShr, kInt, true);
+ EmitInsn_IntShiftArithm(ARGS, kIntArithm_UShr, kInt, true);
break;
case Instruction::ADD_LONG_2ADDR:
@@ -976,15 +976,15 @@
break;
case Instruction::SHL_LONG_2ADDR:
- EmitInsn_IntArithm(ARGS, kIntArithm_Shl, kLong, true);
+ EmitInsn_IntShiftArithm(ARGS, kIntArithm_Shl, kLong, true);
break;
case Instruction::SHR_LONG_2ADDR:
- EmitInsn_IntArithm(ARGS, kIntArithm_Shr, kLong, true);
+ EmitInsn_IntShiftArithm(ARGS, kIntArithm_Shr, kLong, true);
break;
case Instruction::USHR_LONG_2ADDR:
- EmitInsn_IntArithm(ARGS, kIntArithm_UShr, kLong, true);
+ EmitInsn_IntShiftArithm(ARGS, kIntArithm_UShr, kLong, true);
break;
case Instruction::ADD_FLOAT_2ADDR:
@@ -1068,15 +1068,15 @@
break;
case Instruction::SHL_INT_LIT8:
- EmitInsn_IntArithmImmediate(ARGS, kIntArithm_Shl);
+ EmitInsn_IntShiftArithmImmediate(ARGS, kIntArithm_Shl);
break;
case Instruction::SHR_INT_LIT8:
- EmitInsn_IntArithmImmediate(ARGS, kIntArithm_Shr);
+ EmitInsn_IntShiftArithmImmediate(ARGS, kIntArithm_Shr);
break;
case Instruction::USHR_INT_LIT8:
- EmitInsn_IntArithmImmediate(ARGS, kIntArithm_UShr);
+ EmitInsn_IntShiftArithmImmediate(ARGS, kIntArithm_UShr);
break;
case Instruction::UNUSED_3E:
@@ -3300,27 +3300,6 @@
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;
@@ -3328,6 +3307,92 @@
}
+void MethodCompiler::EmitInsn_IntShiftArithm(uint32_t dex_pc,
+ Instruction const* insn,
+ IntShiftArithmKind arithm,
+ JType op_jty,
+ bool is_2addr) {
+
+ DecodedInstruction dec_insn(insn);
+
+ DCHECK(op_jty == kInt || op_jty == kLong) << op_jty;
+
+ llvm::Value* src1_value;
+ llvm::Value* src2_value;
+
+ // NOTE: The 2nd operand of the shift arithmetic instruction is
+ // 32-bit integer regardless of the 1st operand.
+ if (is_2addr) {
+ src1_value = EmitLoadDalvikReg(dec_insn.vA, op_jty, kAccurate);
+ src2_value = EmitLoadDalvikReg(dec_insn.vB, kInt, kAccurate);
+ } else {
+ src1_value = EmitLoadDalvikReg(dec_insn.vB, op_jty, kAccurate);
+ src2_value = EmitLoadDalvikReg(dec_insn.vC, kInt, kAccurate);
+ }
+
+ llvm::Value* result_value =
+ EmitIntShiftArithmResultComputation(dex_pc, src1_value, src2_value,
+ arithm, op_jty);
+
+ EmitStoreDalvikReg(dec_insn.vA, op_jty, kAccurate, result_value);
+
+ irb_.CreateBr(GetNextBasicBlock(dex_pc));
+}
+
+
+void MethodCompiler::
+EmitInsn_IntShiftArithmImmediate(uint32_t dex_pc,
+ Instruction const* insn,
+ IntShiftArithmKind arithm) {
+
+ 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 =
+ EmitIntShiftArithmResultComputation(dex_pc, src_value, imm_value,
+ arithm, kInt);
+
+ EmitStoreDalvikReg(dec_insn.vA, kInt, kAccurate, result_value);
+
+ irb_.CreateBr(GetNextBasicBlock(dex_pc));
+}
+
+
+llvm::Value*
+MethodCompiler::EmitIntShiftArithmResultComputation(uint32_t dex_pc,
+ llvm::Value* lhs,
+ llvm::Value* rhs,
+ IntShiftArithmKind arithm,
+ JType op_jty) {
+ DCHECK(op_jty == kInt || op_jty == kLong) << op_jty;
+
+ if (op_jty == kInt) {
+ rhs = irb_.CreateAnd(rhs, 0x1f);
+ } else {
+ llvm::Value* masked_rhs = irb_.CreateAnd(rhs, 0x3f);
+ rhs = irb_.CreateZExt(masked_rhs, irb_.getJLongTy());
+ }
+
+ switch (arithm) {
+ case kIntArithm_Shl:
+ return irb_.CreateShl(lhs, rhs);
+
+ case kIntArithm_Shr:
+ return irb_.CreateAShr(lhs, rhs);
+
+ case kIntArithm_UShr:
+ return irb_.CreateLShr(lhs, rhs);
+
+ default:
+ LOG(FATAL) << "Unknown integer shift arithmetic kind: " << arithm;
+ return NULL;
+ }
+}
+
+
void MethodCompiler::EmitInsn_RSubImmediate(uint32_t dex_pc,
Instruction const* insn) {
diff --git a/src/compiler_llvm/method_compiler.h b/src/compiler_llvm/method_compiler.h
index 3127447..7e56046 100644
--- a/src/compiler_llvm/method_compiler.h
+++ b/src/compiler_llvm/method_compiler.h
@@ -112,6 +112,9 @@
kIntArithm_And,
kIntArithm_Or,
kIntArithm_Xor,
+ };
+
+ enum IntShiftArithmKind {
kIntArithm_Shl,
kIntArithm_Shr,
kIntArithm_UShr,
@@ -222,6 +225,12 @@
void EmitInsn_IntArithmImmediate(GEN_INSN_ARGS, IntArithmKind arithm);
+ void EmitInsn_IntShiftArithm(GEN_INSN_ARGS, IntShiftArithmKind arithm,
+ JType op_jty, bool is_2addr);
+
+ void EmitInsn_IntShiftArithmImmediate(GEN_INSN_ARGS,
+ IntShiftArithmKind arithm);
+
void EmitInsn_RSubImmediate(GEN_INSN_ARGS);
@@ -275,6 +284,12 @@
IntArithmKind arithm,
JType op_jty);
+ llvm::Value* EmitIntShiftArithmResultComputation(uint32_t dex_pc,
+ llvm::Value* lhs,
+ llvm::Value* rhs,
+ IntShiftArithmKind arithm,
+ JType op_jty);
+
llvm::Value* EmitFPArithmResultComputation(uint32_t dex_pc,
llvm::Value* lhs,
llvm::Value* rhs,