Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(814)

Unified Diff: runtime/vm/intermediate_language_ia32.cc

Issue 10802025: Fuse compare with branch at graph building time. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « runtime/vm/intermediate_language.cc ('k') | runtime/vm/intermediate_language_x64.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: runtime/vm/intermediate_language_ia32.cc
===================================================================
--- runtime/vm/intermediate_language_ia32.cc (revision 9761)
+++ runtime/vm/intermediate_language_ia32.cc (working copy)
@@ -203,9 +203,7 @@
locs->set_in(0, Location::RequiresRegister());
locs->set_in(1, Location::RequiresRegister());
locs->set_temp(0, Location::RequiresRegister());
- if (!is_fused_with_branch()) {
- locs->set_out(Location::RequiresRegister());
- }
+ locs->set_out(Location::RequiresRegister());
return locs;
}
if (HasICData() && (ic_data()->NumberOfChecks() > 0)) {
@@ -216,9 +214,7 @@
locs->set_in(0, Location::RequiresRegister());
locs->set_in(1, Location::RequiresRegister());
locs->set_temp(0, Location::RequiresRegister());
- if (!is_fused_with_branch()) {
- locs->set_out(Location::RegisterLocation(EAX));
- }
+ locs->set_out(Location::RegisterLocation(EAX));
return locs;
}
const intptr_t kNumTemps = 0;
@@ -227,9 +223,7 @@
LocationSummary::kCall);
locs->set_in(0, Location::RequiresRegister());
locs->set_in(1, Location::RequiresRegister());
- if (!is_fused_with_branch()) {
- locs->set_out(Location::RegisterLocation(EAX));
- }
+ locs->set_out(Location::RegisterLocation(EAX));
return locs;
}
@@ -252,18 +246,14 @@
__ testl(temp, Immediate(kSmiTagMask));
__ j(NOT_ZERO, deopt);
__ cmpl(left, right);
- if (comp->is_fused_with_branch()) {
- comp->fused_with_branch()->EmitBranchOnCondition(compiler, EQUAL);
- } else {
- Register result = comp->locs()->out().reg();
- Label load_true, done;
- __ j(EQUAL, &load_true, Assembler::kNearJump);
- __ LoadObject(result, compiler->bool_false());
- __ jmp(&done, Assembler::kNearJump);
- __ Bind(&load_true);
- __ LoadObject(result, compiler->bool_true());
- __ Bind(&done);
- }
+ Register result = comp->locs()->out().reg();
+ Label load_true, done;
+ __ j(EQUAL, &load_true, Assembler::kNearJump);
+ __ LoadObject(result, compiler->bool_false());
+ __ jmp(&done, Assembler::kNearJump);
+ __ Bind(&load_true);
+ __ LoadObject(result, compiler->bool_true());
+ __ Bind(&done);
}
@@ -287,13 +277,8 @@
__ j(NOT_EQUAL, deopt);
__ movsd(XMM0, FieldAddress(left, Double::value_offset()));
__ movsd(XMM1, FieldAddress(right, Double::value_offset()));
- if (comp->is_fused_with_branch()) {
- compiler->EmitDoubleCompareBranch(
- EQUAL, XMM0, XMM1, comp->fused_with_branch());
- } else {
- compiler->EmitDoubleCompareBool(
- EQUAL, XMM0, XMM1, comp->locs()->out().reg());
- }
+ compiler->EmitDoubleCompareBool(
+ EQUAL, XMM0, XMM1, comp->locs()->out().reg());
}
@@ -315,29 +300,29 @@
kNumberOfArguments,
kNoArgumentNames,
kNumArgumentsChecked);
- ASSERT(comp->is_fused_with_branch() || (comp->locs()->out().reg() == EAX));
-
- if (comp->is_fused_with_branch()) {
- __ CompareObject(EAX, compiler->bool_true());
- comp->fused_with_branch()->EmitBranchOnCondition(compiler, EQUAL);
- }
+ ASSERT(comp->locs()->out().reg() == EAX);
}
static void EmitEqualityAsPolymorphicCall(FlowGraphCompiler* compiler,
- EqualityCompareComp* comp,
- Register left,
- Register right) {
- ASSERT(comp->HasICData());
- const ICData& ic_data = ICData::Handle(comp->ic_data()->AsUnaryClassChecks());
+ const ICData& orig_ic_data,
+ const LocationSummary& locs,
+ BranchInstr* branch,
+ Token::Kind kind,
+ intptr_t cid,
+ intptr_t token_pos,
+ intptr_t try_index) {
+ const ICData& ic_data = ICData::Handle(orig_ic_data.AsUnaryClassChecks());
ASSERT(ic_data.NumberOfChecks() > 0);
ASSERT(ic_data.num_args_tested() == 1);
- Label* deopt = compiler->AddDeoptStub(comp->cid(),
- comp->token_pos(),
- comp->try_index(),
+ Label* deopt = compiler->AddDeoptStub(cid,
+ token_pos,
+ try_index,
kDeoptEquality);
+ Register left = locs.in(0).reg();
+ Register right = locs.in(1).reg();
__ testl(left, Immediate(kSmiTagMask));
- Register temp = comp->locs()->temp(0).reg();
+ Register temp = locs.temp(0).reg();
if (ic_data.GetReceiverClassIdAt(0) == kSmi) {
Label done, load_class_id;
__ j(NOT_ZERO, &load_class_id, Assembler::kNearJump);
@@ -350,6 +335,7 @@
__ j(ZERO, deopt); // Smi deopts.
__ LoadClassId(temp, left);
}
+ Condition cond = (kind == Token::kEQ) ? EQUAL : NOT_EQUAL;
Label done;
for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) {
ASSERT((ic_data.GetReceiverClassIdAt(i) != kSmi) || (i == 0));
@@ -362,13 +348,13 @@
// Object.== is same as ===.
__ Drop(2);
__ cmpl(left, right);
- if (comp->is_fused_with_branch()) {
- comp->fused_with_branch()->EmitBranchOnCondition(compiler, EQUAL);
+ if (branch != NULL) {
+ branch->EmitBranchOnCondition(compiler, cond);
} else {
// This case should be rare.
- Register result = comp->locs()->out().reg();
+ Register result = locs.out().reg();
Label load_true;
- __ j(EQUAL, &load_true, Assembler::kNearJump);
+ __ j(cond, &load_true, Assembler::kNearJump);
__ LoadObject(result, compiler->bool_false());
__ jmp(&done);
__ Bind(&load_true);
@@ -377,17 +363,15 @@
} else {
const int kNumberOfArguments = 2;
const Array& kNoArgumentNames = Array::Handle();
- compiler->GenerateStaticCall(comp->cid(),
- comp->token_pos(),
- comp->try_index(),
+ compiler->GenerateStaticCall(cid,
+ token_pos,
+ try_index,
target,
kNumberOfArguments,
kNoArgumentNames);
- ASSERT(comp->is_fused_with_branch() ||
- (comp->locs()->out().reg() == EAX));
- if (comp->is_fused_with_branch()) {
+ if (branch != NULL) {
__ CompareObject(EAX, compiler->bool_true());
- comp->fused_with_branch()->EmitBranchOnCondition(compiler, EQUAL);
+ branch->EmitBranchOnCondition(compiler, cond);
}
}
__ jmp(&done);
@@ -403,9 +387,16 @@
// If type feedback was provided (lists of <class-id, target>), do a
// type by type check (either === or static call to the operator.
static void EmitGenericEqualityCompare(FlowGraphCompiler* compiler,
- EqualityCompareComp* comp) {
- Register left = comp->locs()->in(0).reg();
- Register right = comp->locs()->in(1).reg();
+ const LocationSummary& locs,
+ Token::Kind kind,
+ BranchInstr* branch,
+ const ICData& ic_data,
+ intptr_t cid,
+ intptr_t token_pos,
+ intptr_t try_index) {
+ ASSERT(!ic_data.IsNull() && (ic_data.NumberOfChecks() > 0));
+ Register left = locs.in(0).reg();
+ Register right = locs.in(1).reg();
const Immediate raw_null =
Immediate(reinterpret_cast<intptr_t>(Object::null()));
Label done, non_null_compare;
@@ -413,27 +404,24 @@
__ j(NOT_EQUAL, &non_null_compare, Assembler::kNearJump);
// Comparison with NULL is "===".
__ cmpl(left, right);
- if (comp->is_fused_with_branch()) {
- comp->fused_with_branch()->EmitBranchOnCondition(compiler, EQUAL);
+ Condition cond = (kind == Token::kEQ) ? EQUAL : NOT_EQUAL;
+ if (branch != NULL) {
+ branch->EmitBranchOnCondition(compiler, cond);
} else {
- Register result = comp->locs()->out().reg();
+ Register result = locs.out().reg();
Label load_true;
- __ j(EQUAL, &load_true, Assembler::kNearJump);
+ __ j(cond, &load_true, Assembler::kNearJump);
__ LoadObject(result, compiler->bool_false());
__ jmp(&done);
__ Bind(&load_true);
__ LoadObject(result, compiler->bool_true());
}
__ jmp(&done);
-
__ Bind(&non_null_compare); // Receiver is not null.
__ pushl(left);
__ pushl(right);
- if (comp->HasICData() && (comp->ic_data()->NumberOfChecks() > 0)) {
- EmitEqualityAsPolymorphicCall(compiler, comp, left, right);
- } else {
- EmitEqualityAsInstanceCall(compiler, comp);
- }
+ EmitEqualityAsPolymorphicCall(compiler, ic_data, locs, branch, kind,
+ cid, token_pos, try_index);
__ Bind(&done);
}
@@ -447,7 +435,16 @@
EmitDoubleEqualityCompare(compiler, this);
return;
}
- EmitGenericEqualityCompare(compiler, this);
+ if (HasICData() && (ic_data()->NumberOfChecks() > 0)) {
+ EmitGenericEqualityCompare(compiler, *locs(), Token::kEQ, NULL,
+ *ic_data(), cid(), token_pos(), try_index());
+ } else {
+ Register left = locs()->in(0).reg();
+ Register right = locs()->in(1).reg();
+ __ pushl(left);
+ __ pushl(right);
+ EmitEqualityAsInstanceCall(compiler, this);
+ }
}
@@ -460,13 +457,10 @@
LocationSummary::kNoCall);
summary->set_in(0, Location::RequiresRegister());
summary->set_in(1, Location::RequiresRegister());
- if (!is_fused_with_branch()) {
- summary->set_out(Location::RequiresRegister());
- }
+ summary->set_out(Location::RequiresRegister());
summary->set_temp(0, Location::RequiresRegister());
return summary;
}
- ASSERT(!is_fused_with_branch());
ASSERT(operands_class_id() == kObject);
return MakeCallSummary();
}
@@ -487,14 +481,19 @@
}
-static void EmitSmiRelationalOp(FlowGraphCompiler* compiler,
- RelationalOpComp* comp) {
- Register left = comp->locs()->in(0).reg();
- Register right = comp->locs()->in(1).reg();
- Register temp = comp->locs()->temp(0).reg();
- Label* deopt = compiler->AddDeoptStub(comp->cid(),
- comp->token_pos(),
- comp->try_index(),
+static void EmitSmiComparisonOp(FlowGraphCompiler* compiler,
+ const LocationSummary& locs,
+ Token::Kind kind,
+ BranchInstr* branch,
+ intptr_t cid,
+ intptr_t token_pos,
+ intptr_t try_index) {
+ Register left = locs.in(0).reg();
+ Register right = locs.in(1).reg();
+ Register temp = locs.temp(0).reg();
+ Label* deopt = compiler->AddDeoptStub(cid,
+ token_pos,
+ try_index,
kDeoptSmiCompareSmi,
left,
right);
@@ -503,13 +502,13 @@
__ testl(temp, Immediate(kSmiTagMask));
__ j(NOT_ZERO, deopt);
- Condition true_condition = TokenKindToSmiCondition(comp->kind());
+ Condition true_condition = TokenKindToSmiCondition(kind);
__ cmpl(left, right);
- if (comp->is_fused_with_branch()) {
- comp->fused_with_branch()->EmitBranchOnCondition(compiler, true_condition);
+ if (branch != NULL) {
+ branch->EmitBranchOnCondition(compiler, true_condition);
} else {
- Register result = comp->locs()->out().reg();
+ Register result = locs.out().reg();
Label done, is_true;
__ j(true_condition, &is_true);
__ LoadObject(result, compiler->bool_false());
@@ -524,6 +523,7 @@
static Condition TokenKindToDoubleCondition(Token::Kind kind) {
switch (kind) {
case Token::kEQ: return EQUAL;
+ case Token::kNE: return NOT_EQUAL;
case Token::kLT: return BELOW;
case Token::kGT: return ABOVE;
case Token::kLTE: return BELOW_EQUAL;
@@ -535,39 +535,46 @@
}
-static void EmitDoubleRelationalOp(FlowGraphCompiler* compiler,
- RelationalOpComp* comp) {
- Register left = comp->locs()->in(0).reg();
- Register right = comp->locs()->in(1).reg();
+static void EmitDoubleComparisonOp(FlowGraphCompiler* compiler,
+ const LocationSummary& locs,
+ Token::Kind kind,
+ BranchInstr* branch,
+ intptr_t cid,
+ intptr_t token_pos,
+ intptr_t try_index) {
+ Register left = locs.in(0).reg();
+ Register right = locs.in(1).reg();
// TODO(srdjan): temp is only needed if a conversion Smi->Double occurs.
- Register temp = comp->locs()->temp(0).reg();
- Label* deopt = compiler->AddDeoptStub(comp->cid(),
- comp->token_pos(),
- comp->try_index(),
+ Register temp = locs.temp(0).reg();
+ Label* deopt = compiler->AddDeoptStub(cid,
+ token_pos,
+ try_index,
kDeoptDoubleComparison,
left,
right);
compiler->LoadDoubleOrSmiToXmm(XMM0, left, temp, deopt);
compiler->LoadDoubleOrSmiToXmm(XMM1, right, temp, deopt);
- Condition true_condition = TokenKindToDoubleCondition(comp->kind());
- if (comp->is_fused_with_branch()) {
+ Condition true_condition = TokenKindToDoubleCondition(kind);
+ if (branch != NULL) {
compiler->EmitDoubleCompareBranch(
- true_condition, XMM0, XMM1, comp->fused_with_branch());
+ true_condition, XMM0, XMM1, branch);
} else {
compiler->EmitDoubleCompareBool(
- true_condition, XMM0, XMM1, comp->locs()->out().reg());
+ true_condition, XMM0, XMM1, locs.out().reg());
}
}
void RelationalOpComp::EmitNativeCode(FlowGraphCompiler* compiler) {
if (operands_class_id() == kSmi) {
- EmitSmiRelationalOp(compiler, this);
+ EmitSmiComparisonOp(compiler, *locs(), kind(), NULL,
+ cid(), token_pos(), try_index());
return;
}
if (operands_class_id() == kDouble) {
- EmitDoubleRelationalOp(compiler, this);
+ EmitDoubleComparisonOp(compiler, *locs(), kind(), NULL,
+ cid(), token_pos(), try_index());
return;
}
if (HasICData() && (ic_data()->NumberOfChecks() > 0)) {
@@ -2028,6 +2035,114 @@
__ Bind(&done);
}
+
+// TODO(srdjan): Move to shared.
+static bool ICDataWithBothClassIds(const ICData& ic_data, intptr_t class_id) {
+ if (ic_data.num_args_tested() != 2) return false;
+ if (ic_data.NumberOfChecks() != 1) return false;
+ Function& target = Function::Handle();
+ GrowableArray<intptr_t> class_ids;
+ ic_data.GetCheckAt(0, &class_ids, &target);
+ return (class_ids[0] == class_id) && (class_ids[1] == class_id);
+}
+
+
+LocationSummary* BranchInstr::MakeLocationSummary() const {
+ if ((kind() == Token::kEQ_STRICT) || (kind() == Token::kNE_STRICT)) {
+ const int kNumInputs = 2;
+ const int kNumTemps = 0;
+ LocationSummary* locs = new LocationSummary(kNumInputs,
+ kNumTemps,
+ LocationSummary::kNoCall);
+ locs->set_in(0, Location::RequiresRegister());
+ locs->set_in(1, Location::RequiresRegister());
+ return locs;
+ }
+ if (HasICData() && (ic_data()->NumberOfChecks() > 0)) {
+ if (ICDataWithBothClassIds(*ic_data(), kSmi) ||
+ ICDataWithBothClassIds(*ic_data(), kDouble)) {
+ const intptr_t kNumInputs = 2;
+ const intptr_t kNumTemps = 1;
+ LocationSummary* summary = new LocationSummary(kNumInputs,
+ kNumTemps,
+ LocationSummary::kNoCall);
+ summary->set_in(0, Location::RequiresRegister());
+ summary->set_in(1, Location::RequiresRegister());
+ summary->set_temp(0, Location::RequiresRegister());
+ return summary;
+ }
+ if ((kind() == Token::kEQ) || (kind() == Token::kNE)) {
+ const intptr_t kNumInputs = 2;
+ const intptr_t kNumTemps = 1;
+ LocationSummary* locs = new LocationSummary(kNumInputs,
+ kNumTemps,
+ LocationSummary::kCall);
+ locs->set_in(0, Location::RequiresRegister());
+ locs->set_in(1, Location::RequiresRegister());
+ locs->set_temp(0, Location::RequiresRegister());
+ return locs;
+ }
+ // Otherwise polymorphic dispatch.
+ }
+ // Call.
+ LocationSummary* result = new LocationSummary(0, 0, LocationSummary::kCall);
+ result->set_out(Location::RegisterLocation(EAX));
+ return result;
+}
+
+
+void BranchInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+ if ((kind() == Token::kEQ_STRICT) || (kind() == Token::kNE_STRICT)) {
+ Register left = locs()->in(0).reg();
+ Register right = locs()->in(1).reg();
+ __ cmpl(left, right);
+ Condition cond = (kind() == Token::kEQ_STRICT) ? EQUAL : NOT_EQUAL;
+ EmitBranchOnCondition(compiler, cond);
+ return;
+ }
+ // Relational or equality.
+ if (HasICData() && (ic_data()->NumberOfChecks() > 0)) {
+ if (ICDataWithBothClassIds(*ic_data(), kSmi)) {
+ EmitSmiComparisonOp(compiler, *locs(), kind(), this,
+ cid(), token_pos(), try_index());
+ return;
+ }
+ if (ICDataWithBothClassIds(*ic_data(), kDouble)) {
+ EmitDoubleComparisonOp(compiler, *locs(), kind(), this,
+ cid(), token_pos(), try_index());
+ return;
+ }
+ // TODO(srdjan): Add Smi/Double, Double/Smi comparisons.
+ if ((kind() == Token::kEQ) || (kind() == Token::kNE)) {
+ EmitGenericEqualityCompare(compiler, *locs(), kind(), this, *ic_data(),
+ cid(), token_pos(), try_index());
+ return;
+ }
+ // Otherwise polymorphic dispatch?
+ }
+ // Not equal is always split into '==' and negate,
+ Condition branch_condition = (kind() == Token::kNE) ? NOT_EQUAL : EQUAL;
+ Token::Kind call_kind = (kind() == Token::kNE) ? Token::kEQ : kind();
+ const String& function_name =
+ String::ZoneHandle(String::NewSymbol(Token::Str(call_kind)));
+ compiler->AddCurrentDescriptor(PcDescriptors::kDeopt,
+ cid(),
+ token_pos(),
+ try_index());
+ const intptr_t kNumArguments = 2;
+ const intptr_t kNumArgsChecked = 2; // Type-feedback.
+ compiler->GenerateInstanceCall(cid(),
+ token_pos(),
+ try_index(),
+ function_name,
+ kNumArguments,
+ Array::ZoneHandle(), // No optional arguments.
+ kNumArgsChecked);
+ ASSERT(locs()->out().reg() == EAX);
+ __ CompareObject(locs()->out().reg(), compiler->bool_true());
+ EmitBranchOnCondition(compiler, branch_condition);
+}
+
} // namespace dart
#undef __
« no previous file with comments | « runtime/vm/intermediate_language.cc ('k') | runtime/vm/intermediate_language_x64.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698