| OLD | NEW |
| (Empty) |
| 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 | |
| 3 // BSD-style license that can be found in the LICENSE file. | |
| 4 | |
| 5 library dart2js.cps_ir.loop_invariant_code_motion; | |
| 6 | |
| 7 import 'optimizers.dart'; | |
| 8 import 'cps_ir_nodes.dart'; | |
| 9 import 'loop_hierarchy.dart'; | |
| 10 | |
| 11 /// Lifts primitives out of loops when it is safe and profitable. | |
| 12 /// | |
| 13 /// Currently we only do this for interceptors. | |
| 14 class LoopInvariantCodeMotion extends RecursiveVisitor implements Pass { | |
| 15 String get passName => 'Loop-invariant code motion'; | |
| 16 | |
| 17 final Map<Primitive, Continuation> primitiveLoop = | |
| 18 <Primitive, Continuation>{}; | |
| 19 | |
| 20 LoopHierarchy loopHierarchy; | |
| 21 Continuation currentLoopHeader; | |
| 22 | |
| 23 /// When processing the dependencies of a primitive, [referencedLoop] | |
| 24 /// refers to the innermost loop that contains one of the dependencies | |
| 25 /// seen so far (or `null` if none of the dependencies are bound in a loop). | |
| 26 /// | |
| 27 /// This is used to determine how far the primitive can be lifted without | |
| 28 /// falling out of scope of its dependencies. | |
| 29 Continuation referencedLoop; | |
| 30 | |
| 31 void rewrite(FunctionDefinition node) { | |
| 32 loopHierarchy = new LoopHierarchy(node); | |
| 33 visit(node.body); | |
| 34 } | |
| 35 | |
| 36 @override | |
| 37 Expression traverseContinuation(Continuation cont) { | |
| 38 Continuation oldLoopHeader = currentLoopHeader; | |
| 39 pushAction(() { | |
| 40 currentLoopHeader = oldLoopHeader; | |
| 41 }); | |
| 42 currentLoopHeader = loopHierarchy.getLoopHeader(cont); | |
| 43 for (Parameter param in cont.parameters) { | |
| 44 primitiveLoop[param] = currentLoopHeader; | |
| 45 } | |
| 46 return cont.body; | |
| 47 } | |
| 48 | |
| 49 @override | |
| 50 Expression traverseLetPrim(LetPrim node) { | |
| 51 primitiveLoop[node.primitive] = currentLoopHeader; | |
| 52 if (!shouldLift(node.primitive)) { | |
| 53 return node.body; | |
| 54 } | |
| 55 referencedLoop = null; | |
| 56 visit(node.primitive); // Sets referencedLoop. | |
| 57 Expression next = node.body; | |
| 58 if (referencedLoop != currentLoopHeader) { | |
| 59 // Bind the primitive inside [referencedLoop] (possibly null), | |
| 60 // immediately before the binding of the inner loop. | |
| 61 | |
| 62 // Find the inner loop. | |
| 63 Continuation loop = currentLoopHeader; | |
| 64 Continuation enclosing = loopHierarchy.getEnclosingLoop(loop); | |
| 65 while (enclosing != referencedLoop) { | |
| 66 assert(loop != null); | |
| 67 loop = enclosing; | |
| 68 enclosing = loopHierarchy.getEnclosingLoop(loop); | |
| 69 } | |
| 70 assert(loop != null); | |
| 71 | |
| 72 // Remove LetPrim from its current position. | |
| 73 node.parent.body = node.body; | |
| 74 node.body.parent = node.parent; | |
| 75 | |
| 76 // Insert the LetPrim immediately before the loop. | |
| 77 LetCont loopBinding = loop.parent; | |
| 78 InteriorNode newParent = loopBinding.parent; | |
| 79 newParent.body = node; | |
| 80 node.body = loopBinding; | |
| 81 loopBinding.parent = node; | |
| 82 node.parent = newParent; | |
| 83 | |
| 84 // A different loop now contains the primitive. | |
| 85 primitiveLoop[node.primitive] = enclosing; | |
| 86 } | |
| 87 return next; | |
| 88 } | |
| 89 | |
| 90 /// Returns the the innermost loop that effectively encloses both | |
| 91 /// c1 and c2 (or `null` if there is no such loop). | |
| 92 Continuation leastCommonAncestor(Continuation c1, Continuation c2) { | |
| 93 int d1 = getDepth(c1), d2 = getDepth(c2); | |
| 94 while (c1 != c2) { | |
| 95 if (d1 <= d2) { | |
| 96 c2 = loopHierarchy.getEnclosingLoop(c2); | |
| 97 d2 = getDepth(c2); | |
| 98 } else { | |
| 99 c1 = loopHierarchy.getEnclosingLoop(c1); | |
| 100 d1 = getDepth(c1); | |
| 101 } | |
| 102 } | |
| 103 return c1; | |
| 104 } | |
| 105 | |
| 106 @override | |
| 107 void processReference(Reference ref) { | |
| 108 Continuation loop = | |
| 109 leastCommonAncestor(currentLoopHeader, primitiveLoop[ref.definition]); | |
| 110 referencedLoop = getInnerLoop(loop, referencedLoop); | |
| 111 } | |
| 112 | |
| 113 int getDepth(Continuation loop) { | |
| 114 if (loop == null) return -1; | |
| 115 return loopHierarchy.loopDepth[loop]; | |
| 116 } | |
| 117 | |
| 118 Continuation getInnerLoop(Continuation loop1, Continuation loop2) { | |
| 119 if (loop1 == null) return loop2; | |
| 120 if (loop2 == null) return loop1; | |
| 121 if (loopHierarchy.loopDepth[loop1] > loopHierarchy.loopDepth[loop2]) { | |
| 122 return loop1; | |
| 123 } else { | |
| 124 return loop2; | |
| 125 } | |
| 126 } | |
| 127 | |
| 128 bool shouldLift(Primitive prim) { | |
| 129 // Interceptors are generally safe and almost always profitable for lifting | |
| 130 // out of loops. Several other primitive could be lifted too, but it's not | |
| 131 // always profitable to do so. | |
| 132 | |
| 133 // Note that the type of the interceptor is technically not sound after | |
| 134 // lifting because its current type might have been computed based on a | |
| 135 // refinement node (which has since been removed). As a whole, it still | |
| 136 // works out because all uses of the interceptor must occur in a context | |
| 137 // where it indeed has the type it claims to have. | |
| 138 return prim is Interceptor; | |
| 139 } | |
| 140 } | |
| OLD | NEW |