| Index: pkg/compiler/lib/src/cps_ir/loop_hierarchy.dart
|
| diff --git a/pkg/compiler/lib/src/cps_ir/let_sinking.dart b/pkg/compiler/lib/src/cps_ir/loop_hierarchy.dart
|
| similarity index 60%
|
| copy from pkg/compiler/lib/src/cps_ir/let_sinking.dart
|
| copy to pkg/compiler/lib/src/cps_ir/loop_hierarchy.dart
|
| index 4c4736a967efe944fc6ed9b57193414213f33894..fc639442a227812c311a8ddefdb2cca163151edf 100644
|
| --- a/pkg/compiler/lib/src/cps_ir/let_sinking.dart
|
| +++ b/pkg/compiler/lib/src/cps_ir/loop_hierarchy.dart
|
| @@ -2,119 +2,9 @@
|
| // for details. All rights reserved. Use of this source code is governed by a
|
| // BSD-style license that can be found in the LICENSE file.
|
|
|
| -library dart2js.cps_ir.let_sinking;
|
| +library dart2js.cps_ir.loop_hierarchy;
|
|
|
| import 'cps_ir_nodes.dart';
|
| -import 'optimizers.dart';
|
| -
|
| -/// Sinks single-use primitives to the use when this is safe and profitable.
|
| -///
|
| -/// To avoid sinking non-constant primitives into loops, this pass performs a
|
| -/// control-flow analysis to determine the effective nesting of loops.
|
| -///
|
| -/// In the example below, the value 'p' can be sunk to its use site in the
|
| -/// 'else' branch because that branch is not effectively part of a loop,
|
| -/// despite being lexically nested in a recursive continuation.
|
| -///
|
| -/// let prim p = getInterceptor(<something>)
|
| -/// let rec kont x =
|
| -/// if (<loop condition>)
|
| -/// <loop body>
|
| -/// InvokeContinuation kont x'
|
| -/// else
|
| -/// <after loop>
|
| -/// return p.foo()
|
| -///
|
| -class LetSinker extends RecursiveVisitor implements Pass {
|
| - String get passName => 'Let sinking';
|
| -
|
| - LoopHierarchy loopHierarchy;
|
| - List<Continuation> stack = <Continuation>[];
|
| -
|
| - /// Maps a sinkable primitive to its loop header.
|
| - Map<Primitive, Continuation> loopHeaderForPrimitive =
|
| - <Primitive, Continuation>{};
|
| -
|
| - Continuation currentLoopHeader;
|
| -
|
| - void rewrite(FunctionDefinition node) {
|
| - new ParentVisitor().visit(node);
|
| - loopHierarchy = new LoopHierarchy(node);
|
| - visit(node.body);
|
| - }
|
| -
|
| - @override
|
| - Expression traverseLetPrim(LetPrim node) {
|
| - Primitive prim = node.primitive;
|
| - if (prim.hasExactlyOneUse && prim.isSafeForReordering) {
|
| - // This can potentially be sunk. Register the loop header, so when we
|
| - // find the use site, we can check if they are in the same loop.
|
| - loopHeaderForPrimitive[prim] = currentLoopHeader;
|
| - pushAction(() {
|
| - if (node.primitive != null) {
|
| - // The primitive could not be sunk. Try to sink dependencies here.
|
| - visit(node.primitive);
|
| - } else {
|
| - // The primitive was sunk. Destroy the old LetPrim.
|
| - InteriorNode parent = node.parent;
|
| - parent.body = node.body;
|
| - node.body.parent = parent;
|
| - }
|
| - });
|
| - } else {
|
| - visit(node.primitive);
|
| - }
|
| -
|
| - // Visit the body, wherein this primitive may be sunk to its use site.
|
| - return node.body;
|
| - }
|
| -
|
| - @override
|
| - Expression traverseContinuation(Continuation cont) {
|
| - Continuation oldLoopHeader = currentLoopHeader;
|
| - pushAction(() {
|
| - currentLoopHeader = oldLoopHeader;
|
| - });
|
| - currentLoopHeader = loopHierarchy.getLoopHeader(cont);
|
| - return cont.body;
|
| - }
|
| -
|
| - void processReference(Reference ref) {
|
| - Definition definition = ref.definition;
|
| - if (definition is Primitive &&
|
| - definition is! Parameter &&
|
| - definition.hasExactlyOneUse &&
|
| - definition.isSafeForReordering) {
|
| - // Check if use is in the same loop.
|
| - Continuation bindingLoop = loopHeaderForPrimitive.remove(definition);
|
| - if (bindingLoop == currentLoopHeader || definition is Constant) {
|
| - // Sink the definition.
|
| -
|
| - Expression use = getEnclosingExpression(ref.parent);
|
| - LetPrim binding = definition.parent;
|
| - binding.primitive = null; // Mark old binding for deletion.
|
| - LetPrim newBinding = new LetPrim(definition);
|
| - definition.parent = newBinding;
|
| - InteriorNode useParent = use.parent;
|
| - useParent.body = newBinding;
|
| - newBinding.body = use;
|
| - use.parent = newBinding;
|
| - newBinding.parent = useParent;
|
| -
|
| - // Now that the final binding location has been found, sink the
|
| - // dependencies of the definition down here as well.
|
| - visit(definition);
|
| - }
|
| - }
|
| - }
|
| -
|
| - Expression getEnclosingExpression(Node node) {
|
| - while (node is! Expression) {
|
| - node = node.parent;
|
| - }
|
| - return node;
|
| - }
|
| -}
|
|
|
| /// Determines the effective nesting of loops.
|
| ///
|
| @@ -157,6 +47,12 @@ class LoopHierarchy {
|
| return cont.isRecursive ? cont : loopTarget[cont];
|
| }
|
|
|
| + /// Returns the innermost loop which the given loop is part of, other
|
| + /// than itself.
|
| + Continuation getEnclosingLoop(Continuation loop) {
|
| + return loopTarget[loop];
|
| + }
|
| +
|
| /// Marks the innermost loop as a subloop of the other loop.
|
| ///
|
| /// Returns the innermost loop.
|
|
|