Refactor branch instructions to enable further optimizations.

This CL simplifies the code generation for branches: Each BranchInstr
wraps a comparison computation and we can reuse the code between the two
in many cases. Similar to BindInstr, most accessors forward to the wrapped
computation. One exception is the location summary, which is modified for
branches: The result location is removed since branches don't produce a result.

This way, it is easier to replace a comparison branch
with a specialized version and eliminate redundante checks before branches.
Review URL: https://chromiumcodereview.appspot.com//10887009

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@11500 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
fschneider@google.com 2012-08-29 09:07:11 +00:00
parent c16f0ef499
commit a347dd7f82
9 changed files with 223 additions and 452 deletions

View file

@ -276,8 +276,9 @@ void TestGraphVisitor::ReturnValue(Value* value) {
}
const Bool& bool_true = Bool::ZoneHandle(Bool::True());
Value* constant_true = Bind(Constant(bool_true));
StrictCompareAndBranchInstr* branch =
new StrictCompareAndBranchInstr(value, constant_true, Token::kEQ_STRICT);
StrictCompareComp* comp =
new StrictCompareComp(Token::kEQ_STRICT, value, constant_true);
BranchInstr* branch = new BranchInstr(comp);
AddInstruction(branch);
CloseFragment();
true_successor_address_ = branch->true_successor_address();
@ -289,22 +290,18 @@ void TestGraphVisitor::MergeBranchWithComparison(ComparisonComp* comp) {
ASSERT(!FLAG_enable_type_checks);
ControlInstruction* branch;
if (Token::IsStrictEqualityOperator(comp->kind())) {
branch = new StrictCompareAndBranchInstr(comp->left(),
comp->right(),
comp->kind());
branch = new BranchInstr(new StrictCompareComp(comp->kind(),
comp->left(),
comp->right()));
} else if (Token::IsEqualityOperator(comp->kind()) &&
(comp->left()->BindsToConstantNull() ||
comp->right()->BindsToConstantNull())) {
branch = new StrictCompareAndBranchInstr(
branch = new BranchInstr(new StrictCompareComp(
(comp->kind() == Token::kEQ) ? Token::kEQ_STRICT : Token::kNE_STRICT,
comp->left(),
comp->right(),
(comp->kind() == Token::kEQ) ? Token::kEQ_STRICT : Token::kNE_STRICT);
comp->right()));
} else {
branch = new BranchInstr(condition_token_pos(),
owner()->try_index(),
comp->left(),
comp->right(),
comp->kind());
branch = new BranchInstr(comp);
}
AddInstruction(branch);
CloseFragment();
@ -317,10 +314,10 @@ void TestGraphVisitor::MergeBranchWithNegate(BooleanNegateComp* comp) {
ASSERT(!FLAG_enable_type_checks);
const Bool& bool_true = Bool::ZoneHandle(Bool::True());
Value* constant_true = Bind(Constant(bool_true));
StrictCompareAndBranchInstr* branch =
new StrictCompareAndBranchInstr(comp->value(),
constant_true,
Token::kNE_STRICT);
BranchInstr* branch = new BranchInstr(
new StrictCompareComp(Token::kNE_STRICT,
comp->value(),
constant_true));
AddInstruction(branch);
CloseFragment();
true_successor_address_ = branch->true_successor_address();

View file

@ -752,6 +752,11 @@ void FlowGraphOptimizer::VisitBind(BindInstr* instr) {
}
void FlowGraphOptimizer::VisitBranch(BranchInstr* instr) {
instr->computation()->Accept(this, NULL);
}
void FlowGraphTypePropagator::VisitAssertAssignable(AssertAssignableComp* comp,
BindInstr* instr) {
if (FLAG_eliminate_type_checks &&

View file

@ -30,6 +30,7 @@ class FlowGraphOptimizer : public FlowGraphVisitor {
virtual void VisitEqualityCompare(EqualityCompareComp* comp,
BindInstr* instr);
virtual void VisitBind(BindInstr* instr);
virtual void VisitBranch(BranchInstr* instr);
private:
bool TryReplaceWithArrayOp(BindInstr* instr,

View file

@ -556,27 +556,10 @@ void GotoInstr::PrintTo(BufferFormatter* f) const {
void BranchInstr::PrintTo(BufferFormatter* f) const {
f->Print(" %s:%d ", DebugName(), deopt_id());
f->Print(" %s ", DebugName());
f->Print("if ");
left()->PrintTo(f);
f-> Print(" %s ", Token::Str(kind()));
right()->PrintTo(f);
computation()->PrintTo(f);
f->Print(" goto (%d, %d)",
true_successor()->block_id(),
false_successor()->block_id());
if (HasICData()) {
PrintICData(f, *ic_data());
}
}
void StrictCompareAndBranchInstr::PrintTo(BufferFormatter* f) const {
f->Print(" %s", DebugName());
f->Print("if ");
left()->PrintTo(f);
f-> Print(" %s ", Token::Str(kind()));
right()->PrintTo(f);
f->Print(" goto (%d, %d)",
true_successor()->block_id(),
false_successor()->block_id());
@ -830,21 +813,7 @@ void GotoInstr::PrintToVisualizer(BufferFormatter* f) const {
void BranchInstr::PrintToVisualizer(BufferFormatter* f) const {
f->Print("_ %s ", DebugName());
f->Print("if ");
left()->PrintTo(f);
f-> Print(" %s ", Token::Str(kind()));
right()->PrintTo(f);
f->Print(" goto (B%d, B%d)",
true_successor()->block_id(),
false_successor()->block_id());
}
void StrictCompareAndBranchInstr::PrintToVisualizer(BufferFormatter* f) const {
f->Print("_ %s ", DebugName());
f->Print("if ");
left()->PrintTo(f);
f-> Print(" %s ", Token::Str(kind()));
right()->PrintTo(f);
computation()->PrintTo(f);
f->Print(" goto (B%d, B%d)",
true_successor()->block_id(),
false_successor()->block_id());

View file

@ -1339,6 +1339,17 @@ void StrictCompareComp::EmitNativeCode(FlowGraphCompiler* compiler) {
}
void StrictCompareComp::EmitBranchCode(FlowGraphCompiler* compiler,
BranchInstr* branch) {
Register left = locs()->in(0).reg();
Register right = locs()->in(1).reg();
ASSERT(kind() == Token::kEQ_STRICT || kind() == Token::kNE_STRICT);
Condition true_condition = (kind() == Token::kEQ_STRICT) ? EQUAL : NOT_EQUAL;
__ CompareRegisters(left, right);
branch->EmitBranchOnCondition(compiler, true_condition);
}
void ClosureCallComp::EmitNativeCode(FlowGraphCompiler* compiler) {
// The arguments to the stub include the closure. The arguments
// descriptor describes the closure's arguments (and so does not include

View file

@ -229,6 +229,11 @@ class Computation : public ZoneAllocated {
// TODO(fschneider): Make EmitNativeCode and locs const.
virtual void EmitNativeCode(FlowGraphCompiler* compiler) = 0;
virtual void EmitBranchCode(FlowGraphCompiler* compiler,
BranchInstr* branch) {
UNREACHABLE();
}
static LocationSummary* MakeCallSummary();
// Declare an enum value used to define kind-test predicates.
@ -255,6 +260,8 @@ FOR_EACH_COMPUTATION(DECLARE_PREDICATE)
#undef DECLARE_PREDICATE
private:
friend class BranchInstr;
intptr_t deopt_id_;
const ICData* ic_data_;
LocationSummary* locs_;
@ -814,6 +821,9 @@ class StrictCompareComp : public ComparisonComp {
virtual intptr_t ResultCid() const { return kBoolCid; }
virtual void EmitBranchCode(FlowGraphCompiler* compiler,
BranchInstr* branch);
private:
DISALLOW_COPY_AND_ASSIGN(StrictCompareComp);
};
@ -847,6 +857,9 @@ class EqualityCompareComp : public ComparisonComp {
virtual bool CanDeoptimize() const { return true; }
virtual intptr_t ResultCid() const;
virtual void EmitBranchCode(FlowGraphCompiler* compiler,
BranchInstr* branch);
private:
const intptr_t token_pos_;
const intptr_t try_index_;
@ -888,6 +901,9 @@ class RelationalOpComp : public ComparisonComp {
virtual bool CanDeoptimize() const { return true; }
virtual intptr_t ResultCid() const;
virtual void EmitBranchCode(FlowGraphCompiler* compiler,
BranchInstr* branch);
private:
const intptr_t token_pos_;
const intptr_t try_index_;
@ -2205,7 +2221,6 @@ FOR_EACH_VALUE(DEFINE_VALUE_PREDICATE)
M(ReThrow) \
M(Goto) \
M(Branch) \
M(StrictCompareAndBranch)
// Forward declarations for Instruction classes.
@ -3215,129 +3230,49 @@ class ControlInstruction : public Instruction {
};
template<intptr_t N>
class TemplateControlInstruction: public ControlInstruction {
class BranchInstr : public ControlInstruction {
public:
TemplateControlInstruction<N>() : locs_(NULL) { }
virtual intptr_t InputCount() const { return N; }
virtual Value* InputAt(intptr_t i) const { return inputs_[i]; }
virtual void SetInputAt(intptr_t i, Value* value) {
ASSERT(value != NULL);
inputs_[i] = value;
}
virtual LocationSummary* locs() {
if (locs_ == NULL) {
locs_ = MakeLocationSummary();
}
return locs_;
}
virtual LocationSummary* MakeLocationSummary() const = 0;
protected:
EmbeddedArray<Value*, N> inputs_;
private:
LocationSummary* locs_;
};
class BranchInstr : public TemplateControlInstruction<2> {
public:
BranchInstr(intptr_t token_pos,
intptr_t try_index,
Value* left,
Value* right,
Token::Kind kind)
: deopt_id_(Isolate::kNoDeoptId),
ic_data_(NULL),
token_pos_(token_pos),
try_index_(try_index),
kind_(kind) {
ASSERT(left != NULL);
ASSERT(right != NULL);
inputs_[0] = left;
inputs_[1] = right;
ASSERT(!Token::IsStrictEqualityOperator(kind));
ASSERT(Token::IsEqualityOperator(kind) ||
Token::IsRelationalOperator(kind) ||
Token::IsTypeTestOperator(kind));
Isolate* isolate = Isolate::Current();
deopt_id_ = isolate->GetNextDeoptId();
ic_data_ = isolate->GetICDataForDeoptId(deopt_id_);
}
explicit BranchInstr(ComparisonComp* computation)
: computation_(computation), locs_(NULL) { }
DECLARE_INSTRUCTION(Branch)
Value* left() const { return inputs_[0]; }
Value* right() const { return inputs_[1]; }
virtual intptr_t ArgumentCount() const {
return computation()->ArgumentCount();
}
intptr_t InputCount() const { return computation()->InputCount(); }
virtual intptr_t ArgumentCount() const { return 0; }
Value* InputAt(intptr_t i) const { return computation()->InputAt(i); }
Token::Kind kind() const { return kind_; }
intptr_t deopt_id() const { return deopt_id_; }
const ICData* ic_data() const { return ic_data_; }
bool HasICData() const {
return (ic_data() != NULL) && !ic_data()->IsNull();
void SetInputAt(intptr_t i, Value* value) {
computation()->SetInputAt(i, value);
}
intptr_t token_pos() const { return token_pos_;}
intptr_t try_index() const { return try_index_; }
virtual bool CanDeoptimize() const { return computation()->CanDeoptimize(); }
virtual LocationSummary* MakeLocationSummary() const;
ComparisonComp* computation() const { return computation_; }
void set_computation(ComparisonComp* value) { computation_ = value; }
virtual void EmitNativeCode(FlowGraphCompiler* compiler);
virtual bool CanDeoptimize() const { return true; }
virtual LocationSummary* locs() {
if (computation_->locs_ == NULL) {
LocationSummary* summary = computation_->MakeLocationSummary();
// Branches don't produce a result.
summary->set_out(Location::NoLocation());
computation_->locs_ = summary;
}
return computation_->locs_;
}
private:
intptr_t deopt_id_;
const ICData* ic_data_;
const intptr_t token_pos_;
const intptr_t try_index_;
const Token::Kind kind_;
ComparisonComp* computation_;
LocationSummary* locs_;
DISALLOW_COPY_AND_ASSIGN(BranchInstr);
};
class StrictCompareAndBranchInstr : public TemplateControlInstruction<2> {
public:
StrictCompareAndBranchInstr(Value* left, Value* right, Token::Kind kind)
: kind_(kind) {
ASSERT(left != NULL);
ASSERT(right != NULL);
inputs_[0] = left;
inputs_[1] = right;
ASSERT(Token::IsStrictEqualityOperator(kind));
}
DECLARE_INSTRUCTION(StrictCompareAndBranch)
Value* left() const { return inputs_[0]; }
Value* right() const { return inputs_[1]; }
virtual intptr_t ArgumentCount() const { return 0; }
Token::Kind kind() const { return kind_; }
virtual LocationSummary* MakeLocationSummary() const;
virtual void EmitNativeCode(FlowGraphCompiler* compiler);
virtual bool CanDeoptimize() const { return false; }
private:
const Token::Kind kind_;
DISALLOW_COPY_AND_ASSIGN(StrictCompareAndBranchInstr);
};
#undef DECLARE_INSTRUCTION

View file

@ -540,9 +540,10 @@ static void EmitSmiComparisonOp(FlowGraphCompiler* compiler,
Register left = locs.in(0).reg();
Register right = locs.in(1).reg();
const bool left_is_smi = (branch == NULL) ?
false : (branch->left()->ResultCid() == kSmiCid);
false : (branch->computation()->left()->ResultCid() == kSmiCid);
const bool right_is_smi = (branch == NULL) ?
false : (branch->right()->ResultCid() == kSmiCid);
false : (branch->computation()->right()->ResultCid() == kSmiCid);
// TODO(fschneider): Move smi smi checks outside this instruction.
if (!left_is_smi || !right_is_smi) {
Register temp = locs.temp(0).reg();
Label* deopt = compiler->AddDeoptStub(deopt_id, kDeoptSmiCompareSmi);
@ -610,6 +611,7 @@ static void EmitDoubleComparisonOp(FlowGraphCompiler* compiler,
void EqualityCompareComp::EmitNativeCode(FlowGraphCompiler* compiler) {
ASSERT((kind() == Token::kNE) || (kind() == Token::kEQ));
BranchInstr* kNoBranch = NULL;
if (receiver_class_id() == kSmiCid) {
// Deoptimizes if both arguments not Smi.
@ -631,19 +633,60 @@ void EqualityCompareComp::EmitNativeCode(FlowGraphCompiler* compiler) {
if (HasICData() && (ic_data()->NumberOfChecks() > 0)) {
EmitGenericEqualityCompare(compiler, locs(), kind(), kNoBranch, *ic_data(),
deopt_id(), token_pos(), try_index());
} else {
Register left = locs()->in(0).reg();
Register right = locs()->in(1).reg();
__ pushl(left);
__ pushl(right);
EmitEqualityAsInstanceCall(compiler,
deopt_id(),
token_pos(),
try_index(),
kind(),
locs());
ASSERT(locs()->out().reg() == EAX);
return;
}
Register left = locs()->in(0).reg();
Register right = locs()->in(1).reg();
__ pushl(left);
__ pushl(right);
EmitEqualityAsInstanceCall(compiler,
deopt_id(),
token_pos(),
try_index(),
kind(),
locs());
ASSERT(locs()->out().reg() == EAX);
}
void EqualityCompareComp::EmitBranchCode(FlowGraphCompiler* compiler,
BranchInstr* branch) {
ASSERT((kind() == Token::kNE) || (kind() == Token::kEQ));
if (receiver_class_id() == kSmiCid) {
// Deoptimizes if both arguments not Smi.
EmitSmiComparisonOp(compiler, *locs(), kind(), branch, deopt_id());
return;
}
if (receiver_class_id() == kDoubleCid) {
// Deoptimizes if both arguments are Smi, or if none is Double or Smi.
EmitDoubleComparisonOp(compiler, *locs(), kind(), branch, deopt_id());
return;
}
const bool is_checked_strict_equal =
HasICData() && ic_data()->AllTargetsHaveSameOwner(kInstanceCid);
if (is_checked_strict_equal) {
EmitCheckedStrictEqual(compiler, *ic_data(), *locs(), kind(), branch,
deopt_id());
return;
}
if (HasICData() && (ic_data()->NumberOfChecks() > 0)) {
EmitGenericEqualityCompare(compiler, locs(), kind(), branch, *ic_data(),
deopt_id(), token_pos(), try_index());
return;
}
Register left = locs()->in(0).reg();
Register right = locs()->in(1).reg();
__ pushl(left);
__ pushl(right);
EmitEqualityAsInstanceCall(compiler,
deopt_id(),
token_pos(),
try_index(),
Token::kEQ, // kNE reverse occurs at branch.
locs());
Condition branch_condition = (kind() == Token::kNE) ? NOT_EQUAL : EQUAL;
__ CompareObject(EAX, compiler->bool_true());
branch->EmitBranchOnCondition(compiler, branch_condition);
}
@ -708,7 +751,6 @@ void RelationalOpComp::EmitNativeCode(FlowGraphCompiler* compiler) {
token_pos(),
try_index(),
locs());
ASSERT(locs()->out().reg() == EAX);
return;
}
const String& function_name =
@ -727,7 +769,22 @@ void RelationalOpComp::EmitNativeCode(FlowGraphCompiler* compiler) {
Array::ZoneHandle(), // No optional arguments.
kNumArgsChecked,
locs());
ASSERT(locs()->out().reg() == EAX);
}
void RelationalOpComp::EmitBranchCode(FlowGraphCompiler* compiler,
BranchInstr* branch) {
if (operands_class_id() == kSmiCid) {
EmitSmiComparisonOp(compiler, *locs(), kind(), branch, deopt_id());
return;
}
if (operands_class_id() == kDoubleCid) {
EmitDoubleComparisonOp(compiler, *locs(), kind(), branch, deopt_id());
return;
}
EmitNativeCode(compiler);
__ CompareObject(EAX, compiler->bool_true());
branch->EmitBranchOnCondition(compiler, EQUAL);
}
@ -2108,139 +2165,8 @@ void PolymorphicInstanceCallComp::EmitNativeCode(FlowGraphCompiler* compiler) {
}
// 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);
}
static bool IsCheckedStrictEquals(const ICData& ic_data, Token::Kind kind) {
if ((kind == Token::kEQ) || (kind == Token::kNE)) {
return ic_data.AllTargetsHaveSameOwner(kInstanceCid);
}
return false;
}
LocationSummary* BranchInstr::MakeLocationSummary() const {
if (HasICData() && (ic_data()->NumberOfChecks() > 0)) {
if (ICDataWithBothClassIds(*ic_data(), kSmiCid) ||
ICDataWithBothClassIds(*ic_data(), kDoubleCid) ||
IsCheckedStrictEquals(*ic_data(), kind())) {
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::RegisterLocation(EAX));
locs->set_in(1, Location::RegisterLocation(ECX));
locs->set_temp(0, Location::RegisterLocation(EDX));
return locs;
}
// Otherwise polymorphic dispatch.
}
// Call.
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 0;
LocationSummary* locs =
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall);
locs->set_in(0, Location::RegisterLocation(EAX));
locs->set_in(1, Location::RegisterLocation(ECX));
return locs;
}
void BranchInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
// Relational or equality.
if (HasICData() && (ic_data()->NumberOfChecks() > 0)) {
if (ICDataWithBothClassIds(*ic_data(), kSmiCid)) {
EmitSmiComparisonOp(compiler, *locs(), kind(), this, deopt_id());
return;
}
if (ICDataWithBothClassIds(*ic_data(), kDoubleCid)) {
EmitDoubleComparisonOp(compiler, *locs(), kind(), this, deopt_id());
return;
}
if (IsCheckedStrictEquals(*ic_data(), kind())) {
EmitCheckedStrictEqual(compiler, *ic_data(), *locs(), kind(), this,
deopt_id());
return;
}
// TODO(srdjan): Add Smi/Double, Double/Smi comparisons.
if ((kind() == Token::kEQ) || (kind() == Token::kNE)) {
EmitGenericEqualityCompare(compiler, locs(), kind(), this, *ic_data(),
deopt_id(), token_pos(), try_index());
return;
}
// Otherwise polymorphic dispatch?
}
Register left = locs()->in(0).reg();
Register right = locs()->in(1).reg();
__ pushl(left);
__ pushl(right);
if ((kind() == Token::kNE) || (kind() == Token::kEQ)) {
EmitEqualityAsInstanceCall(compiler,
deopt_id(),
token_pos(),
try_index(),
Token::kEQ, // kNE reverse occurs at branch.
locs());
} else {
const String& function_name =
String::ZoneHandle(Symbols::New(Token::Str(kind())));
compiler->AddCurrentDescriptor(PcDescriptors::kDeopt,
deopt_id(),
token_pos(),
try_index());
const intptr_t kNumArguments = 2;
const intptr_t kNumArgsChecked = 2; // Type-feedback.
compiler->GenerateInstanceCall(deopt_id(),
token_pos(),
try_index(),
function_name,
kNumArguments,
Array::ZoneHandle(), // No optional args.
kNumArgsChecked,
locs());
}
Condition branch_condition = (kind() == Token::kNE) ? NOT_EQUAL : EQUAL;
__ CompareObject(EAX, compiler->bool_true());
EmitBranchOnCondition(compiler, branch_condition);
}
LocationSummary* StrictCompareAndBranchInstr::MakeLocationSummary() const {
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;
}
void StrictCompareAndBranchInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
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);
computation()->EmitBranchCode(compiler, this);
}

View file

@ -550,9 +550,10 @@ static void EmitSmiComparisonOp(FlowGraphCompiler* compiler,
Register left = locs.in(0).reg();
Register right = locs.in(1).reg();
const bool left_is_smi = (branch == NULL) ?
false : (branch->left()->ResultCid() == kSmiCid);
false : (branch->computation()->left()->ResultCid() == kSmiCid);
const bool right_is_smi = (branch == NULL) ?
false : (branch->right()->ResultCid() == kSmiCid);
false : (branch->computation()->right()->ResultCid() == kSmiCid);
// TODO(fschneider): Move smi smi checks outside this instruction.
if (!left_is_smi || !right_is_smi) {
Register temp = locs.temp(0).reg();
Label* deopt = compiler->AddDeoptStub(deopt_id, kDeoptSmiCompareSmi);
@ -620,6 +621,7 @@ static void EmitDoubleComparisonOp(FlowGraphCompiler* compiler,
void EqualityCompareComp::EmitNativeCode(FlowGraphCompiler* compiler) {
ASSERT((kind() == Token::kEQ) || (kind() == Token::kNE));
BranchInstr* kNoBranch = NULL;
if (receiver_class_id() == kSmiCid) {
// Deoptimizes if both arguments not Smi.
@ -641,19 +643,60 @@ void EqualityCompareComp::EmitNativeCode(FlowGraphCompiler* compiler) {
if (HasICData() && (ic_data()->NumberOfChecks() > 0)) {
EmitGenericEqualityCompare(compiler, locs(), kind(), kNoBranch, *ic_data(),
deopt_id(), token_pos(), try_index());
} else {
Register left = locs()->in(0).reg();
Register right = locs()->in(1).reg();
__ pushq(left);
__ pushq(right);
EmitEqualityAsInstanceCall(compiler,
deopt_id(),
token_pos(),
try_index(),
kind(),
locs());
ASSERT(locs()->out().reg() == RAX);
return;
}
Register left = locs()->in(0).reg();
Register right = locs()->in(1).reg();
__ pushq(left);
__ pushq(right);
EmitEqualityAsInstanceCall(compiler,
deopt_id(),
token_pos(),
try_index(),
kind(),
locs());
ASSERT(locs()->out().reg() == RAX);
}
void EqualityCompareComp::EmitBranchCode(FlowGraphCompiler* compiler,
BranchInstr* branch) {
ASSERT((kind() == Token::kNE) || (kind() == Token::kEQ));
if (receiver_class_id() == kSmiCid) {
// Deoptimizes if both arguments not Smi.
EmitSmiComparisonOp(compiler, *locs(), kind(), branch, deopt_id());
return;
}
if (receiver_class_id() == kDoubleCid) {
// Deoptimizes if both arguments are Smi, or if none is Double or Smi.
EmitDoubleComparisonOp(compiler, *locs(), kind(), branch, deopt_id());
return;
}
const bool is_checked_strict_equal =
HasICData() && ic_data()->AllTargetsHaveSameOwner(kInstanceCid);
if (is_checked_strict_equal) {
EmitCheckedStrictEqual(compiler, *ic_data(), *locs(), kind(), branch,
deopt_id());
return;
}
if (HasICData() && (ic_data()->NumberOfChecks() > 0)) {
EmitGenericEqualityCompare(compiler, locs(), kind(), branch, *ic_data(),
deopt_id(), token_pos(), try_index());
return;
}
Register left = locs()->in(0).reg();
Register right = locs()->in(1).reg();
__ pushq(left);
__ pushq(right);
EmitEqualityAsInstanceCall(compiler,
deopt_id(),
token_pos(),
try_index(),
Token::kEQ, // kNE reverse occurs at branch.
locs());
Condition branch_condition = (kind() == Token::kNE) ? NOT_EQUAL : EQUAL;
__ CompareObject(RAX, compiler->bool_true());
branch->EmitBranchOnCondition(compiler, branch_condition);
}
@ -719,7 +762,6 @@ void RelationalOpComp::EmitNativeCode(FlowGraphCompiler* compiler) {
token_pos(),
try_index(),
locs());
ASSERT(locs()->out().reg() == RAX);
return;
}
const String& function_name =
@ -738,7 +780,22 @@ void RelationalOpComp::EmitNativeCode(FlowGraphCompiler* compiler) {
Array::ZoneHandle(), // No optional arguments.
kNumArgsChecked,
locs());
ASSERT(locs()->out().reg() == RAX);
}
void RelationalOpComp::EmitBranchCode(FlowGraphCompiler* compiler,
BranchInstr* branch) {
if (operands_class_id() == kSmiCid) {
EmitSmiComparisonOp(compiler, *locs(), kind(), branch, deopt_id());
return;
}
if (operands_class_id() == kDoubleCid) {
EmitDoubleComparisonOp(compiler, *locs(), kind(), branch, deopt_id());
return;
}
EmitNativeCode(compiler);
__ CompareObject(RAX, compiler->bool_true());
branch->EmitBranchOnCondition(compiler, EQUAL);
}
@ -2116,138 +2173,8 @@ void PolymorphicInstanceCallComp::EmitNativeCode(FlowGraphCompiler* compiler) {
}
// 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);
}
static bool IsCheckedStrictEquals(const ICData& ic_data, Token::Kind kind) {
if ((kind == Token::kEQ) || (kind == Token::kNE)) {
return ic_data.AllTargetsHaveSameOwner(kInstanceCid);
}
return false;
}
LocationSummary* BranchInstr::MakeLocationSummary() const {
if (HasICData() && (ic_data()->NumberOfChecks() > 0)) {
if (ICDataWithBothClassIds(*ic_data(), kSmiCid) ||
ICDataWithBothClassIds(*ic_data(), kDoubleCid) ||
IsCheckedStrictEquals(*ic_data(), kind())) {
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::RegisterLocation(RAX));
locs->set_in(1, Location::RegisterLocation(RCX));
locs->set_temp(0, Location::RegisterLocation(RDX));
return locs;
}
// Otherwise polymorphic dispatch.
}
// Call.
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 0;
LocationSummary* locs =
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall);
locs->set_in(0, Location::RegisterLocation(RAX));
locs->set_in(1, Location::RegisterLocation(RCX));
return locs;
}
void BranchInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
// Relational or equality.
if (HasICData() && (ic_data()->NumberOfChecks() > 0)) {
if (ICDataWithBothClassIds(*ic_data(), kSmiCid)) {
EmitSmiComparisonOp(compiler, *locs(), kind(), this, deopt_id());
return;
}
if (ICDataWithBothClassIds(*ic_data(), kDoubleCid)) {
EmitDoubleComparisonOp(compiler, *locs(), kind(), this, deopt_id());
return;
}
if (IsCheckedStrictEquals(*ic_data(), kind())) {
EmitCheckedStrictEqual(compiler, *ic_data(), *locs(), kind(), this,
deopt_id());
return;
}
// TODO(srdjan): Add Smi/Double, Double/Smi comparisons.
if ((kind() == Token::kEQ) || (kind() == Token::kNE)) {
EmitGenericEqualityCompare(compiler, locs(), kind(), this, *ic_data(),
deopt_id(), token_pos(), try_index());
return;
}
// Otherwise polymorphic dispatch?
}
Register left = locs()->in(0).reg();
Register right = locs()->in(1).reg();
__ pushq(left);
__ pushq(right);
if ((kind() == Token::kNE) || (kind() == Token::kEQ)) {
EmitEqualityAsInstanceCall(compiler,
deopt_id(),
token_pos(),
try_index(),
Token::kEQ, // kNE reverse occurs at branch.
locs());
} else {
const String& function_name =
String::ZoneHandle(Symbols::New(Token::Str(kind())));
compiler->AddCurrentDescriptor(PcDescriptors::kDeopt,
deopt_id(),
token_pos(),
try_index());
const intptr_t kNumArguments = 2;
const intptr_t kNumArgsChecked = 2; // Type-feedback.
compiler->GenerateInstanceCall(deopt_id(),
token_pos(),
try_index(),
function_name,
kNumArguments,
Array::ZoneHandle(), // No optional args.
kNumArgsChecked,
locs());
}
Condition branch_condition = (kind() == Token::kNE) ? NOT_EQUAL : EQUAL;
__ CompareObject(RAX, compiler->bool_true());
EmitBranchOnCondition(compiler, branch_condition);
}
LocationSummary* StrictCompareAndBranchInstr::MakeLocationSummary() const {
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;
}
void StrictCompareAndBranchInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
Register left = locs()->in(0).reg();
Register right = locs()->in(1).reg();
__ cmpq(left, right);
Condition cond = (kind() == Token::kEQ_STRICT) ? EQUAL : NOT_EQUAL;
EmitBranchOnCondition(compiler, cond);
computation()->EmitBranchCode(compiler, this);
}

View file

@ -373,7 +373,7 @@ class LocationSummary : public ZoneAllocated {
}
void set_out(Location loc) {
ASSERT(!always_calls() || loc.IsRegister());
ASSERT(!always_calls() || (loc.IsRegister() || loc.IsInvalid()));
output_location_ = loc;
}