From c397d2951f2e78b6470e8fabf85e98b5965dad18 Mon Sep 17 00:00:00 2001 From: Weiliang Lin Date: Thu, 5 Feb 2015 10:54:13 +0800 Subject: [PATCH] x87: Use signaling NaN for holes in fixed double arrays. Port 9eace97bbaab72962c0fda62e5f9011a10604d0d BUG= R=chunyang.dai@intel.com Review URL: https://codereview.chromium.org/895473002 Cr-Commit-Position: refs/heads/master@{#26445} --- src/x87/lithium-codegen-x87.cc | 77 +++++++++++++++++----------------- src/x87/lithium-x87.cc | 2 +- src/x87/lithium-x87.h | 2 +- src/x87/macro-assembler-x87.cc | 26 +----------- 4 files changed, 43 insertions(+), 64 deletions(-) diff --git a/src/x87/lithium-codegen-x87.cc b/src/x87/lithium-codegen-x87.cc index c9c8a47593..618d2423e1 100644 --- a/src/x87/lithium-codegen-x87.cc +++ b/src/x87/lithium-codegen-x87.cc @@ -2001,10 +2001,9 @@ void LCodeGen::DoConstantS(LConstantS* instr) { void LCodeGen::DoConstantD(LConstantD* instr) { - double v = instr->value(); - uint64_t int_val = bit_cast(v); - int32_t lower = static_cast(int_val); - int32_t upper = static_cast(int_val >> (kBitsPerInt)); + uint64_t const bits = instr->bits(); + uint32_t const lower = static_cast(bits); + uint32_t const upper = static_cast(bits >> 32); DCHECK(instr->result()->IsDoubleRegister()); __ push(Immediate(upper)); @@ -2613,7 +2612,9 @@ void LCodeGen::DoCmpHoleAndBranch(LCmpHoleAndBranch* instr) { __ add(esp, Immediate(kDoubleSize)); int offset = sizeof(kHoleNanUpper32); - __ cmp(MemOperand(esp, -offset), Immediate(kHoleNanUpper32)); + // x87 converts sNaN(0xfff7fffffff7ffff) to QNaN(0xfffffffffff7ffff), + // so we check the upper with 0xffffffff for hole as a temporary fix. + __ cmp(MemOperand(esp, -offset), Immediate(0xffffffff)); EmitBranch(instr, equal); } @@ -4242,10 +4243,11 @@ void LCodeGen::DoMathLog(LMathLog* instr) { __ jmp(&done, Label::kNear); __ bind(&nan_result); - ExternalReference nan = - ExternalReference::address_of_canonical_non_hole_nan(); X87PrepareToWrite(input_reg); - __ fld_d(Operand::StaticVariable(nan)); + __ push(Immediate(0xffffffff)); + __ push(Immediate(0x7fffffff)); + __ fld_d(MemOperand(esp, 0)); + __ lea(esp, Operand(esp, kDoubleSize)); X87CommitWrite(input_reg); __ jmp(&done, Label::kNear); @@ -4640,8 +4642,6 @@ void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) { void LCodeGen::DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr) { - ExternalReference canonical_nan_reference = - ExternalReference::address_of_canonical_non_hole_nan(); Operand double_store_operand = BuildFastArrayOperand( instr->elements(), instr->key(), @@ -4649,25 +4649,21 @@ void LCodeGen::DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr) { FAST_DOUBLE_ELEMENTS, instr->base_offset()); - // Can't use SSE2 in the serializer + uint64_t int_val = kHoleNanInt64; + int32_t lower = static_cast(int_val); + int32_t upper = static_cast(int_val >> (kBitsPerInt)); + Operand double_store_operand2 = BuildFastArrayOperand( + instr->elements(), instr->key(), + instr->hydrogen()->key()->representation(), FAST_DOUBLE_ELEMENTS, + instr->base_offset() + kPointerSize); + if (instr->hydrogen()->IsConstantHoleStore()) { // This means we should store the (double) hole. No floating point // registers required. - double nan_double = FixedDoubleArray::hole_nan_as_double(); - uint64_t int_val = bit_cast(nan_double); - int32_t lower = static_cast(int_val); - int32_t upper = static_cast(int_val >> (kBitsPerInt)); - __ mov(double_store_operand, Immediate(lower)); - Operand double_store_operand2 = BuildFastArrayOperand( - instr->elements(), - instr->key(), - instr->hydrogen()->key()->representation(), - FAST_DOUBLE_ELEMENTS, - instr->base_offset() + kPointerSize); __ mov(double_store_operand2, Immediate(upper)); } else { - Label no_special_nan_handling; + Label no_special_nan_handling, done; X87Register value = ToX87Register(instr->value()); X87Fxch(value); @@ -4675,23 +4671,27 @@ void LCodeGen::DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr) { __ fld(0); __ fld(0); __ FCmp(); - __ j(parity_odd, &no_special_nan_handling, Label::kNear); - __ sub(esp, Immediate(kDoubleSize)); + // All NaNs are Canonicalized to 0x7fffffffffffffff + __ mov(double_store_operand, Immediate(0xffffffff)); + __ mov(double_store_operand2, Immediate(0x7fffffff)); + __ jmp(&done, Label::kNear); + } else { + __ lea(esp, Operand(esp, -kDoubleSize)); __ fst_d(MemOperand(esp, 0)); - __ cmp(MemOperand(esp, sizeof(kHoleNanLower32)), - Immediate(kHoleNanUpper32)); - __ add(esp, Immediate(kDoubleSize)); - Label canonicalize; - __ j(not_equal, &canonicalize, Label::kNear); - __ jmp(&no_special_nan_handling, Label::kNear); - __ bind(&canonicalize); - __ fstp(0); - __ fld_d(Operand::StaticVariable(canonical_nan_reference)); + __ lea(esp, Operand(esp, kDoubleSize)); + int offset = sizeof(kHoleNanUpper32); + // x87 converts sNaN(0xfff7fffffff7ffff) to QNaN(0xfffffffffff7ffff), + // so we check the upper with 0xffffffff for hole as a temporary fix. + __ cmp(MemOperand(esp, -offset), Immediate(0xffffffff)); + __ j(not_equal, &no_special_nan_handling, Label::kNear); + __ mov(double_store_operand, Immediate(lower)); + __ mov(double_store_operand2, Immediate(upper)); + __ jmp(&done, Label::kNear); } - __ bind(&no_special_nan_handling); __ fst_d(double_store_operand); + __ bind(&done); } } @@ -5189,9 +5189,10 @@ void LCodeGen::EmitNumberUntagDNoSSE2(LNumberUntagD* instr, Register input_reg, DeoptimizeIf(not_equal, instr, "not a heap number/undefined"); __ bind(&convert); - ExternalReference nan = - ExternalReference::address_of_canonical_non_hole_nan(); - __ fld_d(Operand::StaticVariable(nan)); + __ push(Immediate(0xffffffff)); + __ push(Immediate(0x7fffffff)); + __ fld_d(MemOperand(esp, 0)); + __ lea(esp, Operand(esp, kDoubleSize)); __ jmp(&done, Label::kNear); __ bind(&heap_number); diff --git a/src/x87/lithium-x87.cc b/src/x87/lithium-x87.cc index 3a52dc4b0f..a0e98e5719 100644 --- a/src/x87/lithium-x87.cc +++ b/src/x87/lithium-x87.cc @@ -1721,7 +1721,7 @@ LInstruction* LChunkBuilder::DoCompareObjectEqAndBranch( LInstruction* LChunkBuilder::DoCompareHoleAndBranch( HCompareHoleAndBranch* instr) { LOperand* value = UseRegisterAtStart(instr->value()); - return new(zone()) LCmpHoleAndBranch(value); + return new (zone()) LCmpHoleAndBranch(value); } diff --git a/src/x87/lithium-x87.h b/src/x87/lithium-x87.h index 5d27fcb7a3..3c3bb9fa81 100644 --- a/src/x87/lithium-x87.h +++ b/src/x87/lithium-x87.h @@ -1350,7 +1350,7 @@ class LConstantD FINAL : public LTemplateInstruction<1, 0, 1> { DECLARE_CONCRETE_INSTRUCTION(ConstantD, "constant-d") DECLARE_HYDROGEN_ACCESSOR(Constant) - double value() const { return hydrogen()->DoubleValue(); } + uint64_t bits() const { return hydrogen()->DoubleValueAsBits(); } }; diff --git a/src/x87/macro-assembler-x87.cc b/src/x87/macro-assembler-x87.cc index c29b597e52..41b93d9239 100644 --- a/src/x87/macro-assembler-x87.cc +++ b/src/x87/macro-assembler-x87.cc @@ -597,30 +597,8 @@ void MacroAssembler::StoreNumberToDoubleElements( fail, DONT_DO_SMI_CHECK); - // Double value, canonicalize NaN. - uint32_t offset = HeapNumber::kValueOffset + sizeof(kHoleNanLower32); - cmp(FieldOperand(maybe_number, offset), - Immediate(kNaNOrInfinityLowerBoundUpper32)); - j(greater_equal, &maybe_nan, Label::kNear); - - bind(¬_nan); - ExternalReference canonical_nan_reference = - ExternalReference::address_of_canonical_non_hole_nan(); fld_d(FieldOperand(maybe_number, HeapNumber::kValueOffset)); - bind(&have_double_value); - fstp_d(FieldOperand(elements, key, times_4, - FixedDoubleArray::kHeaderSize - elements_offset)); - jmp(&done); - - bind(&maybe_nan); - // Could be NaN or Infinity. If fraction is not zero, it's NaN, otherwise - // it's an Infinity, and the non-NaN code path applies. - j(greater, &is_nan, Label::kNear); - cmp(FieldOperand(maybe_number, HeapNumber::kValueOffset), Immediate(0)); - j(zero, ¬_nan); - bind(&is_nan); - fld_d(Operand::StaticVariable(canonical_nan_reference)); - jmp(&have_double_value, Label::kNear); + jmp(&done, Label::kNear); bind(&smi_value); // Value is a smi. Convert to a double and store. @@ -630,9 +608,9 @@ void MacroAssembler::StoreNumberToDoubleElements( push(scratch); fild_s(Operand(esp, 0)); pop(scratch); + bind(&done); fstp_d(FieldOperand(elements, key, times_4, FixedDoubleArray::kHeaderSize - elements_offset)); - bind(&done); }