diff options
-rw-r--r-- | src/passes/Inlining.cpp | 88 | ||||
-rw-r--r-- | src/wasm-traversal.h | 47 | ||||
-rw-r--r-- | test/lit/passes/inlining-unreachable.wast | 58 | ||||
-rw-r--r-- | test/lit/passes/inlining_enable-tail-call.wast | 859 |
4 files changed, 841 insertions, 211 deletions
diff --git a/src/passes/Inlining.cpp b/src/passes/Inlining.cpp index 0643389c2..04bc6d78a 100644 --- a/src/passes/Inlining.cpp +++ b/src/passes/Inlining.cpp @@ -242,9 +242,10 @@ private: struct InliningAction { Expression** callSite; Function* contents; + bool insideATry; - InliningAction(Expression** callSite, Function* contents) - : callSite(callSite), contents(contents) {} + InliningAction(Expression** callSite, Function* contents, bool insideATry) + : callSite(callSite), contents(contents), insideATry(insideATry) {} }; struct InliningState { @@ -254,7 +255,7 @@ struct InliningState { std::unordered_map<Name, std::vector<InliningAction>> actionsForFunction; }; -struct Planner : public WalkerPass<PostWalker<Planner>> { +struct Planner : public WalkerPass<TryDepthWalker<Planner>> { bool isFunctionParallel() override { return true; } Planner(InliningState* state) : state(state) {} @@ -287,7 +288,7 @@ struct Planner : public WalkerPass<PostWalker<Planner>> { // can't add a new element in parallel assert(state->actionsForFunction.count(getFunction()->name) > 0); state->actionsForFunction[getFunction()->name].emplace_back( - &block->list[0], getModule()->getFunction(curr->target)); + &block->list[0], getModule()->getFunction(curr->target), tryDepth > 0); } } @@ -295,7 +296,7 @@ private: InliningState* state; }; -struct Updater : public PostWalker<Updater> { +struct Updater : public TryDepthWalker<Updater> { Module* module; std::map<Index, Index> localMapping; Name returnName; @@ -335,19 +336,38 @@ struct Updater : public PostWalker<Updater> { return; } - // Set the children to locals as necessary, then add a branch out of the - // inlined body. The branch label will be set later when we create branch - // targets for the calls. - Block* childBlock = ChildLocalizer(curr, getFunction(), *module, options) - .getChildrenReplacement(); - Break* branch = builder->makeBreak(Name()); - childBlock->list.push_back(branch); - childBlock->type = Type::unreachable; - replaceCurrent(childBlock); - - curr->isReturn = false; - curr->type = sig.results; - returnCallInfos.push_back({curr, branch}); + if (tryDepth == 0) { + // Return calls in inlined functions should only break out of + // the scope of the inlined code, not the entire function they + // are being inlined into. To achieve this, make the call a + // non-return call and add a break. This does not cause + // unbounded stack growth because inlining and return calling + // both avoid creating a new stack frame. + curr->isReturn = false; + curr->type = sig.results; + // There might still be unreachable children causing this to be + // unreachable. + curr->finalize(); + if (sig.results.isConcrete()) { + replaceCurrent(builder->makeBreak(returnName, curr)); + } else { + replaceCurrent(builder->blockify(curr, builder->makeBreak(returnName))); + } + } else { + // Set the children to locals as necessary, then add a branch out of the + // inlined body. The branch label will be set later when we create branch + // targets for the calls. + Block* childBlock = ChildLocalizer(curr, getFunction(), *module, options) + .getChildrenReplacement(); + Break* branch = builder->makeBreak(Name()); + childBlock->list.push_back(branch); + childBlock->type = Type::unreachable; + replaceCurrent(childBlock); + + curr->isReturn = false; + curr->type = sig.results; + returnCallInfos.push_back({curr, branch}); + } } void visitCall(Call* curr) { @@ -464,14 +484,15 @@ static Expression* doInlining(Module* module, // // (In this case we could use a second block and define the named block $X // after the call's parameters, but that adds work for an extremely rare - // situation.) The latter case does not apply if the call is a return_call, - // because in that case the call's children do not appear inside the same - // block as the inlined body. + // situation.) The latter case does not apply if the call is a + // return_call inside a try, because in that case the call's + // children do not appear inside the same block as the inlined body. + bool hoistCall = call->isReturn && action.insideATry; if (BranchUtils::hasBranchTarget(from->body, block->name) || - (!call->isReturn && BranchUtils::BranchSeeker::has(call, block->name))) { + (!hoistCall && BranchUtils::BranchSeeker::has(call, block->name))) { auto fromNames = BranchUtils::getBranchTargets(from->body); - auto callNames = call->isReturn ? BranchUtils::NameSet{} - : BranchUtils::BranchAccumulator::get(call); + auto callNames = hoistCall ? BranchUtils::NameSet{} + : BranchUtils::BranchAccumulator::get(call); block->name = Names::getValidName(block->name, [&](Name test) { return !fromNames.count(test) && !callNames.count(test); }); @@ -490,7 +511,7 @@ static Expression* doInlining(Module* module, updater.localMapping[i] = builder.addVar(into, from->getLocalType(i)); } - if (call->isReturn) { + if (hoistCall) { // Wrap the existing function body in a block we can branch out of before // entering the inlined function body. This block must have a name that is // different from any other block name above the branch. @@ -544,7 +565,16 @@ static Expression* doInlining(Module* module, builder.makeLocalSet(updater.localMapping[from->getVarIndexBase() + i], LiteralUtils::makeZero(type, *module))); } - *action.callSite = block; + if (call->isReturn) { + assert(!action.insideATry); + if (retType.isConcrete()) { + *action.callSite = builder.makeReturn(block); + } else { + *action.callSite = builder.makeSequence(block, builder.makeReturn()); + } + } else { + *action.callSite = block; + } } // Generate and update the inlined contents @@ -1396,8 +1426,10 @@ struct InlineMainPass : public Pass { // No call at all. return; } - doInlining( - module, main, InliningAction(callSite, originalMain), getPassOptions()); + doInlining(module, + main, + InliningAction(callSite, originalMain, true), + getPassOptions()); } }; diff --git a/src/wasm-traversal.h b/src/wasm-traversal.h index f5f25dd1f..c8078164b 100644 --- a/src/wasm-traversal.h +++ b/src/wasm-traversal.h @@ -537,6 +537,53 @@ struct ExpressionStackWalker : public PostWalker<SubType, VisitorType> { } }; +// Traversal keeping track of try depth + +// This is used to keep track of whether we are in the scope of an +// exception handler. This matters since return_call is not equivalent +// to return + call within an exception handler. If another kind of +// handler scope is added, this code will need to be updated. +template<typename SubType, typename VisitorType = Visitor<SubType>> +struct TryDepthWalker : public PostWalker<SubType, VisitorType> { + TryDepthWalker() = default; + + size_t tryDepth = 0; + + static void doEnterTry(SubType* self, Expression** currp) { + self->tryDepth++; + } + + static void doLeaveTry(SubType* self, Expression** currp) { + self->tryDepth--; + } + + static void scan(SubType* self, Expression** currp) { + auto* curr = *currp; + + if (curr->is<Try>()) { + self->pushTask(SubType::doVisitTry, currp); + auto& catchBodies = curr->cast<Try>()->catchBodies; + for (int i = int(catchBodies.size()) - 1; i >= 0; i--) { + self->pushTask(SubType::scan, &catchBodies[i]); + } + self->pushTask(SubType::doLeaveTry, currp); + self->pushTask(SubType::scan, &curr->cast<Try>()->body); + self->pushTask(SubType::doEnterTry, currp); + return; + } + + if (curr->is<TryTable>()) { + self->pushTask(SubType::doLeaveTry, currp); + } + + PostWalker<SubType, VisitorType>::scan(self, currp); + + if (curr->is<TryTable>()) { + self->pushTask(SubType::doEnterTry, currp); + } + } +}; + } // namespace wasm #endif // wasm_wasm_traversal_h diff --git a/test/lit/passes/inlining-unreachable.wast b/test/lit/passes/inlining-unreachable.wast index 2c93359fd..1b08ac2b0 100644 --- a/test/lit/passes/inlining-unreachable.wast +++ b/test/lit/passes/inlining-unreachable.wast @@ -66,22 +66,51 @@ ) (module - ;; CHECK: (type $0 (func (param i32) (result i32))) + ;; CHECK: (type $0 (func)) - ;; CHECK: (type $1 (func)) + ;; CHECK: (type $1 (func (param i32) (result i32))) - ;; CHECK: (import "env" "imported" (func $imported (type $0) (param i32) (result i32))) + ;; CHECK: (import "env" "imported" (func $imported (type $1) (param i32) (result i32))) (import "env" "imported" (func $imported (param i32) (result i32))) - ;; CHECK: (func $caller (type $1) + ;; CHECK: (func $caller (type $0) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (block ;; CHECK-NEXT: (block $__inlined_func$callee + ;; CHECK-NEXT: (call $imported + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $caller + (drop + (call $callee) + ) + ) + + ;; After inlining, this return_call will turn into a call, but should still be + ;; unreachable. Validation will fail if it is not. + (func $callee (result i32) + (return_call $imported + (unreachable) + ) + ) + + ;; CHECK: (func $caller-2 (type $0) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (block $__inlined_func$callee-2$1 ;; CHECK-NEXT: (block ;; CHECK-NEXT: (block $__return_call ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (unreachable) - ;; CHECK-NEXT: (br $__return_call) + ;; CHECK-NEXT: (try $try + ;; CHECK-NEXT: (do + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (br $__return_call) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (call $imported @@ -92,17 +121,20 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $caller + (func $caller-2 (drop - (call $callee) + (call $callee-2) ) ) - ;; After inlining, this return_call will turn into a call, but should still be - ;; unreachable. Validation will fail if it is not. - (func $callee (result i32) - (return_call $imported - (unreachable) + ;; Same as above, but with a return_call with a try block + (func $callee-2 (result i32) + (try + (do + (return_call $imported + (unreachable) + ) + ) ) ) ) diff --git a/test/lit/passes/inlining_enable-tail-call.wast b/test/lit/passes/inlining_enable-tail-call.wast index 49ea1c3c4..77aa77974 100644 --- a/test/lit/passes/inlining_enable-tail-call.wast +++ b/test/lit/passes/inlining_enable-tail-call.wast @@ -1,7 +1,7 @@ ;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited. ;; NOTE: This test was ported using port_passes_tests_to_lit.py and could be cleaned up. -;; RUN: foreach %s %t wasm-opt --inlining --enable-tail-call -S -o - | filecheck %s +;; RUN: foreach %s %t wasm-opt --inlining --enable-tail-call --enable-exception-handling -S -o - | filecheck %s (module (table 1 1 funcref) @@ -474,20 +474,39 @@ ;; CHECK: (type $0 (func)) ;; CHECK: (func $caller + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (block $__inlined_func$callee + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (i32.const 42) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (return) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $caller + (return_call $callee) + ) + ;; CHECK: (func $caller-2 ;; CHECK-NEXT: (block $__original_body - ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (br $__original_body) + ;; CHECK-NEXT: (try $try + ;; CHECK-NEXT: (do + ;; CHECK-NEXT: (br $__original_body) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (return) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (block $__inlined_func$callee + ;; CHECK-NEXT: (block $__inlined_func$callee$1 ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.const 42) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $caller - (return_call $callee) + (func $caller-2 + (try + (do + (return_call $callee) + ) + ) ) (func $callee (drop @@ -501,19 +520,35 @@ ;; CHECK: (type $0 (func (result i32))) ;; CHECK: (func $caller (result i32) + ;; CHECK-NEXT: (return + ;; CHECK-NEXT: (block $__inlined_func$callee (result i32) + ;; CHECK-NEXT: (i32.const 42) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $caller (result i32) + (return_call $callee) + ) + ;; CHECK: (func $caller-2 (result i32) ;; CHECK-NEXT: (block $__original_body ;; CHECK-NEXT: (return - ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (br $__original_body) + ;; CHECK-NEXT: (try $try + ;; CHECK-NEXT: (do + ;; CHECK-NEXT: (br $__original_body) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (block $__inlined_func$callee (result i32) + ;; CHECK-NEXT: (block $__inlined_func$callee$1 (result i32) ;; CHECK-NEXT: (i32.const 42) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $caller (result i32) - (return_call $callee) + (func $caller-2 (result i32) + (try + (do + (return_call $callee) + ) + ) ) (func $callee (result i32) (i32.const 42) @@ -526,26 +561,51 @@ ;; CHECK: (func $caller ;; CHECK-NEXT: (local $0 i32) + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (block $__inlined_func$callee + ;; CHECK-NEXT: (local.set $0 + ;; CHECK-NEXT: (i32.const 42) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (return) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $caller + (return_call $callee + (i32.const 42) + ) + ) + ;; CHECK: (func $caller-2 + ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (block $__original_body - ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (local.set $0 - ;; CHECK-NEXT: (i32.const 42) + ;; CHECK-NEXT: (try $try + ;; CHECK-NEXT: (do + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (local.set $0 + ;; CHECK-NEXT: (i32.const 42) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (br $__original_body) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (br $__original_body) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (return) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (block $__inlined_func$callee + ;; CHECK-NEXT: (block $__inlined_func$callee$1 ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $caller - (return_call $callee - (i32.const 42) + (func $caller-2 + (try + (do + (return_call $callee + (i32.const 42) + ) + ) ) ) (func $callee (param i32) @@ -561,25 +621,47 @@ ;; CHECK: (func $caller (result i32) ;; CHECK-NEXT: (local $0 i32) + ;; CHECK-NEXT: (return + ;; CHECK-NEXT: (block $__inlined_func$callee (result i32) + ;; CHECK-NEXT: (local.set $0 + ;; CHECK-NEXT: (i32.const 42) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.get $0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $caller (result i32) + (return_call $callee + (i32.const 42) + ) + ) + ;; CHECK: (func $caller-2 (result i32) + ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (block $__original_body ;; CHECK-NEXT: (return - ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (local.set $0 - ;; CHECK-NEXT: (i32.const 42) + ;; CHECK-NEXT: (try $try + ;; CHECK-NEXT: (do + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (local.set $0 + ;; CHECK-NEXT: (i32.const 42) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (br $__original_body) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (br $__original_body) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (block $__inlined_func$callee (result i32) + ;; CHECK-NEXT: (block $__inlined_func$callee$1 (result i32) ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $caller (result i32) - (return_call $callee - (i32.const 42) + (func $caller-2 (result i32) + (try + (do + (return_call $callee + (i32.const 42) + ) + ) ) ) (func $callee (param i32) (result i32) @@ -596,16 +678,64 @@ ;; CHECK-NEXT: (local $y i32) ;; CHECK-NEXT: (local $2 i32) ;; CHECK-NEXT: (local $3 i32) - ;; CHECK-NEXT: (block $__original_body - ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (block $__inlined_func$callee + ;; CHECK-NEXT: (local.set $2 + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.set $3 + ;; CHECK-NEXT: (local.get $y) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (local.set $2 - ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $2) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.set $3 - ;; CHECK-NEXT: (local.get $y) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $3) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (return) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $caller + (local $x i32) + (local $y i32) + (return_call $callee + (local.get $x) + (local.get $y) + ) + ) + (func $callee (param i32 i32) + (drop + (local.get 0) + ) + (drop + (local.get 1) + ) + ) +) +(module + ;; Multiple params, no result, return_call within try block + ;; CHECK: (type $0 (func)) + + ;; CHECK: (func $caller + ;; CHECK-NEXT: (local $x i32) + ;; CHECK-NEXT: (local $y i32) + ;; CHECK-NEXT: (local $2 i32) + ;; CHECK-NEXT: (local $3 i32) + ;; CHECK-NEXT: (block $__original_body + ;; CHECK-NEXT: (try $try + ;; CHECK-NEXT: (do + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (local.set $2 + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.set $3 + ;; CHECK-NEXT: (local.get $y) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (br $__original_body) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (br $__original_body) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (return) @@ -624,9 +754,13 @@ (func $caller (local $x i32) (local $y i32) - (return_call $callee - (local.get $x) - (local.get $y) + (try + (do + (return_call $callee + (local.get $x) + (local.get $y) + ) + ) ) ) (func $callee (param i32 i32) @@ -644,36 +778,73 @@ ;; CHECK: (type $0 (func)) ;; CHECK: (func $first + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (block $__inlined_func$second + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (block $__inlined_func$third$2 + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (i32.const 42) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (return) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (return) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $first + (return_call $second) + ) + ;; CHECK: (func $first-2 ;; CHECK-NEXT: (block $__original_body_0 ;; CHECK-NEXT: (block ;; CHECK-NEXT: (block $__original_body - ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (br $__original_body) + ;; CHECK-NEXT: (try $try + ;; CHECK-NEXT: (do + ;; CHECK-NEXT: (br $__original_body) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (return) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (block $__inlined_func$second - ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (br $__original_body_0) + ;; CHECK-NEXT: (block $__inlined_func$second-2$1 + ;; CHECK-NEXT: (try $try0 + ;; CHECK-NEXT: (do + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (br $__original_body_0) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (return) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (block $__inlined_func$third$1 + ;; CHECK-NEXT: (block $__inlined_func$third$3 ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.const 42) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $first - (return_call $second) + (func $first-2 + (try + (do + (return_call $second-2) + ) + ) ) (func $second (return_call $third) ) + (func $second-2 + (try + (do + (return_call $third) + ) + ) + ) (func $third (drop (i32.const 42) @@ -692,35 +863,109 @@ ;; CHECK-NEXT: (local $3 i32) ;; CHECK-NEXT: (local $4 i32) ;; CHECK-NEXT: (local $5 i32) + ;; CHECK-NEXT: (return + ;; CHECK-NEXT: (block $__inlined_func$second + ;; CHECK-NEXT: (local.set $2 + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.set $3 + ;; CHECK-NEXT: (local.get $y) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (return + ;; CHECK-NEXT: (block $__inlined_func$third$1 (result i32) + ;; CHECK-NEXT: (local.set $4 + ;; CHECK-NEXT: (local.get $2) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.set $5 + ;; CHECK-NEXT: (local.get $3) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (block (result i32) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $4) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $5) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.const 42) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $first (result i32) + (local $x i32) + (local $y i32) + (return_call $second + (local.get $x) + (local.get $y) + ) + ) + (func $second (param i32 i32) (result i32) + (return_call $third + (local.get 0) + (local.get 1) + ) + ) + (func $third (param i32 i32) (result i32) + (drop + (local.get 0) + ) + (drop + (local.get 1) + ) + (i32.const 42) + ) +) + +(module + ;; Chain of return_calls with params and results, return_calls in try block. + ;; CHECK: (type $0 (func (result i32))) + + ;; CHECK: (func $first (result i32) + ;; CHECK-NEXT: (local $x i32) + ;; CHECK-NEXT: (local $y i32) + ;; CHECK-NEXT: (local $2 i32) + ;; CHECK-NEXT: (local $3 i32) + ;; CHECK-NEXT: (local $4 i32) + ;; CHECK-NEXT: (local $5 i32) ;; CHECK-NEXT: (block $__original_body_0 ;; CHECK-NEXT: (return ;; CHECK-NEXT: (block ;; CHECK-NEXT: (block $__original_body ;; CHECK-NEXT: (return - ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (local.set $2 - ;; CHECK-NEXT: (local.get $x) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.set $3 - ;; CHECK-NEXT: (local.get $y) + ;; CHECK-NEXT: (try $try + ;; CHECK-NEXT: (do + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (local.set $2 + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.set $3 + ;; CHECK-NEXT: (local.get $y) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (br $__original_body) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (br $__original_body) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block $__inlined_func$second - ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (try $try0 + ;; CHECK-NEXT: (do ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (local.set $4 - ;; CHECK-NEXT: (local.get $2) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.set $5 - ;; CHECK-NEXT: (local.get $3) + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (local.set $4 + ;; CHECK-NEXT: (local.get $2) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.set $5 + ;; CHECK-NEXT: (local.get $3) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (br $__original_body_0) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (br $__original_body_0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -743,15 +988,23 @@ (func $first (result i32) (local $x i32) (local $y i32) - (return_call $second - (local.get $x) - (local.get $y) + (try + (do + (return_call $second + (local.get $x) + (local.get $y) + ) + ) ) ) (func $second (param i32 i32) (result i32) - (return_call $third - (local.get 0) - (local.get 1) + (try + (do + (return_call $third + (local.get 0) + (local.get 1) + ) + ) ) ) (func $third (param i32 i32) (result i32) @@ -768,20 +1021,46 @@ (module ;; CHECK: (type $0 (func)) - ;; CHECK: (func $0 + ;; CHECK: (func $first ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (block (result i32) - ;; CHECK-NEXT: (block $__inlined_func$1 (result i32) + ;; CHECK-NEXT: (block $__inlined_func$second (result i32) + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (br $__inlined_func$second + ;; CHECK-NEXT: (block (result i32) + ;; CHECK-NEXT: (block $__inlined_func$third$2 (result i32) + ;; CHECK-NEXT: (i32.const 42) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $first + (drop + (call $second) + ) + ) + ;; CHECK: (func $first-2 + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (block (result i32) + ;; CHECK-NEXT: (block $__inlined_func$second-2$1 (result i32) ;; CHECK-NEXT: (block (result i32) ;; CHECK-NEXT: (block $__return_call ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (br $__return_call) + ;; CHECK-NEXT: (try $try + ;; CHECK-NEXT: (do + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (br $__return_call) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block (result i32) - ;; CHECK-NEXT: (block $__inlined_func$2$1 (result i32) + ;; CHECK-NEXT: (block $__inlined_func$third$3 (result i32) ;; CHECK-NEXT: (i32.const 42) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -790,15 +1069,22 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $0 + (func $first-2 (drop - (call $1) + (call $second-2) ) ) - (func $1 (result i32) - (return_call $2) + (func $second (result i32) + (return_call $third) + ) + (func $second-2 (result i32) + (try + (do + (return_call $third) + ) + ) ) - (func $2 (result i32) + (func $third (result i32) (i32.const 42) ) ) @@ -806,18 +1092,45 @@ (module ;; CHECK: (type $0 (func)) - ;; CHECK: (func $0 + ;; CHECK: (func $first ;; CHECK-NEXT: (local $0 i32) - ;; CHECK-NEXT: (block $__inlined_func$1 + ;; CHECK-NEXT: (block $__inlined_func$second ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (block $__return_call + ;; CHECK-NEXT: (block ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (br $__return_call) + ;; CHECK-NEXT: (block $__inlined_func$third$2 + ;; CHECK-NEXT: (local.set $0 + ;; CHECK-NEXT: (i32.const 42) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (br $__inlined_func$second) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $first + (call $second) + ) + ;; CHECK: (func $first-2 + ;; CHECK-NEXT: (local $0 i32) + ;; CHECK-NEXT: (block $__inlined_func$second-2$1 + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (block $__return_call + ;; CHECK-NEXT: (try $try + ;; CHECK-NEXT: (do + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (br $__return_call) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (br $__inlined_func$1) + ;; CHECK-NEXT: (br $__inlined_func$second-2$1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (block $__inlined_func$2$1 + ;; CHECK-NEXT: (block $__inlined_func$third$3 ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (i32.const 42) ;; CHECK-NEXT: ) @@ -829,15 +1142,24 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $0 - (call $1) + (func $first-2 + (call $second-2) ) - (func $1 - (return_call $2 + (func $second + (return_call $third (i32.const 42) ) ) - (func $2 (param i32) + (func $second-2 + (try + (do + (return_call $third + (i32.const 42) + ) + ) + ) + ) + (func $third (param i32) (drop (local.get 0) ) @@ -850,34 +1172,60 @@ ;; CHECK: (type $1 (func (param i32))) - ;; CHECK: (func $0 - ;; CHECK-NEXT: (block $__inlined_func$1 + ;; CHECK: (func $first + ;; CHECK-NEXT: (block $__inlined_func$second + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (call $third + ;; CHECK-NEXT: (br $__inlined_func$second) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (br $__inlined_func$second) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $first + (call $second) + ) + ;; CHECK: (func $first-2 + ;; CHECK-NEXT: (block $__inlined_func$second-2$1 ;; CHECK-NEXT: (block ;; CHECK-NEXT: (block $__return_call - ;; CHECK-NEXT: (br $__inlined_func$1) - ;; CHECK-NEXT: (br $__return_call) - ;; CHECK-NEXT: (br $__inlined_func$1) + ;; CHECK-NEXT: (try $try + ;; CHECK-NEXT: (do + ;; CHECK-NEXT: (br $__inlined_func$second-2$1) + ;; CHECK-NEXT: (br $__return_call) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (br $__inlined_func$second-2$1) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (call $2 + ;; CHECK-NEXT: (call $third ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $0 - (call $1) + (func $first-2 + (call $second-2) ) - (func $1 - (return_call $2 + (func $second + (return_call $third (return) ) ) - ;; CHECK: (func $2 (param $0 i32) + (func $second-2 + (try + (do + (return_call $third + (return) + ) + ) + ) + ) + ;; CHECK: (func $third (param $0 i32) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $2 (param i32) + (func $third (param i32) (drop (local.get 0) ) @@ -888,24 +1236,47 @@ ;; Same as above, but this time the child is not unreachable. ;; CHECK: (type $0 (func)) - ;; CHECK: (func $0 + ;; CHECK: (type $1 (func (param i32))) + + ;; CHECK: (func $first + ;; CHECK-NEXT: (block $__inlined_func$second + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (call $third + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (br $__inlined_func$second) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (br $__inlined_func$second) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $first + (call $second) + ) + ;; CHECK: (func $first-2 ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (local $1 i32) - ;; CHECK-NEXT: (block $__inlined_func$1 + ;; CHECK-NEXT: (block $__inlined_func$second-2$1 ;; CHECK-NEXT: (block ;; CHECK-NEXT: (block $__return_call - ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (local.tee $0 + ;; CHECK-NEXT: (try $try + ;; CHECK-NEXT: (do ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (br $__inlined_func$1) + ;; CHECK-NEXT: (local.tee $0 + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (br $__inlined_func$second-2$1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (br $__return_call) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (br $__return_call) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (br $__inlined_func$1) + ;; CHECK-NEXT: (br $__inlined_func$second-2$1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (block $__inlined_func$2$1 + ;; CHECK-NEXT: (block $__inlined_func$third$2 ;; CHECK-NEXT: (local.set $1 ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) @@ -917,17 +1288,33 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $0 - (call $1) + (func $first-2 + (call $second-2) ) - (func $1 - (return_call $2 + (func $second + (return_call $third (block (result i32) (return) ) ) ) - (func $2 (param i32) + (func $second-2 + (try + (do + (return_call $third + (block (result i32) + (return) + ) + ) + ) + ) + ) + ;; CHECK: (func $third (param $0 i32) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $third (param i32) (drop (local.get 0) ) @@ -942,14 +1329,43 @@ (table 10 funcref) ;; CHECK: (table $0 10 funcref) - ;; CHECK: (func $0 + ;; CHECK: (func $caller + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (block (result i32) + ;; CHECK-NEXT: (block $__inlined_func$callee (result i32) + ;; CHECK-NEXT: (br $__inlined_func$callee + ;; CHECK-NEXT: (call_indirect (type $T) + ;; CHECK-NEXT: (i32.const 42) + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $caller + (drop + (call $callee) + ) + ) + (func $callee (result i32) + (return_call_indirect (type $T) + (i32.const 42) + (i32.const 0) + ) + ) + ;; CHECK: (func $caller-2 ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (block (result i32) - ;; CHECK-NEXT: (block $__inlined_func$1 (result i32) + ;; CHECK-NEXT: (block $__inlined_func$callee-2$1 (result i32) ;; CHECK-NEXT: (block (result i32) ;; CHECK-NEXT: (block $__return_call ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (br $__return_call) + ;; CHECK-NEXT: (try $try + ;; CHECK-NEXT: (do + ;; CHECK-NEXT: (br $__return_call) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (call_indirect (type $T) @@ -961,15 +1377,19 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $0 + (func $caller-2 (drop - (call $1) + (call $callee-2) ) ) - (func $1 (result i32) - (return_call_indirect (type $T) - (i32.const 42) - (i32.const 0) + (func $callee-2 (result i32) + (try + (do + (return_call_indirect (type $T) + (i32.const 42) + (i32.const 0) + ) + ) ) ) ) @@ -981,29 +1401,57 @@ (table 10 funcref) ;; CHECK: (table $0 10 funcref) - ;; CHECK: (func $0 - ;; CHECK-NEXT: (block $__inlined_func$1 + ;; CHECK: (func $caller + ;; CHECK-NEXT: (block $__inlined_func$callee ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (block $__return_call - ;; CHECK-NEXT: (br $__return_call) - ;; CHECK-NEXT: (br $__inlined_func$1) - ;; CHECK-NEXT: ) ;; CHECK-NEXT: (call_indirect (type $T) ;; CHECK-NEXT: (i32.const 42) ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (br $__inlined_func$callee) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $0 - (call $1) + (func $caller + (call $callee) ) - (func $1 + (func $callee (return_call_indirect (type $T) (i32.const 42) (i32.const 0) ) ) + ;; CHECK: (func $caller-2 + ;; CHECK-NEXT: (block $__inlined_func$callee-2$1 + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (block $__return_call + ;; CHECK-NEXT: (try $try + ;; CHECK-NEXT: (do + ;; CHECK-NEXT: (br $__return_call) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (br $__inlined_func$callee-2$1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (call_indirect (type $T) + ;; CHECK-NEXT: (i32.const 42) + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $caller-2 + (call $callee-2) + ) + (func $callee-2 + (try + (do + (return_call_indirect (type $T) + (i32.const 42) + (i32.const 0) + ) + ) + ) + ) ) (module ;; CHECK: (type $6 (func)) @@ -1040,6 +1488,80 @@ ;; CHECK-NEXT: (block ;; CHECK-NEXT: (block $__inlined_func$13$1 ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (if + ;; CHECK-NEXT: (global.get $global$0) + ;; CHECK-NEXT: (then + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (block $__inlined_func$2 + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (if + ;; CHECK-NEXT: (global.get $global$0) + ;; CHECK-NEXT: (then + ;; CHECK-NEXT: (br $__inlined_func$2) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (global.set $global$0 + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (br $__inlined_func$13$1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: ) + (func $19 (; 19 ;) (type $6) + (call $13) + (unreachable) + ) +) +(module + ;; CHECK: (type $6 (func)) + (type $6 (func)) + ;; CHECK: (global $global$0 (mut i32) (i32.const 10)) + + ;; CHECK: (memory $0 1 1) + (memory $0 1 1) + (global $global$0 (mut i32) (i32.const 10)) + ;; CHECK: (export "func_102_invoker" (func $19)) + (export "func_102_invoker" (func $19)) + (func $2 (; 2 ;) (type $6) + (if + (global.get $global$0) + (then + (return) + ) + ) + (global.set $global$0 + (i32.const 1) + ) + ) + (func $13 (; 13 ;) (type $6) + (if + (global.get $global$0) + (then + (unreachable) + ) + ) + (try + (do + (return_call $2) + ) + ) + ) + ;; CHECK: (func $19 + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (block $__inlined_func$13$1 + ;; CHECK-NEXT: (block ;; CHECK-NEXT: (block $__original_body ;; CHECK-NEXT: (block ;; CHECK-NEXT: (if @@ -1048,8 +1570,10 @@ ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (br $__original_body) + ;; CHECK-NEXT: (try $try + ;; CHECK-NEXT: (do + ;; CHECK-NEXT: (br $__original_body) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (br $__inlined_func$13$1) @@ -1086,42 +1610,37 @@ (export "is_even" (func $is_even)) ;; CHECK: (func $is_even (param $i i32) (result i32) ;; CHECK-NEXT: (local $1 i32) - ;; CHECK-NEXT: (block $__original_body - ;; CHECK-NEXT: (return - ;; CHECK-NEXT: (if (result i32) - ;; CHECK-NEXT: (i32.eqz - ;; CHECK-NEXT: (local.get $i) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (then - ;; CHECK-NEXT: (i32.const 1) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (else - ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (local.set $1 - ;; CHECK-NEXT: (i32.sub - ;; CHECK-NEXT: (local.get $i) - ;; CHECK-NEXT: (i32.const 1) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (if (result i32) + ;; CHECK-NEXT: (i32.eqz + ;; CHECK-NEXT: (local.get $i) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (then + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (else + ;; CHECK-NEXT: (return + ;; CHECK-NEXT: (block $__inlined_func$is_odd (result i32) + ;; CHECK-NEXT: (local.set $1 + ;; CHECK-NEXT: (i32.sub + ;; CHECK-NEXT: (local.get $i) + ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (br $__original_body) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (block $__inlined_func$is_odd (result i32) - ;; CHECK-NEXT: (if (result i32) - ;; CHECK-NEXT: (i32.eqz - ;; CHECK-NEXT: (local.get $1) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (then - ;; CHECK-NEXT: (i32.const 0) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (else - ;; CHECK-NEXT: (return_call $is_even - ;; CHECK-NEXT: (i32.sub - ;; CHECK-NEXT: (local.get $1) - ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: (if (result i32) + ;; CHECK-NEXT: (i32.eqz + ;; CHECK-NEXT: (local.get $1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (then + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (else + ;; CHECK-NEXT: (return_call $is_even + ;; CHECK-NEXT: (i32.sub + ;; CHECK-NEXT: (local.get $1) + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) |