Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 |
| OLD | NEW |