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

Side by Side Diff: pkg/compiler/lib/src/cps_ir/mutable_ssa.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) 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.mutable_ssa;
6
7 import 'cps_ir_nodes.dart';
8 import 'optimizers.dart';
9
10 /// Determines which mutable variables should be rewritten to phi assignments
11 /// in this pass.
12 ///
13 /// We do not rewrite variables that have an assignment inside a try block that
14 /// does not contain its declaration.
15 class MutableVariablePreanalysis extends TrampolineRecursiveVisitor {
16 // Number of try blocks enclosing the current position.
17 int currentDepth = 0;
18
19 /// Number of try blocks enclosing the declaration of a given mutable
20 /// variable.
21 ///
22 /// All mutable variables seen will be present in the map after the analysis.
23 Map<MutableVariable, int> variableDepth = <MutableVariable, int>{};
24
25 /// Variables with an assignment inside a try block that does not contain
26 /// its declaration.
27 Set<MutableVariable> hasAssignmentInTry = new Set<MutableVariable>();
28
29 @override
30 Expression traverseLetHandler(LetHandler node) {
31 push(node.handler);
32 ++currentDepth;
33 pushAction(() => --currentDepth);
34 return node.body;
35 }
36
37 void processLetMutable(LetMutable node) {
38 variableDepth[node.variable] = currentDepth;
39 }
40
41 void processSetMutable(SetMutable node) {
42 MutableVariable variable = node.variable;
43 if (currentDepth > variableDepth[variable]) {
44 hasAssignmentInTry.add(variable);
45 }
46 }
47
48 /// True if there are no mutable variables or they are all assigned inside
49 /// a try block. In this case, there is nothing to do and the pass should
50 /// be skipped.
51 bool get allMutablesAreAssignedInTryBlocks {
52 return hasAssignmentInTry.length == variableDepth.length;
53 }
54 }
55
56 /// Replaces mutable variables with continuation parameters, effectively
57 /// bringing them into SSA form.
58 ///
59 /// This pass is intended to clean up mutable variables that were introduced
60 /// by an optimization in the type propagation pass.
61 ///
62 /// This implementation potentially creates a lot of redundant and dead phi
63 /// parameters. These will be cleaned up by redundant phi elimination and
64 /// shrinking reductions.
65 ///
66 /// Discussion:
67 /// For methods with a lot of mutable variables, creating all the spurious
68 /// parameters might be too expensive. If this is the case, we should
69 /// improve this pass to avoid most spurious parameters in practice.
70 class MutableVariableEliminator implements Pass {
71 String get passName => 'Mutable variable elimination';
72
73 /// Mutable variables currently in scope, in order of declaration.
74 /// This list determines the order of the corresponding phi parameters.
75 final List<MutableVariable> mutableVariables = <MutableVariable>[];
76
77 /// Number of phi parameters added to the given continuation.
78 final Map<Continuation, int> continuationPhiCount = <Continuation, int>{};
79
80 /// Stack of yet unprocessed continuations interleaved with the
81 /// mutable variables currently in scope.
82 ///
83 /// Continuations are processed when taken off the stack and mutable
84 /// variables fall out of scope (i.e. removed from [mutableVariables]) when
85 /// taken off the stack.
86 final List<StackItem> stack = <StackItem>[];
87
88 MutableVariablePreanalysis analysis;
89
90 void rewrite(FunctionDefinition node) {
91 analysis = new MutableVariablePreanalysis()..visit(node);
92 if (analysis.allMutablesAreAssignedInTryBlocks) {
93 // Skip the pass if there is nothing to do.
94 return;
95 }
96 processBlock(node.body, <MutableVariable, Primitive>{});
97 while (stack.isNotEmpty) {
98 StackItem item = stack.removeLast();
99 if (item is ContinuationItem) {
100 processBlock(item.continuation.body, item.environment);
101 } else {
102 assert(item is VariableItem);
103 mutableVariables.removeLast();
104 }
105 }
106 }
107
108 bool shouldRewrite(MutableVariable variable) {
109 return !analysis.hasAssignmentInTry.contains(variable);
110 }
111
112 bool isJoinContinuation(Continuation cont) {
113 return !cont.hasExactlyOneUse || cont.firstRef.parent is InvokeContinuation;
114 }
115
116 /// If some useful source information is attached to exactly one of the
117 /// two definitions, the information is copied onto the other.
118 void mergeHints(MutableVariable variable, Primitive value) {
119 if (variable.hint == null) {
120 variable.hint = value.hint;
121 } else if (value.hint == null) {
122 value.hint = variable.hint;
123 }
124 }
125
126 /// Processes a basic block, replacing mutable variable uses with direct
127 /// references to their values.
128 ///
129 /// [environment] is the current value of each mutable variable. The map
130 /// will be mutated during the processing.
131 ///
132 /// Continuations to be processed are put on the stack for later processing.
133 void processBlock(
134 Expression node, Map<MutableVariable, Primitive> environment) {
135 Expression next = node.next;
136 for (; node is! TailExpression; node = next, next = node.next) {
137 if (node is LetMutable && shouldRewrite(node.variable)) {
138 // Put the new mutable variable on the stack while processing the body,
139 // and pop it off again when done with the body.
140 mutableVariables.add(node.variable);
141 stack.add(new VariableItem());
142
143 // Put the initial value into the environment.
144 Primitive value = node.value;
145 environment[node.variable] = value;
146
147 // Preserve variable names.
148 mergeHints(node.variable, value);
149
150 // Remove the mutable variable binding.
151 node.valueRef.unlink();
152 node.remove();
153 } else if (node is LetPrim && node.primitive is SetMutable) {
154 SetMutable setter = node.primitive;
155 MutableVariable variable = setter.variable;
156 if (shouldRewrite(variable)) {
157 // As above, update the environment, preserve variables and remove
158 // the mutable variable assignment.
159 environment[variable] = setter.value;
160 mergeHints(variable, setter.value);
161 setter.valueRef.unlink();
162 node.remove();
163 }
164 } else if (node is LetPrim && node.primitive is GetMutable) {
165 GetMutable getter = node.primitive;
166 MutableVariable variable = getter.variable;
167 if (shouldRewrite(variable)) {
168 // Replace with the reaching definition from the environment.
169 Primitive value = environment[variable];
170 getter.replaceUsesWith(value);
171 mergeHints(variable, value);
172 node.remove();
173 }
174 } else if (node is LetCont) {
175 // Create phi parameters for each join continuation bound here, and put
176 // them on the stack for later processing.
177 // Note that non-join continuations are handled at the use-site.
178 for (Continuation cont in node.continuations) {
179 if (!isJoinContinuation(cont)) continue;
180 // Create a phi parameter for every mutable variable in scope.
181 // At the same time, build the environment to use for processing
182 // the continuation (mapping mutables to phi parameters).
183 continuationPhiCount[cont] = mutableVariables.length;
184 Map<MutableVariable, Primitive> environment =
185 <MutableVariable, Primitive>{};
186 for (MutableVariable variable in mutableVariables) {
187 Parameter phi = new Parameter(variable.hint);
188 phi.type = variable.type;
189 cont.parameters.add(phi);
190 phi.parent = cont;
191 environment[variable] = phi;
192 }
193 stack.add(new ContinuationItem(cont, environment));
194 }
195 } else if (node is LetHandler) {
196 // Process the catch block later and continue into the try block.
197 // We can use the same environment object for the try and catch blocks.
198 // The current environment bindings cannot change inside the try block
199 // because we exclude all variables assigned inside a try block.
200 // The environment might be extended with more bindings before we
201 // analyze the catch block, but that's ok.
202 stack.add(new ContinuationItem(node.handler, environment));
203 }
204 }
205
206 // Analyze the terminal node.
207 if (node is InvokeContinuation) {
208 Continuation cont = node.continuation;
209 if (cont.isReturnContinuation) return;
210 // This is a call to a join continuation. Add arguments for the phi
211 // parameters that were added to this continuation.
212 int phiCount = continuationPhiCount[cont];
213 for (int i = 0; i < phiCount; ++i) {
214 Primitive value = environment[mutableVariables[i]];
215 Reference<Primitive> arg = new Reference<Primitive>(value);
216 node.argumentRefs.add(arg);
217 arg.parent = node;
218 }
219 } else if (node is Branch) {
220 // Enqueue both branches with the current environment.
221 // Clone the environments once so the processing of one branch does not
222 // mutate the environment needed to process the other branch.
223 stack.add(new ContinuationItem(node.trueContinuation,
224 new Map<MutableVariable, Primitive>.from(environment)));
225 stack.add(new ContinuationItem(node.falseContinuation, environment));
226 } else {
227 assert(node is Throw || node is Unreachable);
228 }
229 }
230 }
231
232 abstract class StackItem {}
233
234 /// Represents a mutable variable that is in scope.
235 ///
236 /// The topmost mutable variable falls out of scope when this item is
237 /// taken off the stack.
238 class VariableItem extends StackItem {}
239
240 /// Represents a yet unprocessed continuation together with the
241 /// environment in which to process it.
242 class ContinuationItem extends StackItem {
243 final Continuation continuation;
244 final Map<MutableVariable, Primitive> environment;
245
246 ContinuationItem(this.continuation, this.environment);
247 }
OLDNEW
« no previous file with comments | « pkg/compiler/lib/src/cps_ir/loop_invariant_branch.dart ('k') | pkg/compiler/lib/src/cps_ir/octagon.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698