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

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

Issue 14057004: Convert diamond shaped control flow into a single conditional instruction. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 8 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 | Annotate | Revision Log
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 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
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 const Object& left = instr->left()->definition()->constant_value();
3935 const Object& right = instr->right()->definition()->constant_value();
3936
3937 if (IsNonConstant(left) || IsNonConstant(right)) {
3938 // TODO(vegorov): incorporate nullability information into the lattice.
Florian Schneider 2013/04/10 13:59:50 Maybe check Token::IsEqualityOperator(kind()) even
Vyacheslav Egorov (Google) 2013/04/10 14:51:32 Done.
3939 if ((left.IsNull() && instr->right()->Type()->HasDecidableNullability()) ||
3940 (right.IsNull() && instr->left()->Type()->HasDecidableNullability())) {
3941 bool result = left.IsNull() ? instr->right()->Type()->IsNull()
3942 : instr->left()->Type()->IsNull();
3943 if (instr->kind() == Token::kNE_STRICT ||
3944 instr->kind() == Token::kNE) {
3945 result = !result;
3946 }
3947 SetValue(instr, Smi::Handle(
3948 Smi::New(result ? instr->if_true() : instr->if_false())));
3949 } else {
3950 SetValue(instr, non_constant_);
3951 }
3952 } else if (IsConstant(left) && IsConstant(right)) {
3953 bool result = (left.raw() == right.raw());
3954 if (instr->kind() == Token::kNE_STRICT ||
3955 instr->kind() == Token::kNE) {
3956 result = !result;
3957 }
3958 SetValue(instr, Smi::Handle(
3959 Smi::New(result ? instr->if_true() : instr->if_false())));
3960 }
3961 }
3962
3963
3933 void ConstantPropagator::VisitStrictCompare(StrictCompareInstr* instr) { 3964 void ConstantPropagator::VisitStrictCompare(StrictCompareInstr* instr) {
3934 const Object& left = instr->left()->definition()->constant_value(); 3965 const Object& left = instr->left()->definition()->constant_value();
3935 const Object& right = instr->right()->definition()->constant_value(); 3966 const Object& right = instr->right()->definition()->constant_value();
3936 3967
3937 if (IsNonConstant(left) || IsNonConstant(right)) { 3968 if (IsNonConstant(left) || IsNonConstant(right)) {
3938 // TODO(vegorov): incorporate nullability information into the lattice. 3969 // TODO(vegorov): incorporate nullability information into the lattice.
3939 if ((left.IsNull() && instr->right()->Type()->HasDecidableNullability()) || 3970 if ((left.IsNull() && instr->right()->Type()->HasDecidableNullability()) ||
3940 (right.IsNull() && instr->left()->Type()->HasDecidableNullability())) { 3971 (right.IsNull() && instr->left()->Type()->HasDecidableNullability())) {
3941 bool result = left.IsNull() ? instr->right()->Type()->IsNull() 3972 bool result = left.IsNull() ? instr->right()->Type()->IsNull()
3942 : instr->left()->Type()->IsNull(); 3973 : instr->left()->Type()->IsNull();
(...skipping 799 matching lines...) Expand 10 before | Expand all | Expand 10 after
4742 4773
4743 if (changed) { 4774 if (changed) {
4744 // We may have changed the block order and the dominator tree. 4775 // We may have changed the block order and the dominator tree.
4745 flow_graph->DiscoverBlocks(); 4776 flow_graph->DiscoverBlocks();
4746 GrowableArray<BitVector*> dominance_frontier; 4777 GrowableArray<BitVector*> dominance_frontier;
4747 flow_graph->ComputeDominators(&dominance_frontier); 4778 flow_graph->ComputeDominators(&dominance_frontier);
4748 } 4779 }
4749 } 4780 }
4750 4781
4751 4782
4783 static bool IsTrivialBlock(BlockEntryInstr* block, Definition* defn) {
4784 return (block->IsTargetEntry() && (block->PredecessorCount() == 1)) &&
4785 ((block->next() == block->last_instruction()) ||
4786 ((block->next() == defn) && (defn->next() == block->last_instruction())));
4787 }
4788
4789
4790 static void EliminateTrivialBlock(BlockEntryInstr* block,
4791 Definition* instr,
4792 IfThenElseInstr* before) {
4793 block->UnuseAllInputs();
4794 block->last_instruction()->UnuseAllInputs();
4795
4796 if ((block->next() == instr) &&
4797 (instr->next() == block->last_instruction())) {
4798 before->previous()->LinkTo(instr);
4799 instr->LinkTo(before);
4800 }
4801 }
4802
4803
4804 void IfConverter::Simplify(FlowGraph* flow_graph) {
4805 if (!IfThenElseInstr::IsSupported()) {
4806 return;
4807 }
4808
4809 bool changed = false;
4810
4811 const GrowableArray<BlockEntryInstr*>& postorder = flow_graph->postorder();
4812 for (BlockIterator it(postorder); !it.Done(); it.Advance()) {
4813 BlockEntryInstr* block = it.Current();
4814 JoinEntryInstr* join = block->AsJoinEntry();
4815
4816 // Detect diamond control flow pattern which materializes a value depending
4817 // on the result of the comparison:
4818 //
4819 // Ba:
4820 // ...
4821 // Branch if COMP goto (Bb, Bc)
4822 // Bb: -- trivial block that contains at most one definition
4823 // c1 = Constant(...)
4824 // goto Bd
4825 // Bc: -- trivial block that contains at most one definition
4826 // c2 = Constant(...)
4827 // goto Bd
4828 // Bd:
4829 // v = phi(c1, c2) -- single phi
4830 //
4831 // and replace it with
4832 //
4833 // Ba:
4834 // v = IfThenElse(COMP ? c1 : c2)
4835 //
4836 if ((join != NULL) &&
4837 (join->phis() != NULL) &&
4838 (join->phis()->length() == 1) &&
4839 (block->PredecessorCount() == 2)) {
4840 BlockEntryInstr* pred1 = block->PredecessorAt(0);
Florian Schneider 2013/04/10 13:59:50 Why not use the same names as in the comments for
Vyacheslav Egorov (Google) 2013/04/10 14:51:32 Changed names in the comment to reflect naming in
4841 BlockEntryInstr* pred2 = block->PredecessorAt(1);
4842
4843 PhiInstr* phi = (*join->phis())[0];
4844 Value* v1 = phi->InputAt(0);
4845 Value* v2 = phi->InputAt(1);
4846
4847 if (IsTrivialBlock(pred1, v1->definition()) &&
4848 IsTrivialBlock(pred2, v2->definition()) &&
4849 (pred1->PredecessorAt(0) == pred2->PredecessorAt(0))) {
4850 BlockEntryInstr* pred = pred1->PredecessorAt(0);
4851 BranchInstr* branch = pred->last_instruction()->AsBranch();
4852 ComparisonInstr* comparison = branch->comparison();
4853
4854 // Check if the platform supports efficient branchless IfThenElseInstr
4855 // for the given combination of comparison and values flowing from
4856 // false and true paths.
4857 if (IfThenElseInstr::Supports(comparison, v1, v2)) {
Florian Schneider 2013/04/10 13:59:50 I think the code becomes simpler with an early ret
Vyacheslav Egorov (Google) 2013/04/10 14:51:32 Can't use early return (there is a loop around thi
4858 Value* if_true = (pred1 == branch->true_successor()) ? v1 : v2;
4859 Value* if_false = (pred2 == branch->true_successor()) ? v1 : v2;
4860
4861 IfThenElseInstr* if_then_else = new IfThenElseInstr(
4862 comparison->kind(),
4863 comparison->InputAt(0)->Copy(),
4864 comparison->InputAt(1)->Copy(),
4865 if_true->Copy(),
4866 if_false->Copy());
4867 flow_graph->InsertBefore(branch,
4868 if_then_else,
4869 NULL,
4870 Definition::kValue);
4871
4872 phi->ReplaceUsesWith(if_then_else);
4873
4874 // Connect IfThenElseInstr to the first instruction in the merge block
4875 // effectively eliminating diamond control flow.
4876 // Current block as well as pred1 and pred2 blocks are no longer in
4877 // the graph at this point.
4878 if_then_else->LinkTo(join->next());
4879 pred->set_last_instruction(join->last_instruction());
4880
4881 // Resulting block must inherit block id from the eliminated current
4882 // block to guarantee that ordering of phi operands in its successor
4883 // stays consistent.
4884 pred->set_block_id(block->block_id());
4885
4886 // If v1 and v2 were defined inside eliminated blocks pred1/pred2
4887 // move them out to the place before inserted IfThenElse instruction.
4888 EliminateTrivialBlock(pred1, v1->definition(), if_then_else);
4889 EliminateTrivialBlock(pred2, v2->definition(), if_then_else);
4890
4891 // Update use lists to reflect changes in the graph.
4892 phi->UnuseAllInputs();
4893 branch->UnuseAllInputs();
4894
4895 // The graph has changed. Recompute dominators and block orders after
4896 // this pass is finished.
4897 changed = true;
4898 }
4899 }
4900 }
4901 }
4902
4903 if (changed) {
4904 // We may have changed the block order and the dominator tree.
4905 flow_graph->DiscoverBlocks();
4906 GrowableArray<BitVector*> dominance_frontier;
4907 flow_graph->ComputeDominators(&dominance_frontier);
4908 }
4909 }
4910
4911
4752 } // namespace dart 4912 } // namespace dart
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698