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

Unified Diff: pkg/compiler/lib/src/cps_ir/redundant_join.dart

Issue 2246623002: Delete CPS IR (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 4 years, 4 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 side-by-side diff with in-line comments
Download patch
Index: pkg/compiler/lib/src/cps_ir/redundant_join.dart
diff --git a/pkg/compiler/lib/src/cps_ir/redundant_join.dart b/pkg/compiler/lib/src/cps_ir/redundant_join.dart
deleted file mode 100644
index 3ba1d617635213dae487f114d0f207949ef0eec3..0000000000000000000000000000000000000000
--- a/pkg/compiler/lib/src/cps_ir/redundant_join.dart
+++ /dev/null
@@ -1,262 +0,0 @@
-// Copyright (c) 2015, 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.redundant_join_elimination;
-
-import 'cps_ir_nodes.dart';
-import 'optimizers.dart';
-
-/// Eliminates redundant join points.
-///
-/// A redundant join point is a continuation that immediately branches
-/// based on one of its parameters, and that parameter is a constant value
-/// at every invocation. Each invocation is redirected to jump directly
-/// to the branch target.
-///
-/// Internally in this pass, parameters are treated as names with lexical
-/// scoping, and a given parameter "name" may be declared by more than
-/// one continuation. The reference chains for parameters are therefore
-/// meaningless during this pass, until repaired by [AlphaRenamer] at
-/// the end.
-class RedundantJoinEliminator extends TrampolineRecursiveVisitor
- implements Pass {
- String get passName => 'Redundant join elimination';
-
- final Set<Branch> workSet = new Set<Branch>();
-
- void rewrite(FunctionDefinition node) {
- visit(node);
-
- while (workSet.isNotEmpty) {
- Branch branch = workSet.first;
- workSet.remove(branch);
- rewriteBranch(branch);
- }
-
- new AlphaRenamer().visit(node);
- }
-
- void processBranch(Branch node) {
- workSet.add(node);
- }
-
- /// Returns the body of [node], ignoring all LetCont nodes.
- Expression getEffectiveBody(InteriorNode node) {
- while (true) {
- Expression body = node.body;
- if (body is LetCont) {
- node = body;
- } else {
- return body;
- }
- }
- }
-
- /// Returns the parent of [node], ignoring all LetCont nodes.
- InteriorNode getEffectiveParent(Expression node) {
- while (true) {
- Node parent = node.parent;
- if (parent is LetCont) {
- node = parent;
- } else {
- return parent;
- }
- }
- }
-
- void rewriteBranch(Branch branch) {
- InteriorNode parent = getEffectiveParent(branch);
- if (parent is! Continuation) return;
- Continuation branchCont = parent;
-
- // Other optimizations take care of single-use continuations.
- if (!branchCont.hasMultipleUses) return;
-
- // It might be beneficial to rewrite calls to recursive continuations,
- // but we currently do not support this.
- if (branchCont.isRecursive) return;
-
- // Check that the branching condition is a parameter on the
- // enclosing continuation.
- // Note: Do not use the parent pointer for this check, because parameters
- // are temporarily shared between different continuations during this pass.
- Primitive condition = branch.condition;
- int parameterIndex = branchCont.parameters.indexOf(condition);
- if (parameterIndex == -1) return;
-
- // Check that all callers hit a fixed branch, and count the number
- // of times each branch is hit.
- // We know all callers are InvokeContinuations because they are the only
- // valid uses of a multi-use continuation.
- int trueHits = 0, falseHits = 0;
- InvokeContinuation trueCall, falseCall;
- for (Reference ref = branchCont.firstRef; ref != null; ref = ref.next) {
- InvokeContinuation invoke = ref.parent;
- Primitive argument = invoke.argument(parameterIndex);
- if (argument is! Constant) return; // Branching condition is unknown.
- Constant constant = argument;
- if (isTruthyConstant(constant.value, strict: branch.isStrictCheck)) {
- ++trueHits;
- trueCall = invoke;
- } else {
- ++falseHits;
- falseCall = invoke;
- }
- }
-
- // The optimization is now known to be safe, but it only pays off if
- // one of the callers can inline its target, since otherwise we end up
- // replacing a boolean variable with a labeled break.
- // TODO(asgerf): The labeled break might be better? Evaluate.
- if (!(trueHits == 1 && !trueCall.isEscapingTry ||
- falseHits == 1 && !falseCall.isEscapingTry)) {
- return;
- }
-
- // Lift any continuations bound inside branchCont so they are in scope at
- // the call sites. When lifting, the parameters of branchCont fall out of
- // scope, so they are added as parameters on each lifted continuation.
- // Schematically:
- //
- // (LetCont (branchCont (x1, x2, x3) =
- // (LetCont (innerCont (y) = ...) in
- // [... innerCont(y') ...]))
- //
- // =>
- //
- // (LetCont (innerCont (y, x1, x2, x3) = ...) in
- // (LetCont (branchCont (x1, x2, x3) =
- // [... innerCont(y', x1, x2, x3) ...])
- //
- // Parameter objects become shared between branchCont and the lifted
- // continuations. [AlphaRenamer] will clean up at the end of this pass.
- LetCont outerLetCont = branchCont.parent;
- while (branchCont.body is LetCont) {
- LetCont innerLetCont = branchCont.body;
- for (Continuation innerCont in innerLetCont.continuations) {
- innerCont.parameters.addAll(branchCont.parameters);
- for (Reference ref = innerCont.firstRef; ref != null; ref = ref.next) {
- Expression use = ref.parent;
- if (use is InvokeContinuation) {
- for (Parameter param in branchCont.parameters) {
- use.argumentRefs
- .add(new Reference<Primitive>(param)..parent = use);
- }
- } else {
- // The branch will be eliminated, so don't worry about updating it.
- assert(use == branch);
- }
- }
- }
- innerLetCont.remove();
- innerLetCont.insertAbove(outerLetCont);
- }
-
- assert(branchCont.body == branch);
-
- Continuation trueCont = branch.trueContinuation;
- Continuation falseCont = branch.falseContinuation;
-
- assert(branchCont != trueCont);
- assert(branchCont != falseCont);
-
- // Rewrite every invocation of branchCont to call either the true or false
- // branch directly. Since these were lifted out above branchCont, they are
- // now in scope.
- // Since trueCont and falseCont were branch targets, they originally
- // had no parameters, and so after the lifting, their parameters are
- // exactly the same as those accepted by branchCont.
- while (branchCont.firstRef != null) {
- Reference reference = branchCont.firstRef;
- InvokeContinuation invoke = branchCont.firstRef.parent;
- Constant condition = invoke.argument(parameterIndex);
- if (isTruthyConstant(condition.value, strict: branch.isStrictCheck)) {
- invoke.continuationRef.changeTo(trueCont);
- } else {
- invoke.continuationRef.changeTo(falseCont);
- }
- assert(branchCont.firstRef != reference);
- }
-
- // Remove the now-unused branchCont continuation.
- assert(branchCont.hasNoUses);
- branch.trueContinuationRef.unlink();
- branch.falseContinuationRef.unlink();
- outerLetCont.continuations.remove(branchCont);
- if (outerLetCont.continuations.isEmpty) {
- outerLetCont.remove();
- }
-
- // We may have created new redundant join points in the two branches.
- enqueueContinuation(trueCont);
- enqueueContinuation(falseCont);
- }
-
- void enqueueContinuation(Continuation cont) {
- Expression body = getEffectiveBody(cont);
- if (body is Branch) {
- workSet.add(body);
- }
- }
-}
-
-/// Ensures parameter objects are not shared between different continuations,
-/// akin to alpha-renaming variables so every variable is named uniquely.
-/// For example:
-///
-/// LetCont (k1 x = (return x)) in
-/// LetCont (k2 x = (InvokeContinuation k3 x)) in ...
-/// =>
-/// LetCont (k1 x = (return x)) in
-/// LetCont (k2 x' = (InvokeContinuation k3 x')) in ...
-///
-/// After lifting LetConts in the main pass above, parameter objects can have
-/// multiple bindings. Each reference implicitly refers to the binding that
-/// is currently in scope.
-///
-/// This returns the IR to its normal form after redundant joins have been
-/// eliminated.
-class AlphaRenamer extends TrampolineRecursiveVisitor {
- Map<Parameter, Parameter> renaming = <Parameter, Parameter>{};
-
- processContinuation(Continuation cont) {
- if (cont.isReturnContinuation) return;
-
- List<Parameter> shadowedKeys = <Parameter>[];
- List<Parameter> shadowedValues = <Parameter>[];
-
- // Create new parameters and update the environment.
- for (int i = 0; i < cont.parameters.length; ++i) {
- Parameter param = cont.parameters[i];
- shadowedKeys.add(param);
- shadowedValues.add(renaming.remove(param));
- // If the parameter appears to belong to another continuation,
- // create a new parameter object for this continuation.
- if (param.parent != cont) {
- Parameter newParam = new Parameter(param.hint);
- newParam.type = param.type;
- renaming[param] = newParam;
- cont.parameters[i] = newParam;
- newParam.parent = cont;
- }
- }
-
- pushAction(() {
- // Restore the original environment.
- for (int i = 0; i < cont.parameters.length; ++i) {
- renaming.remove(cont.parameters[i]);
- if (shadowedValues[i] != null) {
- renaming[shadowedKeys[i]] = shadowedValues[i];
- }
- }
- });
- }
-
- processReference(Reference ref) {
- Parameter target = renaming[ref.definition];
- if (target != null) {
- ref.changeTo(target);
- }
- }
-}
« no previous file with comments | « pkg/compiler/lib/src/cps_ir/path_based_optimizer.dart ('k') | pkg/compiler/lib/src/cps_ir/redundant_phi.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698