diff options
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 { |