From a347dd7f82554668b2c9111bdf917773c888d9a7 Mon Sep 17 00:00:00 2001 From: "fschneider@google.com" Date: Wed, 29 Aug 2012 09:07:11 +0000 Subject: [PATCH] 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 --- runtime/vm/flow_graph_builder.cc | 31 ++-- runtime/vm/flow_graph_optimizer.cc | 5 + runtime/vm/flow_graph_optimizer.h | 1 + runtime/vm/il_printer.cc | 37 +--- runtime/vm/intermediate_language.cc | 11 ++ runtime/vm/intermediate_language.h | 145 ++++----------- runtime/vm/intermediate_language_ia32.cc | 222 ++++++++--------------- runtime/vm/intermediate_language_x64.cc | 221 ++++++++-------------- runtime/vm/locations.h | 2 +- 9 files changed, 223 insertions(+), 452 deletions(-) diff --git a/runtime/vm/flow_graph_builder.cc b/runtime/vm/flow_graph_builder.cc index 09282efb58c..58f0d0d8b56 100644 --- a/runtime/vm/flow_graph_builder.cc +++ b/runtime/vm/flow_graph_builder.cc @@ -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(); diff --git a/runtime/vm/flow_graph_optimizer.cc b/runtime/vm/flow_graph_optimizer.cc index 781d4095bc9..af1c5f97aa8 100644 --- a/runtime/vm/flow_graph_optimizer.cc +++ b/runtime/vm/flow_graph_optimizer.cc @@ -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 && diff --git a/runtime/vm/flow_graph_optimizer.h b/runtime/vm/flow_graph_optimizer.h index de6e1ef9fc0..09a0d95b0ff 100644 --- a/runtime/vm/flow_graph_optimizer.h +++ b/runtime/vm/flow_graph_optimizer.h @@ -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, diff --git a/runtime/vm/il_printer.cc b/runtime/vm/il_printer.cc index aa9e1d68699..30afbd1bd33 100644 --- a/runtime/vm/il_printer.cc +++ b/runtime/vm/il_printer.cc @@ -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()); diff --git a/runtime/vm/intermediate_language.cc b/runtime/vm/intermediate_language.cc index a0f635ddfec..7518fcb256f 100644 --- a/runtime/vm/intermediate_language.cc +++ b/runtime/vm/intermediate_language.cc @@ -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 diff --git a/runtime/vm/intermediate_language.h b/runtime/vm/intermediate_language.h index 7759834c620..2217d5b3b5c 100644 --- a/runtime/vm/intermediate_language.h +++ b/runtime/vm/intermediate_language.h @@ -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 -class TemplateControlInstruction: public ControlInstruction { +class BranchInstr : public ControlInstruction { public: - TemplateControlInstruction() : 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 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 diff --git a/runtime/vm/intermediate_language_ia32.cc b/runtime/vm/intermediate_language_ia32.cc index 4ef72e679eb..913fb30644e 100644 --- a/runtime/vm/intermediate_language_ia32.cc +++ b/runtime/vm/intermediate_language_ia32.cc @@ -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 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); } diff --git a/runtime/vm/intermediate_language_x64.cc b/runtime/vm/intermediate_language_x64.cc index bef00086c9d..62db0564d92 100644 --- a/runtime/vm/intermediate_language_x64.cc +++ b/runtime/vm/intermediate_language_x64.cc @@ -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 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); } diff --git a/runtime/vm/locations.h b/runtime/vm/locations.h index 2ddc0650160..57dbb1f79d3 100644 --- a/runtime/vm/locations.h +++ b/runtime/vm/locations.h @@ -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; }