summaryrefslogtreecommitdiff
path: root/src/ir/effects.h
diff options
context:
space:
mode:
authorHeejin Ahn <aheejin@gmail.com>2020-06-03 00:12:15 -0700
committerGitHub <noreply@github.com>2020-06-03 00:12:15 -0700
commit501b0a08fafd2b4d2fbb5dd6a4320641bfc823b1 (patch)
tree9f3ea2e81941baa532818e53a5a8bc1ac19a97d5 /src/ir/effects.h
parent3c4630bbe90752c7c720da4ad3805808852b8566 (diff)
downloadbinaryen-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.h30
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;
}