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

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

Issue 853083005: Revert "Allow LetCont to bind multiple continuations." (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 5 years, 11 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 | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file 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 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 part of dart2js.cps_ir.optimizers; 5 part of dart2js.cps_ir.optimizers;
6 6
7 /** 7 /**
8 * [ShrinkingReducer] applies shrinking reductions to CPS terms as described 8 * [ShrinkingReducer] applies shrinking reductions to CPS terms as described
9 * in 'Compiling with Continuations, Continued' by Andrew Kennedy. 9 * in 'Compiling with Continuations, Continued' by Andrew Kennedy.
10 */ 10 */
(...skipping 28 matching lines...) Expand all
39 void _removeNode(InteriorNode node) { 39 void _removeNode(InteriorNode node) {
40 Node body = node.body; 40 Node body = node.body;
41 InteriorNode parent = node.parent; 41 InteriorNode parent = node.parent;
42 assert(parent.body == node); 42 assert(parent.body == node);
43 43
44 body.parent = parent; 44 body.parent = parent;
45 parent.body = body; 45 parent.body = body;
46 node.parent = _DELETED; 46 node.parent = _DELETED;
47 } 47 }
48 48
49 /// Remove a given continuation from the CPS graph. The LetCont itself is
50 /// removed if the given continuation is the only binding.
51 void _removeContinuation(Continuation cont) {
52 LetCont parent = cont.parent;
53 if (parent.continuations.length == 1) {
54 assert(cont.parent_index == 0);
55 _removeNode(parent);
56 } else {
57 List<Continuation> continuations = parent.continuations;
58 for (int i = cont.parent_index; i < continuations.length - 1; ++i) {
59 Continuation current = continuations[i + 1];
60 continuations[i] = current;
61 current.parent_index = i;
62 }
63 continuations.removeLast();
64 }
65 cont.parent = _DELETED;
66 }
67
68 void _processTask(_ReductionTask task) { 49 void _processTask(_ReductionTask task) {
69 // Skip tasks for deleted nodes. 50 // Lazily skip tasks for deleted nodes.
70 if (task.node.parent == _DELETED) { 51 if (task.node.parent == _DELETED) {
71 return; 52 return;
72 } 53 }
73 54
74 switch (task.kind) { 55 switch (task.kind) {
75 case _ReductionKind.DEAD_VAL: 56 case _ReductionKind.DEAD_VAL:
76 _reduceDeadVal(task); 57 _reduceDeadVal(task);
77 break; 58 break;
78 case _ReductionKind.DEAD_CONT: 59 case _ReductionKind.DEAD_CONT:
79 _reduceDeadCont(task); 60 _reduceDeadCont(task);
(...skipping 21 matching lines...) Expand all
101 // Perform bookkeeping on removed body and scan for new redexes. 82 // Perform bookkeeping on removed body and scan for new redexes.
102 new _RemovalRedexVisitor(_worklist).visit(letPrim.primitive); 83 new _RemovalRedexVisitor(_worklist).visit(letPrim.primitive);
103 } 84 }
104 85
105 /// Applies the dead-cont reduction: 86 /// Applies the dead-cont reduction:
106 /// letcont k x = E0 in E1 -> E1 (k not free in E1). 87 /// letcont k x = E0 in E1 -> E1 (k not free in E1).
107 void _reduceDeadCont(_ReductionTask task) { 88 void _reduceDeadCont(_ReductionTask task) {
108 assert(_isDeadCont(task.node)); 89 assert(_isDeadCont(task.node));
109 90
110 // Remove dead continuation. 91 // Remove dead continuation.
111 Continuation cont = task.node; 92 LetCont letCont = task.node;
112 _removeContinuation(cont); 93 _removeNode(letCont);
113 94
114 // Perform bookkeeping on removed body and scan for new redexes. 95 // Perform bookkeeping on removed body and scan for new redexes.
115 new _RemovalRedexVisitor(_worklist).visit(cont); 96 new _RemovalRedexVisitor(_worklist).visit(letCont.continuation);
116 } 97 }
117 98
118 /// Applies the beta-cont-lin reduction: 99 /// Applies the beta-cont-lin reduction:
119 /// letcont k x = E0 in E1[k y] -> E1[E0[y/x]] (k not free in E1). 100 /// letcont k x = E0 in E1[k y] -> E1[E0[y/x]] (k not free in E1).
120 void _reduceBetaContLin(_ReductionTask task) { 101 void _reduceBetaContLin(_ReductionTask task) {
121 // Might have been mutated, recheck if reduction is still valid. 102 // Might have been mutated, recheck if reduction is still valid.
122 // In the following example, the beta-cont-lin reduction of k0 could have 103 // In the following example, the beta-cont-lin reduction of k0 could have
123 // been invalidated by removal of the dead continuation k1: 104 // been invalidated by removal of the dead continuation k1:
124 // 105 //
125 // letcont k0 x0 = E0 in 106 // letcont k0 x0 = E0 in
126 // letcont k1 x1 = k0 x1 in 107 // letcont k1 x1 = k0 x1 in
127 // return x2 108 // return x2
128 if (!_isBetaContLin(task.node)) { 109 if (!_isBetaContLin(task.node)) {
129 return; 110 return;
130 } 111 }
131 112
132 // Remove the continuation. 113 // Remove the continuation.
133 Continuation cont = task.node; 114 LetCont letCont = task.node;
134 _removeContinuation(cont); 115 Continuation cont = letCont.continuation;
116 _removeNode(letCont);
135 117
136 // Replace its invocation with the continuation body. 118 // Replace its invocation with the continuation body.
137 InvokeContinuation invoke = cont.firstRef.parent; 119 InvokeContinuation invoke = cont.firstRef.parent;
138 InteriorNode invokeParent = invoke.parent; 120 InteriorNode invokeParent = invoke.parent;
139 121
140 cont.body.parent = invokeParent; 122 cont.body.parent = invokeParent;
141 invokeParent.body = cont.body; 123 invokeParent.body = cont.body;
142 124
143 // Substitute the invocation argument for the continuation parameter. 125 // Substitute the invocation argument for the continuation parameter.
144 for (int i = 0; i < invoke.arguments.length; i++) { 126 for (int i = 0; i < invoke.arguments.length; i++) {
145 Reference argRef = invoke.arguments[i]; 127 Reference argRef = invoke.arguments[i];
146 argRef.definition.substituteFor(cont.parameters[i]); 128 argRef.definition.substituteFor(cont.parameters[i]);
147 } 129 }
148 130
149 // Perform bookkeeping on substituted body and scan for new redexes. 131 // Perform bookkeeping on removed body and scan for new redexes.
150 new _RemovalRedexVisitor(_worklist).visit(invoke); 132 new _RemovalRedexVisitor(_worklist).visit(invoke);
151 } 133 }
152 134
153 /// Applies the eta-cont reduction: 135 /// Applies the eta-cont reduction:
154 /// letcont k x = j x in E -> E[j/k]. 136 /// letcont k x = j x in E -> E[j/k].
155 /// If k is unused, degenerates to dead-cont. 137 /// If k is unused, degenerates to dead-cont.
156 void _reduceEtaCont(_ReductionTask task) { 138 void _reduceEtaCont(_ReductionTask task) {
157 // Might have been mutated, recheck if reduction is still valid. 139 // Might have been mutated, recheck if reduction is still valid.
158 // In the following example, the eta-cont reduction of k1 could have been 140 // In the following example, the eta-cont reduction of k1 could have been
159 // invalidated by an earlier beta-cont-lin reduction of k0. 141 // invalidated by an earlier beta-cont-lin reduction of k0.
160 // 142 //
161 // letcont k0 x0 = E0 in 143 // letcont k0 x0 = E0 in
162 // letcont k1 x1 = k0 x1 in E1 144 // letcont k1 x1 = k0 x1 in E1
163 if (!_isEtaCont(task.node)) { 145 if (!_isEtaCont(task.node)) {
164 return; 146 return;
165 } 147 }
166 148
167 // Remove the continuation. 149 // Remove the continuation.
168 Continuation cont = task.node; 150 LetCont letCont = task.node;
169 _removeContinuation(cont); 151 Continuation cont = letCont.continuation;
152 _removeNode(letCont);
170 153
171 InvokeContinuation invoke = cont.body; 154 InvokeContinuation invoke = cont.body;
172 Continuation wrappedCont = invoke.continuation.definition; 155 Continuation wrappedCont = invoke.continuation.definition;
173 156
174 // Replace all occurrences with the wrapped continuation. 157 // Replace all occurrences with the wrapped continuation.
175 wrappedCont.substituteFor(cont); 158 wrappedCont.substituteFor(cont);
176 159
177 // Perform bookkeeping on removed body and scan for new redexes. 160 // Perform bookkeeping on removed body and scan for new redexes.
178 new _RemovalRedexVisitor(_worklist).visit(cont); 161 new _RemovalRedexVisitor(_worklist).visit(cont);
179 } 162 }
180 } 163 }
181 164
182 /// Returns true iff the bound primitive is unused. 165 /// Returns true iff the bound primitive is unused.
183 bool _isDeadVal(LetPrim node) => !node.primitive.hasAtLeastOneUse; 166 bool _isDeadVal(LetPrim node) => !node.primitive.hasAtLeastOneUse;
184 167
185 /// Returns true iff the continuation is unused. 168 /// Returns true iff the bound continuation is unused.
186 bool _isDeadCont(Continuation cont) { 169 bool _isDeadCont(LetCont node) => !node.continuation.hasAtLeastOneUse;
187 return !cont.hasAtLeastOneUse && !cont.isReturnContinuation;
188 }
189 170
190 /// Returns true iff the continuation is used exactly once, and that 171 /// Returns true iff the bound continuation is used exactly once, and that
191 /// use is as the continuation of a continuation invocation. 172 /// use is as the receiver of a continuation invocation.
192 bool _isBetaContLin(Continuation cont) { 173 bool _isBetaContLin(LetCont node) {
174 Continuation cont = node.continuation;
193 if (!cont.hasExactlyOneUse) { 175 if (!cont.hasExactlyOneUse) {
194 return false; 176 return false;
195 } 177 }
196 178
197 if (cont.firstRef.parent is InvokeContinuation) { 179 if (cont.firstRef.parent is InvokeContinuation) {
198 InvokeContinuation invoke = cont.firstRef.parent; 180 InvokeContinuation invoke = cont.firstRef.parent;
199 return (cont == invoke.continuation.definition); 181 return (cont == invoke.continuation.definition);
200 } 182 }
201 183
202 return false; 184 return false;
185
203 } 186 }
204 187
205 /// Returns true iff the continuation consists of a continuation 188 /// Returns true iff the bound continuation consists of a continuation
206 /// invocation, passing on all parameters. Special cases exist (see below). 189 /// invocation, passing on all parameters. Special cases exist (see below).
207 bool _isEtaCont(Continuation cont) { 190 bool _isEtaCont(LetCont node) {
208 if (cont.body is! InvokeContinuation) { 191 Continuation cont = node.continuation;
192 if (!(cont.body is InvokeContinuation)) {
209 return false; 193 return false;
210 } 194 }
211 195
212 InvokeContinuation invoke = cont.body; 196 InvokeContinuation invoke = cont.body;
213 Continuation invokedCont = invoke.continuation.definition; 197 Continuation invokedCont = invoke.continuation.definition;
214 198
215 // Do not eta-reduce return join-points since the resulting code is worse 199 // Do not eta-reduce return join-points since the resulting code is worse
216 // in the common case (i.e. returns are moved inside `if` branches). 200 // in the common case (i.e. returns are moved inside `if` branches).
217 if (invokedCont.isReturnContinuation) { 201 if (invokedCont.isReturnContinuation) {
218 return false; 202 return false;
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
251 if (node.parent == ShrinkingReducer._DELETED) { 235 if (node.parent == ShrinkingReducer._DELETED) {
252 return; 236 return;
253 } else if (_isDeadVal(node)) { 237 } else if (_isDeadVal(node)) {
254 worklist.add(new _ReductionTask(_ReductionKind.DEAD_VAL, node)); 238 worklist.add(new _ReductionTask(_ReductionKind.DEAD_VAL, node));
255 } 239 }
256 } 240 }
257 241
258 void processLetCont(LetCont node) { 242 void processLetCont(LetCont node) {
259 if (node.parent == ShrinkingReducer._DELETED) { 243 if (node.parent == ShrinkingReducer._DELETED) {
260 return; 244 return;
261 } 245 } else if (_isDeadCont(node)) {
262 for (int i = 0; i < node.continuations.length; ++i) { 246 worklist.add(new _ReductionTask(_ReductionKind.DEAD_CONT, node));
263 Continuation cont = node.continuations[i]; 247 } else if (_isEtaCont(node)) {
264 if (_isDeadCont(cont)) { 248 worklist.add(new _ReductionTask(_ReductionKind.ETA_CONT, node));
265 worklist.add(new _ReductionTask(_ReductionKind.DEAD_CONT, cont)); 249 } else if (_isBetaContLin(node)){
266 } else if (_isEtaCont(cont)) { 250 worklist.add(new _ReductionTask(_ReductionKind.BETA_CONT_LIN, node));
267 worklist.add(new _ReductionTask(_ReductionKind.ETA_CONT, cont));
268 } else if (_isBetaContLin(cont)){
269 worklist.add(new _ReductionTask(_ReductionKind.BETA_CONT_LIN, cont));
270 }
271 } 251 }
272 } 252 }
273 } 253 }
274 254
275 /// Traverses a deleted CPS term, marking existing tasks associated with a node 255 /// Traverses a deleted CPS term, marking existing tasks associated with a node
276 /// within the term as deleted (which causes them to be skipped lazily when 256 /// within the term as deleted (which causes them to be skipped lazily when
277 /// popped from the worklist), and adding newly created redexes to the worklist. 257 /// popped from the worklist), and adding newly created redexes to the worklist.
278 class _RemovalRedexVisitor extends _RedexVisitor { 258 class _RemovalRedexVisitor extends _RedexVisitor {
279 _RemovalRedexVisitor(Set<_ReductionTask> worklist) : super(worklist); 259 _RemovalRedexVisitor(Set<_ReductionTask> worklist) : super(worklist);
280 260
281 void processLetPrim(LetPrim node) { 261 void processLetPrim(LetPrim node) {
282 node.parent = ShrinkingReducer._DELETED; 262 node.parent = ShrinkingReducer._DELETED;
283 } 263 }
284 264
285 void processLetCont(LetCont node) { 265 void processLetCont(LetCont node) {
286 node.parent = ShrinkingReducer._DELETED; 266 node.parent = ShrinkingReducer._DELETED;
287 } 267 }
288 268
289 void processContinuation(Continuation node) {
290 node.parent = ShrinkingReducer._DELETED;
291 }
292
293 void processReference(Reference reference) { 269 void processReference(Reference reference) {
294 reference.unlink(); 270 reference.unlink();
295 271
296 if (reference.definition is Primitive) { 272 if (reference.definition is Primitive) {
297 Primitive primitive = reference.definition; 273 Primitive primitive = reference.definition;
298 Node parent = primitive.parent; 274 Node parent = primitive.parent;
299 if (parent is LetPrim && _isDeadVal(parent)) { 275 if (parent is LetPrim && _isDeadVal(parent)) {
300 worklist.add(new _ReductionTask(_ReductionKind.DEAD_VAL, parent)); 276 worklist.add(new _ReductionTask(_ReductionKind.DEAD_VAL, parent));
301 } 277 }
302 } else if (reference.definition is Continuation) { 278 } else if (reference.definition is Continuation) {
303 Continuation cont = reference.definition; 279 Continuation cont = reference.definition;
304 if (cont.isRecursive && cont.hasAtMostOneUse) { 280 if (cont.isRecursive && cont.hasAtMostOneUse) {
305 // Convert recursive to nonrecursive continuations. 281 // Convert recursive to nonrecursive continuations.
306 // If the continuation is still in use, it is either dead and will be 282 // If the continuation is still in use, it is either dead and will be
307 // removed, or it is called nonrecursively outside its body. 283 // removed, or it is called nonrecursively outside its body.
308 cont.isRecursive = false; 284 cont.isRecursive = false;
309 } 285 }
310 if (_isDeadCont(cont)) { 286 Node parent = cont.parent;
311 worklist.add(new _ReductionTask(_ReductionKind.DEAD_CONT, cont)); 287 if (parent is LetCont && _isDeadCont(parent)) {
288 worklist.add(new _ReductionTask(_ReductionKind.DEAD_CONT, parent));
312 } 289 }
313 } 290 }
314 } 291 }
315 } 292 }
316 293
317 /// Traverses the CPS term and sets node.parent for each visited node. 294 /// Traverses the CPS term and sets node.parent for each visited node.
318 class ParentVisitor extends RecursiveVisitor { 295 class ParentVisitor extends RecursiveVisitor {
296
319 processFunctionDefinition(FunctionDefinition node) { 297 processFunctionDefinition(FunctionDefinition node) {
320 node.body.parent = node; 298 node.body.parent = node;
321 node.parameters.forEach((Definition p) => p.parent = node); 299 node.parameters.forEach((Definition p) => p.parent = node);
322 } 300 }
323 301
324 processRunnableBody(RunnableBody node) { 302 processRunnableBody(RunnableBody node) {
325 node.body.parent = node; 303 node.body.parent = node;
326 } 304 }
327 305
328 processConstructorDefinition(ConstructorDefinition node) { 306 processConstructorDefinition(ConstructorDefinition node) {
(...skipping 12 matching lines...) Expand all
341 node.arguments.forEach( 319 node.arguments.forEach(
342 (RunnableBody argument) => argument.body.parent = node); 320 (RunnableBody argument) => argument.body.parent = node);
343 } 321 }
344 322
345 processLetPrim(LetPrim node) { 323 processLetPrim(LetPrim node) {
346 node.primitive.parent = node; 324 node.primitive.parent = node;
347 node.body.parent = node; 325 node.body.parent = node;
348 } 326 }
349 327
350 processLetCont(LetCont node) { 328 processLetCont(LetCont node) {
351 for (int i = 0; i < node.continuations.length; ++i) { 329 node.continuation.parent = node;
352 Continuation cont = node.continuations[i];
353 cont.parent = node;
354 cont.parent_index = i;
355 }
356 node.body.parent = node; 330 node.body.parent = node;
357 } 331 }
358 332
359 processInvokeStatic(InvokeStatic node) { 333 processInvokeStatic(InvokeStatic node) {
334 node.continuation.parent = node;
360 node.arguments.forEach((Reference ref) => ref.parent = node); 335 node.arguments.forEach((Reference ref) => ref.parent = node);
361 node.continuation.parent = node;
362 } 336 }
363 337
364 processInvokeContinuation(InvokeContinuation node) { 338 processInvokeContinuation(InvokeContinuation node) {
365 node.continuation.parent = node; 339 node.continuation.parent = node;
366 node.arguments.forEach((Reference ref) => ref.parent = node); 340 node.arguments.forEach((Reference ref) => ref.parent = node);
367 } 341 }
368 342
369 processInvokeMethod(InvokeMethod node) { 343 processInvokeMethod(InvokeMethod node) {
370 node.receiver.parent = node; 344 node.receiver.parent = node;
371 node.continuation.parent = node; 345 node.continuation.parent = node;
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after
502 } 476 }
503 477
504 String toString() => "$kind: $node"; 478 String toString() => "$kind: $node";
505 } 479 }
506 480
507 /// A dummy class used solely to mark nodes as deleted once they are removed 481 /// A dummy class used solely to mark nodes as deleted once they are removed
508 /// from a term. 482 /// from a term.
509 class _DeletedNode extends Node { 483 class _DeletedNode extends Node {
510 accept(_) => null; 484 accept(_) => null;
511 } 485 }
OLDNEW
« no previous file with comments | « pkg/compiler/lib/src/cps_ir/redundant_phi.dart ('k') | pkg/compiler/lib/src/cps_ir/type_propagation.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698