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 396 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
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 Loading... |
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 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, |
| 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 Loading... |
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 |
OLD | NEW |