summaryrefslogtreecommitdiffstats
path: root/compiler/optimizing/code_generator_arm.cc
diff options
context:
space:
mode:
authorCalin Juravle <calin@google.com>2015-03-25 17:15:21 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2015-03-25 17:15:22 +0000
commit39b4bf99a1167cd9d5e5454059dd360e67f1eac1 (patch)
tree1536a13873faa1031901d003fb987522598c381f /compiler/optimizing/code_generator_arm.cc
parent3679a47027b40290018d0ccc50b996a15645dfef (diff)
parentab4a2f5995b79c2b5b28c91b419a2c91cb88e377 (diff)
downloadart-39b4bf99a1167cd9d5e5454059dd360e67f1eac1.tar.gz
art-39b4bf99a1167cd9d5e5454059dd360e67f1eac1.tar.bz2
art-39b4bf99a1167cd9d5e5454059dd360e67f1eac1.zip
Merge changes I4b3b4d90,I70e0d78f,I2848636f
* changes: Forbid the use of shifts in ShifterOperand in Thumb2 Make subs and adds alter flags when rn is an immediate Inline long shift code
Diffstat (limited to 'compiler/optimizing/code_generator_arm.cc')
-rw-r--r--compiler/optimizing/code_generator_arm.cc74
1 files changed, 51 insertions, 23 deletions
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index 5a79a692d1..97c470b730 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -2326,10 +2326,8 @@ void InstructionCodeGeneratorARM::VisitDivZeroCheck(HDivZeroCheck* instruction)
void LocationsBuilderARM::HandleShift(HBinaryOperation* op) {
DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
- LocationSummary::CallKind call_kind = op->GetResultType() == Primitive::kPrimLong
- ? LocationSummary::kCall
- : LocationSummary::kNoCall;
- LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(op, call_kind);
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(op, LocationSummary::kNoCall);
switch (op->GetResultType()) {
case Primitive::kPrimInt: {
@@ -2339,12 +2337,10 @@ void LocationsBuilderARM::HandleShift(HBinaryOperation* op) {
break;
}
case Primitive::kPrimLong: {
- InvokeRuntimeCallingConvention calling_convention;
- locations->SetInAt(0, Location::RegisterPairLocation(
- calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
- locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
- // The runtime helper puts the output in R0,R1.
- locations->SetOut(Location::RegisterPairLocation(R0, R1));
+ locations->SetInAt(0, Location::RequiresRegister());
+ locations->SetInAt(1, Location::RequiresRegister());
+ locations->AddTemp(Location::RequiresRegister());
+ locations->SetOut(Location::RequiresRegister());
break;
}
default:
@@ -2392,24 +2388,56 @@ void InstructionCodeGeneratorARM::HandleShift(HBinaryOperation* op) {
break;
}
case Primitive::kPrimLong: {
- // TODO: Inline the assembly instead of calling the runtime.
- InvokeRuntimeCallingConvention calling_convention;
- DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegisterPairLow<Register>());
- DCHECK_EQ(calling_convention.GetRegisterAt(1), first.AsRegisterPairHigh<Register>());
- DCHECK_EQ(calling_convention.GetRegisterAt(2), second.AsRegister<Register>());
- DCHECK_EQ(R0, out.AsRegisterPairLow<Register>());
- DCHECK_EQ(R1, out.AsRegisterPairHigh<Register>());
+ Register o_h = out.AsRegisterPairHigh<Register>();
+ Register o_l = out.AsRegisterPairLow<Register>();
+
+ Register temp = locations->GetTemp(0).AsRegister<Register>();
+
+ Register high = first.AsRegisterPairHigh<Register>();
+ Register low = first.AsRegisterPairLow<Register>();
+
+ Register second_reg = second.AsRegister<Register>();
- int32_t entry_point_offset;
if (op->IsShl()) {
- entry_point_offset = QUICK_ENTRY_POINT(pShlLong);
+ // Shift the high part
+ __ and_(second_reg, second_reg, ShifterOperand(63));
+ __ Lsl(o_h, high, second_reg);
+ // Shift the low part and `or` what overflew on the high part
+ __ rsb(temp, second_reg, ShifterOperand(32));
+ __ Lsr(temp, low, temp);
+ __ orr(o_h, o_h, ShifterOperand(temp));
+ // If the shift is > 32 bits, override the high part
+ __ subs(temp, second_reg, ShifterOperand(32));
+ __ it(PL);
+ __ Lsl(o_h, low, temp, false, PL);
+ // Shift the low part
+ __ Lsl(o_l, low, second_reg);
} else if (op->IsShr()) {
- entry_point_offset = QUICK_ENTRY_POINT(pShrLong);
+ // Shift the low part
+ __ and_(second_reg, second_reg, ShifterOperand(63));
+ __ Lsr(o_l, low, second_reg);
+ // Shift the high part and `or` what underflew on the low part
+ __ rsb(temp, second_reg, ShifterOperand(32));
+ __ Lsl(temp, high, temp);
+ __ orr(o_l, o_l, ShifterOperand(temp));
+ // If the shift is > 32 bits, override the low part
+ __ subs(temp, second_reg, ShifterOperand(32));
+ __ it(PL);
+ __ Asr(o_l, high, temp, false, PL);
+ // Shift the high part
+ __ Asr(o_h, high, second_reg);
} else {
- entry_point_offset = QUICK_ENTRY_POINT(pUshrLong);
+ // same as Shr except we use `Lsr`s and not `Asr`s
+ __ and_(second_reg, second_reg, ShifterOperand(63));
+ __ Lsr(o_l, low, second_reg);
+ __ rsb(temp, second_reg, ShifterOperand(32));
+ __ Lsl(temp, high, temp);
+ __ orr(o_l, o_l, ShifterOperand(temp));
+ __ subs(temp, second_reg, ShifterOperand(32));
+ __ it(PL);
+ __ Lsr(o_l, high, temp, false, PL);
+ __ Lsr(o_h, high, second_reg);
}
- __ LoadFromOffset(kLoadWord, LR, TR, entry_point_offset);
- __ blx(LR);
break;
}
default: