Commit e66ceb90 authored by lrn@chromium.org's avatar lrn@chromium.org

X64 Crank: Implemented DoBranch and all *AndBranch comparisons.

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@6385 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 8d3b6755
......@@ -1285,11 +1285,11 @@ void LCodeGen::DoCmpID(LCmpID* instr) {
NearLabel done;
Condition cc = TokenToCondition(instr->op(), instr->is_double());
__ mov(ToRegister(result), Handle<Object>(Heap::true_value()));
__ mov(ToRegister(result), Factory::true_value());
__ j(cc, &done);
__ bind(&unordered);
__ mov(ToRegister(result), Handle<Object>(Heap::false_value()));
__ mov(ToRegister(result), Factory::false_value());
__ bind(&done);
}
......@@ -1320,10 +1320,10 @@ void LCodeGen::DoCmpJSObjectEq(LCmpJSObjectEq* instr) {
Register result = ToRegister(instr->result());
__ cmp(left, Operand(right));
__ mov(result, Handle<Object>(Heap::true_value()));
__ mov(result, Factory::true_value());
NearLabel done;
__ j(equal, &done);
__ mov(result, Handle<Object>(Heap::false_value()));
__ mov(result, Factory::false_value());
__ bind(&done);
}
......@@ -1348,10 +1348,10 @@ void LCodeGen::DoIsNull(LIsNull* instr) {
__ cmp(reg, Factory::null_value());
if (instr->is_strict()) {
__ mov(result, Handle<Object>(Heap::true_value()));
__ mov(result, Factory::true_value());
NearLabel done;
__ j(equal, &done);
__ mov(result, Handle<Object>(Heap::false_value()));
__ mov(result, Factory::false_value());
__ bind(&done);
} else {
NearLabel true_value, false_value, done;
......@@ -1368,10 +1368,10 @@ void LCodeGen::DoIsNull(LIsNull* instr) {
__ test(scratch, Immediate(1 << Map::kIsUndetectable));
__ j(not_zero, &true_value);
__ bind(&false_value);
__ mov(result, Handle<Object>(Heap::false_value()));
__ mov(result, Factory::false_value());
__ jmp(&done);
__ bind(&true_value);
__ mov(result, Handle<Object>(Heap::true_value()));
__ mov(result, Factory::true_value());
__ bind(&done);
}
}
......@@ -1447,11 +1447,11 @@ void LCodeGen::DoIsObject(LIsObject* instr) {
__ j(true_cond, &is_true);
__ bind(&is_false);
__ mov(result, Handle<Object>(Heap::false_value()));
__ mov(result, Factory::false_value());
__ jmp(&done);
__ bind(&is_true);
__ mov(result, Handle<Object>(Heap::true_value()));
__ mov(result, Factory::true_value());
__ bind(&done);
}
......@@ -1479,10 +1479,10 @@ void LCodeGen::DoIsSmi(LIsSmi* instr) {
ASSERT(instr->hydrogen()->value()->representation().IsTagged());
__ test(input, Immediate(kSmiTagMask));
__ mov(result, Handle<Object>(Heap::true_value()));
__ mov(result, Factory::true_value());
NearLabel done;
__ j(zero, &done);
__ mov(result, Handle<Object>(Heap::false_value()));
__ mov(result, Factory::false_value());
__ bind(&done);
}
......@@ -1507,7 +1507,6 @@ static InstanceType TestType(HHasInstanceType* instr) {
}
static Condition BranchCondition(HHasInstanceType* instr) {
InstanceType from = instr->from();
InstanceType to = instr->to();
......@@ -1529,10 +1528,10 @@ void LCodeGen::DoHasInstanceType(LHasInstanceType* instr) {
__ j(zero, &is_false);
__ CmpObjectType(input, TestType(instr->hydrogen()), result);
__ j(NegateCondition(BranchCondition(instr->hydrogen())), &is_false);
__ mov(result, Handle<Object>(Heap::true_value()));
__ mov(result, Factory::true_value());
__ jmp(&done);
__ bind(&is_false);
__ mov(result, Handle<Object>(Heap::false_value()));
__ mov(result, Factory::false_value());
__ bind(&done);
}
......@@ -1559,12 +1558,12 @@ void LCodeGen::DoHasCachedArrayIndex(LHasCachedArrayIndex* instr) {
Register result = ToRegister(instr->result());
ASSERT(instr->hydrogen()->value()->representation().IsTagged());
__ mov(result, Handle<Object>(Heap::true_value()));
__ mov(result, Factory::true_value());
__ test(FieldOperand(input, String::kHashFieldOffset),
Immediate(String::kContainsCachedArrayIndexMask));
NearLabel done;
__ j(not_zero, &done);
__ mov(result, Handle<Object>(Heap::false_value()));
__ mov(result, Factory::false_value());
__ bind(&done);
}
......@@ -1653,11 +1652,11 @@ void LCodeGen::DoClassOfTest(LClassOfTest* instr) {
__ j(not_equal, &is_false);
__ bind(&is_true);
__ mov(result, Handle<Object>(Heap::true_value()));
__ mov(result, Factory::true_value());
__ jmp(&done);
__ bind(&is_false);
__ mov(result, Handle<Object>(Heap::false_value()));
__ mov(result, Factory::false_value());
__ bind(&done);
}
......@@ -3292,11 +3291,11 @@ void LCodeGen::DoTypeofIs(LTypeofIs* instr) {
instr->type_literal());
__ j(final_branch_condition, &true_label);
__ bind(&false_label);
__ mov(result, Handle<Object>(Heap::false_value()));
__ mov(result, Factory::false_value());
__ jmp(&done);
__ bind(&true_label);
__ mov(result, Handle<Object>(Heap::true_value()));
__ mov(result, Factory::true_value());
__ bind(&done);
}
......@@ -3341,9 +3340,9 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label,
final_branch_condition = below;
} else if (type_name->Equals(Heap::boolean_symbol())) {
__ cmp(input, Handle<Object>(Heap::true_value()));
__ cmp(input, Factory::true_value());
__ j(equal, true_label);
__ cmp(input, Handle<Object>(Heap::false_value()));
__ cmp(input, Factory::false_value());
final_branch_condition = equal;
} else if (type_name->Equals(Heap::undefined_symbol())) {
......
......@@ -523,7 +523,8 @@ enum InstanceType {
JS_BUILTINS_OBJECT_TYPE,
JS_GLOBAL_PROXY_TYPE,
JS_ARRAY_TYPE,
JS_REGEXP_TYPE, // LAST_JS_OBJECT_TYPE
JS_REGEXP_TYPE, // LAST_JS_OBJECT_TYPE, FIRST_FUNCTION_CLASS_TYPE
JS_FUNCTION_TYPE,
......@@ -541,7 +542,10 @@ enum InstanceType {
// function objects are not counted as objects, even though they are
// implemented as such; only values whose typeof is "object" are included.
FIRST_JS_OBJECT_TYPE = JS_VALUE_TYPE,
LAST_JS_OBJECT_TYPE = JS_REGEXP_TYPE
LAST_JS_OBJECT_TYPE = JS_REGEXP_TYPE,
// RegExp objects have [[Class]] "function" because they are callable.
// All types from this type and above are objects with [[Class]] "function".
FIRST_FUNCTION_CLASS_TYPE = JS_REGEXP_TYPE
};
......
......@@ -707,6 +707,10 @@ class Assembler : public Malloced {
arithmetic_op_32(0x1b, dst, src);
}
void sbbq(Register dst, Register src) {
arithmetic_op(0x1b, dst, src);
}
void cmpb(Register dst, Immediate src) {
immediate_arithmetic_op_8(0x7, dst, src);
}
......
......@@ -3248,6 +3248,12 @@ void InstanceofStub::Generate(MacroAssembler* masm) {
}
Register InstanceofStub::left() { return rax; }
Register InstanceofStub::right() { return rdx; }
int CompareStub::MinorKey() {
// Encode the three parameters in a unique 16 bit value. To avoid duplicate
// stubs the never NaN NaN condition is only taken into account if the
......@@ -4272,22 +4278,119 @@ void StringCompareStub::Generate(MacroAssembler* masm) {
}
void ICCompareStub::GenerateSmis(MacroAssembler* masm) {
UNIMPLEMENTED();
ASSERT(state_ == CompareIC::SMIS);
NearLabel miss;
__ JumpIfNotBothSmi(rdx, rax, &miss);
if (GetCondition() == equal) {
// For equality we do not care about the sign of the result.
__ SmiSub(rax, rax, rdx);
} else {
NearLabel done;
__ SmiSub(rdx, rdx, rax);
__ j(no_overflow, &done);
// Correct sign of result in case of overflow.
__ SmiNot(rdx, rdx);
__ bind(&done);
__ movq(rax, rdx);
}
__ ret(0);
__ bind(&miss);
GenerateMiss(masm);
}
void ICCompareStub::GenerateHeapNumbers(MacroAssembler* masm) {
UNIMPLEMENTED();
ASSERT(state_ == CompareIC::HEAP_NUMBERS);
NearLabel generic_stub;
NearLabel unordered;
NearLabel miss;
Condition either_smi = masm->CheckEitherSmi(rax, rdx);
__ j(either_smi, &generic_stub);
__ CmpObjectType(rax, HEAP_NUMBER_TYPE, rcx);
__ j(not_equal, &miss);
__ CmpObjectType(rdx, HEAP_NUMBER_TYPE, rcx);
__ j(not_equal, &miss);
// Load left and right operand
__ movsd(xmm0, FieldOperand(rdx, HeapNumber::kValueOffset));
__ movsd(xmm1, FieldOperand(rax, HeapNumber::kValueOffset));
// Compare operands
__ ucomisd(xmm0, xmm1);
// Don't base result on EFLAGS when a NaN is involved.
__ j(parity_even, &unordered);
// Return a result of -1, 0, or 1, based on EFLAGS.
// Performing mov, because xor would destroy the flag register.
__ movl(rax, Immediate(0));
__ movl(rcx, Immediate(0));
__ setcc(above, rax); // Add one to zero if carry clear and not equal.
__ sbbq(rax, rcx); // Subtract one if below (aka. carry set).
__ ret(0);
__ bind(&unordered);
CompareStub stub(GetCondition(), strict(), NO_COMPARE_FLAGS);
__ bind(&generic_stub);
__ jmp(stub.GetCode(), RelocInfo::CODE_TARGET);
__ bind(&miss);
GenerateMiss(masm);
}
void ICCompareStub::GenerateObjects(MacroAssembler* masm) {
UNIMPLEMENTED();
ASSERT(state_ == CompareIC::OBJECTS);
NearLabel miss;
Condition either_smi = masm->CheckEitherSmi(rdx, rax);
__ j(either_smi, &miss);
__ CmpObjectType(rax, JS_OBJECT_TYPE, rcx);
__ j(not_equal, &miss, not_taken);
__ CmpObjectType(rdx, JS_OBJECT_TYPE, rcx);
__ j(not_equal, &miss, not_taken);
ASSERT(GetCondition() == equal);
__ subq(rax, rdx);
__ ret(0);
__ bind(&miss);
GenerateMiss(masm);
}
void ICCompareStub::GenerateMiss(MacroAssembler* masm) {
UNIMPLEMENTED();
// Save the registers.
__ pop(rcx);
__ push(rdx);
__ push(rax);
__ push(rcx);
// Call the runtime system in a fresh internal frame.
ExternalReference miss = ExternalReference(IC_Utility(IC::kCompareIC_Miss));
__ EnterInternalFrame();
__ push(rdx);
__ push(rax);
__ Push(Smi::FromInt(op_));
__ CallExternalReference(miss, 3);
__ LeaveInternalFrame();
// Compute the entry point of the rewritten stub.
__ lea(rdi, FieldOperand(rax, Code::kHeaderSize));
// Restore registers.
__ pop(rcx);
__ pop(rax);
__ pop(rdx);
__ push(rcx);
// Do a tail call to the rewritten stub.
__ jmp(rdi);
}
#undef __
......
This diff is collapsed.
......@@ -138,8 +138,7 @@ class LCodeGen BASE_EMBEDDED {
Label* if_false,
Handle<String> class_name,
Register input,
Register temporary,
Register temporary2);
Register temporary);
int StackSlotCount() const { return chunk()->spill_slot_count(); }
int ParameterCount() const { return scope()->num_parameters(); }
......
......@@ -913,8 +913,103 @@ LInstruction* LChunkBuilder::DoGoto(HGoto* instr) {
LInstruction* LChunkBuilder::DoBranch(HBranch* instr) {
Abort("Unimplemented: %s", "DoBranch");
return NULL;
HValue* v = instr->value();
if (v->EmitAtUses()) {
if (v->IsClassOfTest()) {
HClassOfTest* compare = HClassOfTest::cast(v);
ASSERT(compare->value()->representation().IsTagged());
return new LClassOfTestAndBranch(UseTempRegister(compare->value()),
TempRegister());
} else if (v->IsCompare()) {
HCompare* compare = HCompare::cast(v);
Token::Value op = compare->token();
HValue* left = compare->left();
HValue* right = compare->right();
Representation r = compare->GetInputRepresentation();
if (r.IsInteger32()) {
ASSERT(left->representation().IsInteger32());
ASSERT(right->representation().IsInteger32());
return new LCmpIDAndBranch(UseRegisterAtStart(left),
UseOrConstantAtStart(right));
} else if (r.IsDouble()) {
ASSERT(left->representation().IsDouble());
ASSERT(right->representation().IsDouble());
return new LCmpIDAndBranch(UseRegisterAtStart(left),
UseRegisterAtStart(right));
} else {
ASSERT(left->representation().IsTagged());
ASSERT(right->representation().IsTagged());
bool reversed = op == Token::GT || op == Token::LTE;
LOperand* left_operand = UseFixed(left, reversed ? rax : rdx);
LOperand* right_operand = UseFixed(right, reversed ? rdx : rax);
LCmpTAndBranch* result = new LCmpTAndBranch(left_operand,
right_operand);
return MarkAsCall(result, instr);
}
} else if (v->IsIsSmi()) {
HIsSmi* compare = HIsSmi::cast(v);
ASSERT(compare->value()->representation().IsTagged());
return new LIsSmiAndBranch(Use(compare->value()));
} else if (v->IsHasInstanceType()) {
HHasInstanceType* compare = HHasInstanceType::cast(v);
ASSERT(compare->value()->representation().IsTagged());
return new LHasInstanceTypeAndBranch(
UseRegisterAtStart(compare->value()));
} else if (v->IsHasCachedArrayIndex()) {
HHasCachedArrayIndex* compare = HHasCachedArrayIndex::cast(v);
ASSERT(compare->value()->representation().IsTagged());
return new LHasCachedArrayIndexAndBranch(
UseRegisterAtStart(compare->value()));
} else if (v->IsIsNull()) {
HIsNull* compare = HIsNull::cast(v);
ASSERT(compare->value()->representation().IsTagged());
// We only need a temp register for non-strict compare.
LOperand* temp = compare->is_strict() ? NULL : TempRegister();
return new LIsNullAndBranch(UseRegisterAtStart(compare->value()),
temp);
} 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);
} else if (v->IsCompareJSObjectEq()) {
HCompareJSObjectEq* compare = HCompareJSObjectEq::cast(v);
return new LCmpJSObjectEqAndBranch(UseRegisterAtStart(compare->left()),
UseRegisterAtStart(compare->right()));
} else if (v->IsInstanceOf()) {
HInstanceOf* instance_of = HInstanceOf::cast(v);
LInstanceOfAndBranch* result =
new LInstanceOfAndBranch(
UseFixed(instance_of->left(), InstanceofStub::left()),
UseFixed(instance_of->right(), InstanceofStub::right()));
return MarkAsCall(result, instr);
} else if (v->IsTypeofIs()) {
HTypeofIs* typeof_is = HTypeofIs::cast(v);
return new LTypeofIsAndBranch(UseTempRegister(typeof_is->value()));
} else {
if (v->IsConstant()) {
if (HConstant::cast(v)->handle()->IsTrue()) {
return new LGoto(instr->FirstSuccessor()->block_id());
} else if (HConstant::cast(v)->handle()->IsFalse()) {
return new LGoto(instr->SecondSuccessor()->block_id());
}
}
Abort("Undefined compare before branch");
return NULL;
}
}
return new LBranch(UseRegisterAtStart(v));
}
......@@ -1124,8 +1219,29 @@ LInstruction* LChunkBuilder::DoPower(HPower* instr) {
LInstruction* LChunkBuilder::DoCompare(HCompare* instr) {
Abort("Unimplemented: %s", "DoCompare");
return NULL;
Token::Value op = instr->token();
Representation r = instr->GetInputRepresentation();
if (r.IsInteger32()) {
ASSERT(instr->left()->representation().IsInteger32());
ASSERT(instr->right()->representation().IsInteger32());
LOperand* left = UseRegisterAtStart(instr->left());
LOperand* right = UseOrConstantAtStart(instr->right());
return DefineAsRegister(new LCmpID(left, right));
} else if (r.IsDouble()) {
ASSERT(instr->left()->representation().IsDouble());
ASSERT(instr->right()->representation().IsDouble());
LOperand* left = UseRegisterAtStart(instr->left());
LOperand* right = UseRegisterAtStart(instr->right());
return DefineAsRegister(new LCmpID(left, right));
} else {
ASSERT(instr->left()->representation().IsTagged());
ASSERT(instr->right()->representation().IsTagged());
bool reversed = (op == Token::GT || op == Token::LTE);
LOperand* left = UseFixed(instr->left(), reversed ? rax : rdx);
LOperand* right = UseFixed(instr->right(), reversed ? rdx : rax);
LCmpT* result = new LCmpT(left, right);
return MarkAsCall(DefineFixed(result, rax), instr);
}
}
......
......@@ -788,11 +788,10 @@ class LHasInstanceType: public LTemplateInstruction<1, 1> {
};
class LHasInstanceTypeAndBranch: public LControlInstruction<1, 1> {
class LHasInstanceTypeAndBranch: public LControlInstruction<1, 0> {
public:
LHasInstanceTypeAndBranch(LOperand* value, LOperand* temp) {
explicit LHasInstanceTypeAndBranch(LOperand* value) {
inputs_[0] = value;
temps_[0] = temp;
}
DECLARE_CONCRETE_INSTRUCTION(HasInstanceTypeAndBranch,
......@@ -840,12 +839,11 @@ class LClassOfTest: public LTemplateInstruction<1, 1, 1> {
};
class LClassOfTestAndBranch: public LControlInstruction<1, 2> {
class LClassOfTestAndBranch: public LControlInstruction<1, 1> {
public:
LClassOfTestAndBranch(LOperand* value, LOperand* temp, LOperand* temp2) {
LClassOfTestAndBranch(LOperand* value, LOperand* temp) {
inputs_[0] = value;
temps_[0] = temp;
temps_[1] = temp2;
}
DECLARE_CONCRETE_INSTRUCTION(ClassOfTestAndBranch,
......
......@@ -885,6 +885,13 @@ Condition MacroAssembler::CheckSmi(Register src) {
}
Condition MacroAssembler::CheckSmi(const Operand& src) {
ASSERT_EQ(0, kSmiTag);
testb(src, Immediate(kSmiTagMask));
return zero;
}
Condition MacroAssembler::CheckNonNegativeSmi(Register src) {
ASSERT_EQ(0, kSmiTag);
// Make mask 0x8000000000000001 and test that both bits are zero.
......@@ -1386,6 +1393,40 @@ void MacroAssembler::Call(Handle<Code> code_object, RelocInfo::Mode rmode) {
}
void MacroAssembler::Pushad() {
push(rax);
push(rcx);
push(rdx);
push(rbx);
// Not pushing rsp or rbp.
push(rsi);
push(rdi);
push(r8);
push(r9);
// r10 is kScratchRegister.
push(r11);
push(r12);
// r13 is kRootRegister.
push(r14);
// r15 is kSmiConstantRegister
}
void MacroAssembler::Popad() {
pop(r14);
pop(r12);
pop(r11);
pop(r9);
pop(r8);
pop(rdi);
pop(rsi);
pop(rbx);
pop(rdx);
pop(rcx);
pop(rax);
}
void MacroAssembler::PushTryHandler(CodeLocation try_location,
HandlerType type) {
// Adjust this code if not the case.
......
......@@ -272,6 +272,7 @@ class MacroAssembler: public Assembler {
// Is the value a tagged smi.
Condition CheckSmi(Register src);
Condition CheckSmi(const Operand& src);
// Is the value a non-negative tagged smi.
Condition CheckNonNegativeSmi(Register src);
......@@ -590,6 +591,13 @@ class MacroAssembler: public Assembler {
void Call(ExternalReference ext);
void Call(Handle<Code> code_object, RelocInfo::Mode rmode);
// Non-x64 instructions.
// Push/pop all general purpose registers.
// Does not push rsp/rbp nor any of the assembler's special purpose registers
// (kScratchRegister, kSmiConstantRegister, kRootRegister).
void Pushad();
void Popad();
// Compare object type for heap object.
// Always use unsigned comparisons: above and below, not less and greater.
// Incoming register is heap_object and outgoing register is map.
......
......@@ -82,7 +82,7 @@ test-serialize/ContextSerialization: SKIP
test-serialize/ContextDeserialization: SKIP
test-debug/BreakPointReturn: SKIP
test-debug/DebugStepLinearMixedICs: SKIP
test-debug/DebugConditional: SKIP
##############################################################################
[ $arch == arm ]
......
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