From b51cdb32acd8b056752375e5f01d243033ec360c Mon Sep 17 00:00:00 2001 From: Andreas Gampe Date: Sun, 29 Mar 2015 17:32:48 -0700 Subject: [PATCH] ART: Arm32 optimizing compiler backend should honor sdiv We still support architectures that do not have sdiv. Issue: https://code.google.com/p/android/issues/detail?id=162257 Change-Id: I6d43620b7599f70a630668791a796a1703b62912 --- compiler/optimizing/code_generator_arm.cc | 99 +++++++++++++++++++++++-------- 1 file changed, 74 insertions(+), 25 deletions(-) diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc index 0f79d189b..1f95041a9 100644 --- a/compiler/optimizing/code_generator_arm.cc +++ b/compiler/optimizing/code_generator_arm.cc @@ -2087,16 +2087,32 @@ void InstructionCodeGeneratorARM::VisitMul(HMul* mul) { } void LocationsBuilderARM::VisitDiv(HDiv* div) { - LocationSummary::CallKind call_kind = div->GetResultType() == Primitive::kPrimLong - ? LocationSummary::kCall - : LocationSummary::kNoCall; + LocationSummary::CallKind call_kind = LocationSummary::kNoCall; + if (div->GetResultType() == Primitive::kPrimLong) { + // pLdiv runtime call. + call_kind = LocationSummary::kCall; + } else if (div->GetResultType() == Primitive::kPrimInt && + !codegen_->GetInstructionSetFeatures().HasDivideInstruction()) { + // pIdivmod runtime call. + call_kind = LocationSummary::kCall; + } + LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(div, call_kind); switch (div->GetResultType()) { case Primitive::kPrimInt: { - locations->SetInAt(0, Location::RequiresRegister()); - locations->SetInAt(1, Location::RequiresRegister()); - locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); + if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) { + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetInAt(1, Location::RequiresRegister()); + locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); + } else { + InvokeRuntimeCallingConvention calling_convention; + locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0))); + locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1))); + // Note: divrem will compute both the quotient and the remainder as the pair R0 and R1, but + // we only need the former. + locations->SetOut(Location::RegisterLocation(R0)); + } break; } case Primitive::kPrimLong: { @@ -2129,9 +2145,18 @@ void InstructionCodeGeneratorARM::VisitDiv(HDiv* div) { switch (div->GetResultType()) { case Primitive::kPrimInt: { - __ sdiv(out.AsRegister(), - first.AsRegister(), - second.AsRegister()); + if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) { + __ sdiv(out.AsRegister(), + first.AsRegister(), + second.AsRegister()); + } else { + InvokeRuntimeCallingConvention calling_convention; + DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegister()); + DCHECK_EQ(calling_convention.GetRegisterAt(1), second.AsRegister()); + DCHECK_EQ(R0, out.AsRegister()); + + codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pIdivmod), div, div->GetDexPc(), nullptr); + } break; } @@ -2169,17 +2194,32 @@ void InstructionCodeGeneratorARM::VisitDiv(HDiv* div) { void LocationsBuilderARM::VisitRem(HRem* rem) { Primitive::Type type = rem->GetResultType(); - LocationSummary::CallKind call_kind = type == Primitive::kPrimInt - ? LocationSummary::kNoCall - : LocationSummary::kCall; + + // Most remainders are implemented in the runtime. + LocationSummary::CallKind call_kind = LocationSummary::kCall; + if (rem->GetResultType() == Primitive::kPrimInt && + codegen_->GetInstructionSetFeatures().HasDivideInstruction()) { + // Have hardware divide instruction for int, do it with three instructions. + call_kind = LocationSummary::kNoCall; + } + LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(rem, call_kind); switch (type) { case Primitive::kPrimInt: { - locations->SetInAt(0, Location::RequiresRegister()); - locations->SetInAt(1, Location::RequiresRegister()); - locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); - locations->AddTemp(Location::RequiresRegister()); + if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) { + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetInAt(1, Location::RequiresRegister()); + locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); + locations->AddTemp(Location::RequiresRegister()); + } else { + InvokeRuntimeCallingConvention calling_convention; + locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0))); + locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1))); + // Note: divrem will compute both the quotient and the remainder as the pair R0 and R1, but + // we only need the latter. + locations->SetOut(Location::RegisterLocation(R1)); + } break; } case Primitive::kPrimLong: { @@ -2224,16 +2264,25 @@ void InstructionCodeGeneratorARM::VisitRem(HRem* rem) { Primitive::Type type = rem->GetResultType(); switch (type) { case Primitive::kPrimInt: { - Register reg1 = first.AsRegister(); - Register reg2 = second.AsRegister(); - Register temp = locations->GetTemp(0).AsRegister(); + if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) { + Register reg1 = first.AsRegister(); + Register reg2 = second.AsRegister(); + Register temp = locations->GetTemp(0).AsRegister(); + + // temp = reg1 / reg2 (integer division) + // temp = temp * reg2 + // dest = reg1 - temp + __ sdiv(temp, reg1, reg2); + __ mul(temp, temp, reg2); + __ sub(out.AsRegister(), reg1, ShifterOperand(temp)); + } else { + InvokeRuntimeCallingConvention calling_convention; + DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegister()); + DCHECK_EQ(calling_convention.GetRegisterAt(1), second.AsRegister()); + DCHECK_EQ(R1, out.AsRegister()); - // temp = reg1 / reg2 (integer division) - // temp = temp * reg2 - // dest = reg1 - temp - __ sdiv(temp, reg1, reg2); - __ mul(temp, temp, reg2); - __ sub(out.AsRegister(), reg1, ShifterOperand(temp)); + codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pIdivmod), rem, rem->GetDexPc(), nullptr); + } break; } -- 2.11.0