summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlon Zakai <azakai@google.com>2020-10-26 18:43:29 -0700
committerGitHub <noreply@github.com>2020-10-26 18:43:29 -0700
commitf3125579cca998300c230232ed4ded4fe0aaa34c (patch)
treeaeceb7770b47fe8d5eef0f38e26fa540b67db482
parent514a6c5eb339b67db852643405428f3add7d0e39 (diff)
downloadbinaryen-f3125579cca998300c230232ed4ded4fe0aaa34c.tar.gz
binaryen-f3125579cca998300c230232ed4ded4fe0aaa34c.tar.bz2
binaryen-f3125579cca998300c230232ed4ded4fe0aaa34c.zip
Rewrite DCE pass (#3274)
The DCE pass is one of the oldest in binaryen, and had quite a lot of cruft from the changes in unreachability and other stuff in wasm and binaryen's history. This PR rewrites it from scratch, making it about 1/3 the size. I noticed this when looking for places to use code autogeneration. The old version had annoying boilerplate, while the new one avoids any need for it. There may be noticeable differences, as the old pass did more than it needed to. It overlapped with remove-unused-names for some reason I don't remember. The new pass leaves that to the other pass to do. I added another run of remove-unused-names to avoid noticeable differences in optimized builds, but you can see differences in the testcases that only run DCE by itself. (The test differences in this PR are mostly whitespace.) (The overlap is that if a block ended up not needed, that is, all branches to it were removed, the old DCE would remove the block.) This pass is about 15% faster than the old version. However, when adding another run of remove-unused-names the difference basically vanishes, so this isn't a speedup.
-rw-r--r--src/ir/type-updating.h12
-rw-r--r--src/passes/Asyncify.cpp1
-rw-r--r--src/passes/DeadCodeElimination.cpp588
-rw-r--r--src/passes/pass.cpp1
-rw-r--r--test/passes/asyncify_enable-multivalue.txt408
-rw-r--r--test/passes/asyncify_mod-asyncify-always-and-only-unwind.txt74
-rw-r--r--test/passes/asyncify_mod-asyncify-never-unwind.txt76
-rw-r--r--test/passes/asyncify_pass-arg=asyncify-imports@env.import,env.import2.txt252
-rw-r--r--test/passes/dce_all-features.txt243
-rw-r--r--test/passes/dce_all-features.wast57
-rw-r--r--test/passes/dce_vacuum.bin.txt98
-rw-r--r--test/passes/dce_vacuum_remove-unused-names.bin.txt94
-rw-r--r--test/passes/dce_vacuum_remove-unused-names.txt (renamed from test/passes/dce_vacuum.txt)0
-rw-r--r--test/passes/dce_vacuum_remove-unused-names.wasm (renamed from test/passes/dce_vacuum.wasm)bin260 -> 260 bytes
-rw-r--r--test/passes/dce_vacuum_remove-unused-names.wast (renamed from test/passes/dce_vacuum.wast)0
-rw-r--r--test/passes/interesting-pass-mix.txt19
-rw-r--r--test/wasm2js/br.2asm.js22
-rw-r--r--test/wasm2js/br_table.2asm.js34
-rw-r--r--test/wasm2js/br_table_temp.2asm.js34
-rw-r--r--test/wasm2js/excess_fallthrough.2asm.js28
20 files changed, 926 insertions, 1115 deletions
diff --git a/src/ir/type-updating.h b/src/ir/type-updating.h
index c028d3b5b..1a1086a0c 100644
--- a/src/ir/type-updating.h
+++ b/src/ir/type-updating.h
@@ -147,6 +147,14 @@ struct TypeUpdater
discoverBreaks(curr, parent ? +1 : -1);
}
+ // Applies a type change to a node, and potentially to its parents.
+ void changeType(Expression* curr, Type type) {
+ if (curr->type != type) {
+ curr->type = type;
+ propagateTypesUp(curr);
+ }
+ }
+
// adds (or removes) breaks depending on break/switch contents
void discoverBreaks(Expression* curr, int change) {
if (auto* br = curr->dynCast<Break>()) {
@@ -314,6 +322,10 @@ struct TypeUpdater
propagateTypesUp(curr);
}
}
+
+ bool hasBreaks(Block* block) {
+ return block->name.is() && blockInfos[block->name].numBreaks > 0;
+ }
};
} // namespace wasm
diff --git a/src/passes/Asyncify.cpp b/src/passes/Asyncify.cpp
index 1524bd6c3..3cf0a76d2 100644
--- a/src/passes/Asyncify.cpp
+++ b/src/passes/Asyncify.cpp
@@ -1488,6 +1488,7 @@ struct Asyncify : public Pass {
// because the flow changes add many branches, break up if-elses, etc.,
// all of which extend the live ranges of locals. In other words, it is
// not possible to coalesce well afterwards.
+ runner.add("remove-unused-names");
runner.add("simplify-locals-nonesting");
runner.add("reorder-locals");
runner.add("coalesce-locals");
diff --git a/src/passes/DeadCodeElimination.cpp b/src/passes/DeadCodeElimination.cpp
index a17abfd90..3e84a7be1 100644
--- a/src/passes/DeadCodeElimination.cpp
+++ b/src/passes/DeadCodeElimination.cpp
@@ -28,8 +28,8 @@
// have no side effects.
//
-#include <ir/block-utils.h>
-#include <ir/branch-utils.h>
+#include <ir/iteration.h>
+#include <ir/properties.h>
#include <ir/type-updating.h>
#include <pass.h>
#include <vector>
@@ -39,7 +39,9 @@
namespace wasm {
struct DeadCodeElimination
- : public WalkerPass<PostWalker<DeadCodeElimination>> {
+ : public WalkerPass<
+ PostWalker<DeadCodeElimination,
+ UnifiedExpressionVisitor<DeadCodeElimination>>> {
bool isFunctionParallel() override { return true; }
Pass* create() override { return new DeadCodeElimination; }
@@ -58,516 +60,116 @@ struct DeadCodeElimination
return expression;
}
- // whether the current code is actually reachable
- bool reachable;
-
void doWalkFunction(Function* func) {
- reachable = true;
typeUpdater.walk(func->body);
walk(func->body);
}
- std::set<Name> reachableBreaks;
-
- void addBreak(Name name) {
- // we normally have already reduced unreachable code into (unreachable)
- // nodes, so we would not get to this place at all anyhow, the breaking
- // instruction itself would be removed. However, an exception are things
- // like (block (result i32) (call $x) (unreachable)) , which has type i32
- // despite not being exited.
- // TODO: optimize such cases
- if (reachable) {
- reachableBreaks.insert(name);
- }
- }
-
- // if a child exists and is unreachable, we can replace ourselves with it
- bool isDead(Expression* child) {
- return child && child->type == Type::unreachable;
- }
-
- // a similar check, assumes the child exists
- bool isUnreachable(Expression* child) {
- return child->type == Type::unreachable;
- }
-
- // things that stop control flow
-
- void visitBreak(Break* curr) {
- if (isDead(curr->value)) {
- // the condition is evaluated last, so if the value was unreachable, the
- // whole thing is
- 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;
- // if we previously returned a value, then this block
- // must have the same type, so it fits in the ast
- // properly. it ends in an unreachable
- // anyhow, so that is ok.
- block->finalize(curr->type);
- replaceCurrent(block);
- } else {
- replaceCurrent(curr->condition);
- }
- return;
- }
- addBreak(curr->name);
- if (!curr->condition) {
- reachable = false;
- }
- }
-
- void visitSwitch(Switch* curr) {
- if (isDead(curr->value)) {
- replaceCurrent(curr->value);
- return;
- }
- if (isUnreachable(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(curr->type);
- replaceCurrent(block);
- } else {
- replaceCurrent(curr->condition);
+ void visitExpression(Expression* curr) {
+ if (!Properties::isControlFlowStructure(curr)) {
+ // Control flow structures require special handling, but others are
+ // simple.
+ if (curr->type == Type::unreachable) {
+ // This may be dead code. Check if there is an unreachable child.
+ bool hasUnreachableChild = false;
+ for (auto* child : ChildIterator(curr)) {
+ if (child->type == Type::unreachable) {
+ hasUnreachableChild = true;
+ break;
+ }
+ }
+ if (hasUnreachableChild) {
+ // This is indeed unreachable code, made unreachable by that child.
+ Builder builder(*getModule());
+ std::vector<Expression*> remainingChildren;
+ bool afterUnreachable = false;
+ for (auto* child : ChildIterator(curr)) {
+ if (afterUnreachable) {
+ typeUpdater.noteRecursiveRemoval(child);
+ continue;
+ }
+ if (child->type == Type::unreachable) {
+ remainingChildren.push_back(child);
+ afterUnreachable = true;
+ } else {
+ remainingChildren.push_back(builder.makeDrop(child));
+ }
+ }
+ if (remainingChildren.size() == 1) {
+ replaceCurrent(remainingChildren[0]);
+ } else {
+ replaceCurrent(builder.makeBlock(remainingChildren));
+ }
+ }
}
return;
}
- for (auto target : curr->targets) {
- addBreak(target);
- }
- addBreak(curr->default_);
- reachable = false;
- }
-
- void visitReturn(Return* curr) {
- if (isDead(curr->value)) {
- replaceCurrent(curr->value);
- return;
- }
- reachable = false;
- }
-
- void visitUnreachable(Unreachable* curr) { reachable = false; }
-
- void visitBlock(Block* curr) {
- auto& list = curr->list;
- // if we are currently unreachable (before we take into account
- // breaks to the block) then a child may be unreachable, and we
- // can shorten
- if (!reachable && list.size() > 1) {
- // to do here: nothing to remove after it)
- for (Index i = 0; i < list.size() - 1; i++) {
+ // This is a control flow structure.
+ if (auto* block = curr->dynCast<Block>()) {
+ auto& list = block->list;
+ // The index from which to remove, which is one after the first
+ // unreachable instruction. Note that 0 is not a valid value, so we can
+ // use it as such.
+ Index removeFromHere = 0;
+ for (Index i = 0; i < list.size(); i++) {
if (list[i]->type == Type::unreachable) {
- list.resize(i + 1);
+ removeFromHere = i + 1;
break;
}
}
- }
- if (curr->name.is()) {
- reachable = reachable || reachableBreaks.count(curr->name);
- reachableBreaks.erase(curr->name);
- }
- if (list.size() == 1 && isUnreachable(list[0])) {
- replaceCurrent(
- BlockUtils::simplifyToContentsWithPossibleTypeChange(curr, this));
- } else {
- // the block may have had a type, but can now be unreachable, which allows
- // more reduction outside
- typeUpdater.maybeUpdateTypeToUnreachable(curr);
- }
- }
-
- void visitLoop(Loop* curr) {
- if (curr->name.is()) {
- reachableBreaks.erase(curr->name);
- }
- if (isUnreachable(curr->body) &&
- !BranchUtils::BranchSeeker::has(curr->body, curr->name)) {
- replaceCurrent(curr->body);
- return;
- }
- }
-
- // ifs and trys need special handling: only one of (if body and else body /
- // try body and catch body) should be reachable to make the whole of (if /
- // try) to be reachable.
-
- // stack of reachable state, for forking and joining
- std::vector<bool> ifStack;
- std::vector<bool> tryStack;
-
- static void doAfterIfCondition(DeadCodeElimination* self,
- Expression** currp) {
- self->ifStack.push_back(self->reachable);
- }
-
- static void doAfterIfElseTrue(DeadCodeElimination* self, Expression** currp) {
- assert((*currp)->cast<If>()->ifFalse);
- bool reachableBefore = self->ifStack.back();
- self->ifStack.pop_back();
- self->ifStack.push_back(self->reachable);
- self->reachable = reachableBefore;
- }
-
- void visitIf(If* curr) {
- // the ifStack has the branch that joins us, either from before if just an
- // if, or the ifTrue if an if-else
- reachable = reachable || ifStack.back();
- ifStack.pop_back();
- if (isUnreachable(curr->condition)) {
- replaceCurrent(curr->condition);
- }
- // the if may have had a type, but can now be unreachable, which allows more
- // reduction outside
- typeUpdater.maybeUpdateTypeToUnreachable(curr);
- }
-
- static void doBeforeTryBody(DeadCodeElimination* self, Expression** currp) {
- self->tryStack.push_back(self->reachable);
- }
-
- static void doAfterTryBody(DeadCodeElimination* self, Expression** currp) {
- bool reachableBefore = self->tryStack.back();
- self->tryStack.pop_back();
- self->tryStack.push_back(self->reachable);
- self->reachable = reachableBefore;
- }
-
- void visitTry(Try* curr) {
- // the tryStack has the branch that joins us
- reachable = reachable || tryStack.back();
- tryStack.pop_back();
- // the try may have had a type, but can now be unreachable, which allows
- // more reduction outside
- typeUpdater.maybeUpdateTypeToUnreachable(curr);
- }
-
- void visitThrow(Throw* curr) { reachable = false; }
-
- void visitRethrow(Rethrow* curr) { reachable = false; }
-
- void visitBrOnExn(BrOnExn* curr) {
- if (isDead(curr->exnref)) {
- replaceCurrent(curr->exnref);
- return;
- }
- addBreak(curr->name);
- }
-
- static void scan(DeadCodeElimination* self, Expression** currp) {
- auto* curr = *currp;
- if (!self->reachable) {
-// convert to an unreachable safely
-#define DELEGATE(CLASS_TO_VISIT) \
- { \
- auto* parent = self->typeUpdater.parents[curr]; \
- self->typeUpdater.noteRecursiveRemoval(curr); \
- ExpressionManipulator::convert<CLASS_TO_VISIT, Unreachable>( \
- static_cast<CLASS_TO_VISIT*>(curr)); \
- self->typeUpdater.noteAddition(curr, parent); \
- break; \
- }
- switch (curr->_id) {
- case Expression::Id::BlockId:
- DELEGATE(Block);
- case Expression::Id::IfId:
- DELEGATE(If);
- case Expression::Id::LoopId:
- DELEGATE(Loop);
- case Expression::Id::BreakId:
- DELEGATE(Break);
- case Expression::Id::SwitchId:
- DELEGATE(Switch);
- case Expression::Id::CallId:
- DELEGATE(Call);
- case Expression::Id::CallIndirectId:
- DELEGATE(CallIndirect);
- case Expression::Id::LocalGetId:
- DELEGATE(LocalGet);
- case Expression::Id::LocalSetId:
- DELEGATE(LocalSet);
- case Expression::Id::GlobalGetId:
- DELEGATE(GlobalGet);
- case Expression::Id::GlobalSetId:
- DELEGATE(GlobalSet);
- case Expression::Id::LoadId:
- DELEGATE(Load);
- case Expression::Id::StoreId:
- DELEGATE(Store);
- case Expression::Id::ConstId:
- DELEGATE(Const);
- case Expression::Id::UnaryId:
- DELEGATE(Unary);
- case Expression::Id::BinaryId:
- DELEGATE(Binary);
- case Expression::Id::SelectId:
- DELEGATE(Select);
- case Expression::Id::DropId:
- DELEGATE(Drop);
- case Expression::Id::ReturnId:
- DELEGATE(Return);
- case Expression::Id::MemorySizeId:
- DELEGATE(MemorySize);
- case Expression::Id::MemoryGrowId:
- DELEGATE(MemoryGrow);
- case Expression::Id::NopId:
- DELEGATE(Nop);
- case Expression::Id::UnreachableId:
- break;
- case Expression::Id::AtomicCmpxchgId:
- DELEGATE(AtomicCmpxchg);
- case Expression::Id::AtomicRMWId:
- DELEGATE(AtomicRMW);
- case Expression::Id::AtomicWaitId:
- DELEGATE(AtomicWait);
- case Expression::Id::AtomicNotifyId:
- DELEGATE(AtomicNotify);
- case Expression::Id::AtomicFenceId:
- DELEGATE(AtomicFence);
- case Expression::Id::SIMDExtractId:
- DELEGATE(SIMDExtract);
- case Expression::Id::SIMDReplaceId:
- DELEGATE(SIMDReplace);
- case Expression::Id::SIMDShuffleId:
- DELEGATE(SIMDShuffle);
- case Expression::Id::SIMDTernaryId:
- DELEGATE(SIMDTernary);
- case Expression::Id::SIMDShiftId:
- DELEGATE(SIMDShift);
- case Expression::Id::SIMDLoadId:
- DELEGATE(SIMDLoad);
- case Expression::Id::SIMDLoadStoreLaneId:
- DELEGATE(SIMDLoadStoreLane);
- case Expression::Id::MemoryInitId:
- DELEGATE(MemoryInit);
- case Expression::Id::DataDropId:
- DELEGATE(DataDrop);
- case Expression::Id::MemoryCopyId:
- DELEGATE(MemoryCopy);
- case Expression::Id::MemoryFillId:
- DELEGATE(MemoryFill);
- case Expression::Id::PopId:
- DELEGATE(Pop);
- case Expression::Id::RefNullId:
- DELEGATE(RefNull);
- case Expression::Id::RefIsNullId:
- DELEGATE(RefIsNull);
- case Expression::Id::RefFuncId:
- DELEGATE(RefFunc);
- case Expression::Id::RefEqId:
- DELEGATE(RefEq);
- case Expression::Id::TryId:
- DELEGATE(Try);
- case Expression::Id::ThrowId:
- DELEGATE(Throw);
- case Expression::Id::RethrowId:
- DELEGATE(Rethrow);
- case Expression::Id::BrOnExnId:
- DELEGATE(BrOnExn);
- case Expression::Id::TupleMakeId:
- DELEGATE(TupleMake);
- case Expression::Id::TupleExtractId:
- DELEGATE(TupleExtract);
- case Expression::Id::I31NewId:
- DELEGATE(I31New);
- case Expression::Id::I31GetId:
- DELEGATE(I31Get);
- case Expression::Id::RefTestId:
- DELEGATE(RefTest);
- case Expression::Id::RefCastId:
- DELEGATE(RefCast);
- case Expression::Id::BrOnCastId:
- DELEGATE(BrOnCast);
- case Expression::Id::RttCanonId:
- DELEGATE(RttCanon);
- case Expression::Id::RttSubId:
- DELEGATE(RttSub);
- case Expression::Id::StructNewId:
- DELEGATE(StructNew);
- case Expression::Id::StructGetId:
- DELEGATE(StructGet);
- case Expression::Id::StructSetId:
- DELEGATE(StructSet);
- case Expression::Id::ArrayNewId:
- DELEGATE(ArrayNew);
- case Expression::Id::ArrayGetId:
- DELEGATE(ArrayGet);
- case Expression::Id::ArraySetId:
- DELEGATE(ArraySet);
- case Expression::Id::ArrayLenId:
- DELEGATE(ArrayLen);
- case Expression::Id::InvalidId:
- WASM_UNREACHABLE("unimp");
- case Expression::Id::NumExpressionIds:
- WASM_UNREACHABLE("unimp");
- }
-#undef DELEGATE
- return;
- }
- if (curr->is<If>()) {
- self->pushTask(DeadCodeElimination::doVisitIf, currp);
- if (curr->cast<If>()->ifFalse) {
- self->pushTask(DeadCodeElimination::scan, &curr->cast<If>()->ifFalse);
- self->pushTask(DeadCodeElimination::doAfterIfElseTrue, currp);
- }
- self->pushTask(DeadCodeElimination::scan, &curr->cast<If>()->ifTrue);
- self->pushTask(DeadCodeElimination::doAfterIfCondition, currp);
- self->pushTask(DeadCodeElimination::scan, &curr->cast<If>()->condition);
- } else if (curr->is<Try>()) {
- self->pushTask(DeadCodeElimination::doVisitTry, currp);
- self->pushTask(DeadCodeElimination::scan, &curr->cast<Try>()->catchBody);
- self->pushTask(DeadCodeElimination::doAfterTryBody, currp);
- self->pushTask(DeadCodeElimination::scan, &curr->cast<Try>()->body);
- self->pushTask(DeadCodeElimination::doBeforeTryBody, currp);
- } else {
- super::scan(self, currp);
- }
- }
-
- // other things
-
- // we don't need to drop unreachable nodes
- Expression* drop(Expression* toDrop) {
- if (toDrop->type == Type::unreachable) {
- return toDrop;
- }
- return Builder(*getModule()).makeDrop(toDrop);
- }
-
- template<typename T> Expression* handleCall(T* curr) {
- for (Index i = 0; i < curr->operands.size(); i++) {
- if (isUnreachable(curr->operands[i])) {
- if (i > 0) {
- auto* block = getModule()->allocator.alloc<Block>();
- Index newSize = i + 1;
- block->list.resize(newSize);
- Index j = 0;
- for (; j < newSize; j++) {
- block->list[j] = drop(curr->operands[j]);
- }
- block->finalize(curr->type);
- return replaceCurrent(block);
- } else {
- return replaceCurrent(curr->operands[i]);
+ if (removeFromHere != 0) {
+ for (Index i = removeFromHere; i < list.size(); i++) {
+ typeUpdater.noteRecursiveRemoval(list[i]);
+ }
+ list.resize(removeFromHere);
+ if (list.size() == 1 && list[0]->is<Unreachable>()) {
+ replaceCurrent(list[0]);
+ return;
}
}
- }
- return curr;
- }
-
- void visitCall(Call* curr) {
- handleCall(curr);
- if (curr->isReturn) {
- reachable = false;
- }
- }
-
- void visitCallIndirect(CallIndirect* curr) {
- if (handleCall(curr) != curr) {
- return;
- }
- if (isUnreachable(curr->target)) {
- auto* block = getModule()->allocator.alloc<Block>();
- for (auto* operand : curr->operands) {
- block->list.push_back(drop(operand));
+ // Finally, if there is no need for a concrete type (which is when there
+ // is one marked, but nothing breaks to it, and also the block does not
+ // have a concrete value flowing out) then remove it, which may allow
+ // more reduction.
+ if (block->type.isConcrete() && list.back()->type == Type::unreachable &&
+ !typeUpdater.hasBreaks(block)) {
+ typeUpdater.changeType(block, Type::unreachable);
}
- block->list.push_back(curr->target);
- block->finalize(curr->type);
- replaceCurrent(block);
- }
- if (curr->isReturn) {
- reachable = false;
- }
- }
-
- // Append the reachable operands of the current node to a block, and replace
- // it with the block
- void blockifyReachableOperands(std::vector<Expression*>&& list, Type type) {
- for (size_t i = 0; i < list.size(); ++i) {
- auto* elem = list[i];
- if (isUnreachable(elem)) {
- auto* replacement = elem;
- if (i > 0) {
- auto* block = getModule()->allocator.alloc<Block>();
- for (size_t j = 0; j < i; ++j) {
- block->list.push_back(drop(list[j]));
- }
- block->list.push_back(list[i]);
- block->finalize(type);
- replacement = block;
+ } else if (auto* iff = curr->dynCast<If>()) {
+ if (iff->condition->type == Type::unreachable) {
+ typeUpdater.noteRecursiveRemoval(iff->ifTrue);
+ if (iff->ifFalse) {
+ typeUpdater.noteRecursiveRemoval(iff->ifFalse);
}
- replaceCurrent(replacement);
+ replaceCurrent(iff->condition);
return;
}
+ // If both arms are unreachable, there is no need for a concrete type,
+ // which may allow more reduction.
+ if (iff->type != Type::unreachable && iff->ifFalse &&
+ iff->ifTrue->type == Type::unreachable &&
+ iff->ifFalse->type == Type::unreachable) {
+ typeUpdater.changeType(iff, Type::unreachable);
+ }
+ } else if (auto* loop = curr->dynCast<Loop>()) {
+ // The loop body may have unreachable type if it branches back to the
+ // loop top, for example. The only case we look for here is where we've
+ // already removed the entire body as dead code.
+ if (loop->body->is<Unreachable>()) {
+ replaceCurrent(loop->body);
+ }
+ } else if (auto* tryy = curr->dynCast<Try>()) {
+ // If both try body and catch body are unreachable, there is no need for a
+ // concrete type, which may allow more reduction.
+ if (tryy->type != Type::unreachable &&
+ tryy->body->type == Type::unreachable &&
+ tryy->catchBody->type == Type::unreachable) {
+ typeUpdater.changeType(tryy, Type::unreachable);
+ }
+ } else {
+ WASM_UNREACHABLE("unimplemented DCE control flow structure");
}
}
-
- void visitLocalSet(LocalSet* curr) {
- blockifyReachableOperands({curr->value}, curr->type);
- }
-
- void visitGlobalSet(GlobalSet* curr) {
- blockifyReachableOperands({curr->value}, curr->type);
- }
-
- void visitLoad(Load* curr) {
- blockifyReachableOperands({curr->ptr}, curr->type);
- }
-
- void visitStore(Store* curr) {
- blockifyReachableOperands({curr->ptr, curr->value}, curr->type);
- }
-
- void visitAtomicRMW(AtomicRMW* curr) {
- blockifyReachableOperands({curr->ptr, curr->value}, curr->type);
- }
-
- void visitAtomicCmpxchg(AtomicCmpxchg* curr) {
- blockifyReachableOperands({curr->ptr, curr->expected, curr->replacement},
- curr->type);
- }
-
- void visitUnary(Unary* curr) {
- blockifyReachableOperands({curr->value}, curr->type);
- }
-
- void visitBinary(Binary* curr) {
- blockifyReachableOperands({curr->left, curr->right}, curr->type);
- }
-
- void visitSelect(Select* curr) {
- blockifyReachableOperands({curr->ifTrue, curr->ifFalse, curr->condition},
- curr->type);
- }
-
- void visitDrop(Drop* curr) {
- blockifyReachableOperands({curr->value}, curr->type);
- }
-
- void visitMemorySize(MemorySize* curr) {}
-
- void visitMemoryGrow(MemoryGrow* curr) {
- blockifyReachableOperands({curr->delta}, curr->type);
- }
-
- void visitRefIsNull(RefIsNull* curr) {
- blockifyReachableOperands({curr->value}, curr->type);
- }
-
- void visitRefEq(RefEq* curr) {
- blockifyReachableOperands({curr->left, curr->right}, curr->type);
- }
-
- void visitFunction(Function* curr) { assert(reachableBreaks.size() == 0); }
};
Pass* createDeadCodeEliminationPass() { return new DeadCodeElimination(); }
diff --git a/src/passes/pass.cpp b/src/passes/pass.cpp
index c6d479dfb..3e9429695 100644
--- a/src/passes/pass.cpp
+++ b/src/passes/pass.cpp
@@ -407,6 +407,7 @@ void PassRunner::addDefaultFunctionOptimizationPasses() {
add("local-cse");
}
add("dce");
+ add("remove-unused-names");
add("remove-unused-brs");
add("remove-unused-names");
add("optimize-instructions");
diff --git a/test/passes/asyncify_enable-multivalue.txt b/test/passes/asyncify_enable-multivalue.txt
index 08d0d7bf9..7d92b0c97 100644
--- a/test/passes/asyncify_enable-multivalue.txt
+++ b/test/passes/asyncify_enable-multivalue.txt
@@ -491,55 +491,57 @@
)
)
(block
- (if
- (if (result i32)
- (i32.eq
- (global.get $__asyncify_state)
- (i32.const 0)
- )
- (i32.const 1)
- (i32.eq
- (local.get $6)
- (i32.const 0)
- )
- )
- (block
- (local.set $7
- (call $import2)
- )
- (if
+ (block
+ (if
+ (if (result i32)
(i32.eq
(global.get $__asyncify_state)
- (i32.const 1)
+ (i32.const 0)
)
- (br $__asyncify_unwind
+ (i32.const 1)
+ (i32.eq
+ (local.get $6)
(i32.const 0)
)
- (local.set $1
- (local.get $7)
+ )
+ (block
+ (local.set $7
+ (call $import2)
+ )
+ (if
+ (i32.eq
+ (global.get $__asyncify_state)
+ (i32.const 1)
+ )
+ (br $__asyncify_unwind
+ (i32.const 0)
+ )
+ (local.set $1
+ (local.get $7)
+ )
)
)
)
- )
- (if
- (i32.eq
- (global.get $__asyncify_state)
- (i32.const 0)
- )
- (block
- (local.set $temp
- (local.get $1)
- )
- (local.set $2
- (local.get $temp)
+ (if
+ (i32.eq
+ (global.get $__asyncify_state)
+ (i32.const 0)
)
- (return
- (local.get $2)
+ (block
+ (local.set $temp
+ (local.get $1)
+ )
+ (local.set $2
+ (local.get $temp)
+ )
+ (return
+ (local.get $2)
+ )
)
)
+ (nop)
+ (nop)
)
- (nop)
- (nop)
)
(unreachable)
)
@@ -814,84 +816,86 @@
)
)
(block
- (if
- (i32.eq
- (global.get $__asyncify_state)
- (i32.const 0)
- )
- (loop $l
- (local.set $3
- (local.get $y)
- )
- (local.set $4
- (i32.add
- (local.get $3)
- (i32.const 1)
- )
- )
- (local.set $x
- (local.get $4)
- )
- (local.set $5
- (local.get $x)
- )
- (local.set $6
- (i32.div_s
- (local.get $5)
- (i32.const 3)
- )
- )
- (local.set $y
- (local.get $6)
- )
- (local.set $7
- (local.get $y)
- )
- (br_if $l
- (local.get $7)
- )
- )
- )
- (if
- (if (result i32)
+ (block
+ (if
(i32.eq
(global.get $__asyncify_state)
(i32.const 0)
)
- (i32.const 1)
- (i32.eq
- (local.get $12)
- (i32.const 0)
+ (loop $l
+ (local.set $3
+ (local.get $y)
+ )
+ (local.set $4
+ (i32.add
+ (local.get $3)
+ (i32.const 1)
+ )
+ )
+ (local.set $x
+ (local.get $4)
+ )
+ (local.set $5
+ (local.get $x)
+ )
+ (local.set $6
+ (i32.div_s
+ (local.get $5)
+ (i32.const 3)
+ )
+ )
+ (local.set $y
+ (local.get $6)
+ )
+ (local.set $7
+ (local.get $y)
+ )
+ (br_if $l
+ (local.get $7)
+ )
)
)
- (block
- (call $import)
- (if
+ (if
+ (if (result i32)
(i32.eq
(global.get $__asyncify_state)
- (i32.const 1)
+ (i32.const 0)
)
- (br $__asyncify_unwind
+ (i32.const 1)
+ (i32.eq
+ (local.get $12)
(i32.const 0)
)
)
+ (block
+ (call $import)
+ (if
+ (i32.eq
+ (global.get $__asyncify_state)
+ (i32.const 1)
+ )
+ (br $__asyncify_unwind
+ (i32.const 0)
+ )
+ )
+ )
)
- )
- (if
- (i32.eq
- (global.get $__asyncify_state)
- (i32.const 0)
- )
- (block
- (local.set $8
- (local.get $y)
+ (if
+ (i32.eq
+ (global.get $__asyncify_state)
+ (i32.const 0)
)
- (return
- (local.get $8)
+ (block
+ (local.set $8
+ (local.get $y)
+ )
+ (return
+ (local.get $8)
+ )
)
)
+ (nop)
)
- (nop)
)
(unreachable)
)
@@ -1291,90 +1295,92 @@
)
(block
(block
- (if
- (i32.eq
- (global.get $__asyncify_state)
- (i32.const 0)
- )
- (local.set $1
- (local.get $x)
- )
- )
(block
(if
(i32.eq
(global.get $__asyncify_state)
(i32.const 0)
)
- (local.set $4
- (local.get $1)
+ (local.set $1
+ (local.get $x)
)
)
- (if
- (i32.or
- (local.get $4)
- (i32.eq
- (global.get $__asyncify_state)
- (i32.const 2)
- )
- )
+ (block
(if
(i32.eq
(global.get $__asyncify_state)
(i32.const 0)
)
- (return
- (i32.const 1)
- )
- )
- )
- (if
- (i32.or
- (i32.eqz
- (local.get $4)
- )
- (i32.eq
- (global.get $__asyncify_state)
- (i32.const 2)
+ (local.set $4
+ (local.get $1)
)
)
(if
- (if (result i32)
+ (i32.or
+ (local.get $4)
(i32.eq
(global.get $__asyncify_state)
- (i32.const 0)
+ (i32.const 2)
)
- (i32.const 1)
+ )
+ (if
(i32.eq
- (local.get $6)
+ (global.get $__asyncify_state)
(i32.const 0)
)
+ (return
+ (i32.const 1)
+ )
)
- (block
- (call $import3
+ )
+ (if
+ (i32.or
+ (i32.eqz
+ (local.get $4)
+ )
+ (i32.eq
+ (global.get $__asyncify_state)
(i32.const 2)
)
- (if
+ )
+ (if
+ (if (result i32)
(i32.eq
(global.get $__asyncify_state)
- (i32.const 1)
+ (i32.const 0)
)
- (br $__asyncify_unwind
+ (i32.const 1)
+ (i32.eq
+ (local.get $6)
(i32.const 0)
)
)
+ (block
+ (call $import3
+ (i32.const 2)
+ )
+ (if
+ (i32.eq
+ (global.get $__asyncify_state)
+ (i32.const 1)
+ )
+ (br $__asyncify_unwind
+ (i32.const 0)
+ )
+ )
+ )
)
)
)
)
- )
- (if
- (i32.eq
- (global.get $__asyncify_state)
- (i32.const 0)
- )
- (return
- (i32.const 3)
+ (if
+ (i32.eq
+ (global.get $__asyncify_state)
+ (i32.const 0)
+ )
+ (return
+ (i32.const 3)
+ )
)
)
)
@@ -1470,90 +1476,92 @@
)
(block
(block
- (if
- (i32.eq
- (global.get $__asyncify_state)
- (i32.const 0)
- )
- (local.set $1
- (local.get $x)
- )
- )
(block
(if
(i32.eq
(global.get $__asyncify_state)
(i32.const 0)
)
- (local.set $4
- (local.get $1)
+ (local.set $1
+ (local.get $x)
)
)
- (if
- (i32.or
- (local.get $4)
+ (block
+ (if
(i32.eq
(global.get $__asyncify_state)
- (i32.const 2)
+ (i32.const 0)
+ )
+ (local.set $4
+ (local.get $1)
)
)
(if
- (if (result i32)
+ (i32.or
+ (local.get $4)
(i32.eq
(global.get $__asyncify_state)
- (i32.const 0)
- )
- (i32.const 1)
- (i32.eq
- (local.get $6)
- (i32.const 0)
+ (i32.const 2)
)
)
- (block
- (call $import3
- (i32.const 1)
- )
- (if
+ (if
+ (if (result i32)
(i32.eq
(global.get $__asyncify_state)
- (i32.const 1)
+ (i32.const 0)
)
- (br $__asyncify_unwind
+ (i32.const 1)
+ (i32.eq
+ (local.get $6)
(i32.const 0)
)
)
- )
- )
- )
- (if
- (i32.or
- (i32.eqz
- (local.get $4)
- )
- (i32.eq
- (global.get $__asyncify_state)
- (i32.const 2)
+ (block
+ (call $import3
+ (i32.const 1)
+ )
+ (if
+ (i32.eq
+ (global.get $__asyncify_state)
+ (i32.const 1)
+ )
+ (br $__asyncify_unwind
+ (i32.const 0)
+ )
+ )
+ )
)
)
(if
- (i32.eq
- (global.get $__asyncify_state)
- (i32.const 0)
+ (i32.or
+ (i32.eqz
+ (local.get $4)
+ )
+ (i32.eq
+ (global.get $__asyncify_state)
+ (i32.const 2)
+ )
)
- (return
- (i32.const 2)
+ (if
+ (i32.eq
+ (global.get $__asyncify_state)
+ (i32.const 0)
+ )
+ (return
+ (i32.const 2)
+ )
)
)
)
)
- )
- (if
- (i32.eq
- (global.get $__asyncify_state)
- (i32.const 0)
- )
- (return
- (i32.const 3)
+ (if
+ (i32.eq
+ (global.get $__asyncify_state)
+ (i32.const 0)
+ )
+ (return
+ (i32.const 3)
+ )
)
)
)
diff --git a/test/passes/asyncify_mod-asyncify-always-and-only-unwind.txt b/test/passes/asyncify_mod-asyncify-always-and-only-unwind.txt
index 62c3ba33f..ecf0a41c8 100644
--- a/test/passes/asyncify_mod-asyncify-always-and-only-unwind.txt
+++ b/test/passes/asyncify_mod-asyncify-always-and-only-unwind.txt
@@ -152,52 +152,54 @@
)
)
(block
- (if
- (if (result i32)
- (i32.eq
- (global.get $__asyncify_state)
- (i32.const 0)
- )
- (i32.const 1)
- (i32.eq
- (local.get $6)
- (i32.const 0)
- )
- )
- (block
- (local.set $7
- (call $import2)
- )
- (if
+ (block
+ (if
+ (if (result i32)
+ (i32.eq
+ (global.get $__asyncify_state)
+ (i32.const 0)
+ )
(i32.const 1)
- (br $__asyncify_unwind
+ (i32.eq
+ (local.get $6)
(i32.const 0)
)
- (local.set $1
- (local.get $7)
+ )
+ (block
+ (local.set $7
+ (call $import2)
+ )
+ (if
+ (i32.const 1)
+ (br $__asyncify_unwind
+ (i32.const 0)
+ )
+ (local.set $1
+ (local.get $7)
+ )
)
)
)
- )
- (if
- (i32.eq
- (global.get $__asyncify_state)
- (i32.const 0)
- )
- (block
- (local.set $temp
- (local.get $1)
- )
- (local.set $2
- (local.get $temp)
+ (if
+ (i32.eq
+ (global.get $__asyncify_state)
+ (i32.const 0)
)
- (return
- (local.get $2)
+ (block
+ (local.set $temp
+ (local.get $1)
+ )
+ (local.set $2
+ (local.get $temp)
+ )
+ (return
+ (local.get $2)
+ )
)
)
+ (nop)
+ (nop)
)
- (nop)
- (nop)
)
(unreachable)
)
diff --git a/test/passes/asyncify_mod-asyncify-never-unwind.txt b/test/passes/asyncify_mod-asyncify-never-unwind.txt
index eaf2794cf..2177c5220 100644
--- a/test/passes/asyncify_mod-asyncify-never-unwind.txt
+++ b/test/passes/asyncify_mod-asyncify-never-unwind.txt
@@ -164,52 +164,54 @@
)
)
(block
- (if
- (if (result i32)
- (i32.eq
- (global.get $__asyncify_state)
- (i32.const 0)
- )
- (i32.const 1)
- (i32.eq
- (local.get $6)
- (i32.const 0)
- )
- )
- (block
- (local.set $7
- (call $import2)
- )
- (if
- (i32.const 0)
- (br $__asyncify_unwind
+ (block
+ (if
+ (if (result i32)
+ (i32.eq
+ (global.get $__asyncify_state)
+ (i32.const 0)
+ )
+ (i32.const 1)
+ (i32.eq
+ (local.get $6)
(i32.const 0)
)
- (local.set $1
- (local.get $7)
+ )
+ (block
+ (local.set $7
+ (call $import2)
+ )
+ (if
+ (i32.const 0)
+ (br $__asyncify_unwind
+ (i32.const 0)
+ )
+ (local.set $1
+ (local.get $7)
+ )
)
)
)
- )
- (if
- (i32.eq
- (global.get $__asyncify_state)
- (i32.const 0)
- )
- (block
- (local.set $temp
- (local.get $1)
- )
- (local.set $2
- (local.get $temp)
+ (if
+ (i32.eq
+ (global.get $__asyncify_state)
+ (i32.const 0)
)
- (return
- (local.get $2)
+ (block
+ (local.set $temp
+ (local.get $1)
+ )
+ (local.set $2
+ (local.get $temp)
+ )
+ (return
+ (local.get $2)
+ )
)
)
+ (nop)
+ (nop)
)
- (nop)
- (nop)
)
(unreachable)
)
diff --git a/test/passes/asyncify_pass-arg=asyncify-imports@env.import,env.import2.txt b/test/passes/asyncify_pass-arg=asyncify-imports@env.import,env.import2.txt
index defef94ed..2a8c0061a 100644
--- a/test/passes/asyncify_pass-arg=asyncify-imports@env.import,env.import2.txt
+++ b/test/passes/asyncify_pass-arg=asyncify-imports@env.import,env.import2.txt
@@ -488,55 +488,57 @@
)
)
(block
- (if
- (if (result i32)
- (i32.eq
- (global.get $__asyncify_state)
- (i32.const 0)
- )
- (i32.const 1)
- (i32.eq
- (local.get $6)
- (i32.const 0)
- )
- )
- (block
- (local.set $7
- (call $import2)
- )
- (if
+ (block
+ (if
+ (if (result i32)
(i32.eq
(global.get $__asyncify_state)
- (i32.const 1)
+ (i32.const 0)
)
- (br $__asyncify_unwind
+ (i32.const 1)
+ (i32.eq
+ (local.get $6)
(i32.const 0)
)
- (local.set $1
- (local.get $7)
+ )
+ (block
+ (local.set $7
+ (call $import2)
+ )
+ (if
+ (i32.eq
+ (global.get $__asyncify_state)
+ (i32.const 1)
+ )
+ (br $__asyncify_unwind
+ (i32.const 0)
+ )
+ (local.set $1
+ (local.get $7)
+ )
)
)
)
- )
- (if
- (i32.eq
- (global.get $__asyncify_state)
- (i32.const 0)
- )
- (block
- (local.set $temp
- (local.get $1)
- )
- (local.set $2
- (local.get $temp)
+ (if
+ (i32.eq
+ (global.get $__asyncify_state)
+ (i32.const 0)
)
- (return
- (local.get $2)
+ (block
+ (local.set $temp
+ (local.get $1)
+ )
+ (local.set $2
+ (local.get $temp)
+ )
+ (return
+ (local.get $2)
+ )
)
)
+ (nop)
+ (nop)
)
- (nop)
- (nop)
)
(unreachable)
)
@@ -810,84 +812,86 @@
)
)
(block
- (if
- (i32.eq
- (global.get $__asyncify_state)
- (i32.const 0)
- )
- (loop $l
- (local.set $2
- (local.get $y)
- )
- (local.set $3
- (i32.add
- (local.get $2)
- (i32.const 1)
- )
- )
- (local.set $x
- (local.get $3)
- )
- (local.set $4
- (local.get $x)
- )
- (local.set $5
- (i32.div_s
- (local.get $4)
- (i32.const 3)
- )
- )
- (local.set $y
- (local.get $5)
- )
- (local.set $6
- (local.get $y)
- )
- (br_if $l
- (local.get $6)
- )
- )
- )
- (if
- (if (result i32)
+ (block
+ (if
(i32.eq
(global.get $__asyncify_state)
(i32.const 0)
)
- (i32.const 1)
- (i32.eq
- (local.get $11)
- (i32.const 0)
+ (loop $l
+ (local.set $2
+ (local.get $y)
+ )
+ (local.set $3
+ (i32.add
+ (local.get $2)
+ (i32.const 1)
+ )
+ )
+ (local.set $x
+ (local.get $3)
+ )
+ (local.set $4
+ (local.get $x)
+ )
+ (local.set $5
+ (i32.div_s
+ (local.get $4)
+ (i32.const 3)
+ )
+ )
+ (local.set $y
+ (local.get $5)
+ )
+ (local.set $6
+ (local.get $y)
+ )
+ (br_if $l
+ (local.get $6)
+ )
)
)
- (block
- (call $import)
- (if
+ (if
+ (if (result i32)
(i32.eq
(global.get $__asyncify_state)
- (i32.const 1)
+ (i32.const 0)
)
- (br $__asyncify_unwind
+ (i32.const 1)
+ (i32.eq
+ (local.get $11)
(i32.const 0)
)
)
+ (block
+ (call $import)
+ (if
+ (i32.eq
+ (global.get $__asyncify_state)
+ (i32.const 1)
+ )
+ (br $__asyncify_unwind
+ (i32.const 0)
+ )
+ )
+ )
)
- )
- (if
- (i32.eq
- (global.get $__asyncify_state)
- (i32.const 0)
- )
- (block
- (local.set $7
- (local.get $y)
+ (if
+ (i32.eq
+ (global.get $__asyncify_state)
+ (i32.const 0)
)
- (return
- (local.get $7)
+ (block
+ (local.set $7
+ (local.get $y)
+ )
+ (return
+ (local.get $7)
+ )
)
)
+ (nop)
)
- (nop)
)
(unreachable)
)
@@ -1062,21 +1066,23 @@
(local $2 i32)
(local $3 i32)
(block
- (local.set $1
- (local.get $x)
- )
- (if
- (local.get $1)
- (return
- (i32.const 1)
+ (block
+ (local.set $1
+ (local.get $x)
)
- (call $import3
- (i32.const 2)
+ (if
+ (local.get $1)
+ (return
+ (i32.const 1)
+ )
+ (call $import3
+ (i32.const 2)
+ )
)
)
- )
- (return
- (i32.const 3)
+ (return
+ (i32.const 3)
+ )
)
)
(func $calls-import2-if-else-oneside2 (param $x i32) (result i32)
@@ -1084,21 +1090,23 @@
(local $2 i32)
(local $3 i32)
(block
- (local.set $1
- (local.get $x)
- )
- (if
- (local.get $1)
- (call $import3
- (i32.const 1)
+ (block
+ (local.set $1
+ (local.get $x)
)
- (return
- (i32.const 2)
+ (if
+ (local.get $1)
+ (call $import3
+ (i32.const 1)
+ )
+ (return
+ (i32.const 2)
+ )
)
)
- )
- (return
- (i32.const 3)
+ (return
+ (i32.const 3)
+ )
)
)
(func $calls-loop (param $x i32)
diff --git a/test/passes/dce_all-features.txt b/test/passes/dce_all-features.txt
index 4b76b2f12..4088d5a34 100644
--- a/test/passes/dce_all-features.txt
+++ b/test/passes/dce_all-features.txt
@@ -24,7 +24,9 @@
)
(if
(i32.const 0)
- (return)
+ (block $out3
+ (return)
+ )
)
(block $out4
(br_table $out4 $out4 $out4 $out4
@@ -41,10 +43,12 @@
)
(if
(i32.const 0)
- (if
- (i32.const 0)
- (unreachable)
- (unreachable)
+ (block $block4
+ (if
+ (i32.const 0)
+ (unreachable)
+ (unreachable)
+ )
)
)
(if
@@ -69,13 +73,15 @@
)
(if
(i32.const 0)
- (block $out18
- (block $in19
- (br_if $in19
- (i32.const 1)
+ (block $block11
+ (block $out18
+ (block $in19
+ (br_if $in19
+ (i32.const 1)
+ )
)
+ (unreachable)
)
- (unreachable)
)
)
(block $out20
@@ -96,13 +102,15 @@
)
(if
(i32.const 0)
- (block $out25
- (block $in26
- (br_table $in26 $in26
- (i32.const 1)
+ (block $block13
+ (block $out25
+ (block $in26
+ (br_table $in26 $in26
+ (i32.const 1)
+ )
)
+ (unreachable)
)
- (unreachable)
)
)
(if
@@ -122,7 +130,7 @@
(unreachable)
)
(block $out29
- (block
+ (loop $in30
(br_if $out29
(i32.const 1)
)
@@ -131,11 +139,13 @@
)
(if
(i32.const 0)
- (loop $in32
- (br_if $in32
- (i32.const 1)
+ (block $block20
+ (loop $in32
+ (br_if $in32
+ (i32.const 1)
+ )
+ (unreachable)
)
- (unreachable)
)
)
(if
@@ -273,8 +283,12 @@
)
)
(func $typed-block-none-then-unreachable (result i32)
- (return
- (i32.const 0)
+ (block $top-typed
+ (block $switch$0
+ (return
+ (i32.const 0)
+ )
+ )
)
)
(func $typed-block-remove-br-changes-type (param $$$0 i32) (result i32)
@@ -317,15 +331,19 @@
)
)
(func $unreachable-block-ends-switch (result i32)
- (block $label$3
- (nop)
- (unreachable)
+ (block $label$0
+ (block $label$3
+ (nop)
+ (unreachable)
+ )
)
)
(func $unreachable-block-ends-br_if (result i32)
- (block $label$2
- (nop)
- (unreachable)
+ (block $label$0
+ (block $label$2
+ (nop)
+ (unreachable)
+ )
)
)
(func $unreachable-brs-3 (result i32)
@@ -339,11 +357,15 @@
(drop
(i32.const 1)
)
- (block
- (drop
- (i32.const 4104)
+ (block $label$0
+ (block $label$1
+ (block
+ (drop
+ (i32.const 4104)
+ )
+ (unreachable)
+ )
)
- (unreachable)
)
)
(func $call-unreach (param $var$0 i64) (param $var$1 i64) (result i64)
@@ -355,32 +377,36 @@
(block $label$0 (result i64)
(local.get $var$1)
)
- (block
- (drop
- (i64.sub
- (local.get $var$0)
- (i64.const 1)
- )
- )
+ (block $label$1
(block
(drop
- (block $block (result i64)
- (local.set $2
- (local.get $var$0)
+ (i64.sub
+ (local.get $var$0)
+ (i64.const 1)
+ )
+ )
+ (block
+ (drop
+ (block $block (result i64)
+ (local.set $2
+ (local.get $var$0)
+ )
+ (nop)
+ (local.get $2)
)
- (nop)
- (local.get $2)
)
+ (unreachable)
)
- (unreachable)
)
)
)
)
(func $br-gone-means-block-type-changes-then-refinalize-at-end-is-too-late (param $var$0 i32) (result i32)
- (block $block
- (nop)
- (unreachable)
+ (block $label$0
+ (block $block
+ (nop)
+ (unreachable)
+ )
)
)
(func $br-with-unreachable-value-should-not-give-a-block-a-value (param $var$0 i32) (result i32)
@@ -397,25 +423,31 @@
)
)
(func $replace-br-value-of-i32-with-unreachable (result i32)
- (block $label$1
- (nop)
- (unreachable)
+ (block $label$0
+ (block $label$1
+ (nop)
+ (unreachable)
+ )
)
)
(func $shorten-block-requires-sync-refinalize (param $var$0 i32) (param $var$1 i32)
(unreachable)
)
(func $block-with-type-but-is-unreachable (param $var$0 i32) (result i32)
- (block $block
- (nop)
- (unreachable)
+ (block $label$0
+ (block $block
+ (nop)
+ (unreachable)
+ )
)
)
(func $if-with-type-but-is-unreachable (param $var$0 i32) (result i32)
- (if
- (local.get $var$0)
- (unreachable)
- (unreachable)
+ (block $label$0
+ (if
+ (local.get $var$0)
+ (unreachable)
+ (unreachable)
+ )
)
)
(func $unreachable-loop
@@ -423,8 +455,10 @@
)
(func $br-block-from-unary (result i32)
(block $label$6 (result i32)
- (br $label$6
- (i32.const 8)
+ (block $label$7
+ (br $label$6
+ (i32.const 8)
+ )
)
)
)
@@ -444,19 +478,23 @@
)
)
(func $replace-with-unreachable-affects-parent (param $var$0 f32) (param $var$1 i64)
- (drop
- (i64.const 0)
- )
- (if
- (block $block (result i32)
- (call $replace-with-unreachable-affects-parent
- (f32.const 1)
- (i64.const -15917430362925035)
+ (block $top
+ (block
+ (drop
+ (i64.const 0)
+ )
+ (if
+ (block $block (result i32)
+ (call $replace-with-unreachable-affects-parent
+ (f32.const 1)
+ (i64.const -15917430362925035)
+ )
+ (i32.const 1)
+ )
+ (unreachable)
+ (unreachable)
)
- (i32.const 1)
)
- (unreachable)
- (unreachable)
)
)
(func $replace-block-changes-later-when-if-goes
@@ -503,6 +541,7 @@
)
(module
(type $none_=>_none (func))
+ (type $none_=>_i32 (func (result i32)))
(event $e (attr 0) (param))
(func $foo
(nop)
@@ -542,12 +581,68 @@
)
)
(func $throw
- (throw $e
+ (block $label$0
+ (block $label$1
+ (throw $e
+ )
+ )
)
)
(func $rethrow
- (rethrow
- (ref.null exn)
+ (block $label$0
+ (block $label$1
+ (rethrow
+ (ref.null exn)
+ )
+ )
+ )
+ )
+ (func $unnecessary-concrete-block (result i32)
+ (block $foo
+ (nop)
+ (unreachable)
+ )
+ )
+ (func $necessary-concrete-block (result i32)
+ (block $foo (result i32)
+ (br $foo
+ (i32.const 1)
+ )
+ )
+ )
+ (func $unnecessary-concrete-if (result i32)
+ (if
+ (i32.const 0)
+ (return
+ (i32.const 1)
+ )
+ (unreachable)
+ )
+ )
+ (func $unnecessary-concrete-try (result i32)
+ (try
+ (do
+ (unreachable)
+ )
+ (catch
+ (unreachable)
+ )
+ )
+ )
+ (func $note-loss-of-if-children
+ (block $label$1
+ (block $label$2
+ (nop)
+ (unreachable)
+ )
+ )
+ )
+ (func $note-loss-of-non-control-flow-children
+ (block $out
+ (block $block
+ (nop)
+ (unreachable)
+ )
)
)
)
diff --git a/test/passes/dce_all-features.wast b/test/passes/dce_all-features.wast
index bf0c188d0..9ebcccb60 100644
--- a/test/passes/dce_all-features.wast
+++ b/test/passes/dce_all-features.wast
@@ -810,4 +810,61 @@
)
)
)
+
+ (func $unnecessary-concrete-block (result i32)
+ (block $foo (result i32) ;; unnecessary type
+ (nop)
+ (unreachable)
+ )
+ )
+ (func $necessary-concrete-block (result i32)
+ (block $foo (result i32)
+ (br $foo (i32.const 1))
+ (unreachable)
+ )
+ )
+ (func $unnecessary-concrete-if (result i32)
+ (if (result i32) ;; unnecessary type
+ (i32.const 0)
+ (return (i32.const 1))
+ (unreachable)
+ )
+ )
+ (func $unnecessary-concrete-try (result i32)
+ (try (result i32)
+ (do
+ (unreachable)
+ )
+ (catch
+ (unreachable)
+ )
+ )
+ )
+ (func $note-loss-of-if-children
+ (block $label$1
+ (if ;; begins unreachable - type never changes - but after the condition
+ ;; becomes unreachable, it will lose the children, which means no more
+ ;; br to the outer block, changing that type.
+ (block $label$2 (result i32)
+ (nop)
+ (unreachable)
+ )
+ (unreachable)
+ (br $label$1)
+ )
+ )
+ )
+ (func $note-loss-of-non-control-flow-children
+ (block $out
+ (drop
+ (i32.add
+ (block (result i32)
+ (nop)
+ (unreachable)
+ )
+ (br $out) ;; when this is removed as dead, the block becomes unreachable
+ )
+ )
+ )
+ )
)
diff --git a/test/passes/dce_vacuum.bin.txt b/test/passes/dce_vacuum.bin.txt
deleted file mode 100644
index cee1143d3..000000000
--- a/test/passes/dce_vacuum.bin.txt
+++ /dev/null
@@ -1,98 +0,0 @@
-(module
- (type $f32_f32_=>_f32 (func (param f32 f32) (result f32)))
- (type $f64_f64_=>_f64 (func (param f64 f64) (result f64)))
- (export "f32.compute_radix" (func $0))
- (export "f64.compute_radix" (func $1))
- (func $0 (param $0 f32) (param $1 f32) (result f32)
- (block $label$1
- (loop $label$2
- (br_if $label$2
- (f32.eq
- (f32.add
- (f32.sub
- (f32.add
- (local.tee $0
- (f32.add
- (local.get $0)
- (local.get $0)
- )
- )
- (f32.const 1)
- )
- (local.get $0)
- )
- (f32.const -1)
- )
- (f32.const 0)
- )
- )
- )
- (block
- (drop
- (call $0
- (f32.add
- (local.get $0)
- (local.tee $1
- (f32.add
- (local.get $1)
- (f32.const 1)
- )
- )
- )
- (local.get $0)
- )
- )
- (unreachable)
- )
- )
- )
- (func $1 (param $0 f64) (param $1 f64) (result f64)
- (block $label$1 (result f64)
- (loop $label$2
- (br_if $label$2
- (f64.eq
- (f64.add
- (f64.sub
- (f64.add
- (local.tee $0
- (f64.add
- (local.get $0)
- (local.get $0)
- )
- )
- (f64.const 1)
- )
- (local.get $0)
- )
- (f64.const -1)
- )
- (f64.const 0)
- )
- )
- )
- (loop $label$3
- (br_if $label$3
- (f64.ne
- (f64.sub
- (f64.sub
- (f64.add
- (local.get $0)
- (local.tee $1
- (f64.add
- (local.get $1)
- (f64.const 1)
- )
- )
- )
- (local.get $0)
- )
- (local.get $1)
- )
- (f64.const 0)
- )
- )
- )
- (local.get $1)
- )
- )
-)
diff --git a/test/passes/dce_vacuum_remove-unused-names.bin.txt b/test/passes/dce_vacuum_remove-unused-names.bin.txt
new file mode 100644
index 000000000..26e2c565a
--- /dev/null
+++ b/test/passes/dce_vacuum_remove-unused-names.bin.txt
@@ -0,0 +1,94 @@
+(module
+ (type $f32_f32_=>_f32 (func (param f32 f32) (result f32)))
+ (type $f64_f64_=>_f64 (func (param f64 f64) (result f64)))
+ (export "f32.compute_radix" (func $0))
+ (export "f64.compute_radix" (func $1))
+ (func $0 (param $0 f32) (param $1 f32) (result f32)
+ (loop $label$2
+ (br_if $label$2
+ (f32.eq
+ (f32.add
+ (f32.sub
+ (f32.add
+ (local.tee $0
+ (f32.add
+ (local.get $0)
+ (local.get $0)
+ )
+ )
+ (f32.const 1)
+ )
+ (local.get $0)
+ )
+ (f32.const -1)
+ )
+ (f32.const 0)
+ )
+ )
+ )
+ (block
+ (drop
+ (call $0
+ (f32.add
+ (local.get $0)
+ (local.tee $1
+ (f32.add
+ (local.get $1)
+ (f32.const 1)
+ )
+ )
+ )
+ (local.get $0)
+ )
+ )
+ (unreachable)
+ )
+ )
+ (func $1 (param $0 f64) (param $1 f64) (result f64)
+ (loop $label$2
+ (br_if $label$2
+ (f64.eq
+ (f64.add
+ (f64.sub
+ (f64.add
+ (local.tee $0
+ (f64.add
+ (local.get $0)
+ (local.get $0)
+ )
+ )
+ (f64.const 1)
+ )
+ (local.get $0)
+ )
+ (f64.const -1)
+ )
+ (f64.const 0)
+ )
+ )
+ )
+ (loop $label$3
+ (br_if $label$3
+ (f64.ne
+ (f64.sub
+ (f64.sub
+ (f64.add
+ (local.get $0)
+ (local.tee $1
+ (f64.add
+ (local.get $1)
+ (f64.const 1)
+ )
+ )
+ )
+ (local.get $0)
+ )
+ (local.get $1)
+ )
+ (f64.const 0)
+ )
+ )
+ )
+ (local.get $1)
+ )
+)
diff --git a/test/passes/dce_vacuum.txt b/test/passes/dce_vacuum_remove-unused-names.txt
index 2c4466058..2c4466058 100644
--- a/test/passes/dce_vacuum.txt
+++ b/test/passes/dce_vacuum_remove-unused-names.txt
diff --git a/test/passes/dce_vacuum.wasm b/test/passes/dce_vacuum_remove-unused-names.wasm
index 5fa1892bd..5fa1892bd 100644
--- a/test/passes/dce_vacuum.wasm
+++ b/test/passes/dce_vacuum_remove-unused-names.wasm
Binary files differ
diff --git a/test/passes/dce_vacuum.wast b/test/passes/dce_vacuum_remove-unused-names.wast
index 47f4affbd..47f4affbd 100644
--- a/test/passes/dce_vacuum.wast
+++ b/test/passes/dce_vacuum_remove-unused-names.wast
diff --git a/test/passes/interesting-pass-mix.txt b/test/passes/interesting-pass-mix.txt
index 0fbbc809c..c37414599 100644
--- a/test/passes/interesting-pass-mix.txt
+++ b/test/passes/interesting-pass-mix.txt
@@ -41,14 +41,16 @@
)
(loop $shape$4$continue
(call $trivial)
- (br_if $shape$4$continue
+ (if
(local.get $0)
+ (br $shape$4$continue)
)
)
(loop $shape$6$continue
(call $trivial)
- (br_if $shape$6$continue
+ (if
(local.get $0)
+ (br $shape$6$continue)
)
)
)
@@ -119,8 +121,9 @@
(call $before-and-after
(i32.const 9)
)
- (br_if $shape$4$continue
+ (if
(local.get $0)
+ (br $shape$4$continue)
)
)
(call $before-and-after
@@ -187,9 +190,12 @@
)
(block $block$7$break
(block $switch$3$default
- (br_table $block$7$break $block$7$break $block$7$break $switch$3$default
- (local.get $0)
+ (block $switch$3$case$7
+ (br_table $switch$3$case$7 $switch$3$case$7 $switch$3$case$7 $switch$3$default
+ (local.get $0)
+ )
)
+ (br $block$7$break)
)
(call $switch
(i32.const 2)
@@ -212,8 +218,9 @@
(call $if-br-wat
(i32.const 1)
)
- (br_if $block$2$break
+ (if
(local.get $0)
+ (br $block$2$break)
)
)
(call $if-br-wat
diff --git a/test/wasm2js/br.2asm.js b/test/wasm2js/br.2asm.js
index 73484e457..c60de9fc2 100644
--- a/test/wasm2js/br.2asm.js
+++ b/test/wasm2js/br.2asm.js
@@ -106,8 +106,10 @@ function asmFunc(global, env) {
function $13() {
var $0 = 0, $1_1 = 0, $3_1 = 0;
block : {
- $0 = 3;
- break block;
+ loop_in : while (1) {
+ $0 = 3;
+ break block;
+ };
}
return $0 | 0;
}
@@ -115,9 +117,11 @@ function asmFunc(global, env) {
function $14() {
var $0 = 0, $1_1 = 0, $3_1 = 0;
block : {
- dummy();
- $0 = 4;
- break block;
+ loop_in : while (1) {
+ dummy();
+ $0 = 4;
+ break block;
+ };
}
return $0 | 0;
}
@@ -125,9 +129,11 @@ function asmFunc(global, env) {
function $15() {
var $0 = 0;
block : {
- dummy();
- $0 = 5;
- break block;
+ loop_in : while (1) {
+ dummy();
+ $0 = 5;
+ break block;
+ };
}
return $0 | 0;
}
diff --git a/test/wasm2js/br_table.2asm.js b/test/wasm2js/br_table.2asm.js
index 4171374b9..5e1c2c05c 100644
--- a/test/wasm2js/br_table.2asm.js
+++ b/test/wasm2js/br_table.2asm.js
@@ -12560,10 +12560,12 @@ function asmFunc(global, env) {
function $20() {
var $1_1 = 0, $2_1 = 0, $4_1 = 0;
fake_return_waka123 : {
- $1_1 = 3;
- switch (0 | 0) {
- default:
- break fake_return_waka123;
+ loop_in : while (1) {
+ $1_1 = 3;
+ switch (0 | 0) {
+ default:
+ break fake_return_waka123;
+ };
};
}
return $1_1 | 0;
@@ -12572,11 +12574,13 @@ function asmFunc(global, env) {
function $21() {
var $1_1 = 0, $2_1 = 0, $4_1 = 0;
fake_return_waka123 : {
- dummy();
- $1_1 = 4;
- switch (-1 | 0) {
- default:
- break fake_return_waka123;
+ loop_in : while (1) {
+ dummy();
+ $1_1 = 4;
+ switch (-1 | 0) {
+ default:
+ break fake_return_waka123;
+ };
};
}
return $1_1 | 0;
@@ -12585,11 +12589,13 @@ function asmFunc(global, env) {
function $22() {
var $1_1 = 0;
fake_return_waka123 : {
- dummy();
- $1_1 = 5;
- switch (1 | 0) {
- default:
- break fake_return_waka123;
+ loop_in : while (1) {
+ dummy();
+ $1_1 = 5;
+ switch (1 | 0) {
+ default:
+ break fake_return_waka123;
+ };
};
}
return $1_1 | 0;
diff --git a/test/wasm2js/br_table_temp.2asm.js b/test/wasm2js/br_table_temp.2asm.js
index 3a56dda00..99d7ceeef 100644
--- a/test/wasm2js/br_table_temp.2asm.js
+++ b/test/wasm2js/br_table_temp.2asm.js
@@ -12556,10 +12556,12 @@ function asmFunc(global, env) {
function $20() {
var $1_1 = 0, $2_1 = 0, $4_1 = 0;
fake_return_waka123 : {
- $1_1 = 3;
- switch (0 | 0) {
- default:
- break fake_return_waka123;
+ loop_in : while (1) {
+ $1_1 = 3;
+ switch (0 | 0) {
+ default:
+ break fake_return_waka123;
+ };
};
}
return $1_1 | 0;
@@ -12568,11 +12570,13 @@ function asmFunc(global, env) {
function $21() {
var $1_1 = 0, $2_1 = 0, $4_1 = 0;
fake_return_waka123 : {
- dummy();
- $1_1 = 4;
- switch (-1 | 0) {
- default:
- break fake_return_waka123;
+ loop_in : while (1) {
+ dummy();
+ $1_1 = 4;
+ switch (-1 | 0) {
+ default:
+ break fake_return_waka123;
+ };
};
}
return $1_1 | 0;
@@ -12581,11 +12585,13 @@ function asmFunc(global, env) {
function $22() {
var $1_1 = 0;
fake_return_waka123 : {
- dummy();
- $1_1 = 5;
- switch (1 | 0) {
- default:
- break fake_return_waka123;
+ loop_in : while (1) {
+ dummy();
+ $1_1 = 5;
+ switch (1 | 0) {
+ default:
+ break fake_return_waka123;
+ };
};
}
return $1_1 | 0;
diff --git a/test/wasm2js/excess_fallthrough.2asm.js b/test/wasm2js/excess_fallthrough.2asm.js
index d1290aa50..3c8d09bf4 100644
--- a/test/wasm2js/excess_fallthrough.2asm.js
+++ b/test/wasm2js/excess_fallthrough.2asm.js
@@ -18,20 +18,22 @@ function asmFunc(global, env) {
function foo($0) {
$0 = $0 | 0;
- label$5 : {
- bar();
- block : {
- switch (123 | 0) {
- case 0:
- bar();
- break;
- default:
- break label$5;
- };
+ label$4 : while (1) {
+ label$5 : {
+ bar();
+ block : {
+ switch (123 | 0) {
+ case 0:
+ bar();
+ break;
+ default:
+ break label$5;
+ };
+ }
+ return;
}
- return;
- }
- abort();
+ abort();
+ };
}
return {