| OLD | NEW |
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, 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 library dart2js.cps_ir.let_sinking; | 5 library dart2js.cps_ir.let_sinking; |
| 6 | 6 |
| 7 import 'cps_ir_nodes.dart'; | 7 import 'cps_ir_nodes.dart'; |
| 8 import 'optimizers.dart'; | 8 import 'optimizers.dart'; |
| 9 | 9 |
| 10 /// Sinks single-use primitives to the use when this is safe and profitable. | 10 /// Sinks single-use primitives to the use when this is safe and profitable. |
| (...skipping 12 matching lines...) Expand all Loading... |
| 23 /// InvokeContinuation kont x' | 23 /// InvokeContinuation kont x' |
| 24 /// else | 24 /// else |
| 25 /// <after loop> | 25 /// <after loop> |
| 26 /// return p.foo() | 26 /// return p.foo() |
| 27 /// | 27 /// |
| 28 class LetSinker extends RecursiveVisitor implements Pass { | 28 class LetSinker extends RecursiveVisitor implements Pass { |
| 29 String get passName => 'Let sinking'; | 29 String get passName => 'Let sinking'; |
| 30 | 30 |
| 31 LoopHierarchy loopHierarchy; | 31 LoopHierarchy loopHierarchy; |
| 32 List<Continuation> stack = <Continuation>[]; | 32 List<Continuation> stack = <Continuation>[]; |
| 33 Set<LetPrim> sunkNodes = new Set<LetPrim>(); | 33 |
| 34 /// Maps a sinkable primitive to its loop header. |
| 35 Map<Primitive, Continuation> loopHeaderForPrimitive = |
| 36 <Primitive, Continuation>{}; |
| 37 |
| 38 Continuation currentLoopHeader; |
| 34 | 39 |
| 35 void rewrite(FunctionDefinition node) { | 40 void rewrite(FunctionDefinition node) { |
| 36 new ParentVisitor().visit(node); | 41 new ParentVisitor().visit(node); |
| 37 loopHierarchy = new LoopHierarchy(node); | 42 loopHierarchy = new LoopHierarchy(node); |
| 38 visit(node.body); | 43 visit(node.body); |
| 39 } | 44 } |
| 40 | 45 |
| 41 @override | 46 @override |
| 42 Expression traverseLetPrim(LetPrim node) { | 47 Expression traverseLetPrim(LetPrim node) { |
| 43 pushAction(() { | 48 Primitive prim = node.primitive; |
| 44 if (node.primitive != null) { | 49 if (prim.hasExactlyOneUse && prim.isSafeForReordering) { |
| 45 // The primitive could not be sunk. Sink dependencies to this location. | 50 // This can potentially be sunk. Register the loop header, so when we |
| 46 visit(node.primitive); | 51 // find the use site, we can check if they are in the same loop. |
| 47 } else { | 52 loopHeaderForPrimitive[prim] = currentLoopHeader; |
| 48 // The primitive was sunk. Destroy the old LetPrim. | 53 pushAction(() { |
| 49 InteriorNode parent = node.parent; | 54 if (node.primitive != null) { |
| 50 parent.body = node.body; | 55 // The primitive could not be sunk. Try to sink dependencies here. |
| 51 node.body.parent = parent; | 56 visit(node.primitive); |
| 52 } | 57 } else { |
| 53 }); | 58 // The primitive was sunk. Destroy the old LetPrim. |
| 59 InteriorNode parent = node.parent; |
| 60 parent.body = node.body; |
| 61 node.body.parent = parent; |
| 62 } |
| 63 }); |
| 64 } else { |
| 65 visit(node.primitive); |
| 66 } |
| 54 | 67 |
| 55 // Visit the body, wherein this primitive may be sunk to its use site. | 68 // Visit the body, wherein this primitive may be sunk to its use site. |
| 56 return node.body; | 69 return node.body; |
| 57 } | 70 } |
| 58 | 71 |
| 72 @override |
| 73 Expression traverseContinuation(Continuation cont) { |
| 74 Continuation oldLoopHeader = currentLoopHeader; |
| 75 pushAction(() { |
| 76 currentLoopHeader = oldLoopHeader; |
| 77 }); |
| 78 currentLoopHeader = loopHierarchy.getLoopHeader(cont); |
| 79 return cont.body; |
| 80 } |
| 81 |
| 59 void processReference(Reference ref) { | 82 void processReference(Reference ref) { |
| 60 Definition definition = ref.definition; | 83 Definition definition = ref.definition; |
| 61 if (definition is Primitive && | 84 if (definition is Primitive && |
| 62 definition is! Parameter && | 85 definition is! Parameter && |
| 63 definition.hasExactlyOneUse && | 86 definition.hasExactlyOneUse && |
| 64 definition.isSafeForReordering) { | 87 definition.isSafeForReordering) { |
| 65 // Check if use is in the same loop. | 88 // Check if use is in the same loop. |
| 66 LetPrim binding = definition.parent; | 89 Continuation bindingLoop = loopHeaderForPrimitive.remove(definition); |
| 67 Continuation bindingLoop = loopHierarchy.getLoopHeader(binding); | 90 if (bindingLoop == currentLoopHeader || definition is Constant) { |
| 68 Expression use = getEnclosingExpression(ref.parent); | |
| 69 Continuation useLoop = loopHierarchy.getLoopHeader(use); | |
| 70 if (bindingLoop == useLoop || definition is Constant) { | |
| 71 // Sink the definition. | 91 // Sink the definition. |
| 72 | 92 |
| 93 Expression use = getEnclosingExpression(ref.parent); |
| 94 LetPrim binding = definition.parent; |
| 73 binding.primitive = null; // Mark old binding for deletion. | 95 binding.primitive = null; // Mark old binding for deletion. |
| 74 LetPrim newBinding = new LetPrim(definition); | 96 LetPrim newBinding = new LetPrim(definition); |
| 75 definition.parent = newBinding; | 97 definition.parent = newBinding; |
| 76 InteriorNode useParent = use.parent; | 98 InteriorNode useParent = use.parent; |
| 77 useParent.body = newBinding; | 99 useParent.body = newBinding; |
| 78 newBinding.body = use; | 100 newBinding.body = use; |
| 79 use.parent = newBinding; | 101 use.parent = newBinding; |
| 80 newBinding.parent = useParent; | 102 newBinding.parent = useParent; |
| 81 | 103 |
| 82 // Now that the final binding location has been found, sink the | 104 // Now that the final binding location has been found, sink the |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 123 /// Current nesting depth. | 145 /// Current nesting depth. |
| 124 int currentDepth = 0; | 146 int currentDepth = 0; |
| 125 | 147 |
| 126 /// Computes the loop hierarchy for the given function. | 148 /// Computes the loop hierarchy for the given function. |
| 127 /// | 149 /// |
| 128 /// Parent pointers must be computed for [node]. | 150 /// Parent pointers must be computed for [node]. |
| 129 LoopHierarchy(FunctionDefinition node) { | 151 LoopHierarchy(FunctionDefinition node) { |
| 130 _processBlock(node.body, null); | 152 _processBlock(node.body, null); |
| 131 } | 153 } |
| 132 | 154 |
| 133 /// Returns the innermost loop which [node] is effectively part of. | 155 /// Returns the innermost loop which [cont] is effectively part of. |
| 134 Continuation getLoopHeader(Expression exp) { | 156 Continuation getLoopHeader(Continuation cont) { |
| 135 Node node = exp.parent; | 157 return cont.isRecursive ? cont : loopTarget[cont]; |
| 136 while (node != null && node is! Continuation) { | |
| 137 node = node.parent; | |
| 138 } | |
| 139 if (node is Continuation) { | |
| 140 if (node.isRecursive) { | |
| 141 return node; | |
| 142 } else { | |
| 143 return loopTarget[node]; | |
| 144 } | |
| 145 } | |
| 146 return null; | |
| 147 } | 158 } |
| 148 | 159 |
| 149 /// Marks the innermost loop as a subloop of the other loop. | 160 /// Marks the innermost loop as a subloop of the other loop. |
| 150 /// | 161 /// |
| 151 /// Returns the innermost loop. | 162 /// Returns the innermost loop. |
| 152 /// | 163 /// |
| 153 /// Both continuations, [c1] and [c2] may be null (i.e. no loop). | 164 /// Both continuations, [c1] and [c2] may be null (i.e. no loop). |
| 154 /// | 165 /// |
| 155 /// A loop is said to be a subloop of an enclosing loop if it can invoke | 166 /// A loop is said to be a subloop of an enclosing loop if it can invoke |
| 156 /// that loop recursively. This information is stored in [loopTarget]. | 167 /// that loop recursively. This information is stored in [loopTarget]. |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 237 target = _markInnerLoop(target, catchLoop); | 248 target = _markInnerLoop(target, catchLoop); |
| 238 for (Continuation cont in callContinuations) { | 249 for (Continuation cont in callContinuations) { |
| 239 // Store the loop target on each call continuation in the basic block. | 250 // Store the loop target on each call continuation in the basic block. |
| 240 // Because we walk over call continuations as part of the basic block | 251 // Because we walk over call continuations as part of the basic block |
| 241 // traversal, these do not get their loop target set otherwise. | 252 // traversal, these do not get their loop target set otherwise. |
| 242 loopTarget[cont] = target; | 253 loopTarget[cont] = target; |
| 243 } | 254 } |
| 244 return target; | 255 return target; |
| 245 } | 256 } |
| 246 } | 257 } |
| OLD | NEW |