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 |