Commit 43d79516 authored by lrn@chromium.org's avatar lrn@chromium.org

X64 Crankshaft: Added a bunch of operations.

Review URL: http://codereview.chromium.org/6366010

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@6455 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 6c650cf1
...@@ -425,7 +425,7 @@ void Operand::set_sib(ScaleFactor scale, Register index, Register base) { ...@@ -425,7 +425,7 @@ void Operand::set_sib(ScaleFactor scale, Register index, Register base) {
// Use SIB with no index register only for base rsp or r12. Otherwise we // Use SIB with no index register only for base rsp or r12. Otherwise we
// would skip the SIB byte entirely. // would skip the SIB byte entirely.
ASSERT(!index.is(rsp) || base.is(rsp) || base.is(r12)); ASSERT(!index.is(rsp) || base.is(rsp) || base.is(r12));
buf_[1] = scale << 6 | index.low_bits() << 3 | base.low_bits(); buf_[1] = (scale << 6) | (index.low_bits() << 3) | base.low_bits();
rex_ |= index.high_bit() << 1 | base.high_bit(); rex_ |= index.high_bit() << 1 | base.high_bit();
len_ = 2; len_ = 2;
} }
......
...@@ -300,6 +300,34 @@ Operand::Operand(const Operand& operand, int32_t offset) { ...@@ -300,6 +300,34 @@ Operand::Operand(const Operand& operand, int32_t offset) {
} }
} }
bool Operand::AddressUsesRegister(Register reg) const {
int code = reg.code();
ASSERT((buf_[0] & 0xC0) != 0xC0); // Always a memory operand.
// Start with only low three bits of base register. Initial decoding doesn't
// distinguish on the REX.B bit.
int base_code = buf_[0] & 0x07;
if (base_code == rsp.code()) {
// SIB byte present in buf_[1].
// Check the index register from the SIB byte + REX.X prefix.
int index_code = ((buf_[1] >> 3) & 0x07) | ((rex_ & 0x02) << 2);
// Index code (including REX.X) of 0x04 (rsp) means no index register.
if (index_code != rsp.code() && index_code == code) return true;
// Add REX.B to get the full base register code.
base_code = (buf_[1] & 0x07) | ((rex_ & 0x01) << 3);
// A base register of 0x05 (rbp) with mod = 0 means no base register.
if (base_code == rbp.code() && ((buf_[0] & 0xC0) == 0)) return false;
return code == base_code;
} else {
// A base register with low bits of 0x05 (rbp or r13) and mod = 0 means
// no base register.
if (base_code == rbp.code() && ((buf_[0] & 0xC0) == 0)) return false;
base_code |= ((rex_ & 0x01) << 3);
return code == base_code;
}
}
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Implementation of Assembler. // Implementation of Assembler.
...@@ -2661,6 +2689,30 @@ void Assembler::movq(Register dst, XMMRegister src) { ...@@ -2661,6 +2689,30 @@ void Assembler::movq(Register dst, XMMRegister src) {
} }
void Assembler::movdqa(const Operand& dst, XMMRegister src) {
ASSERT(CpuFeatures::IsEnabled(SSE2));
EnsureSpace ensure_space(this);
last_pc_ = pc_;
emit(0x66);
emit_rex_64(src, dst);
emit(0x0F);
emit(0x7F);
emit_sse_operand(src, dst);
}
void Assembler::movdqa(XMMRegister dst, const Operand& src) {
ASSERT(CpuFeatures::IsEnabled(SSE2));
EnsureSpace ensure_space(this);
last_pc_ = pc_;
emit(0x66);
emit_rex_64(dst, src);
emit(0x0F);
emit(0x6F);
emit_sse_operand(dst, src);
}
void Assembler::extractps(Register dst, XMMRegister src, byte imm8) { void Assembler::extractps(Register dst, XMMRegister src, byte imm8) {
ASSERT(is_uint2(imm8)); ASSERT(is_uint2(imm8));
EnsureSpace ensure_space(this); EnsureSpace ensure_space(this);
......
...@@ -153,6 +153,7 @@ struct Register { ...@@ -153,6 +153,7 @@ struct Register {
// Unfortunately we can't make this private in a struct when initializing // Unfortunately we can't make this private in a struct when initializing
// by assignment. // by assignment.
int code_; int code_;
private: private:
static const int registerCodeByAllocationIndex[kNumAllocatableRegisters]; static const int registerCodeByAllocationIndex[kNumAllocatableRegisters];
static const int allocationIndexByRegisterCode[kNumRegisters]; static const int allocationIndexByRegisterCode[kNumRegisters];
...@@ -390,11 +391,15 @@ class Operand BASE_EMBEDDED { ...@@ -390,11 +391,15 @@ class Operand BASE_EMBEDDED {
// this must not overflow. // this must not overflow.
Operand(const Operand& base, int32_t offset); Operand(const Operand& base, int32_t offset);
// Checks whether either base or index register is the given register.
// Does not check the "reg" part of the Operand.
bool AddressUsesRegister(Register reg) const;
private: private:
byte rex_; byte rex_;
byte buf_[6]; byte buf_[6];
// The number of bytes in buf_. // The number of bytes of buf_ in use.
unsigned int len_; byte len_;
// Set the ModR/M byte without an encoded 'reg' register. The // Set the ModR/M byte without an encoded 'reg' register. The
// register is encoded later as part of the emit_operand operation. // register is encoded later as part of the emit_operand operation.
...@@ -824,6 +829,10 @@ class Assembler : public Malloced { ...@@ -824,6 +829,10 @@ class Assembler : public Malloced {
arithmetic_op_32(0x23, dst, src); arithmetic_op_32(0x23, dst, src);
} }
void andl(Register dst, const Operand& src) {
arithmetic_op_32(0x23, dst, src);
}
void andb(Register dst, Immediate src) { void andb(Register dst, Immediate src) {
immediate_arithmetic_op_8(0x4, dst, src); immediate_arithmetic_op_8(0x4, dst, src);
} }
...@@ -1209,6 +1218,9 @@ class Assembler : public Malloced { ...@@ -1209,6 +1218,9 @@ class Assembler : public Malloced {
void movsd(XMMRegister dst, XMMRegister src); void movsd(XMMRegister dst, XMMRegister src);
void movsd(XMMRegister dst, const Operand& src); void movsd(XMMRegister dst, const Operand& src);
void movdqa(const Operand& dst, XMMRegister src);
void movdqa(XMMRegister dst, const Operand& src);
void movss(XMMRegister dst, const Operand& src); void movss(XMMRegister dst, const Operand& src);
void movss(const Operand& dst, XMMRegister src); void movss(const Operand& dst, XMMRegister src);
...@@ -1249,10 +1261,6 @@ class Assembler : public Malloced { ...@@ -1249,10 +1261,6 @@ class Assembler : public Malloced {
void emit_sse_operand(XMMRegister dst, Register src); void emit_sse_operand(XMMRegister dst, Register src);
void emit_sse_operand(Register dst, XMMRegister src); void emit_sse_operand(Register dst, XMMRegister src);
// Use either movsd or movlpd.
// void movdbl(XMMRegister dst, const Operand& src);
// void movdbl(const Operand& dst, XMMRegister src);
// Debugging // Debugging
void Print(); void Print();
......
...@@ -2866,7 +2866,7 @@ void CEntryStub::GenerateCore(MacroAssembler* masm, ...@@ -2866,7 +2866,7 @@ void CEntryStub::GenerateCore(MacroAssembler* masm,
__ j(zero, &failure_returned); __ j(zero, &failure_returned);
// Exit the JavaScript to C++ exit frame. // Exit the JavaScript to C++ exit frame.
__ LeaveExitFrame(); __ LeaveExitFrame(save_doubles_);
__ ret(0); __ ret(0);
// Handling of failure. // Handling of failure.
...@@ -2975,7 +2975,7 @@ void CEntryStub::Generate(MacroAssembler* masm) { ...@@ -2975,7 +2975,7 @@ void CEntryStub::Generate(MacroAssembler* masm) {
#else #else
int arg_stack_space = 0; int arg_stack_space = 0;
#endif #endif
__ EnterExitFrame(arg_stack_space); __ EnterExitFrame(arg_stack_space, save_doubles_);
// rax: Holds the context at this point, but should not be used. // rax: Holds the context at this point, but should not be used.
// On entry to code generated by GenerateCore, it must hold // On entry to code generated by GenerateCore, it must hold
......
...@@ -1025,11 +1025,19 @@ int DisassemblerX64::TwoByteOpcodeInstruction(byte* data) { ...@@ -1025,11 +1025,19 @@ int DisassemblerX64::TwoByteOpcodeInstruction(byte* data) {
rex_w() ? 'q' : 'd', rex_w() ? 'q' : 'd',
NameOfXMMRegister(regop)); NameOfXMMRegister(regop));
current += PrintRightOperand(current); current += PrintRightOperand(current);
} else if (opcode == 0x6F) {
AppendToBuffer("movdqa %s,",
NameOfXMMRegister(regop));
current += PrintRightOperand(current);
} else if (opcode == 0x7E) { } else if (opcode == 0x7E) {
AppendToBuffer("mov%c ", AppendToBuffer("mov%c ",
rex_w() ? 'q' : 'd'); rex_w() ? 'q' : 'd');
current += PrintRightOperand(current); current += PrintRightOperand(current);
AppendToBuffer(", %s", NameOfXMMRegister(regop)); AppendToBuffer(", %s", NameOfXMMRegister(regop));
} else if (opcode == 0x7F) {
AppendToBuffer("movdqa ");
current += PrintRightOperand(current);
AppendToBuffer(", %s", NameOfXMMRegister(regop));
} else { } else {
const char* mnemonic = "?"; const char* mnemonic = "?";
if (opcode == 0x57) { if (opcode == 0x57) {
......
This diff is collapsed.
...@@ -87,7 +87,6 @@ class LCodeGen BASE_EMBEDDED { ...@@ -87,7 +87,6 @@ class LCodeGen BASE_EMBEDDED {
// Deferred code support. // Deferred code support.
void DoDeferredNumberTagD(LNumberTagD* instr); void DoDeferredNumberTagD(LNumberTagD* instr);
void DoDeferredNumberTagI(LNumberTagI* instr);
void DoDeferredTaggedToI(LTaggedToI* instr); void DoDeferredTaggedToI(LTaggedToI* instr);
void DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr); void DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr);
void DoDeferredStackCheck(LGoto* instr); void DoDeferredStackCheck(LGoto* instr);
...@@ -215,8 +214,6 @@ class LCodeGen BASE_EMBEDDED { ...@@ -215,8 +214,6 @@ class LCodeGen BASE_EMBEDDED {
// Returns the condition on which a final split to // Returns the condition on which a final split to
// true and false label should be made, to optimize fallthrough. // true and false label should be made, to optimize fallthrough.
Condition EmitIsObject(Register input, Condition EmitIsObject(Register input,
Register temp1,
Register temp2,
Label* is_not_object, Label* is_not_object,
Label* is_object); Label* is_object);
......
...@@ -958,12 +958,7 @@ LInstruction* LChunkBuilder::DoTest(HTest* instr) { ...@@ -958,12 +958,7 @@ LInstruction* LChunkBuilder::DoTest(HTest* instr) {
} else if (v->IsIsObject()) { } else if (v->IsIsObject()) {
HIsObject* compare = HIsObject::cast(v); HIsObject* compare = HIsObject::cast(v);
ASSERT(compare->value()->representation().IsTagged()); ASSERT(compare->value()->representation().IsTagged());
return new LIsObjectAndBranch(UseRegisterAtStart(compare->value()));
LOperand* temp1 = TempRegister();
LOperand* temp2 = TempRegister();
return new LIsObjectAndBranch(UseRegisterAtStart(compare->value()),
temp1,
temp2);
} else if (v->IsCompareJSObjectEq()) { } else if (v->IsCompareJSObjectEq()) {
HCompareJSObjectEq* compare = HCompareJSObjectEq::cast(v); HCompareJSObjectEq* compare = HCompareJSObjectEq::cast(v);
return new LCmpJSObjectEqAndBranch(UseRegisterAtStart(compare->left()), return new LCmpJSObjectEqAndBranch(UseRegisterAtStart(compare->left()),
...@@ -1227,26 +1222,34 @@ LInstruction* LChunkBuilder::DoCompare(HCompare* instr) { ...@@ -1227,26 +1222,34 @@ LInstruction* LChunkBuilder::DoCompare(HCompare* instr) {
LInstruction* LChunkBuilder::DoCompareJSObjectEq( LInstruction* LChunkBuilder::DoCompareJSObjectEq(
HCompareJSObjectEq* instr) { HCompareJSObjectEq* instr) {
Abort("Unimplemented: %s", "DoCompareJSObjectEq"); LOperand* left = UseRegisterAtStart(instr->left());
return NULL; LOperand* right = UseRegisterAtStart(instr->right());
LCmpJSObjectEq* result = new LCmpJSObjectEq(left, right);
return DefineAsRegister(result);
} }
LInstruction* LChunkBuilder::DoIsNull(HIsNull* instr) { LInstruction* LChunkBuilder::DoIsNull(HIsNull* instr) {
Abort("Unimplemented: %s", "DoIsNull"); ASSERT(instr->value()->representation().IsTagged());
return NULL; LOperand* value = UseRegisterAtStart(instr->value());
return DefineAsRegister(new LIsNull(value));
} }
LInstruction* LChunkBuilder::DoIsObject(HIsObject* instr) { LInstruction* LChunkBuilder::DoIsObject(HIsObject* instr) {
Abort("Unimplemented: %s", "DoIsObject"); ASSERT(instr->value()->representation().IsTagged());
return NULL; LOperand* value = UseRegister(instr->value());
return DefineAsRegister(new LIsObject(value));
} }
LInstruction* LChunkBuilder::DoIsSmi(HIsSmi* instr) { LInstruction* LChunkBuilder::DoIsSmi(HIsSmi* instr) {
Abort("Unimplemented: %s", "DoIsSmi"); ASSERT(instr->value()->representation().IsTagged());
return NULL; LOperand* value = UseAtStart(instr->value());
return DefineAsRegister(new LIsSmi(value));
} }
...@@ -1300,7 +1303,62 @@ LInstruction* LChunkBuilder::DoThrow(HThrow* instr) { ...@@ -1300,7 +1303,62 @@ LInstruction* LChunkBuilder::DoThrow(HThrow* instr) {
LInstruction* LChunkBuilder::DoChange(HChange* instr) { LInstruction* LChunkBuilder::DoChange(HChange* instr) {
Abort("Unimplemented: %s", "DoChange"); Representation from = instr->from();
Representation to = instr->to();
if (from.IsTagged()) {
if (to.IsDouble()) {
LOperand* value = UseRegister(instr->value());
LNumberUntagD* res = new LNumberUntagD(value);
return AssignEnvironment(DefineAsRegister(res));
} else {
ASSERT(to.IsInteger32());
LOperand* value = UseRegister(instr->value());
bool needs_check = !instr->value()->type().IsSmi();
if (needs_check) {
LOperand* xmm_temp =
(instr->CanTruncateToInt32() && CpuFeatures::IsSupported(SSE3))
? NULL
: FixedTemp(xmm1);
LTaggedToI* res = new LTaggedToI(value, xmm_temp);
return AssignEnvironment(DefineSameAsFirst(res));
} else {
return DefineSameAsFirst(new LSmiUntag(value, needs_check));
}
}
} else if (from.IsDouble()) {
if (to.IsTagged()) {
LOperand* value = UseRegister(instr->value());
LOperand* temp = TempRegister();
// Make sure that temp and result_temp are different registers.
LUnallocated* result_temp = TempRegister();
LNumberTagD* result = new LNumberTagD(value, temp);
return AssignPointerMap(Define(result, result_temp));
} else {
ASSERT(to.IsInteger32());
bool needs_temp = instr->CanTruncateToInt32() &&
!CpuFeatures::IsSupported(SSE3);
LOperand* value = needs_temp ?
UseTempRegister(instr->value()) : UseRegister(instr->value());
LOperand* temp = needs_temp ? TempRegister() : NULL;
return AssignEnvironment(DefineAsRegister(new LDoubleToI(value, temp)));
}
} else if (from.IsInteger32()) {
if (to.IsTagged()) {
HValue* val = instr->value();
LOperand* value = UseRegister(val);
if (val->HasRange() && val->range()->IsInSmiRange()) {
return DefineSameAsFirst(new LSmiTag(value));
} else {
LNumberTagI* result = new LNumberTagI(value);
return AssignEnvironment(AssignPointerMap(DefineSameAsFirst(result)));
}
} else {
ASSERT(to.IsDouble());
return DefineAsRegister(new LInteger32ToDouble(Use(instr->value())));
}
}
UNREACHABLE();
return NULL; return NULL;
} }
......
...@@ -721,23 +721,20 @@ class LIsNullAndBranch: public LControlInstruction<1, 1> { ...@@ -721,23 +721,20 @@ class LIsNullAndBranch: public LControlInstruction<1, 1> {
}; };
class LIsObject: public LTemplateInstruction<1, 1, 1> { class LIsObject: public LTemplateInstruction<1, 1, 0> {
public: public:
LIsObject(LOperand* value, LOperand* temp) { explicit LIsObject(LOperand* value) {
inputs_[0] = value; inputs_[0] = value;
temps_[0] = temp;
} }
DECLARE_CONCRETE_INSTRUCTION(IsObject, "is-object") DECLARE_CONCRETE_INSTRUCTION(IsObject, "is-object")
}; };
class LIsObjectAndBranch: public LControlInstruction<1, 2> { class LIsObjectAndBranch: public LControlInstruction<1, 0> {
public: public:
LIsObjectAndBranch(LOperand* value, LOperand* temp, LOperand* temp2) { explicit LIsObjectAndBranch(LOperand* value) {
inputs_[0] = value; inputs_[0] = value;
temps_[0] = temp;
temps_[1] = temp2;
} }
DECLARE_CONCRETE_INSTRUCTION(IsObjectAndBranch, "is-object-and-branch") DECLARE_CONCRETE_INSTRUCTION(IsObjectAndBranch, "is-object-and-branch")
......
...@@ -375,6 +375,16 @@ void MacroAssembler::CallRuntime(Runtime::FunctionId id, int num_arguments) { ...@@ -375,6 +375,16 @@ void MacroAssembler::CallRuntime(Runtime::FunctionId id, int num_arguments) {
} }
void MacroAssembler::CallRuntimeSaveDoubles(Runtime::FunctionId id) {
Runtime::Function* function = Runtime::FunctionForId(id);
Set(rax, function->nargs);
movq(rbx, ExternalReference(function));
CEntryStub ces(1);
ces.SaveDoubles();
CallStub(&ces);
}
MaybeObject* MacroAssembler::TryCallRuntime(Runtime::FunctionId id, MaybeObject* MacroAssembler::TryCallRuntime(Runtime::FunctionId id,
int num_arguments) { int num_arguments) {
return TryCallRuntime(Runtime::FunctionForId(id), num_arguments); return TryCallRuntime(Runtime::FunctionForId(id), num_arguments);
...@@ -967,6 +977,27 @@ Condition MacroAssembler::CheckUInteger32ValidSmiValue(Register src) { ...@@ -967,6 +977,27 @@ Condition MacroAssembler::CheckUInteger32ValidSmiValue(Register src) {
} }
void MacroAssembler::CheckSmiToIndicator(Register dst, Register src) {
if (dst.is(src)) {
andl(dst, Immediate(kSmiTagMask));
} else {
movl(dst, Immediate(kSmiTagMask));
andl(dst, src);
}
}
void MacroAssembler::CheckSmiToIndicator(Register dst, const Operand& src) {
if (!(src.AddressUsesRegister(dst))) {
movl(dst, Immediate(kSmiTagMask));
andl(dst, src);
} else {
movl(dst, src);
andl(dst, Immediate(kSmiTagMask));
}
}
void MacroAssembler::SmiAddConstant(Register dst, Register src, Smi* constant) { void MacroAssembler::SmiAddConstant(Register dst, Register src, Smi* constant) {
if (constant->value() == 0) { if (constant->value() == 0) {
if (!dst.is(src)) { if (!dst.is(src)) {
...@@ -1427,6 +1458,34 @@ void MacroAssembler::Popad() { ...@@ -1427,6 +1458,34 @@ void MacroAssembler::Popad() {
} }
void MacroAssembler::Dropad() {
const int kRegistersPushedByPushad = 11;
addq(rsp, Immediate(kRegistersPushedByPushad * kPointerSize));
}
// Order general registers are pushed by Pushad:
// rax, rcx, rdx, rbx, rsi, rdi, r8, r9, r11, r12, r14.
int MacroAssembler::kSafepointPushRegisterIndices[Register::kNumRegisters] = {
0,
1,
2,
3,
-1,
-1,
4,
5,
6,
7,
-1,
8,
9,
-1,
10,
-1
};
void MacroAssembler::PushTryHandler(CodeLocation try_location, void MacroAssembler::PushTryHandler(CodeLocation try_location,
HandlerType type) { HandlerType type) {
// Adjust this code if not the case. // Adjust this code if not the case.
...@@ -1775,12 +1834,24 @@ void MacroAssembler::EnterExitFramePrologue(bool save_rax) { ...@@ -1775,12 +1834,24 @@ void MacroAssembler::EnterExitFramePrologue(bool save_rax) {
} }
void MacroAssembler::EnterExitFrameEpilogue(int arg_stack_space) { void MacroAssembler::EnterExitFrameEpilogue(int arg_stack_space,
bool save_doubles) {
#ifdef _WIN64 #ifdef _WIN64
const int kShaddowSpace = 4; const int kShadowSpace = 4;
arg_stack_space += kShaddowSpace; arg_stack_space += kShadowSpace;
#endif #endif
if (arg_stack_space > 0) { // Optionally save all XMM registers.
if (save_doubles) {
CpuFeatures::Scope scope(SSE2);
int space = XMMRegister::kNumRegisters * kDoubleSize +
arg_stack_space * kPointerSize;
subq(rsp, Immediate(space));
int offset = -2 * kPointerSize;
for (int i = 0; i < XMMRegister::kNumAllocatableRegisters; i++) {
XMMRegister reg = XMMRegister::FromAllocationIndex(i);
movsd(Operand(rbp, offset - ((i + 1) * kDoubleSize)), reg);
}
} else if (arg_stack_space > 0) {
subq(rsp, Immediate(arg_stack_space * kPointerSize)); subq(rsp, Immediate(arg_stack_space * kPointerSize));
} }
...@@ -1797,7 +1868,7 @@ void MacroAssembler::EnterExitFrameEpilogue(int arg_stack_space) { ...@@ -1797,7 +1868,7 @@ void MacroAssembler::EnterExitFrameEpilogue(int arg_stack_space) {
} }
void MacroAssembler::EnterExitFrame(int arg_stack_space) { void MacroAssembler::EnterExitFrame(int arg_stack_space, bool save_doubles) {
EnterExitFramePrologue(true); EnterExitFramePrologue(true);
// Setup argv in callee-saved register r12. It is reused in LeaveExitFrame, // Setup argv in callee-saved register r12. It is reused in LeaveExitFrame,
...@@ -1805,25 +1876,31 @@ void MacroAssembler::EnterExitFrame(int arg_stack_space) { ...@@ -1805,25 +1876,31 @@ void MacroAssembler::EnterExitFrame(int arg_stack_space) {
int offset = StandardFrameConstants::kCallerSPOffset - kPointerSize; int offset = StandardFrameConstants::kCallerSPOffset - kPointerSize;
lea(r12, Operand(rbp, r14, times_pointer_size, offset)); lea(r12, Operand(rbp, r14, times_pointer_size, offset));
EnterExitFrameEpilogue(arg_stack_space); EnterExitFrameEpilogue(arg_stack_space, save_doubles);
} }
void MacroAssembler::EnterApiExitFrame(int arg_stack_space) { void MacroAssembler::EnterApiExitFrame(int arg_stack_space) {
EnterExitFramePrologue(false); EnterExitFramePrologue(false);
EnterExitFrameEpilogue(arg_stack_space); EnterExitFrameEpilogue(arg_stack_space, false);
} }
void MacroAssembler::LeaveExitFrame() { void MacroAssembler::LeaveExitFrame(bool save_doubles) {
// Registers: // Registers:
// r12 : argv // r12 : argv
if (save_doubles) {
int offset = -2 * kPointerSize;
for (int i = 0; i < XMMRegister::kNumAllocatableRegisters; i++) {
XMMRegister reg = XMMRegister::FromAllocationIndex(i);
movsd(reg, Operand(rbp, offset - ((i + 1) * kDoubleSize)));
}
}
// Get the return address from the stack and restore the frame pointer. // Get the return address from the stack and restore the frame pointer.
movq(rcx, Operand(rbp, 1 * kPointerSize)); movq(rcx, Operand(rbp, 1 * kPointerSize));
movq(rbp, Operand(rbp, 0 * kPointerSize)); movq(rbp, Operand(rbp, 0 * kPointerSize));
// Pop everything up to and including the arguments and the receiver // Drop everything up to and including the arguments and the receiver
// from the caller stack. // from the caller stack.
lea(rsp, Operand(r12, 1 * kPointerSize)); lea(rsp, Operand(r12, 1 * kPointerSize));
......
...@@ -152,7 +152,7 @@ class MacroAssembler: public Assembler { ...@@ -152,7 +152,7 @@ class MacroAssembler: public Assembler {
// //
// Allocates arg_stack_space * kPointerSize memory (not GCed) on the stack // Allocates arg_stack_space * kPointerSize memory (not GCed) on the stack
// accessible via StackSpaceOperand. // accessible via StackSpaceOperand.
void EnterExitFrame(int arg_stack_space = 0); void EnterExitFrame(int arg_stack_space = 0, bool save_doubles = false);
// Enter specific kind of exit frame. Allocates arg_stack_space * kPointerSize // Enter specific kind of exit frame. Allocates arg_stack_space * kPointerSize
// memory (not GCed) on the stack accessible via StackSpaceOperand. // memory (not GCed) on the stack accessible via StackSpaceOperand.
...@@ -161,20 +161,20 @@ class MacroAssembler: public Assembler { ...@@ -161,20 +161,20 @@ class MacroAssembler: public Assembler {
// Leave the current exit frame. Expects/provides the return value in // Leave the current exit frame. Expects/provides the return value in
// register rax:rdx (untouched) and the pointer to the first // register rax:rdx (untouched) and the pointer to the first
// argument in register rsi. // argument in register rsi.
void LeaveExitFrame(); void LeaveExitFrame(bool save_doubles = false);
// Leave the current exit frame. Expects/provides the return value in // Leave the current exit frame. Expects/provides the return value in
// register rax (untouched). // register rax (untouched).
void LeaveApiExitFrame(); void LeaveApiExitFrame();
// Push and pop the registers that can hold pointers. // Push and pop the registers that can hold pointers.
void PushSafepointRegisters() { UNIMPLEMENTED(); } void PushSafepointRegisters() { Pushad(); }
void PopSafepointRegisters() { UNIMPLEMENTED(); } void PopSafepointRegisters() { Popad(); }
static int SafepointRegisterStackIndex(int reg_code) { static int SafepointRegisterStackIndex(int reg_code) {
UNIMPLEMENTED(); return kSafepointPushRegisterIndices[reg_code];
return 0;
} }
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// JavaScript invokes // JavaScript invokes
...@@ -301,6 +301,11 @@ class MacroAssembler: public Assembler { ...@@ -301,6 +301,11 @@ class MacroAssembler: public Assembler {
// conversion to a smi. // conversion to a smi.
Condition CheckUInteger32ValidSmiValue(Register src); Condition CheckUInteger32ValidSmiValue(Register src);
// Check whether src is a Smi, and set dst to zero if it is a smi,
// and to one if it isn't.
void CheckSmiToIndicator(Register dst, Register src);
void CheckSmiToIndicator(Register dst, const Operand& src);
// Test-and-jump functions. Typically combines a check function // Test-and-jump functions. Typically combines a check function
// above with a conditional jump. // above with a conditional jump.
...@@ -597,6 +602,9 @@ class MacroAssembler: public Assembler { ...@@ -597,6 +602,9 @@ class MacroAssembler: public Assembler {
// (kScratchRegister, kSmiConstantRegister, kRootRegister). // (kScratchRegister, kSmiConstantRegister, kRootRegister).
void Pushad(); void Pushad();
void Popad(); void Popad();
// Sets the stack as after performing Popad, without actually loading the
// registers.
void Dropad();
// Compare object type for heap object. // Compare object type for heap object.
// Always use unsigned comparisons: above and below, not less and greater. // Always use unsigned comparisons: above and below, not less and greater.
...@@ -812,6 +820,9 @@ class MacroAssembler: public Assembler { ...@@ -812,6 +820,9 @@ class MacroAssembler: public Assembler {
// Call a runtime routine. // Call a runtime routine.
void CallRuntime(Runtime::Function* f, int num_arguments); void CallRuntime(Runtime::Function* f, int num_arguments);
// Call a runtime function and save the value of XMM registers.
void CallRuntimeSaveDoubles(Runtime::FunctionId id);
// Call a runtime function, returning the CodeStub object called. // Call a runtime function, returning the CodeStub object called.
// Try to generate the stub code if necessary. Do not perform a GC // Try to generate the stub code if necessary. Do not perform a GC
// but instead return a retry after GC failure. // but instead return a retry after GC failure.
...@@ -931,6 +942,9 @@ class MacroAssembler: public Assembler { ...@@ -931,6 +942,9 @@ class MacroAssembler: public Assembler {
bool allow_stub_calls() { return allow_stub_calls_; } bool allow_stub_calls() { return allow_stub_calls_; }
private: private:
// Order general registers are pushed by Pushad.
// rax, rcx, rdx, rbx, rsi, rdi, r8, r9, r11, r12, r14.
static int kSafepointPushRegisterIndices[Register::kNumRegisters];
bool generating_stub_; bool generating_stub_;
bool allow_stub_calls_; bool allow_stub_calls_;
...@@ -961,7 +975,7 @@ class MacroAssembler: public Assembler { ...@@ -961,7 +975,7 @@ class MacroAssembler: public Assembler {
// Allocates arg_stack_space * kPointerSize memory (not GCed) on the stack // Allocates arg_stack_space * kPointerSize memory (not GCed) on the stack
// accessible via StackSpaceOperand. // accessible via StackSpaceOperand.
void EnterExitFrameEpilogue(int arg_stack_space); void EnterExitFrameEpilogue(int arg_stack_space, bool save_doubles);
void LeaveExitFrameEpilogue(); void LeaveExitFrameEpilogue();
......
...@@ -48,6 +48,12 @@ using v8::internal::rcx; ...@@ -48,6 +48,12 @@ using v8::internal::rcx;
using v8::internal::rdx; using v8::internal::rdx;
using v8::internal::rbp; using v8::internal::rbp;
using v8::internal::rsp; using v8::internal::rsp;
using v8::internal::r8;
using v8::internal::r9;
using v8::internal::r12;
using v8::internal::r13;
using v8::internal::times_1;
using v8::internal::FUNCTION_CAST; using v8::internal::FUNCTION_CAST;
using v8::internal::CodeDesc; using v8::internal::CodeDesc;
using v8::internal::less_equal; using v8::internal::less_equal;
...@@ -289,4 +295,47 @@ TEST(AssemblerX64LoopImmediates) { ...@@ -289,4 +295,47 @@ TEST(AssemblerX64LoopImmediates) {
CHECK_EQ(1, result); CHECK_EQ(1, result);
} }
TEST(OperandRegisterDependency) {
int offsets[4] = {0, 1, 0xfed, 0xbeefcad};
for (int i = 0; i < 4; i++) {
int offset = offsets[i];
CHECK(Operand(rax, offset).AddressUsesRegister(rax));
CHECK(!Operand(rax, offset).AddressUsesRegister(r8));
CHECK(!Operand(rax, offset).AddressUsesRegister(rcx));
CHECK(Operand(rax, rax, times_1, offset).AddressUsesRegister(rax));
CHECK(!Operand(rax, rax, times_1, offset).AddressUsesRegister(r8));
CHECK(!Operand(rax, rax, times_1, offset).AddressUsesRegister(rcx));
CHECK(Operand(rax, rcx, times_1, offset).AddressUsesRegister(rax));
CHECK(Operand(rax, rcx, times_1, offset).AddressUsesRegister(rcx));
CHECK(!Operand(rax, rcx, times_1, offset).AddressUsesRegister(r8));
CHECK(!Operand(rax, rcx, times_1, offset).AddressUsesRegister(r9));
CHECK(!Operand(rax, rcx, times_1, offset).AddressUsesRegister(rdx));
CHECK(!Operand(rax, rcx, times_1, offset).AddressUsesRegister(rsp));
CHECK(Operand(rsp, offset).AddressUsesRegister(rsp));
CHECK(!Operand(rsp, offset).AddressUsesRegister(rax));
CHECK(!Operand(rsp, offset).AddressUsesRegister(r12));
CHECK(Operand(rbp, offset).AddressUsesRegister(rbp));
CHECK(!Operand(rbp, offset).AddressUsesRegister(rax));
CHECK(!Operand(rbp, offset).AddressUsesRegister(r13));
CHECK(Operand(rbp, rax, times_1, offset).AddressUsesRegister(rbp));
CHECK(Operand(rbp, rax, times_1, offset).AddressUsesRegister(rax));
CHECK(!Operand(rbp, rax, times_1, offset).AddressUsesRegister(rcx));
CHECK(!Operand(rbp, rax, times_1, offset).AddressUsesRegister(r13));
CHECK(!Operand(rbp, rax, times_1, offset).AddressUsesRegister(r8));
CHECK(!Operand(rbp, rax, times_1, offset).AddressUsesRegister(rsp));
CHECK(Operand(rsp, rbp, times_1, offset).AddressUsesRegister(rsp));
CHECK(Operand(rsp, rbp, times_1, offset).AddressUsesRegister(rbp));
CHECK(!Operand(rsp, rbp, times_1, offset).AddressUsesRegister(rax));
CHECK(!Operand(rsp, rbp, times_1, offset).AddressUsesRegister(r12));
CHECK(!Operand(rsp, rbp, times_1, offset).AddressUsesRegister(r13));
}
}
#undef __ #undef __
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