Support hardware divide instruction
Bug: 11299025
Uses sdiv for division and a combo of sdiv, mul and sub for modulus.
Only does this on processors that are capable of the sdiv instruction, as determined
by the build system.
Also provides a command line arg --instruction-set-features= to allow cross compilation.
Makefile adds the --instruction-set-features= arg to build-time dex2oat runs and defaults
it to something obtained from the target architecture.
Provides a GetInstructionSetFeatures() function on CompilerDriver that can be
queried for various features. The only feature supported right now is hasDivideInstruction().
Also adds a few more instructions to the ARM disassembler
b/11535253 is an addition to this CL to be done later.
Change-Id: Ia8aaf801fd94bc71e476902749cf20f74eba9f68
diff --git a/compiler/dex/quick/gen_common.cc b/compiler/dex/quick/gen_common.cc
index 2b3404a..df6493d 100644
--- a/compiler/dex/quick/gen_common.cc
+++ b/compiler/dex/quick/gen_common.cc
@@ -1307,6 +1307,7 @@
}
StoreValue(rl_dest, rl_result);
} else {
+ bool done = false; // Set to true if we happen to find a way to use a real instruction.
if (cu_->instruction_set == kMips) {
rl_src1 = LoadValue(rl_src1, kCoreReg);
rl_src2 = LoadValue(rl_src2, kCoreReg);
@@ -1314,7 +1315,23 @@
GenImmedCheck(kCondEq, rl_src2.low_reg, 0, kThrowDivZero);
}
rl_result = GenDivRem(rl_dest, rl_src1.low_reg, rl_src2.low_reg, op == kOpDiv);
- } else {
+ done = true;
+ } else if (cu_->instruction_set == kThumb2) {
+ if (cu_->GetInstructionSetFeatures().HasDivideInstruction()) {
+ // Use ARM SDIV instruction for division. For remainder we also need to
+ // calculate using a MUL and subtract.
+ rl_src1 = LoadValue(rl_src1, kCoreReg);
+ rl_src2 = LoadValue(rl_src2, kCoreReg);
+ if (check_zero) {
+ GenImmedCheck(kCondEq, rl_src2.low_reg, 0, kThrowDivZero);
+ }
+ rl_result = GenDivRem(rl_dest, rl_src1.low_reg, rl_src2.low_reg, op == kOpDiv);
+ done = true;
+ }
+ }
+
+ // If we haven't already generated the code use the callout function.
+ if (!done) {
ThreadOffset func_offset = QUICK_ENTRYPOINT_OFFSET(pIdivmod);
FlushAllRegs(); /* Send everything to home location */
LoadValueDirectFixed(rl_src2, TargetReg(kArg1));
@@ -1323,7 +1340,7 @@
if (check_zero) {
GenImmedCheck(kCondEq, TargetReg(kArg1), 0, kThrowDivZero);
}
- // NOTE: callout here is not a safepoint
+ // NOTE: callout here is not a safepoint.
CallHelper(r_tgt, func_offset, false /* not a safepoint */);
if (op == kOpDiv)
rl_result = GetReturn(false);
@@ -1561,11 +1578,24 @@
if (HandleEasyDivRem(opcode, is_div, rl_src, rl_dest, lit)) {
return;
}
+
+ bool done = false;
if (cu_->instruction_set == kMips) {
rl_src = LoadValue(rl_src, kCoreReg);
rl_result = GenDivRemLit(rl_dest, rl_src.low_reg, lit, is_div);
- } else {
- FlushAllRegs(); /* Everything to home location */
+ done = true;
+ } else if (cu_->instruction_set == kThumb2) {
+ if (cu_->GetInstructionSetFeatures().HasDivideInstruction()) {
+ // Use ARM SDIV instruction for division. For remainder we also need to
+ // calculate using a MUL and subtract.
+ rl_src = LoadValue(rl_src, kCoreReg);
+ rl_result = GenDivRemLit(rl_dest, rl_src.low_reg, lit, is_div);
+ done = true;
+ }
+ }
+
+ if (!done) {
+ FlushAllRegs(); /* Everything to home location. */
LoadValueDirectFixed(rl_src, TargetReg(kArg0));
Clobber(TargetReg(kArg0));
ThreadOffset func_offset = QUICK_ENTRYPOINT_OFFSET(pIdivmod);
@@ -1583,7 +1613,7 @@
}
rl_src = LoadValue(rl_src, kCoreReg);
rl_result = EvalLoc(rl_dest, kCoreReg, true);
- // Avoid shifts by literal 0 - no support in Thumb. Change to copy
+ // Avoid shifts by literal 0 - no support in Thumb. Change to copy.
if (shift_op && (lit == 0)) {
OpRegCopy(rl_result.low_reg, rl_src.low_reg);
} else {