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);
......
This diff is collapsed.
......@@ -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