x87: Use signaling NaN for holes in fixed double arrays.
authorWeiliang Lin <weiliang.lin@intel.com>
Thu, 5 Feb 2015 02:54:13 +0000 (10:54 +0800)
committerWeiliang Lin <weiliang.lin@intel.com>
Thu, 5 Feb 2015 02:53:57 +0000 (02:53 +0000)
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
src/x87/lithium-x87.cc
src/x87/lithium-x87.h
src/x87/macro-assembler-x87.cc

index c9c8a47..618d242 100644 (file)
@@ -2001,10 +2001,9 @@ void LCodeGen::DoConstantS(LConstantS* instr) {
 
 
 void LCodeGen::DoConstantD(LConstantD* instr) {
-  double v = instr->value();
-  uint64_t int_val = bit_cast<uint64_t, double>(v);
-  int32_t lower = static_cast<int32_t>(int_val);
-  int32_t upper = static_cast<int32_t>(int_val >> (kBitsPerInt));
+  uint64_t const bits = instr->bits();
+  uint32_t const lower = static_cast<uint32_t>(bits);
+  uint32_t const upper = static_cast<uint32_t>(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<int32_t>(int_val);
+  int32_t upper = static_cast<int32_t>(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<uint64_t, double>(nan_double);
-    int32_t lower = static_cast<int32_t>(int_val);
-    int32_t upper = static_cast<int32_t>(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);
index 3a52dc4..a0e98e5 100644 (file)
@@ -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);
 }
 
 
index 5d27fcb..3c3bb9f 100644 (file)
@@ -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(); }
 };
 
 
index c29b597..41b93d9 100644 (file)
@@ -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(&not_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, &not_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);
 }