| Index: pkg/compiler/lib/src/cps_ir/duplicate_branch.dart
|
| diff --git a/pkg/compiler/lib/src/cps_ir/duplicate_branch.dart b/pkg/compiler/lib/src/cps_ir/duplicate_branch.dart
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..7b1d294827bbea5948f353eb7f9df278d5227461
|
| --- /dev/null
|
| +++ b/pkg/compiler/lib/src/cps_ir/duplicate_branch.dart
|
| @@ -0,0 +1,123 @@
|
| +// Copyright (c) 2016, 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.
|
| +library dart2js.cps_ir.duplicate_branch;
|
| +
|
| +import 'cps_ir_nodes.dart';
|
| +import 'optimizers.dart';
|
| +import 'cps_fragment.dart';
|
| +
|
| +/// Removes branches that branch on the same value as a previously seen branch.
|
| +/// For example:
|
| +///
|
| +/// if (x == y) {
|
| +/// if (x == y) TRUE else FALSE
|
| +/// }
|
| +///
|
| +/// ==> ([GVN] pass merges identical expressions)
|
| +///
|
| +/// var b = (x == y)
|
| +/// if (b) {
|
| +/// if (b) TRUE else FALSE
|
| +/// }
|
| +///
|
| +/// ==> (this pass removes the duplicate branch)
|
| +///
|
| +/// var b = (x == y)
|
| +/// if (b) {
|
| +/// TRUE
|
| +/// }
|
| +//
|
| +// TODO(asgerf): A kind of redundant join can arise where a branching condition
|
| +// is known to be true/false on all but one predecessor for a branch. We could
|
| +// try to reduce those.
|
| +//
|
| +// TODO(asgerf): Could be more precise if GVN shared expressions that are not
|
| +// in direct scope of one another, e.g. by using phis pass the shared value.
|
| +//
|
| +class DuplicateBranchEliminator extends TrampolineRecursiveVisitor
|
| + implements Pass {
|
| + String get passName => 'Duplicate branch elimination';
|
| +
|
| + static const int TRUE = 1 << 0;
|
| + static const int OTHER_TRUTHY = 1 << 1;
|
| + static const int FALSE = 1 << 2;
|
| + static const int OTHER_FALSY = 1 << 3;
|
| +
|
| + static const int TRUTHY = TRUE | OTHER_TRUTHY;
|
| + static const int FALSY = FALSE | OTHER_FALSY;
|
| + static const int ANY = TRUTHY | FALSY;
|
| +
|
| + /// The possible values of the given primitive (or ANY if absent) at the
|
| + /// current traversal position.
|
| + Map<Primitive, int> valueOf = <Primitive, int>{};
|
| +
|
| + /// The possible values of each primitive at the entry to a continuation.
|
| + ///
|
| + /// Unreachable continuations are absent from the map.
|
| + final Map<Continuation, Map<Primitive, int>> valuesAt =
|
| + <Continuation, Map<Primitive, int>>{};
|
| +
|
| + void rewrite(FunctionDefinition node) {
|
| + visit(node);
|
| + }
|
| +
|
| + Map<Primitive, int> copy(Map<Primitive, int> map) {
|
| + return new Map<Primitive, int>.from(map);
|
| + }
|
| +
|
| + Expression traverseLetHandler(LetHandler node) {
|
| + valuesAt[node.handler] = copy(valueOf);
|
| + push(node.handler);
|
| + return node.body;
|
| + }
|
| +
|
| + Expression traverseContinuation(Continuation cont) {
|
| + valueOf = valuesAt[cont];
|
| + if (valueOf == null) {
|
| + // Do not go into unreachable code.
|
| + destroyAndReplace(cont.body, new Unreachable());
|
| + }
|
| + return cont.body;
|
| + }
|
| +
|
| + void visitInvokeContinuation(InvokeContinuation node) {
|
| + Continuation cont = node.continuation.definition;
|
| + if (cont.isReturnContinuation) return;
|
| + if (node.isRecursive) return;
|
| + Map<Primitive, int> target = valuesAt[cont];
|
| + if (target == null) {
|
| + valuesAt[cont] = valueOf;
|
| + } else {
|
| + for (Primitive prim in target.keys) {
|
| + target[prim] |= valueOf[prim] ?? ANY;
|
| + }
|
| + }
|
| + }
|
| +
|
| + visitBranch(Branch node) {
|
| + Primitive condition = node.condition.definition.effectiveDefinition;
|
| + Continuation trueCont = node.trueContinuation.definition;
|
| + Continuation falseCont = node.falseContinuation.definition;
|
| + if (condition.hasExactlyOneUse) {
|
| + // Handle common case specially. Do not add [condition] to the map if
|
| + // there are no other uses.
|
| + valuesAt[trueCont] = copy(valueOf);
|
| + valuesAt[falseCont] = valueOf;
|
| + return;
|
| + }
|
| + int values = valueOf[condition] ?? ANY;
|
| + int positiveValues = node.isStrictCheck ? TRUE : TRUTHY;
|
| + int negativeValues = (~positiveValues) & ANY;
|
| + if (values & positiveValues == 0) {
|
| + destroyAndReplace(node, new InvokeContinuation(falseCont, []));
|
| + valuesAt[falseCont] = valueOf;
|
| + } else if (values & negativeValues == 0) {
|
| + destroyAndReplace(node, new InvokeContinuation(trueCont, []));
|
| + valuesAt[trueCont] = valueOf;
|
| + } else {
|
| + valuesAt[trueCont] = copy(valueOf)..[condition] = values & positiveValues;
|
| + valuesAt[falseCont] = valueOf..[condition] = values & negativeValues;
|
| + }
|
| + }
|
| +}
|
|
|