Index: src/ia32/lithium-codegen-ia32.cc |
diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc |
index ac82dcfd41eda2687d40349c382b7e7fceee8820..16cff91b8c31ce65a6690d4a91eb68f9f407c89a 100644 |
--- a/src/ia32/lithium-codegen-ia32.cc |
+++ b/src/ia32/lithium-codegen-ia32.cc |
@@ -353,7 +353,6 @@ bool LCodeGen::GenerateBody() { |
instr->CompileToNative(this); |
if (!CpuFeatures::IsSupported(SSE2)) { |
- ASSERT(!instr->HasDoubleRegisterResult() || x87_stack_depth_ == 1); |
if (FLAG_debug_code && FLAG_enable_slow_asserts) { |
__ VerifyX87StackDepth(x87_stack_depth_); |
} |
@@ -501,68 +500,181 @@ Register LCodeGen::ToRegister(int index) const { |
} |
+X87Register LCodeGen::ToX87Register(int index) const { |
+ return X87Register::FromAllocationIndex(index); |
+} |
+ |
+ |
XMMRegister LCodeGen::ToDoubleRegister(int index) const { |
return XMMRegister::FromAllocationIndex(index); |
} |
-bool LCodeGen::IsX87TopOfStack(LOperand* op) const { |
- return op->IsDoubleRegister(); |
+void LCodeGen::X87LoadForUsage(X87Register reg) { |
+ ASSERT(X87StackContains(reg)); |
+ X87Fxch(reg); |
+ x87_stack_depth_--; |
} |
-void LCodeGen::ReadX87Operand(Operand dst) { |
- ASSERT(x87_stack_depth_ == 1); |
- __ fst_d(dst); |
+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); |
+ 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; |
+ if (st == 0) { |
+ __ fxch(other_slot); |
+ } else if (other_slot == 0) { |
+ __ fxch(st); |
+ } else { |
+ __ fxch(st); |
+ __ fxch(other_slot); |
+ __ fxch(st); |
+ } |
+ } |
} |
-void LCodeGen::PushX87DoubleOperand(Operand src) { |
- ASSERT(x87_stack_depth_ == 0); |
- x87_stack_depth_++; |
- __ fld_d(src); |
+int LCodeGen::x87_st2idx(int pos) { |
+ return x87_stack_depth_ - pos - 1; |
} |
-void LCodeGen::PushX87FloatOperand(Operand src) { |
- ASSERT(x87_stack_depth_ == 0); |
- x87_stack_depth_++; |
- __ fld_s(src); |
+int LCodeGen::X87ArrayIndex(X87Register reg) { |
+ for (int i = 0; i < x87_stack_depth_; i++) { |
+ if (x87_stack_[i].is(reg)) return i; |
+ } |
+ UNREACHABLE(); |
+ return -1; |
} |
-void LCodeGen::PopX87() { |
- ASSERT(x87_stack_depth_ == 1); |
+bool LCodeGen::X87StackContains(X87Register reg) { |
+ for (int i = 0; i < x87_stack_depth_; i++) { |
+ if (x87_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); |
+ 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]; |
+ } |
x87_stack_depth_--; |
- __ fstp(0); |
+ __ fstp(st); |
} |
-void LCodeGen::CurrentInstructionReturnsX87Result() { |
- ASSERT(x87_stack_depth_ <= 1); |
- if (x87_stack_depth_ == 0) { |
- x87_stack_depth_ = 1; |
+void LCodeGen::X87Mov(X87Register dst, Operand src, X87OperandType opts) { |
+ if (X87StackContains(dst)) { |
+ X87Fxch(dst); |
+ __ fstp(0); |
+ } else { |
+ ASSERT(x87_stack_depth_ < X87Register::kNumAllocatableRegisters); |
+ x87_stack_[x87_stack_depth_] = dst; |
+ x87_stack_depth_++; |
} |
+ 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(); |
+ } |
+} |
+ |
+ |
+void LCodeGen::X87Mov(Operand dst, X87Register src) { |
+ X87Fxch(src); |
+ __ fst_d(dst); |
+} |
+ |
+ |
+void LCodeGen::X87PrepareToWrite(X87Register reg) { |
+ if (X87StackContains(reg)) { |
+ X87Free(reg); |
+ } |
+ // Mark this register as the next register to write to |
+ x87_stack_[x87_stack_depth_] = reg; |
+} |
+ |
+ |
+void LCodeGen::X87CommitWrite(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_++; |
+} |
+ |
+ |
+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); |
} |
void LCodeGen::FlushX87StackIfNecessary(LInstruction* instr) { |
- if (x87_stack_depth_ > 0) { |
- if ((instr->ClobbersDoubleRegisters() || |
- instr->HasDoubleRegisterResult()) && |
- !instr->HasDoubleRegisterInput()) { |
- PopX87(); |
+ if (x87_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]; |
+ // Skip registers which contain the inputs for the next instruction |
+ // when flushing the stack |
+ if (double_inputs && instr->IsDoubleInput(reg, this)) { |
+ continue; |
+ } |
+ X87Free(reg); |
+ if (i < x87_stack_depth_-1) i++; |
+ } |
+ } |
+ if (instr->IsReturn()) { |
+ while (x87_stack_depth_ > 0) { |
+ __ fstp(0); |
+ x87_stack_depth_--; |
} |
} |
} |
+void LCodeGen::EmitFlushX87ForDeopt() { |
+ for (int i = 0; i < x87_stack_depth_; i++) __ fstp(0); |
+} |
+ |
+ |
Register LCodeGen::ToRegister(LOperand* op) const { |
ASSERT(op->IsRegister()); |
return ToRegister(op->index()); |
} |
+X87Register LCodeGen::ToX87Register(LOperand* op) const { |
+ ASSERT(op->IsDoubleRegister()); |
+ return ToX87Register(op->index()); |
+} |
+ |
+ |
XMMRegister LCodeGen::ToDoubleRegister(LOperand* op) const { |
ASSERT(op->IsDoubleRegister()); |
return ToDoubleRegister(op->index()); |
@@ -835,8 +947,6 @@ void LCodeGen::DeoptimizeIf(Condition cc, |
Deoptimizer::BailoutType bailout_type) { |
RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt); |
ASSERT(environment->HasBeenRegistered()); |
- // It's an error to deoptimize with the x87 fp stack in use. |
- ASSERT(x87_stack_depth_ == 0); |
int id = environment->deoptimization_index(); |
ASSERT(info()->IsOptimizing() || info()->IsStub()); |
Address entry = |
@@ -874,11 +984,20 @@ void LCodeGen::DeoptimizeIf(Condition cc, |
__ popfd(); |
} |
+ // Before Instructions which can deopt, we normally flush the x87 stack. But |
+ // 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) { |
+ Label done; |
+ if (cc != no_condition) __ j(NegateCondition(cc), &done, Label::kNear); |
+ EmitFlushX87ForDeopt(); |
+ __ bind(&done); |
+ } |
+ |
if (FLAG_trap_on_deopt && info()->IsOptimizing()) { |
Label done; |
- if (cc != no_condition) { |
- __ j(NegateCondition(cc), &done, Label::kNear); |
- } |
+ if (cc != no_condition) __ j(NegateCondition(cc), &done, Label::kNear); |
__ int3(); |
__ bind(&done); |
} |
@@ -1721,11 +1840,10 @@ void LCodeGen::DoConstantD(LConstantD* instr) { |
int32_t upper = static_cast<int32_t>(int_val >> (kBitsPerInt)); |
if (!CpuFeatures::IsSafeForSnapshot(SSE2)) { |
- __ push(Immediate(lower)); |
__ push(Immediate(upper)); |
- PushX87DoubleOperand(Operand(esp, 0)); |
+ __ push(Immediate(lower)); |
+ X87Mov(ToX87Register(instr->result()), Operand(esp, 0)); |
__ add(Operand(esp), Immediate(kDoubleSize)); |
- CurrentInstructionReturnsX87Result(); |
} else { |
CpuFeatureScope scope1(masm(), SSE2); |
ASSERT(instr->result()->IsDoubleRegister()); |
@@ -1990,62 +2108,67 @@ void LCodeGen::DoMathMinMax(LMathMinMax* instr) { |
void LCodeGen::DoArithmeticD(LArithmeticD* instr) { |
- CpuFeatureScope scope(masm(), SSE2); |
- XMMRegister left = ToDoubleRegister(instr->left()); |
- XMMRegister right = ToDoubleRegister(instr->right()); |
- XMMRegister result = ToDoubleRegister(instr->result()); |
- // Modulo uses a fixed result register. |
- ASSERT(instr->op() == Token::MOD || left.is(result)); |
- switch (instr->op()) { |
- case Token::ADD: |
- __ addsd(left, right); |
- break; |
- case Token::SUB: |
- __ subsd(left, right); |
- break; |
- case Token::MUL: |
- __ mulsd(left, right); |
- break; |
- case Token::DIV: |
- __ divsd(left, right); |
- // Don't delete this mov. It may improve performance on some CPUs, |
- // when there is a mulsd depending on the result |
- __ movaps(left, left); |
- break; |
- case Token::MOD: { |
- // Pass two doubles as arguments on the stack. |
- __ PrepareCallCFunction(4, eax); |
- __ movdbl(Operand(esp, 0 * kDoubleSize), left); |
- __ movdbl(Operand(esp, 1 * kDoubleSize), right); |
- __ CallCFunction( |
- ExternalReference::double_fp_operation(Token::MOD, isolate()), |
- 4); |
- |
- // Return value is in st(0) on ia32. |
- // Store it into the (fixed) result register. |
- __ sub(Operand(esp), Immediate(kDoubleSize)); |
- __ fstp_d(Operand(esp, 0)); |
- __ movdbl(result, Operand(esp, 0)); |
- __ add(Operand(esp), Immediate(kDoubleSize)); |
- break; |
+ if (CpuFeatures::IsSafeForSnapshot(SSE2)) { |
+ CpuFeatureScope scope(masm(), SSE2); |
+ XMMRegister left = ToDoubleRegister(instr->left()); |
+ XMMRegister right = ToDoubleRegister(instr->right()); |
+ XMMRegister result = ToDoubleRegister(instr->result()); |
+ // Modulo uses a fixed result register. |
+ ASSERT(instr->op() == Token::MOD || left.is(result)); |
+ switch (instr->op()) { |
+ case Token::ADD: |
+ __ addsd(left, right); |
+ break; |
+ case Token::SUB: |
+ __ subsd(left, right); |
+ break; |
+ case Token::MUL: |
+ __ mulsd(left, right); |
+ break; |
+ case Token::DIV: |
+ __ divsd(left, right); |
+ // Don't delete this mov. It may improve performance on some CPUs, |
+ // when there is a mulsd depending on the result |
+ __ movaps(left, left); |
+ break; |
+ case Token::MOD: { |
+ // Pass two doubles as arguments on the stack. |
+ __ PrepareCallCFunction(4, eax); |
+ __ movdbl(Operand(esp, 0 * kDoubleSize), left); |
+ __ movdbl(Operand(esp, 1 * kDoubleSize), right); |
+ __ CallCFunction( |
+ ExternalReference::double_fp_operation(Token::MOD, isolate()), |
+ 4); |
+ |
+ // Return value is in st(0) on ia32. |
+ // Store it into the (fixed) result register. |
+ __ sub(Operand(esp), Immediate(kDoubleSize)); |
+ __ fstp_d(Operand(esp, 0)); |
+ __ movdbl(result, Operand(esp, 0)); |
+ __ add(Operand(esp), Immediate(kDoubleSize)); |
+ break; |
+ } |
+ default: |
+ UNREACHABLE(); |
+ break; |
+ } |
+ } else { |
+ X87Register left = ToX87Register(instr->left()); |
+ X87Register right = ToX87Register(instr->right()); |
+ X87Register result = ToX87Register(instr->result()); |
+ X87PrepareBinaryOp(left, right, result); |
+ switch (instr->op()) { |
+ case Token::MUL: |
+ __ fmul_i(1); |
+ break; |
+ default: |
+ UNREACHABLE(); |
+ break; |
} |
- default: |
- UNREACHABLE(); |
- break; |
} |
} |
-void LCodeGen::DoNegateNoSSE2D(LNegateNoSSE2D* instr) { |
- __ push(Immediate(-1)); |
- __ fild_s(Operand(esp, 0)); |
- __ add(esp, Immediate(kPointerSize)); |
- __ fmulp(); |
- CurrentInstructionReturnsX87Result(); |
-} |
- |
- |
- |
void LCodeGen::DoArithmeticT(LArithmeticT* instr) { |
ASSERT(ToRegister(instr->context()).is(esi)); |
ASSERT(ToRegister(instr->left()).is(edx)); |
@@ -2963,8 +3086,7 @@ void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) { |
XMMRegister result = ToDoubleRegister(instr->result()); |
__ movdbl(result, FieldOperand(object, offset)); |
} else { |
- PushX87DoubleOperand(FieldOperand(object, offset)); |
- CurrentInstructionReturnsX87Result(); |
+ X87Mov(ToX87Register(instr->result()), FieldOperand(object, offset)); |
} |
return; |
} |
@@ -3209,16 +3331,14 @@ void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) { |
__ movss(result, operand); |
__ cvtss2sd(result, result); |
} else { |
- PushX87FloatOperand(operand); |
- CurrentInstructionReturnsX87Result(); |
+ X87Mov(ToX87Register(instr->result()), operand, kX87FloatOperand); |
} |
} else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) { |
if (CpuFeatures::IsSupported(SSE2)) { |
CpuFeatureScope scope(masm(), SSE2); |
__ movdbl(ToDoubleRegister(instr->result()), operand); |
} else { |
- PushX87DoubleOperand(operand); |
- CurrentInstructionReturnsX87Result(); |
+ X87Mov(ToX87Register(instr->result()), operand); |
} |
} else { |
Register result(ToRegister(instr->result())); |
@@ -3289,8 +3409,7 @@ void LCodeGen::DoLoadKeyedFixedDoubleArray(LLoadKeyed* instr) { |
XMMRegister result = ToDoubleRegister(instr->result()); |
__ movdbl(result, double_load_operand); |
} else { |
- PushX87DoubleOperand(double_load_operand); |
- CurrentInstructionReturnsX87Result(); |
+ X87Mov(ToX87Register(instr->result()), double_load_operand); |
} |
} |
@@ -4284,7 +4403,8 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) { |
XMMRegister value = ToDoubleRegister(instr->value()); |
__ movdbl(FieldOperand(object, offset), value); |
} else { |
- __ fstp_d(FieldOperand(object, offset)); |
+ X87Register value = ToX87Register(instr->value()); |
+ X87Mov(FieldOperand(object, offset), value); |
} |
return; |
} |
@@ -4410,7 +4530,7 @@ void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) { |
CpuFeatureScope scope(masm(), SSE2); |
__ movdbl(operand, ToDoubleRegister(instr->value())); |
} else { |
- __ fst_d(operand); |
+ X87Mov(operand, ToX87Register(instr->value())); |
} |
} else { |
Register value = ToRegister(instr->value()); |
@@ -4492,7 +4612,8 @@ void LCodeGen::DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr) { |
__ mov(double_store_operand2, Immediate(upper)); |
} else { |
Label no_special_nan_handling; |
- ASSERT(x87_stack_depth_ > 0); |
+ X87Register value = ToX87Register(instr->value()); |
+ X87Fxch(value); |
if (instr->NeedsCanonicalization()) { |
__ fld(0); |
@@ -4962,17 +5083,22 @@ void LCodeGen::DoNumberTagD(LNumberTagD* instr) { |
convert_hole = load->UsesMustHandleHole(); |
} |
+ bool use_sse2 = CpuFeatures::IsSupported(SSE2); |
+ if (!use_sse2) { |
+ // Put the value to the top of stack |
+ X87Register src = ToX87Register(instr->value()); |
+ X87LoadForUsage(src); |
+ } |
+ |
Label no_special_nan_handling; |
Label done; |
if (convert_hole) { |
- bool use_sse2 = CpuFeatures::IsSupported(SSE2); |
if (use_sse2) { |
CpuFeatureScope scope(masm(), SSE2); |
XMMRegister input_reg = ToDoubleRegister(instr->value()); |
__ ucomisd(input_reg, input_reg); |
} else { |
__ fld(0); |
- __ fld(0); |
__ FCmp(); |
} |
@@ -5026,6 +5152,10 @@ void LCodeGen::DoNumberTagD(LNumberTagD* instr) { |
} else { |
__ fst_d(FieldOperand(reg, HeapNumber::kValueOffset)); |
} |
+ if (!use_sse2) { |
+ // clean up the stack |
+ __ fstp(0); |
+ } |
__ bind(&done); |
} |
@@ -5075,12 +5205,14 @@ void LCodeGen::DoSmiUntag(LSmiUntag* instr) { |
void LCodeGen::EmitNumberUntagDNoSSE2(Register input_reg, |
Register temp_reg, |
+ X87Register res_reg, |
bool allow_undefined_as_nan, |
bool deoptimize_on_minus_zero, |
LEnvironment* env, |
NumberUntagDMode mode) { |
Label load_smi, done; |
+ X87PrepareToWrite(res_reg); |
STATIC_ASSERT(NUMBER_CANDIDATE_IS_ANY_TAGGED_CONVERT_HOLE > |
NUMBER_CANDIDATE_IS_ANY_TAGGED); |
if (mode >= NUMBER_CANDIDATE_IS_ANY_TAGGED) { |
@@ -5141,6 +5273,7 @@ void LCodeGen::EmitNumberUntagDNoSSE2(Register input_reg, |
__ pop(input_reg); |
__ SmiTag(input_reg); // Retag smi. |
__ bind(&done); |
+ X87CommitWrite(res_reg); |
} |
@@ -5522,11 +5655,11 @@ void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) { |
} else { |
EmitNumberUntagDNoSSE2(input_reg, |
temp_reg, |
+ ToX87Register(instr->result()), |
instr->hydrogen()->allow_undefined_as_nan(), |
deoptimize_on_minus_zero, |
instr->environment(), |
mode); |
- CurrentInstructionReturnsX87Result(); |
} |
} |