diff options
| author | 2017-03-28 12:46:53 +0000 | |
|---|---|---|
| committer | 2017-03-28 12:46:54 +0000 | |
| commit | 1082e0e46ddfae2ed9cc3d0a3d6025e7335ac239 (patch) | |
| tree | efd47e9a513486a79ed1efc6fed8d0dda15f326c /compiler/optimizing | |
| parent | 7359649f638859e265f252b2301a15c4b7bbafa4 (diff) | |
| parent | 53463ba8717fc93379ebf2b0c04a9a2c85382973 (diff) | |
Merge "Math.round float intrinsic for ARM."
Diffstat (limited to 'compiler/optimizing')
| -rw-r--r-- | compiler/optimizing/common_arm.h | 5 | ||||
| -rw-r--r-- | compiler/optimizing/intrinsics_arm_vixl.cc | 54 |
2 files changed, 58 insertions, 1 deletions
diff --git a/compiler/optimizing/common_arm.h b/compiler/optimizing/common_arm.h index e184745520..01304ac35b 100644 --- a/compiler/optimizing/common_arm.h +++ b/compiler/optimizing/common_arm.h @@ -66,6 +66,11 @@ inline vixl::aarch32::SRegister LowSRegisterFrom(Location location) { return vixl::aarch32::SRegister(location.AsFpuRegisterPairLow<vixl::aarch32::SRegister>()); } +inline vixl::aarch32::SRegister HighSRegisterFrom(Location location) { + DCHECK(location.IsFpuRegisterPair()) << location; + return vixl::aarch32::SRegister(location.AsFpuRegisterPairHigh<vixl::aarch32::SRegister>()); +} + inline vixl::aarch32::Register RegisterFrom(Location location) { DCHECK(location.IsRegister()) << location; return vixl::aarch32::Register(location.reg()); diff --git a/compiler/optimizing/intrinsics_arm_vixl.cc b/compiler/optimizing/intrinsics_arm_vixl.cc index b25bad7170..0d933eaf82 100644 --- a/compiler/optimizing/intrinsics_arm_vixl.cc +++ b/compiler/optimizing/intrinsics_arm_vixl.cc @@ -39,6 +39,7 @@ using helpers::Int32ConstantFrom; using helpers::LocationFrom; using helpers::LowRegisterFrom; using helpers::LowSRegisterFrom; +using helpers::HighSRegisterFrom; using helpers::OutputDRegister; using helpers::OutputSRegister; using helpers::OutputRegister; @@ -794,6 +795,58 @@ void IntrinsicCodeGeneratorARMVIXL::VisitMathRint(HInvoke* invoke) { __ Vrintn(F64, F64, OutputDRegister(invoke), InputDRegisterAt(invoke, 0)); } +void IntrinsicLocationsBuilderARMVIXL::VisitMathRoundFloat(HInvoke* invoke) { + if (features_.HasARMv8AInstructions()) { + LocationSummary* locations = new (arena_) LocationSummary(invoke, + LocationSummary::kNoCall, + kIntrinsified); + locations->SetInAt(0, Location::RequiresFpuRegister()); + locations->SetOut(Location::RequiresRegister()); + locations->AddTemp(Location::RequiresFpuRegister()); + } +} + +void IntrinsicCodeGeneratorARMVIXL::VisitMathRoundFloat(HInvoke* invoke) { + DCHECK(codegen_->GetInstructionSetFeatures().HasARMv8AInstructions()); + + ArmVIXLAssembler* assembler = GetAssembler(); + vixl32::SRegister in_reg = InputSRegisterAt(invoke, 0); + vixl32::Register out_reg = OutputRegister(invoke); + vixl32::SRegister temp1 = LowSRegisterFrom(invoke->GetLocations()->GetTemp(0)); + vixl32::SRegister temp2 = HighSRegisterFrom(invoke->GetLocations()->GetTemp(0)); + vixl32::Label done; + vixl32::Label* final_label = codegen_->GetFinalLabel(invoke, &done); + + // Round to nearest integer, ties away from zero. + __ Vcvta(S32, F32, temp1, in_reg); + __ Vmov(out_reg, temp1); + + // For positive, zero or NaN inputs, rounding is done. + __ Cmp(out_reg, 0); + __ B(ge, final_label, /* far_target */ false); + + // Handle input < 0 cases. + // If input is negative but not a tie, previous result (round to nearest) is valid. + // If input is a negative tie, change rounding direction to positive infinity, out_reg += 1. + __ Vrinta(F32, F32, temp1, in_reg); + __ Vmov(temp2, 0.5); + __ Vsub(F32, temp1, in_reg, temp1); + __ Vcmp(F32, temp1, temp2); + __ Vmrs(RegisterOrAPSR_nzcv(kPcCode), FPSCR); + { + // Use ExactAsemblyScope here because we are using IT. + ExactAssemblyScope it_scope(assembler->GetVIXLAssembler(), + 2 * kMaxInstructionSizeInBytes, + CodeBufferCheckScope::kMaximumSize); + __ it(eq); + __ add(eq, out_reg, out_reg, 1); + } + + if (done.IsReferenced()) { + __ Bind(&done); + } +} + void IntrinsicLocationsBuilderARMVIXL::VisitMemoryPeekByte(HInvoke* invoke) { CreateIntToIntLocations(arena_, invoke); } @@ -3100,7 +3153,6 @@ void IntrinsicCodeGeneratorARMVIXL::VisitIntegerValueOf(HInvoke* invoke) { } UNIMPLEMENTED_INTRINSIC(ARMVIXL, MathRoundDouble) // Could be done by changing rounding mode, maybe? -UNIMPLEMENTED_INTRINSIC(ARMVIXL, MathRoundFloat) // Could be done by changing rounding mode, maybe? UNIMPLEMENTED_INTRINSIC(ARMVIXL, UnsafeCASLong) // High register pressure. UNIMPLEMENTED_INTRINSIC(ARMVIXL, SystemArrayCopyChar) UNIMPLEMENTED_INTRINSIC(ARMVIXL, IntegerHighestOneBit) |