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() { ...@@ -65,7 +65,7 @@ int IntelDoubleRegister::NumAllocatableRegisters() {
if (CpuFeatures::IsSupported(SSE2)) { if (CpuFeatures::IsSupported(SSE2)) {
return XMMRegister::kNumAllocatableRegisters; return XMMRegister::kNumAllocatableRegisters;
} else { } else {
return X87TopOfStackRegister::kNumAllocatableRegisters; return X87Register::kNumAllocatableRegisters;
} }
} }
...@@ -74,7 +74,7 @@ int IntelDoubleRegister::NumRegisters() { ...@@ -74,7 +74,7 @@ int IntelDoubleRegister::NumRegisters() {
if (CpuFeatures::IsSupported(SSE2)) { if (CpuFeatures::IsSupported(SSE2)) {
return XMMRegister::kNumRegisters; return XMMRegister::kNumRegisters;
} else { } else {
return X87TopOfStackRegister::kNumRegisters; return X87Register::kNumRegisters;
} }
} }
...@@ -83,7 +83,7 @@ const char* IntelDoubleRegister::AllocationIndexToString(int index) { ...@@ -83,7 +83,7 @@ const char* IntelDoubleRegister::AllocationIndexToString(int index) {
if (CpuFeatures::IsSupported(SSE2)) { if (CpuFeatures::IsSupported(SSE2)) {
return XMMRegister::AllocationIndexToString(index); return XMMRegister::AllocationIndexToString(index);
} else { } else {
return X87TopOfStackRegister::AllocationIndexToString(index); return X87Register::AllocationIndexToString(index);
} }
} }
...@@ -1784,6 +1784,12 @@ void Assembler::fisub_s(const Operand& adr) { ...@@ -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) { void Assembler::fmul(int i) {
EnsureSpace ensure_space(this); EnsureSpace ensure_space(this);
emit_farith(0xDC, 0xC8, i); emit_farith(0xDC, 0xC8, i);
......
...@@ -229,30 +229,40 @@ struct XMMRegister : IntelDoubleRegister { ...@@ -229,30 +229,40 @@ struct XMMRegister : IntelDoubleRegister {
#define xmm7 (static_cast<const XMMRegister&>(double_register_7)) #define xmm7 (static_cast<const XMMRegister&>(double_register_7))
struct X87TopOfStackRegister : IntelDoubleRegister { struct X87Register : IntelDoubleRegister {
static const int kNumAllocatableRegisters = 1; static const int kNumAllocatableRegisters = 5;
static const int kNumRegisters = 1; static const int kNumRegisters = 5;
bool is(X87TopOfStackRegister reg) const { bool is(X87Register reg) const {
return code_ == reg.code_; return code_ == reg.code_;
} }
static const char* AllocationIndexToString(int index) { static const char* AllocationIndexToString(int index) {
ASSERT(index >= 0 && index < kNumAllocatableRegisters); ASSERT(index >= 0 && index < kNumAllocatableRegisters);
const char* const names[] = { const char* const names[] = {
"st0", "stX_0", "stX_1", "stX_2", "stX_3", "stX_4"
}; };
return names[index]; return names[index];
} }
static int ToAllocationIndex(X87TopOfStackRegister reg) { static X87Register FromAllocationIndex(int index) {
ASSERT(reg.code() == 0); STATIC_ASSERT(sizeof(X87Register) == sizeof(IntelDoubleRegister));
return 0; ASSERT(index >= 0 && index < NumAllocatableRegisters());
X87Register result;
result.code_ = index;
return result;
}
static int ToAllocationIndex(X87Register reg) {
return reg.code_;
} }
}; };
#define x87tos \ #define stX_0 static_cast<const X87Register&>(double_register_0)
static_cast<const X87TopOfStackRegister&>(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; typedef IntelDoubleRegister DoubleRegister;
...@@ -947,6 +957,7 @@ class Assembler : public AssemblerBase { ...@@ -947,6 +957,7 @@ class Assembler : public AssemblerBase {
void fadd(int i); void fadd(int i);
void fsub(int i); void fsub(int i);
void fmul(int i); void fmul(int i);
void fmul_i(int i);
void fdiv(int i); void fdiv(int i);
void fisub_s(const Operand& adr); void fisub_s(const Operand& adr);
......
...@@ -353,7 +353,6 @@ bool LCodeGen::GenerateBody() { ...@@ -353,7 +353,6 @@ bool LCodeGen::GenerateBody() {
instr->CompileToNative(this); instr->CompileToNative(this);
if (!CpuFeatures::IsSupported(SSE2)) { if (!CpuFeatures::IsSupported(SSE2)) {
ASSERT(!instr->HasDoubleRegisterResult() || x87_stack_depth_ == 1);
if (FLAG_debug_code && FLAG_enable_slow_asserts) { if (FLAG_debug_code && FLAG_enable_slow_asserts) {
__ VerifyX87StackDepth(x87_stack_depth_); __ VerifyX87StackDepth(x87_stack_depth_);
} }
...@@ -501,68 +500,181 @@ Register LCodeGen::ToRegister(int index) const { ...@@ -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 { XMMRegister LCodeGen::ToDoubleRegister(int index) const {
return XMMRegister::FromAllocationIndex(index); return XMMRegister::FromAllocationIndex(index);
} }
bool LCodeGen::IsX87TopOfStack(LOperand* op) const { void LCodeGen::X87LoadForUsage(X87Register reg) {
return op->IsDoubleRegister(); ASSERT(X87StackContains(reg));
X87Fxch(reg);
x87_stack_depth_--;
} }
void LCodeGen::ReadX87Operand(Operand dst) { void LCodeGen::X87Fxch(X87Register reg, int other_slot) {
ASSERT(x87_stack_depth_ == 1); ASSERT(X87StackContains(reg) && x87_stack_depth_ > other_slot);
__ fst_d(dst); 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) { int LCodeGen::x87_st2idx(int pos) {
ASSERT(x87_stack_depth_ == 0); return x87_stack_depth_ - pos - 1;
x87_stack_depth_++;
__ fld_d(src);
} }
void LCodeGen::PushX87FloatOperand(Operand src) { int LCodeGen::X87ArrayIndex(X87Register reg) {
ASSERT(x87_stack_depth_ == 0); for (int i = 0; i < x87_stack_depth_; i++) {
x87_stack_depth_++; if (x87_stack_[i].is(reg)) return i;
__ fld_s(src); }
UNREACHABLE();
return -1;
} }
void LCodeGen::PopX87() { bool LCodeGen::X87StackContains(X87Register reg) {
ASSERT(x87_stack_depth_ == 1); 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_--; x87_stack_depth_--;
__ fstp(st);
}
void LCodeGen::X87Mov(X87Register dst, Operand src, X87OperandType opts) {
if (X87StackContains(dst)) {
X87Fxch(dst);
__ fstp(0); __ fstp(0);
} else {
ASSERT(x87_stack_depth_ < X87Register::kNumAllocatableRegisters);
x87_stack_[x87_stack_depth_] = dst;
x87_stack_depth_++;
}
X87Fld(src, opts);
} }
void LCodeGen::CurrentInstructionReturnsX87Result() { void LCodeGen::X87Fld(Operand src, X87OperandType opts) {
ASSERT(x87_stack_depth_ <= 1); if (opts == kX87DoubleOperand) {
if (x87_stack_depth_ == 0) { __ fld_d(src);
x87_stack_depth_ = 1; } 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) { void LCodeGen::FlushX87StackIfNecessary(LInstruction* instr) {
if (x87_stack_depth_ > 0) { if (x87_stack_depth_ > 0 && instr->ClobbersDoubleRegisters()) {
if ((instr->ClobbersDoubleRegisters() || bool double_inputs = instr->HasDoubleRegisterInput();
instr->HasDoubleRegisterResult()) &&
!instr->HasDoubleRegisterInput()) { // Flush stack from tos down, since FreeX87() will mess with tos
PopX87(); 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 { Register LCodeGen::ToRegister(LOperand* op) const {
ASSERT(op->IsRegister()); ASSERT(op->IsRegister());
return ToRegister(op->index()); return ToRegister(op->index());
} }
X87Register LCodeGen::ToX87Register(LOperand* op) const {
ASSERT(op->IsDoubleRegister());
return ToX87Register(op->index());
}
XMMRegister LCodeGen::ToDoubleRegister(LOperand* op) const { XMMRegister LCodeGen::ToDoubleRegister(LOperand* op) const {
ASSERT(op->IsDoubleRegister()); ASSERT(op->IsDoubleRegister());
return ToDoubleRegister(op->index()); return ToDoubleRegister(op->index());
...@@ -835,8 +947,6 @@ void LCodeGen::DeoptimizeIf(Condition cc, ...@@ -835,8 +947,6 @@ void LCodeGen::DeoptimizeIf(Condition cc,
Deoptimizer::BailoutType bailout_type) { Deoptimizer::BailoutType bailout_type) {
RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt); RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt);
ASSERT(environment->HasBeenRegistered()); 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(); int id = environment->deoptimization_index();
ASSERT(info()->IsOptimizing() || info()->IsStub()); ASSERT(info()->IsOptimizing() || info()->IsStub());
Address entry = Address entry =
...@@ -874,11 +984,20 @@ void LCodeGen::DeoptimizeIf(Condition cc, ...@@ -874,11 +984,20 @@ void LCodeGen::DeoptimizeIf(Condition cc,
__ popfd(); __ popfd();
} }
if (FLAG_trap_on_deopt && info()->IsOptimizing()) { // 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; Label done;
if (cc != no_condition) { if (cc != no_condition) __ j(NegateCondition(cc), &done, Label::kNear);
__ 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);
__ int3(); __ int3();
__ bind(&done); __ bind(&done);
} }
...@@ -1721,11 +1840,10 @@ void LCodeGen::DoConstantD(LConstantD* instr) { ...@@ -1721,11 +1840,10 @@ void LCodeGen::DoConstantD(LConstantD* instr) {
int32_t upper = static_cast<int32_t>(int_val >> (kBitsPerInt)); int32_t upper = static_cast<int32_t>(int_val >> (kBitsPerInt));
if (!CpuFeatures::IsSafeForSnapshot(SSE2)) { if (!CpuFeatures::IsSafeForSnapshot(SSE2)) {
__ push(Immediate(lower));
__ push(Immediate(upper)); __ push(Immediate(upper));
PushX87DoubleOperand(Operand(esp, 0)); __ push(Immediate(lower));
X87Mov(ToX87Register(instr->result()), Operand(esp, 0));
__ add(Operand(esp), Immediate(kDoubleSize)); __ add(Operand(esp), Immediate(kDoubleSize));
CurrentInstructionReturnsX87Result();
} else { } else {
CpuFeatureScope scope1(masm(), SSE2); CpuFeatureScope scope1(masm(), SSE2);
ASSERT(instr->result()->IsDoubleRegister()); ASSERT(instr->result()->IsDoubleRegister());
...@@ -1990,6 +2108,7 @@ void LCodeGen::DoMathMinMax(LMathMinMax* instr) { ...@@ -1990,6 +2108,7 @@ void LCodeGen::DoMathMinMax(LMathMinMax* instr) {
void LCodeGen::DoArithmeticD(LArithmeticD* instr) { void LCodeGen::DoArithmeticD(LArithmeticD* instr) {
if (CpuFeatures::IsSafeForSnapshot(SSE2)) {
CpuFeatureScope scope(masm(), SSE2); CpuFeatureScope scope(masm(), SSE2);
XMMRegister left = ToDoubleRegister(instr->left()); XMMRegister left = ToDoubleRegister(instr->left());
XMMRegister right = ToDoubleRegister(instr->right()); XMMRegister right = ToDoubleRegister(instr->right());
...@@ -2033,19 +2152,23 @@ void LCodeGen::DoArithmeticD(LArithmeticD* instr) { ...@@ -2033,19 +2152,23 @@ void LCodeGen::DoArithmeticD(LArithmeticD* instr) {
UNREACHABLE(); UNREACHABLE();
break; 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;
}
}
} }
void LCodeGen::DoNegateNoSSE2D(LNegateNoSSE2D* instr) {
__ push(Immediate(-1));
__ fild_s(Operand(esp, 0));
__ add(esp, Immediate(kPointerSize));
__ fmulp();
CurrentInstructionReturnsX87Result();
}
void LCodeGen::DoArithmeticT(LArithmeticT* instr) { void LCodeGen::DoArithmeticT(LArithmeticT* instr) {
ASSERT(ToRegister(instr->context()).is(esi)); ASSERT(ToRegister(instr->context()).is(esi));
ASSERT(ToRegister(instr->left()).is(edx)); ASSERT(ToRegister(instr->left()).is(edx));
...@@ -2963,8 +3086,7 @@ void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) { ...@@ -2963,8 +3086,7 @@ void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) {
XMMRegister result = ToDoubleRegister(instr->result()); XMMRegister result = ToDoubleRegister(instr->result());
__ movdbl(result, FieldOperand(object, offset)); __ movdbl(result, FieldOperand(object, offset));
} else { } else {
PushX87DoubleOperand(FieldOperand(object, offset)); X87Mov(ToX87Register(instr->result()), FieldOperand(object, offset));
CurrentInstructionReturnsX87Result();
} }
return; return;
} }
...@@ -3209,16 +3331,14 @@ void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) { ...@@ -3209,16 +3331,14 @@ void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) {
__ movss(result, operand); __ movss(result, operand);
__ cvtss2sd(result, result); __ cvtss2sd(result, result);
} else { } else {
PushX87FloatOperand(operand); X87Mov(ToX87Register(instr->result()), operand, kX87FloatOperand);
CurrentInstructionReturnsX87Result();
} }
} else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) { } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
if (CpuFeatures::IsSupported(SSE2)) { if (CpuFeatures::IsSupported(SSE2)) {
CpuFeatureScope scope(masm(), SSE2); CpuFeatureScope scope(masm(), SSE2);
__ movdbl(ToDoubleRegister(instr->result()), operand); __ movdbl(ToDoubleRegister(instr->result()), operand);
} else { } else {
PushX87DoubleOperand(operand); X87Mov(ToX87Register(instr->result()), operand);
CurrentInstructionReturnsX87Result();
} }
} else { } else {
Register result(ToRegister(instr->result())); Register result(ToRegister(instr->result()));
...@@ -3289,8 +3409,7 @@ void LCodeGen::DoLoadKeyedFixedDoubleArray(LLoadKeyed* instr) { ...@@ -3289,8 +3409,7 @@ void LCodeGen::DoLoadKeyedFixedDoubleArray(LLoadKeyed* instr) {
XMMRegister result = ToDoubleRegister(instr->result()); XMMRegister result = ToDoubleRegister(instr->result());
__ movdbl(result, double_load_operand); __ movdbl(result, double_load_operand);
} else { } else {
PushX87DoubleOperand(double_load_operand); X87Mov(ToX87Register(instr->result()), double_load_operand);
CurrentInstructionReturnsX87Result();
} }
} }
...@@ -4284,7 +4403,8 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) { ...@@ -4284,7 +4403,8 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
XMMRegister value = ToDoubleRegister(instr->value()); XMMRegister value = ToDoubleRegister(instr->value());
__ movdbl(FieldOperand(object, offset), value); __ movdbl(FieldOperand(object, offset), value);
} else { } else {
__ fstp_d(FieldOperand(object, offset)); X87Register value = ToX87Register(instr->value());
X87Mov(FieldOperand(object, offset), value);
} }
return; return;
} }
...@@ -4410,7 +4530,7 @@ void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) { ...@@ -4410,7 +4530,7 @@ void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) {
CpuFeatureScope scope(masm(), SSE2); CpuFeatureScope scope(masm(), SSE2);
__ movdbl(operand, ToDoubleRegister(instr->value())); __ movdbl(operand, ToDoubleRegister(instr->value()));
} else { } else {
__ fst_d(operand); X87Mov(operand, ToX87Register(instr->value()));
} }
} else { } else {
Register value = ToRegister(instr->value()); Register value = ToRegister(instr->value());
...@@ -4492,7 +4612,8 @@ void LCodeGen::DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr) { ...@@ -4492,7 +4612,8 @@ void LCodeGen::DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr) {
__ mov(double_store_operand2, Immediate(upper)); __ mov(double_store_operand2, Immediate(upper));
} else { } else {
Label no_special_nan_handling; Label no_special_nan_handling;
ASSERT(x87_stack_depth_ > 0); X87Register value = ToX87Register(instr->value());
X87Fxch(value);
if (instr->NeedsCanonicalization()) { if (instr->NeedsCanonicalization()) {
__ fld(0); __ fld(0);
...@@ -4962,16 +5083,21 @@ void LCodeGen::DoNumberTagD(LNumberTagD* instr) { ...@@ -4962,16 +5083,21 @@ void LCodeGen::DoNumberTagD(LNumberTagD* instr) {
convert_hole = load->UsesMustHandleHole(); 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 no_special_nan_handling;
Label done; Label done;
if (convert_hole) { if (convert_hole) {
bool use_sse2 = CpuFeatures::IsSupported(SSE2);
if (use_sse2) { if (use_sse2) {
CpuFeatureScope scope(masm(), SSE2); CpuFeatureScope scope(masm(), SSE2);
XMMRegister input_reg = ToDoubleRegister(instr->value()); XMMRegister input_reg = ToDoubleRegister(instr->value());
__ ucomisd(input_reg, input_reg); __ ucomisd(input_reg, input_reg);
} else { } else {
__ fld(0);
__ fld(0); __ fld(0);
__ FCmp(); __ FCmp();
} }
...@@ -5026,6 +5152,10 @@ void LCodeGen::DoNumberTagD(LNumberTagD* instr) { ...@@ -5026,6 +5152,10 @@ void LCodeGen::DoNumberTagD(LNumberTagD* instr) {
} else { } else {
__ fst_d(FieldOperand(reg, HeapNumber::kValueOffset)); __ fst_d(FieldOperand(reg, HeapNumber::kValueOffset));
} }
if (!use_sse2) {
// clean up the stack
__ fstp(0);
}
__ bind(&done); __ bind(&done);
} }
...@@ -5075,12 +5205,14 @@ void LCodeGen::DoSmiUntag(LSmiUntag* instr) { ...@@ -5075,12 +5205,14 @@ void LCodeGen::DoSmiUntag(LSmiUntag* instr) {
void LCodeGen::EmitNumberUntagDNoSSE2(Register input_reg, void LCodeGen::EmitNumberUntagDNoSSE2(Register input_reg,
Register temp_reg, Register temp_reg,
X87Register res_reg,
bool allow_undefined_as_nan, bool allow_undefined_as_nan,
bool deoptimize_on_minus_zero, bool deoptimize_on_minus_zero,
LEnvironment* env, LEnvironment* env,
NumberUntagDMode mode) { NumberUntagDMode mode) {
Label load_smi, done; Label load_smi, done;
X87PrepareToWrite(res_reg);
STATIC_ASSERT(NUMBER_CANDIDATE_IS_ANY_TAGGED_CONVERT_HOLE > STATIC_ASSERT(NUMBER_CANDIDATE_IS_ANY_TAGGED_CONVERT_HOLE >
NUMBER_CANDIDATE_IS_ANY_TAGGED); NUMBER_CANDIDATE_IS_ANY_TAGGED);
if (mode >= NUMBER_CANDIDATE_IS_ANY_TAGGED) { if (mode >= NUMBER_CANDIDATE_IS_ANY_TAGGED) {
...@@ -5141,6 +5273,7 @@ void LCodeGen::EmitNumberUntagDNoSSE2(Register input_reg, ...@@ -5141,6 +5273,7 @@ void LCodeGen::EmitNumberUntagDNoSSE2(Register input_reg,
__ pop(input_reg); __ pop(input_reg);
__ SmiTag(input_reg); // Retag smi. __ SmiTag(input_reg); // Retag smi.
__ bind(&done); __ bind(&done);
X87CommitWrite(res_reg);
} }
...@@ -5522,11 +5655,11 @@ void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) { ...@@ -5522,11 +5655,11 @@ void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) {
} else { } else {
EmitNumberUntagDNoSSE2(input_reg, EmitNumberUntagDNoSSE2(input_reg,
temp_reg, temp_reg,
ToX87Register(instr->result()),
instr->hydrogen()->allow_undefined_as_nan(), instr->hydrogen()->allow_undefined_as_nan(),
deoptimize_on_minus_zero, deoptimize_on_minus_zero,
instr->environment(), instr->environment(),
mode); mode);
CurrentInstructionReturnsX87Result();
} }
} }
......
...@@ -105,7 +105,7 @@ class LCodeGen BASE_EMBEDDED { ...@@ -105,7 +105,7 @@ class LCodeGen BASE_EMBEDDED {
Operand ToOperand(LOperand* op) const; Operand ToOperand(LOperand* op) const;
Register ToRegister(LOperand* op) const; Register ToRegister(LOperand* op) const;
XMMRegister ToDoubleRegister(LOperand* op) const; XMMRegister ToDoubleRegister(LOperand* op) const;
bool IsX87TopOfStack(LOperand* op) const; X87Register ToX87Register(LOperand* op) const;
bool IsInteger32(LConstantOperand* op) const; bool IsInteger32(LConstantOperand* op) const;
bool IsSmi(LConstantOperand* op) const; bool IsSmi(LConstantOperand* op) const;
...@@ -118,14 +118,20 @@ class LCodeGen BASE_EMBEDDED { ...@@ -118,14 +118,20 @@ class LCodeGen BASE_EMBEDDED {
double ToDouble(LConstantOperand* op) const; double ToDouble(LConstantOperand* op) const;
// Support for non-sse2 (x87) floating point stack handling. // Support for non-sse2 (x87) floating point stack handling.
// These functions maintain the depth of the stack (either 0 or 1) // These functions maintain the mapping of physical stack registers to our
void PushX87DoubleOperand(Operand src); // virtual registers between instructions.
void PushX87FloatOperand(Operand src); enum X87OperandType { kX87DoubleOperand, kX87FloatOperand, kX87IntOperand };
void ReadX87Operand(Operand dst);
bool X87StackNonEmpty() const { return x87_stack_depth_ > 0; } void X87Mov(X87Register reg, Operand src,
void PopX87(); X87OperandType operand = kX87DoubleOperand);
void CurrentInstructionReturnsX87Result(); void X87Mov(Operand src, X87Register reg);
void FlushX87StackIfNecessary(LInstruction* instr);
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; Handle<Object> ToHandle(LConstantOperand* op) const;
...@@ -292,6 +298,7 @@ class LCodeGen BASE_EMBEDDED { ...@@ -292,6 +298,7 @@ class LCodeGen BASE_EMBEDDED {
Register ToRegister(int index) const; Register ToRegister(int index) const;
XMMRegister ToDoubleRegister(int index) const; XMMRegister ToDoubleRegister(int index) const;
X87Register ToX87Register(int index) const;
int ToInteger32(LConstantOperand* op) const; int ToInteger32(LConstantOperand* op) const;
Operand BuildFastArrayOperand(LOperand* elements_pointer, Operand BuildFastArrayOperand(LOperand* elements_pointer,
...@@ -331,6 +338,7 @@ class LCodeGen BASE_EMBEDDED { ...@@ -331,6 +338,7 @@ class LCodeGen BASE_EMBEDDED {
void EmitNumberUntagDNoSSE2( void EmitNumberUntagDNoSSE2(
Register input, Register input,
Register temp, Register temp,
X87Register res_reg,
bool allow_undefined_as_nan, bool allow_undefined_as_nan,
bool deoptimize_on_minus_zero, bool deoptimize_on_minus_zero,
LEnvironment* env, LEnvironment* env,
...@@ -392,6 +400,16 @@ class LCodeGen BASE_EMBEDDED { ...@@ -392,6 +400,16 @@ class LCodeGen BASE_EMBEDDED {
// register, or a stack slot operand. // register, or a stack slot operand.
void EmitPushTaggedOperand(LOperand* 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_; Zone* zone_;
LPlatformChunk* const chunk_; LPlatformChunk* const chunk_;
MacroAssembler* const masm_; MacroAssembler* const masm_;
...@@ -413,6 +431,7 @@ class LCodeGen BASE_EMBEDDED { ...@@ -413,6 +431,7 @@ class LCodeGen BASE_EMBEDDED {
int osr_pc_offset_; int osr_pc_offset_;
int last_lazy_deopt_pc_; int last_lazy_deopt_pc_;
bool frame_is_built_; bool frame_is_built_;
X87Register x87_stack_[X87Register::kNumAllocatableRegisters];
int x87_stack_depth_; int x87_stack_depth_;
// Builder that keeps track of safepoints in the code. The table // Builder that keeps track of safepoints in the code. The table
......
...@@ -332,10 +332,8 @@ void LGapResolver::EmitMove(int index) { ...@@ -332,10 +332,8 @@ void LGapResolver::EmitMove(int index) {
} else { } else {
__ push(Immediate(upper)); __ push(Immediate(upper));
__ push(Immediate(lower)); __ push(Immediate(lower));
if (cgen_->X87StackNonEmpty()) { X87Register dst = cgen_->ToX87Register(destination);
cgen_->PopX87(); cgen_->X87Mov(dst, MemOperand(esp, 0));
}
cgen_->PushX87DoubleOperand(MemOperand(esp, 0));
__ add(esp, Immediate(kDoubleSize)); __ add(esp, Immediate(kDoubleSize));
} }
} else { } else {
...@@ -367,10 +365,10 @@ void LGapResolver::EmitMove(int index) { ...@@ -367,10 +365,10 @@ void LGapResolver::EmitMove(int index) {
} else { } else {
// load from the register onto the stack, store in destination, which must // load from the register onto the stack, store in destination, which must
// be a double stack slot in the non-SSE2 case. // be a double stack slot in the non-SSE2 case.
ASSERT(source->index() == 0); // source is on top of the stack
ASSERT(destination->IsDoubleStackSlot()); ASSERT(destination->IsDoubleStackSlot());
Operand dst = cgen_->ToOperand(destination); Operand dst = cgen_->ToOperand(destination);
cgen_->ReadX87Operand(dst); X87Register src = cgen_->ToX87Register(source);
cgen_->X87Mov(dst, src);
} }
} else if (source->IsDoubleStackSlot()) { } else if (source->IsDoubleStackSlot()) {
if (CpuFeatures::IsSupported(SSE2)) { if (CpuFeatures::IsSupported(SSE2)) {
...@@ -403,10 +401,8 @@ void LGapResolver::EmitMove(int index) { ...@@ -403,10 +401,8 @@ void LGapResolver::EmitMove(int index) {
__ mov(dst1, tmp); __ mov(dst1, tmp);
} else { } else {
Operand src = cgen_->ToOperand(source); Operand src = cgen_->ToOperand(source);
if (cgen_->X87StackNonEmpty()) { X87Register dst = cgen_->ToX87Register(destination);
cgen_->PopX87(); cgen_->X87Mov(dst, src);
}
cgen_->PushX87DoubleOperand(src);
} }
} }
} else { } else {
......
...@@ -82,6 +82,17 @@ bool LInstruction::HasDoubleRegisterInput() { ...@@ -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) { void LInstruction::PrintTo(StringStream* stream) {
stream->Add("%s ", this->Mnemonic()); stream->Add("%s ", this->Mnemonic());
...@@ -494,12 +505,6 @@ LUnallocated* LChunkBuilder::ToUnallocated(XMMRegister reg) { ...@@ -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) { LOperand* LChunkBuilder::UseFixed(HValue* value, Register fixed_register) {
return Use(value, ToUnallocated(fixed_register)); return Use(value, ToUnallocated(fixed_register));
} }
...@@ -510,11 +515,6 @@ LOperand* LChunkBuilder::UseFixedDouble(HValue* value, XMMRegister reg) { ...@@ -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) { LOperand* LChunkBuilder::UseRegister(HValue* value) {
return Use(value, new(zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER)); return Use(value, new(zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER));
} }
...@@ -642,13 +642,6 @@ LInstruction* LChunkBuilder::DefineFixedDouble( ...@@ -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) { LInstruction* LChunkBuilder::AssignEnvironment(LInstruction* instr) {
HEnvironment* hydrogen_env = current_block_->last_environment(); HEnvironment* hydrogen_env = current_block_->last_environment();
int argument_index_accumulator = 0; int argument_index_accumulator = 0;
...@@ -1577,17 +1570,7 @@ LInstruction* LChunkBuilder::DoMul(HMul* instr) { ...@@ -1577,17 +1570,7 @@ LInstruction* LChunkBuilder::DoMul(HMul* instr) {
} }
return DefineSameAsFirst(mul); return DefineSameAsFirst(mul);
} else if (instr->representation().IsDouble()) { } else if (instr->representation().IsDouble()) {
if (CpuFeatures::IsSafeForSnapshot(SSE2)) {
return DoArithmeticD(Token::MUL, instr); 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);
} else { } else {
ASSERT(instr->representation().IsSmiOrTagged()); ASSERT(instr->representation().IsSmiOrTagged());
return DoArithmeticT(Token::MUL, instr); return DoArithmeticT(Token::MUL, instr);
...@@ -1937,11 +1920,7 @@ LInstruction* LChunkBuilder::DoChange(HChange* instr) { ...@@ -1937,11 +1920,7 @@ LInstruction* LChunkBuilder::DoChange(HChange* instr) {
? TempRegister() ? TempRegister()
: NULL; : NULL;
LNumberUntagD* res = new(zone()) LNumberUntagD(value, temp); LNumberUntagD* res = new(zone()) LNumberUntagD(value, temp);
if (CpuFeatures::IsSafeForSnapshot(SSE2)) {
return AssignEnvironment(DefineAsRegister(res)); return AssignEnvironment(DefineAsRegister(res));
} else {
return AssignEnvironment(DefineX87TOS(res));
}
} else if (to.IsSmi()) { } else if (to.IsSmi()) {
HValue* val = instr->value(); HValue* val = instr->value();
LOperand* value = UseRegister(val); LOperand* value = UseRegister(val);
...@@ -1976,9 +1955,7 @@ LInstruction* LChunkBuilder::DoChange(HChange* instr) { ...@@ -1976,9 +1955,7 @@ LInstruction* LChunkBuilder::DoChange(HChange* instr) {
} else if (from.IsDouble()) { } else if (from.IsDouble()) {
if (to.IsTagged()) { if (to.IsTagged()) {
info()->MarkAsDeferredCalling(); info()->MarkAsDeferredCalling();
LOperand* value = CpuFeatures::IsSupported(SSE2) LOperand* value = UseRegisterAtStart(instr->value());
? UseRegisterAtStart(instr->value())
: UseAtStart(instr->value());
LOperand* temp = FLAG_inline_new ? TempRegister() : NULL; LOperand* temp = FLAG_inline_new ? TempRegister() : NULL;
// Make sure that temp and result_temp are different registers. // Make sure that temp and result_temp are different registers.
...@@ -2140,12 +2117,8 @@ LInstruction* LChunkBuilder::DoConstant(HConstant* instr) { ...@@ -2140,12 +2117,8 @@ LInstruction* LChunkBuilder::DoConstant(HConstant* instr) {
} else if (r.IsDouble()) { } else if (r.IsDouble()) {
double value = instr->DoubleValue(); double value = instr->DoubleValue();
bool value_is_zero = BitCast<uint64_t, double>(value) == 0; bool value_is_zero = BitCast<uint64_t, double>(value) == 0;
if (CpuFeatures::IsSafeForSnapshot(SSE2)) {
LOperand* temp = value_is_zero ? NULL : TempRegister(); LOperand* temp = value_is_zero ? NULL : TempRegister();
return DefineAsRegister(new(zone()) LConstantD(temp)); return DefineAsRegister(new(zone()) LConstantD(temp));
} else {
return DefineX87TOS(new(zone()) LConstantD(NULL));
}
} else if (r.IsTagged()) { } else if (r.IsTagged()) {
return DefineAsRegister(new(zone()) LConstantT); return DefineAsRegister(new(zone()) LConstantT);
} else { } else {
...@@ -2337,11 +2310,7 @@ LInstruction* LChunkBuilder::DoStoreKeyed(HStoreKeyed* instr) { ...@@ -2337,11 +2310,7 @@ LInstruction* LChunkBuilder::DoStoreKeyed(HStoreKeyed* instr) {
if (instr->value()->representation().IsDouble()) { if (instr->value()->representation().IsDouble()) {
LOperand* object = UseRegisterAtStart(instr->elements()); LOperand* object = UseRegisterAtStart(instr->elements());
LOperand* val = NULL; LOperand* val = NULL;
if (CpuFeatures::IsSafeForSnapshot(SSE2)) {
val = UseRegisterAtStart(instr->value()); val = UseRegisterAtStart(instr->value());
} else if (!instr->IsConstantHoleStore()) {
val = UseX87TopOfStack(instr->value());
}
LOperand* key = UseRegisterOrConstantAtStart(instr->key()); LOperand* key = UseRegisterOrConstantAtStart(instr->key());
return new(zone()) LStoreKeyed(object, key, val); return new(zone()) LStoreKeyed(object, key, val);
} else { } else {
...@@ -2471,11 +2440,7 @@ LInstruction* LChunkBuilder::DoStoreNamedField(HStoreNamedField* instr) { ...@@ -2471,11 +2440,7 @@ LInstruction* LChunkBuilder::DoStoreNamedField(HStoreNamedField* instr) {
val = UseTempRegister(instr->value()); val = UseTempRegister(instr->value());
} else if (FLAG_track_double_fields && } else if (FLAG_track_double_fields &&
instr->field_representation().IsDouble()) { instr->field_representation().IsDouble()) {
if (CpuFeatures::IsSafeForSnapshot(SSE2)) {
val = UseRegisterAtStart(instr->value()); val = UseRegisterAtStart(instr->value());
} else {
val = UseX87TopOfStack(instr->value());
}
} else { } else {
val = UseRegister(instr->value()); val = UseRegister(instr->value());
} }
......
...@@ -141,7 +141,6 @@ class LCodeGen; ...@@ -141,7 +141,6 @@ class LCodeGen;
V(MathTan) \ V(MathTan) \
V(ModI) \ V(ModI) \
V(MulI) \ V(MulI) \
V(NegateNoSSE2D) \
V(NumberTagD) \ V(NumberTagD) \
V(NumberTagI) \ V(NumberTagI) \
V(NumberTagU) \ V(NumberTagU) \
...@@ -265,7 +264,11 @@ class LInstruction: public ZoneObject { ...@@ -265,7 +264,11 @@ class LInstruction: public ZoneObject {
bool ClobbersTemps() const { return is_call_; } bool ClobbersTemps() const { return is_call_; }
bool ClobbersRegisters() const { return is_call_; } bool ClobbersRegisters() const { return is_call_; }
virtual bool ClobbersDoubleRegisters() const { 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; virtual bool HasResult() const = 0;
...@@ -273,6 +276,7 @@ class LInstruction: public ZoneObject { ...@@ -273,6 +276,7 @@ class LInstruction: public ZoneObject {
bool HasDoubleRegisterResult(); bool HasDoubleRegisterResult();
bool HasDoubleRegisterInput(); bool HasDoubleRegisterInput();
bool IsDoubleInput(X87Register reg, LCodeGen* cgen);
LOperand* FirstInput() { return InputAt(0); } LOperand* FirstInput() { return InputAt(0); }
LOperand* Output() { return HasResult() ? result() : NULL; } LOperand* Output() { return HasResult() ? result() : NULL; }
...@@ -377,7 +381,6 @@ class LGap: public LTemplateInstruction<0, 0, 0> { ...@@ -377,7 +381,6 @@ class LGap: public LTemplateInstruction<0, 0, 0> {
class LInstructionGap: public LGap { class LInstructionGap: public LGap {
public: public:
explicit LInstructionGap(HBasicBlock* block) : LGap(block) { } explicit LInstructionGap(HBasicBlock* block) : LGap(block) { }
virtual bool ClobbersDoubleRegisters() const { return false; }
virtual bool HasInterestingComment(LCodeGen* gen) const { virtual bool HasInterestingComment(LCodeGen* gen) const {
return !IsRedundant(); return !IsRedundant();
...@@ -659,18 +662,6 @@ class LMathFloorOfDiv: public LTemplateInstruction<1, 2, 1> { ...@@ -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> { class LMulI: public LTemplateInstruction<1, 2, 1> {
public: public:
LMulI(LOperand* left, LOperand* right, LOperand* temp) { LMulI(LOperand* left, LOperand* right, LOperand* temp) {
...@@ -1222,10 +1213,6 @@ class LConstantD: public LTemplateInstruction<1, 0, 1> { ...@@ -1222,10 +1213,6 @@ class LConstantD: public LTemplateInstruction<1, 0, 1> {
temps_[0] = temp; temps_[0] = temp;
} }
virtual bool ClobbersDoubleRegisters() const {
return false;
}
LOperand* temp() { return temps_[0]; } LOperand* temp() { return temps_[0]; }
DECLARE_CONCRETE_INSTRUCTION(ConstantD, "constant-d") DECLARE_CONCRETE_INSTRUCTION(ConstantD, "constant-d")
...@@ -2206,9 +2193,7 @@ class LNumberUntagD: public LTemplateInstruction<1, 1, 1> { ...@@ -2206,9 +2193,7 @@ class LNumberUntagD: public LTemplateInstruction<1, 1, 1> {
LOperand* value() { return inputs_[0]; } LOperand* value() { return inputs_[0]; }
LOperand* temp() { return temps_[0]; } LOperand* temp() { return temps_[0]; }
virtual bool ClobbersDoubleRegisters() const { virtual bool ClobbersDoubleRegisters() const { return false; }
return false;
}
DECLARE_CONCRETE_INSTRUCTION(NumberUntagD, "double-untag") DECLARE_CONCRETE_INSTRUCTION(NumberUntagD, "double-untag")
DECLARE_HYDROGEN_ACCESSOR(Change); DECLARE_HYDROGEN_ACCESSOR(Change);
...@@ -2852,14 +2837,13 @@ class LChunkBuilder BASE_EMBEDDED { ...@@ -2852,14 +2837,13 @@ class LChunkBuilder BASE_EMBEDDED {
// Methods for getting operands for Use / Define / Temp. // Methods for getting operands for Use / Define / Temp.
LUnallocated* ToUnallocated(Register reg); LUnallocated* ToUnallocated(Register reg);
LUnallocated* ToUnallocated(XMMRegister reg); LUnallocated* ToUnallocated(XMMRegister reg);
LUnallocated* ToUnallocated(X87TopOfStackRegister reg); LUnallocated* ToUnallocated(X87Register reg);
// Methods for setting up define-use relationships. // Methods for setting up define-use relationships.
MUST_USE_RESULT LOperand* Use(HValue* value, LUnallocated* operand); MUST_USE_RESULT LOperand* Use(HValue* value, LUnallocated* operand);
MUST_USE_RESULT LOperand* UseFixed(HValue* value, Register fixed_register); MUST_USE_RESULT LOperand* UseFixed(HValue* value, Register fixed_register);
MUST_USE_RESULT LOperand* UseFixedDouble(HValue* value, MUST_USE_RESULT LOperand* UseFixedDouble(HValue* value,
XMMRegister fixed_register); XMMRegister fixed_register);
MUST_USE_RESULT LOperand* UseX87TopOfStack(HValue* value);
// A value that is guaranteed to be allocated to a register. // A value that is guaranteed to be allocated to a register.
// Operand created by UseRegister is guaranteed to be live until the end of // 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