summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/passes/DeadCodeElimination.cpp48
-rw-r--r--src/wasm/wasm.cpp7
-rw-r--r--test/passes/dce.txt116
-rw-r--r--test/passes/dce.wast67
-rw-r--r--test/passes/dce_vacuum.txt7
-rw-r--r--test/unit.fromasm18
-rw-r--r--test/unit.fromasm.clamp18
-rw-r--r--test/unit.fromasm.imprecise18
8 files changed, 219 insertions, 80 deletions
diff --git a/src/passes/DeadCodeElimination.cpp b/src/passes/DeadCodeElimination.cpp
index 41012fccb..33a52a09a 100644
--- a/src/passes/DeadCodeElimination.cpp
+++ b/src/passes/DeadCodeElimination.cpp
@@ -51,12 +51,20 @@ struct DeadCodeElimination : public WalkerPass<PostWalker<DeadCodeElimination>>
std::set<Name> reachableBreaks;
void addBreak(Name name) {
- assert(reachable);
- reachableBreaks.insert(name);
+ // we normally have already reduced unreachable code into (unreachable)
+ // nodes, so we would not get to this function at all anyhow, the breaking
+ // instruction itself would be removed. However, an exception are things
+ // like (block i32 (call $x) (unreachable)) , which has type i32
+ // despite not being exited.
+ // TODO: optimize such cases
+ if (reachable) {
+ reachableBreaks.insert(name);
+ }
}
- bool isDead(Expression* curr) {
- return curr && curr->is<Unreachable>();
+ // if a child is unreachable, we can replace ourselves with it
+ bool isDead(Expression* child) {
+ return child && child->type == unreachable;
}
// things that stop control flow
@@ -67,6 +75,19 @@ struct DeadCodeElimination : public WalkerPass<PostWalker<DeadCodeElimination>>
replaceCurrent(curr->value);
return;
}
+ if (isDead(curr->condition)) {
+ if (curr->value) {
+ auto* block = getModule()->allocator.alloc<Block>();
+ block->list.resize(2);
+ block->list[0] = drop(curr->value);
+ block->list[1] = curr->condition;
+ block->finalize();
+ replaceCurrent(block);
+ } else {
+ replaceCurrent(curr->condition);
+ }
+ return;
+ }
addBreak(curr->name);
if (!curr->condition) {
reachable = false;
@@ -78,6 +99,19 @@ struct DeadCodeElimination : public WalkerPass<PostWalker<DeadCodeElimination>>
replaceCurrent(curr->value);
return;
}
+ if (isDead(curr->condition)) {
+ if (curr->value) {
+ auto* block = getModule()->allocator.alloc<Block>();
+ block->list.resize(2);
+ block->list[0] = drop(curr->value);
+ block->list[1] = curr->condition;
+ block->finalize();
+ replaceCurrent(block);
+ } else {
+ replaceCurrent(curr->condition);
+ }
+ return;
+ }
for (auto target : curr->targets) {
addBreak(target);
}
@@ -137,7 +171,7 @@ struct DeadCodeElimination : public WalkerPass<PostWalker<DeadCodeElimination>>
reachable = reachable || reachableBreaks.count(curr->name);
reachableBreaks.erase(curr->name);
}
- if (curr->list.size() == 1 && isDead(curr->list[0])) {
+ if (curr->list.size() == 1 && isDead(curr->list[0]) && !BreakSeeker::has(curr->list[0], curr->name)) {
replaceCurrent(curr->list[0]);
}
}
@@ -146,7 +180,7 @@ struct DeadCodeElimination : public WalkerPass<PostWalker<DeadCodeElimination>>
if (curr->name.is()) {
reachableBreaks.erase(curr->name);
}
- if (isDead(curr->body)) {
+ if (isDead(curr->body) && !BreakSeeker::has(curr->body, curr->name)) {
replaceCurrent(curr->body);
return;
}
@@ -360,7 +394,7 @@ struct DeadCodeElimination : public WalkerPass<PostWalker<DeadCodeElimination>>
}
void visitHost(Host* curr) {
- // TODO
+ handleCall(curr);
}
void visitFunction(Function* curr) {
diff --git a/src/wasm/wasm.cpp b/src/wasm/wasm.cpp
index a983fc943..36eff681f 100644
--- a/src/wasm/wasm.cpp
+++ b/src/wasm/wasm.cpp
@@ -409,7 +409,12 @@ void Host::finalize() {
break;
}
case GrowMemory: {
- type = i32;
+ // if the single operand is not reachable, so are we
+ if (operands[0]->type == unreachable) {
+ type = unreachable;
+ } else {
+ type = i32;
+ }
break;
}
default: abort();
diff --git a/test/passes/dce.txt b/test/passes/dce.txt
index 80ba622a4..22189fb66 100644
--- a/test/passes/dce.txt
+++ b/test/passes/dce.txt
@@ -21,9 +21,7 @@
)
(if
(i32.const 0)
- (block $out3
- (return)
- )
+ (return)
)
(block $out4
(br_table $out4 $out4 $out4 $out4
@@ -40,12 +38,10 @@
)
(if
(i32.const 0)
- (block $block4
- (if
- (i32.const 0)
- (unreachable)
- (unreachable)
- )
+ (if
+ (i32.const 0)
+ (unreachable)
+ (unreachable)
)
)
(if
@@ -76,15 +72,13 @@
)
(if
(i32.const 0)
- (block $block11
- (block $out18
- (block $in19
- (br_if $in19
- (i32.const 1)
- )
+ (block $out18
+ (block $in19
+ (br_if $in19
+ (i32.const 1)
)
- (unreachable)
)
+ (unreachable)
)
)
(block $out20
@@ -105,15 +99,13 @@
)
(if
(i32.const 0)
- (block $block13
- (block $out25
- (block $in26
- (br_table $in26 $in26
- (i32.const 1)
- )
+ (block $out25
+ (block $in26
+ (br_table $in26 $in26
+ (i32.const 1)
)
- (unreachable)
)
+ (unreachable)
)
)
(if
@@ -133,7 +125,7 @@
(unreachable)
)
(block $out29
- (loop $in30
+ (block
(br_if $out29
(i32.const 1)
)
@@ -142,13 +134,11 @@
)
(if
(i32.const 0)
- (block $block20
- (loop $in32
- (br_if $in32
- (i32.const 1)
- )
- (unreachable)
+ (loop $in32
+ (br_if $in32
+ (i32.const 1)
)
+ (unreachable)
)
)
(if
@@ -300,13 +290,8 @@
)
)
(func $typed-block-none-then-unreachable (type $2) (result i32)
- (block $top-typed i32
- (block $switch$0
- (return
- (i32.const 0)
- )
- )
- (unreachable)
+ (return
+ (i32.const 0)
)
)
(func $typed-block-remove-br-changes-type (type $3) (param $$$0 i32) (result i32)
@@ -337,4 +322,61 @@
(i32.const 0)
)
)
+ (func $unreachable-br (type $2) (result i32)
+ (block $out i32
+ (br $out
+ (i32.const 0)
+ )
+ )
+ )
+ (func $unreachable-br-loop (type $2) (result i32)
+ (loop $out
+ (br $out)
+ )
+ )
+ (func $unreachable-block-ends-switch (type $2) (result i32)
+ (block $label$0 i32
+ (block $label$3
+ (nop)
+ (unreachable)
+ )
+ (unreachable)
+ )
+ )
+ (func $unreachable-block-ends-br_if (type $1) (result i32)
+ (block $label$0 i32
+ (block $label$2
+ (nop)
+ (unreachable)
+ )
+ (unreachable)
+ )
+ )
+ (func $unreachable-brs-3 (type $2) (result i32)
+ (block $label$0 i32
+ (br $label$0
+ (i32.const 18)
+ )
+ )
+ )
+ (func $unreachable-brs-4 (type $3) (param $var$0 i32) (result i32)
+ (i32.add
+ (i32.const 1)
+ (block $label$0 i32
+ (br $label$0
+ (block $label$1 i32
+ (drop
+ (block
+ (drop
+ (i32.const 4104)
+ )
+ (unreachable)
+ )
+ )
+ (unreachable)
+ )
+ )
+ )
+ )
+ )
)
diff --git a/test/passes/dce.wast b/test/passes/dce.wast
index 0bed1e8ff..865f373cf 100644
--- a/test/passes/dce.wast
+++ b/test/passes/dce.wast
@@ -442,4 +442,71 @@
(nop)
(i32.const 0)
)
+ (func $unreachable-br (result i32)
+ (block $out i32
+ (br $out
+ (br $out (i32.const 0))
+ )
+ )
+ )
+ (func $unreachable-br-loop (result i32)
+ (loop $out
+ (br $out)
+ )
+ )
+ (func $unreachable-block-ends-switch (result i32)
+ (block $label$0 i32
+ (block $label$3
+ (nop)
+ (br_table $label$3
+ (unreachable)
+ )
+ (unreachable)
+ )
+ (i32.const 19)
+ )
+ )
+ (func $unreachable-block-ends-br_if (type $1) (result i32)
+ (block $label$0 i32
+ (block $label$2
+ (nop)
+ (br_if $label$2
+ (unreachable)
+ )
+ (unreachable)
+ )
+ (i32.const 19)
+ )
+ )
+ (func $unreachable-brs-3 (result i32)
+ (block $label$0 i32
+ (br $label$0
+ (grow_memory
+ (br $label$0
+ (i32.const 18)
+ )
+ )
+ )
+ (i32.const 21)
+ )
+ )
+ (func $unreachable-brs-4 (param $var$0 i32) (result i32)
+ (i32.add
+ (i32.const 1)
+ (block $label$0 i32
+ (br $label$0
+ (block $label$1 i32 ;; this block is declared i32, but we can see it is unreachable
+ (drop
+ (br_if $label$0
+ (i32.const 4104)
+ (unreachable)
+ )
+ )
+ (i32.const 4)
+ )
+ )
+ (i32.const 16)
+ )
+ )
+ )
)
diff --git a/test/passes/dce_vacuum.txt b/test/passes/dce_vacuum.txt
index 157339e9b..4fb982524 100644
--- a/test/passes/dce_vacuum.txt
+++ b/test/passes/dce_vacuum.txt
@@ -2,11 +2,8 @@
(type $0 (func (result i32)))
(memory $0 0)
(func $__Z12serveroptionPc (type $0) (result i32)
- (block $switch$0
- (return
- (i32.const 0)
- )
+ (return
+ (i32.const 0)
)
- (unreachable)
)
)
diff --git a/test/unit.fromasm b/test/unit.fromasm
index 45dc81937..580057f82 100644
--- a/test/unit.fromasm
+++ b/test/unit.fromasm
@@ -197,16 +197,14 @@
(i32.const 51)
)
)
- (block $label$break$Lout
- (block $switch-case9
- (block $switch-case6
- (block $switch-case5
- (block $switch-case4
- (br_table $switch-case9 $label$break$Lout $label$break$Lout $switch-case6 $label$break$Lout $label$break$Lout $label$break$Lout $label$break$Lout $switch-case5 $label$break$Lout $switch-case4 $label$break$Lout
- (i32.sub
- (get_local $0)
- (i32.const 2)
- )
+ (block $switch-case9
+ (block $switch-case6
+ (block $switch-case5
+ (block $switch-case4
+ (br_table $switch-case9 $switch-case9 $switch-case9 $switch-case6 $switch-case9 $switch-case9 $switch-case9 $switch-case9 $switch-case5 $switch-case9 $switch-case4 $switch-case9
+ (i32.sub
+ (get_local $0)
+ (i32.const 2)
)
)
)
diff --git a/test/unit.fromasm.clamp b/test/unit.fromasm.clamp
index 469c4932b..7bfcdd531 100644
--- a/test/unit.fromasm.clamp
+++ b/test/unit.fromasm.clamp
@@ -221,16 +221,14 @@
(i32.const 51)
)
)
- (block $label$break$Lout
- (block $switch-case9
- (block $switch-case6
- (block $switch-case5
- (block $switch-case4
- (br_table $switch-case9 $label$break$Lout $label$break$Lout $switch-case6 $label$break$Lout $label$break$Lout $label$break$Lout $label$break$Lout $switch-case5 $label$break$Lout $switch-case4 $label$break$Lout
- (i32.sub
- (get_local $0)
- (i32.const 2)
- )
+ (block $switch-case9
+ (block $switch-case6
+ (block $switch-case5
+ (block $switch-case4
+ (br_table $switch-case9 $switch-case9 $switch-case9 $switch-case6 $switch-case9 $switch-case9 $switch-case9 $switch-case9 $switch-case5 $switch-case9 $switch-case4 $switch-case9
+ (i32.sub
+ (get_local $0)
+ (i32.const 2)
)
)
)
diff --git a/test/unit.fromasm.imprecise b/test/unit.fromasm.imprecise
index 3254980d9..f78f530c1 100644
--- a/test/unit.fromasm.imprecise
+++ b/test/unit.fromasm.imprecise
@@ -178,16 +178,14 @@
(i32.const 51)
)
)
- (block $label$break$Lout
- (block $switch-case9
- (block $switch-case6
- (block $switch-case5
- (block $switch-case4
- (br_table $switch-case9 $label$break$Lout $label$break$Lout $switch-case6 $label$break$Lout $label$break$Lout $label$break$Lout $label$break$Lout $switch-case5 $label$break$Lout $switch-case4 $label$break$Lout
- (i32.sub
- (get_local $0)
- (i32.const 2)
- )
+ (block $switch-case9
+ (block $switch-case6
+ (block $switch-case5
+ (block $switch-case4
+ (br_table $switch-case9 $switch-case9 $switch-case9 $switch-case6 $switch-case9 $switch-case9 $switch-case9 $switch-case9 $switch-case5 $switch-case9 $switch-case4 $switch-case9
+ (i32.sub
+ (get_local $0)
+ (i32.const 2)
)
)
)