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 |