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/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 |