diff options
| -rw-r--r-- | compiler/dex/quick/arm/fp_arm.cc | 26 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_arm.cc | 66 | ||||
| -rw-r--r-- | runtime/arch/arm/entrypoints_init_arm.cc | 2 | ||||
| -rw-r--r-- | runtime/arch/arm/quick_entrypoints_arm.S | 15 | ||||
| -rw-r--r-- | runtime/entrypoints/quick/quick_default_externs.h | 1 | ||||
| -rw-r--r-- | test/477-long-to-float-conversion-precision/info.txt | 2 | ||||
| -rw-r--r-- | test/477-long-to-float-conversion-precision/src/Main.java | 5 | ||||
| -rw-r--r-- | test/Android.run-test.mk | 23 |
8 files changed, 39 insertions, 101 deletions
diff --git a/compiler/dex/quick/arm/fp_arm.cc b/compiler/dex/quick/arm/fp_arm.cc index 94fc4743a4..1a5c1080ff 100644 --- a/compiler/dex/quick/arm/fp_arm.cc +++ b/compiler/dex/quick/arm/fp_arm.cc @@ -191,30 +191,8 @@ void ArmMir2Lir::GenConversion(Instruction::Code opcode, RegLocation rl_dest, Re GenConversionCall(kQuickF2l, rl_dest, rl_src, kCoreReg); return; case Instruction::LONG_TO_FLOAT: { - rl_src = LoadValueWide(rl_src, kFPReg); - RegisterInfo* info = GetRegInfo(rl_src.reg); - RegStorage src_low = info->FindMatchingView(RegisterInfo::kLowSingleStorageMask)->GetReg(); - DCHECK(src_low.Valid()); - RegStorage src_high = info->FindMatchingView(RegisterInfo::kHighSingleStorageMask)->GetReg(); - DCHECK(src_high.Valid()); - rl_result = EvalLoc(rl_dest, kFPReg, true); - // Allocate temp registers. - RegStorage high_val = AllocTempDouble(); - RegStorage low_val = AllocTempDouble(); - RegStorage const_val = AllocTempDouble(); - // Long to double. - NewLIR2(kThumb2VcvtF64S32, high_val.GetReg(), src_high.GetReg()); - NewLIR2(kThumb2VcvtF64U32, low_val.GetReg(), src_low.GetReg()); - LoadConstantWide(const_val, INT64_C(0x41f0000000000000)); - NewLIR3(kThumb2VmlaF64, low_val.GetReg(), high_val.GetReg(), const_val.GetReg()); - // Double to float. - NewLIR2(kThumb2VcvtDF, rl_result.reg.GetReg(), low_val.GetReg()); - // Free temp registers. - FreeTemp(high_val); - FreeTemp(low_val); - FreeTemp(const_val); - // Store result. - StoreValue(rl_dest, rl_result); + CheckEntrypointTypes<kQuickL2f, float, int64_t>(); // float -> kFPReg + GenConversionCall(kQuickL2f, rl_dest, rl_src, kFPReg); return; } case Instruction::DOUBLE_TO_LONG: diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc index 987a6c4ff7..1c68654522 100644 --- a/compiler/optimizing/code_generator_arm.cc +++ b/compiler/optimizing/code_generator_arm.cc @@ -1456,11 +1456,12 @@ void LocationsBuilderARM::VisitTypeConversion(HTypeConversion* conversion) { Primitive::Type input_type = conversion->GetInputType(); DCHECK_NE(result_type, input_type); - // The float-to-long and double-to-long type conversions rely on a - // call to the runtime. + // The float-to-long, double-to-long and long-to-float type conversions + // rely on a call to the runtime. LocationSummary::CallKind call_kind = - ((input_type == Primitive::kPrimFloat || input_type == Primitive::kPrimDouble) - && result_type == Primitive::kPrimLong) + (((input_type == Primitive::kPrimFloat || input_type == Primitive::kPrimDouble) + && result_type == Primitive::kPrimLong) + || (input_type == Primitive::kPrimLong && result_type == Primitive::kPrimFloat)) ? LocationSummary::kCall : LocationSummary::kNoCall; LocationSummary* locations = @@ -1603,15 +1604,14 @@ void LocationsBuilderARM::VisitTypeConversion(HTypeConversion* conversion) { locations->SetOut(Location::RequiresFpuRegister()); break; - case Primitive::kPrimLong: + case Primitive::kPrimLong: { // Processing a Dex `long-to-float' instruction. - locations->SetInAt(0, Location::RequiresRegister()); - locations->SetOut(Location::RequiresFpuRegister()); - locations->AddTemp(Location::RequiresRegister()); - locations->AddTemp(Location::RequiresRegister()); - locations->AddTemp(Location::RequiresFpuRegister()); - locations->AddTemp(Location::RequiresFpuRegister()); + InvokeRuntimeCallingConvention calling_convention; + locations->SetInAt(0, Location::RegisterPairLocation( + calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1))); + locations->SetOut(Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0))); break; + } case Primitive::kPrimDouble: // Processing a Dex `double-to-float' instruction. @@ -1820,47 +1820,13 @@ void InstructionCodeGeneratorARM::VisitTypeConversion(HTypeConversion* conversio break; } - case Primitive::kPrimLong: { + case Primitive::kPrimLong: // Processing a Dex `long-to-float' instruction. - Register low = in.AsRegisterPairLow<Register>(); - Register high = in.AsRegisterPairHigh<Register>(); - SRegister output = out.AsFpuRegister<SRegister>(); - Register constant_low = locations->GetTemp(0).AsRegister<Register>(); - Register constant_high = locations->GetTemp(1).AsRegister<Register>(); - SRegister temp1_s = locations->GetTemp(2).AsFpuRegisterPairLow<SRegister>(); - DRegister temp1_d = FromLowSToD(temp1_s); - SRegister temp2_s = locations->GetTemp(3).AsFpuRegisterPairLow<SRegister>(); - DRegister temp2_d = FromLowSToD(temp2_s); - - // Operations use doubles for precision reasons (each 32-bit - // half of a long fits in the 53-bit mantissa of a double, - // but not in the 24-bit mantissa of a float). This is - // especially important for the low bits. The result is - // eventually converted to float. - - // temp1_d = int-to-double(high) - __ vmovsr(temp1_s, high); - __ vcvtdi(temp1_d, temp1_s); - // Using vmovd to load the `k2Pow32EncodingForDouble` constant - // as an immediate value into `temp2_d` does not work, as - // this instruction only transfers 8 significant bits of its - // immediate operand. Instead, use two 32-bit core - // registers to load `k2Pow32EncodingForDouble` into - // `temp2_d`. - __ LoadImmediate(constant_low, Low32Bits(k2Pow32EncodingForDouble)); - __ LoadImmediate(constant_high, High32Bits(k2Pow32EncodingForDouble)); - __ vmovdrr(temp2_d, constant_low, constant_high); - // temp1_d = temp1_d * 2^32 - __ vmuld(temp1_d, temp1_d, temp2_d); - // temp2_d = unsigned-to-double(low) - __ vmovsr(temp2_s, low); - __ vcvtdu(temp2_d, temp2_s); - // temp1_d = temp1_d + temp2_d - __ vaddd(temp1_d, temp1_d, temp2_d); - // output = double-to-float(temp1_d); - __ vcvtsd(output, temp1_d); + codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pL2f), + conversion, + conversion->GetDexPc(), + nullptr); break; - } case Primitive::kPrimDouble: // Processing a Dex `double-to-float' instruction. diff --git a/runtime/arch/arm/entrypoints_init_arm.cc b/runtime/arch/arm/entrypoints_init_arm.cc index cafc868789..2f2654d4f6 100644 --- a/runtime/arch/arm/entrypoints_init_arm.cc +++ b/runtime/arch/arm/entrypoints_init_arm.cc @@ -127,11 +127,13 @@ void InitEntryPoints(InterpreterEntryPoints* ipoints, JniEntryPoints* jpoints, qpoints->pFmodf = fmodf; qpoints->pD2l = art_d2l; qpoints->pF2l = art_f2l; + qpoints->pL2f = art_l2f; } else { qpoints->pFmod = art_quick_fmod; qpoints->pFmodf = art_quick_fmodf; qpoints->pD2l = art_quick_d2l; qpoints->pF2l = art_quick_f2l; + qpoints->pL2f = art_quick_l2f; } // Intrinsics diff --git a/runtime/arch/arm/quick_entrypoints_arm.S b/runtime/arch/arm/quick_entrypoints_arm.S index 064f5a6d98..2e7f34ef6d 100644 --- a/runtime/arch/arm/quick_entrypoints_arm.S +++ b/runtime/arch/arm/quick_entrypoints_arm.S @@ -1468,3 +1468,18 @@ ENTRY art_quick_f2l vmov r0, s0 b art_f2l END art_quick_f2l + + /* float art_l2f(int64_t l) */ + .extern art_l2f +ENTRY art_quick_l2f + push {lr} + .cfi_adjust_cfa_offset 4 + .cfi_rel_offset lr, 0 + sub sp, #4 + .cfi_adjust_cfa_offset 4 + bl art_l2f + vmov s0, r0 + add sp, #4 + .cfi_adjust_cfa_offset -4 + pop {pc} +END art_quick_l2f diff --git a/runtime/entrypoints/quick/quick_default_externs.h b/runtime/entrypoints/quick/quick_default_externs.h index c7aaa2021f..a64e818241 100644 --- a/runtime/entrypoints/quick/quick_default_externs.h +++ b/runtime/entrypoints/quick/quick_default_externs.h @@ -80,6 +80,7 @@ extern "C" void art_quick_unlock_object(art::mirror::Object*); // Math entrypoints. extern "C" int64_t art_quick_d2l(double); extern "C" int64_t art_quick_f2l(float); +extern "C" float art_quick_l2f (int64_t); extern "C" int64_t art_quick_ldiv(int64_t, int64_t); extern "C" int64_t art_quick_lmod(int64_t, int64_t); extern "C" int64_t art_quick_lmul(int64_t, int64_t); diff --git a/test/477-long-to-float-conversion-precision/info.txt b/test/477-long-to-float-conversion-precision/info.txt index d9d41d70ba..1e07cf3f0b 100644 --- a/test/477-long-to-float-conversion-precision/info.txt +++ b/test/477-long-to-float-conversion-precision/info.txt @@ -1 +1 @@ -Tests for type conversions precision. +Regression test for type conversion precision. diff --git a/test/477-long-to-float-conversion-precision/src/Main.java b/test/477-long-to-float-conversion-precision/src/Main.java index bc17053e20..cd9703943d 100644 --- a/test/477-long-to-float-conversion-precision/src/Main.java +++ b/test/477-long-to-float-conversion-precision/src/Main.java @@ -30,9 +30,8 @@ public class Main { } private static void longToFloat() { - // The result for this test case is slightly less accurate on ARM, - // due to the implementation of long-to-float type conversions for - // this architecture (both in Quick and Optimizing). + // The result for this test case used to be slightly less accurate + // on ARM (both in Quick and Optimizing). assertFloatEquals(Float.intBitsToFloat(-555858671), $opt$LongToFloat(-8008112895877447681L)); } diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk index d224f43728..fa13fe5c64 100644 --- a/test/Android.run-test.mk +++ b/test/Android.run-test.mk @@ -387,29 +387,6 @@ endif TEST_ART_BROKEN_DEFAULT_RUN_TESTS := -# Known broken tests for Quick's and Optimizing's ARM back ends. -TEST_ART_BROKEN_ARM_RUN_TESTS := 477-long-to-float-conversion-precision # b/20413424 - -ifeq ($(TARGET_ARCH),arm) - ifneq (,$(filter 32,$(ALL_ADDRESS_SIZES))) - ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,target,$(RUN_TYPES),$(PREBUILD_TYPES), \ - $(COMPILER_TYPES),$(RELOCATE_TYPES),$(TRACE_TYPES),$(GC_TYPES),$(JNI_TYPES), \ - $(IMAGE_TYPES),$(PICTEST_TYPES),$(DEBUGGABLE_TYPES),$(TEST_ART_BROKEN_ARM_RUN_TESTS),32) - endif -endif - -ifdef TARGET_2ND_ARCH - ifeq ($(TARGET_2ND_ARCH),arm) - ifneq (,$(filter 32,$(ALL_ADDRESS_SIZES))) - ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,target,$(RUN_TYPES),$(PREBUILD_TYPES), \ - $(COMPILER_TYPES),$(RELOCATE_TYPES),$(TRACE_TYPES),$(GC_TYPES),$(JNI_TYPES), \ - $(IMAGE_TYPES),$(PICTEST_TYPES),$(DEBUGGABLE_TYPES),$(TEST_ART_BROKEN_ARM_RUN_TESTS),32) - endif - endif -endif - -TEST_ART_BROKEN_ARM_RUN_TESTS := - # Known broken tests for the arm64 optimizing compiler backend. TEST_ART_BROKEN_OPTIMIZING_ARM64_RUN_TESTS := |