diff options
author | Alon Zakai <azakai@google.com> | 2020-10-26 18:43:29 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-10-26 18:43:29 -0700 |
commit | f3125579cca998300c230232ed4ded4fe0aaa34c (patch) | |
tree | aeceb7770b47fe8d5eef0f38e26fa540b67db482 | |
parent | 514a6c5eb339b67db852643405428f3add7d0e39 (diff) | |
download | binaryen-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.
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 Binary files differindex 5fa1892bd..5fa1892bd 100644 --- a/test/passes/dce_vacuum.wasm +++ b/test/passes/dce_vacuum_remove-unused-names.wasm 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 { |