Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(684)

Side by Side Diff: pkg/compiler/lib/src/cps_ir/redundant_phi.dart

Issue 2246623002: Delete CPS IR (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2014, 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.redundant_phi_elimination;
6
7 import 'cps_ir_nodes.dart';
8 import 'optimizers.dart';
9
10 /// Eliminate redundant phis from the given [FunctionDefinition].
11 ///
12 /// Phis in this case are [Continuations] together with corresponding
13 /// [InvokeContinuation]s. A [Continuation] parameter at position i is redundant
14 /// if for all [InvokeContinuation]s, the parameter at position i is identical
15 /// (except for feedback). Redundant parameters are removed from the
16 /// continuation signature, all invocations, and replaced within the
17 /// continuation body.
18 class RedundantPhiEliminator extends TrampolineRecursiveVisitor
19 implements Pass {
20 String get passName => 'Redundant phi elimination';
21
22 final Set<Continuation> workSet = new Set<Continuation>();
23
24 @override
25 void rewrite(FunctionDefinition root) {
26 // Traverse the tree once to build the work set.
27 visit(root);
28
29 // Process each continuation one-by-one.
30 while (workSet.isNotEmpty) {
31 Continuation cont = workSet.first;
32 workSet.remove(cont);
33
34 if (cont.isReturnContinuation) {
35 continue; // Skip function return continuations.
36 }
37
38 _processContinuation(cont);
39 }
40 }
41
42 /// Called for each continuation on the work set. Modifies the IR graph if
43 /// [cont] is a candidate for redundant phi elimination.
44 void _processContinuation(Continuation cont) {
45 // Generate the list of all cont invocations. If cont is used in any other
46 // context (i.e. as a continuation of InvokeMethod), it is not possible to
47 // optimize.
48 List<InvokeContinuation> invokes = <InvokeContinuation>[];
49 for (Reference ref = cont.firstRef; ref != null; ref = ref.next) {
50 Node parent = ref.parent;
51 if (parent is InvokeContinuation && ref == parent.continuationRef) {
52 invokes.add(parent);
53 } else {
54 return; // Can't optimize.
55 }
56 }
57
58 if (invokes.isEmpty) {
59 return; // Continuation is never invoked, can't optimize.
60 }
61
62 /// Returns the unique definition of parameter i if it exists and null
63 /// otherwise. A definition is unique if it is the only value used to
64 /// invoke the continuation, excluding feedback.
65 Primitive uniqueDefinitionOf(int i) {
66 Primitive value = null;
67 for (InvokeContinuation invoke in invokes) {
68 Primitive def = invoke.argument(i).effectiveDefinition;
69
70 if (cont.parameters[i] == def) {
71 // Invocation param == param in LetCont (i.e. a recursive call).
72 continue;
73 } else if (value == null) {
74 value = def; // Set initial comparison value.
75 } else if (value != def) {
76 return null; // Differing invocation arguments.
77 }
78 }
79
80 return value;
81 }
82
83 // If uniqueDefinition is in the body of the LetCont binding the
84 // continuation, then we will drop the continuation binding to just inside
85 // the binding of uniqueDefiniton. This is not safe if we drop the
86 // continuation binding inside a LetHandler exception handler binding.
87 LetCont letCont = cont.parent;
88 bool safeForHandlers(Definition uniqueDefinition) {
89 bool seenHandler = false;
90 Node current = uniqueDefinition.parent;
91 while (current != null) {
92 if (current == letCont) return !seenHandler;
93 seenHandler = seenHandler || current is LetHandler;
94 current = current.parent;
95 }
96 // When uniqueDefinition is not in the body of the LetCont binding the
97 // continuation, we will not move any code, so that is safe.
98 return true;
99 }
100
101 // Check if individual parameters are always called with a unique
102 // definition, and remove them if that is the case. During each iteration,
103 // we read the current parameter/argument from index `src` and copy it
104 // to index `dst`.
105 int dst = 0;
106 for (int src = 0; src < cont.parameters.length; src++) {
107 // Is the current phi redundant?
108 Primitive uniqueDefinition = uniqueDefinitionOf(src);
109 if (uniqueDefinition == null || !safeForHandlers(uniqueDefinition)) {
110 // Reorganize parameters and arguments in case of deletions.
111 if (src != dst) {
112 cont.parameters[dst] = cont.parameters[src];
113 for (InvokeContinuation invoke in invokes) {
114 invoke.argumentRefs[dst] = invoke.argumentRefs[src];
115 }
116 }
117 dst++;
118 continue;
119 }
120
121 Primitive oldDefinition = cont.parameters[src];
122
123 // Add continuations of about-to-be modified invokes to worklist since
124 // we might introduce new optimization opportunities.
125 for (Reference ref = oldDefinition.firstRef;
126 ref != null;
127 ref = ref.next) {
128 Node parent = ref.parent;
129 if (parent is InvokeContinuation) {
130 Continuation thatCont = parent.continuation;
131 if (thatCont != cont) {
132 workSet.add(thatCont);
133 }
134 }
135 }
136
137 // Replace individual parameters:
138 // * In the continuation body, replace occurrence of param with value,
139 // * and implicitly remove param from continuation signature and
140 // invocations by not incrementing `dst`. References of removed
141 // arguments are unlinked to keep definition usages up to date.
142 oldDefinition.replaceUsesWith(uniqueDefinition);
143 for (InvokeContinuation invoke in invokes) {
144 invoke.argumentRefs[src].unlink();
145 }
146
147 // Finally, if the substituted definition is not in scope of the affected
148 // continuation, move the continuation binding. This is safe to do since
149 // the continuation is referenced only as the target in continuation
150 // invokes, and all such invokes must be within the scope of
151 // [uniqueDefinition]. Note that this is linear in the depth of
152 // the binding of [uniqueDefinition].
153 letCont = _makeUniqueBinding(cont);
154 _moveIntoScopeOf(letCont, uniqueDefinition);
155 }
156
157 // Remove trailing items from parameter and argument lists.
158 cont.parameters.length = dst;
159 for (InvokeContinuation invoke in invokes) {
160 invoke.argumentRefs.length = dst;
161 }
162 }
163
164 void processLetCont(LetCont node) {
165 node.continuations.forEach(workSet.add);
166 }
167 }
168
169 /// Returns true, iff [letCont] is not scope of [definition].
170 /// Linear in the depth of definition within the IR graph.
171 bool _isInScopeOf(LetCont letCont, Definition definition) {
172 for (Node node = definition.parent; node != null; node = node.parent) {
173 if (node == letCont) {
174 return false;
175 }
176 }
177
178 return true;
179 }
180
181 /// Moves [letCont] below the binding of [definition] within the IR graph.
182 /// Does nothing if [letCont] is already within the scope of [definition].
183 /// Assumes that one argument is nested within the scope of the other
184 /// when this method is called.
185 void _moveIntoScopeOf(LetCont letCont, Definition definition) {
186 if (_isInScopeOf(letCont, definition)) return;
187
188 InteriorNode binding = definition.parent;
189 letCont.remove();
190 letCont.insertBelow(binding);
191 }
192
193 /// Ensures [continuation] has its own LetCont binding by creating
194 /// a new LetCont below its current binding, if necessary.
195 ///
196 /// Returns the LetCont that now binds [continuation].
197 LetCont _makeUniqueBinding(Continuation continuation) {
198 LetCont letCont = continuation.parent;
199 if (letCont.continuations.length == 1) return letCont;
200 letCont.continuations.remove(continuation);
201 LetCont newBinding = new LetCont(continuation, null);
202 continuation.parent = newBinding;
203 newBinding.insertBelow(letCont);
204 return newBinding;
205 }
OLDNEW
« no previous file with comments | « pkg/compiler/lib/src/cps_ir/redundant_join.dart ('k') | pkg/compiler/lib/src/cps_ir/redundant_refinement.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698