| 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.let_sinking; | |
| 6 | |
| 7 import 'cps_ir_nodes.dart'; | |
| 8 import 'optimizers.dart'; | |
| 9 import 'loop_hierarchy.dart'; | |
| 10 | |
| 11 /// Sinks single-use primitives to the use when this is safe and profitable. | |
| 12 /// | |
| 13 /// To avoid sinking non-constant primitives into loops, this pass performs a | |
| 14 /// control-flow analysis to determine the effective nesting of loops. | |
| 15 /// | |
| 16 /// In the example below, the value 'p' can be sunk to its use site in the | |
| 17 /// 'else' branch because that branch is not effectively part of a loop, | |
| 18 /// despite being lexically nested in a recursive continuation. | |
| 19 /// | |
| 20 /// let prim p = getInterceptor(<something>) | |
| 21 /// let rec kont x = | |
| 22 /// if (<loop condition>) | |
| 23 /// <loop body> | |
| 24 /// InvokeContinuation kont x' | |
| 25 /// else | |
| 26 /// <after loop> | |
| 27 /// return p.foo() | |
| 28 /// | |
| 29 class LetSinker extends RecursiveVisitor implements Pass { | |
| 30 String get passName => 'Let sinking'; | |
| 31 | |
| 32 LoopHierarchy loopHierarchy; | |
| 33 List<Continuation> stack = <Continuation>[]; | |
| 34 | |
| 35 /// Maps a sinkable primitive to its loop header. | |
| 36 Map<Primitive, Continuation> loopHeaderForPrimitive = | |
| 37 <Primitive, Continuation>{}; | |
| 38 | |
| 39 Continuation currentLoopHeader; | |
| 40 | |
| 41 void rewrite(FunctionDefinition node) { | |
| 42 new ParentVisitor().visit(node); | |
| 43 loopHierarchy = new LoopHierarchy(node); | |
| 44 visit(node.body); | |
| 45 } | |
| 46 | |
| 47 @override | |
| 48 Expression traverseLetPrim(LetPrim node) { | |
| 49 Primitive prim = node.primitive; | |
| 50 if (prim.hasExactlyOneUse && prim.isSafeForReordering) { | |
| 51 // This can potentially be sunk. Register the loop header, so when we | |
| 52 // find the use site, we can check if they are in the same loop. | |
| 53 loopHeaderForPrimitive[prim] = currentLoopHeader; | |
| 54 pushAction(() { | |
| 55 if (node.primitive != null) { | |
| 56 // The primitive could not be sunk. Try to sink dependencies here. | |
| 57 visit(node.primitive); | |
| 58 } else { | |
| 59 // The primitive was sunk. Destroy the old LetPrim. | |
| 60 InteriorNode parent = node.parent; | |
| 61 parent.body = node.body; | |
| 62 node.body.parent = parent; | |
| 63 } | |
| 64 }); | |
| 65 } else { | |
| 66 visit(node.primitive); | |
| 67 } | |
| 68 | |
| 69 // Visit the body, wherein this primitive may be sunk to its use site. | |
| 70 return node.body; | |
| 71 } | |
| 72 | |
| 73 @override | |
| 74 Expression traverseContinuation(Continuation cont) { | |
| 75 Continuation oldLoopHeader = currentLoopHeader; | |
| 76 pushAction(() { | |
| 77 currentLoopHeader = oldLoopHeader; | |
| 78 }); | |
| 79 currentLoopHeader = loopHierarchy.getLoopHeader(cont); | |
| 80 return cont.body; | |
| 81 } | |
| 82 | |
| 83 void processReference(Reference ref) { | |
| 84 Definition definition = ref.definition; | |
| 85 if (definition is Primitive && | |
| 86 definition is! Parameter && | |
| 87 definition.hasExactlyOneUse && | |
| 88 definition.isSafeForReordering) { | |
| 89 // Check if use is in the same loop. | |
| 90 Continuation bindingLoop = loopHeaderForPrimitive.remove(definition); | |
| 91 if (bindingLoop == currentLoopHeader || definition is Constant) { | |
| 92 // Sink the definition. | |
| 93 | |
| 94 Expression use = getEnclosingExpression(ref.parent); | |
| 95 LetPrim binding = definition.parent; | |
| 96 binding.primitive = null; // Mark old binding for deletion. | |
| 97 LetPrim newBinding = new LetPrim(definition); | |
| 98 definition.parent = newBinding; | |
| 99 InteriorNode useParent = use.parent; | |
| 100 useParent.body = newBinding; | |
| 101 newBinding.body = use; | |
| 102 use.parent = newBinding; | |
| 103 newBinding.parent = useParent; | |
| 104 | |
| 105 // Now that the final binding location has been found, sink the | |
| 106 // dependencies of the definition down here as well. | |
| 107 visit(definition); | |
| 108 } | |
| 109 } | |
| 110 } | |
| 111 | |
| 112 Expression getEnclosingExpression(Node node) { | |
| 113 while (node is! Expression) { | |
| 114 node = node.parent; | |
| 115 } | |
| 116 return node; | |
| 117 } | |
| 118 } | |
| 119 | |
| OLD | NEW |