summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlon Zakai <azakai@google.com>2021-09-01 08:18:28 -0700
committerGitHub <noreply@github.com>2021-09-01 08:18:28 -0700
commitd66d2d9bb0ea1e067c6b3e2d322a1d2357336893 (patch)
tree5ec1830c65a2ea061b903fee5e450a2509fc9488
parent82cdabf20e496508cd241ef31a5f630c2de844ad (diff)
downloadbinaryen-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.h2
-rw-r--r--src/passes/Vacuum.cpp6
-rw-r--r--test/lit/passes/vacuum-tnh.wast63
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)
+ )
)