Index: pkg/compiler/lib/src/ssa/codegen_helpers.dart |
diff --git a/pkg/compiler/lib/src/ssa/codegen_helpers.dart b/pkg/compiler/lib/src/ssa/codegen_helpers.dart |
index 254e577a31f6141119a0e9d6f9c1fd77a60370a7..681056f6ce29c694a6765c1b4b8a75f95c323d1d 100644 |
--- a/pkg/compiler/lib/src/ssa/codegen_helpers.dart |
+++ b/pkg/compiler/lib/src/ssa/codegen_helpers.dart |
@@ -353,7 +353,7 @@ class SsaInstructionMerger extends HBaseVisitor { |
input is! HPhi && |
input is! HLocalValue && |
!input.isJsStatement()) { |
- if (input.isPure()) { |
+ if (isEffectivelyPure(input)) { |
// Only consider a pure input if it is in the same loop. |
// Otherwise, we might move GVN'ed instruction back into the |
// loop. |
@@ -382,6 +382,25 @@ class SsaInstructionMerger extends HBaseVisitor { |
} |
} |
+ // Some non-pure instructions may be treated as pure. HLocalGet depends on |
+ // assignments, but we can ignore the initializing assignment since it will by |
+ // construction always precede a use. |
+ bool isEffectivelyPure(HInstruction instruction) { |
+ if (instruction is HLocalGet) return !isAssignedLocal(instruction.local); |
+ return instruction.isPure(); |
+ } |
+ |
+ bool isAssignedLocal(HLocalValue local) { |
+ // [HLocalValue]s have an initializing assignment which is guaranteed to |
+ // precede the use, except for [HParameterValue]s which are 'assigned' at |
+ // entry. |
+ int initializingAssignmentCount = (local is HParameterValue) ? 0 : 1; |
+ return local.usedBy |
+ .where((user) => user is HLocalSet) |
+ .skip(initializingAssignmentCount) |
+ .isNotEmpty; |
+ } |
+ |
void visitInstruction(HInstruction instruction) { |
// A code motion invariant instruction is dealt before visiting it. |
assert(!instruction.isCodeMotionInvariant()); |
@@ -481,7 +500,7 @@ class SsaInstructionMerger extends HBaseVisitor { |
// Pop instructions from expectedInputs until instruction is found. |
// Return true if it is found, or false if not. |
bool findInInputsAndPopNonMatching(HInstruction instruction) { |
- assert(!instruction.isPure()); |
+ assert(!isEffectivelyPure(instruction)); |
while (!expectedInputs.isEmpty) { |
HInstruction nextInput = expectedInputs.removeLast(); |
assert(!generateAtUseSite.contains(nextInput)); |
@@ -504,7 +523,7 @@ class SsaInstructionMerger extends HBaseVisitor { |
markAsGenerateAtUseSite(instruction); |
continue; |
} |
- if (instruction.isPure()) { |
+ if (isEffectivelyPure(instruction)) { |
if (pureInputs.contains(instruction)) { |
tryGenerateAtUseSite(instruction); |
} else { |
@@ -550,7 +569,7 @@ class SsaInstructionMerger extends HBaseVisitor { |
// push expected-inputs from left-to right, and the `pure` function |
// invocation is "more left" (i.e. before) the first argument of `f`. |
// With that approach we end up with: |
- // t3 = pure(foo(); |
+ // t3 = pure(foo()); |
// f(bar(), t3); |
// use(t3); |
// |