Commit a5a144c7 authored by olivf@chromium.org's avatar olivf@chromium.org

Implement X87 stack tracking and x87 multiplication

BUG=
R=mvstanton@chromium.org

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@15628 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent b2f909cf
......@@ -65,7 +65,7 @@ int IntelDoubleRegister::NumAllocatableRegisters() {
if (CpuFeatures::IsSupported(SSE2)) {
return XMMRegister::kNumAllocatableRegisters;
} else {
return X87TopOfStackRegister::kNumAllocatableRegisters;
return X87Register::kNumAllocatableRegisters;
}
}
......@@ -74,7 +74,7 @@ int IntelDoubleRegister::NumRegisters() {
if (CpuFeatures::IsSupported(SSE2)) {
return XMMRegister::kNumRegisters;
} else {
return X87TopOfStackRegister::kNumRegisters;
return X87Register::kNumRegisters;
}
}
......@@ -83,7 +83,7 @@ const char* IntelDoubleRegister::AllocationIndexToString(int index) {
if (CpuFeatures::IsSupported(SSE2)) {
return XMMRegister::AllocationIndexToString(index);
} else {
return X87TopOfStackRegister::AllocationIndexToString(index);
return X87Register::AllocationIndexToString(index);
}
}
......@@ -1784,6 +1784,12 @@ void Assembler::fisub_s(const Operand& adr) {
}
void Assembler::fmul_i(int i) {
EnsureSpace ensure_space(this);
emit_farith(0xD8, 0xC8, i);
}
void Assembler::fmul(int i) {
EnsureSpace ensure_space(this);
emit_farith(0xDC, 0xC8, i);
......
......@@ -229,30 +229,40 @@ struct XMMRegister : IntelDoubleRegister {
#define xmm7 (static_cast<const XMMRegister&>(double_register_7))
struct X87TopOfStackRegister : IntelDoubleRegister {
static const int kNumAllocatableRegisters = 1;
static const int kNumRegisters = 1;
struct X87Register : IntelDoubleRegister {
static const int kNumAllocatableRegisters = 5;
static const int kNumRegisters = 5;
bool is(X87TopOfStackRegister reg) const {
bool is(X87Register reg) const {
return code_ == reg.code_;
}
static const char* AllocationIndexToString(int index) {
ASSERT(index >= 0 && index < kNumAllocatableRegisters);
const char* const names[] = {
"st0",
"stX_0", "stX_1", "stX_2", "stX_3", "stX_4"
};
return names[index];
}
static int ToAllocationIndex(X87TopOfStackRegister reg) {
ASSERT(reg.code() == 0);
return 0;
static X87Register FromAllocationIndex(int index) {
STATIC_ASSERT(sizeof(X87Register) == sizeof(IntelDoubleRegister));
ASSERT(index >= 0 && index < NumAllocatableRegisters());
X87Register result;
result.code_ = index;
return result;
}
static int ToAllocationIndex(X87Register reg) {
return reg.code_;
}
};
#define x87tos \
static_cast<const X87TopOfStackRegister&>(double_register_0)
#define stX_0 static_cast<const X87Register&>(double_register_0)
#define stX_1 static_cast<const X87Register&>(double_register_1)
#define stX_2 static_cast<const X87Register&>(double_register_2)
#define stX_3 static_cast<const X87Register&>(double_register_3)
#define stX_4 static_cast<const X87Register&>(double_register_4)
typedef IntelDoubleRegister DoubleRegister;
......@@ -947,6 +957,7 @@ class Assembler : public AssemblerBase {
void fadd(int i);
void fsub(int i);
void fmul(int i);
void fmul_i(int i);
void fdiv(int i);
void fisub_s(const Operand& adr);
......
......@@ -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,16 +5083,21 @@ 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();
}
}
......
......@@ -105,7 +105,7 @@ class LCodeGen BASE_EMBEDDED {
Operand ToOperand(LOperand* op) const;
Register ToRegister(LOperand* op) const;
XMMRegister ToDoubleRegister(LOperand* op) const;
bool IsX87TopOfStack(LOperand* op) const;
X87Register ToX87Register(LOperand* op) const;
bool IsInteger32(LConstantOperand* op) const;
bool IsSmi(LConstantOperand* op) const;
......@@ -118,14 +118,20 @@ class LCodeGen BASE_EMBEDDED {
double ToDouble(LConstantOperand* op) const;
// Support for non-sse2 (x87) floating point stack handling.
// These functions maintain the depth of the stack (either 0 or 1)
void PushX87DoubleOperand(Operand src);
void PushX87FloatOperand(Operand src);
void ReadX87Operand(Operand dst);
bool X87StackNonEmpty() const { return x87_stack_depth_ > 0; }
void PopX87();
void CurrentInstructionReturnsX87Result();
void FlushX87StackIfNecessary(LInstruction* instr);
// These functions maintain the mapping of physical stack registers to our
// virtual registers between instructions.
enum X87OperandType { kX87DoubleOperand, kX87FloatOperand, kX87IntOperand };
void X87Mov(X87Register reg, Operand src,
X87OperandType operand = kX87DoubleOperand);
void X87Mov(Operand src, X87Register reg);
void X87PrepareBinaryOp(
X87Register left, X87Register right, X87Register result);
void X87LoadForUsage(X87Register reg);
void X87PrepareToWrite(X87Register reg);
void X87CommitWrite(X87Register reg);
Handle<Object> ToHandle(LConstantOperand* op) const;
......@@ -292,6 +298,7 @@ class LCodeGen BASE_EMBEDDED {
Register ToRegister(int index) const;
XMMRegister ToDoubleRegister(int index) const;
X87Register ToX87Register(int index) const;
int ToInteger32(LConstantOperand* op) const;
Operand BuildFastArrayOperand(LOperand* elements_pointer,
......@@ -331,6 +338,7 @@ class LCodeGen BASE_EMBEDDED {
void EmitNumberUntagDNoSSE2(
Register input,
Register temp,
X87Register res_reg,
bool allow_undefined_as_nan,
bool deoptimize_on_minus_zero,
LEnvironment* env,
......@@ -392,6 +400,16 @@ class LCodeGen 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);
Zone* zone_;
LPlatformChunk* const chunk_;
MacroAssembler* const masm_;
......@@ -413,6 +431,7 @@ class LCodeGen BASE_EMBEDDED {
int osr_pc_offset_;
int last_lazy_deopt_pc_;
bool frame_is_built_;
X87Register x87_stack_[X87Register::kNumAllocatableRegisters];
int x87_stack_depth_;
// Builder that keeps track of safepoints in the code. The table
......
......@@ -332,10 +332,8 @@ void LGapResolver::EmitMove(int index) {
} else {
__ push(Immediate(upper));
__ push(Immediate(lower));
if (cgen_->X87StackNonEmpty()) {
cgen_->PopX87();
}
cgen_->PushX87DoubleOperand(MemOperand(esp, 0));
X87Register dst = cgen_->ToX87Register(destination);
cgen_->X87Mov(dst, MemOperand(esp, 0));
__ add(esp, Immediate(kDoubleSize));
}
} else {
......@@ -367,10 +365,10 @@ void LGapResolver::EmitMove(int index) {
} else {
// load from the register onto the stack, store in destination, which must
// be a double stack slot in the non-SSE2 case.
ASSERT(source->index() == 0); // source is on top of the stack
ASSERT(destination->IsDoubleStackSlot());
Operand dst = cgen_->ToOperand(destination);
cgen_->ReadX87Operand(dst);
X87Register src = cgen_->ToX87Register(source);
cgen_->X87Mov(dst, src);
}
} else if (source->IsDoubleStackSlot()) {
if (CpuFeatures::IsSupported(SSE2)) {
......@@ -403,10 +401,8 @@ void LGapResolver::EmitMove(int index) {
__ mov(dst1, tmp);
} else {
Operand src = cgen_->ToOperand(source);
if (cgen_->X87StackNonEmpty()) {
cgen_->PopX87();
}
cgen_->PushX87DoubleOperand(src);
X87Register dst = cgen_->ToX87Register(destination);
cgen_->X87Mov(dst, src);
}
}
} else {
......
......@@ -82,6 +82,17 @@ bool LInstruction::HasDoubleRegisterInput() {
}
bool LInstruction::IsDoubleInput(X87Register reg, LCodeGen* cgen) {
for (int i = 0; i < InputCount(); i++) {
LOperand* op = InputAt(i);
if (op != NULL && op->IsDoubleRegister()) {
if (cgen->ToX87Register(op).is(reg)) return true;
}
}
return false;
}
void LInstruction::PrintTo(StringStream* stream) {
stream->Add("%s ", this->Mnemonic());
......@@ -494,12 +505,6 @@ LUnallocated* LChunkBuilder::ToUnallocated(XMMRegister reg) {
}
LUnallocated* LChunkBuilder::ToUnallocated(X87TopOfStackRegister reg) {
return new(zone()) LUnallocated(LUnallocated::FIXED_DOUBLE_REGISTER,
X87TopOfStackRegister::ToAllocationIndex(reg));
}
LOperand* LChunkBuilder::UseFixed(HValue* value, Register fixed_register) {
return Use(value, ToUnallocated(fixed_register));
}
......@@ -510,11 +515,6 @@ LOperand* LChunkBuilder::UseFixedDouble(HValue* value, XMMRegister reg) {
}
LOperand* LChunkBuilder::UseX87TopOfStack(HValue* value) {
return Use(value, ToUnallocated(x87tos));
}
LOperand* LChunkBuilder::UseRegister(HValue* value) {
return Use(value, new(zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER));
}
......@@ -642,13 +642,6 @@ LInstruction* LChunkBuilder::DefineFixedDouble(
}
template<int I, int T>
LInstruction* LChunkBuilder::DefineX87TOS(
LTemplateInstruction<1, I, T>* instr) {
return Define(instr, ToUnallocated(x87tos));
}
LInstruction* LChunkBuilder::AssignEnvironment(LInstruction* instr) {
HEnvironment* hydrogen_env = current_block_->last_environment();
int argument_index_accumulator = 0;
......@@ -1577,17 +1570,7 @@ LInstruction* LChunkBuilder::DoMul(HMul* instr) {
}
return DefineSameAsFirst(mul);
} else if (instr->representation().IsDouble()) {
if (CpuFeatures::IsSafeForSnapshot(SSE2)) {
return DoArithmeticD(Token::MUL, instr);
}
ASSERT(instr->right()->IsConstant() &&
static_cast<HConstant*>(instr->right())->DoubleValue() == -1);
// TODO(olivf) This is currently just a hack to support the UnaryOp Minus
// Stub. This will go away once we can use more than one X87 register,
// thus fully support binary instructions without SSE2.
LOperand* left = UseX87TopOfStack(instr->left());
LNegateNoSSE2D* result = new(zone()) LNegateNoSSE2D(left);
return DefineX87TOS(result);
return DoArithmeticD(Token::MUL, instr);
} else {
ASSERT(instr->representation().IsSmiOrTagged());
return DoArithmeticT(Token::MUL, instr);
......@@ -1937,11 +1920,7 @@ LInstruction* LChunkBuilder::DoChange(HChange* instr) {
? TempRegister()
: NULL;
LNumberUntagD* res = new(zone()) LNumberUntagD(value, temp);
if (CpuFeatures::IsSafeForSnapshot(SSE2)) {
return AssignEnvironment(DefineAsRegister(res));
} else {
return AssignEnvironment(DefineX87TOS(res));
}
return AssignEnvironment(DefineAsRegister(res));
} else if (to.IsSmi()) {
HValue* val = instr->value();
LOperand* value = UseRegister(val);
......@@ -1976,9 +1955,7 @@ LInstruction* LChunkBuilder::DoChange(HChange* instr) {
} else if (from.IsDouble()) {
if (to.IsTagged()) {
info()->MarkAsDeferredCalling();
LOperand* value = CpuFeatures::IsSupported(SSE2)
? UseRegisterAtStart(instr->value())
: UseAtStart(instr->value());
LOperand* value = UseRegisterAtStart(instr->value());
LOperand* temp = FLAG_inline_new ? TempRegister() : NULL;
// Make sure that temp and result_temp are different registers.
......@@ -2140,12 +2117,8 @@ LInstruction* LChunkBuilder::DoConstant(HConstant* instr) {
} else if (r.IsDouble()) {
double value = instr->DoubleValue();
bool value_is_zero = BitCast<uint64_t, double>(value) == 0;
if (CpuFeatures::IsSafeForSnapshot(SSE2)) {
LOperand* temp = value_is_zero ? NULL : TempRegister();
return DefineAsRegister(new(zone()) LConstantD(temp));
} else {
return DefineX87TOS(new(zone()) LConstantD(NULL));
}
LOperand* temp = value_is_zero ? NULL : TempRegister();
return DefineAsRegister(new(zone()) LConstantD(temp));
} else if (r.IsTagged()) {
return DefineAsRegister(new(zone()) LConstantT);
} else {
......@@ -2337,11 +2310,7 @@ LInstruction* LChunkBuilder::DoStoreKeyed(HStoreKeyed* instr) {
if (instr->value()->representation().IsDouble()) {
LOperand* object = UseRegisterAtStart(instr->elements());
LOperand* val = NULL;
if (CpuFeatures::IsSafeForSnapshot(SSE2)) {
val = UseRegisterAtStart(instr->value());
} else if (!instr->IsConstantHoleStore()) {
val = UseX87TopOfStack(instr->value());
}
val = UseRegisterAtStart(instr->value());
LOperand* key = UseRegisterOrConstantAtStart(instr->key());
return new(zone()) LStoreKeyed(object, key, val);
} else {
......@@ -2471,11 +2440,7 @@ LInstruction* LChunkBuilder::DoStoreNamedField(HStoreNamedField* instr) {
val = UseTempRegister(instr->value());
} else if (FLAG_track_double_fields &&
instr->field_representation().IsDouble()) {
if (CpuFeatures::IsSafeForSnapshot(SSE2)) {
val = UseRegisterAtStart(instr->value());
} else {
val = UseX87TopOfStack(instr->value());
}
val = UseRegisterAtStart(instr->value());
} else {
val = UseRegister(instr->value());
}
......
......@@ -141,7 +141,6 @@ class LCodeGen;
V(MathTan) \
V(ModI) \
V(MulI) \
V(NegateNoSSE2D) \
V(NumberTagD) \
V(NumberTagI) \
V(NumberTagU) \
......@@ -265,7 +264,11 @@ class LInstruction: public ZoneObject {
bool ClobbersTemps() const { return is_call_; }
bool ClobbersRegisters() const { return is_call_; }
virtual bool ClobbersDoubleRegisters() const {
return is_call_ || !CpuFeatures::IsSupported(SSE2);
return is_call_ ||
(!CpuFeatures::IsSupported(SSE2) &&
// We only have rudimentary X87Stack tracking, thus in general
// cannot handle deoptimization nor phi-nodes.
(HasEnvironment() || IsControl()));
}
virtual bool HasResult() const = 0;
......@@ -273,6 +276,7 @@ class LInstruction: public ZoneObject {
bool HasDoubleRegisterResult();
bool HasDoubleRegisterInput();
bool IsDoubleInput(X87Register reg, LCodeGen* cgen);
LOperand* FirstInput() { return InputAt(0); }
LOperand* Output() { return HasResult() ? result() : NULL; }
......@@ -377,7 +381,6 @@ class LGap: public LTemplateInstruction<0, 0, 0> {
class LInstructionGap: public LGap {
public:
explicit LInstructionGap(HBasicBlock* block) : LGap(block) { }
virtual bool ClobbersDoubleRegisters() const { return false; }
virtual bool HasInterestingComment(LCodeGen* gen) const {
return !IsRedundant();
......@@ -659,18 +662,6 @@ class LMathFloorOfDiv: public LTemplateInstruction<1, 2, 1> {
};
class LNegateNoSSE2D: public LTemplateInstruction<1, 1, 0> {
public:
explicit LNegateNoSSE2D(LOperand* value) {
inputs_[0] = value;
}
LOperand* value() { return inputs_[0]; }
DECLARE_CONCRETE_INSTRUCTION(NegateNoSSE2D, "negate-no-sse2-d")
};
class LMulI: public LTemplateInstruction<1, 2, 1> {
public:
LMulI(LOperand* left, LOperand* right, LOperand* temp) {
......@@ -1222,10 +1213,6 @@ class LConstantD: public LTemplateInstruction<1, 0, 1> {
temps_[0] = temp;
}
virtual bool ClobbersDoubleRegisters() const {
return false;
}
LOperand* temp() { return temps_[0]; }
DECLARE_CONCRETE_INSTRUCTION(ConstantD, "constant-d")
......@@ -2206,9 +2193,7 @@ class LNumberUntagD: public LTemplateInstruction<1, 1, 1> {
LOperand* value() { return inputs_[0]; }
LOperand* temp() { return temps_[0]; }
virtual bool ClobbersDoubleRegisters() const {
return false;
}
virtual bool ClobbersDoubleRegisters() const { return false; }
DECLARE_CONCRETE_INSTRUCTION(NumberUntagD, "double-untag")
DECLARE_HYDROGEN_ACCESSOR(Change);
......@@ -2852,14 +2837,13 @@ class LChunkBuilder BASE_EMBEDDED {
// Methods for getting operands for Use / Define / Temp.
LUnallocated* ToUnallocated(Register reg);
LUnallocated* ToUnallocated(XMMRegister reg);
LUnallocated* ToUnallocated(X87TopOfStackRegister reg);
LUnallocated* ToUnallocated(X87Register reg);
// Methods for setting up define-use relationships.
MUST_USE_RESULT LOperand* Use(HValue* value, LUnallocated* operand);
MUST_USE_RESULT LOperand* UseFixed(HValue* value, Register fixed_register);
MUST_USE_RESULT LOperand* UseFixedDouble(HValue* value,
XMMRegister fixed_register);
MUST_USE_RESULT LOperand* UseX87TopOfStack(HValue* value);
// A value that is guaranteed to be allocated to a register.
// Operand created by UseRegister is guaranteed to be live until the end of
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment