Index: src/arm64/macro-assembler-arm64.cc |
diff --git a/src/arm64/macro-assembler-arm64.cc b/src/arm64/macro-assembler-arm64.cc |
index 0b2954e18f54ee9b78eeb5b6ff3a517e62b5876e..f85c28faff79a4a3f55f497994fb74908481c6a8 100644 |
--- a/src/arm64/macro-assembler-arm64.cc |
+++ b/src/arm64/macro-assembler-arm64.cc |
@@ -1222,6 +1222,64 @@ void MacroAssembler::AssertStackConsistency() { |
} |
+void MacroAssembler::AssertFPCRState(Register fpcr) { |
+ if (emit_debug_code()) { |
+ Label unexpected_mode, done; |
+ UseScratchRegisterScope temps(this); |
+ if (fpcr.IsNone()) { |
+ fpcr = temps.AcquireX(); |
+ Mrs(fpcr, FPCR); |
+ } |
+ |
+ // Settings overridden by ConfiugreFPCR(): |
+ // - Assert that default-NaN mode is set. |
+ Tbz(fpcr, DN_offset, &unexpected_mode); |
+ |
+ // Settings left to their default values: |
+ // - Assert that flush-to-zero is not set. |
+ Tbnz(fpcr, FZ_offset, &unexpected_mode); |
+ // - Assert that the rounding mode is nearest-with-ties-to-even. |
+ STATIC_ASSERT(FPTieEven == 0); |
+ Tst(fpcr, RMode_mask); |
+ B(eq, &done); |
+ |
+ Bind(&unexpected_mode); |
+ Abort(kUnexpectedFPCRMode); |
+ |
+ Bind(&done); |
+ } |
+} |
+ |
+ |
+void MacroAssembler::ConfigureFPCR() { |
+ UseScratchRegisterScope temps(this); |
+ Register fpcr = temps.AcquireX(); |
+ Mrs(fpcr, FPCR); |
+ |
+ // If necessary, enable default-NaN mode. The default values of the other FPCR |
+ // options should be suitable, and AssertFPCRState will verify that. |
+ Label no_write_required; |
+ Tbnz(fpcr, DN_offset, &no_write_required); |
+ |
+ Orr(fpcr, fpcr, DN_mask); |
+ Msr(FPCR, fpcr); |
+ |
+ Bind(&no_write_required); |
+ AssertFPCRState(fpcr); |
+} |
+ |
+ |
+void MacroAssembler::CanonicalizeNaN(const FPRegister& dst, |
+ const FPRegister& src) { |
+ AssertFPCRState(); |
+ |
+ // With DN=1 and RMode=FPTieEven, subtracting 0.0 preserves all inputs except |
+ // for NaNs, which become the default NaN. We use fsub rather than fadd |
+ // because sub preserves -0.0 inputs: -0.0 + 0.0 = 0.0, but -0.0 - 0.0 = -0.0. |
+ Fsub(dst, src, fp_zero); |
+} |
+ |
+ |
void MacroAssembler::LoadRoot(CPURegister destination, |
Heap::RootListIndex index) { |
// TODO(jbramley): Most root values are constants, and can be synthesized |
@@ -3888,7 +3946,6 @@ void MacroAssembler::StoreNumberToDoubleElements(Register value_reg, |
Register elements_reg, |
Register scratch1, |
FPRegister fpscratch1, |
- FPRegister fpscratch2, |
Label* fail, |
int elements_offset) { |
ASSERT(!AreAliased(value_reg, key_reg, elements_reg, scratch1)); |
@@ -3906,12 +3963,9 @@ void MacroAssembler::StoreNumberToDoubleElements(Register value_reg, |
fail, DONT_DO_SMI_CHECK); |
Ldr(fpscratch1, FieldMemOperand(value_reg, HeapNumber::kValueOffset)); |
- Fmov(fpscratch2, FixedDoubleArray::canonical_not_the_hole_nan_as_double()); |
- // Check for NaN by comparing the number to itself: NaN comparison will |
- // report unordered, indicated by the overflow flag being set. |
- Fcmp(fpscratch1, fpscratch1); |
- Fcsel(fpscratch1, fpscratch2, fpscratch1, vs); |
+ // Canonicalize NaNs. |
+ CanonicalizeNaN(fpscratch1); |
// Store the result. |
Bind(&store_num); |