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
This commit is contained in:
parent
b2f909cf3e
commit
a5a144c7c0
@ -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,59 +500,166 @@ 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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int LCodeGen::x87_st2idx(int pos) {
|
||||
return x87_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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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(st);
|
||||
}
|
||||
|
||||
|
||||
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::PushX87DoubleOperand(Operand src) {
|
||||
ASSERT(x87_stack_depth_ == 0);
|
||||
x87_stack_depth_++;
|
||||
__ fld_d(src);
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::PushX87FloatOperand(Operand src) {
|
||||
ASSERT(x87_stack_depth_ == 0);
|
||||
x87_stack_depth_++;
|
||||
__ fld_s(src);
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::PopX87() {
|
||||
ASSERT(x87_stack_depth_ == 1);
|
||||
x87_stack_depth_--;
|
||||
__ fstp(0);
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::CurrentInstructionReturnsX87Result() {
|
||||
ASSERT(x87_stack_depth_ <= 1);
|
||||
if (x87_stack_depth_ == 0) {
|
||||
x87_stack_depth_ = 1;
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@ -563,6 +669,12 @@ Register LCodeGen::ToRegister(LOperand* op) const {
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
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;
|
||||
// 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
|
||||
|
Loading…
Reference in New Issue
Block a user