diff options
author | Heejin Ahn <aheejin@gmail.com> | 2020-06-03 00:12:15 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-06-03 00:12:15 -0700 |
commit | 501b0a08fafd2b4d2fbb5dd6a4320641bfc823b1 (patch) | |
tree | 9f3ea2e81941baa532818e53a5a8bc1ac19a97d5 /src/ir/effects.h | |
parent | 3c4630bbe90752c7c720da4ad3805808852b8566 (diff) | |
download | binaryen-501b0a08fafd2b4d2fbb5dd6a4320641bfc823b1.tar.gz binaryen-501b0a08fafd2b4d2fbb5dd6a4320641bfc823b1.tar.bz2 binaryen-501b0a08fafd2b4d2fbb5dd6a4320641bfc823b1.zip |
Prevent pops from sinking in SimplifyLocals (#2885)
This prevents `exnref.pop`s from being sinked and separated from
`catch`. For example,
```wast
(try
(do)
(catch
(local.set $0 (exnref.pop))
(call $foo
(i32.const 3)
(local.get $0)
)
)
)
```
Here, if we sink `exnref.pop` to remove `local.set $0` and
`local.get $0`, it becomes this:
```wast
(try
(do)
(catch
(nop)
(call $foo
(i32.const 3)
(exnref.pop)
)
)
)
```
This move was possible because `i32.const 3` does not have any side
effects. But this is incorrect because now `exnref.pop` does not follow
right after `catch`.
To prevent this, this patch checks this case in `canSink` in
SimplifyLocals. When we encountered a similar case in CodeFolding, we
prevented every expression that contains `Pop` anywhere in it from being
moved, which was too conservative. This adds `danglingPop` property in
`EffectAnalyzer`, so that only pops that are not enclosed within a
`catch` count as 'dangling pops` and we only prevent those pops from
being moved or sinked.
Diffstat (limited to 'src/ir/effects.h')
-rw-r--r-- | src/ir/effects.h | 30 |
1 files changed, 26 insertions, 4 deletions
diff --git a/src/ir/effects.h b/src/ir/effects.h index d2afc8133..f6c87a4e5 100644 --- a/src/ir/effects.h +++ b/src/ir/effects.h @@ -76,6 +76,11 @@ struct EffectAnalyzer // inner try, we don't mark it as 'throws', because it will be caught by an // inner catch. size_t tryDepth = 0; + // The nested depth of catch. This is necessary to track danglng pops. + size_t catchDepth = 0; + // If this expression contains 'exnref.pop's that are not enclosed in 'catch' + // body. For example, (drop (exnref.pop)) should set this to true. + bool danglingPop = false; static void scan(EffectAnalyzer* self, Expression** currp) { Expression* curr = *currp; @@ -83,6 +88,7 @@ struct EffectAnalyzer // separately if (curr->is<Try>()) { self->pushTask(doVisitTry, currp); + self->pushTask(doEndCatch, currp); self->pushTask(scan, &curr->cast<Try>()->catchBody); self->pushTask(doStartCatch, currp); self->pushTask(scan, &curr->cast<Try>()->body); @@ -100,6 +106,12 @@ struct EffectAnalyzer static void doStartCatch(EffectAnalyzer* self, Expression** currp) { assert(self->tryDepth > 0 && "try depth cannot be negative"); self->tryDepth--; + self->catchDepth++; + } + + static void doEndCatch(EffectAnalyzer* self, Expression** currp) { + assert(self->catchDepth > 0 && "catch depth cannot be negative"); + self->catchDepth--; } // Helper functions to check for various effect types @@ -128,7 +140,7 @@ struct EffectAnalyzer } bool hasSideEffects() const { return hasGlobalSideEffects() || localsWritten.size() > 0 || - transfersControlFlow() || implicitTrap; + transfersControlFlow() || implicitTrap || danglingPop; } bool hasAnything() const { return hasSideEffects() || accessesLocal() || readsMemory || @@ -148,7 +160,8 @@ struct EffectAnalyzer if ((transfersControlFlow() && other.hasSideEffects()) || (other.transfersControlFlow() && hasSideEffects()) || ((writesMemory || calls) && other.accessesMemory()) || - (accessesMemory() && (other.writesMemory || other.calls))) { + (accessesMemory() && (other.writesMemory || other.calls)) || + (danglingPop || other.danglingPop)) { return true; } // All atomics are sequentially consistent for now, and ordered wrt other @@ -203,6 +216,7 @@ struct EffectAnalyzer implicitTrap = implicitTrap || other.implicitTrap; isAtomic = isAtomic || other.isAtomic; throws = throws || other.throws; + danglingPop = danglingPop || other.danglingPop; for (auto i : other.localsRead) { localsRead.insert(i); } @@ -470,7 +484,11 @@ struct EffectAnalyzer } void visitNop(Nop* curr) {} void visitUnreachable(Unreachable* curr) { branchesOut = true; } - void visitPop(Pop* curr) { calls = true; } + void visitPop(Pop* curr) { + if (catchDepth == 0) { + danglingPop = true; + } + } void visitTupleMake(TupleMake* curr) {} void visitTupleExtract(TupleExtract* curr) {} @@ -500,7 +518,8 @@ struct EffectAnalyzer ImplicitTrap = 1 << 8, IsAtomic = 1 << 9, Throws = 1 << 10, - Any = (1 << 11) - 1 + DanglingPop = 1 << 11, + Any = (1 << 12) - 1 }; uint32_t getSideEffects() const { uint32_t effects = 0; @@ -537,6 +556,9 @@ struct EffectAnalyzer if (throws) { effects |= SideEffects::Throws; } + if (danglingPop) { + effects |= SideEffects::DanglingPop; + } return effects; } |