summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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 {