-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
dart2js cps: Eliminate duplicate branches.
BUG= R=sra@google.com Review URL: https://codereview.chromium.org/1585923010 .
- Loading branch information
Showing
4 changed files
with
127 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters