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

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

Issue 2955073005: VM-codegen: Add IL instruction to check if a Smi is in a constant range
Patch Set: Remove unrelated change and other Slava feedback Created 3 years, 5 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
« no previous file with comments | « runtime/vm/constant_propagator.cc ('k') | runtime/vm/flow_graph_type_propagator.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 #if !defined(DART_PRECOMPILED_RUNTIME) 4 #if !defined(DART_PRECOMPILED_RUNTIME)
5 #include "vm/flow_graph_inliner.h" 5 #include "vm/flow_graph_inliner.h"
6 6
7 #include "vm/aot_optimizer.h" 7 #include "vm/aot_optimizer.h"
8 #include "vm/precompiler.h" 8 #include "vm/precompiler.h"
9 #include "vm/block_scheduler.h" 9 #include "vm/block_scheduler.h"
10 #include "vm/branch_optimizer.h" 10 #include "vm/branch_optimizer.h"
(...skipping 1654 matching lines...) Expand 10 before | Expand all | Expand 10 after
1665 1665
1666 Definition* receiver = call_->ArgumentAt(0); 1666 Definition* receiver = call_->ArgumentAt(0);
1667 // There are at least two variants including non-inlined ones, so we have 1667 // There are at least two variants including non-inlined ones, so we have
1668 // at least one branch on the class id. 1668 // at least one branch on the class id.
1669 LoadClassIdInstr* load_cid = 1669 LoadClassIdInstr* load_cid =
1670 new (Z) LoadClassIdInstr(new (Z) Value(receiver)); 1670 new (Z) LoadClassIdInstr(new (Z) Value(receiver));
1671 load_cid->set_ssa_temp_index(owner_->caller_graph()->alloc_ssa_temp_index()); 1671 load_cid->set_ssa_temp_index(owner_->caller_graph()->alloc_ssa_temp_index());
1672 cursor = AppendInstruction(cursor, load_cid); 1672 cursor = AppendInstruction(cursor, load_cid);
1673 for (intptr_t i = 0; i < inlined_variants_.length(); ++i) { 1673 for (intptr_t i = 0; i < inlined_variants_.length(); ++i) {
1674 const CidRange& variant = inlined_variants_[i]; 1674 const CidRange& variant = inlined_variants_[i];
1675 bool test_is_range = !variant.IsSingleCid();
1676 bool is_last_test = (i == inlined_variants_.length() - 1); 1675 bool is_last_test = (i == inlined_variants_.length() - 1);
1677 // 1. Guard the body with a class id check. We don't need any check if 1676 // 1. Guard the body with a class id check. We don't need any check if
1678 // it's the last test and global analysis has told us that the call is 1677 // it's the last test and global analysis has told us that the call is
1679 // complete. 1678 // complete.
1680 if (is_last_test && non_inlined_variants_->is_empty()) { 1679 if (is_last_test && non_inlined_variants_->is_empty()) {
1681 // If it is the last variant use a check class id instruction which can 1680 // If it is the last variant use a check class id instruction which can
1682 // deoptimize, followed unconditionally by the body. Omit the check if 1681 // deoptimize, followed unconditionally by the body. Omit the check if
1683 // we know that we have covered all possible classes. 1682 // we know that we have covered all possible classes.
1684 if (!call_->complete()) { 1683 if (!call_->complete()) {
1685 RedefinitionInstr* cid_redefinition = 1684 RedefinitionInstr* cid_redefinition =
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
1725 current_block->set_last_instruction(goto_join); 1724 current_block->set_last_instruction(goto_join);
1726 } else { 1725 } else {
1727 // There is no possibility of a TargetEntry (the first entry to a 1726 // There is no possibility of a TargetEntry (the first entry to a
1728 // shared inlined body) because this is the last inlined entry. 1727 // shared inlined body) because this is the last inlined entry.
1729 UNREACHABLE(); 1728 UNREACHABLE();
1730 } 1729 }
1731 cursor = NULL; 1730 cursor = NULL;
1732 } else { 1731 } else {
1733 // For all variants except the last, use a branch on the loaded class 1732 // For all variants except the last, use a branch on the loaded class
1734 // id. 1733 // id.
1735 const Smi& cid = Smi::ZoneHandle(Smi::New(variant.cid_start)); 1734 ComparisonInstr* compare;
1736 ConstantInstr* cid_constant = owner_->caller_graph()->GetConstant(cid);
1737 BranchInstr* branch;
1738 BranchInstr* upper_limit_branch = NULL;
1739 BlockEntryInstr* cid_test_entry_block = current_block; 1735 BlockEntryInstr* cid_test_entry_block = current_block;
1740 if (test_is_range) { 1736 if (variant.IsSingleCid()) {
1741 // Double branch for testing a range of Cids. TODO(erikcorry): Make a 1737 const Smi& cid = Smi::ZoneHandle(Smi::New(variant.cid_start));
1742 // special instruction that uses subtraction and unsigned comparison to 1738 ConstantInstr* cid_constant = owner_->caller_graph()->GetConstant(cid);
1743 // do this with a single branch. 1739 compare = new StrictCompareInstr(
1744 const Smi& cid_end = Smi::ZoneHandle(Smi::New(variant.cid_end));
1745 ConstantInstr* cid_constant_end =
1746 owner_->caller_graph()->GetConstant(cid_end);
1747 RelationalOpInstr* compare_top = new RelationalOpInstr(
1748 call_->instance_call()->token_pos(), Token::kLTE,
1749 new Value(load_cid), new Value(cid_constant_end), kSmiCid,
1750 call_->deopt_id());
1751 BranchInstr* branch_top = upper_limit_branch =
1752 new BranchInstr(compare_top, Thread::kNoDeoptId);
1753 branch_top->InheritDeoptTarget(zone(), call_);
1754 cursor = AppendInstruction(cursor, branch_top);
1755 current_block->set_last_instruction(branch_top);
1756
1757 TargetEntryInstr* below_target = new TargetEntryInstr(
1758 AllocateBlockId(), try_idx, Thread::kNoDeoptId);
1759 below_target->InheritDeoptTarget(zone(), call_);
1760 current_block->AddDominatedBlock(below_target);
1761 cursor = current_block = below_target;
1762 *branch_top->true_successor_address() = below_target;
1763
1764 RelationalOpInstr* compare_bottom = new RelationalOpInstr(
1765 call_->instance_call()->token_pos(), Token::kGTE,
1766 new Value(load_cid), new Value(cid_constant), kSmiCid,
1767 call_->deopt_id());
1768 branch = new BranchInstr(compare_bottom, Thread::kNoDeoptId);
1769 } else {
1770 StrictCompareInstr* compare = new StrictCompareInstr(
1771 call_->instance_call()->token_pos(), Token::kEQ_STRICT, 1740 call_->instance_call()->token_pos(), Token::kEQ_STRICT,
1772 new Value(load_cid), new Value(cid_constant), 1741 new Value(load_cid), new Value(cid_constant),
1773 /* number_check = */ false, Thread::kNoDeoptId); 1742 /* number_check = */ false, Thread::kNoDeoptId);
1774 branch = new BranchInstr(compare, Thread::kNoDeoptId); 1743 } else {
1744 compare = new SmiRangeComparisonInstr(
1745 call_->instance_call()->token_pos(), new Value(load_cid),
1746 variant.cid_start, variant.cid_end);
1775 } 1747 }
1748 BranchInstr* branch = new BranchInstr(compare, Thread::kNoDeoptId);
1776 1749
1777 branch->InheritDeoptTarget(zone(), call_); 1750 branch->InheritDeoptTarget(zone(), call_);
1778 cursor = AppendInstruction(cursor, branch); 1751 cursor = AppendInstruction(cursor, branch);
1779 current_block->set_last_instruction(branch); 1752 current_block->set_last_instruction(branch);
1780 cursor = NULL; 1753 cursor = NULL;
1781 1754
1782 // 2. Handle a match by linking to the inlined body. There are three 1755 // 2. Handle a match by linking to the inlined body. There are three
1783 // cases (unshared, shared first predecessor, and shared subsequent 1756 // cases (unshared, shared first predecessor, and shared subsequent
1784 // predecessors). 1757 // predecessors).
1785 BlockEntryInstr* callee_entry = inlined_entries_[i]; 1758 BlockEntryInstr* callee_entry = inlined_entries_[i];
(...skipping 30 matching lines...) Expand all
1816 // 3. Prepare to handle a match failure on the next iteration or the 1789 // 3. Prepare to handle a match failure on the next iteration or the
1817 // fall-through code below for non-inlined variants. 1790 // fall-through code below for non-inlined variants.
1818 1791
1819 TargetEntryInstr* false_target = 1792 TargetEntryInstr* false_target =
1820 new TargetEntryInstr(AllocateBlockId(), try_idx, Thread::kNoDeoptId); 1793 new TargetEntryInstr(AllocateBlockId(), try_idx, Thread::kNoDeoptId);
1821 false_target->InheritDeoptTarget(zone(), call_); 1794 false_target->InheritDeoptTarget(zone(), call_);
1822 *branch->false_successor_address() = false_target; 1795 *branch->false_successor_address() = false_target;
1823 cid_test_entry_block->AddDominatedBlock(false_target); 1796 cid_test_entry_block->AddDominatedBlock(false_target);
1824 1797
1825 cursor = current_block = false_target; 1798 cursor = current_block = false_target;
1826
1827 if (test_is_range) {
1828 // If we tested against a range of Cids there are two different tests
1829 // that can go to the no-cid-match target.
1830 JoinEntryInstr* join =
1831 new JoinEntryInstr(AllocateBlockId(), try_idx, Thread::kNoDeoptId);
1832 TargetEntryInstr* false_target2 = new TargetEntryInstr(
1833 AllocateBlockId(), try_idx, Thread::kNoDeoptId);
1834 *upper_limit_branch->false_successor_address() = false_target2;
1835 cid_test_entry_block->AddDominatedBlock(false_target2);
1836 cid_test_entry_block->AddDominatedBlock(join);
1837 GotoInstr* goto_1 = new GotoInstr(join, Thread::kNoDeoptId);
1838 GotoInstr* goto_2 = new GotoInstr(join, Thread::kNoDeoptId);
1839 false_target->LinkTo(goto_1);
1840 false_target2->LinkTo(goto_2);
1841 false_target->set_last_instruction(goto_1);
1842 false_target2->set_last_instruction(goto_2);
1843
1844 join->InheritDeoptTarget(zone(), call_);
1845 false_target2->InheritDeoptTarget(zone(), call_);
1846 goto_1->InheritDeoptTarget(zone(), call_);
1847 goto_2->InheritDeoptTarget(zone(), call_);
1848
1849 cursor = current_block = join;
1850 }
1851 } 1799 }
1852 } 1800 }
1853 1801
1854 // Handle any non-inlined variants. 1802 // Handle any non-inlined variants.
1855 if (!non_inlined_variants_->is_empty()) { 1803 if (!non_inlined_variants_->is_empty()) {
1856 // Move push arguments of the call. 1804 // Move push arguments of the call.
1857 for (intptr_t i = 0; i < call_->ArgumentCount(); ++i) { 1805 for (intptr_t i = 0; i < call_->ArgumentCount(); ++i) {
1858 PushArgumentInstr* push = call_->PushArgumentAt(i); 1806 PushArgumentInstr* push = call_->PushArgumentAt(i);
1859 push->ReplaceUsesWith(push->value()->definition()); 1807 push->ReplaceUsesWith(push->value()->definition());
1860 push->previous()->LinkTo(push->next()); 1808 push->previous()->LinkTo(push->next());
(...skipping 1906 matching lines...) Expand 10 before | Expand all | Expand 10 after
3767 } 3715 }
3768 3716
3769 default: 3717 default:
3770 return false; 3718 return false;
3771 } 3719 }
3772 } 3720 }
3773 3721
3774 3722
3775 } // namespace dart 3723 } // namespace dart
3776 #endif // !defined(DART_PRECOMPILED_RUNTIME) 3724 #endif // !defined(DART_PRECOMPILED_RUNTIME)
OLDNEW
« no previous file with comments | « runtime/vm/constant_propagator.cc ('k') | runtime/vm/flow_graph_type_propagator.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698