Revision: 6455
Author: [email protected]
Date: Tue Jan 25 03:30:47 2011
Log: X64 Crankshaft: Added a bunch of operations.
Review URL: http://codereview.chromium.org/6366010
http://code.google.com/p/v8/source/detail?r=6455
Modified:
/branches/bleeding_edge/src/x64/assembler-x64-inl.h
/branches/bleeding_edge/src/x64/assembler-x64.cc
/branches/bleeding_edge/src/x64/assembler-x64.h
/branches/bleeding_edge/src/x64/code-stubs-x64.cc
/branches/bleeding_edge/src/x64/disasm-x64.cc
/branches/bleeding_edge/src/x64/lithium-codegen-x64.cc
/branches/bleeding_edge/src/x64/lithium-codegen-x64.h
/branches/bleeding_edge/src/x64/lithium-x64.cc
/branches/bleeding_edge/src/x64/lithium-x64.h
/branches/bleeding_edge/src/x64/macro-assembler-x64.cc
/branches/bleeding_edge/src/x64/macro-assembler-x64.h
/branches/bleeding_edge/test/cctest/test-assembler-x64.cc
=======================================
--- /branches/bleeding_edge/src/x64/assembler-x64-inl.h Wed Jan 19 03:42:43
2011
+++ /branches/bleeding_edge/src/x64/assembler-x64-inl.h Tue Jan 25 03:30:47
2011
@@ -425,7 +425,7 @@
// 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;
}
=======================================
--- /branches/bleeding_edge/src/x64/assembler-x64.cc Mon Jan 24 23:57:56
2011
+++ /branches/bleeding_edge/src/x64/assembler-x64.cc Tue Jan 25 03:30:47
2011
@@ -299,6 +299,34 @@
buf_[1] = operand.buf_[1];
}
}
+
+
+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.
@@ -2659,6 +2687,30 @@
emit(0x7E);
emit_sse_operand(src, dst);
}
+
+
+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) {
=======================================
--- /branches/bleeding_edge/src/x64/assembler-x64.h Mon Jan 24 23:57:56 2011
+++ /branches/bleeding_edge/src/x64/assembler-x64.h Tue Jan 25 03:30:47 2011
@@ -153,6 +153,7 @@
// 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 @@
// 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.
@@ -823,6 +828,10 @@
void andl(Register dst, Register 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) {
immediate_arithmetic_op_8(0x4, dst, src);
@@ -1209,6 +1218,9 @@
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 @@
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();
=======================================
--- /branches/bleeding_edge/src/x64/code-stubs-x64.cc Mon Jan 24 23:49:39
2011
+++ /branches/bleeding_edge/src/x64/code-stubs-x64.cc Tue Jan 25 03:30:47
2011
@@ -2866,7 +2866,7 @@
__ j(zero, &failure_returned);
// Exit the JavaScript to C++ exit frame.
- __ LeaveExitFrame();
+ __ LeaveExitFrame(save_doubles_);
__ ret(0);
// Handling of failure.
@@ -2975,7 +2975,7 @@
#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
=======================================
--- /branches/bleeding_edge/src/x64/disasm-x64.cc Fri Jan 21 15:58:00 2011
+++ /branches/bleeding_edge/src/x64/disasm-x64.cc Tue Jan 25 03:30:47 2011
@@ -1023,6 +1023,10 @@
if (opcode == 0x6E) {
AppendToBuffer("mov%c %s,",
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) {
@@ -1030,6 +1034,10 @@
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) {
=======================================
--- /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc Tue Jan 25
02:35:57 2011
+++ /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc Tue Jan 25
03:30:47 2011
@@ -934,7 +934,18 @@
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::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 @@
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::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::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::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");
-}
-
-
-void LCodeGen::DoDeferredNumberTagI(LNumberTagI* instr) {
- Abort("Unimplemented: %s", "DoDeferredNumberTagI");
+ LOperand* input = instr->InputAt(0);
+ ASSERT(input->IsRegister() && input->Equals(instr->result()));
+ Register reg = ToRegister(input);
+
+ __ 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::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);
}
=======================================
--- /branches/bleeding_edge/src/x64/lithium-codegen-x64.h Tue Jan 25
02:10:36 2011
+++ /branches/bleeding_edge/src/x64/lithium-codegen-x64.h Tue Jan 25
03:30:47 2011
@@ -87,7 +87,6 @@
// 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 @@
// 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);
=======================================
--- /branches/bleeding_edge/src/x64/lithium-x64.cc Tue Jan 25 02:35:57 2011
+++ /branches/bleeding_edge/src/x64/lithium-x64.cc Tue Jan 25 03:30:47 2011
@@ -958,12 +958,7 @@
} 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::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::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;
}
=======================================
--- /branches/bleeding_edge/src/x64/lithium-x64.h Tue Jan 25 02:35:57 2011
+++ /branches/bleeding_edge/src/x64/lithium-x64.h Tue Jan 25 03:30:47 2011
@@ -721,23 +721,20 @@
};
-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")
=======================================
--- /branches/bleeding_edge/src/x64/macro-assembler-x64.cc Wed Jan 19
02:17:18 2011
+++ /branches/bleeding_edge/src/x64/macro-assembler-x64.cc Tue Jan 25
03:30:47 2011
@@ -373,6 +373,16 @@
void MacroAssembler::CallRuntime(Runtime::FunctionId id, int
num_arguments) {
CallRuntime(Runtime::FunctionForId(id), 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,
@@ -965,6 +975,27 @@
testl(src, src);
return positive;
}
+
+
+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) {
@@ -1427,6 +1458,34 @@
}
+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::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::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 @@
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));
=======================================
--- /branches/bleeding_edge/src/x64/macro-assembler-x64.h Wed Jan 19
02:17:18 2011
+++ /branches/bleeding_edge/src/x64/macro-assembler-x64.h Tue Jan 25
03:30:47 2011
@@ -152,7 +152,7 @@
//
// 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,19 +161,19 @@
// 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 @@
// 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 @@
// (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 @@
// 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 @@
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 @@
// 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();
=======================================
--- /branches/bleeding_edge/test/cctest/test-assembler-x64.cc Tue Dec 7
03:01:02 2010
+++ /branches/bleeding_edge/test/cctest/test-assembler-x64.cc Tue Jan 25
03:30:47 2011
@@ -48,6 +48,12 @@
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;
@@ -288,5 +294,48 @@
int result = FUNCTION_CAST<F0>(buffer)();
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 __
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev