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

Side by Side Diff: runtime/vm/aot_optimizer.cc

Issue 2314133003: AOT: Use a cid range check when possible to implement type tests. (Closed)
Patch Set: . Created 4 years, 3 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 unified diff | Download patch
OLDNEW
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 #include "vm/aot_optimizer.h" 5 #include "vm/aot_optimizer.h"
6 6
7 #include "vm/bit_vector.h" 7 #include "vm/bit_vector.h"
8 #include "vm/branch_optimizer.h" 8 #include "vm/branch_optimizer.h"
9 #include "vm/cha.h" 9 #include "vm/cha.h"
10 #include "vm/compiler.h" 10 #include "vm/compiler.h"
(...skipping 19 matching lines...) Expand all
30 namespace dart { 30 namespace dart {
31 31
32 DEFINE_FLAG(int, max_exhaustive_polymorphic_checks, 5, 32 DEFINE_FLAG(int, max_exhaustive_polymorphic_checks, 5,
33 "If a call receiver is known to be of at most this many classes, " 33 "If a call receiver is known to be of at most this many classes, "
34 "generate exhaustive class tests instead of a megamorphic call"); 34 "generate exhaustive class tests instead of a megamorphic call");
35 35
36 // Quick access to the current isolate and zone. 36 // Quick access to the current isolate and zone.
37 #define I (isolate()) 37 #define I (isolate())
38 #define Z (zone()) 38 #define Z (zone())
39 39
40 #ifdef DART_PRECOMPILER
41
40 static bool ShouldInlineSimd() { 42 static bool ShouldInlineSimd() {
41 return FlowGraphCompiler::SupportsUnboxedSimd128(); 43 return FlowGraphCompiler::SupportsUnboxedSimd128();
42 } 44 }
43 45
44 46
45 static bool CanUnboxDouble() { 47 static bool CanUnboxDouble() {
46 return FlowGraphCompiler::SupportsUnboxedDoubles(); 48 return FlowGraphCompiler::SupportsUnboxedDoubles();
47 } 49 }
48 50
49 51
(...skipping 357 matching lines...) Expand 10 before | Expand all | Expand 10 after
407 // Remove the original push arguments. 409 // Remove the original push arguments.
408 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { 410 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) {
409 PushArgumentInstr* push = call->PushArgumentAt(i); 411 PushArgumentInstr* push = call->PushArgumentAt(i);
410 push->ReplaceUsesWith(push->value()->definition()); 412 push->ReplaceUsesWith(push->value()->definition());
411 push->RemoveFromGraph(); 413 push->RemoveFromGraph();
412 } 414 }
413 call->ReplaceWith(replacement, current_iterator()); 415 call->ReplaceWith(replacement, current_iterator());
414 } 416 }
415 417
416 418
419 void AotOptimizer::ReplaceCallWithSubgraph(Definition* call,
420 TargetEntryInstr* entry,
421 Definition* last) {
422 // We are splitting block A into a subgraph starting at A and ending at B.
423 // Give the original block id to B to maintain the order of phi inputs at its
424 // successors consistent with block ids.
425 BlockEntryInstr* a = call->GetBlock();
426 BlockEntryInstr* b = last->GetBlock();
427 intptr_t block_id_temp = a->block_id();
428 a->set_block_id(b->block_id());
429 b->set_block_id(block_id_temp);
430
431 // Remove the original push arguments.
432 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) {
433 PushArgumentInstr* push = call->PushArgumentAt(i);
434 push->ReplaceUsesWith(push->value()->definition());
435 push->RemoveFromGraph();
436 }
437 // Replace all uses of this definition with the result.
438 if (call->HasUses()) {
439 call->ReplaceUsesWith(last);
440 }
441 // Finally insert the sequence other definition in place of this one in the
442 // graph.
443 if (entry->next() != NULL) {
444 call->previous()->LinkTo(entry->next());
445 }
446 entry->UnuseAllInputs(); // Entry block is not in the graph.
447 if (last != NULL) {
448 if (last->IsPhi()) {
449 last->AsPhi()->block()->LinkTo(call);
450 } else {
451 last->LinkTo(call);
452 }
453 }
454 call->RemoveFromGraph();
455 call->set_previous(NULL);
456 call->set_next(NULL);
457
458 // Discover new predecessors and recompute dominators.
459 flow_graph()->DiscoverBlocks();
460 GrowableArray<BitVector*> dominance_frontier;
461 flow_graph()->ComputeDominators(&dominance_frontier);
462 }
463
464
417 void AotOptimizer::AddCheckSmi(Definition* to_check, 465 void AotOptimizer::AddCheckSmi(Definition* to_check,
418 intptr_t deopt_id, 466 intptr_t deopt_id,
419 Environment* deopt_environment, 467 Environment* deopt_environment,
420 Instruction* insert_before) { 468 Instruction* insert_before) {
421 if (to_check->Type()->ToCid() != kSmiCid) { 469 if (to_check->Type()->ToCid() != kSmiCid) {
422 InsertBefore(insert_before, 470 InsertBefore(insert_before,
423 new(Z) CheckSmiInstr(new(Z) Value(to_check), 471 new(Z) CheckSmiInstr(new(Z) Value(to_check),
424 deopt_id, 472 deopt_id,
425 insert_before->token_pos()), 473 insert_before->token_pos()),
426 deopt_environment, 474 deopt_environment,
(...skipping 1106 matching lines...) Expand 10 before | Expand all | Expand 10 after
1533 new(Z) StrictCompareInstr( 1581 new(Z) StrictCompareInstr(
1534 call->token_pos(), 1582 call->token_pos(),
1535 negate ? Token::kNE_STRICT : Token::kEQ_STRICT, 1583 negate ? Token::kNE_STRICT : Token::kEQ_STRICT,
1536 new(Z) Value(left_cid), 1584 new(Z) Value(left_cid),
1537 new(Z) Value(cid), 1585 new(Z) Value(cid),
1538 false); // No number check. 1586 false); // No number check.
1539 ReplaceCall(call, check_cid); 1587 ReplaceCall(call, check_cid);
1540 return; 1588 return;
1541 } 1589 }
1542 1590
1591 TypeRangeCache* cache = thread()->type_range_cache();
1592 intptr_t lower_limit, upper_limit;
1593 if (cache != NULL &&
1594 cache->InstanceOfHasClassRange(type, &lower_limit, &upper_limit)) {
1595 ReplaceWithClassRangeCheck(call, left, negate, lower_limit, upper_limit);
1596 return;
1597 }
1598
1543 const ICData& unary_checks = 1599 const ICData& unary_checks =
1544 ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecks()); 1600 ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecks());
1545 if ((unary_checks.NumberOfChecks() > 0) && 1601 if ((unary_checks.NumberOfChecks() > 0) &&
1546 (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks)) { 1602 (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks)) {
1547 ZoneGrowableArray<intptr_t>* results = 1603 ZoneGrowableArray<intptr_t>* results =
1548 new(Z) ZoneGrowableArray<intptr_t>(unary_checks.NumberOfChecks() * 2); 1604 new(Z) ZoneGrowableArray<intptr_t>(unary_checks.NumberOfChecks() * 2);
1549 InstanceOfAsBool(unary_checks, type, results); 1605 InstanceOfAsBool(unary_checks, type, results);
1550 if (results->length() == unary_checks.NumberOfChecks() * 2) { 1606 if (results->length() == unary_checks.NumberOfChecks() * 2) {
1551 const bool can_deopt = TryExpandTestCidsResult(results, type); 1607 const bool can_deopt = TryExpandTestCidsResult(results, type);
1552 if (can_deopt && !IsAllowedForInlining(call->deopt_id())) { 1608 if (can_deopt && !IsAllowedForInlining(call->deopt_id())) {
(...skipping 16 matching lines...) Expand all
1569 new(Z) InstanceOfInstr(call->token_pos(), 1625 new(Z) InstanceOfInstr(call->token_pos(),
1570 new(Z) Value(left), 1626 new(Z) Value(left),
1571 new(Z) Value(type_args), 1627 new(Z) Value(type_args),
1572 type, 1628 type,
1573 negate, 1629 negate,
1574 call->deopt_id()); 1630 call->deopt_id());
1575 ReplaceCall(call, instance_of); 1631 ReplaceCall(call, instance_of);
1576 } 1632 }
1577 1633
1578 1634
1635 void AotOptimizer::ReplaceWithClassRangeCheck(InstanceCallInstr* call,
Florian Schneider 2016/09/07 16:35:57 I wonder if it would be easier to replace the call
rmacnak 2016/09/07 22:21:27 Yes, I like that better.
1636 Definition* left,
1637 bool negate,
1638 intptr_t lower_limit,
1639 intptr_t upper_limit) {
1640 // left.instanceof(type) =>
1641 // t = left.cid,
1642 // t < lower_limit ? negate : (t > upper_limit ? negate, !negate)
1643 TargetEntryInstr* entry =
1644 new(Z) TargetEntryInstr(flow_graph()->allocate_block_id(),
1645 call->GetBlock()->try_index());
1646 entry->InheritDeoptTarget(Z, call);
1647 TargetEntryInstr* check_upper =
1648 new(Z) TargetEntryInstr(flow_graph()->allocate_block_id(),
1649 call->GetBlock()->try_index());
1650 check_upper->InheritDeoptTarget(Z, call);
1651 TargetEntryInstr* too_low =
1652 new(Z) TargetEntryInstr(flow_graph()->allocate_block_id(),
1653 call->GetBlock()->try_index());
1654 too_low->InheritDeoptTarget(Z, call);
1655 TargetEntryInstr* too_high =
1656 new(Z) TargetEntryInstr(flow_graph()->allocate_block_id(),
1657 call->GetBlock()->try_index());
1658 too_high->InheritDeoptTarget(Z, call);
1659 TargetEntryInstr* match =
1660 new(Z) TargetEntryInstr(flow_graph()->allocate_block_id(),
1661 call->GetBlock()->try_index());
1662 match->InheritDeoptTarget(Z, call);
1663 JoinEntryInstr* result =
1664 new(Z) JoinEntryInstr(flow_graph()->allocate_block_id(),
1665 call->GetBlock()->try_index());
1666 result->InheritDeoptTargetAfter(flow_graph(), call, NULL);
1667
1668 LoadClassIdInstr* left_cid = new(Z) LoadClassIdInstr(new(Z) Value(left));
1669 ConstantInstr* lower_cid =
1670 flow_graph()->GetConstant(Smi::Handle(Z, Smi::New(lower_limit)));
1671 RelationalOpInstr* compare_lower =
1672 new(Z) RelationalOpInstr(call->token_pos(),
1673 Token::kLT,
1674 new(Z) Value(left_cid),
1675 new(Z) Value(lower_cid),
1676 kSmiCid,
1677 call->deopt_id());
1678 BranchInstr* branch_lower = new(Z) BranchInstr(compare_lower);
1679 flow_graph()->AppendTo(entry,
1680 left_cid,
1681 call->env(),
1682 FlowGraph::kValue);
1683 flow_graph()->AppendTo(left_cid,
1684 branch_lower,
1685 call->env(),
1686 FlowGraph::kEffect);
1687
1688 ConstantInstr* upper_cid =
1689 flow_graph()->GetConstant(Smi::Handle(Z, Smi::New(upper_limit)));
1690 RelationalOpInstr* compare_upper =
1691 new(Z) RelationalOpInstr(call->token_pos(),
1692 Token::kGT,
1693 new(Z) Value(left_cid),
1694 new(Z) Value(upper_cid),
1695 kSmiCid,
1696 call->deopt_id());
1697 BranchInstr* branch_upper = new(Z) BranchInstr(compare_upper);
1698 flow_graph()->AppendTo(check_upper,
1699 branch_upper,
1700 call->env(),
1701 FlowGraph::kEffect);
1702
1703 *branch_lower->true_successor_address() = too_low;
1704 *branch_lower->false_successor_address() = check_upper;
1705
1706 *branch_upper->true_successor_address() = too_high;
1707 *branch_upper->false_successor_address() = match;
1708
1709 flow_graph()->AppendTo(too_low,
1710 new(Z) GotoInstr(result),
1711 call->env(),
1712 FlowGraph::kEffect);
1713 flow_graph()->AppendTo(too_high,
1714 new(Z) GotoInstr(result),
1715 call->env(),
1716 FlowGraph::kEffect);
1717 flow_graph()->AppendTo(match,
1718 new(Z) GotoInstr(result),
1719 call->env(),
1720 FlowGraph::kEffect);
1721
1722 PhiInstr* result_phi = new(Z) PhiInstr(result, 3);
1723 flow_graph()->AllocateSSAIndexes(result_phi);
1724 result_phi->mark_alive();
1725
1726 // Discovers predecessors for the 'result' block.
1727 ReplaceCallWithSubgraph(call, entry, result_phi);
1728
1729 Value* v;
1730 v = new(Z) Value(flow_graph()->GetConstant(Bool::Get(negate)));
1731 v->definition()->AddInputUse(v);
1732 result_phi->SetInputAt(result->IndexOfPredecessor(too_low), v);
1733
1734 v = new(Z) Value(flow_graph()->GetConstant(Bool::Get(negate)));
1735 v->definition()->AddInputUse(v);
1736 result_phi->SetInputAt(result->IndexOfPredecessor(too_high), v);
1737
1738 v = new(Z) Value(flow_graph()->GetConstant(Bool::Get(!negate)));
1739 v->definition()->AddInputUse(v);
1740 result_phi->SetInputAt(result->IndexOfPredecessor(match), v);
1741
1742 result->InsertPhi(result_phi);
1743
1744 flow_graph()->VerifyUseLists();
1745 }
1746
1747
1579 // TODO(srdjan): Apply optimizations as in ReplaceWithInstanceOf (TestCids). 1748 // TODO(srdjan): Apply optimizations as in ReplaceWithInstanceOf (TestCids).
1580 void AotOptimizer::ReplaceWithTypeCast(InstanceCallInstr* call) { 1749 void AotOptimizer::ReplaceWithTypeCast(InstanceCallInstr* call) {
1581 ASSERT(Token::IsTypeCastOperator(call->token_kind())); 1750 ASSERT(Token::IsTypeCastOperator(call->token_kind()));
1582 Definition* left = call->ArgumentAt(0); 1751 Definition* left = call->ArgumentAt(0);
1583 Definition* type_args = call->ArgumentAt(1); 1752 Definition* type_args = call->ArgumentAt(1);
1584 const AbstractType& type = 1753 const AbstractType& type =
1585 AbstractType::Cast(call->ArgumentAt(2)->AsConstant()->value()); 1754 AbstractType::Cast(call->ArgumentAt(2)->AsConstant()->value());
1586 ASSERT(!type.IsMalformedOrMalbounded()); 1755 ASSERT(!type.IsMalformedOrMalbounded());
1587 const ICData& unary_checks = 1756 const ICData& unary_checks =
1588 ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecks()); 1757 ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecks());
(...skipping 542 matching lines...) Expand 10 before | Expand all | Expand 10 after
2131 new(Z) Value(check->index()->definition()), 2300 new(Z) Value(check->index()->definition()),
2132 check->deopt_id()); 2301 check->deopt_id());
2133 flow_graph_->InsertBefore(check, new_check, 2302 flow_graph_->InsertBefore(check, new_check,
2134 check->env(), FlowGraph::kEffect); 2303 check->env(), FlowGraph::kEffect);
2135 current_iterator()->RemoveCurrentFromGraph(); 2304 current_iterator()->RemoveCurrentFromGraph();
2136 } 2305 }
2137 } 2306 }
2138 } 2307 }
2139 } 2308 }
2140 2309
2310 #endif // DART_PRECOMPILER
2141 2311
2142 } // namespace dart 2312 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/vm/aot_optimizer.h ('k') | runtime/vm/compiler.cc » ('j') | runtime/vm/precompiler.cc » ('J')

Powered by Google App Engine
This is Rietveld 408576698