diff options
-rw-r--r-- | src/passes/LocalCSE.cpp | 12 | ||||
-rw-r--r-- | test/lit/passes/local-cse_all-features.wast | 52 |
2 files changed, 63 insertions, 1 deletions
diff --git a/src/passes/LocalCSE.cpp b/src/passes/LocalCSE.cpp index bb017e938..63704382e 100644 --- a/src/passes/LocalCSE.cpp +++ b/src/passes/LocalCSE.cpp @@ -421,6 +421,16 @@ struct Checker // hashed expressions, if there are any. if (!activeOriginals.empty()) { EffectAnalyzer effects(options, *getModule()); + // We can ignore traps here: + // + // (ORIGINAL) + // (curr) + // (COPY) + // + // We are some code in between an original and a copy of it, and we are + // trying to turn COPY into a local.get of a value that we stash at the + // original. If |curr| traps then we simply don't reach the copy anyhow. + effects.trap = false; // We only need to visit this node itself, as we have already visited its // children by the time we get here. effects.visit(curr); @@ -460,7 +470,7 @@ struct Checker if (info.requests > 0) { // This is an original. Compute its side effects, as we cannot optimize - // away repeated apperances if it has any. + // away repeated appearances if it has any. EffectAnalyzer effects(options, *getModule(), curr); // We can ignore traps here, as we replace a repeating expression with a diff --git a/test/lit/passes/local-cse_all-features.wast b/test/lit/passes/local-cse_all-features.wast index cbd5c68c2..d943b940f 100644 --- a/test/lit/passes/local-cse_all-features.wast +++ b/test/lit/passes/local-cse_all-features.wast @@ -350,3 +350,55 @@ ) ) ) + +(module + ;; CHECK: (type $struct (struct (field i32))) + (type $struct (struct (field i32))) + + ;; CHECK: (type $1 (func (param anyref))) + + ;; CHECK: (type $2 (func (param i32))) + + ;; CHECK: (func $caller (type $1) (param $x anyref) + ;; CHECK-NEXT: (local $1 i32) + ;; CHECK-NEXT: (call $callee + ;; CHECK-NEXT: (local.tee $1 + ;; CHECK-NEXT: (struct.get $struct 0 + ;; CHECK-NEXT: (ref.cast (ref $struct) + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (call $callee + ;; CHECK-NEXT: (local.get $1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $caller (param $x anyref) + (call $callee + (struct.get $struct 0 + (ref.cast (ref $struct) + (local.get $x) + ) + ) + ) + ;; The call in between the struct.get has effects, but they do not + ;; interfere: the struct.get reads locals and immutable data only, and we + ;; can ignore possible traps in both the call and the struct.get (as if + ;; anything traps we just don't reach the local.get that the optimization + ;; emits). + (call $callee + (struct.get $struct 0 + (ref.cast (ref $struct) + (local.get $x) + ) + ) + ) + ) + + ;; CHECK: (func $callee (type $2) (param $x i32) + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: ) + (func $callee (param $x i32) + ) +) |