Commit 10c5f2e8 authored by bmeurer's avatar bmeurer Committed by Commit bot

[ic] Introduce BOOLEAN state for CompareIC.

Slow path for relational comparison of boolean primitive values
now goes through the runtime, which made the slow path even
slower than it already was. So in order to repair the regression,
we just track boolean feedback for comparisons and use that
to generate decent code in Crankshaft (not the best possible
code, but good enough for Crankshaft; TurboFan will be able
to do better on that).

R=jarin@chromium.org
BUG=chromium:534200
LOG=n

Review URL: https://codereview.chromium.org/1347063004

Cr-Commit-Position: refs/heads/master@{#30860}
parent 02a2580b
......@@ -3360,6 +3360,30 @@ void BinaryOpICWithAllocationSiteStub::Generate(MacroAssembler* masm) {
}
void CompareICStub::GenerateBooleans(MacroAssembler* masm) {
DCHECK_EQ(CompareICState::BOOLEAN, state());
Label miss;
__ CheckMap(r1, r2, Heap::kBooleanMapRootIndex, &miss, DO_SMI_CHECK);
__ CheckMap(r0, r3, Heap::kBooleanMapRootIndex, &miss, DO_SMI_CHECK);
if (op() != Token::EQ_STRICT && is_strong(strength())) {
__ TailCallRuntime(Runtime::kThrowStrongModeImplicitConversion, 0, 1);
} else {
if (!Token::IsEqualityOp(op())) {
__ ldr(r1, FieldMemOperand(r1, Oddball::kToNumberOffset));
__ AssertSmi(r1);
__ ldr(r0, FieldMemOperand(r0, Oddball::kToNumberOffset));
__ AssertSmi(r0);
}
__ sub(r0, r1, r0);
__ Ret();
}
__ bind(&miss);
GenerateMiss(masm);
}
void CompareICStub::GenerateSmis(MacroAssembler* masm) {
DCHECK(state() == CompareICState::SMI);
Label miss;
......
......@@ -3246,6 +3246,32 @@ void StringCharFromCodeGenerator::GenerateSlow(
}
void CompareICStub::GenerateBooleans(MacroAssembler* masm) {
// Inputs are in x0 (lhs) and x1 (rhs).
DCHECK_EQ(CompareICState::BOOLEAN, state());
ASM_LOCATION("CompareICStub[Booleans]");
Label miss;
__ CheckMap(x1, x2, Heap::kBooleanMapRootIndex, &miss, DO_SMI_CHECK);
__ CheckMap(x0, x3, Heap::kBooleanMapRootIndex, &miss, DO_SMI_CHECK);
if (op() != Token::EQ_STRICT && is_strong(strength())) {
__ TailCallRuntime(Runtime::kThrowStrongModeImplicitConversion, 0, 1);
} else {
if (!Token::IsEqualityOp(op())) {
__ Ldr(x1, FieldMemOperand(x1, Oddball::kToNumberOffset));
__ AssertSmi(x1);
__ Ldr(x0, FieldMemOperand(x0, Oddball::kToNumberOffset));
__ AssertSmi(x0);
}
__ Sub(x0, x1, x0);
__ Ret();
}
__ Bind(&miss);
GenerateMiss(masm);
}
void CompareICStub::GenerateSmis(MacroAssembler* masm) {
// Inputs are in x0 (lhs) and x1 (rhs).
DCHECK(state() == CompareICState::SMI);
......
......@@ -351,6 +351,7 @@ InlineCacheState CompareICStub::GetICState() const {
switch (state) {
case CompareICState::UNINITIALIZED:
return ::v8::internal::UNINITIALIZED;
case CompareICState::BOOLEAN:
case CompareICState::SMI:
case CompareICState::NUMBER:
case CompareICState::INTERNALIZED_STRING:
......@@ -416,6 +417,9 @@ void CompareICStub::Generate(MacroAssembler* masm) {
case CompareICState::UNINITIALIZED:
GenerateMiss(masm);
break;
case CompareICState::BOOLEAN:
GenerateBooleans(masm);
break;
case CompareICState::SMI:
GenerateSmis(masm);
break;
......
......@@ -1697,6 +1697,7 @@ class CompareICStub : public PlatformCodeStub {
private:
Code::Kind GetCodeKind() const override { return Code::COMPARE_IC; }
void GenerateBooleans(MacroAssembler* masm);
void GenerateSmis(MacroAssembler* masm);
void GenerateNumbers(MacroAssembler* masm);
void GenerateInternalizedStrings(MacroAssembler* masm);
......
......@@ -5946,6 +5946,11 @@ class HObjectAccess final {
Representation::Integer32());
}
static HObjectAccess ForOddballToNumber(
Representation representation = Representation::Tagged()) {
return HObjectAccess(kInobject, Oddball::kToNumberOffset, representation);
}
static HObjectAccess ForOddballTypeOf() {
return HObjectAccess(kInobject, Oddball::kTypeOfOffset,
Representation::HeapObject());
......
......@@ -11650,6 +11650,23 @@ HControlInstruction* HOptimizedGraphBuilder::BuildCompareInstruction(
HStringCompareAndBranch* result =
New<HStringCompareAndBranch>(left, right, op);
return result;
} else if (combined_type->Is(Type::Boolean())) {
AddCheckMap(left, isolate()->factory()->boolean_map());
AddCheckMap(right, isolate()->factory()->boolean_map());
if (Token::IsEqualityOp(op)) {
HCompareObjectEqAndBranch* result =
New<HCompareObjectEqAndBranch>(left, right);
return result;
}
left = Add<HLoadNamedField>(
left, nullptr,
HObjectAccess::ForOddballToNumber(Representation::Smi()));
right = Add<HLoadNamedField>(
right, nullptr,
HObjectAccess::ForOddballToNumber(Representation::Smi()));
HCompareNumericAndBranch* result =
New<HCompareNumericAndBranch>(left, right, op);
return result;
} else {
if (combined_rep.IsTagged() || combined_rep.IsNone()) {
HCompareGeneric* result = Add<HCompareGeneric>(
......
......@@ -3400,6 +3400,37 @@ void BinaryOpICWithAllocationSiteStub::Generate(MacroAssembler* masm) {
}
void CompareICStub::GenerateBooleans(MacroAssembler* masm) {
DCHECK_EQ(CompareICState::BOOLEAN, state());
Label miss;
Label::Distance const miss_distance =
masm->emit_debug_code() ? Label::kFar : Label::kNear;
__ JumpIfSmi(edx, &miss, miss_distance);
__ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
__ JumpIfSmi(eax, &miss, miss_distance);
__ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
__ JumpIfNotRoot(ecx, Heap::kBooleanMapRootIndex, &miss, miss_distance);
__ JumpIfNotRoot(ebx, Heap::kBooleanMapRootIndex, &miss, miss_distance);
if (op() != Token::EQ_STRICT && is_strong(strength())) {
__ TailCallRuntime(Runtime::kThrowStrongModeImplicitConversion, 0, 1);
} else {
if (!Token::IsEqualityOp(op())) {
__ mov(eax, FieldOperand(eax, Oddball::kToNumberOffset));
__ AssertSmi(eax);
__ mov(edx, FieldOperand(edx, Oddball::kToNumberOffset));
__ AssertSmi(edx);
__ xchg(eax, edx);
}
__ sub(eax, edx);
__ Ret();
}
__ bind(&miss);
GenerateMiss(masm);
}
void CompareICStub::GenerateSmis(MacroAssembler* masm) {
DCHECK(state() == CompareICState::SMI);
Label miss;
......
......@@ -358,6 +358,8 @@ const char* CompareICState::GetStateName(State state) {
switch (state) {
case UNINITIALIZED:
return "UNINITIALIZED";
case BOOLEAN:
return "BOOLEAN";
case SMI:
return "SMI";
case NUMBER:
......@@ -384,6 +386,8 @@ Type* CompareICState::StateToType(Zone* zone, State state, Handle<Map> map) {
switch (state) {
case UNINITIALIZED:
return Type::None(zone);
case BOOLEAN:
return Type::Boolean(zone);
case SMI:
return Type::SignedSmall(zone);
case NUMBER:
......@@ -410,6 +414,7 @@ CompareICState::State CompareICState::NewInputState(State old_state,
Handle<Object> value) {
switch (old_state) {
case UNINITIALIZED:
if (value->IsBoolean()) return BOOLEAN;
if (value->IsSmi()) return SMI;
if (value->IsHeapNumber()) return NUMBER;
if (value->IsInternalizedString()) return INTERNALIZED_STRING;
......@@ -417,6 +422,9 @@ CompareICState::State CompareICState::NewInputState(State old_state,
if (value->IsSymbol()) return UNIQUE_NAME;
if (value->IsJSObject()) return OBJECT;
break;
case BOOLEAN:
if (value->IsBoolean()) return BOOLEAN;
break;
case SMI:
if (value->IsSmi()) return SMI;
if (value->IsHeapNumber()) return NUMBER;
......@@ -454,6 +462,7 @@ CompareICState::State CompareICState::TargetState(
bool has_inlined_smi_code, Handle<Object> x, Handle<Object> y) {
switch (old_state) {
case UNINITIALIZED:
if (x->IsBoolean() && y->IsBoolean()) return BOOLEAN;
if (x->IsSmi() && y->IsSmi()) return SMI;
if (x->IsNumber() && y->IsNumber()) return NUMBER;
if (Token::IsOrderedRelationalCompareOp(op)) {
......@@ -500,6 +509,7 @@ CompareICState::State CompareICState::TargetState(
return Token::IsEqualityOp(op) ? OBJECT : GENERIC;
}
return GENERIC;
case BOOLEAN:
case STRING:
case UNIQUE_NAME:
case OBJECT:
......@@ -509,5 +519,6 @@ CompareICState::State CompareICState::TargetState(
UNREACHABLE();
return GENERIC; // Make the compiler happy.
}
} // namespace internal
} // namespace v8
......@@ -174,9 +174,11 @@ class CompareICState {
// ... < GENERIC
// SMI < NUMBER
// INTERNALIZED_STRING < STRING
// INTERNALIZED_STRING < UNIQUE_NAME
// KNOWN_OBJECT < OBJECT
enum State {
UNINITIALIZED,
BOOLEAN,
SMI,
NUMBER,
STRING,
......
......@@ -3518,6 +3518,30 @@ void BinaryOpICWithAllocationSiteStub::Generate(MacroAssembler* masm) {
}
void CompareICStub::GenerateBooleans(MacroAssembler* masm) {
DCHECK_EQ(CompareICState::BOOLEAN, state());
Label miss;
__ CheckMap(a1, a2, Heap::kBooleanMapRootIndex, &miss, DO_SMI_CHECK);
__ CheckMap(a0, a3, Heap::kBooleanMapRootIndex, &miss, DO_SMI_CHECK);
if (op() != Token::EQ_STRICT && is_strong(strength())) {
__ TailCallRuntime(Runtime::kThrowStrongModeImplicitConversion, 0, 1);
} else {
if (!Token::IsEqualityOp(op())) {
__ lw(a1, FieldMemOperand(a1, Oddball::kToNumberOffset));
__ AssertSmi(a1);
__ lw(a0, FieldMemOperand(a0, Oddball::kToNumberOffset));
__ AssertSmi(a0);
}
__ Ret(USE_DELAY_SLOT);
__ Subu(v0, a1, a0);
}
__ bind(&miss);
GenerateMiss(masm);
}
void CompareICStub::GenerateSmis(MacroAssembler* masm) {
DCHECK(state() == CompareICState::SMI);
Label miss;
......
......@@ -3551,6 +3551,30 @@ void BinaryOpICWithAllocationSiteStub::Generate(MacroAssembler* masm) {
}
void CompareICStub::GenerateBooleans(MacroAssembler* masm) {
DCHECK_EQ(CompareICState::BOOLEAN, state());
Label miss;
__ CheckMap(a1, a2, Heap::kBooleanMapRootIndex, &miss, DO_SMI_CHECK);
__ CheckMap(a0, a3, Heap::kBooleanMapRootIndex, &miss, DO_SMI_CHECK);
if (op() != Token::EQ_STRICT && is_strong(strength())) {
__ TailCallRuntime(Runtime::kThrowStrongModeImplicitConversion, 0, 1);
} else {
if (!Token::IsEqualityOp(op())) {
__ ld(a1, FieldMemOperand(a1, Oddball::kToNumberOffset));
__ AssertSmi(a1);
__ ld(a0, FieldMemOperand(a0, Oddball::kToNumberOffset));
__ AssertSmi(a0);
}
__ Ret(USE_DELAY_SLOT);
__ Dsubu(v0, a1, a0);
}
__ bind(&miss);
GenerateMiss(masm);
}
void CompareICStub::GenerateSmis(MacroAssembler* masm) {
DCHECK(state() == CompareICState::SMI);
Label miss;
......
......@@ -3356,6 +3356,37 @@ void BinaryOpICWithAllocationSiteStub::Generate(MacroAssembler* masm) {
}
void CompareICStub::GenerateBooleans(MacroAssembler* masm) {
DCHECK_EQ(CompareICState::BOOLEAN, state());
Label miss;
Label::Distance const miss_distance =
masm->emit_debug_code() ? Label::kFar : Label::kNear;
__ JumpIfSmi(rdx, &miss, miss_distance);
__ movp(rcx, FieldOperand(rdx, HeapObject::kMapOffset));
__ JumpIfSmi(rax, &miss, miss_distance);
__ movp(rbx, FieldOperand(rax, HeapObject::kMapOffset));
__ JumpIfNotRoot(rcx, Heap::kBooleanMapRootIndex, &miss, miss_distance);
__ JumpIfNotRoot(rbx, Heap::kBooleanMapRootIndex, &miss, miss_distance);
if (op() != Token::EQ_STRICT && is_strong(strength())) {
__ TailCallRuntime(Runtime::kThrowStrongModeImplicitConversion, 0, 1);
} else {
if (!Token::IsEqualityOp(op())) {
__ movp(rax, FieldOperand(rax, Oddball::kToNumberOffset));
__ AssertSmi(rax);
__ movp(rdx, FieldOperand(rdx, Oddball::kToNumberOffset));
__ AssertSmi(rdx);
__ xchgp(rax, rdx);
}
__ subp(rax, rdx);
__ Ret();
}
__ bind(&miss);
GenerateMiss(masm);
}
void CompareICStub::GenerateSmis(MacroAssembler* masm) {
DCHECK(state() == CompareICState::SMI);
Label miss;
......
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