diff options
author | Alon Zakai <azakai@google.com> | 2021-09-01 08:18:28 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-09-01 08:18:28 -0700 |
commit | d66d2d9bb0ea1e067c6b3e2d322a1d2357336893 (patch) | |
tree | 5ec1830c65a2ea061b903fee5e450a2509fc9488 | |
parent | 82cdabf20e496508cd241ef31a5f630c2de844ad (diff) | |
download | binaryen-d66d2d9bb0ea1e067c6b3e2d322a1d2357336893.tar.gz binaryen-d66d2d9bb0ea1e067c6b3e2d322a1d2357336893.tar.bz2 binaryen-d66d2d9bb0ea1e067c6b3e2d322a1d2357336893.zip |
Use TrapsNeverHappen mode in more places in Vacuum (#4117)
We had already replaced the check on drop, but we can also
use that mode on all the other things there, as the pass never
does reorderings of things - it just removes them.
For example, the pass can now remove part of a dropped thing,
(drop (struct.get (foo)))
=>
(drop (foo))
In this example the struct.get can be removed, even if the foo
can't.
-rw-r--r-- | src/ir/effects.h | 2 | ||||
-rw-r--r-- | src/passes/Vacuum.cpp | 6 | ||||
-rw-r--r-- | test/lit/passes/vacuum-tnh.wast | 63 |
3 files changed, 54 insertions, 17 deletions
diff --git a/src/ir/effects.h b/src/ir/effects.h index 3f0f78e6f..b9393ade2 100644 --- a/src/ir/effects.h +++ b/src/ir/effects.h @@ -169,7 +169,7 @@ public: // and gets the result that there are no unremovable side effects, then it // must either // - // 1. Remove any side effects present, if any, so they no longer exists. + // 1. Remove any side effects present, if any, so they no longer exist. // 2. Keep the code exactly where it is. // // If instead of 1&2 a pass kept the side effect and also reordered the code diff --git a/src/passes/Vacuum.cpp b/src/passes/Vacuum.cpp index dec4add01..abd54f334 100644 --- a/src/passes/Vacuum.cpp +++ b/src/passes/Vacuum.cpp @@ -103,7 +103,7 @@ struct Vacuum : public WalkerPass<ExpressionStackWalker<Vacuum>> { // Check if this expression itself has side effects, ignoring children. EffectAnalyzer self(getPassOptions(), *getModule()); self.visit(curr); - if (self.hasSideEffects()) { + if (self.hasUnremovableSideEffects()) { return curr; } // The result isn't used, and this has no side effects itself, so we can @@ -111,7 +111,7 @@ struct Vacuum : public WalkerPass<ExpressionStackWalker<Vacuum>> { SmallVector<Expression*, 1> childrenWithEffects; for (auto* child : ChildIterator(curr)) { if (EffectAnalyzer(getPassOptions(), *getModule(), child) - .hasSideEffects()) { + .hasUnremovableSideEffects()) { childrenWithEffects.push_back(child); } } @@ -378,7 +378,7 @@ struct Vacuum : public WalkerPass<ExpressionStackWalker<Vacuum>> { } if (curr->getResults() == Type::none && !EffectAnalyzer(getPassOptions(), *getModule(), curr->body) - .hasSideEffects()) { + .hasUnremovableSideEffects()) { ExpressionManipulator::nop(curr->body); } } diff --git a/test/lit/passes/vacuum-tnh.wast b/test/lit/passes/vacuum-tnh.wast index eaa63a4ae..4820a55bc 100644 --- a/test/lit/passes/vacuum-tnh.wast +++ b/test/lit/passes/vacuum-tnh.wast @@ -4,10 +4,11 @@ (module (memory 1 1) + ;; CHECK: (type $struct (struct (field (mut i32)))) + (type $struct (struct (field (mut i32)))) + ;; CHECK: (func $drop (param $x i32) (param $y anyref) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (unreachable) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) (func $drop (param $x i32) (param $y anyref) ;; A load might trap, normally, but if traps never happen then we can @@ -36,15 +37,8 @@ ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block $block (result i32) - ;; CHECK-NEXT: (local.set $x - ;; CHECK-NEXT: (i32.const 2) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (i32.load - ;; CHECK-NEXT: (local.get $x) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.set $x + ;; CHECK-NEXT: (i32.const 2) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: ) @@ -55,7 +49,7 @@ ) ;; Add to the load an additional specific side effect, of writing to a - ;; local. + ;; local. We can remove the load, but not the write to a local. (drop (block (result i32) (local.set $x (i32.const 2)) @@ -71,4 +65,47 @@ ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) (func $return-nothing) + + ;; CHECK: (func $partial (param $x (ref $struct)) + ;; CHECK-NEXT: (local $y (ref null $struct)) + ;; CHECK-NEXT: (local.set $y + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.set $y + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $partial (param $x (ref $struct)) + (local $y (ref null $struct)) + ;; The struct.get's side effect can be ignored due to tnh, and the value is + ;; dropped anyhow, so we can remove it. We cannot remove the local.tee + ;; inside it, however, so we must only vacuum out the struct.get and + ;; nothing more. (In addition, a drop of a tee will become a set.) + (drop + (struct.get $struct 0 + (local.tee $y + (local.get $x) + ) + ) + ) + ;; Similar, but with an eqz on the outside, which can also be removed. + (drop + (i32.eqz + (struct.get $struct 0 + (local.tee $y + (local.get $x) + ) + ) + ) + ) + ) + + ;; CHECK: (func $toplevel + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: ) + (func $toplevel + ;; A removable side effect at the top level of a function. We can turn this + ;; into a nop. + (unreachable) + ) ) |