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 |