diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/passes/DeadCodeElimination.cpp | 48 | ||||
-rw-r--r-- | src/wasm/wasm.cpp | 7 |
2 files changed, 47 insertions, 8 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(); |