Skip to content

Commit

Permalink
dart2js cps: Hoist unsafe expressions from loop entry.
Browse files Browse the repository at this point in the history
Primitives that potentially throw cannot normally be hoisted, but we can
sometimes hoist them anyway if they are at the loop entry.

We now hoist GetLength, GetField, GetIndex, NullCheck, and BoundsCheck.

BUG=
[email protected]

Review URL: https://codereview.chromium.org/1578963002 .
  • Loading branch information
asgerf committed Jan 12, 2016
1 parent e6cc028 commit c85916d
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 7 deletions.
50 changes: 44 additions & 6 deletions pkg/compiler/lib/src/cps_ir/gvn.dart
Original file line number Diff line number Diff line change
Expand Up @@ -176,15 +176,48 @@ class GVN extends TrampolineRecursiveVisitor implements Pass {
return next;
}

bool isFirstImpureExpressionInLoop(Expression exp) {
InteriorNode node = exp.parent;
for (; node is Expression; node = node.parent) {
if (node is LetPrim && node.primitive.isSafeForElimination) {
continue;
}
if (node is LetCont) {
continue;
}
return false;
}
return node == currentLoopHeader;
}

bool isHoistablePrimitive(Primitive prim) {
if (prim.isSafeForElimination) return true;
if (prim is NullCheck ||
prim is BoundsCheck ||
prim is GetLength ||
prim is GetField ||
prim is GetIndex) {
// Expressions that potentially throw but have no other effects can be
// hoisted if they occur as the first impure expression in a loop.
// Note regarding BoundsCheck: the current array length is an input to
// check, so the check itself has no heap dependency. It will only be
// hoisted if the length was hoisted.
// TODO(asgerf): In general we could hoist these out of multiple loops,
// but the trick we use here only works for one loop level.
return isFirstImpureExpressionInLoop(prim.parent);
}
return false;
}

/// Try to hoist the binding of [prim] out of loops. Returns `true` if it was
/// hoisted or marked as a trivial hoist-on-demand primitive.
bool tryToHoistOutOfLoop(Primitive prim, int gvn) {
// Do not hoist primitives with side effects.
if (!prim.isSafeForElimination) return false;

// Bail out fast if the primitive is not inside a loop.
if (currentLoopHeader == null) return false;

// Do not hoist primitives with side effects.
if (!isHoistablePrimitive(prim)) return false;

LetPrim letPrim = prim.parent;

// Find the depth of the outermost scope where we can bind the primitive
Expand Down Expand Up @@ -327,9 +360,15 @@ class GVN extends TrampolineRecursiveVisitor implements Pass {
}

/// Assuming [prim] has no side effects, returns true if it can safely
/// be hoisted out of [loop] without changing its value.
/// be hoisted out of [loop] without changing its value or changing the timing
/// of a thrown exception.
bool canHoistHeapDependencyOutOfLoop(Primitive prim, Continuation loop) {
assert(prim.isSafeForElimination);
// If the primitive might throw, we have to check that it is the first
// impure expression in the loop. This has already been checked if
// [loop] is the current loop header, but for other loops we just give up.
if (!prim.isSafeForElimination && loop != currentLoopHeader) {
return false;
}
if (prim is GetLength && !isImmutableLength(prim)) {
return !loopEffects.loopChangesLength(loop);
} else if (prim is GetField && !isImmutable(prim.field)) {
Expand All @@ -343,7 +382,6 @@ class GVN extends TrampolineRecursiveVisitor implements Pass {
}
}


// ------------------ TRAVERSAL AND EFFECT NUMBERING ---------------------
//
// These methods traverse the IR while updating the current effect numbers.
Expand Down
3 changes: 2 additions & 1 deletion tests/compiler/dart2js/cps_ir/expected/codeUnitAt_2.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@ function() {
for (; i < v0; sum += "ABC".charCodeAt(i), ++i)
;
P.print(sum);
v0 = "Hello".length;
sum = 0;
for (i = 0; i < "Hello".length; sum += "Hello".charCodeAt(i), ++i)
for (i = 0; i < v0; sum += "Hello".charCodeAt(i), ++i)
;
P.print(sum);
}

0 comments on commit c85916d

Please sign in to comment.