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) {
// Use SIB with no index register only for base rsp or r12. Otherwise we
// would skip the SIB byte entirely.
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();
len_ = 2;
}
......
......@@ -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.
......@@ -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) {
ASSERT(is_uint2(imm8));
EnsureSpace ensure_space(this);
......
......@@ -153,6 +153,7 @@ struct Register {
// Unfortunately we can't make this private in a struct when initializing
// by assignment.
int code_;
private:
static const int registerCodeByAllocationIndex[kNumAllocatableRegisters];
static const int allocationIndexByRegisterCode[kNumRegisters];
......@@ -390,11 +391,15 @@ class Operand BASE_EMBEDDED {
// this must not overflow.
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:
byte rex_;
byte buf_[6];
// The number of bytes in buf_.
unsigned int len_;
// The number of bytes of buf_ in use.
byte len_;
// Set the ModR/M byte without an encoded 'reg' register. The
// register is encoded later as part of the emit_operand operation.
......@@ -824,6 +829,10 @@ class Assembler : public Malloced {
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) {
immediate_arithmetic_op_8(0x4, dst, src);
}
......@@ -1209,6 +1218,9 @@ class Assembler : public Malloced {
void movsd(XMMRegister dst, XMMRegister 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(const Operand& dst, XMMRegister src);
......@@ -1249,10 +1261,6 @@ class Assembler : public Malloced {
void emit_sse_operand(XMMRegister dst, Register 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
void Print();
......
......@@ -2866,7 +2866,7 @@ void CEntryStub::GenerateCore(MacroAssembler* masm,
__ j(zero, &failure_returned);
// Exit the JavaScript to C++ exit frame.
__ LeaveExitFrame();
__ LeaveExitFrame(save_doubles_);
__ ret(0);
// Handling of failure.
......@@ -2975,7 +2975,7 @@ void CEntryStub::Generate(MacroAssembler* masm) {
#else
int arg_stack_space = 0;
#endif
__ EnterExitFrame(arg_stack_space);
__ EnterExitFrame(arg_stack_space, save_doubles_);
// rax: Holds the context at this point, but should not be used.
// On entry to code generated by GenerateCore, it must hold
......
......@@ -1025,11 +1025,19 @@ int DisassemblerX64::TwoByteOpcodeInstruction(byte* data) {
rex_w() ? 'q' : 'd',
NameOfXMMRegister(regop));
current += PrintRightOperand(current);
} else if (opcode == 0x6F) {
AppendToBuffer("movdqa %s,",
NameOfXMMRegister(regop));
current += PrintRightOperand(current);
} else if (opcode == 0x7E) {
AppendToBuffer("mov%c ",
rex_w() ? 'q' : 'd');
current += PrintRightOperand(current);
AppendToBuffer(", %s", NameOfXMMRegister(regop));
} else if (opcode == 0x7F) {
AppendToBuffer("movdqa ");
current += PrintRightOperand(current);
AppendToBuffer(", %s", NameOfXMMRegister(regop));
} else {
const char* mnemonic = "?";
if (opcode == 0x57) {
......
......@@ -934,7 +934,18 @@ void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) {
void LCodeGen::DoCmpJSObjectEq(LCmpJSObjectEq* instr) {
Abort("Unimplemented: %s", "DoCmpJSObjectEq");
Register left = ToRegister(instr->InputAt(0));
Register right = ToRegister(instr->InputAt(1));
Register result = ToRegister(instr->result());
NearLabel different, done;
__ cmpq(left, right);
__ j(not_equal, &different);
__ LoadRoot(result, Heap::kTrueValueRootIndex);
__ jmp(&done);
__ bind(&different);
__ LoadRoot(result, Heap::kFalseValueRootIndex);
__ bind(&done);
}
......@@ -950,7 +961,45 @@ void LCodeGen::DoCmpJSObjectEqAndBranch(LCmpJSObjectEqAndBranch* instr) {
void LCodeGen::DoIsNull(LIsNull* instr) {
Abort("Unimplemented: %s", "DoIsNull");
Register reg = ToRegister(instr->InputAt(0));
Register result = ToRegister(instr->result());
// If the expression is known to be a smi, then it's
// definitely not null. Materialize false.
// Consider adding other type and representation tests too.
if (instr->hydrogen()->value()->type().IsSmi()) {
__ LoadRoot(result, Heap::kFalseValueRootIndex);
return;
}
__ CompareRoot(reg, Heap::kNullValueRootIndex);
if (instr->is_strict()) {
__ movl(result, Immediate(Heap::kTrueValueRootIndex));
NearLabel load;
__ j(equal, &load);
__ movl(result, Immediate(Heap::kFalseValueRootIndex));
__ bind(&load);
__ movq(result, Operand(kRootRegister, result, times_pointer_size, 0));
} else {
NearLabel true_value, false_value, done;
__ j(equal, &true_value);
__ CompareRoot(reg, Heap::kUndefinedValueRootIndex);
__ j(equal, &true_value);
__ JumpIfSmi(reg, &false_value);
// Check for undetectable objects by looking in the bit field in
// the map. The object has already been smi checked.
Register scratch = result;
__ movq(scratch, FieldOperand(reg, HeapObject::kMapOffset));
__ testb(FieldOperand(scratch, Map::kBitFieldOffset),
Immediate(1 << Map::kIsUndetectable));
__ j(not_zero, &true_value);
__ bind(&false_value);
__ LoadRoot(result, Heap::kFalseValueRootIndex);
__ jmp(&done);
__ bind(&true_value);
__ LoadRoot(result, Heap::kTrueValueRootIndex);
__ bind(&done);
}
}
......@@ -992,56 +1041,77 @@ void LCodeGen::DoIsNullAndBranch(LIsNullAndBranch* instr) {
Condition LCodeGen::EmitIsObject(Register input,
Register temp1,
Register temp2,
Label* is_not_object,
Label* is_object) {
ASSERT(!input.is(temp1));
ASSERT(!input.is(temp2));
ASSERT(!temp1.is(temp2));
ASSERT(!input.is(kScratchRegister));
__ JumpIfSmi(input, is_not_object);
__ Cmp(input, Factory::null_value());
__ CompareRoot(input, Heap::kNullValueRootIndex);
__ j(equal, is_object);
__ movq(temp1, FieldOperand(input, HeapObject::kMapOffset));
__ movq(kScratchRegister, FieldOperand(input, HeapObject::kMapOffset));
// Undetectable objects behave like undefined.
__ testb(FieldOperand(temp1, Map::kBitFieldOffset),
__ testb(FieldOperand(kScratchRegister, Map::kBitFieldOffset),
Immediate(1 << Map::kIsUndetectable));
__ j(not_zero, is_not_object);
__ movzxbl(temp2, FieldOperand(temp1, Map::kInstanceTypeOffset));
__ cmpb(temp2, Immediate(FIRST_JS_OBJECT_TYPE));
__ movzxbl(kScratchRegister,
FieldOperand(kScratchRegister, Map::kInstanceTypeOffset));
__ cmpb(kScratchRegister, Immediate(FIRST_JS_OBJECT_TYPE));
__ j(below, is_not_object);
__ cmpb(temp2, Immediate(LAST_JS_OBJECT_TYPE));
__ cmpb(kScratchRegister, Immediate(LAST_JS_OBJECT_TYPE));
return below_equal;
}
void LCodeGen::DoIsObject(LIsObject* instr) {
Abort("Unimplemented: %s", "DoIsObject");
Register reg = ToRegister(instr->InputAt(0));
Register result = ToRegister(instr->result());
Label is_false, is_true, done;
Condition true_cond = EmitIsObject(reg, &is_false, &is_true);
__ j(true_cond, &is_true);
__ bind(&is_false);
__ LoadRoot(result, Heap::kFalseValueRootIndex);
__ jmp(&done);
__ bind(&is_true);
__ LoadRoot(result, Heap::kTrueValueRootIndex);
__ bind(&done);
}
void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) {
Register reg = ToRegister(instr->InputAt(0));
Register temp = ToRegister(instr->TempAt(0));
Register temp2 = ToRegister(instr->TempAt(1));
int true_block = chunk_->LookupDestination(instr->true_block_id());
int false_block = chunk_->LookupDestination(instr->false_block_id());
Label* true_label = chunk_->GetAssemblyLabel(true_block);
Label* false_label = chunk_->GetAssemblyLabel(false_block);
Condition true_cond = EmitIsObject(reg, temp, temp2, false_label, true_label);
Condition true_cond = EmitIsObject(reg, false_label, true_label);
EmitBranch(true_block, false_block, true_cond);
}
void LCodeGen::DoIsSmi(LIsSmi* instr) {
Abort("Unimplemented: %s", "DoIsSmi");
LOperand* input_operand = instr->InputAt(0);
Register result = ToRegister(instr->result());
if (input_operand->IsRegister()) {
Register input = ToRegister(input_operand);
__ CheckSmiToIndicator(result, input);
} else {
Operand input = ToOperand(instr->InputAt(0));
__ CheckSmiToIndicator(result, input);
}
// result is zero if input is a smi, and one otherwise.
ASSERT(Heap::kFalseValueRootIndex == Heap::kTrueValueRootIndex + 1);
__ movq(result, Operand(kRootRegister, result, times_pointer_size,
Heap::kTrueValueRootIndex * kPointerSize));
}
......@@ -1174,7 +1244,25 @@ void LCodeGen::EmitClassOfTest(Label* is_true,
void LCodeGen::DoClassOfTest(LClassOfTest* instr) {
Abort("Unimplemented: %s", "DoClassOfTest");
Register input = ToRegister(instr->InputAt(0));
Register result = ToRegister(instr->result());
ASSERT(input.is(result));
Register temp = ToRegister(instr->TempAt(0));
Handle<String> class_name = instr->hydrogen()->class_name();
NearLabel done;
Label is_true, is_false;
EmitClassOfTest(&is_true, &is_false, class_name, input, temp);
__ j(not_equal, &is_false);
__ bind(&is_true);
__ LoadRoot(result, Heap::kTrueValueRootIndex);
__ jmp(&done);
__ bind(&is_false);
__ LoadRoot(result, Heap::kFalseValueRootIndex);
__ bind(&done);
}
......@@ -1196,7 +1284,12 @@ void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) {
void LCodeGen::DoCmpMapAndBranch(LCmpMapAndBranch* instr) {
Abort("Unimplemented: %s", "DoCmpMapAndBranch");
Register reg = ToRegister(instr->InputAt(0));
int true_block = instr->true_block_id();
int false_block = instr->false_block_id();
__ Cmp(FieldOperand(reg, HeapObject::kMapOffset), instr->map());
EmitBranch(true_block, false_block, equal);
}
......@@ -1488,27 +1581,63 @@ void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) {
void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) {
Abort("Unimplemented: %s", "DoInteger32ToDouble");
LOperand* input = instr->InputAt(0);
ASSERT(input->IsRegister() || input->IsStackSlot());
LOperand* output = instr->result();
ASSERT(output->IsDoubleRegister());
__ cvtlsi2sd(ToDoubleRegister(output), ToOperand(input));
}
void LCodeGen::DoNumberTagI(LNumberTagI* instr) {
Abort("Unimplemented: %s", "DoNumberTagI");
}
LOperand* input = instr->InputAt(0);
ASSERT(input->IsRegister() && input->Equals(instr->result()));
Register reg = ToRegister(input);
void LCodeGen::DoDeferredNumberTagI(LNumberTagI* instr) {
Abort("Unimplemented: %s", "DoDeferredNumberTagI");
__ Integer32ToSmi(reg, reg);
}
void LCodeGen::DoNumberTagD(LNumberTagD* instr) {
Abort("Unimplemented: %s", "DoNumberTagD");
class DeferredNumberTagD: public LDeferredCode {
public:
DeferredNumberTagD(LCodeGen* codegen, LNumberTagD* instr)
: LDeferredCode(codegen), instr_(instr) { }
virtual void Generate() { codegen()->DoDeferredNumberTagD(instr_); }
private:
LNumberTagD* instr_;
};
XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0));
Register reg = ToRegister(instr->result());
Register tmp = ToRegister(instr->TempAt(0));
DeferredNumberTagD* deferred = new DeferredNumberTagD(this, instr);
if (FLAG_inline_new) {
__ AllocateHeapNumber(reg, tmp, deferred->entry());
} else {
__ jmp(deferred->entry());
}
__ bind(deferred->exit());
__ movsd(FieldOperand(reg, HeapNumber::kValueOffset), input_reg);
}
void LCodeGen::DoDeferredNumberTagD(LNumberTagD* instr) {
Abort("Unimplemented: %s", "DoDeferredNumberTagD");
// TODO(3095996): Get rid of this. For now, we need to make the
// result register contain a valid pointer because it is already
// contained in the register pointer map.
Register reg = ToRegister(instr->result());
__ Move(reg, Smi::FromInt(0));
__ PushSafepointRegisters();
__ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber);
RecordSafepointWithRegisters(
instr->pointer_map(), 0, Safepoint::kNoDeoptimizationIndex);
// Ensure that value in rax survives popping registers.
__ movq(kScratchRegister, rax);
__ PopSafepointRegisters();
__ movq(reg, kScratchRegister);
}
......@@ -1525,7 +1654,34 @@ void LCodeGen::DoSmiUntag(LSmiUntag* instr) {
void LCodeGen::EmitNumberUntagD(Register input_reg,
XMMRegister result_reg,
LEnvironment* env) {
Abort("Unimplemented: %s", "EmitNumberUntagD");
NearLabel load_smi, heap_number, done;
// Smi check.
__ JumpIfSmi(input_reg, &load_smi);
// Heap number map check.
__ CompareRoot(FieldOperand(input_reg, HeapObject::kMapOffset),
Heap::kHeapNumberMapRootIndex);
__ j(equal, &heap_number);
__ CompareRoot(input_reg, Heap::kUndefinedValueRootIndex);
DeoptimizeIf(not_equal, env);
// Convert undefined to NaN. Compute NaN as 0/0.
__ xorpd(result_reg, result_reg);
__ divsd(result_reg, result_reg);
__ jmp(&done);
// Heap number to XMM conversion.
__ bind(&heap_number);
__ movsd(result_reg, FieldOperand(input_reg, HeapNumber::kValueOffset));
__ jmp(&done);
// Smi to XMM conversion
__ bind(&load_smi);
__ SmiToInteger32(kScratchRegister, input_reg); // Untag smi first.
__ cvtlsi2sd(result_reg, kScratchRegister);
__ bind(&done);
}
......
......@@ -87,7 +87,6 @@ class LCodeGen BASE_EMBEDDED {
// Deferred code support.
void DoDeferredNumberTagD(LNumberTagD* instr);
void DoDeferredNumberTagI(LNumberTagI* instr);
void DoDeferredTaggedToI(LTaggedToI* instr);
void DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr);
void DoDeferredStackCheck(LGoto* instr);
......@@ -215,8 +214,6 @@ class LCodeGen BASE_EMBEDDED {
// Returns the condition on which a final split to
// true and false label should be made, to optimize fallthrough.
Condition EmitIsObject(Register input,
Register temp1,
Register temp2,
Label* is_not_object,
Label* is_object);
......
......@@ -958,12 +958,7 @@ LInstruction* LChunkBuilder::DoTest(HTest* instr) {
} else if (v->IsIsObject()) {
HIsObject* compare = HIsObject::cast(v);
ASSERT(compare->value()->representation().IsTagged());
LOperand* temp1 = TempRegister();
LOperand* temp2 = TempRegister();
return new LIsObjectAndBranch(UseRegisterAtStart(compare->value()),
temp1,
temp2);
return new LIsObjectAndBranch(UseRegisterAtStart(compare->value()));
} else if (v->IsCompareJSObjectEq()) {
HCompareJSObjectEq* compare = HCompareJSObjectEq::cast(v);
return new LCmpJSObjectEqAndBranch(UseRegisterAtStart(compare->left()),
......@@ -1227,26 +1222,34 @@ LInstruction* LChunkBuilder::DoCompare(HCompare* instr) {
LInstruction* LChunkBuilder::DoCompareJSObjectEq(
HCompareJSObjectEq* instr) {
Abort("Unimplemented: %s", "DoCompareJSObjectEq");
return NULL;
LOperand* left = UseRegisterAtStart(instr->left());
LOperand* right = UseRegisterAtStart(instr->right());
LCmpJSObjectEq* result = new LCmpJSObjectEq(left, right);
return DefineAsRegister(result);
}
LInstruction* LChunkBuilder::DoIsNull(HIsNull* instr) {
Abort("Unimplemented: %s", "DoIsNull");
return NULL;
ASSERT(instr->value()->representation().IsTagged());
LOperand* value = UseRegisterAtStart(instr->value());
return DefineAsRegister(new LIsNull(value));
}
LInstruction* LChunkBuilder::DoIsObject(HIsObject* instr) {
Abort("Unimplemented: %s", "DoIsObject");
return NULL;
ASSERT(instr->value()->representation().IsTagged());
LOperand* value = UseRegister(instr->value());
return DefineAsRegister(new LIsObject(value));
}
LInstruction* LChunkBuilder::DoIsSmi(HIsSmi* instr) {
Abort("Unimplemented: %s", "DoIsSmi");
return NULL;
ASSERT(instr->value()->representation().IsTagged());
LOperand* value = UseAtStart(instr->value());
return DefineAsRegister(new LIsSmi(value));
}
......@@ -1300,7 +1303,62 @@ LInstruction* LChunkBuilder::DoThrow(HThrow* 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;
}
......
......@@ -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:
LIsObject(LOperand* value, LOperand* temp) {
explicit LIsObject(LOperand* value) {
inputs_[0] = value;
temps_[0] = temp;
}
DECLARE_CONCRETE_INSTRUCTION(IsObject, "is-object")
};
class LIsObjectAndBranch: public LControlInstruction<1, 2> {
class LIsObjectAndBranch: public LControlInstruction<1, 0> {
public:
LIsObjectAndBranch(LOperand* value, LOperand* temp, LOperand* temp2) {
explicit LIsObjectAndBranch(LOperand* value) {
inputs_[0] = value;
temps_[0] = temp;
temps_[1] = temp2;
}
DECLARE_CONCRETE_INSTRUCTION(IsObjectAndBranch, "is-object-and-branch")
......
......@@ -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,
int num_arguments) {
return TryCallRuntime(Runtime::FunctionForId(id), num_arguments);
......@@ -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) {
if (constant->value() == 0) {
if (!dst.is(src)) {
......@@ -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,
HandlerType type) {
// Adjust this code if not the case.
......@@ -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
const int kShaddowSpace = 4;
arg_stack_space += kShaddowSpace;
const int kShadowSpace = 4;
arg_stack_space += kShadowSpace;
#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));
}
......@@ -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);
// Setup argv in callee-saved register r12. It is reused in LeaveExitFrame,
......@@ -1805,25 +1876,31 @@ void MacroAssembler::EnterExitFrame(int arg_stack_space) {
int offset = StandardFrameConstants::kCallerSPOffset - kPointerSize;
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) {
EnterExitFramePrologue(false);
EnterExitFrameEpilogue(arg_stack_space);
EnterExitFrameEpilogue(arg_stack_space, false);
}
void MacroAssembler::LeaveExitFrame() {
void MacroAssembler::LeaveExitFrame(bool save_doubles) {
// Registers:
// 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.
movq(rcx, Operand(rbp, 1 * 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.
lea(rsp, Operand(r12, 1 * kPointerSize));
......
......@@ -152,7 +152,7 @@ class MacroAssembler: public Assembler {
//
// Allocates arg_stack_space * kPointerSize memory (not GCed) on the stack
// 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
// memory (not GCed) on the stack accessible via StackSpaceOperand.
......@@ -161,20 +161,20 @@ class MacroAssembler: public Assembler {
// Leave the current exit frame. Expects/provides the return value in
// register rax:rdx (untouched) and the pointer to the first
// argument in register rsi.
void LeaveExitFrame();
void LeaveExitFrame(bool save_doubles = false);
// Leave the current exit frame. Expects/provides the return value in
// register rax (untouched).
void LeaveApiExitFrame();
// Push and pop the registers that can hold pointers.
void PushSafepointRegisters() { UNIMPLEMENTED(); }
void PopSafepointRegisters() { UNIMPLEMENTED(); }
void PushSafepointRegisters() { Pushad(); }
void PopSafepointRegisters() { Popad(); }
static int SafepointRegisterStackIndex(int reg_code) {
UNIMPLEMENTED();
return 0;
return kSafepointPushRegisterIndices[reg_code];
}
// ---------------------------------------------------------------------------
// JavaScript invokes
......@@ -301,6 +301,11 @@ class MacroAssembler: public Assembler {
// conversion to a smi.
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
// above with a conditional jump.
......@@ -597,6 +602,9 @@ class MacroAssembler: public Assembler {
// (kScratchRegister, kSmiConstantRegister, kRootRegister).
void Pushad();
void Popad();
// Sets the stack as after performing Popad, without actually loading the
// registers.
void Dropad();
// Compare object type for heap object.
// Always use unsigned comparisons: above and below, not less and greater.
......@@ -812,6 +820,9 @@ class MacroAssembler: public Assembler {
// Call a runtime routine.
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.
// Try to generate the stub code if necessary. Do not perform a GC
// but instead return a retry after GC failure.
......@@ -931,6 +942,9 @@ class MacroAssembler: public Assembler {
bool allow_stub_calls() { return allow_stub_calls_; }
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 allow_stub_calls_;
......@@ -961,7 +975,7 @@ class MacroAssembler: public Assembler {
// Allocates arg_stack_space * kPointerSize memory (not GCed) on the stack
// accessible via StackSpaceOperand.
void EnterExitFrameEpilogue(int arg_stack_space);
void EnterExitFrameEpilogue(int arg_stack_space, bool save_doubles);
void LeaveExitFrameEpilogue();
......
......@@ -48,6 +48,12 @@ using v8::internal::rcx;
using v8::internal::rdx;
using v8::internal::rbp;
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::CodeDesc;
using v8::internal::less_equal;
......@@ -289,4 +295,47 @@ TEST(AssemblerX64LoopImmediates) {
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 __
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