blob: d02e1ac40610a0149f02f98eb5ff512eeaf5c2b7 [file] [log] [blame]
// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
// 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.
part of tree_ir.optimization;
/// Rewrites [WhileTrue] statements with an [If] body into a [WhileCondition],
/// in situations where only one of the branches contains a [Continue] to the
/// loop. Schematically:
///
/// L:
/// while (true) {
/// if (E) {
/// S1 (has references to L)
/// } else {
/// S2 (has no references to L)
/// }
/// }
/// ==>
/// L:
/// while (E) {
/// S1
/// };
/// S2
///
/// A similar transformation is used when S2 occurs in the 'then' position.
///
/// Note that the above pattern needs no iteration since nested ifs
/// have been collapsed previously in the [StatementRewriter] phase.
class LoopRewriter extends RecursiveVisitor with PassMixin {
String get passName => 'Loop rewriter';
Set<Label> usedContinueLabels = new Set<Label>();
void rewriteExecutableDefinition(ExecutableDefinition root) {
root.body = visitStatement(root.body);
}
Statement visitLabeledStatement(LabeledStatement node) {
node.body = visitStatement(node.body);
node.next = visitStatement(node.next);
return node;
}
Statement visitAssign(Assign node) {
// Clean up redundant assignments left behind in the previous phase.
Expression value = node.value;
if (value is VariableUse && node.variable == value.variable) {
--node.variable.readCount;
--node.variable.writeCount;
return visitStatement(node.next);
}
visitExpression(node.value);
node.next = visitStatement(node.next);
return node;
}
Statement visitReturn(Return node) {
visitExpression(node.value);
return node;
}
Statement visitBreak(Break node) {
return node;
}
Statement visitContinue(Continue node) {
usedContinueLabels.add(node.target);
return node;
}
Statement visitIf(If node) {
visitExpression(node.condition);
node.thenStatement = visitStatement(node.thenStatement);
node.elseStatement = visitStatement(node.elseStatement);
return node;
}
Statement visitWhileTrue(WhileTrue node) {
assert(!usedContinueLabels.contains(node.label));
if (node.body is If) {
If body = node.body;
body.thenStatement = visitStatement(body.thenStatement);
bool thenHasContinue = usedContinueLabels.remove(node.label);
body.elseStatement = visitStatement(body.elseStatement);
bool elseHasContinue = usedContinueLabels.remove(node.label);
if (thenHasContinue && !elseHasContinue) {
node.label.binding = null; // Prepare to rebind the label.
return new WhileCondition(
node.label,
body.condition,
body.thenStatement,
body.elseStatement);
} else if (!thenHasContinue && elseHasContinue) {
node.label.binding = null;
return new WhileCondition(
node.label,
new Not(body.condition),
body.elseStatement,
body.thenStatement);
}
} else {
node.body = visitStatement(node.body);
usedContinueLabels.remove(node.label);
}
return node;
}
Statement visitWhileCondition(WhileCondition node) {
// Note: not reachable but the implementation is trivial
visitExpression(node.condition);
node.body = visitStatement(node.body);
node.next = visitStatement(node.next);
return node;
}
Statement visitExpressionStatement(ExpressionStatement node) {
visitExpression(node.expression);
node.next = visitStatement(node.next);
return node;
}
Statement visitTry(Try node) {
node.tryBody = visitStatement(node.tryBody);
node.catchBody = visitStatement(node.catchBody);
return node;
}
Statement visitFunctionDeclaration(FunctionDeclaration node) {
new LoopRewriter().rewrite(node.definition);
node.next = visitStatement(node.next);
return node;
}
void visitFunctionExpression(FunctionExpression node) {
new LoopRewriter().rewrite(node.definition);
}
Statement visitSetField(SetField node) {
visitExpression(node.object);
visitExpression(node.value);
node.next = visitStatement(node.next);
return node;
}
}