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

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 396 matching lines...) Expand 10 before | Expand all | Expand 10 after
407 // Remove the original push arguments. 407 // Remove the original push arguments.
408 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { 408 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) {
409 PushArgumentInstr* push = call->PushArgumentAt(i); 409 PushArgumentInstr* push = call->PushArgumentAt(i);
410 push->ReplaceUsesWith(push->value()->definition()); 410 push->ReplaceUsesWith(push->value()->definition());
411 push->RemoveFromGraph(); 411 push->RemoveFromGraph();
412 } 412 }
413 call->ReplaceWith(replacement, current_iterator()); 413 call->ReplaceWith(replacement, current_iterator());
414 } 414 }
415 415
416 416
417 void AotOptimizer::ReplaceCallWithSubgraph(Definition* call,
418 TargetEntryInstr* entry,
419 Definition* last) {
420 // We are splitting block A into a subgraph starting at A and ending at B.
421 // Give the original block id to B to maintain the order of phi inputs at its
422 // successors consistent with block ids.
423 BlockEntryInstr* a = call->GetBlock();
424 BlockEntryInstr* b = last->GetBlock();
425 intptr_t block_id_temp = a->block_id();
426 a->set_block_id(b->block_id());
427 b->set_block_id(block_id_temp);
428
429 // Remove the original push arguments.
430 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) {
431 PushArgumentInstr* push = call->PushArgumentAt(i);
432 push->ReplaceUsesWith(push->value()->definition());
433 push->RemoveFromGraph();
434 }
435 // Replace all uses of this definition with the result.
436 if (call->HasUses()) {
437 call->ReplaceUsesWith(last);
438 }
439 // Finally insert the sequence other definition in place of this one in the
440 // graph.
441 if (entry->next() != NULL) {
442 call->previous()->LinkTo(entry->next());
443 }
444 entry->UnuseAllInputs(); // Entry block is not in the graph.
445 if (last != NULL) {
446 if (last->IsPhi()) {
447 last->AsPhi()->block()->LinkTo(call);
448 } else {
449 last->LinkTo(call);
450 }
451 }
452 call->RemoveFromGraph();
453 call->set_previous(NULL);
454 call->set_next(NULL);
455
456 // Discover new predecessors and recompute dominators.
457 flow_graph()->DiscoverBlocks();
458 GrowableArray<BitVector*> dominance_frontier;
459 flow_graph()->ComputeDominators(&dominance_frontier);
460 }
461
462
417 void AotOptimizer::AddCheckSmi(Definition* to_check, 463 void AotOptimizer::AddCheckSmi(Definition* to_check,
418 intptr_t deopt_id, 464 intptr_t deopt_id,
419 Environment* deopt_environment, 465 Environment* deopt_environment,
420 Instruction* insert_before) { 466 Instruction* insert_before) {
421 if (to_check->Type()->ToCid() != kSmiCid) { 467 if (to_check->Type()->ToCid() != kSmiCid) {
422 InsertBefore(insert_before, 468 InsertBefore(insert_before,
423 new(Z) CheckSmiInstr(new(Z) Value(to_check), 469 new(Z) CheckSmiInstr(new(Z) Value(to_check),
424 deopt_id, 470 deopt_id,
425 insert_before->token_pos()), 471 insert_before->token_pos()),
426 deopt_environment, 472 deopt_environment,
(...skipping 1106 matching lines...) Expand 10 before | Expand all | Expand 10 after
1533 new(Z) StrictCompareInstr( 1579 new(Z) StrictCompareInstr(
1534 call->token_pos(), 1580 call->token_pos(),
1535 negate ? Token::kNE_STRICT : Token::kEQ_STRICT, 1581 negate ? Token::kNE_STRICT : Token::kEQ_STRICT,
1536 new(Z) Value(left_cid), 1582 new(Z) Value(left_cid),
1537 new(Z) Value(cid), 1583 new(Z) Value(cid),
1538 false); // No number check. 1584 false); // No number check.
1539 ReplaceCall(call, check_cid); 1585 ReplaceCall(call, check_cid);
1540 return; 1586 return;
1541 } 1587 }
1542 1588
1589 #ifdef DART_PRECOMPILER
1590 TypeRangeCache* cache = thread()->type_range_cache();
1591 intptr_t lower_limit, upper_limit;
1592 if (cache != NULL &&
1593 cache->InstanceOfHasClassRange(type, &lower_limit, &upper_limit)) {
1594 ReplaceWithClassRangeCheck(call, left, negate, lower_limit, upper_limit);
1595 return;
1596 }
1597 #endif // DART_PRECOMPILER
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,
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 544 matching lines...) Expand 10 before | Expand all | Expand 10 after
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
2141 2310
2142 } // namespace dart 2311 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/vm/aot_optimizer.h ('k') | runtime/vm/compiler.cc » ('j') | runtime/vm/flow_graph.h » ('J')

Powered by Google App Engine
This is Rietveld 408576698