Add X87 implementations for Integer32ToDouble, DoubleToI, DoubleToSmi
authorolivf@chromium.org <olivf@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 20 Aug 2013 13:01:54 +0000 (13:01 +0000)
committerolivf@chromium.org <olivf@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 20 Aug 2013 13:01:54 +0000 (13:01 +0000)
Additionally refactor the X87Stack tracking

BUG=
R=verwaest@chromium.org

Review URL: https://codereview.chromium.org/20781007

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@16246 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/ia32/assembler-ia32.cc
src/ia32/assembler-ia32.h
src/ia32/lithium-codegen-ia32.cc
src/ia32/lithium-codegen-ia32.h
src/ia32/lithium-ia32.h
test/mjsunit/regress/regress-x87.js [new file with mode: 0644]

index 7bea373..37218e5 100644 (file)
@@ -1641,6 +1641,13 @@ void Assembler::fstp_s(const Operand& adr) {
 }
 
 
+void Assembler::fst_s(const Operand& adr) {
+  EnsureSpace ensure_space(this);
+  EMIT(0xD9);
+  emit_operand(edx, adr);
+}
+
+
 void Assembler::fstp_d(const Operand& adr) {
   EnsureSpace ensure_space(this);
   EMIT(0xDD);
index 8380897..c102937 100644 (file)
@@ -929,6 +929,7 @@ class Assembler : public AssemblerBase {
   void fld_d(const Operand& adr);
 
   void fstp_s(const Operand& adr);
+  void fst_s(const Operand& adr);
   void fstp_d(const Operand& adr);
   void fst_d(const Operand& adr);
 
index 6dc0171..bffc062 100644 (file)
@@ -359,10 +359,9 @@ bool LCodeGen::GenerateBody() {
 
     instr->CompileToNative(this);
 
-    if (!CpuFeatures::IsSupported(SSE2)) {
-      if (FLAG_debug_code && FLAG_enable_slow_asserts) {
-        __ VerifyX87StackDepth(x87_stack_depth_);
-      }
+    if (!CpuFeatures::IsSupported(SSE2) &&
+        FLAG_debug_code && FLAG_enable_slow_asserts) {
+        __ VerifyX87StackDepth(x87_stack_.depth());
     }
   }
   EnsureSpaceForLazyDeopt();
@@ -497,21 +496,21 @@ XMMRegister LCodeGen::ToDoubleRegister(int index) const {
 
 
 void LCodeGen::X87LoadForUsage(X87Register reg) {
-  ASSERT(X87StackContains(reg));
-  X87Fxch(reg);
-  x87_stack_depth_--;
+  ASSERT(x87_stack_.Contains(reg));
+  x87_stack_.Fxch(reg);
+  x87_stack_.pop();
 }
 
 
-void LCodeGen::X87Fxch(X87Register reg, int other_slot) {
-  ASSERT(X87StackContains(reg) && x87_stack_depth_ > other_slot);
-  int i  = X87ArrayIndex(reg);
-  int st = x87_st2idx(i);
+void LCodeGen::X87Stack::Fxch(X87Register reg, int other_slot) {
+  ASSERT(Contains(reg) && stack_depth_ > other_slot);
+  int i  = ArrayIndex(reg);
+  int st = st2idx(i);
   if (st != other_slot) {
-    int other_i = x87_st2idx(other_slot);
-    X87Register other   = x87_stack_[other_i];
-    x87_stack_[other_i] = reg;
-    x87_stack_[i]       = other;
+    int other_i = st2idx(other_slot);
+    X87Register other stack_[other_i];
+    stack_[other_i]   = reg;
+    stack_[i]         = other;
     if (st == 0) {
       __ fxch(other_slot);
     } else if (other_slot == 0) {
@@ -525,88 +524,101 @@ void LCodeGen::X87Fxch(X87Register reg, int other_slot) {
 }
 
 
-int LCodeGen::x87_st2idx(int pos) {
-  return x87_stack_depth_ - pos - 1;
+int LCodeGen::X87Stack::st2idx(int pos) {
+  return stack_depth_ - pos - 1;
 }
 
 
-int LCodeGen::X87ArrayIndex(X87Register reg) {
-  for (int i = 0; i < x87_stack_depth_; i++) {
-    if (x87_stack_[i].is(reg)) return i;
+int LCodeGen::X87Stack::ArrayIndex(X87Register reg) {
+  for (int i = 0; i < stack_depth_; i++) {
+    if (stack_[i].is(reg)) return i;
   }
   UNREACHABLE();
   return -1;
 }
 
 
-bool LCodeGen::X87StackContains(X87Register reg) {
-  for (int i = 0; i < x87_stack_depth_; i++) {
-    if (x87_stack_[i].is(reg)) return true;
+bool LCodeGen::X87Stack::Contains(X87Register reg) {
+  for (int i = 0; i < stack_depth_; i++) {
+    if (stack_[i].is(reg)) return true;
   }
   return false;
 }
 
 
-void LCodeGen::X87Free(X87Register reg) {
-  ASSERT(X87StackContains(reg));
-  int i  = X87ArrayIndex(reg);
-  int st = x87_st2idx(i);
+void LCodeGen::X87Stack::Free(X87Register reg) {
+  ASSERT(Contains(reg));
+  int i  = ArrayIndex(reg);
+  int st = st2idx(i);
   if (st > 0) {
     // keep track of how fstp(i) changes the order of elements
-    int tos_i = x87_st2idx(0);
-    x87_stack_[i] = x87_stack_[tos_i];
+    int tos_i = st2idx(0);
+    stack_[i] = stack_[tos_i];
   }
-  x87_stack_depth_--;
+  pop();
   __ fstp(st);
 }
 
 
 void LCodeGen::X87Mov(X87Register dst, Operand src, X87OperandType opts) {
-  if (X87StackContains(dst)) {
-    X87Fxch(dst);
+  if (x87_stack_.Contains(dst)) {
+    x87_stack_.Fxch(dst);
     __ fstp(0);
   } else {
-    ASSERT(x87_stack_depth_ < X87Register::kNumAllocatableRegisters);
-    x87_stack_[x87_stack_depth_] = dst;
-    x87_stack_depth_++;
+    x87_stack_.push(dst);
   }
   X87Fld(src, opts);
 }
 
 
 void LCodeGen::X87Fld(Operand src, X87OperandType opts) {
-  if (opts == kX87DoubleOperand) {
-    __ fld_d(src);
-  } else if (opts == kX87FloatOperand) {
-    __ fld_s(src);
-  } else if (opts == kX87IntOperand) {
-    __ fild_s(src);
-  } else {
-    UNREACHABLE();
+  ASSERT(!src.is_reg_only());
+  switch (opts) {
+    case kX87DoubleOperand:
+      __ fld_d(src);
+      break;
+    case kX87FloatOperand:
+      __ fld_s(src);
+      break;
+    case kX87IntOperand:
+      __ fild_s(src);
+      break;
+    default:
+      UNREACHABLE();
   }
 }
 
 
-void LCodeGen::X87Mov(Operand dst, X87Register src) {
-  X87Fxch(src);
-  __ fst_d(dst);
+void LCodeGen::X87Mov(Operand dst, X87Register src, X87OperandType opts) {
+  ASSERT(!dst.is_reg_only());
+  x87_stack_.Fxch(src);
+  switch (opts) {
+    case kX87DoubleOperand:
+      __ fst_d(dst);
+      break;
+    case kX87IntOperand:
+      __ fist_s(dst);
+      break;
+    default:
+      UNREACHABLE();
+  }
 }
 
 
-void LCodeGen::X87PrepareToWrite(X87Register reg) {
-  if (X87StackContains(reg)) {
-    X87Free(reg);
+void LCodeGen::X87Stack::PrepareToWrite(X87Register reg) {
+  if (Contains(reg)) {
+    Free(reg);
   }
   // Mark this register as the next register to write to
-  x87_stack_[x87_stack_depth_] = reg;
+  stack_[stack_depth_] = reg;
 }
 
 
-void LCodeGen::X87CommitWrite(X87Register reg) {
+void LCodeGen::X87Stack::CommitWrite(X87Register reg) {
   // Assert the reg is prepared to write, but not on the virtual stack yet
-  ASSERT(!X87StackContains(reg) && x87_stack_[x87_stack_depth_].is(reg) &&
-      x87_stack_depth_ < X87Register::kNumAllocatableRegisters);
-  x87_stack_depth_++;
+  ASSERT(!Contains(reg) && stack_[stack_depth_].is(reg) &&
+      stack_depth_ < X87Register::kNumAllocatableRegisters);
+  stack_depth_++;
 }
 
 
@@ -614,38 +626,47 @@ void LCodeGen::X87PrepareBinaryOp(
     X87Register left, X87Register right, X87Register result) {
   // You need to use DefineSameAsFirst for x87 instructions
   ASSERT(result.is(left));
-  X87Fxch(right, 1);
-  X87Fxch(left);
+  x87_stack_.Fxch(right, 1);
+  x87_stack_.Fxch(left);
 }
 
 
-void LCodeGen::FlushX87StackIfNecessary(LInstruction* instr) {
-  if (x87_stack_depth_ > 0 && instr->ClobbersDoubleRegisters()) {
+void LCodeGen::X87Stack::FlushIfNecessary(LInstruction* instr, LCodeGen* cgen) {
+  if (stack_depth_ > 0 && instr->ClobbersDoubleRegisters()) {
     bool double_inputs = instr->HasDoubleRegisterInput();
 
     // Flush stack from tos down, since FreeX87() will mess with tos
-    for (int i = x87_stack_depth_-1; i >= 0; i--) {
-      X87Register reg = x87_stack_[i];
+    for (int i = stack_depth_-1; i >= 0; i--) {
+      X87Register reg = stack_[i];
       // Skip registers which contain the inputs for the next instruction
       // when flushing the stack
-      if (double_inputs && instr->IsDoubleInput(reg, this)) {
+      if (double_inputs && instr->IsDoubleInput(reg, cgen)) {
         continue;
       }
-      X87Free(reg);
-      if (i < x87_stack_depth_-1) i++;
+      Free(reg);
+      if (i < stack_depth_-1) i++;
     }
   }
   if (instr->IsReturn()) {
-    while (x87_stack_depth_ > 0) {
+    while (stack_depth_ > 0) {
       __ fstp(0);
-      x87_stack_depth_--;
+      stack_depth_--;
     }
   }
 }
 
 
 void LCodeGen::EmitFlushX87ForDeopt() {
-  for (int i = 0; i < x87_stack_depth_; i++) __ fstp(0);
+  // The deoptimizer does not support X87 Registers. But as long as we
+  // deopt from a stub its not a problem, since we will re-materialize the
+  // original stub inputs, which can't be double registers.
+  ASSERT(info()->IsStub());
+  if (FLAG_debug_code && FLAG_enable_slow_asserts) {
+    __ pushfd();
+    __ VerifyX87StackDepth(x87_stack_.depth());
+    __ popfd();
+  }
+  for (int i = 0; i < x87_stack_.depth(); i++) __ fstp(0);
 }
 
 
@@ -1003,7 +1024,7 @@ void LCodeGen::DeoptimizeIf(Condition cc,
   // we can have inputs or outputs of the current instruction on the stack,
   // thus we need to flush them here from the physical stack to leave it in a
   // consistent state.
-  if (x87_stack_depth_ > 0) {
+  if (x87_stack_.depth() > 0) {
     Label done;
     if (cc != no_condition) __ j(NegateCondition(cc), &done, Label::kNear);
     EmitFlushX87ForDeopt();
@@ -1865,15 +1886,16 @@ void LCodeGen::DoConstantD(LConstantD* instr) {
   uint64_t int_val = BitCast<uint64_t, double>(v);
   int32_t lower = static_cast<int32_t>(int_val);
   int32_t upper = static_cast<int32_t>(int_val >> (kBitsPerInt));
+  ASSERT(instr->result()->IsDoubleRegister());
 
   if (!CpuFeatures::IsSafeForSnapshot(SSE2)) {
     __ push(Immediate(upper));
     __ push(Immediate(lower));
-    X87Mov(ToX87Register(instr->result()), Operand(esp, 0));
+    X87Register reg = ToX87Register(instr->result());
+    X87Mov(reg, Operand(esp, 0));
     __ add(Operand(esp), Immediate(kDoubleSize));
   } else {
     CpuFeatureScope scope1(masm(), SSE2);
-    ASSERT(instr->result()->IsDoubleRegister());
     XMMRegister res = ToDoubleRegister(instr->result());
     if (int_val == 0) {
       __ xorps(res, res);
@@ -2266,7 +2288,6 @@ void LCodeGen::DoIsNumberAndBranch(LIsNumberAndBranch* instr) {
 void LCodeGen::DoBranch(LBranch* instr) {
   Representation r = instr->hydrogen()->value()->representation();
   if (r.IsSmiOrInteger32()) {
-    ASSERT(!info()->IsStub());
     Register reg = ToRegister(instr->value());
     __ test(reg, Operand(reg));
     EmitBranch(instr, not_zero);
@@ -4874,15 +4895,20 @@ void LCodeGen::DoStringAdd(LStringAdd* instr) {
 
 
 void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) {
+  LOperand* input = instr->value();
+  LOperand* output = instr->result();
+  ASSERT(input->IsRegister() || input->IsStackSlot());
+  ASSERT(output->IsDoubleRegister());
   if (CpuFeatures::IsSupported(SSE2)) {
     CpuFeatureScope scope(masm(), SSE2);
-    LOperand* input = instr->value();
-    ASSERT(input->IsRegister() || input->IsStackSlot());
-    LOperand* output = instr->result();
-    ASSERT(output->IsDoubleRegister());
     __ cvtsi2sd(ToDoubleRegister(output), ToOperand(input));
+  } else if (input->IsRegister()) {
+    Register input_reg = ToRegister(input);
+    __ push(input_reg);
+    X87Mov(ToX87Register(output), Operand(esp, 0), kX87IntOperand);
+    __ pop(input_reg);
   } else {
-    UNREACHABLE();
+    X87Mov(ToX87Register(output), ToOperand(input), kX87IntOperand);
   }
 }
 
@@ -5570,44 +5596,75 @@ void LCodeGen::DoDoubleToI(LDoubleToI* instr) {
   ASSERT(input->IsDoubleRegister());
   LOperand* result = instr->result();
   ASSERT(result->IsRegister());
-  CpuFeatureScope scope(masm(), SSE2);
-
-  XMMRegister input_reg = ToDoubleRegister(input);
   Register result_reg = ToRegister(result);
 
-  __ cvttsd2si(result_reg, Operand(input_reg));
+  Label done;
+  if (CpuFeatures::IsSafeForSnapshot(SSE2)) {
+    CpuFeatureScope scope(masm(), SSE2);
 
-  if (instr->truncating()) {
-    // Performs a truncating conversion of a floating point number as used by
-    // the JS bitwise operations.
-    Label fast_case_succeeded;
-    __ cmp(result_reg, 0x80000000u);
-    __ j(not_equal, &fast_case_succeeded);
-    __ sub(esp, Immediate(kDoubleSize));
-    __ movdbl(MemOperand(esp, 0), input_reg);
-    DoubleToIStub stub(esp, result_reg, 0, true);
-    __ call(stub.GetCode(isolate()), RelocInfo::CODE_TARGET);
-    __ add(esp, Immediate(kDoubleSize));
-    __ bind(&fast_case_succeeded);
+    XMMRegister input_reg = ToDoubleRegister(input);
+
+    __ cvttsd2si(result_reg, Operand(input_reg));
+
+    if (instr->truncating()) {
+      // Performs a truncating conversion of a floating point number as used by
+      // the JS bitwise operations.
+      Label fast_case_succeeded;
+      __ cmp(result_reg, 0x80000000u);
+      __ j(not_equal, &fast_case_succeeded);
+      __ sub(esp, Immediate(kDoubleSize));
+      __ movdbl(MemOperand(esp, 0), input_reg);
+      DoubleToIStub stub(esp, result_reg, 0, true);
+      __ call(stub.GetCode(isolate()), RelocInfo::CODE_TARGET);
+      __ add(esp, Immediate(kDoubleSize));
+      __ bind(&fast_case_succeeded);
+    } else {
+      __ cvtsi2sd(xmm0, Operand(result_reg));
+      __ ucomisd(xmm0, input_reg);
+      DeoptimizeIf(not_equal, instr->environment());
+      DeoptimizeIf(parity_even, instr->environment());  // NaN.
+      if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
+        // The integer converted back is equal to the original. We
+        // only have to test if we got -0 as an input.
+        __ test(result_reg, Operand(result_reg));
+        __ j(not_zero, &done, Label::kNear);
+        __ movmskpd(result_reg, input_reg);
+        // Bit 0 contains the sign of the double in input_reg.
+        // If input was positive, we are ok and return 0, otherwise
+        // deoptimize.
+        __ and_(result_reg, 1);
+        DeoptimizeIf(not_zero, instr->environment());
+      }
+      __ bind(&done);
+    }
   } else {
-    Label done;
-    __ cvtsi2sd(xmm0, Operand(result_reg));
-    __ ucomisd(xmm0, input_reg);
-    DeoptimizeIf(not_equal, instr->environment());
-    DeoptimizeIf(parity_even, instr->environment());  // NaN.
+    X87Register input_reg = ToX87Register(input);
+    __ push(result_reg);
+    X87Mov(Operand(esp, 0), input_reg, kX87IntOperand);
+    if (instr->truncating()) {
+      __ pop(result_reg);
+    } else {
+      X87Fxch(input_reg);
+      __ fld(0);
+      __ fild_s(Operand(esp, 0));
+      __ pop(result_reg);
+      __ FCmp();
+      DeoptimizeIf(not_equal, instr->environment());
+      DeoptimizeIf(parity_even, instr->environment());  // NaN.
+    }
     if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
-      // The integer converted back is equal to the original. We
-      // only have to test if we got -0 as an input.
       __ test(result_reg, Operand(result_reg));
       __ j(not_zero, &done, Label::kNear);
-      __ movmskpd(result_reg, input_reg);
-      // Bit 0 contains the sign of the double in input_reg.
-      // If input was positive, we are ok and return 0, otherwise
-      // deoptimize.
-      __ and_(result_reg, 1);
+      // To check for minus zero, we load the value again as float, and check
+      // if that is still 0.
+      X87Fxch(input_reg);
+      __ push(result_reg);
+      __ fst_s(Operand(esp, 0));
+      __ pop(result_reg);
+      __ test(result_reg, Operand(result_reg));
       DeoptimizeIf(not_zero, instr->environment());
+      __ bind(&done);
     }
-    __ bind(&done);
   }
 }
 
@@ -5617,30 +5674,56 @@ void LCodeGen::DoDoubleToSmi(LDoubleToSmi* instr) {
   ASSERT(input->IsDoubleRegister());
   LOperand* result = instr->result();
   ASSERT(result->IsRegister());
-  CpuFeatureScope scope(masm(), SSE2);
-
-  XMMRegister input_reg = ToDoubleRegister(input);
   Register result_reg = ToRegister(result);
 
   Label done;
-  __ cvttsd2si(result_reg, Operand(input_reg));
-  __ cvtsi2sd(xmm0, Operand(result_reg));
-  __ ucomisd(xmm0, input_reg);
-  DeoptimizeIf(not_equal, instr->environment());
-  DeoptimizeIf(parity_even, instr->environment());  // NaN.
+  if (CpuFeatures::IsSafeForSnapshot(SSE2)) {
+    CpuFeatureScope scope(masm(), SSE2);
 
-  if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
-    // The integer converted back is equal to the original. We
-    // only have to test if we got -0 as an input.
-    __ test(result_reg, Operand(result_reg));
-    __ j(not_zero, &done, Label::kNear);
-    __ movmskpd(result_reg, input_reg);
-    // Bit 0 contains the sign of the double in input_reg.
-    // If input was positive, we are ok and return 0, otherwise
-    // deoptimize.
-    __ and_(result_reg, 1);
-    DeoptimizeIf(not_zero, instr->environment());
-    __ bind(&done);
+    XMMRegister input_reg = ToDoubleRegister(input);
+
+    __ cvttsd2si(result_reg, Operand(input_reg));
+    __ cvtsi2sd(xmm0, Operand(result_reg));
+    __ ucomisd(xmm0, input_reg);
+    DeoptimizeIf(not_equal, instr->environment());
+    DeoptimizeIf(parity_even, instr->environment());  // NaN.
+    if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
+      // The integer converted back is equal to the original. We
+      // only have to test if we got -0 as an input.
+      __ test(result_reg, Operand(result_reg));
+      __ j(not_zero, &done, Label::kNear);
+      __ movmskpd(result_reg, input_reg);
+      // Bit 0 contains the sign of the double in input_reg.
+      // If input was positive, we are ok and return 0, otherwise
+      // deoptimize.
+      __ and_(result_reg, 1);
+      DeoptimizeIf(not_zero, instr->environment());
+      __ bind(&done);
+    }
+  } else {
+    X87Register input_reg = ToX87Register(input);
+    X87Fxch(input_reg);
+    __ push(result_reg);
+    X87Mov(Operand(esp, 0), input_reg, kX87IntOperand);
+    __ fld(0);
+    __ fild_s(Operand(esp, 0));
+    __ pop(result_reg);
+    __ FCmp();
+    DeoptimizeIf(not_equal, instr->environment());
+    DeoptimizeIf(parity_even, instr->environment());  // NaN.
+
+    if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
+      __ test(result_reg, Operand(result_reg));
+      __ j(not_zero, &done, Label::kNear);
+      // To check for minus zero, we load the value again as float, and check
+      // if that is still 0.
+      __ push(result_reg);
+      __ fst_s(Operand(esp, 0));
+      __ pop(result_reg);
+      __ test(result_reg, Operand(result_reg));
+      DeoptimizeIf(not_zero, instr->environment());
+      __ bind(&done);
+    }
   }
   __ SmiTag(result_reg);
   DeoptimizeIf(overflow, instr->environment());
index e498f53..5a474b6 100644 (file)
@@ -68,7 +68,7 @@ class LCodeGen V8_FINAL BASE_EMBEDDED {
         osr_pc_offset_(-1),
         last_lazy_deopt_pc_(0),
         frame_is_built_(false),
-        x87_stack_depth_(0),
+        x87_stack_(assembler),
         safepoints_(info->zone()),
         resolver_(this),
         expected_safepoint_kind_(Safepoint::kSimple),
@@ -122,14 +122,23 @@ class LCodeGen V8_FINAL BASE_EMBEDDED {
 
   void X87Mov(X87Register reg, Operand src,
       X87OperandType operand = kX87DoubleOperand);
-  void X87Mov(Operand src, X87Register reg);
+  void X87Mov(Operand src, X87Register reg,
+      X87OperandType operand = kX87DoubleOperand);
 
   void X87PrepareBinaryOp(
       X87Register left, X87Register right, X87Register result);
 
   void X87LoadForUsage(X87Register reg);
-  void X87PrepareToWrite(X87Register reg);
-  void X87CommitWrite(X87Register reg);
+  void X87PrepareToWrite(X87Register reg) { x87_stack_.PrepareToWrite(reg); }
+  void X87CommitWrite(X87Register reg) { x87_stack_.CommitWrite(reg); }
+
+  void X87Fxch(X87Register reg, int other_slot = 0) {
+    x87_stack_.Fxch(reg, other_slot);
+  }
+
+  bool X87StackEmpty() {
+    return x87_stack_.depth() == 0;
+  }
 
   Handle<Object> ToHandle(LConstantOperand* op) const;
 
@@ -399,15 +408,13 @@ class LCodeGen V8_FINAL BASE_EMBEDDED {
   // register, or a stack slot operand.
   void EmitPushTaggedOperand(LOperand* operand);
 
-  void X87Fxch(X87Register reg, int other_slot = 0);
   void X87Fld(Operand src, X87OperandType opts);
-  void X87Free(X87Register reg);
 
-  void FlushX87StackIfNecessary(LInstruction* instr);
   void EmitFlushX87ForDeopt();
-  bool X87StackContains(X87Register reg);
-  int X87ArrayIndex(X87Register reg);
-  int x87_st2idx(int pos);
+  void FlushX87StackIfNecessary(LInstruction* instr) {
+    x87_stack_.FlushIfNecessary(instr, this);
+  }
+  friend class LGapResolver;
 
 #ifdef _MSC_VER
   // On windows, you may not access the stack more than one page below
@@ -438,8 +445,48 @@ class LCodeGen V8_FINAL BASE_EMBEDDED {
   int osr_pc_offset_;
   int last_lazy_deopt_pc_;
   bool frame_is_built_;
-  X87Register x87_stack_[X87Register::kNumAllocatableRegisters];
-  int x87_stack_depth_;
+
+  class X87Stack {
+   public:
+    explicit X87Stack(MacroAssembler* masm) : stack_depth_(0), masm_(masm) { }
+    explicit X87Stack(const X87Stack& other)
+        : stack_depth_(0), masm_(other.masm_) {
+      stack_depth_ = other.stack_depth_;
+      for (int i = 0; i < stack_depth_; i++) {
+        stack_[i] = other.stack_[i];
+      }
+    }
+    bool operator==(const X87Stack& other) const {
+      if (stack_depth_ != other.stack_depth_) return false;
+      for (int i = 0; i < stack_depth_; i++) {
+        if (!stack_[i].is(other.stack_[i])) return false;
+      }
+      return true;
+    }
+    bool Contains(X87Register reg);
+    void Fxch(X87Register reg, int other_slot = 0);
+    void Free(X87Register reg);
+    void PrepareToWrite(X87Register reg);
+    void CommitWrite(X87Register reg);
+    void FlushIfNecessary(LInstruction* instr, LCodeGen* cgen);
+    int depth() const { return stack_depth_; }
+    void pop() { stack_depth_--; }
+    void push(X87Register reg) {
+      ASSERT(stack_depth_ < X87Register::kNumAllocatableRegisters);
+      stack_[stack_depth_] = reg;
+      stack_depth_++;
+    }
+
+    MacroAssembler* masm() const { return masm_; }
+
+   private:
+    int ArrayIndex(X87Register reg);
+    int st2idx(int pos);
+    X87Register stack_[X87Register::kNumAllocatableRegisters];
+    int stack_depth_;
+    MacroAssembler* const masm_;
+  };
+  X87Stack x87_stack_;
 
   // Builder that keeps track of safepoints in the code. The table
   // itself is emitted at the end of the generated code.
index f35c777..a6a2526 100644 (file)
@@ -277,10 +277,9 @@ class LInstruction : public ZoneObject {
   bool ClobbersRegisters() const { return IsCall(); }
   virtual bool ClobbersDoubleRegisters() const {
     return IsCall() ||
-      (!CpuFeatures::IsSupported(SSE2) &&
-       // We only have rudimentary X87Stack tracking, thus in general
-       // cannot handle deoptimization nor phi-nodes.
-       (HasEnvironment() || IsControl()));
+           // We only have rudimentary X87Stack tracking, thus in general
+           // cannot handle phi-nodes.
+           (!CpuFeatures::IsSafeForSnapshot(SSE2) && IsControl());
   }
 
   virtual bool HasResult() const = 0;
@@ -1542,11 +1541,6 @@ class LLoadNamedField V8_FINAL : public LTemplateInstruction<1, 1, 0> {
     inputs_[0] = object;
   }
 
-  virtual bool ClobbersDoubleRegisters() const {
-    return !CpuFeatures::IsSupported(SSE2) &&
-        !hydrogen()->representation().IsDouble();
-  }
-
   LOperand* object() { return inputs_[0]; }
 
   DECLARE_CONCRETE_INSTRUCTION(LoadNamedField, "load-named-field")
@@ -2206,8 +2200,6 @@ class LNumberUntagD V8_FINAL : public LTemplateInstruction<1, 1, 1> {
   LOperand* value() { return inputs_[0]; }
   LOperand* temp() { return temps_[0]; }
 
-  virtual bool ClobbersDoubleRegisters() const V8_OVERRIDE { return false; }
-
   DECLARE_CONCRETE_INSTRUCTION(NumberUntagD, "double-untag")
   DECLARE_HYDROGEN_ACCESSOR(Change);
 };
diff --git a/test/mjsunit/regress/regress-x87.js b/test/mjsunit/regress/regress-x87.js
new file mode 100644 (file)
index 0000000..60380a8
--- /dev/null
@@ -0,0 +1,48 @@
+// Copyright 2013 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --allow-natives-syntax --noenable-sse2
+
+// Regression for register allocation.
+var x;
+var a = new Float32Array([1,2, 4, 6, 8, 11, NaN, 1/0, -3])
+var val = 2.1*a[1]*a[0]*a[1*2*3*0]*a[1*1]*1.0;
+assertEquals(8.4, val);
+
+// Regression for double-phis
+var a;
+var t = true;
+var res = [2.5, 2];
+for (var i = 0; i < 2; i++) {
+  if (t) {
+    a = 1.5;
+  } else {
+    a = true;
+  }
+  assertEquals(res[i], a+1);
+  t = false;
+}