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/flow_graph_optimizer.h" | 5 #include "vm/flow_graph_optimizer.h" |
6 | 6 |
7 #include "vm/bit_vector.h" | 7 #include "vm/bit_vector.h" |
8 #include "vm/cha.h" | 8 #include "vm/cha.h" |
9 #include "vm/flow_graph_builder.h" | 9 #include "vm/flow_graph_builder.h" |
10 #include "vm/flow_graph_compiler.h" | 10 #include "vm/flow_graph_compiler.h" |
(...skipping 3912 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3923 UNREACHABLE(); | 3923 UNREACHABLE(); |
3924 } | 3924 } |
3925 | 3925 |
3926 | 3926 |
3927 void ConstantPropagator::VisitStoreLocal(StoreLocalInstr* instr) { | 3927 void ConstantPropagator::VisitStoreLocal(StoreLocalInstr* instr) { |
3928 // Instruction is eliminated when translating to SSA. | 3928 // Instruction is eliminated when translating to SSA. |
3929 UNREACHABLE(); | 3929 UNREACHABLE(); |
3930 } | 3930 } |
3931 | 3931 |
3932 | 3932 |
3933 void ConstantPropagator::VisitIfThenElse(IfThenElseInstr* instr) { | |
3934 ASSERT(Token::IsEqualityOperator(instr->kind())); | |
3935 | |
3936 const Object& left = instr->left()->definition()->constant_value(); | |
3937 const Object& right = instr->right()->definition()->constant_value(); | |
3938 | |
3939 if (IsNonConstant(left) || IsNonConstant(right)) { | |
3940 // TODO(vegorov): incorporate nullability information into the lattice. | |
3941 if ((left.IsNull() && instr->right()->Type()->HasDecidableNullability()) || | |
3942 (right.IsNull() && instr->left()->Type()->HasDecidableNullability())) { | |
3943 bool result = left.IsNull() ? instr->right()->Type()->IsNull() | |
3944 : instr->left()->Type()->IsNull(); | |
3945 if (instr->kind() == Token::kNE_STRICT || | |
3946 instr->kind() == Token::kNE) { | |
3947 result = !result; | |
3948 } | |
3949 SetValue(instr, Smi::Handle( | |
3950 Smi::New(result ? instr->if_true() : instr->if_false()))); | |
3951 } else { | |
3952 SetValue(instr, non_constant_); | |
3953 } | |
3954 } else if (IsConstant(left) && IsConstant(right)) { | |
3955 bool result = (left.raw() == right.raw()); | |
srdjan
2013/04/10 21:47:30
Since equality can be overridden, I do not think t
Vyacheslav Egorov (Google)
2013/04/10 21:51:28
Agreed, this is fragile.
The plan is to remove t
| |
3956 if (instr->kind() == Token::kNE_STRICT || | |
3957 instr->kind() == Token::kNE) { | |
3958 result = !result; | |
3959 } | |
3960 SetValue(instr, Smi::Handle( | |
3961 Smi::New(result ? instr->if_true() : instr->if_false()))); | |
3962 } | |
3963 } | |
3964 | |
3965 | |
3933 void ConstantPropagator::VisitStrictCompare(StrictCompareInstr* instr) { | 3966 void ConstantPropagator::VisitStrictCompare(StrictCompareInstr* instr) { |
3934 const Object& left = instr->left()->definition()->constant_value(); | 3967 const Object& left = instr->left()->definition()->constant_value(); |
3935 const Object& right = instr->right()->definition()->constant_value(); | 3968 const Object& right = instr->right()->definition()->constant_value(); |
3936 | 3969 |
3937 if (IsNonConstant(left) || IsNonConstant(right)) { | 3970 if (IsNonConstant(left) || IsNonConstant(right)) { |
3938 // TODO(vegorov): incorporate nullability information into the lattice. | 3971 // TODO(vegorov): incorporate nullability information into the lattice. |
3939 if ((left.IsNull() && instr->right()->Type()->HasDecidableNullability()) || | 3972 if ((left.IsNull() && instr->right()->Type()->HasDecidableNullability()) || |
3940 (right.IsNull() && instr->left()->Type()->HasDecidableNullability())) { | 3973 (right.IsNull() && instr->left()->Type()->HasDecidableNullability())) { |
3941 bool result = left.IsNull() ? instr->right()->Type()->IsNull() | 3974 bool result = left.IsNull() ? instr->right()->Type()->IsNull() |
3942 : instr->left()->Type()->IsNull(); | 3975 : instr->left()->Type()->IsNull(); |
(...skipping 799 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4742 | 4775 |
4743 if (changed) { | 4776 if (changed) { |
4744 // We may have changed the block order and the dominator tree. | 4777 // We may have changed the block order and the dominator tree. |
4745 flow_graph->DiscoverBlocks(); | 4778 flow_graph->DiscoverBlocks(); |
4746 GrowableArray<BitVector*> dominance_frontier; | 4779 GrowableArray<BitVector*> dominance_frontier; |
4747 flow_graph->ComputeDominators(&dominance_frontier); | 4780 flow_graph->ComputeDominators(&dominance_frontier); |
4748 } | 4781 } |
4749 } | 4782 } |
4750 | 4783 |
4751 | 4784 |
4785 static bool IsTrivialBlock(BlockEntryInstr* block, Definition* defn) { | |
4786 return (block->IsTargetEntry() && (block->PredecessorCount() == 1)) && | |
4787 ((block->next() == block->last_instruction()) || | |
4788 ((block->next() == defn) && (defn->next() == block->last_instruction()))); | |
4789 } | |
4790 | |
4791 | |
4792 static void EliminateTrivialBlock(BlockEntryInstr* block, | |
4793 Definition* instr, | |
4794 IfThenElseInstr* before) { | |
4795 block->UnuseAllInputs(); | |
4796 block->last_instruction()->UnuseAllInputs(); | |
4797 | |
4798 if ((block->next() == instr) && | |
4799 (instr->next() == block->last_instruction())) { | |
4800 before->previous()->LinkTo(instr); | |
4801 instr->LinkTo(before); | |
4802 } | |
4803 } | |
4804 | |
4805 | |
4806 void IfConverter::Simplify(FlowGraph* flow_graph) { | |
4807 if (!IfThenElseInstr::IsSupported()) { | |
4808 return; | |
4809 } | |
4810 | |
4811 bool changed = false; | |
4812 | |
4813 const GrowableArray<BlockEntryInstr*>& postorder = flow_graph->postorder(); | |
4814 for (BlockIterator it(postorder); !it.Done(); it.Advance()) { | |
4815 BlockEntryInstr* block = it.Current(); | |
4816 JoinEntryInstr* join = block->AsJoinEntry(); | |
4817 | |
4818 // Detect diamond control flow pattern which materializes a value depending | |
4819 // on the result of the comparison: | |
4820 // | |
4821 // B_pred: | |
4822 // ... | |
4823 // Branch if COMP goto (B_pred1, B_pred2) | |
4824 // B_pred1: -- trivial block that contains at most one definition | |
4825 // v1 = Constant(...) | |
4826 // goto B_block | |
4827 // B_pred2: -- trivial block that contains at most one definition | |
4828 // v2 = Constant(...) | |
4829 // goto B_block | |
4830 // B_block: | |
4831 // v3 = phi(v1, v2) -- single phi | |
4832 // | |
4833 // and replace it with | |
4834 // | |
4835 // Ba: | |
4836 // v3 = IfThenElse(COMP ? v1 : v2) | |
4837 // | |
4838 if ((join != NULL) && | |
4839 (join->phis() != NULL) && | |
4840 (join->phis()->length() == 1) && | |
4841 (block->PredecessorCount() == 2)) { | |
4842 BlockEntryInstr* pred1 = block->PredecessorAt(0); | |
4843 BlockEntryInstr* pred2 = block->PredecessorAt(1); | |
4844 | |
4845 PhiInstr* phi = (*join->phis())[0]; | |
4846 Value* v1 = phi->InputAt(0); | |
4847 Value* v2 = phi->InputAt(1); | |
4848 | |
4849 if (IsTrivialBlock(pred1, v1->definition()) && | |
4850 IsTrivialBlock(pred2, v2->definition()) && | |
4851 (pred1->PredecessorAt(0) == pred2->PredecessorAt(0))) { | |
4852 BlockEntryInstr* pred = pred1->PredecessorAt(0); | |
4853 BranchInstr* branch = pred->last_instruction()->AsBranch(); | |
4854 ComparisonInstr* comparison = branch->comparison(); | |
4855 | |
4856 // Check if the platform supports efficient branchless IfThenElseInstr | |
4857 // for the given combination of comparison and values flowing from | |
4858 // false and true paths. | |
4859 if (IfThenElseInstr::Supports(comparison, v1, v2)) { | |
4860 Value* if_true = (pred1 == branch->true_successor()) ? v1 : v2; | |
4861 Value* if_false = (pred2 == branch->true_successor()) ? v1 : v2; | |
4862 | |
4863 IfThenElseInstr* if_then_else = new IfThenElseInstr( | |
4864 comparison->kind(), | |
4865 comparison->InputAt(0)->Copy(), | |
4866 comparison->InputAt(1)->Copy(), | |
4867 if_true->Copy(), | |
4868 if_false->Copy()); | |
4869 flow_graph->InsertBefore(branch, | |
4870 if_then_else, | |
4871 NULL, | |
4872 Definition::kValue); | |
4873 | |
4874 phi->ReplaceUsesWith(if_then_else); | |
4875 | |
4876 // Connect IfThenElseInstr to the first instruction in the merge block | |
4877 // effectively eliminating diamond control flow. | |
4878 // Current block as well as pred1 and pred2 blocks are no longer in | |
4879 // the graph at this point. | |
4880 if_then_else->LinkTo(join->next()); | |
4881 pred->set_last_instruction(join->last_instruction()); | |
4882 | |
4883 // Resulting block must inherit block id from the eliminated current | |
4884 // block to guarantee that ordering of phi operands in its successor | |
4885 // stays consistent. | |
4886 pred->set_block_id(block->block_id()); | |
4887 | |
4888 // If v1 and v2 were defined inside eliminated blocks pred1/pred2 | |
4889 // move them out to the place before inserted IfThenElse instruction. | |
4890 EliminateTrivialBlock(pred1, v1->definition(), if_then_else); | |
4891 EliminateTrivialBlock(pred2, v2->definition(), if_then_else); | |
4892 | |
4893 // Update use lists to reflect changes in the graph. | |
4894 phi->UnuseAllInputs(); | |
4895 branch->UnuseAllInputs(); | |
4896 | |
4897 // The graph has changed. Recompute dominators and block orders after | |
4898 // this pass is finished. | |
4899 changed = true; | |
4900 } | |
4901 } | |
4902 } | |
4903 } | |
4904 | |
4905 if (changed) { | |
4906 // We may have changed the block order and the dominator tree. | |
4907 flow_graph->DiscoverBlocks(); | |
4908 GrowableArray<BitVector*> dominance_frontier; | |
4909 flow_graph->ComputeDominators(&dominance_frontier); | |
4910 } | |
4911 } | |
4912 | |
4913 | |
4752 } // namespace dart | 4914 } // namespace dart |
OLD | NEW |