[optimizing compiler] Add REM_FLOAT and REM_DOUBLE
- for arm, x86, x86_64 backends
- reinstated fmod quick entry points for x86. This is a partial revert
of bd3682eada753de52975ae2b4a712bd87dc139a6 which added inline assembly
for floting point rem on x86. Note that Quick still uses the inline
version.
- fix rem tests for longs
Change-Id: I73be19a9f2f2bcf3f718d9ca636e67bdd72b5440
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc
index ca72f3f..0a3f830 100644
--- a/compiler/optimizing/builder.cc
+++ b/compiler/optimizing/builder.cc
@@ -1435,6 +1435,16 @@
break;
}
+ case Instruction::REM_FLOAT: {
+ Binop_23x<HRem>(instruction, Primitive::kPrimFloat, dex_pc);
+ break;
+ }
+
+ case Instruction::REM_DOUBLE: {
+ Binop_23x<HRem>(instruction, Primitive::kPrimDouble, dex_pc);
+ break;
+ }
+
case Instruction::AND_INT: {
Binop_23x<HAnd>(instruction, Primitive::kPrimInt);
break;
@@ -1574,6 +1584,16 @@
break;
}
+ case Instruction::REM_FLOAT_2ADDR: {
+ Binop_12x<HRem>(instruction, Primitive::kPrimFloat, dex_pc);
+ break;
+ }
+
+ case Instruction::REM_DOUBLE_2ADDR: {
+ Binop_12x<HRem>(instruction, Primitive::kPrimDouble, dex_pc);
+ break;
+ }
+
case Instruction::SHL_INT_2ADDR: {
Binop_12x_shift<HShl>(instruction, Primitive::kPrimInt);
break;
diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc
index 7f358ea..461409d 100644
--- a/compiler/optimizing/code_generator.cc
+++ b/compiler/optimizing/code_generator.cc
@@ -499,19 +499,27 @@
}
void CodeGenerator::RecordPcInfo(HInstruction* instruction, uint32_t dex_pc) {
- if (instruction != nullptr && instruction->IsTypeConversion()) {
+ if (instruction != nullptr) {
// The code generated for some type conversions may call the
// runtime, thus normally requiring a subsequent call to this
// method. However, the method verifier does not produce PC
- // information for Dex type conversion instructions, as it
- // considers them as "atomic" (they cannot join a GC).
+ // information for certain instructions, which are considered "atomic"
+ // (they cannot join a GC).
// Therefore we do not currently record PC information for such
// instructions. As this may change later, we added this special
// case so that code generators may nevertheless call
// CodeGenerator::RecordPcInfo without triggering an error in
// CodeGenerator::BuildNativeGCMap ("Missing ref for dex pc 0x")
// thereafter.
- return;
+ if (instruction->IsTypeConversion()) {
+ return;
+ }
+ if (instruction->IsRem()) {
+ Primitive::Type type = instruction->AsRem()->GetResultType();
+ if ((type == Primitive::kPrimFloat) || (type == Primitive::kPrimDouble)) {
+ return;
+ }
+ }
}
// Collect PC infos for the mapping table.
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index 36af393..cbe5f0c 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -44,7 +44,7 @@
static constexpr Register kRuntimeParameterCoreRegisters[] = { R0, R1, R2, R3 };
static constexpr size_t kRuntimeParameterCoreRegistersLength =
arraysize(kRuntimeParameterCoreRegisters);
-static constexpr SRegister kRuntimeParameterFpuRegisters[] = { S0, S1 };
+static constexpr SRegister kRuntimeParameterFpuRegisters[] = { S0, S1, S2, S3 };
static constexpr size_t kRuntimeParameterFpuRegistersLength =
arraysize(kRuntimeParameterFpuRegisters);
@@ -2132,12 +2132,13 @@
}
void LocationsBuilderARM::VisitRem(HRem* rem) {
- LocationSummary::CallKind call_kind = rem->GetResultType() == Primitive::kPrimLong
- ? LocationSummary::kCall
- : LocationSummary::kNoCall;
+ Primitive::Type type = rem->GetResultType();
+ LocationSummary::CallKind call_kind = type == Primitive::kPrimInt
+ ? LocationSummary::kNoCall
+ : LocationSummary::kCall;
LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(rem, call_kind);
- switch (rem->GetResultType()) {
+ switch (type) {
case Primitive::kPrimInt: {
locations->SetInAt(0, Location::RequiresRegister());
locations->SetInAt(1, Location::RequiresRegister());
@@ -2155,14 +2156,26 @@
locations->SetOut(Location::RegisterPairLocation(R2, R3));
break;
}
- case Primitive::kPrimFloat:
+ case Primitive::kPrimFloat: {
+ InvokeRuntimeCallingConvention calling_convention;
+ locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
+ locations->SetInAt(1, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(1)));
+ locations->SetOut(Location::FpuRegisterLocation(S0));
+ break;
+ }
+
case Primitive::kPrimDouble: {
- LOG(FATAL) << "Unimplemented rem type " << rem->GetResultType();
+ InvokeRuntimeCallingConvention calling_convention;
+ locations->SetInAt(0, Location::FpuRegisterPairLocation(
+ calling_convention.GetFpuRegisterAt(0), calling_convention.GetFpuRegisterAt(1)));
+ locations->SetInAt(1, Location::FpuRegisterPairLocation(
+ calling_convention.GetFpuRegisterAt(2), calling_convention.GetFpuRegisterAt(3)));
+ locations->SetOut(Location::Location::FpuRegisterPairLocation(S0, S1));
break;
}
default:
- LOG(FATAL) << "Unexpected rem type " << rem->GetResultType();
+ LOG(FATAL) << "Unexpected rem type " << type;
}
}
@@ -2172,7 +2185,8 @@
Location first = locations->InAt(0);
Location second = locations->InAt(1);
- switch (rem->GetResultType()) {
+ Primitive::Type type = rem->GetResultType();
+ switch (type) {
case Primitive::kPrimInt: {
Register reg1 = first.AsRegister<Register>();
Register reg2 = second.AsRegister<Register>();
@@ -2188,26 +2202,22 @@
}
case Primitive::kPrimLong: {
- 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.AsRegisterPairLow<Register>());
- DCHECK_EQ(calling_convention.GetRegisterAt(3), second.AsRegisterPairHigh<Register>());
- DCHECK_EQ(R2, out.AsRegisterPairLow<Register>());
- DCHECK_EQ(R3, out.AsRegisterPairHigh<Register>());
-
codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pLmod), rem, rem->GetDexPc());
break;
}
- case Primitive::kPrimFloat:
+ case Primitive::kPrimFloat: {
+ codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pFmodf), rem, rem->GetDexPc());
+ break;
+ }
+
case Primitive::kPrimDouble: {
- LOG(FATAL) << "Unimplemented rem type " << rem->GetResultType();
+ codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pFmod), rem, rem->GetDexPc());
break;
}
default:
- LOG(FATAL) << "Unexpected rem type " << rem->GetResultType();
+ LOG(FATAL) << "Unexpected rem type " << type;
}
}
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index 2fd712f..8a0c2de 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -2206,12 +2206,13 @@
}
void LocationsBuilderX86::VisitRem(HRem* rem) {
- LocationSummary::CallKind call_kind = rem->GetResultType() == Primitive::kPrimLong
- ? LocationSummary::kCall
- : LocationSummary::kNoCall;
+ Primitive::Type type = rem->GetResultType();
+ LocationSummary::CallKind call_kind = type == Primitive::kPrimInt
+ ? LocationSummary::kNoCall
+ : LocationSummary::kCall;
LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(rem, call_kind);
- switch (rem->GetResultType()) {
+ switch (type) {
case Primitive::kPrimInt: {
locations->SetInAt(0, Location::RegisterLocation(EAX));
locations->SetInAt(1, Location::RequiresRegister());
@@ -2228,14 +2229,29 @@
locations->SetOut(Location::RegisterPairLocation(EAX, EDX));
break;
}
- case Primitive::kPrimFloat:
+ case Primitive::kPrimFloat: {
+ InvokeRuntimeCallingConvention calling_convention;
+ // x86 floating-point parameters are passed through core registers (EAX, ECX).
+ locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
+ locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
+ // The runtime helper puts the result in XMM0.
+ locations->SetOut(Location::FpuRegisterLocation(XMM0));
+ break;
+ }
case Primitive::kPrimDouble: {
- LOG(FATAL) << "Unimplemented rem type " << rem->GetResultType();
+ InvokeRuntimeCallingConvention calling_convention;
+ // x86 floating-point parameters are passed through core registers (EAX_ECX, EDX_EBX).
+ locations->SetInAt(0, Location::RegisterPairLocation(
+ calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
+ locations->SetInAt(1, Location::RegisterPairLocation(
+ calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
+ // The runtime helper puts the result in XMM0.
+ locations->SetOut(Location::FpuRegisterLocation(XMM0));
break;
}
default:
- LOG(FATAL) << "Unexpected rem type " << rem->GetResultType();
+ LOG(FATAL) << "Unexpected rem type " << type;
}
}
@@ -2247,9 +2263,14 @@
GenerateDivRemIntegral(rem);
break;
}
- case Primitive::kPrimFloat:
+ case Primitive::kPrimFloat: {
+ __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pFmodf)));
+ codegen_->RecordPcInfo(rem, rem->GetDexPc());
+ break;
+ }
case Primitive::kPrimDouble: {
- LOG(FATAL) << "Unimplemented rem type " << type;
+ __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pFmod)));
+ codegen_->RecordPcInfo(rem, rem->GetDexPc());
break;
}
default:
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index 39a9766..233f4a4 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -43,8 +43,9 @@
static constexpr Register kRuntimeParameterCoreRegisters[] = { RDI, RSI, RDX };
static constexpr size_t kRuntimeParameterCoreRegistersLength =
arraysize(kRuntimeParameterCoreRegisters);
-static constexpr FloatRegister kRuntimeParameterFpuRegisters[] = { };
-static constexpr size_t kRuntimeParameterFpuRegistersLength = 0;
+static constexpr FloatRegister kRuntimeParameterFpuRegisters[] = { XMM0, XMM1 };
+static constexpr size_t kRuntimeParameterFpuRegistersLength =
+ arraysize(kRuntimeParameterFpuRegisters);
class InvokeRuntimeCallingConvention : public CallingConvention<Register, FloatRegister> {
public:
@@ -1999,16 +2000,16 @@
// 0x80000000(00000000)/-1 triggers an arithmetic exception!
// Dividing by -1 is actually negation and -0x800000000(00000000) = 0x80000000(00000000)
// so it's safe to just use negl instead of more complex comparisons.
-
- __ cmpl(second_reg, Immediate(-1));
- __ j(kEqual, slow_path->GetEntryLabel());
-
if (type == Primitive::kPrimInt) {
+ __ cmpl(second_reg, Immediate(-1));
+ __ j(kEqual, slow_path->GetEntryLabel());
// edx:eax <- sign-extended of eax
__ cdq();
// eax = quotient, edx = remainder
__ idivl(second_reg);
} else {
+ __ cmpq(second_reg, Immediate(-1));
+ __ j(kEqual, slow_path->GetEntryLabel());
// rdx:rax <- sign-extended of rax
__ cqo();
// rax = quotient, rdx = remainder
@@ -2075,9 +2076,14 @@
}
void LocationsBuilderX86_64::VisitRem(HRem* rem) {
- LocationSummary* locations =
- new (GetGraph()->GetArena()) LocationSummary(rem, LocationSummary::kNoCall);
- switch (rem->GetResultType()) {
+ Primitive::Type type = rem->GetResultType();
+ LocationSummary::CallKind call_kind =
+ (type == Primitive::kPrimInt) || (type == Primitive::kPrimLong)
+ ? LocationSummary::kNoCall
+ : LocationSummary::kCall;
+ LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(rem, call_kind);
+
+ switch (type) {
case Primitive::kPrimInt:
case Primitive::kPrimLong: {
locations->SetInAt(0, Location::RegisterLocation(RAX));
@@ -2089,12 +2095,16 @@
case Primitive::kPrimFloat:
case Primitive::kPrimDouble: {
- LOG(FATAL) << "Unimplemented rem type " << rem->GetResultType();
+ InvokeRuntimeCallingConvention calling_convention;
+ locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
+ locations->SetInAt(1, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(1)));
+ // The runtime helper puts the result in XMM0.
+ locations->SetOut(Location::FpuRegisterLocation(XMM0));
break;
}
default:
- LOG(FATAL) << "Unexpected rem type " << rem->GetResultType();
+ LOG(FATAL) << "Unexpected rem type " << type;
}
}
@@ -2106,13 +2116,16 @@
GenerateDivRemIntegral(rem);
break;
}
-
- case Primitive::kPrimFloat:
- case Primitive::kPrimDouble: {
- LOG(FATAL) << "Unimplemented rem type " << rem->GetResultType();
+ case Primitive::kPrimFloat: {
+ __ gs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pFmodf), true));
+ codegen_->RecordPcInfo(rem, rem->GetDexPc());
break;
}
-
+ case Primitive::kPrimDouble: {
+ __ gs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pFmod), true));
+ codegen_->RecordPcInfo(rem, rem->GetDexPc());
+ break;
+ }
default:
LOG(FATAL) << "Unexpected rem type " << rem->GetResultType();
}