From fd6ab9d3fe49e18bcf38af0c9b0dfbc4bf173585 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 11 Jul 2024 11:14:51 -0700 Subject: [PATCH 01/35] drop --- src/passes/Monomorphize.cpp | 49 ++++++++++++++++++++++++++++--------- 1 file changed, 38 insertions(+), 11 deletions(-) diff --git a/src/passes/Monomorphize.cpp b/src/passes/Monomorphize.cpp index 5237f786450..9fc77734646 100644 --- a/src/passes/Monomorphize.cpp +++ b/src/passes/Monomorphize.cpp @@ -103,6 +103,31 @@ namespace wasm { namespace { +// Finds the calls and whether each one of them is dropped. +struct CallFinder : public Walker { + struct Info { + Call* call; + bool dropped; + }; + + std::vector infos; + + void visitCall(Call* curr) { + // Add the call as non-dropped, and update the drop later if we are. + infos.push_back(Info{curr, false}); + } + + void visitDrop(Drop* curr) { + if (curr->value->is()) { + // The call we just added to |infos| is dropped. + assert(!infos.empty()); + auto& back = infos.back(); + assert(back->call == curr); + back->dropped = true; + } + } +}; + // Relevant information about a callsite for purposes of monomorphization. struct CallContext { // The operands of the call, processed to leave the parts that make sense to @@ -181,12 +206,12 @@ struct CallContext { // remaining values by updating |newOperands| (for example, if all the values // sent are constants, then |newOperands| will end up empty, as we have // nothing left to send). - void buildFromCall(Call* call, + void buildFromCall(CallFinder::Info& info, std::vector& newOperands, Module& wasm) { Builder builder(wasm); - for (auto* operand : call->operands) { + for (auto* operand : info.call->operands) { // Process the operand. This is a copy operation, as we are trying to move // (copy) code from the callsite into the called function. When we find we // can copy then we do so, and when we cannot that value remains as a @@ -212,8 +237,7 @@ struct CallContext { })); } - // TODO: handle drop - dropped = false; + dropped = info.dropped; } // Checks whether an expression can be moved into the context. @@ -309,27 +333,30 @@ struct Monomorphize : public Pass { // to call the monomorphized targets. for (auto name : funcNames) { auto* func = module->getFunction(name); - for (auto* call : FindAll(func->body).list) { - if (call->type == Type::unreachable) { + + CallFinder callFinder; + callFinder.walk(func->body); + for (auto& info : callFinder.infos) { + if (info.call->type == Type::unreachable) { // Ignore unreachable code. // TODO: return_call? continue; } - if (call->target == name) { + if (info.call->target == name) { // Avoid recursion, which adds some complexity (as we'd be modifying // ourselves if we apply optimizations). continue; } - processCall(call, *module); + processCall(info, *module); } } } // Try to optimize a call. - void processCall(Call* call, Module& wasm) { - auto target = call->target; + void processCall(CallFinder::Info& info, Module& wasm) { + auto target = info.call->target; auto* func = wasm.getFunction(target); if (func->imported()) { // Nothing to do since this calls outside of the module. @@ -342,7 +369,7 @@ struct Monomorphize : public Pass { // if we use that context. CallContext context; std::vector newOperands; - context.buildFromCall(call, newOperands, wasm); + context.buildFromCall(info, newOperands, wasm); // See if we've already evaluated this function + call context. If so, then // we've memoized the result. From 170a6f06fd13fb3a363a7ffc587f0b6f133cde43 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 11 Jul 2024 11:24:56 -0700 Subject: [PATCH 02/35] yolo --- src/ir/return-utils.h | 46 ++++++++++++++++++++++++++ src/passes/DeadArgumentElimination.cpp | 19 ++--------- src/passes/Monomorphize.cpp | 10 ++++-- 3 files changed, 56 insertions(+), 19 deletions(-) create mode 100644 src/ir/return-utils.h diff --git a/src/ir/return-utils.h b/src/ir/return-utils.h new file mode 100644 index 00000000000..c53797bd8d6 --- /dev/null +++ b/src/ir/return-utils.h @@ -0,0 +1,46 @@ +/* + * Copyright 2024 WebAssembly Community Group participants + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef wasm_ir_return_h +#define wasm_ir_return_h + +#include "wasm-traversal.h" +#include "wasm.h" + +namespace wasm::ReturnUtils { + +// Removes values from both explicit returns and implicit ones (values that flow +// from the body). This is useful after changing a function's type to no longer +// return anything. +struct ReturnValueRemover : public PostWalker { + void visitReturn(Return* curr) { + auto* value = curr->value; + assert(value); + curr->value = nullptr; + Builder builder(*module); + replaceCurrent(builder.makeSequence(builder.makeDrop(value), curr)); + } + + void visitFunction(Function* curr) { + if (curr->body->type.isConcrete()) { + curr->body = Builder(*module).makeDrop(curr->body); + } + } +}; + +} // namespace wasm::ReturnUtils + +#endif // wasm_ir_return_h diff --git a/src/passes/DeadArgumentElimination.cpp b/src/passes/DeadArgumentElimination.cpp index 4a341571e4c..fdb5d71cfe4 100644 --- a/src/passes/DeadArgumentElimination.cpp +++ b/src/passes/DeadArgumentElimination.cpp @@ -42,6 +42,7 @@ #include "ir/find_all.h" #include "ir/lubs.h" #include "ir/module-utils.h" +#include "ir/return-utils.h" #include "ir/type-updating.h" #include "ir/utils.h" #include "param-utils.h" @@ -358,23 +359,7 @@ struct DAE : public Pass { } } // Remove any return values. - struct ReturnUpdater : public PostWalker { - Module* module; - ReturnUpdater(Function* func, Module* module) : module(module) { - walk(func->body); - } - void visitReturn(Return* curr) { - auto* value = curr->value; - assert(value); - curr->value = nullptr; - Builder builder(*module); - replaceCurrent(builder.makeSequence(builder.makeDrop(value), curr)); - } - } returnUpdater(func, module); - // Remove any value flowing out. - if (func->body->type.isConcrete()) { - func->body = Builder(*module).makeDrop(func->body); - } + ReturnUtils::ReturnValueRemover().walkFunctionInModule(func, module); } // Given a function and all the calls to it, see if we can refine the type of diff --git a/src/passes/Monomorphize.cpp b/src/passes/Monomorphize.cpp index 9fc77734646..5e96181a96e 100644 --- a/src/passes/Monomorphize.cpp +++ b/src/passes/Monomorphize.cpp @@ -92,6 +92,7 @@ #include "ir/manipulation.h" #include "ir/module-utils.h" #include "ir/names.h" +#include "ir/return-utils.h" #include "ir/type-updating.h" #include "ir/utils.h" #include "pass.h" @@ -480,8 +481,9 @@ struct Monomorphize : public Pass { newParams.push_back(operand->type); } } - // TODO: support changes to results. - auto newResults = func->getResults(); + // If we were dropped then we are pulling the drop into the monomorphized + // function, which means we return nothing. + auto newResults = context.dropped ? Type::none : func->getResults(); newFunc->type = Signature(Type(newParams), newResults); // We must update local indexes: the new function has a potentially @@ -576,6 +578,10 @@ struct Monomorphize : public Pass { newFunc->body = builder.makeBlock(pre); } + if (context.dropped) { + ReturnUtils::ReturnValueRemover().walkFunctionInModule(func, &wasm); + } + return newFunc; } From 206339e7141db61f5f63922e221c3b23219785f9 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 11 Jul 2024 11:27:31 -0700 Subject: [PATCH 03/35] yolo --- src/ir/return-utils.h | 5 +++-- src/passes/Monomorphize.cpp | 9 +++++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/ir/return-utils.h b/src/ir/return-utils.h index c53797bd8d6..f14b766b2b6 100644 --- a/src/ir/return-utils.h +++ b/src/ir/return-utils.h @@ -17,6 +17,7 @@ #ifndef wasm_ir_return_h #define wasm_ir_return_h +#include "wasm-builder.h" #include "wasm-traversal.h" #include "wasm.h" @@ -30,13 +31,13 @@ struct ReturnValueRemover : public PostWalker { auto* value = curr->value; assert(value); curr->value = nullptr; - Builder builder(*module); + Builder builder(*getModule()); replaceCurrent(builder.makeSequence(builder.makeDrop(value), curr)); } void visitFunction(Function* curr) { if (curr->body->type.isConcrete()) { - curr->body = Builder(*module).makeDrop(curr->body); + curr->body = Builder(*getModule()).makeDrop(curr->body); } } }; diff --git a/src/passes/Monomorphize.cpp b/src/passes/Monomorphize.cpp index 5e96181a96e..64c12f725ab 100644 --- a/src/passes/Monomorphize.cpp +++ b/src/passes/Monomorphize.cpp @@ -105,7 +105,7 @@ namespace wasm { namespace { // Finds the calls and whether each one of them is dropped. -struct CallFinder : public Walker { +struct CallFinder : public PostWalker { struct Info { Call* call; bool dropped; @@ -123,8 +123,8 @@ struct CallFinder : public Walker { // The call we just added to |infos| is dropped. assert(!infos.empty()); auto& back = infos.back(); - assert(back->call == curr); - back->dropped = true; + assert(back.call == curr->value); + back.dropped = true; } } }; @@ -357,7 +357,8 @@ struct Monomorphize : public Pass { // Try to optimize a call. void processCall(CallFinder::Info& info, Module& wasm) { - auto target = info.call->target; + auto* call = info.call; + auto target = call->target; auto* func = wasm.getFunction(target); if (func->imported()) { // Nothing to do since this calls outside of the module. From 79b695e625f6584c29b8a809d751aa1bcc896e3a Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 11 Jul 2024 12:54:47 -0700 Subject: [PATCH 04/35] yolo --- src/passes/Monomorphize.cpp | 54 ++++++++++++++++++++++++------------- 1 file changed, 36 insertions(+), 18 deletions(-) diff --git a/src/passes/Monomorphize.cpp b/src/passes/Monomorphize.cpp index 64c12f725ab..01beaa35a3d 100644 --- a/src/passes/Monomorphize.cpp +++ b/src/passes/Monomorphize.cpp @@ -104,18 +104,24 @@ namespace wasm { namespace { +// Core information about a call: the call itself, and if it is dropped, the +// drop. +struct CallInfo { + Call* call; + // Store a reference to the drop's pointer so that we can replace it, as when + // we optimize a dropped call we need to replace (drop (call)) with (call). + // Or, if the call is not dropped, this is nullptr; + Expression** drop; +}; + // Finds the calls and whether each one of them is dropped. struct CallFinder : public PostWalker { - struct Info { - Call* call; - bool dropped; - }; - std::vector infos; + std::vector infos; void visitCall(Call* curr) { // Add the call as non-dropped, and update the drop later if we are. - infos.push_back(Info{curr, false}); + infos.push_back(CallInfo{curr, false}); } void visitDrop(Drop* curr) { @@ -207,7 +213,7 @@ struct CallContext { // remaining values by updating |newOperands| (for example, if all the values // sent are constants, then |newOperands| will end up empty, as we have // nothing left to send). - void buildFromCall(CallFinder::Info& info, + void buildFromCall(CallInfo& info, std::vector& newOperands, Module& wasm) { Builder builder(wasm); @@ -238,7 +244,7 @@ struct CallContext { })); } - dropped = info.dropped; + dropped = !!info.drop; } // Checks whether an expression can be moved into the context. @@ -356,7 +362,7 @@ struct Monomorphize : public Pass { } // Try to optimize a call. - void processCall(CallFinder::Info& info, Module& wasm) { + void processCall(CallInfo& info, Module& wasm) { auto* call = info.call; auto target = call->target; auto* func = wasm.getFunction(target); @@ -379,11 +385,8 @@ struct Monomorphize : public Pass { if (iter != funcContextMap.end()) { auto newTarget = iter->second; if (newTarget != target) { - // When we computed this before we found a benefit to optimizing, and - // created a new monomorphized function to call. Use it by simply - // applying the new operands we computed, and adjusting the call target. - call->operands.set(newOperands); - call->target = newTarget; + // We saw benefit to optimizing this case. Apply that. + updateCall(info, newTarget, newOperands, wasm); } return; } @@ -448,8 +451,7 @@ struct Monomorphize : public Pass { if (worthwhile) { // We are using the monomorphized function, so update the call and add it // to the module. - call->operands.set(newOperands); - call->target = monoFunc->name; + updateCall(info, monoFunc->name, newOperands, wasm); wasm.addFunction(std::move(monoFunc)); } @@ -484,7 +486,7 @@ struct Monomorphize : public Pass { } // If we were dropped then we are pulling the drop into the monomorphized // function, which means we return nothing. - auto newResults = context.dropped ? Type::none : func->getResults(); + auto newResults = context.drop ? Type::none : func->getResults(); newFunc->type = Signature(Type(newParams), newResults); // We must update local indexes: the new function has a potentially @@ -579,13 +581,29 @@ struct Monomorphize : public Pass { newFunc->body = builder.makeBlock(pre); } - if (context.dropped) { + if (context.drop) { ReturnUtils::ReturnValueRemover().walkFunctionInModule(func, &wasm); } return newFunc; } + // Given a call and a new target it should be calling, apply that new target, + // including updating the operands and handling dropping. + void updateCall(const CallInfo& info, + Name newTarget, + const std::vector& newOperands, + Module& wasm) { + call->target = newTarget; + call->operands.set(newOperands); + + if (info.drop) { + // Replace (drop (call)) with (call), that is, replace the drop with the + // (updated) call. + *info.drop = call; + } + } + // Run minimal function-level optimizations on a function. This optimizes at // -O1 which is very fast and runs in linear time basically, and so it should // be reasonable to run as part of this pass: -O1 is several times faster than From 6595096e1f8291aa43c270551aa718760bd2a299 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 11 Jul 2024 12:57:13 -0700 Subject: [PATCH 05/35] yolo --- src/passes/Monomorphize.cpp | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/passes/Monomorphize.cpp b/src/passes/Monomorphize.cpp index 01beaa35a3d..2e83d7dbfe8 100644 --- a/src/passes/Monomorphize.cpp +++ b/src/passes/Monomorphize.cpp @@ -120,8 +120,8 @@ struct CallFinder : public PostWalker { std::vector infos; void visitCall(Call* curr) { - // Add the call as non-dropped, and update the drop later if we are. - infos.push_back(CallInfo{curr, false}); + // Add the call as not having a drop, and update the drop later if we are. + infos.push_back(CallInfo{curr, nullptr}); } void visitDrop(Drop* curr) { @@ -130,7 +130,7 @@ struct CallFinder : public PostWalker { assert(!infos.empty()); auto& back = infos.back(); assert(back.call == curr->value); - back.dropped = true; + back.drop = getCurrentPointer(); } } }; @@ -486,7 +486,7 @@ struct Monomorphize : public Pass { } // If we were dropped then we are pulling the drop into the monomorphized // function, which means we return nothing. - auto newResults = context.drop ? Type::none : func->getResults(); + auto newResults = context.dropped ? Type::none : func->getResults(); newFunc->type = Signature(Type(newParams), newResults); // We must update local indexes: the new function has a potentially @@ -581,7 +581,7 @@ struct Monomorphize : public Pass { newFunc->body = builder.makeBlock(pre); } - if (context.drop) { + if (context.dropped) { ReturnUtils::ReturnValueRemover().walkFunctionInModule(func, &wasm); } @@ -594,13 +594,16 @@ struct Monomorphize : public Pass { Name newTarget, const std::vector& newOperands, Module& wasm) { - call->target = newTarget; - call->operands.set(newOperands); + info.call->target = newTarget; + info.call->operands.set(newOperands); if (info.drop) { // Replace (drop (call)) with (call), that is, replace the drop with the - // (updated) call. - *info.drop = call; + // (updated) call which now has type none. Note we should have handled + // unreachability before getting here. + assert(info.call->type != Type::unreachable); + info.call->type = Type::none; + *info.drop = info.call; } } From 35a24834eaa0e735990cb3ba2c72b782fbf37cd7 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 11 Jul 2024 13:40:35 -0700 Subject: [PATCH 06/35] test+fix --- src/passes/Monomorphize.cpp | 3 +- test/lit/passes/monomorphize-drop.wast | 111 +++++++++++++++++++++++++ 2 files changed, 113 insertions(+), 1 deletion(-) create mode 100644 test/lit/passes/monomorphize-drop.wast diff --git a/src/passes/Monomorphize.cpp b/src/passes/Monomorphize.cpp index 2e83d7dbfe8..b98a89465c9 100644 --- a/src/passes/Monomorphize.cpp +++ b/src/passes/Monomorphize.cpp @@ -582,7 +582,8 @@ struct Monomorphize : public Pass { } if (context.dropped) { - ReturnUtils::ReturnValueRemover().walkFunctionInModule(func, &wasm); + ReturnUtils::ReturnValueRemover().walkFunctionInModule(newFunc.get(), + &wasm); } return newFunc; diff --git a/test/lit/passes/monomorphize-drop.wast b/test/lit/passes/monomorphize-drop.wast new file mode 100644 index 00000000000..4883aca28db --- /dev/null +++ b/test/lit/passes/monomorphize-drop.wast @@ -0,0 +1,111 @@ +;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited. + +;; As in monomorphize-types.wast, test in both "always" mode, which always +;; monomorphizes, and in "careful" mode which does it only when it appears to +;; actually help. + +;; RUN: foreach %s %t wasm-opt --monomorphize-always -all -S -o - | filecheck %s --check-prefix ALWAYS +;; RUN: foreach %s %t wasm-opt --monomorphize -all -S -o - | filecheck %s --check-prefix CAREFUL + +(module + ;; Test that dropped functions are monomorphized, and the drop is reverse- + ;; inlined into the called function, enabling more optimizations. + + ;; ALWAYS: (type $0 (func)) + + ;; ALWAYS: (type $1 (func (param i32 i32) (result i32))) + + ;; ALWAYS: (func $work (type $1) (param $x i32) (param $y i32) (result i32) + ;; ALWAYS-NEXT: (i32.mul + ;; ALWAYS-NEXT: (i32.xor + ;; ALWAYS-NEXT: (local.get $x) + ;; ALWAYS-NEXT: (local.get $y) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: (i32.add + ;; ALWAYS-NEXT: (local.get $x) + ;; ALWAYS-NEXT: (local.get $y) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: ) + ;; CAREFUL: (type $0 (func)) + + ;; CAREFUL: (type $1 (func (param i32 i32) (result i32))) + + ;; CAREFUL: (func $work (type $1) (param $0 i32) (param $1 i32) (result i32) + ;; CAREFUL-NEXT: (i32.mul + ;; CAREFUL-NEXT: (i32.add + ;; CAREFUL-NEXT: (local.get $0) + ;; CAREFUL-NEXT: (local.get $1) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: (i32.xor + ;; CAREFUL-NEXT: (local.get $0) + ;; CAREFUL-NEXT: (local.get $1) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: ) + (func $work (param $x i32) (param $y i32) (result i32) + ;; Do some nontrivial work that we return. If this is dropped then we don't + ;; need that work. + (i32.mul + (i32.xor + (local.get $x) + (local.get $y) + ) + (i32.add + (local.get $x) + (local.get $y) + ) + ) + ) + + ;; ALWAYS: (func $calls (type $0) + ;; ALWAYS-NEXT: (call $work_2) + ;; ALWAYS-NEXT: (call $work_2) + ;; ALWAYS-NEXT: ) + ;; CAREFUL: (func $calls (type $0) + ;; CAREFUL-NEXT: (call $work_2) + ;; CAREFUL-NEXT: (call $work_2) + ;; CAREFUL-NEXT: ) + (func $calls + (drop + (call $work + (i32.const 3) + (i32.const 4) + ) + ) + (drop + (call $work + (i32.const 3) + (i32.const 4) + ) + ) + ) +) +;; ALWAYS: (func $work_2 (type $0) +;; ALWAYS-NEXT: (local $x i32) +;; ALWAYS-NEXT: (local $y i32) +;; ALWAYS-NEXT: (drop +;; ALWAYS-NEXT: (block (result i32) +;; ALWAYS-NEXT: (local.set $x +;; ALWAYS-NEXT: (i32.const 3) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (local.set $y +;; ALWAYS-NEXT: (i32.const 4) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (i32.mul +;; ALWAYS-NEXT: (i32.xor +;; ALWAYS-NEXT: (local.get $x) +;; ALWAYS-NEXT: (local.get $y) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (i32.add +;; ALWAYS-NEXT: (local.get $x) +;; ALWAYS-NEXT: (local.get $y) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) + +;; CAREFUL: (func $work_2 (type $0) +;; CAREFUL-NEXT: (nop) +;; CAREFUL-NEXT: ) From ba38860ed88bf0570f29ac3ee5f939b9ac3ecb28 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 11 Jul 2024 13:42:39 -0700 Subject: [PATCH 07/35] test+fix --- test/lit/passes/monomorphize-drop.wast | 64 +++++++++++++++++++++++--- 1 file changed, 57 insertions(+), 7 deletions(-) diff --git a/test/lit/passes/monomorphize-drop.wast b/test/lit/passes/monomorphize-drop.wast index 4883aca28db..3eec3751f7c 100644 --- a/test/lit/passes/monomorphize-drop.wast +++ b/test/lit/passes/monomorphize-drop.wast @@ -11,10 +11,12 @@ ;; Test that dropped functions are monomorphized, and the drop is reverse- ;; inlined into the called function, enabling more optimizations. - ;; ALWAYS: (type $0 (func)) + ;; ALWAYS: (type $0 (func (param i32))) ;; ALWAYS: (type $1 (func (param i32 i32) (result i32))) + ;; ALWAYS: (type $2 (func)) + ;; ALWAYS: (func $work (type $1) (param $x i32) (param $y i32) (result i32) ;; ALWAYS-NEXT: (i32.mul ;; ALWAYS-NEXT: (i32.xor @@ -27,10 +29,12 @@ ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) - ;; CAREFUL: (type $0 (func)) + ;; CAREFUL: (type $0 (func (param i32))) ;; CAREFUL: (type $1 (func (param i32 i32) (result i32))) + ;; CAREFUL: (type $2 (func)) + ;; CAREFUL: (func $work (type $1) (param $0 i32) (param $1 i32) (result i32) ;; CAREFUL-NEXT: (i32.mul ;; CAREFUL-NEXT: (i32.add @@ -58,15 +62,23 @@ ) ) - ;; ALWAYS: (func $calls (type $0) + ;; ALWAYS: (func $calls (type $0) (param $x i32) ;; ALWAYS-NEXT: (call $work_2) ;; ALWAYS-NEXT: (call $work_2) + ;; ALWAYS-NEXT: (call $work_3 + ;; ALWAYS-NEXT: (local.get $x) + ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) - ;; CAREFUL: (func $calls (type $0) + ;; CAREFUL: (func $calls (type $0) (param $x i32) ;; CAREFUL-NEXT: (call $work_2) ;; CAREFUL-NEXT: (call $work_2) + ;; CAREFUL-NEXT: (call $work_3 + ;; CAREFUL-NEXT: (local.get $x) + ;; CAREFUL-NEXT: ) ;; CAREFUL-NEXT: ) - (func $calls + (func $calls (param $x i32) + ;; Both of these can call the same monomorphized function. In CAREFUL mode + ;; that function's body can also be optimized into a nop. (drop (call $work (i32.const 3) @@ -79,9 +91,18 @@ (i32.const 4) ) ) + ;; Another call, now with an unknown parameter. This calls a different + ;; monomorphized function, but once again the body can be optimized into a + ;; nop in CAREFUL. + (drop + (call $work + (i32.const 3) + (local.get $x) + ) + ) ) ) -;; ALWAYS: (func $work_2 (type $0) +;; ALWAYS: (func $work_2 (type $2) ;; ALWAYS-NEXT: (local $x i32) ;; ALWAYS-NEXT: (local $y i32) ;; ALWAYS-NEXT: (drop @@ -106,6 +127,35 @@ ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) -;; CAREFUL: (func $work_2 (type $0) +;; ALWAYS: (func $work_3 (type $0) (param $0 i32) +;; ALWAYS-NEXT: (local $x i32) +;; ALWAYS-NEXT: (local $y i32) +;; ALWAYS-NEXT: (drop +;; ALWAYS-NEXT: (block (result i32) +;; ALWAYS-NEXT: (local.set $x +;; ALWAYS-NEXT: (i32.const 3) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (local.set $y +;; ALWAYS-NEXT: (local.get $0) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (i32.mul +;; ALWAYS-NEXT: (i32.xor +;; ALWAYS-NEXT: (local.get $x) +;; ALWAYS-NEXT: (local.get $y) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (i32.add +;; ALWAYS-NEXT: (local.get $x) +;; ALWAYS-NEXT: (local.get $y) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) + +;; CAREFUL: (func $work_2 (type $2) +;; CAREFUL-NEXT: (nop) +;; CAREFUL-NEXT: ) + +;; CAREFUL: (func $work_3 (type $0) (param $0 i32) ;; CAREFUL-NEXT: (nop) ;; CAREFUL-NEXT: ) From ed76396640503a3db88d90e9cb527e7a91dd11fc Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 11 Jul 2024 13:43:20 -0700 Subject: [PATCH 08/35] test --- test/lit/passes/monomorphize-drop.wast | 49 ++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/test/lit/passes/monomorphize-drop.wast b/test/lit/passes/monomorphize-drop.wast index 3eec3751f7c..1f53334fb5c 100644 --- a/test/lit/passes/monomorphize-drop.wast +++ b/test/lit/passes/monomorphize-drop.wast @@ -17,6 +17,8 @@ ;; ALWAYS: (type $2 (func)) + ;; ALWAYS: (type $3 (func (param i32 i32))) + ;; ALWAYS: (func $work (type $1) (param $x i32) (param $y i32) (result i32) ;; ALWAYS-NEXT: (i32.mul ;; ALWAYS-NEXT: (i32.xor @@ -35,6 +37,8 @@ ;; CAREFUL: (type $2 (func)) + ;; CAREFUL: (type $3 (func (param i32 i32))) + ;; CAREFUL: (func $work (type $1) (param $0 i32) (param $1 i32) (result i32) ;; CAREFUL-NEXT: (i32.mul ;; CAREFUL-NEXT: (i32.add @@ -68,6 +72,10 @@ ;; ALWAYS-NEXT: (call $work_3 ;; ALWAYS-NEXT: (local.get $x) ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: (call $work_4 + ;; ALWAYS-NEXT: (local.get $x) + ;; ALWAYS-NEXT: (local.get $x) + ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) ;; CAREFUL: (func $calls (type $0) (param $x i32) ;; CAREFUL-NEXT: (call $work_2) @@ -75,6 +83,10 @@ ;; CAREFUL-NEXT: (call $work_3 ;; CAREFUL-NEXT: (local.get $x) ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: (call $work_4 + ;; CAREFUL-NEXT: (local.get $x) + ;; CAREFUL-NEXT: (local.get $x) + ;; CAREFUL-NEXT: ) ;; CAREFUL-NEXT: ) (func $calls (param $x i32) ;; Both of these can call the same monomorphized function. In CAREFUL mode @@ -100,6 +112,14 @@ (local.get $x) ) ) + ;; Two unknown parameters. Yet another monomorphized function, but the same + ;; outcome. + (drop + (call $work + (local.get $x) + (local.get $x) + ) + ) ) ) ;; ALWAYS: (func $work_2 (type $2) @@ -152,6 +172,31 @@ ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) +;; ALWAYS: (func $work_4 (type $3) (param $0 i32) (param $1 i32) +;; ALWAYS-NEXT: (local $x i32) +;; ALWAYS-NEXT: (local $y i32) +;; ALWAYS-NEXT: (drop +;; ALWAYS-NEXT: (block (result i32) +;; ALWAYS-NEXT: (local.set $x +;; ALWAYS-NEXT: (local.get $0) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (local.set $y +;; ALWAYS-NEXT: (local.get $1) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (i32.mul +;; ALWAYS-NEXT: (i32.xor +;; ALWAYS-NEXT: (local.get $x) +;; ALWAYS-NEXT: (local.get $y) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (i32.add +;; ALWAYS-NEXT: (local.get $x) +;; ALWAYS-NEXT: (local.get $y) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) + ;; CAREFUL: (func $work_2 (type $2) ;; CAREFUL-NEXT: (nop) ;; CAREFUL-NEXT: ) @@ -159,3 +204,7 @@ ;; CAREFUL: (func $work_3 (type $0) (param $0 i32) ;; CAREFUL-NEXT: (nop) ;; CAREFUL-NEXT: ) + +;; CAREFUL: (func $work_4 (type $3) (param $0 i32) (param $1 i32) +;; CAREFUL-NEXT: (nop) +;; CAREFUL-NEXT: ) From d64ef3ab8039ab3d247627bb6371e4e6b6f66fbc Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 11 Jul 2024 13:45:16 -0700 Subject: [PATCH 09/35] test --- test/lit/passes/monomorphize-drop.wast | 86 +++++++++++++++++--------- 1 file changed, 58 insertions(+), 28 deletions(-) diff --git a/test/lit/passes/monomorphize-drop.wast b/test/lit/passes/monomorphize-drop.wast index 1f53334fb5c..3e4bdea8631 100644 --- a/test/lit/passes/monomorphize-drop.wast +++ b/test/lit/passes/monomorphize-drop.wast @@ -11,15 +11,27 @@ ;; Test that dropped functions are monomorphized, and the drop is reverse- ;; inlined into the called function, enabling more optimizations. - ;; ALWAYS: (type $0 (func (param i32))) + ;; ALWAYS: (type $0 (func (param i32 i32) (result i32))) - ;; ALWAYS: (type $1 (func (param i32 i32) (result i32))) + ;; ALWAYS: (type $1 (func (param i32))) ;; ALWAYS: (type $2 (func)) ;; ALWAYS: (type $3 (func (param i32 i32))) - ;; ALWAYS: (func $work (type $1) (param $x i32) (param $y i32) (result i32) + ;; ALWAYS: (import "a" "b" (func $import (type $0) (param i32 i32) (result i32))) + ;; CAREFUL: (type $0 (func (param i32 i32) (result i32))) + + ;; CAREFUL: (type $1 (func (param i32))) + + ;; CAREFUL: (type $2 (func)) + + ;; CAREFUL: (type $3 (func (param i32 i32))) + + ;; CAREFUL: (import "a" "b" (func $import (type $0) (param i32 i32) (result i32))) + (import "a" "b" (func $import (param i32 i32) (result i32))) + + ;; ALWAYS: (func $work (type $0) (param $x i32) (param $y i32) (result i32) ;; ALWAYS-NEXT: (i32.mul ;; ALWAYS-NEXT: (i32.xor ;; ALWAYS-NEXT: (local.get $x) @@ -31,15 +43,7 @@ ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) - ;; CAREFUL: (type $0 (func (param i32))) - - ;; CAREFUL: (type $1 (func (param i32 i32) (result i32))) - - ;; CAREFUL: (type $2 (func)) - - ;; CAREFUL: (type $3 (func (param i32 i32))) - - ;; CAREFUL: (func $work (type $1) (param $0 i32) (param $1 i32) (result i32) + ;; CAREFUL: (func $work (type $0) (param $0 i32) (param $1 i32) (result i32) ;; CAREFUL-NEXT: (i32.mul ;; CAREFUL-NEXT: (i32.add ;; CAREFUL-NEXT: (local.get $0) @@ -66,24 +70,24 @@ ) ) - ;; ALWAYS: (func $calls (type $0) (param $x i32) - ;; ALWAYS-NEXT: (call $work_2) - ;; ALWAYS-NEXT: (call $work_2) - ;; ALWAYS-NEXT: (call $work_3 + ;; ALWAYS: (func $calls (type $1) (param $x i32) + ;; ALWAYS-NEXT: (call $work_4) + ;; ALWAYS-NEXT: (call $work_4) + ;; ALWAYS-NEXT: (call $work_5 ;; ALWAYS-NEXT: (local.get $x) ;; ALWAYS-NEXT: ) - ;; ALWAYS-NEXT: (call $work_4 + ;; ALWAYS-NEXT: (call $work_6 ;; ALWAYS-NEXT: (local.get $x) ;; ALWAYS-NEXT: (local.get $x) ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) - ;; CAREFUL: (func $calls (type $0) (param $x i32) - ;; CAREFUL-NEXT: (call $work_2) - ;; CAREFUL-NEXT: (call $work_2) - ;; CAREFUL-NEXT: (call $work_3 + ;; CAREFUL: (func $calls (type $1) (param $x i32) + ;; CAREFUL-NEXT: (call $work_4) + ;; CAREFUL-NEXT: (call $work_4) + ;; CAREFUL-NEXT: (call $work_5 ;; CAREFUL-NEXT: (local.get $x) ;; CAREFUL-NEXT: ) - ;; CAREFUL-NEXT: (call $work_4 + ;; CAREFUL-NEXT: (call $work_6 ;; CAREFUL-NEXT: (local.get $x) ;; CAREFUL-NEXT: (local.get $x) ;; CAREFUL-NEXT: ) @@ -121,8 +125,34 @@ ) ) ) + + ;; ALWAYS: (func $call-import (type $2) + ;; ALWAYS-NEXT: (drop + ;; ALWAYS-NEXT: (call $import + ;; ALWAYS-NEXT: (i32.const 3) + ;; ALWAYS-NEXT: (i32.const 4) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: ) + ;; CAREFUL: (func $call-import (type $2) + ;; CAREFUL-NEXT: (drop + ;; CAREFUL-NEXT: (call $import + ;; CAREFUL-NEXT: (i32.const 3) + ;; CAREFUL-NEXT: (i32.const 4) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: ) + (func $call-import + ;; Calling an import allows no optimizations. + (drop + (call $import + (i32.const 3) + (i32.const 4) + ) + ) + ) ) -;; ALWAYS: (func $work_2 (type $2) +;; ALWAYS: (func $work_4 (type $2) ;; ALWAYS-NEXT: (local $x i32) ;; ALWAYS-NEXT: (local $y i32) ;; ALWAYS-NEXT: (drop @@ -147,7 +177,7 @@ ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) -;; ALWAYS: (func $work_3 (type $0) (param $0 i32) +;; ALWAYS: (func $work_5 (type $1) (param $0 i32) ;; ALWAYS-NEXT: (local $x i32) ;; ALWAYS-NEXT: (local $y i32) ;; ALWAYS-NEXT: (drop @@ -172,7 +202,7 @@ ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) -;; ALWAYS: (func $work_4 (type $3) (param $0 i32) (param $1 i32) +;; ALWAYS: (func $work_6 (type $3) (param $0 i32) (param $1 i32) ;; ALWAYS-NEXT: (local $x i32) ;; ALWAYS-NEXT: (local $y i32) ;; ALWAYS-NEXT: (drop @@ -197,14 +227,14 @@ ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) -;; CAREFUL: (func $work_2 (type $2) +;; CAREFUL: (func $work_4 (type $2) ;; CAREFUL-NEXT: (nop) ;; CAREFUL-NEXT: ) -;; CAREFUL: (func $work_3 (type $0) (param $0 i32) +;; CAREFUL: (func $work_5 (type $1) (param $0 i32) ;; CAREFUL-NEXT: (nop) ;; CAREFUL-NEXT: ) -;; CAREFUL: (func $work_4 (type $3) (param $0 i32) (param $1 i32) +;; CAREFUL: (func $work_6 (type $3) (param $0 i32) (param $1 i32) ;; CAREFUL-NEXT: (nop) ;; CAREFUL-NEXT: ) From 16da2904ab13e785cef81b908d72dd066849561b Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 11 Jul 2024 13:49:01 -0700 Subject: [PATCH 10/35] test --- test/lit/passes/monomorphize-drop.wast | 157 ++++++++++++++++++++----- 1 file changed, 129 insertions(+), 28 deletions(-) diff --git a/test/lit/passes/monomorphize-drop.wast b/test/lit/passes/monomorphize-drop.wast index 3e4bdea8631..8e5545a1143 100644 --- a/test/lit/passes/monomorphize-drop.wast +++ b/test/lit/passes/monomorphize-drop.wast @@ -11,27 +11,31 @@ ;; Test that dropped functions are monomorphized, and the drop is reverse- ;; inlined into the called function, enabling more optimizations. - ;; ALWAYS: (type $0 (func (param i32 i32) (result i32))) + ;; ALWAYS: (type $0 (func)) - ;; ALWAYS: (type $1 (func (param i32))) + ;; ALWAYS: (type $1 (func (param i32 i32) (result i32))) - ;; ALWAYS: (type $2 (func)) + ;; ALWAYS: (type $2 (func (param i32) (result i32))) - ;; ALWAYS: (type $3 (func (param i32 i32))) + ;; ALWAYS: (type $3 (func (param i32))) - ;; ALWAYS: (import "a" "b" (func $import (type $0) (param i32 i32) (result i32))) + ;; ALWAYS: (type $4 (func (param i32 i32))) + + ;; ALWAYS: (import "a" "b" (func $import (type $1) (param i32 i32) (result i32))) ;; CAREFUL: (type $0 (func (param i32 i32) (result i32))) - ;; CAREFUL: (type $1 (func (param i32))) + ;; CAREFUL: (type $1 (func)) + + ;; CAREFUL: (type $2 (func (param i32) (result i32))) - ;; CAREFUL: (type $2 (func)) + ;; CAREFUL: (type $3 (func (param i32))) - ;; CAREFUL: (type $3 (func (param i32 i32))) + ;; CAREFUL: (type $4 (func (param i32 i32))) ;; CAREFUL: (import "a" "b" (func $import (type $0) (param i32 i32) (result i32))) (import "a" "b" (func $import (param i32 i32) (result i32))) - ;; ALWAYS: (func $work (type $0) (param $x i32) (param $y i32) (result i32) + ;; ALWAYS: (func $work (type $1) (param $x i32) (param $y i32) (result i32) ;; ALWAYS-NEXT: (i32.mul ;; ALWAYS-NEXT: (i32.xor ;; ALWAYS-NEXT: (local.get $x) @@ -70,29 +74,37 @@ ) ) - ;; ALWAYS: (func $calls (type $1) (param $x i32) - ;; ALWAYS-NEXT: (call $work_4) - ;; ALWAYS-NEXT: (call $work_4) - ;; ALWAYS-NEXT: (call $work_5 + ;; ALWAYS: (func $calls (type $2) (param $x i32) (result i32) + ;; ALWAYS-NEXT: (call $work_6) + ;; ALWAYS-NEXT: (call $work_6) + ;; ALWAYS-NEXT: (call $work_7 + ;; ALWAYS-NEXT: (local.get $x) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: (call $work_8 + ;; ALWAYS-NEXT: (local.get $x) ;; ALWAYS-NEXT: (local.get $x) ;; ALWAYS-NEXT: ) - ;; ALWAYS-NEXT: (call $work_6 + ;; ALWAYS-NEXT: (call $work ;; ALWAYS-NEXT: (local.get $x) ;; ALWAYS-NEXT: (local.get $x) ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) - ;; CAREFUL: (func $calls (type $1) (param $x i32) - ;; CAREFUL-NEXT: (call $work_4) - ;; CAREFUL-NEXT: (call $work_4) - ;; CAREFUL-NEXT: (call $work_5 + ;; CAREFUL: (func $calls (type $2) (param $x i32) (result i32) + ;; CAREFUL-NEXT: (call $work_6) + ;; CAREFUL-NEXT: (call $work_6) + ;; CAREFUL-NEXT: (call $work_7 ;; CAREFUL-NEXT: (local.get $x) ;; CAREFUL-NEXT: ) - ;; CAREFUL-NEXT: (call $work_6 + ;; CAREFUL-NEXT: (call $work_8 + ;; CAREFUL-NEXT: (local.get $x) + ;; CAREFUL-NEXT: (local.get $x) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: (call $work ;; CAREFUL-NEXT: (local.get $x) ;; CAREFUL-NEXT: (local.get $x) ;; CAREFUL-NEXT: ) ;; CAREFUL-NEXT: ) - (func $calls (param $x i32) + (func $calls (param $x i32) (result i32) ;; Both of these can call the same monomorphized function. In CAREFUL mode ;; that function's body can also be optimized into a nop. (drop @@ -124,9 +136,15 @@ (local.get $x) ) ) + ;; A call of the same target without a drop. We can't optimize here in + ;; CAREFUL mode since we can't save any work. + (call $work + (local.get $x) + (local.get $x) + ) ) - ;; ALWAYS: (func $call-import (type $2) + ;; ALWAYS: (func $call-import (type $0) ;; ALWAYS-NEXT: (drop ;; ALWAYS-NEXT: (call $import ;; ALWAYS-NEXT: (i32.const 3) @@ -134,7 +152,7 @@ ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) - ;; CAREFUL: (func $call-import (type $2) + ;; CAREFUL: (func $call-import (type $1) ;; CAREFUL-NEXT: (drop ;; CAREFUL-NEXT: (call $import ;; CAREFUL-NEXT: (i32.const 3) @@ -151,8 +169,66 @@ ) ) ) + + ;; ALWAYS: (func $import-work (type $1) (param $x i32) (param $y i32) (result i32) + ;; ALWAYS-NEXT: (call $import + ;; ALWAYS-NEXT: (i32.xor + ;; ALWAYS-NEXT: (local.get $x) + ;; ALWAYS-NEXT: (local.get $y) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: (i32.add + ;; ALWAYS-NEXT: (local.get $x) + ;; ALWAYS-NEXT: (local.get $y) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: ) + ;; CAREFUL: (func $import-work (type $0) (param $0 i32) (param $1 i32) (result i32) + ;; CAREFUL-NEXT: (call $import + ;; CAREFUL-NEXT: (i32.xor + ;; CAREFUL-NEXT: (local.get $0) + ;; CAREFUL-NEXT: (local.get $1) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: (i32.add + ;; CAREFUL-NEXT: (local.get $0) + ;; CAREFUL-NEXT: (local.get $1) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: ) + (func $import-work (param $x i32) (param $y i32) (result i32) + ;; Do some work and also call an import. + (call $import + (i32.xor + (local.get $x) + (local.get $y) + ) + (i32.add + (local.get $x) + (local.get $y) + ) + ) + ) + + ;; ALWAYS: (func $call-import-work (type $0) + ;; ALWAYS-NEXT: (call $import-work_9) + ;; ALWAYS-NEXT: ) + ;; CAREFUL: (func $call-import-work (type $1) + ;; CAREFUL-NEXT: (drop + ;; CAREFUL-NEXT: (call $import-work + ;; CAREFUL-NEXT: (i32.const 3) + ;; CAREFUL-NEXT: (i32.const 4) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: ) + (func $call-import-work + (drop + (call $import-work + (i32.const 3) + (i32.const 4) + ) + ) + ) ) -;; ALWAYS: (func $work_4 (type $2) +;; ALWAYS: (func $work_6 (type $0) ;; ALWAYS-NEXT: (local $x i32) ;; ALWAYS-NEXT: (local $y i32) ;; ALWAYS-NEXT: (drop @@ -177,7 +253,7 @@ ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) -;; ALWAYS: (func $work_5 (type $1) (param $0 i32) +;; ALWAYS: (func $work_7 (type $3) (param $0 i32) ;; ALWAYS-NEXT: (local $x i32) ;; ALWAYS-NEXT: (local $y i32) ;; ALWAYS-NEXT: (drop @@ -202,7 +278,7 @@ ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) -;; ALWAYS: (func $work_6 (type $3) (param $0 i32) (param $1 i32) +;; ALWAYS: (func $work_8 (type $4) (param $0 i32) (param $1 i32) ;; ALWAYS-NEXT: (local $x i32) ;; ALWAYS-NEXT: (local $y i32) ;; ALWAYS-NEXT: (drop @@ -227,14 +303,39 @@ ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) -;; CAREFUL: (func $work_4 (type $2) +;; ALWAYS: (func $import-work_9 (type $0) +;; ALWAYS-NEXT: (local $x i32) +;; ALWAYS-NEXT: (local $y i32) +;; ALWAYS-NEXT: (drop +;; ALWAYS-NEXT: (block (result i32) +;; ALWAYS-NEXT: (local.set $x +;; ALWAYS-NEXT: (i32.const 3) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (local.set $y +;; ALWAYS-NEXT: (i32.const 4) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (call $import +;; ALWAYS-NEXT: (i32.xor +;; ALWAYS-NEXT: (local.get $x) +;; ALWAYS-NEXT: (local.get $y) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (i32.add +;; ALWAYS-NEXT: (local.get $x) +;; ALWAYS-NEXT: (local.get $y) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) + +;; CAREFUL: (func $work_6 (type $1) ;; CAREFUL-NEXT: (nop) ;; CAREFUL-NEXT: ) -;; CAREFUL: (func $work_5 (type $1) (param $0 i32) +;; CAREFUL: (func $work_7 (type $3) (param $0 i32) ;; CAREFUL-NEXT: (nop) ;; CAREFUL-NEXT: ) -;; CAREFUL: (func $work_6 (type $3) (param $0 i32) (param $1 i32) +;; CAREFUL: (func $work_8 (type $4) (param $0 i32) (param $1 i32) ;; CAREFUL-NEXT: (nop) ;; CAREFUL-NEXT: ) From 81661bcede30aaa9a3f9194282a57cff392211c7 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 11 Jul 2024 13:54:53 -0700 Subject: [PATCH 11/35] work --- test/lit/passes/monomorphize-drop.wast | 122 ++++++++++++++++++------- 1 file changed, 87 insertions(+), 35 deletions(-) diff --git a/test/lit/passes/monomorphize-drop.wast b/test/lit/passes/monomorphize-drop.wast index 8e5545a1143..5fcd9ffe710 100644 --- a/test/lit/passes/monomorphize-drop.wast +++ b/test/lit/passes/monomorphize-drop.wast @@ -15,22 +15,26 @@ ;; ALWAYS: (type $1 (func (param i32 i32) (result i32))) - ;; ALWAYS: (type $2 (func (param i32) (result i32))) + ;; ALWAYS: (type $2 (func (param i32))) - ;; ALWAYS: (type $3 (func (param i32))) + ;; ALWAYS: (type $3 (func (result i32))) - ;; ALWAYS: (type $4 (func (param i32 i32))) + ;; ALWAYS: (type $4 (func (param i32) (result i32))) + + ;; ALWAYS: (type $5 (func (param i32 i32))) ;; ALWAYS: (import "a" "b" (func $import (type $1) (param i32 i32) (result i32))) ;; CAREFUL: (type $0 (func (param i32 i32) (result i32))) ;; CAREFUL: (type $1 (func)) - ;; CAREFUL: (type $2 (func (param i32) (result i32))) + ;; CAREFUL: (type $2 (func (param i32))) + + ;; CAREFUL: (type $3 (func (param i32) (result i32))) - ;; CAREFUL: (type $3 (func (param i32))) + ;; CAREFUL: (type $4 (func (result i32))) - ;; CAREFUL: (type $4 (func (param i32 i32))) + ;; CAREFUL: (type $5 (func (param i32 i32))) ;; CAREFUL: (import "a" "b" (func $import (type $0) (param i32 i32) (result i32))) (import "a" "b" (func $import (param i32 i32) (result i32))) @@ -74,37 +78,29 @@ ) ) - ;; ALWAYS: (func $calls (type $2) (param $x i32) (result i32) - ;; ALWAYS-NEXT: (call $work_6) - ;; ALWAYS-NEXT: (call $work_6) - ;; ALWAYS-NEXT: (call $work_7 - ;; ALWAYS-NEXT: (local.get $x) - ;; ALWAYS-NEXT: ) - ;; ALWAYS-NEXT: (call $work_8 - ;; ALWAYS-NEXT: (local.get $x) + ;; ALWAYS: (func $calls (type $2) (param $x i32) + ;; ALWAYS-NEXT: (call $work_8) + ;; ALWAYS-NEXT: (call $work_8) + ;; ALWAYS-NEXT: (call $work_9 ;; ALWAYS-NEXT: (local.get $x) ;; ALWAYS-NEXT: ) - ;; ALWAYS-NEXT: (call $work + ;; ALWAYS-NEXT: (call $work_10 ;; ALWAYS-NEXT: (local.get $x) ;; ALWAYS-NEXT: (local.get $x) ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) - ;; CAREFUL: (func $calls (type $2) (param $x i32) (result i32) - ;; CAREFUL-NEXT: (call $work_6) - ;; CAREFUL-NEXT: (call $work_6) - ;; CAREFUL-NEXT: (call $work_7 + ;; CAREFUL: (func $calls (type $2) (param $x i32) + ;; CAREFUL-NEXT: (call $work_8) + ;; CAREFUL-NEXT: (call $work_8) + ;; CAREFUL-NEXT: (call $work_9 ;; CAREFUL-NEXT: (local.get $x) ;; CAREFUL-NEXT: ) - ;; CAREFUL-NEXT: (call $work_8 - ;; CAREFUL-NEXT: (local.get $x) - ;; CAREFUL-NEXT: (local.get $x) - ;; CAREFUL-NEXT: ) - ;; CAREFUL-NEXT: (call $work + ;; CAREFUL-NEXT: (call $work_10 ;; CAREFUL-NEXT: (local.get $x) ;; CAREFUL-NEXT: (local.get $x) ;; CAREFUL-NEXT: ) ;; CAREFUL-NEXT: ) - (func $calls (param $x i32) (result i32) + (func $calls (param $x i32) ;; Both of these can call the same monomorphized function. In CAREFUL mode ;; that function's body can also be optimized into a nop. (drop @@ -136,14 +132,49 @@ (local.get $x) ) ) - ;; A call of the same target without a drop. We can't optimize here in - ;; CAREFUL mode since we can't save any work. + ) + + ;; ALWAYS: (func $call-undropped-trivial (type $4) (param $x i32) (result i32) + ;; ALWAYS-NEXT: (call $work + ;; ALWAYS-NEXT: (local.get $x) + ;; ALWAYS-NEXT: (local.get $x) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: ) + ;; CAREFUL: (func $call-undropped-trivial (type $3) (param $x i32) (result i32) + ;; CAREFUL-NEXT: (call $work + ;; CAREFUL-NEXT: (local.get $x) + ;; CAREFUL-NEXT: (local.get $x) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: ) + (func $call-undropped-trivial (param $x i32) (result i32) + ;; A call of the same target that is dropped in the previous function, but + ;; now without a drop. We know nothing nontrivial here, so we do nothing. (call $work (local.get $x) (local.get $x) ) ) + ;; ALWAYS: (func $call-undropped (type $3) (result i32) + ;; ALWAYS-NEXT: (call $work_11) + ;; ALWAYS-NEXT: ) + ;; CAREFUL: (func $call-undropped (type $4) (result i32) + ;; CAREFUL-NEXT: (call $work + ;; CAREFUL-NEXT: (i32.const 3) + ;; CAREFUL-NEXT: (i32.const 4) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: ) + (func $call-undropped (result i32) + ;; As above but now with constant params. We can monomorphize here (there is + ;; no issue in optimizing here without a drop and with a drop elsewhere), + ;; but we only do so in ALWAYS as in CAREFUL mode we can't find enough to + ;; do (without the drop, we can't remove any code). + (call $work + (i32.const 3) + (i32.const 4) + ) + ) + ;; ALWAYS: (func $call-import (type $0) ;; ALWAYS-NEXT: (drop ;; ALWAYS-NEXT: (call $import @@ -209,7 +240,7 @@ ) ;; ALWAYS: (func $call-import-work (type $0) - ;; ALWAYS-NEXT: (call $import-work_9) + ;; ALWAYS-NEXT: (call $import-work_12) ;; ALWAYS-NEXT: ) ;; CAREFUL: (func $call-import-work (type $1) ;; CAREFUL-NEXT: (drop @@ -228,7 +259,7 @@ ) ) ) -;; ALWAYS: (func $work_6 (type $0) +;; ALWAYS: (func $work_8 (type $0) ;; ALWAYS-NEXT: (local $x i32) ;; ALWAYS-NEXT: (local $y i32) ;; ALWAYS-NEXT: (drop @@ -253,7 +284,7 @@ ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) -;; ALWAYS: (func $work_7 (type $3) (param $0 i32) +;; ALWAYS: (func $work_9 (type $2) (param $0 i32) ;; ALWAYS-NEXT: (local $x i32) ;; ALWAYS-NEXT: (local $y i32) ;; ALWAYS-NEXT: (drop @@ -278,7 +309,7 @@ ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) -;; ALWAYS: (func $work_8 (type $4) (param $0 i32) (param $1 i32) +;; ALWAYS: (func $work_10 (type $5) (param $0 i32) (param $1 i32) ;; ALWAYS-NEXT: (local $x i32) ;; ALWAYS-NEXT: (local $y i32) ;; ALWAYS-NEXT: (drop @@ -303,7 +334,28 @@ ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) -;; ALWAYS: (func $import-work_9 (type $0) +;; ALWAYS: (func $work_11 (type $3) (result i32) +;; ALWAYS-NEXT: (local $x i32) +;; ALWAYS-NEXT: (local $y i32) +;; ALWAYS-NEXT: (local.set $x +;; ALWAYS-NEXT: (i32.const 3) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (local.set $y +;; ALWAYS-NEXT: (i32.const 4) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (i32.mul +;; ALWAYS-NEXT: (i32.xor +;; ALWAYS-NEXT: (local.get $x) +;; ALWAYS-NEXT: (local.get $y) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (i32.add +;; ALWAYS-NEXT: (local.get $x) +;; ALWAYS-NEXT: (local.get $y) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) + +;; ALWAYS: (func $import-work_12 (type $0) ;; ALWAYS-NEXT: (local $x i32) ;; ALWAYS-NEXT: (local $y i32) ;; ALWAYS-NEXT: (drop @@ -328,14 +380,14 @@ ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) -;; CAREFUL: (func $work_6 (type $1) +;; CAREFUL: (func $work_8 (type $1) ;; CAREFUL-NEXT: (nop) ;; CAREFUL-NEXT: ) -;; CAREFUL: (func $work_7 (type $3) (param $0 i32) +;; CAREFUL: (func $work_9 (type $2) (param $0 i32) ;; CAREFUL-NEXT: (nop) ;; CAREFUL-NEXT: ) -;; CAREFUL: (func $work_8 (type $4) (param $0 i32) (param $1 i32) +;; CAREFUL: (func $work_10 (type $5) (param $0 i32) (param $1 i32) ;; CAREFUL-NEXT: (nop) ;; CAREFUL-NEXT: ) From 44b20cc501333a4ff4097d6f06619787897587fb Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 11 Jul 2024 15:44:41 -0700 Subject: [PATCH 12/35] work --- test/lit/passes/monomorphize-drop.wast | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/test/lit/passes/monomorphize-drop.wast b/test/lit/passes/monomorphize-drop.wast index 5fcd9ffe710..5ec19a0b246 100644 --- a/test/lit/passes/monomorphize-drop.wast +++ b/test/lit/passes/monomorphize-drop.wast @@ -30,9 +30,9 @@ ;; CAREFUL: (type $2 (func (param i32))) - ;; CAREFUL: (type $3 (func (param i32) (result i32))) + ;; CAREFUL: (type $3 (func (result i32))) - ;; CAREFUL: (type $4 (func (result i32))) + ;; CAREFUL: (type $4 (func (param i32) (result i32))) ;; CAREFUL: (type $5 (func (param i32 i32))) @@ -140,7 +140,7 @@ ;; ALWAYS-NEXT: (local.get $x) ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) - ;; CAREFUL: (func $call-undropped-trivial (type $3) (param $x i32) (result i32) + ;; CAREFUL: (func $call-undropped-trivial (type $4) (param $x i32) (result i32) ;; CAREFUL-NEXT: (call $work ;; CAREFUL-NEXT: (local.get $x) ;; CAREFUL-NEXT: (local.get $x) @@ -158,17 +158,13 @@ ;; ALWAYS: (func $call-undropped (type $3) (result i32) ;; ALWAYS-NEXT: (call $work_11) ;; ALWAYS-NEXT: ) - ;; CAREFUL: (func $call-undropped (type $4) (result i32) - ;; CAREFUL-NEXT: (call $work - ;; CAREFUL-NEXT: (i32.const 3) - ;; CAREFUL-NEXT: (i32.const 4) - ;; CAREFUL-NEXT: ) + ;; CAREFUL: (func $call-undropped (type $3) (result i32) + ;; CAREFUL-NEXT: (call $work_11) ;; CAREFUL-NEXT: ) (func $call-undropped (result i32) - ;; As above but now with constant params. We can monomorphize here (there is - ;; no issue in optimizing here without a drop and with a drop elsewhere), - ;; but we only do so in ALWAYS as in CAREFUL mode we can't find enough to - ;; do (without the drop, we can't remove any code). + ;; As above but now with constant params. We can monomorphize here - there + ;; is no issue in optimizing here without a drop and with a drop elsewhere - + ;; but we do call a different function of course, that returns an i32. (call $work (i32.const 3) (i32.const 4) @@ -391,3 +387,7 @@ ;; CAREFUL: (func $work_10 (type $5) (param $0 i32) (param $1 i32) ;; CAREFUL-NEXT: (nop) ;; CAREFUL-NEXT: ) + +;; CAREFUL: (func $work_11 (type $3) (result i32) +;; CAREFUL-NEXT: (i32.const 49) +;; CAREFUL-NEXT: ) From 60472972f105e95a46c71b5a7ed82f17d6bd4da7 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 11 Jul 2024 15:48:06 -0700 Subject: [PATCH 13/35] comment --- test/lit/passes/monomorphize-drop.wast | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/lit/passes/monomorphize-drop.wast b/test/lit/passes/monomorphize-drop.wast index 5ec19a0b246..8170cd6e1b1 100644 --- a/test/lit/passes/monomorphize-drop.wast +++ b/test/lit/passes/monomorphize-drop.wast @@ -247,6 +247,10 @@ ;; CAREFUL-NEXT: ) ;; CAREFUL-NEXT: ) (func $call-import-work + ;; This is monomorphized in ALWAYS (as the drop means the call context is + ;; not trivial), but not in CAREFUL mode (as there is no significant benefit + ;; from optimizations on the monomorphized function - the import is opaque + ;; work we cannot do anything with, even if we see it is handed consts). (drop (call $import-work (i32.const 3) From d460fba4d7684a353c2a8f89e4f67026cfbfb31b Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 11 Jul 2024 15:52:43 -0700 Subject: [PATCH 14/35] fix --- src/passes/Monomorphize.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/passes/Monomorphize.cpp b/src/passes/Monomorphize.cpp index 7c3a16e2401..a516a787520 100644 --- a/src/passes/Monomorphize.cpp +++ b/src/passes/Monomorphize.cpp @@ -110,7 +110,7 @@ struct CallInfo { Call* call; // Store a reference to the drop's pointer so that we can replace it, as when // we optimize a dropped call we need to replace (drop (call)) with (call). - // Or, if the call is not dropped, this is nullptr; + // Or, if the call is not dropped, this is nullptr. Expression** drop; }; From 923387f26a22ff35d3314574bc4d10796fd3d1a1 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 11 Jul 2024 15:52:57 -0700 Subject: [PATCH 15/35] fix --- src/passes/Monomorphize.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/passes/Monomorphize.cpp b/src/passes/Monomorphize.cpp index a516a787520..583c72847c4 100644 --- a/src/passes/Monomorphize.cpp +++ b/src/passes/Monomorphize.cpp @@ -116,7 +116,6 @@ struct CallInfo { // Finds the calls and whether each one of them is dropped. struct CallFinder : public PostWalker { - std::vector infos; void visitCall(Call* curr) { From 9c67aa8f237e647ad3886bea492acd077bfae81c Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 11 Jul 2024 16:25:49 -0700 Subject: [PATCH 16/35] handle return_call* --- src/ir/return-utils.h | 43 +++++ test/lit/passes/monomorphize-drop.wast | 255 +++++++++++++++++++++---- 2 files changed, 257 insertions(+), 41 deletions(-) diff --git a/src/ir/return-utils.h b/src/ir/return-utils.h index f14b766b2b6..49f86e267f9 100644 --- a/src/ir/return-utils.h +++ b/src/ir/return-utils.h @@ -17,6 +17,7 @@ #ifndef wasm_ir_return_h #define wasm_ir_return_h +#include "ir/utils.h" #include "wasm-builder.h" #include "wasm-traversal.h" #include "wasm.h" @@ -35,11 +36,53 @@ struct ReturnValueRemover : public PostWalker { replaceCurrent(builder.makeSequence(builder.makeDrop(value), curr)); } + void visitCall(Call* curr) { + handleReturnCall(curr, getModule()->getFunction(curr->target)->getSig()); + } + + void visitCallIndirect(CallIndirect* curr) { + handleReturnCall(curr, curr->heapType.getSignature()); + } + + void visitCallRef(CallRef* curr) { + Type targetType = curr->target->type; + if (!targetType.isSignature()) { + // We don't know what type the call should return, but it will also never + // be reached, so we don't need to do anything here. + return; + } + handleReturnCall(curr, targetType.getHeapType().getSignature()); + } + + + template + void handleReturnCall(T* curr, Signature sig) { + if (curr->isReturn) { + // This can no longer be a return call, as it calls something that returns + // a value, and we do not. Update the type (note we must handle the case + // of an unreachable child, and also this change may affect our parent, so + // refinalize the entire function). + curr->isReturn = false; + curr->type = sig.results; + curr->finalize(); + refinalize = true; + + replaceCurrent(Builder(*getModule()).makeDrop(curr)); + } + } + void visitFunction(Function* curr) { if (curr->body->type.isConcrete()) { curr->body = Builder(*getModule()).makeDrop(curr->body); } + + if (refinalize) { + ReFinalize().walkFunctionInModule(curr, getModule()); + } } + +private: + bool refinalize = false; }; } // namespace wasm::ReturnUtils diff --git a/test/lit/passes/monomorphize-drop.wast b/test/lit/passes/monomorphize-drop.wast index 8170cd6e1b1..0c2be9d7cba 100644 --- a/test/lit/passes/monomorphize-drop.wast +++ b/test/lit/passes/monomorphize-drop.wast @@ -13,33 +13,41 @@ ;; ALWAYS: (type $0 (func)) - ;; ALWAYS: (type $1 (func (param i32 i32) (result i32))) + ;; ALWAYS: (type $iii (func (param i32 i32) (result i32))) - ;; ALWAYS: (type $2 (func (param i32))) + ;; ALWAYS: (type $i (func (result i32))) + ;; CAREFUL: (type $0 (func)) - ;; ALWAYS: (type $3 (func (result i32))) + ;; CAREFUL: (type $iii (func (param i32 i32) (result i32))) - ;; ALWAYS: (type $4 (func (param i32) (result i32))) + ;; CAREFUL: (type $i (func (result i32))) + (type $i (func (result i32))) - ;; ALWAYS: (type $5 (func (param i32 i32))) + (type $iii (func (param i32 i32) (result i32))) - ;; ALWAYS: (import "a" "b" (func $import (type $1) (param i32 i32) (result i32))) - ;; CAREFUL: (type $0 (func (param i32 i32) (result i32))) + ;; ALWAYS: (type $3 (func (param i32))) - ;; CAREFUL: (type $1 (func)) + ;; ALWAYS: (type $4 (func (param i32) (result i32))) - ;; CAREFUL: (type $2 (func (param i32))) + ;; ALWAYS: (type $5 (func (param i32 i32))) - ;; CAREFUL: (type $3 (func (result i32))) + ;; ALWAYS: (import "a" "b" (func $import (type $iii) (param i32 i32) (result i32))) + ;; CAREFUL: (type $3 (func (param i32))) ;; CAREFUL: (type $4 (func (param i32) (result i32))) ;; CAREFUL: (type $5 (func (param i32 i32))) - ;; CAREFUL: (import "a" "b" (func $import (type $0) (param i32 i32) (result i32))) + ;; CAREFUL: (import "a" "b" (func $import (type $iii) (param i32 i32) (result i32))) (import "a" "b" (func $import (param i32 i32) (result i32))) - ;; ALWAYS: (func $work (type $1) (param $x i32) (param $y i32) (result i32) + ;; ALWAYS: (table $table 10 10 funcref) + ;; CAREFUL: (table $table 10 10 funcref) + (table $table 10 10 funcref) + + ;; ALWAYS: (elem declare func $import) + + ;; ALWAYS: (func $work (type $iii) (param $x i32) (param $y i32) (result i32) ;; ALWAYS-NEXT: (i32.mul ;; ALWAYS-NEXT: (i32.xor ;; ALWAYS-NEXT: (local.get $x) @@ -51,7 +59,7 @@ ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) - ;; CAREFUL: (func $work (type $0) (param $0 i32) (param $1 i32) (result i32) + ;; CAREFUL: (func $work (type $iii) (param $0 i32) (param $1 i32) (result i32) ;; CAREFUL-NEXT: (i32.mul ;; CAREFUL-NEXT: (i32.add ;; CAREFUL-NEXT: (local.get $0) @@ -78,24 +86,24 @@ ) ) - ;; ALWAYS: (func $calls (type $2) (param $x i32) - ;; ALWAYS-NEXT: (call $work_8) - ;; ALWAYS-NEXT: (call $work_8) - ;; ALWAYS-NEXT: (call $work_9 + ;; ALWAYS: (func $calls (type $3) (param $x i32) + ;; ALWAYS-NEXT: (call $work_10) + ;; ALWAYS-NEXT: (call $work_10) + ;; ALWAYS-NEXT: (call $work_11 ;; ALWAYS-NEXT: (local.get $x) ;; ALWAYS-NEXT: ) - ;; ALWAYS-NEXT: (call $work_10 + ;; ALWAYS-NEXT: (call $work_12 ;; ALWAYS-NEXT: (local.get $x) ;; ALWAYS-NEXT: (local.get $x) ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) - ;; CAREFUL: (func $calls (type $2) (param $x i32) - ;; CAREFUL-NEXT: (call $work_8) - ;; CAREFUL-NEXT: (call $work_8) - ;; CAREFUL-NEXT: (call $work_9 + ;; CAREFUL: (func $calls (type $3) (param $x i32) + ;; CAREFUL-NEXT: (call $work_10) + ;; CAREFUL-NEXT: (call $work_10) + ;; CAREFUL-NEXT: (call $work_11 ;; CAREFUL-NEXT: (local.get $x) ;; CAREFUL-NEXT: ) - ;; CAREFUL-NEXT: (call $work_10 + ;; CAREFUL-NEXT: (call $work_12 ;; CAREFUL-NEXT: (local.get $x) ;; CAREFUL-NEXT: (local.get $x) ;; CAREFUL-NEXT: ) @@ -155,11 +163,11 @@ ) ) - ;; ALWAYS: (func $call-undropped (type $3) (result i32) - ;; ALWAYS-NEXT: (call $work_11) + ;; ALWAYS: (func $call-undropped (type $i) (result i32) + ;; ALWAYS-NEXT: (call $work_13) ;; ALWAYS-NEXT: ) - ;; CAREFUL: (func $call-undropped (type $3) (result i32) - ;; CAREFUL-NEXT: (call $work_11) + ;; CAREFUL: (func $call-undropped (type $i) (result i32) + ;; CAREFUL-NEXT: (call $work_13) ;; CAREFUL-NEXT: ) (func $call-undropped (result i32) ;; As above but now with constant params. We can monomorphize here - there @@ -179,7 +187,7 @@ ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) - ;; CAREFUL: (func $call-import (type $1) + ;; CAREFUL: (func $call-import (type $0) ;; CAREFUL-NEXT: (drop ;; CAREFUL-NEXT: (call $import ;; CAREFUL-NEXT: (i32.const 3) @@ -197,7 +205,7 @@ ) ) - ;; ALWAYS: (func $import-work (type $1) (param $x i32) (param $y i32) (result i32) + ;; ALWAYS: (func $import-work (type $iii) (param $x i32) (param $y i32) (result i32) ;; ALWAYS-NEXT: (call $import ;; ALWAYS-NEXT: (i32.xor ;; ALWAYS-NEXT: (local.get $x) @@ -209,7 +217,7 @@ ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) - ;; CAREFUL: (func $import-work (type $0) (param $0 i32) (param $1 i32) (result i32) + ;; CAREFUL: (func $import-work (type $iii) (param $0 i32) (param $1 i32) (result i32) ;; CAREFUL-NEXT: (call $import ;; CAREFUL-NEXT: (i32.xor ;; CAREFUL-NEXT: (local.get $0) @@ -236,9 +244,9 @@ ) ;; ALWAYS: (func $call-import-work (type $0) - ;; ALWAYS-NEXT: (call $import-work_12) + ;; ALWAYS-NEXT: (call $import-work_14) ;; ALWAYS-NEXT: ) - ;; CAREFUL: (func $call-import-work (type $1) + ;; CAREFUL: (func $call-import-work (type $0) ;; CAREFUL-NEXT: (drop ;; CAREFUL-NEXT: (call $import-work ;; CAREFUL-NEXT: (i32.const 3) @@ -258,8 +266,123 @@ ) ) ) + + ;; ALWAYS: (func $many-returns (type $i) (result i32) + ;; ALWAYS-NEXT: (if + ;; ALWAYS-NEXT: (call $import + ;; ALWAYS-NEXT: (i32.const 1) + ;; ALWAYS-NEXT: (i32.const 2) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: (then + ;; ALWAYS-NEXT: (return + ;; ALWAYS-NEXT: (i32.const 3) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: (else + ;; ALWAYS-NEXT: (return_call $import + ;; ALWAYS-NEXT: (i32.const 4) + ;; ALWAYS-NEXT: (i32.const 5) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: (if + ;; ALWAYS-NEXT: (call $import + ;; ALWAYS-NEXT: (i32.const 6) + ;; ALWAYS-NEXT: (i32.const 7) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: (then + ;; ALWAYS-NEXT: (return_call_indirect $table (type $i) + ;; ALWAYS-NEXT: (i32.const 8) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: (else + ;; ALWAYS-NEXT: (return_call_ref $iii + ;; ALWAYS-NEXT: (i32.const 1) + ;; ALWAYS-NEXT: (i32.const 2) + ;; ALWAYS-NEXT: (ref.func $import) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: (i32.const 4) + ;; ALWAYS-NEXT: ) + ;; CAREFUL: (func $many-returns (type $i) (result i32) + ;; CAREFUL-NEXT: (if (result i32) + ;; CAREFUL-NEXT: (call $import + ;; CAREFUL-NEXT: (i32.const 1) + ;; CAREFUL-NEXT: (i32.const 2) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: (then + ;; CAREFUL-NEXT: (i32.const 3) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: (else + ;; CAREFUL-NEXT: (return_call $import + ;; CAREFUL-NEXT: (i32.const 4) + ;; CAREFUL-NEXT: (i32.const 5) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: ) + (func $many-returns (result i32) + ;; This function returns in every possible way, which we need to handle in + ;; the monomorphized function (that no longer returns a value). + (if + (call $import + (i32.const 1) + (i32.const 2) + ) + (then + (return + (i32.const 3) + ) + ) + (else + (return_call $import + (i32.const 4) + (i32.const 5) + ) + ) + ) + (if + (call $import + (i32.const 6) + (i32.const 7) + ) + (then + (return_call_indirect (type $i) + (i32.const 8) + ) + ) + (else + (return_call_ref $iii + (i32.const 1) + (i32.const 2) + (ref.func $import) + ) + ) + ) + ;; Implicit return at the end. + (i32.const 4) + ) + + ;; ALWAYS: (func $call-many-returns (type $0) + ;; ALWAYS-NEXT: (call $many-returns_15) + ;; ALWAYS-NEXT: ) + ;; CAREFUL: (func $call-many-returns (type $0) + ;; CAREFUL-NEXT: (drop + ;; CAREFUL-NEXT: (call $many-returns) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: ) + (func $call-many-returns + ;; Call the above function to cause it to get monomorphized (only in ALWAYS, + ;; as there is no work we can remove). + ;; + ;; This also tests a function with no parameters being handled. + (drop + (call $many-returns) + ) + ) ) -;; ALWAYS: (func $work_8 (type $0) +;; ALWAYS: (func $work_10 (type $0) ;; ALWAYS-NEXT: (local $x i32) ;; ALWAYS-NEXT: (local $y i32) ;; ALWAYS-NEXT: (drop @@ -284,7 +407,7 @@ ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) -;; ALWAYS: (func $work_9 (type $2) (param $0 i32) +;; ALWAYS: (func $work_11 (type $3) (param $0 i32) ;; ALWAYS-NEXT: (local $x i32) ;; ALWAYS-NEXT: (local $y i32) ;; ALWAYS-NEXT: (drop @@ -309,7 +432,7 @@ ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) -;; ALWAYS: (func $work_10 (type $5) (param $0 i32) (param $1 i32) +;; ALWAYS: (func $work_12 (type $5) (param $0 i32) (param $1 i32) ;; ALWAYS-NEXT: (local $x i32) ;; ALWAYS-NEXT: (local $y i32) ;; ALWAYS-NEXT: (drop @@ -334,7 +457,7 @@ ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) -;; ALWAYS: (func $work_11 (type $3) (result i32) +;; ALWAYS: (func $work_13 (type $i) (result i32) ;; ALWAYS-NEXT: (local $x i32) ;; ALWAYS-NEXT: (local $y i32) ;; ALWAYS-NEXT: (local.set $x @@ -355,7 +478,7 @@ ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) -;; ALWAYS: (func $import-work_12 (type $0) +;; ALWAYS: (func $import-work_14 (type $0) ;; ALWAYS-NEXT: (local $x i32) ;; ALWAYS-NEXT: (local $y i32) ;; ALWAYS-NEXT: (drop @@ -380,18 +503,68 @@ ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) -;; CAREFUL: (func $work_8 (type $1) +;; ALWAYS: (func $many-returns_15 (type $0) +;; ALWAYS-NEXT: (drop +;; ALWAYS-NEXT: (block (result i32) +;; ALWAYS-NEXT: (if +;; ALWAYS-NEXT: (call $import +;; ALWAYS-NEXT: (i32.const 1) +;; ALWAYS-NEXT: (i32.const 2) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (then +;; ALWAYS-NEXT: (drop +;; ALWAYS-NEXT: (i32.const 3) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (return) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (else +;; ALWAYS-NEXT: (drop +;; ALWAYS-NEXT: (call $import +;; ALWAYS-NEXT: (i32.const 4) +;; ALWAYS-NEXT: (i32.const 5) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (if +;; ALWAYS-NEXT: (call $import +;; ALWAYS-NEXT: (i32.const 6) +;; ALWAYS-NEXT: (i32.const 7) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (then +;; ALWAYS-NEXT: (drop +;; ALWAYS-NEXT: (call_indirect $table (type $i) +;; ALWAYS-NEXT: (i32.const 8) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (else +;; ALWAYS-NEXT: (drop +;; ALWAYS-NEXT: (call_ref $iii +;; ALWAYS-NEXT: (i32.const 1) +;; ALWAYS-NEXT: (i32.const 2) +;; ALWAYS-NEXT: (ref.func $import) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (i32.const 4) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) + +;; CAREFUL: (func $work_10 (type $0) ;; CAREFUL-NEXT: (nop) ;; CAREFUL-NEXT: ) -;; CAREFUL: (func $work_9 (type $2) (param $0 i32) +;; CAREFUL: (func $work_11 (type $3) (param $0 i32) ;; CAREFUL-NEXT: (nop) ;; CAREFUL-NEXT: ) -;; CAREFUL: (func $work_10 (type $5) (param $0 i32) (param $1 i32) +;; CAREFUL: (func $work_12 (type $5) (param $0 i32) (param $1 i32) ;; CAREFUL-NEXT: (nop) ;; CAREFUL-NEXT: ) -;; CAREFUL: (func $work_11 (type $3) (result i32) +;; CAREFUL: (func $work_13 (type $i) (result i32) ;; CAREFUL-NEXT: (i32.const 49) ;; CAREFUL-NEXT: ) From b04fdc3683a76c7803b143f6762f20d280aab4ac Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 11 Jul 2024 16:37:30 -0700 Subject: [PATCH 17/35] format --- src/ir/return-utils.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/ir/return-utils.h b/src/ir/return-utils.h index 49f86e267f9..c8c98fc918e 100644 --- a/src/ir/return-utils.h +++ b/src/ir/return-utils.h @@ -54,9 +54,7 @@ struct ReturnValueRemover : public PostWalker { handleReturnCall(curr, targetType.getHeapType().getSignature()); } - - template - void handleReturnCall(T* curr, Signature sig) { + template void handleReturnCall(T* curr, Signature sig) { if (curr->isReturn) { // This can no longer be a return call, as it calls something that returns // a value, and we do not. Update the type (note we must handle the case From cc1356f24c3693804629aac7406d957fdc0f02ee Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 11 Jul 2024 16:49:25 -0700 Subject: [PATCH 18/35] add missing returns --- src/ir/return-utils.h | 17 +++++------------ test/lit/passes/monomorphize-drop.wast | 3 +++ 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/src/ir/return-utils.h b/src/ir/return-utils.h index c8c98fc918e..3a9d13cf58d 100644 --- a/src/ir/return-utils.h +++ b/src/ir/return-utils.h @@ -17,7 +17,6 @@ #ifndef wasm_ir_return_h #define wasm_ir_return_h -#include "ir/utils.h" #include "wasm-builder.h" #include "wasm-traversal.h" #include "wasm.h" @@ -58,14 +57,15 @@ struct ReturnValueRemover : public PostWalker { if (curr->isReturn) { // This can no longer be a return call, as it calls something that returns // a value, and we do not. Update the type (note we must handle the case - // of an unreachable child, and also this change may affect our parent, so - // refinalize the entire function). + // of an unreachable child, so refinalize). curr->isReturn = false; curr->type = sig.results; curr->finalize(); - refinalize = true; - replaceCurrent(Builder(*getModule()).makeDrop(curr)); + // Return after the dropped call. + Builder builder(*getModule()); + replaceCurrent(builder.makeSequence(builder.makeDrop(curr), + builder.makeReturn())); } } @@ -73,14 +73,7 @@ struct ReturnValueRemover : public PostWalker { if (curr->body->type.isConcrete()) { curr->body = Builder(*getModule()).makeDrop(curr->body); } - - if (refinalize) { - ReFinalize().walkFunctionInModule(curr, getModule()); - } } - -private: - bool refinalize = false; }; } // namespace wasm::ReturnUtils diff --git a/test/lit/passes/monomorphize-drop.wast b/test/lit/passes/monomorphize-drop.wast index 0c2be9d7cba..54b70be1f32 100644 --- a/test/lit/passes/monomorphize-drop.wast +++ b/test/lit/passes/monomorphize-drop.wast @@ -524,6 +524,7 @@ ;; ALWAYS-NEXT: (i32.const 5) ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (return) ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: (if @@ -537,6 +538,7 @@ ;; ALWAYS-NEXT: (i32.const 8) ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (return) ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: (else ;; ALWAYS-NEXT: (drop @@ -546,6 +548,7 @@ ;; ALWAYS-NEXT: (ref.func $import) ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (return) ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: (i32.const 4) From 5ea36755fb039d24f7302b8140a90679a842388c Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 11 Jul 2024 16:49:39 -0700 Subject: [PATCH 19/35] format --- src/ir/return-utils.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ir/return-utils.h b/src/ir/return-utils.h index 3a9d13cf58d..50c230b3186 100644 --- a/src/ir/return-utils.h +++ b/src/ir/return-utils.h @@ -64,8 +64,8 @@ struct ReturnValueRemover : public PostWalker { // Return after the dropped call. Builder builder(*getModule()); - replaceCurrent(builder.makeSequence(builder.makeDrop(curr), - builder.makeReturn())); + replaceCurrent( + builder.makeSequence(builder.makeDrop(curr), builder.makeReturn())); } } From 4d6f9b4daa26e1b4943c46b74bdb80fc730d4b4f Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 12 Jul 2024 09:37:45 -0700 Subject: [PATCH 20/35] rework return_calls --- src/ir/CMakeLists.txt | 1 + src/ir/return-utils.cpp | 89 ++++++++++++++++++++++++++ src/ir/return-utils.h | 60 +++-------------- src/passes/DeadArgumentElimination.cpp | 2 +- src/passes/Monomorphize.cpp | 20 ++++-- 5 files changed, 116 insertions(+), 56 deletions(-) create mode 100644 src/ir/return-utils.cpp diff --git a/src/ir/CMakeLists.txt b/src/ir/CMakeLists.txt index 996daa56416..45b08702de8 100644 --- a/src/ir/CMakeLists.txt +++ b/src/ir/CMakeLists.txt @@ -17,6 +17,7 @@ set(ir_SOURCES LocalGraph.cpp LocalStructuralDominance.cpp ReFinalize.cpp + return-utils.cpp stack-utils.cpp table-utils.cpp type-updating.cpp diff --git a/src/ir/return-utils.cpp b/src/ir/return-utils.cpp new file mode 100644 index 00000000000..9d2fbf72133 --- /dev/null +++ b/src/ir/return-utils.cpp @@ -0,0 +1,89 @@ +/* + * Copyright 2024 WebAssembly Community Group participants + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/module-utils.h" +#include "ir/return-utils.h" +#include "wasm-builder.h" +#include "wasm-traversal.h" +#include "wasm.h" + +namespace wasm::ReturnUtils { + +void removeReturns(Function* func, Module& wasm) { + struct ReturnValueRemover : public PostWalker { + void visitReturn(Return* curr) { + auto* value = curr->value; + assert(value); + curr->value = nullptr; + Builder builder(*getModule()); + replaceCurrent(builder.makeSequence(builder.makeDrop(value), curr)); + } + + void visitCall(Call* curr) { + handleReturnCall(curr); + } + void visitCallIndirect(CallIndirect* curr) { + handleReturnCall(curr); + } + void visitCallRef(CallRef* curr) { + handleReturnCall(curr); + } + + template void handleReturnCall(T* curr, Signature sig) { + if (curr->isReturn) { + Fatal() << "Cannot remove return_calls in ReturnValueRemover"; + } + } + + void visitFunction(Function* curr) { + if (curr->body->type.isConcrete()) { + curr->body = Builder(*getModule()).makeDrop(curr->body); + } + } + }; + + ReturnValueRemover().walkFunctionInModule(func, &wasm); +} + +std::unordered_map findReturnCallers(Module& wasm); + ParallelFunctionAnalysis analysis(wasm, [&](Function* func, bool& hasReturnCall) { + struct Finder : PostWalker { + bool hasReturnCall = false; + + void visitCall(Call* curr) { + if (curr->isReturn) { + hasReturnCall = true; + } + } + void visitCallIndirect(CallIndirect* curr) { + if (curr->isReturn) { + hasReturnCall = true; + } + } + void visitCallRef(CallRef* curr) { + if (curr->isReturn) { + hasReturnCall = true; + } + } + } finder; + + finder.walk(func->body); + hasReturnCall = finder.hasReturnCall; + }); + return std::move(analysis.map); +} + +} // namespace wasm::ReturnUtils diff --git a/src/ir/return-utils.h b/src/ir/return-utils.h index 50c230b3186..a5214ba017c 100644 --- a/src/ir/return-utils.h +++ b/src/ir/return-utils.h @@ -17,8 +17,6 @@ #ifndef wasm_ir_return_h #define wasm_ir_return_h -#include "wasm-builder.h" -#include "wasm-traversal.h" #include "wasm.h" namespace wasm::ReturnUtils { @@ -26,55 +24,15 @@ namespace wasm::ReturnUtils { // Removes values from both explicit returns and implicit ones (values that flow // from the body). This is useful after changing a function's type to no longer // return anything. -struct ReturnValueRemover : public PostWalker { - void visitReturn(Return* curr) { - auto* value = curr->value; - assert(value); - curr->value = nullptr; - Builder builder(*getModule()); - replaceCurrent(builder.makeSequence(builder.makeDrop(value), curr)); - } - - void visitCall(Call* curr) { - handleReturnCall(curr, getModule()->getFunction(curr->target)->getSig()); - } - - void visitCallIndirect(CallIndirect* curr) { - handleReturnCall(curr, curr->heapType.getSignature()); - } - - void visitCallRef(CallRef* curr) { - Type targetType = curr->target->type; - if (!targetType.isSignature()) { - // We don't know what type the call should return, but it will also never - // be reached, so we don't need to do anything here. - return; - } - handleReturnCall(curr, targetType.getHeapType().getSignature()); - } - - template void handleReturnCall(T* curr, Signature sig) { - if (curr->isReturn) { - // This can no longer be a return call, as it calls something that returns - // a value, and we do not. Update the type (note we must handle the case - // of an unreachable child, so refinalize). - curr->isReturn = false; - curr->type = sig.results; - curr->finalize(); - - // Return after the dropped call. - Builder builder(*getModule()); - replaceCurrent( - builder.makeSequence(builder.makeDrop(curr), builder.makeReturn())); - } - } - - void visitFunction(Function* curr) { - if (curr->body->type.isConcrete()) { - curr->body = Builder(*getModule()).makeDrop(curr->body); - } - } -}; +// +// This does *not* handle return calls, and will error on them. Removing a +// return call may change the semantics of the program, so we do not do it +// automatically here. +void removeReturns(Function* func, Module& wasm); + +// Return a map of every function to whether it does a return call. +using ReturnCallersMap = std::unordered_map; +ReturnCallersMap findReturnCallers(Module& wasm); } // namespace wasm::ReturnUtils diff --git a/src/passes/DeadArgumentElimination.cpp b/src/passes/DeadArgumentElimination.cpp index fdb5d71cfe4..83cd7e86d07 100644 --- a/src/passes/DeadArgumentElimination.cpp +++ b/src/passes/DeadArgumentElimination.cpp @@ -359,7 +359,7 @@ struct DAE : public Pass { } } // Remove any return values. - ReturnUtils::ReturnValueRemover().walkFunctionInModule(func, module); + ReturnUtils::removeReturns(func, *module); } // Given a function and all the calls to it, see if we can refine the type of diff --git a/src/passes/Monomorphize.cpp b/src/passes/Monomorphize.cpp index 583c72847c4..ee42c432593 100644 --- a/src/passes/Monomorphize.cpp +++ b/src/passes/Monomorphize.cpp @@ -329,6 +329,11 @@ struct Monomorphize : public Pass { void run(Module* module) override { // TODO: parallelize, see comments below + // Find all the return-calling functions. We cannot remove their returns + // (because turning a return call into a normal call may break the program + // by using more stack). + auto returnCallersMap = ReturnUtils::findReturnCallers(*module); + // Note the list of all functions. We'll be adding more, and do not want to // operate on those. std::vector funcNames; @@ -355,13 +360,13 @@ struct Monomorphize : public Pass { continue; } - processCall(info, *module); + processCall(info, *module, returnCallersMap); } } } // Try to optimize a call. - void processCall(CallInfo& info, Module& wasm) { + void processCall(CallInfo& info, Module& wasm, ReturnCallersMap& returnCallersMap) { auto* call = info.call; auto target = call->target; auto* func = wasm.getFunction(target); @@ -378,6 +383,14 @@ struct Monomorphize : public Pass { std::vector newOperands; context.buildFromCall(info, newOperands, wasm); + // If the called function does a return call, then as noted earlier we + // cannot remove its returns, so do not consider the drop part of the + // context in such cases (as if we reverse-inlined the drop into the target + // then we'd be removing the returns). + if (returnCallersMap[func]) { + context.dropped = false; + } + // See if we've already evaluated this function + call context. If so, then // we've memoized the result. auto iter = funcContextMap.find({target, context}); @@ -581,8 +594,7 @@ struct Monomorphize : public Pass { } if (context.dropped) { - ReturnUtils::ReturnValueRemover().walkFunctionInModule(newFunc.get(), - &wasm); + ReturnUtils::removeReturns(newFunc.get(), wasm); } return newFunc; From 635e91d8bf8592e29ee06ede399db2978268a773 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 12 Jul 2024 09:41:01 -0700 Subject: [PATCH 21/35] builds --- src/ir/return-utils.cpp | 62 ++++++++++++++++++++----------------- src/passes/Monomorphize.cpp | 2 +- 2 files changed, 34 insertions(+), 30 deletions(-) diff --git a/src/ir/return-utils.cpp b/src/ir/return-utils.cpp index 9d2fbf72133..d82400ec907 100644 --- a/src/ir/return-utils.cpp +++ b/src/ir/return-utils.cpp @@ -22,44 +22,48 @@ namespace wasm::ReturnUtils { -void removeReturns(Function* func, Module& wasm) { - struct ReturnValueRemover : public PostWalker { - void visitReturn(Return* curr) { - auto* value = curr->value; - assert(value); - curr->value = nullptr; - Builder builder(*getModule()); - replaceCurrent(builder.makeSequence(builder.makeDrop(value), curr)); - } +namespace { - void visitCall(Call* curr) { - handleReturnCall(curr); - } - void visitCallIndirect(CallIndirect* curr) { - handleReturnCall(curr); - } - void visitCallRef(CallRef* curr) { - handleReturnCall(curr); - } +struct ReturnValueRemover : public PostWalker { + void visitReturn(Return* curr) { + auto* value = curr->value; + assert(value); + curr->value = nullptr; + Builder builder(*getModule()); + replaceCurrent(builder.makeSequence(builder.makeDrop(value), curr)); + } - template void handleReturnCall(T* curr, Signature sig) { - if (curr->isReturn) { - Fatal() << "Cannot remove return_calls in ReturnValueRemover"; - } + void visitCall(Call* curr) { + handleReturnCall(curr); + } + void visitCallIndirect(CallIndirect* curr) { + handleReturnCall(curr); + } + void visitCallRef(CallRef* curr) { + handleReturnCall(curr); + } + + template void handleReturnCall(T* curr) { + if (curr->isReturn) { + Fatal() << "Cannot remove return_calls in ReturnValueRemover"; } + } - void visitFunction(Function* curr) { - if (curr->body->type.isConcrete()) { - curr->body = Builder(*getModule()).makeDrop(curr->body); - } + void visitFunction(Function* curr) { + if (curr->body->type.isConcrete()) { + curr->body = Builder(*getModule()).makeDrop(curr->body); } - }; + } +}; +} // anonymous namespace + +void removeReturns(Function* func, Module& wasm) { ReturnValueRemover().walkFunctionInModule(func, &wasm); } -std::unordered_map findReturnCallers(Module& wasm); - ParallelFunctionAnalysis analysis(wasm, [&](Function* func, bool& hasReturnCall) { +std::unordered_map findReturnCallers(Module& wasm) { + ModuleUtils::ParallelFunctionAnalysis analysis(wasm, [&](Function* func, bool& hasReturnCall) { struct Finder : PostWalker { bool hasReturnCall = false; diff --git a/src/passes/Monomorphize.cpp b/src/passes/Monomorphize.cpp index ee42c432593..e39f6d9697b 100644 --- a/src/passes/Monomorphize.cpp +++ b/src/passes/Monomorphize.cpp @@ -366,7 +366,7 @@ struct Monomorphize : public Pass { } // Try to optimize a call. - void processCall(CallInfo& info, Module& wasm, ReturnCallersMap& returnCallersMap) { + void processCall(CallInfo& info, Module& wasm, ReturnUtils::ReturnCallersMap& returnCallersMap) { auto* call = info.call; auto target = call->target; auto* func = wasm.getFunction(target); From 48e1aaa97a89737f686e76e11bf953cd2f8075f3 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 12 Jul 2024 09:41:15 -0700 Subject: [PATCH 22/35] format --- src/ir/return-utils.cpp | 53 +++++++++++++++++-------------------- src/passes/Monomorphize.cpp | 4 ++- 2 files changed, 27 insertions(+), 30 deletions(-) diff --git a/src/ir/return-utils.cpp b/src/ir/return-utils.cpp index d82400ec907..7f5a862a70b 100644 --- a/src/ir/return-utils.cpp +++ b/src/ir/return-utils.cpp @@ -14,8 +14,8 @@ * limitations under the License. */ -#include "ir/module-utils.h" #include "ir/return-utils.h" +#include "ir/module-utils.h" #include "wasm-builder.h" #include "wasm-traversal.h" #include "wasm.h" @@ -33,15 +33,9 @@ struct ReturnValueRemover : public PostWalker { replaceCurrent(builder.makeSequence(builder.makeDrop(value), curr)); } - void visitCall(Call* curr) { - handleReturnCall(curr); - } - void visitCallIndirect(CallIndirect* curr) { - handleReturnCall(curr); - } - void visitCallRef(CallRef* curr) { - handleReturnCall(curr); - } + void visitCall(Call* curr) { handleReturnCall(curr); } + void visitCallIndirect(CallIndirect* curr) { handleReturnCall(curr); } + void visitCallRef(CallRef* curr) { handleReturnCall(curr); } template void handleReturnCall(T* curr) { if (curr->isReturn) { @@ -63,30 +57,31 @@ void removeReturns(Function* func, Module& wasm) { } std::unordered_map findReturnCallers(Module& wasm) { - ModuleUtils::ParallelFunctionAnalysis analysis(wasm, [&](Function* func, bool& hasReturnCall) { - struct Finder : PostWalker { - bool hasReturnCall = false; + ModuleUtils::ParallelFunctionAnalysis + analysis(wasm, [&](Function* func, bool& hasReturnCall) { + struct Finder : PostWalker { + bool hasReturnCall = false; - void visitCall(Call* curr) { - if (curr->isReturn) { - hasReturnCall = true; + void visitCall(Call* curr) { + if (curr->isReturn) { + hasReturnCall = true; + } } - } - void visitCallIndirect(CallIndirect* curr) { - if (curr->isReturn) { - hasReturnCall = true; + void visitCallIndirect(CallIndirect* curr) { + if (curr->isReturn) { + hasReturnCall = true; + } } - } - void visitCallRef(CallRef* curr) { - if (curr->isReturn) { - hasReturnCall = true; + void visitCallRef(CallRef* curr) { + if (curr->isReturn) { + hasReturnCall = true; + } } - } - } finder; + } finder; - finder.walk(func->body); - hasReturnCall = finder.hasReturnCall; - }); + finder.walk(func->body); + hasReturnCall = finder.hasReturnCall; + }); return std::move(analysis.map); } diff --git a/src/passes/Monomorphize.cpp b/src/passes/Monomorphize.cpp index e39f6d9697b..8e188104404 100644 --- a/src/passes/Monomorphize.cpp +++ b/src/passes/Monomorphize.cpp @@ -366,7 +366,9 @@ struct Monomorphize : public Pass { } // Try to optimize a call. - void processCall(CallInfo& info, Module& wasm, ReturnUtils::ReturnCallersMap& returnCallersMap) { + void processCall(CallInfo& info, + Module& wasm, + ReturnUtils::ReturnCallersMap& returnCallersMap) { auto* call = info.call; auto target = call->target; auto* func = wasm.getFunction(target); From 7ed19e855fe681098698e6fb2f41ddb13b7d934d Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 12 Jul 2024 09:42:12 -0700 Subject: [PATCH 23/35] whoops --- src/ir/return-utils.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/ir/return-utils.cpp b/src/ir/return-utils.cpp index 7f5a862a70b..7de1122dcaa 100644 --- a/src/ir/return-utils.cpp +++ b/src/ir/return-utils.cpp @@ -59,6 +59,10 @@ void removeReturns(Function* func, Module& wasm) { std::unordered_map findReturnCallers(Module& wasm) { ModuleUtils::ParallelFunctionAnalysis analysis(wasm, [&](Function* func, bool& hasReturnCall) { + if (func->imported()) { + return; + } + struct Finder : PostWalker { bool hasReturnCall = false; From 099872a9ff31fc814a772da558bc7fe663e27a0c Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 12 Jul 2024 09:42:39 -0700 Subject: [PATCH 24/35] work --- test/lit/passes/monomorphize-drop.wast | 96 +++++++++----------------- 1 file changed, 34 insertions(+), 62 deletions(-) diff --git a/test/lit/passes/monomorphize-drop.wast b/test/lit/passes/monomorphize-drop.wast index 54b70be1f32..261088040d2 100644 --- a/test/lit/passes/monomorphize-drop.wast +++ b/test/lit/passes/monomorphize-drop.wast @@ -16,8 +16,6 @@ ;; ALWAYS: (type $iii (func (param i32 i32) (result i32))) ;; ALWAYS: (type $i (func (result i32))) - ;; CAREFUL: (type $0 (func)) - ;; CAREFUL: (type $iii (func (param i32 i32) (result i32))) ;; CAREFUL: (type $i (func (result i32))) @@ -32,6 +30,8 @@ ;; ALWAYS: (type $5 (func (param i32 i32))) ;; ALWAYS: (import "a" "b" (func $import (type $iii) (param i32 i32) (result i32))) + ;; CAREFUL: (type $2 (func)) + ;; CAREFUL: (type $3 (func (param i32))) ;; CAREFUL: (type $4 (func (param i32) (result i32))) @@ -59,6 +59,8 @@ ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) + ;; CAREFUL: (elem declare func $import) + ;; CAREFUL: (func $work (type $iii) (param $0 i32) (param $1 i32) (result i32) ;; CAREFUL-NEXT: (i32.mul ;; CAREFUL-NEXT: (i32.add @@ -187,7 +189,7 @@ ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) - ;; CAREFUL: (func $call-import (type $0) + ;; CAREFUL: (func $call-import (type $2) ;; CAREFUL-NEXT: (drop ;; CAREFUL-NEXT: (call $import ;; CAREFUL-NEXT: (i32.const 3) @@ -246,7 +248,7 @@ ;; ALWAYS: (func $call-import-work (type $0) ;; ALWAYS-NEXT: (call $import-work_14) ;; ALWAYS-NEXT: ) - ;; CAREFUL: (func $call-import-work (type $0) + ;; CAREFUL: (func $call-import-work (type $2) ;; CAREFUL-NEXT: (drop ;; CAREFUL-NEXT: (call $import-work ;; CAREFUL-NEXT: (i32.const 3) @@ -306,13 +308,15 @@ ;; ALWAYS-NEXT: (i32.const 4) ;; ALWAYS-NEXT: ) ;; CAREFUL: (func $many-returns (type $i) (result i32) - ;; CAREFUL-NEXT: (if (result i32) + ;; CAREFUL-NEXT: (if ;; CAREFUL-NEXT: (call $import ;; CAREFUL-NEXT: (i32.const 1) ;; CAREFUL-NEXT: (i32.const 2) ;; CAREFUL-NEXT: ) ;; CAREFUL-NEXT: (then - ;; CAREFUL-NEXT: (i32.const 3) + ;; CAREFUL-NEXT: (return + ;; CAREFUL-NEXT: (i32.const 3) + ;; CAREFUL-NEXT: ) ;; CAREFUL-NEXT: ) ;; CAREFUL-NEXT: (else ;; CAREFUL-NEXT: (return_call $import @@ -321,6 +325,25 @@ ;; CAREFUL-NEXT: ) ;; CAREFUL-NEXT: ) ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: (if + ;; CAREFUL-NEXT: (call $import + ;; CAREFUL-NEXT: (i32.const 6) + ;; CAREFUL-NEXT: (i32.const 7) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: (then + ;; CAREFUL-NEXT: (return_call_indirect $table (type $i) + ;; CAREFUL-NEXT: (i32.const 8) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: (else + ;; CAREFUL-NEXT: (return_call_ref $iii + ;; CAREFUL-NEXT: (i32.const 1) + ;; CAREFUL-NEXT: (i32.const 2) + ;; CAREFUL-NEXT: (ref.func $import) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: (i32.const 4) ;; CAREFUL-NEXT: ) (func $many-returns (result i32) ;; This function returns in every possible way, which we need to handle in @@ -365,9 +388,11 @@ ) ;; ALWAYS: (func $call-many-returns (type $0) - ;; ALWAYS-NEXT: (call $many-returns_15) + ;; ALWAYS-NEXT: (drop + ;; ALWAYS-NEXT: (call $many-returns) + ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) - ;; CAREFUL: (func $call-many-returns (type $0) + ;; CAREFUL: (func $call-many-returns (type $2) ;; CAREFUL-NEXT: (drop ;; CAREFUL-NEXT: (call $many-returns) ;; CAREFUL-NEXT: ) @@ -503,60 +528,7 @@ ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) -;; ALWAYS: (func $many-returns_15 (type $0) -;; ALWAYS-NEXT: (drop -;; ALWAYS-NEXT: (block (result i32) -;; ALWAYS-NEXT: (if -;; ALWAYS-NEXT: (call $import -;; ALWAYS-NEXT: (i32.const 1) -;; ALWAYS-NEXT: (i32.const 2) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: (then -;; ALWAYS-NEXT: (drop -;; ALWAYS-NEXT: (i32.const 3) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: (return) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: (else -;; ALWAYS-NEXT: (drop -;; ALWAYS-NEXT: (call $import -;; ALWAYS-NEXT: (i32.const 4) -;; ALWAYS-NEXT: (i32.const 5) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: (return) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: (if -;; ALWAYS-NEXT: (call $import -;; ALWAYS-NEXT: (i32.const 6) -;; ALWAYS-NEXT: (i32.const 7) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: (then -;; ALWAYS-NEXT: (drop -;; ALWAYS-NEXT: (call_indirect $table (type $i) -;; ALWAYS-NEXT: (i32.const 8) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: (return) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: (else -;; ALWAYS-NEXT: (drop -;; ALWAYS-NEXT: (call_ref $iii -;; ALWAYS-NEXT: (i32.const 1) -;; ALWAYS-NEXT: (i32.const 2) -;; ALWAYS-NEXT: (ref.func $import) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: (return) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: (i32.const 4) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: ) - -;; CAREFUL: (func $work_10 (type $0) +;; CAREFUL: (func $work_10 (type $2) ;; CAREFUL-NEXT: (nop) ;; CAREFUL-NEXT: ) From 6a5419fae4263b64b87c4ec778925d9faa2840c5 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 12 Jul 2024 11:12:56 -0700 Subject: [PATCH 25/35] tests --- test/lit/passes/monomorphize-drop.wast | 166 +++++++++++++++++++------ 1 file changed, 126 insertions(+), 40 deletions(-) diff --git a/test/lit/passes/monomorphize-drop.wast b/test/lit/passes/monomorphize-drop.wast index 261088040d2..d2ffd266a7e 100644 --- a/test/lit/passes/monomorphize-drop.wast +++ b/test/lit/passes/monomorphize-drop.wast @@ -41,6 +41,8 @@ ;; CAREFUL: (import "a" "b" (func $import (type $iii) (param i32 i32) (result i32))) (import "a" "b" (func $import (param i32 i32) (result i32))) + (import "a" "c" (func $import2)) + ;; ALWAYS: (table $table 10 10 funcref) ;; CAREFUL: (table $table 10 10 funcref) (table $table 10 10 funcref) @@ -181,6 +183,18 @@ ) ) + (func $no-params (result i32) + ;; A function that will be dropped, and has no params. + (i32.const 42) + ) + + (func $call-no-params (result i32) + (drop + (call $no-params) + ) + (call $no-params) + ) + ;; ALWAYS: (func $call-import (type $0) ;; ALWAYS-NEXT: (drop ;; ALWAYS-NEXT: (call $import @@ -345,65 +359,137 @@ ;; CAREFUL-NEXT: ) ;; CAREFUL-NEXT: (i32.const 4) ;; CAREFUL-NEXT: ) - (func $many-returns (result i32) - ;; This function returns in every possible way, which we need to handle in - ;; the monomorphized function (that no longer returns a value). + (func $return-normal (param $x i32) (result i32) + ;; This function has a return, which needs to be handled in the + ;; monomorphized function, as we'll no longer return a value. (if - (call $import - (i32.const 1) - (i32.const 2) - ) + (local.get $x) (then + (drop + (call $import2) + ) (return - (i32.const 3) + (i32.const 0) ) ) - (else - (return_call $import - (i32.const 4) - (i32.const 5) - ) + ) + ;; Also return a value by flowing it out. + (i32.const 1) + ) + + (func $call-return-normal (param $x i32) + ;; Call the above function with 0, 1, and an unknown value, to test the two + ;; code paths there + the case of the input being unknown. + (drop + (call $return-normal + (i32.const 0) + ) + ) + (drop + (call $return-normal + (i32.const 1) ) ) + (drop + (call $return-normal + (local.get $x) + ) + ) + ) + + (func $return-call (param $x i32) (result i32) + ;; As above, but now with a return_call. We do not monomorphize the drop + ;; part, as if we included the drop we'd turn the call into a non-return + ;; call, which can break things. (if - (call $import - (i32.const 6) - (i32.const 7) + (local.get $x) + (then + (return_call + (call $import2) + ) ) + ) + (i32.const 1) + ) + + (func $call-return-call (param $x i32) + ;; As above, but due to the return call we won't monomorphize the drop. + (drop + (call $return-call + (i32.const 0) + ) + ) + (drop + (call $return-call + (i32.const 1) + ) + ) + (drop + (call $return-call + (local.get $x) + ) + ) + ) + + (func $return-call-indirect (param $x i32) (result i32) + ;; As above, but now with a return_call_indirect. The outcome is similar. + (if + (local.get $x) (then (return_call_indirect (type $i) - (i32.const 8) + (call $import2) ) ) - (else - (return_call_ref $iii - (i32.const 1) - (i32.const 2) - (ref.func $import) + ) + (i32.const 1) + ) + + (func $call-return-call (param $x i32) + (drop + (call $return-call-indirect + (i32.const 0) + ) + ) + (drop + (call $return-call-indirect + (i32.const 1) + ) + ) + (drop + (call $return-call-indirect + (local.get $x) + ) + ) + ) + + (func $return-call-ref (param $x i32) (result i32) + ;; As above, but now with a return_call_ref. The outcome is similar. + (if + (local.get $x) + (then + (return_call_ref (type $i) + (ref.func $import2) ) ) ) - ;; Implicit return at the end. - (i32.const 4) + (i32.const 1) ) - ;; ALWAYS: (func $call-many-returns (type $0) - ;; ALWAYS-NEXT: (drop - ;; ALWAYS-NEXT: (call $many-returns) - ;; ALWAYS-NEXT: ) - ;; ALWAYS-NEXT: ) - ;; CAREFUL: (func $call-many-returns (type $2) - ;; CAREFUL-NEXT: (drop - ;; CAREFUL-NEXT: (call $many-returns) - ;; CAREFUL-NEXT: ) - ;; CAREFUL-NEXT: ) - (func $call-many-returns - ;; Call the above function to cause it to get monomorphized (only in ALWAYS, - ;; as there is no work we can remove). - ;; - ;; This also tests a function with no parameters being handled. + (func $call-return-call (param $x i32) + (drop + (call $return-call-ref + (i32.const 0) + ) + ) + (drop + (call $return-call-ref + (i32.const 1) + ) + ) (drop - (call $many-returns) + (call $return-call-ref + (local.get $x) + ) ) ) ) From 561714fa717aa0390a35f50e9ff63c0fa184d4a8 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 12 Jul 2024 11:15:11 -0700 Subject: [PATCH 26/35] test.work --- test/lit/passes/monomorphize-drop.wast | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/test/lit/passes/monomorphize-drop.wast b/test/lit/passes/monomorphize-drop.wast index d2ffd266a7e..5a5e1c3972b 100644 --- a/test/lit/passes/monomorphize-drop.wast +++ b/test/lit/passes/monomorphize-drop.wast @@ -41,7 +41,7 @@ ;; CAREFUL: (import "a" "b" (func $import (type $iii) (param i32 i32) (result i32))) (import "a" "b" (func $import (param i32 i32) (result i32))) - (import "a" "c" (func $import2)) + (import "a" "c" (func $import2 (result i32))) ;; ALWAYS: (table $table 10 10 funcref) ;; CAREFUL: (table $table 10 10 funcref) @@ -404,9 +404,7 @@ (if (local.get $x) (then - (return_call - (call $import2) - ) + (return_call $import2) ) ) (i32.const 1) @@ -444,7 +442,7 @@ (i32.const 1) ) - (func $call-return-call (param $x i32) + (func $call-return-call-indirect (param $x i32) (drop (call $return-call-indirect (i32.const 0) @@ -467,7 +465,7 @@ (if (local.get $x) (then - (return_call_ref (type $i) + (return_call_ref $i (ref.func $import2) ) ) @@ -475,7 +473,7 @@ (i32.const 1) ) - (func $call-return-call (param $x i32) + (func $call-return-call-ref (param $x i32) (drop (call $return-call-ref (i32.const 0) From 403fdacc08e5272fca732d2084332482858f569d Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 12 Jul 2024 11:18:13 -0700 Subject: [PATCH 27/35] test.work --- test/lit/passes/monomorphize-drop.wast | 31 ++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/test/lit/passes/monomorphize-drop.wast b/test/lit/passes/monomorphize-drop.wast index 5a5e1c3972b..7c79e15d130 100644 --- a/test/lit/passes/monomorphize-drop.wast +++ b/test/lit/passes/monomorphize-drop.wast @@ -195,6 +195,11 @@ (call $no-params) ) + (func $call-no-params-return (result i32) + ;; Return calls can be monomorphized too. + (return_call $import2) + ) + ;; ALWAYS: (func $call-import (type $0) ;; ALWAYS-NEXT: (drop ;; ALWAYS-NEXT: (call $import @@ -489,6 +494,32 @@ (local.get $x) ) ) + + ;; Also add some return calls here, to show that it is fine for the caller + ;; to have them: we can still monomorphize the previous calls (without their + ;; drops). + (if + (local.get $x) + (then + (return_call $import2) + ) + ) + (if + (local.get $x) + (then + (return_call_indirect (type $i) + (ref.func $import2) + ) + ) + ) + (if + (local.get $x) + (then + (return_call_ref $i + (ref.func $import2) + ) + ) + ) ) ) ;; ALWAYS: (func $work_10 (type $0) From ce132235b19af9e4ff8ce8a9e7a09c4ab547053b Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 12 Jul 2024 11:21:41 -0700 Subject: [PATCH 28/35] fix.test --- test/lit/passes/monomorphize-drop.wast | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/lit/passes/monomorphize-drop.wast b/test/lit/passes/monomorphize-drop.wast index 7c79e15d130..31f7ebad45f 100644 --- a/test/lit/passes/monomorphize-drop.wast +++ b/test/lit/passes/monomorphize-drop.wast @@ -478,7 +478,7 @@ (i32.const 1) ) - (func $call-return-call-ref (param $x i32) + (func $call-return-call-ref (param $x i32) (result i32) (drop (call $return-call-ref (i32.const 0) @@ -508,7 +508,7 @@ (local.get $x) (then (return_call_indirect (type $i) - (ref.func $import2) + (i32.const 7) ) ) ) @@ -520,6 +520,7 @@ ) ) ) + (unreachable) ) ) ;; ALWAYS: (func $work_10 (type $0) From c6a653eabcf8b8defbfa6e1827c12ca1cd58482d Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 12 Jul 2024 11:54:23 -0700 Subject: [PATCH 29/35] fix --- src/passes/Monomorphize.cpp | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/src/passes/Monomorphize.cpp b/src/passes/Monomorphize.cpp index 8e188104404..8c08db55bde 100644 --- a/src/passes/Monomorphize.cpp +++ b/src/passes/Monomorphize.cpp @@ -360,15 +360,21 @@ struct Monomorphize : public Pass { continue; } - processCall(info, *module, returnCallersMap); + // If the target function does a return call, then as noted earlier we + // cannot remove its returns, so do not consider the drop as part of the + // context in such cases (as if we reverse-inlined the drop into the + // target then we'd be removing the returns). + if (returnCallersMap[module->getFunction(info.call->target)]) { + info.drop = nullptr; + } + + processCall(info, *module); } } } // Try to optimize a call. - void processCall(CallInfo& info, - Module& wasm, - ReturnUtils::ReturnCallersMap& returnCallersMap) { + void processCall(CallInfo& info, Module& wasm) { auto* call = info.call; auto target = call->target; auto* func = wasm.getFunction(target); @@ -385,14 +391,6 @@ struct Monomorphize : public Pass { std::vector newOperands; context.buildFromCall(info, newOperands, wasm); - // If the called function does a return call, then as noted earlier we - // cannot remove its returns, so do not consider the drop part of the - // context in such cases (as if we reverse-inlined the drop into the target - // then we'd be removing the returns). - if (returnCallersMap[func]) { - context.dropped = false; - } - // See if we've already evaluated this function + call context. If so, then // we've memoized the result. auto iter = funcContextMap.find({target, context}); From 021b396361023688a29d62a1ca09237c22ac0380 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 12 Jul 2024 12:00:41 -0700 Subject: [PATCH 30/35] work --- test/lit/passes/monomorphize-drop.wast | 675 ++++++++++++++++++++----- 1 file changed, 558 insertions(+), 117 deletions(-) diff --git a/test/lit/passes/monomorphize-drop.wast b/test/lit/passes/monomorphize-drop.wast index 31f7ebad45f..6a05b24263b 100644 --- a/test/lit/passes/monomorphize-drop.wast +++ b/test/lit/passes/monomorphize-drop.wast @@ -11,43 +11,43 @@ ;; Test that dropped functions are monomorphized, and the drop is reverse- ;; inlined into the called function, enabling more optimizations. - ;; ALWAYS: (type $0 (func)) - - ;; ALWAYS: (type $iii (func (param i32 i32) (result i32))) - ;; ALWAYS: (type $i (func (result i32))) - ;; CAREFUL: (type $iii (func (param i32 i32) (result i32))) - ;; CAREFUL: (type $i (func (result i32))) (type $i (func (result i32))) - (type $iii (func (param i32 i32) (result i32))) + ;; ALWAYS: (type $1 (func)) - ;; ALWAYS: (type $3 (func (param i32))) + ;; ALWAYS: (type $2 (func (param i32))) - ;; ALWAYS: (type $4 (func (param i32) (result i32))) + ;; ALWAYS: (type $3 (func (param i32) (result i32))) - ;; ALWAYS: (type $5 (func (param i32 i32))) + ;; ALWAYS: (type $iii (func (param i32 i32) (result i32))) + ;; CAREFUL: (type $1 (func (param i32))) - ;; ALWAYS: (import "a" "b" (func $import (type $iii) (param i32 i32) (result i32))) - ;; CAREFUL: (type $2 (func)) + ;; CAREFUL: (type $2 (func (param i32) (result i32))) + + ;; CAREFUL: (type $3 (func)) - ;; CAREFUL: (type $3 (func (param i32))) + ;; CAREFUL: (type $iii (func (param i32 i32) (result i32))) + (type $iii (func (param i32 i32) (result i32))) - ;; CAREFUL: (type $4 (func (param i32) (result i32))) + ;; ALWAYS: (type $5 (func (param i32 i32))) + ;; ALWAYS: (import "a" "b" (func $import (type $iii) (param i32 i32) (result i32))) ;; CAREFUL: (type $5 (func (param i32 i32))) ;; CAREFUL: (import "a" "b" (func $import (type $iii) (param i32 i32) (result i32))) (import "a" "b" (func $import (param i32 i32) (result i32))) + ;; ALWAYS: (import "a" "c" (func $import2 (type $i) (result i32))) + ;; CAREFUL: (import "a" "c" (func $import2 (type $i) (result i32))) (import "a" "c" (func $import2 (result i32))) ;; ALWAYS: (table $table 10 10 funcref) ;; CAREFUL: (table $table 10 10 funcref) (table $table 10 10 funcref) - ;; ALWAYS: (elem declare func $import) + ;; ALWAYS: (elem declare func $import2) ;; ALWAYS: (func $work (type $iii) (param $x i32) (param $y i32) (result i32) ;; ALWAYS-NEXT: (i32.mul @@ -55,17 +55,17 @@ ;; ALWAYS-NEXT: (local.get $x) ;; ALWAYS-NEXT: (local.get $y) ;; ALWAYS-NEXT: ) - ;; ALWAYS-NEXT: (i32.add + ;; ALWAYS-NEXT: (i32.div_s ;; ALWAYS-NEXT: (local.get $x) ;; ALWAYS-NEXT: (local.get $y) ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) - ;; CAREFUL: (elem declare func $import) + ;; CAREFUL: (elem declare func $import2) ;; CAREFUL: (func $work (type $iii) (param $0 i32) (param $1 i32) (result i32) ;; CAREFUL-NEXT: (i32.mul - ;; CAREFUL-NEXT: (i32.add + ;; CAREFUL-NEXT: (i32.div_s ;; CAREFUL-NEXT: (local.get $0) ;; CAREFUL-NEXT: (local.get $1) ;; CAREFUL-NEXT: ) @@ -83,31 +83,31 @@ (local.get $x) (local.get $y) ) - (i32.add + (i32.div_s (local.get $x) (local.get $y) ) ) ) - ;; ALWAYS: (func $calls (type $3) (param $x i32) - ;; ALWAYS-NEXT: (call $work_10) - ;; ALWAYS-NEXT: (call $work_10) - ;; ALWAYS-NEXT: (call $work_11 + ;; ALWAYS: (func $calls (type $2) (param $x i32) + ;; ALWAYS-NEXT: (call $work_20) + ;; ALWAYS-NEXT: (call $work_20) + ;; ALWAYS-NEXT: (call $work_21 ;; ALWAYS-NEXT: (local.get $x) ;; ALWAYS-NEXT: ) - ;; ALWAYS-NEXT: (call $work_12 + ;; ALWAYS-NEXT: (call $work_22 ;; ALWAYS-NEXT: (local.get $x) ;; ALWAYS-NEXT: (local.get $x) ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) - ;; CAREFUL: (func $calls (type $3) (param $x i32) - ;; CAREFUL-NEXT: (call $work_10) - ;; CAREFUL-NEXT: (call $work_10) - ;; CAREFUL-NEXT: (call $work_11 + ;; CAREFUL: (func $calls (type $1) (param $x i32) + ;; CAREFUL-NEXT: (call $work_20) + ;; CAREFUL-NEXT: (call $work_20) + ;; CAREFUL-NEXT: (call $work_21 ;; CAREFUL-NEXT: (local.get $x) ;; CAREFUL-NEXT: ) - ;; CAREFUL-NEXT: (call $work_12 + ;; CAREFUL-NEXT: (call $work_22 ;; CAREFUL-NEXT: (local.get $x) ;; CAREFUL-NEXT: (local.get $x) ;; CAREFUL-NEXT: ) @@ -146,13 +146,13 @@ ) ) - ;; ALWAYS: (func $call-undropped-trivial (type $4) (param $x i32) (result i32) + ;; ALWAYS: (func $call-undropped-trivial (type $3) (param $x i32) (result i32) ;; ALWAYS-NEXT: (call $work ;; ALWAYS-NEXT: (local.get $x) ;; ALWAYS-NEXT: (local.get $x) ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) - ;; CAREFUL: (func $call-undropped-trivial (type $4) (param $x i32) (result i32) + ;; CAREFUL: (func $call-undropped-trivial (type $2) (param $x i32) (result i32) ;; CAREFUL-NEXT: (call $work ;; CAREFUL-NEXT: (local.get $x) ;; CAREFUL-NEXT: (local.get $x) @@ -168,10 +168,10 @@ ) ;; ALWAYS: (func $call-undropped (type $i) (result i32) - ;; ALWAYS-NEXT: (call $work_13) + ;; ALWAYS-NEXT: (call $work_23) ;; ALWAYS-NEXT: ) ;; CAREFUL: (func $call-undropped (type $i) (result i32) - ;; CAREFUL-NEXT: (call $work_13) + ;; CAREFUL-NEXT: (call $work_23) ;; CAREFUL-NEXT: ) (func $call-undropped (result i32) ;; As above but now with constant params. We can monomorphize here - there @@ -183,24 +183,55 @@ ) ) + ;; ALWAYS: (func $no-params (type $i) (result i32) + ;; ALWAYS-NEXT: (i32.const 42) + ;; ALWAYS-NEXT: ) + ;; CAREFUL: (func $no-params (type $i) (result i32) + ;; CAREFUL-NEXT: (i32.const 42) + ;; CAREFUL-NEXT: ) (func $no-params (result i32) ;; A function that will be dropped, and has no params. (i32.const 42) ) + ;; ALWAYS: (func $call-no-params (type $i) (result i32) + ;; ALWAYS-NEXT: (call $no-params_24) + ;; ALWAYS-NEXT: (call $no-params) + ;; ALWAYS-NEXT: ) + ;; CAREFUL: (func $call-no-params (type $i) (result i32) + ;; CAREFUL-NEXT: (call $no-params_24) + ;; CAREFUL-NEXT: (call $no-params) + ;; CAREFUL-NEXT: ) (func $call-no-params (result i32) + ;; We can optimize the drop into the target. (drop (call $no-params) ) + ;; Without a drop, the call context is trivial and we do nothing. (call $no-params) ) + ;; ALWAYS: (func $call-no-params-return (type $i) (result i32) + ;; ALWAYS-NEXT: (return_call $work + ;; ALWAYS-NEXT: (i32.const 10) + ;; ALWAYS-NEXT: (i32.const 20) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: ) + ;; CAREFUL: (func $call-no-params-return (type $i) (result i32) + ;; CAREFUL-NEXT: (return_call $work + ;; CAREFUL-NEXT: (i32.const 10) + ;; CAREFUL-NEXT: (i32.const 20) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: ) (func $call-no-params-return (result i32) - ;; Return calls can be monomorphized too. - (return_call $import2) + ;; Return calls can be monomorphized too, but we have that as a TODO atm. + (return_call $work + (i32.const 10) + (i32.const 20) + ) ) - ;; ALWAYS: (func $call-import (type $0) + ;; ALWAYS: (func $call-import (type $1) ;; ALWAYS-NEXT: (drop ;; ALWAYS-NEXT: (call $import ;; ALWAYS-NEXT: (i32.const 3) @@ -208,7 +239,7 @@ ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) - ;; CAREFUL: (func $call-import (type $2) + ;; CAREFUL: (func $call-import (type $3) ;; CAREFUL-NEXT: (drop ;; CAREFUL-NEXT: (call $import ;; CAREFUL-NEXT: (i32.const 3) @@ -257,17 +288,17 @@ (local.get $x) (local.get $y) ) - (i32.add + (i32.div_s (local.get $x) (local.get $y) ) ) ) - ;; ALWAYS: (func $call-import-work (type $0) - ;; ALWAYS-NEXT: (call $import-work_14) + ;; ALWAYS: (func $call-import-work (type $1) + ;; ALWAYS-NEXT: (call $import-work_25) ;; ALWAYS-NEXT: ) - ;; CAREFUL: (func $call-import-work (type $2) + ;; CAREFUL: (func $call-import-work (type $3) ;; CAREFUL-NEXT: (drop ;; CAREFUL-NEXT: (call $import-work ;; CAREFUL-NEXT: (i32.const 3) @@ -288,81 +319,33 @@ ) ) - ;; ALWAYS: (func $many-returns (type $i) (result i32) + ;; ALWAYS: (func $return-normal (type $3) (param $x i32) (result i32) ;; ALWAYS-NEXT: (if - ;; ALWAYS-NEXT: (call $import - ;; ALWAYS-NEXT: (i32.const 1) - ;; ALWAYS-NEXT: (i32.const 2) - ;; ALWAYS-NEXT: ) - ;; ALWAYS-NEXT: (then - ;; ALWAYS-NEXT: (return - ;; ALWAYS-NEXT: (i32.const 3) - ;; ALWAYS-NEXT: ) - ;; ALWAYS-NEXT: ) - ;; ALWAYS-NEXT: (else - ;; ALWAYS-NEXT: (return_call $import - ;; ALWAYS-NEXT: (i32.const 4) - ;; ALWAYS-NEXT: (i32.const 5) - ;; ALWAYS-NEXT: ) - ;; ALWAYS-NEXT: ) - ;; ALWAYS-NEXT: ) - ;; ALWAYS-NEXT: (if - ;; ALWAYS-NEXT: (call $import - ;; ALWAYS-NEXT: (i32.const 6) - ;; ALWAYS-NEXT: (i32.const 7) - ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: (local.get $x) ;; ALWAYS-NEXT: (then - ;; ALWAYS-NEXT: (return_call_indirect $table (type $i) - ;; ALWAYS-NEXT: (i32.const 8) + ;; ALWAYS-NEXT: (drop + ;; ALWAYS-NEXT: (call $import2) ;; ALWAYS-NEXT: ) - ;; ALWAYS-NEXT: ) - ;; ALWAYS-NEXT: (else - ;; ALWAYS-NEXT: (return_call_ref $iii - ;; ALWAYS-NEXT: (i32.const 1) - ;; ALWAYS-NEXT: (i32.const 2) - ;; ALWAYS-NEXT: (ref.func $import) + ;; ALWAYS-NEXT: (return + ;; ALWAYS-NEXT: (i32.const 0) ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) - ;; ALWAYS-NEXT: (i32.const 4) + ;; ALWAYS-NEXT: (i32.const 1) ;; ALWAYS-NEXT: ) - ;; CAREFUL: (func $many-returns (type $i) (result i32) - ;; CAREFUL-NEXT: (if - ;; CAREFUL-NEXT: (call $import - ;; CAREFUL-NEXT: (i32.const 1) - ;; CAREFUL-NEXT: (i32.const 2) - ;; CAREFUL-NEXT: ) - ;; CAREFUL-NEXT: (then - ;; CAREFUL-NEXT: (return - ;; CAREFUL-NEXT: (i32.const 3) - ;; CAREFUL-NEXT: ) - ;; CAREFUL-NEXT: ) - ;; CAREFUL-NEXT: (else - ;; CAREFUL-NEXT: (return_call $import - ;; CAREFUL-NEXT: (i32.const 4) - ;; CAREFUL-NEXT: (i32.const 5) - ;; CAREFUL-NEXT: ) - ;; CAREFUL-NEXT: ) - ;; CAREFUL-NEXT: ) + ;; CAREFUL: (func $return-normal (type $2) (param $0 i32) (result i32) ;; CAREFUL-NEXT: (if - ;; CAREFUL-NEXT: (call $import - ;; CAREFUL-NEXT: (i32.const 6) - ;; CAREFUL-NEXT: (i32.const 7) - ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: (local.get $0) ;; CAREFUL-NEXT: (then - ;; CAREFUL-NEXT: (return_call_indirect $table (type $i) - ;; CAREFUL-NEXT: (i32.const 8) + ;; CAREFUL-NEXT: (drop + ;; CAREFUL-NEXT: (call $import2) ;; CAREFUL-NEXT: ) - ;; CAREFUL-NEXT: ) - ;; CAREFUL-NEXT: (else - ;; CAREFUL-NEXT: (return_call_ref $iii - ;; CAREFUL-NEXT: (i32.const 1) - ;; CAREFUL-NEXT: (i32.const 2) - ;; CAREFUL-NEXT: (ref.func $import) + ;; CAREFUL-NEXT: (return + ;; CAREFUL-NEXT: (i32.const 0) ;; CAREFUL-NEXT: ) ;; CAREFUL-NEXT: ) ;; CAREFUL-NEXT: ) - ;; CAREFUL-NEXT: (i32.const 4) + ;; CAREFUL-NEXT: (i32.const 1) ;; CAREFUL-NEXT: ) (func $return-normal (param $x i32) (result i32) ;; This function has a return, which needs to be handled in the @@ -382,6 +365,20 @@ (i32.const 1) ) + ;; ALWAYS: (func $call-return-normal (type $2) (param $x i32) + ;; ALWAYS-NEXT: (call $return-normal_26) + ;; ALWAYS-NEXT: (call $return-normal_27) + ;; ALWAYS-NEXT: (call $return-normal_28 + ;; ALWAYS-NEXT: (local.get $x) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: ) + ;; CAREFUL: (func $call-return-normal (type $1) (param $x i32) + ;; CAREFUL-NEXT: (call $return-normal_25) + ;; CAREFUL-NEXT: (call $return-normal_26) + ;; CAREFUL-NEXT: (call $return-normal_27 + ;; CAREFUL-NEXT: (local.get $x) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: ) (func $call-return-normal (param $x i32) ;; Call the above function with 0, 1, and an unknown value, to test the two ;; code paths there + the case of the input being unknown. @@ -402,6 +399,24 @@ ) ) + ;; ALWAYS: (func $return-call (type $3) (param $x i32) (result i32) + ;; ALWAYS-NEXT: (if + ;; ALWAYS-NEXT: (local.get $x) + ;; ALWAYS-NEXT: (then + ;; ALWAYS-NEXT: (return_call $import2) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: (i32.const 1) + ;; ALWAYS-NEXT: ) + ;; CAREFUL: (func $return-call (type $2) (param $0 i32) (result i32) + ;; CAREFUL-NEXT: (if + ;; CAREFUL-NEXT: (local.get $0) + ;; CAREFUL-NEXT: (then + ;; CAREFUL-NEXT: (return_call $import2) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: (i32.const 1) + ;; CAREFUL-NEXT: ) (func $return-call (param $x i32) (result i32) ;; As above, but now with a return_call. We do not monomorphize the drop ;; part, as if we included the drop we'd turn the call into a non-return @@ -415,6 +430,32 @@ (i32.const 1) ) + ;; ALWAYS: (func $call-return-call (type $2) (param $x i32) + ;; ALWAYS-NEXT: (drop + ;; ALWAYS-NEXT: (call $return-call_29) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: (drop + ;; ALWAYS-NEXT: (call $return-call_30) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: (drop + ;; ALWAYS-NEXT: (call $return-call + ;; ALWAYS-NEXT: (local.get $x) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: ) + ;; CAREFUL: (func $call-return-call (type $1) (param $x i32) + ;; CAREFUL-NEXT: (drop + ;; CAREFUL-NEXT: (call $return-call_28) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: (drop + ;; CAREFUL-NEXT: (call $return-call_29) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: (drop + ;; CAREFUL-NEXT: (call $return-call + ;; CAREFUL-NEXT: (local.get $x) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: ) (func $call-return-call (param $x i32) ;; As above, but due to the return call we won't monomorphize the drop. (drop @@ -434,6 +475,28 @@ ) ) + ;; ALWAYS: (func $return-call-indirect (type $3) (param $x i32) (result i32) + ;; ALWAYS-NEXT: (if + ;; ALWAYS-NEXT: (local.get $x) + ;; ALWAYS-NEXT: (then + ;; ALWAYS-NEXT: (return_call_indirect $table (type $i) + ;; ALWAYS-NEXT: (call $import2) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: (i32.const 1) + ;; ALWAYS-NEXT: ) + ;; CAREFUL: (func $return-call-indirect (type $2) (param $0 i32) (result i32) + ;; CAREFUL-NEXT: (if + ;; CAREFUL-NEXT: (local.get $0) + ;; CAREFUL-NEXT: (then + ;; CAREFUL-NEXT: (return_call_indirect $table (type $i) + ;; CAREFUL-NEXT: (call $import2) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: (i32.const 1) + ;; CAREFUL-NEXT: ) (func $return-call-indirect (param $x i32) (result i32) ;; As above, but now with a return_call_indirect. The outcome is similar. (if @@ -447,6 +510,32 @@ (i32.const 1) ) + ;; ALWAYS: (func $call-return-call-indirect (type $2) (param $x i32) + ;; ALWAYS-NEXT: (drop + ;; ALWAYS-NEXT: (call $return-call-indirect_31) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: (drop + ;; ALWAYS-NEXT: (call $return-call-indirect_32) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: (drop + ;; ALWAYS-NEXT: (call $return-call-indirect + ;; ALWAYS-NEXT: (local.get $x) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: ) + ;; CAREFUL: (func $call-return-call-indirect (type $1) (param $x i32) + ;; CAREFUL-NEXT: (drop + ;; CAREFUL-NEXT: (call $return-call-indirect_30) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: (drop + ;; CAREFUL-NEXT: (call $return-call-indirect_31) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: (drop + ;; CAREFUL-NEXT: (call $return-call-indirect + ;; CAREFUL-NEXT: (local.get $x) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: ) (func $call-return-call-indirect (param $x i32) (drop (call $return-call-indirect @@ -465,6 +554,26 @@ ) ) + ;; ALWAYS: (func $return-call-ref (type $3) (param $x i32) (result i32) + ;; ALWAYS-NEXT: (if + ;; ALWAYS-NEXT: (local.get $x) + ;; ALWAYS-NEXT: (then + ;; ALWAYS-NEXT: (return_call_ref $i + ;; ALWAYS-NEXT: (ref.func $import2) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: (i32.const 1) + ;; ALWAYS-NEXT: ) + ;; CAREFUL: (func $return-call-ref (type $2) (param $0 i32) (result i32) + ;; CAREFUL-NEXT: (if + ;; CAREFUL-NEXT: (local.get $0) + ;; CAREFUL-NEXT: (then + ;; CAREFUL-NEXT: (return_call $import2) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: (i32.const 1) + ;; CAREFUL-NEXT: ) (func $return-call-ref (param $x i32) (result i32) ;; As above, but now with a return_call_ref. The outcome is similar. (if @@ -478,6 +587,78 @@ (i32.const 1) ) + ;; ALWAYS: (func $call-return-call-ref (type $3) (param $x i32) (result i32) + ;; ALWAYS-NEXT: (drop + ;; ALWAYS-NEXT: (call $return-call-ref_33) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: (drop + ;; ALWAYS-NEXT: (call $return-call-ref_34) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: (drop + ;; ALWAYS-NEXT: (call $return-call-ref + ;; ALWAYS-NEXT: (local.get $x) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: (if + ;; ALWAYS-NEXT: (local.get $x) + ;; ALWAYS-NEXT: (then + ;; ALWAYS-NEXT: (return_call $import2) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: (if + ;; ALWAYS-NEXT: (local.get $x) + ;; ALWAYS-NEXT: (then + ;; ALWAYS-NEXT: (return_call_indirect $table (type $i) + ;; ALWAYS-NEXT: (i32.const 7) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: (if + ;; ALWAYS-NEXT: (local.get $x) + ;; ALWAYS-NEXT: (then + ;; ALWAYS-NEXT: (return_call_ref $i + ;; ALWAYS-NEXT: (ref.func $import2) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: (unreachable) + ;; ALWAYS-NEXT: ) + ;; CAREFUL: (func $call-return-call-ref (type $2) (param $x i32) (result i32) + ;; CAREFUL-NEXT: (drop + ;; CAREFUL-NEXT: (call $return-call-ref_32) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: (drop + ;; CAREFUL-NEXT: (call $return-call-ref_33) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: (drop + ;; CAREFUL-NEXT: (call $return-call-ref + ;; CAREFUL-NEXT: (local.get $x) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: (if + ;; CAREFUL-NEXT: (local.get $x) + ;; CAREFUL-NEXT: (then + ;; CAREFUL-NEXT: (return_call $import2) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: (if + ;; CAREFUL-NEXT: (local.get $x) + ;; CAREFUL-NEXT: (then + ;; CAREFUL-NEXT: (return_call_indirect $table (type $i) + ;; CAREFUL-NEXT: (i32.const 7) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: (if + ;; CAREFUL-NEXT: (local.get $x) + ;; CAREFUL-NEXT: (then + ;; CAREFUL-NEXT: (return_call_ref $i + ;; CAREFUL-NEXT: (ref.func $import2) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: (unreachable) + ;; CAREFUL-NEXT: ) (func $call-return-call-ref (param $x i32) (result i32) (drop (call $return-call-ref @@ -523,7 +704,7 @@ (unreachable) ) ) -;; ALWAYS: (func $work_10 (type $0) +;; ALWAYS: (func $work_20 (type $1) ;; ALWAYS-NEXT: (local $x i32) ;; ALWAYS-NEXT: (local $y i32) ;; ALWAYS-NEXT: (drop @@ -539,7 +720,7 @@ ;; ALWAYS-NEXT: (local.get $x) ;; ALWAYS-NEXT: (local.get $y) ;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: (i32.add +;; ALWAYS-NEXT: (i32.div_s ;; ALWAYS-NEXT: (local.get $x) ;; ALWAYS-NEXT: (local.get $y) ;; ALWAYS-NEXT: ) @@ -548,7 +729,7 @@ ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) -;; ALWAYS: (func $work_11 (type $3) (param $0 i32) +;; ALWAYS: (func $work_21 (type $2) (param $0 i32) ;; ALWAYS-NEXT: (local $x i32) ;; ALWAYS-NEXT: (local $y i32) ;; ALWAYS-NEXT: (drop @@ -564,7 +745,7 @@ ;; ALWAYS-NEXT: (local.get $x) ;; ALWAYS-NEXT: (local.get $y) ;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: (i32.add +;; ALWAYS-NEXT: (i32.div_s ;; ALWAYS-NEXT: (local.get $x) ;; ALWAYS-NEXT: (local.get $y) ;; ALWAYS-NEXT: ) @@ -573,7 +754,7 @@ ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) -;; ALWAYS: (func $work_12 (type $5) (param $0 i32) (param $1 i32) +;; ALWAYS: (func $work_22 (type $5) (param $0 i32) (param $1 i32) ;; ALWAYS-NEXT: (local $x i32) ;; ALWAYS-NEXT: (local $y i32) ;; ALWAYS-NEXT: (drop @@ -589,7 +770,7 @@ ;; ALWAYS-NEXT: (local.get $x) ;; ALWAYS-NEXT: (local.get $y) ;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: (i32.add +;; ALWAYS-NEXT: (i32.div_s ;; ALWAYS-NEXT: (local.get $x) ;; ALWAYS-NEXT: (local.get $y) ;; ALWAYS-NEXT: ) @@ -598,7 +779,7 @@ ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) -;; ALWAYS: (func $work_13 (type $i) (result i32) +;; ALWAYS: (func $work_23 (type $i) (result i32) ;; ALWAYS-NEXT: (local $x i32) ;; ALWAYS-NEXT: (local $y i32) ;; ALWAYS-NEXT: (local.set $x @@ -612,14 +793,20 @@ ;; ALWAYS-NEXT: (local.get $x) ;; ALWAYS-NEXT: (local.get $y) ;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: (i32.add +;; ALWAYS-NEXT: (i32.div_s ;; ALWAYS-NEXT: (local.get $x) ;; ALWAYS-NEXT: (local.get $y) ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) -;; ALWAYS: (func $import-work_14 (type $0) +;; ALWAYS: (func $no-params_24 (type $1) +;; ALWAYS-NEXT: (drop +;; ALWAYS-NEXT: (i32.const 42) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) + +;; ALWAYS: (func $import-work_25 (type $1) ;; ALWAYS-NEXT: (local $x i32) ;; ALWAYS-NEXT: (local $y i32) ;; ALWAYS-NEXT: (drop @@ -644,18 +831,272 @@ ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) -;; CAREFUL: (func $work_10 (type $2) +;; ALWAYS: (func $return-normal_26 (type $1) +;; ALWAYS-NEXT: (local $x i32) +;; ALWAYS-NEXT: (drop +;; ALWAYS-NEXT: (block (result i32) +;; ALWAYS-NEXT: (local.set $x +;; ALWAYS-NEXT: (i32.const 0) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (block (result i32) +;; ALWAYS-NEXT: (if +;; ALWAYS-NEXT: (local.get $x) +;; ALWAYS-NEXT: (then +;; ALWAYS-NEXT: (drop +;; ALWAYS-NEXT: (call $import2) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (block +;; ALWAYS-NEXT: (drop +;; ALWAYS-NEXT: (i32.const 0) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (return) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (i32.const 1) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) + +;; ALWAYS: (func $return-normal_27 (type $1) +;; ALWAYS-NEXT: (local $x i32) +;; ALWAYS-NEXT: (drop +;; ALWAYS-NEXT: (block (result i32) +;; ALWAYS-NEXT: (local.set $x +;; ALWAYS-NEXT: (i32.const 1) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (block (result i32) +;; ALWAYS-NEXT: (if +;; ALWAYS-NEXT: (local.get $x) +;; ALWAYS-NEXT: (then +;; ALWAYS-NEXT: (drop +;; ALWAYS-NEXT: (call $import2) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (block +;; ALWAYS-NEXT: (drop +;; ALWAYS-NEXT: (i32.const 0) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (return) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (i32.const 1) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) + +;; ALWAYS: (func $return-normal_28 (type $2) (param $0 i32) +;; ALWAYS-NEXT: (local $x i32) +;; ALWAYS-NEXT: (drop +;; ALWAYS-NEXT: (block (result i32) +;; ALWAYS-NEXT: (local.set $x +;; ALWAYS-NEXT: (local.get $0) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (block (result i32) +;; ALWAYS-NEXT: (if +;; ALWAYS-NEXT: (local.get $x) +;; ALWAYS-NEXT: (then +;; ALWAYS-NEXT: (drop +;; ALWAYS-NEXT: (call $import2) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (block +;; ALWAYS-NEXT: (drop +;; ALWAYS-NEXT: (i32.const 0) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (return) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (i32.const 1) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) + +;; ALWAYS: (func $return-call_29 (type $i) (result i32) +;; ALWAYS-NEXT: (local $x i32) +;; ALWAYS-NEXT: (local.set $x +;; ALWAYS-NEXT: (i32.const 0) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (block (result i32) +;; ALWAYS-NEXT: (if +;; ALWAYS-NEXT: (local.get $x) +;; ALWAYS-NEXT: (then +;; ALWAYS-NEXT: (return_call $import2) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (i32.const 1) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) + +;; ALWAYS: (func $return-call_30 (type $i) (result i32) +;; ALWAYS-NEXT: (local $x i32) +;; ALWAYS-NEXT: (local.set $x +;; ALWAYS-NEXT: (i32.const 1) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (block (result i32) +;; ALWAYS-NEXT: (if +;; ALWAYS-NEXT: (local.get $x) +;; ALWAYS-NEXT: (then +;; ALWAYS-NEXT: (return_call $import2) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (i32.const 1) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) + +;; ALWAYS: (func $return-call-indirect_31 (type $i) (result i32) +;; ALWAYS-NEXT: (local $x i32) +;; ALWAYS-NEXT: (local.set $x +;; ALWAYS-NEXT: (i32.const 0) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (block (result i32) +;; ALWAYS-NEXT: (if +;; ALWAYS-NEXT: (local.get $x) +;; ALWAYS-NEXT: (then +;; ALWAYS-NEXT: (return_call_indirect $table (type $i) +;; ALWAYS-NEXT: (call $import2) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (i32.const 1) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) + +;; ALWAYS: (func $return-call-indirect_32 (type $i) (result i32) +;; ALWAYS-NEXT: (local $x i32) +;; ALWAYS-NEXT: (local.set $x +;; ALWAYS-NEXT: (i32.const 1) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (block (result i32) +;; ALWAYS-NEXT: (if +;; ALWAYS-NEXT: (local.get $x) +;; ALWAYS-NEXT: (then +;; ALWAYS-NEXT: (return_call_indirect $table (type $i) +;; ALWAYS-NEXT: (call $import2) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (i32.const 1) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) + +;; ALWAYS: (func $return-call-ref_33 (type $i) (result i32) +;; ALWAYS-NEXT: (local $x i32) +;; ALWAYS-NEXT: (local.set $x +;; ALWAYS-NEXT: (i32.const 0) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (block (result i32) +;; ALWAYS-NEXT: (if +;; ALWAYS-NEXT: (local.get $x) +;; ALWAYS-NEXT: (then +;; ALWAYS-NEXT: (return_call_ref $i +;; ALWAYS-NEXT: (ref.func $import2) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (i32.const 1) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) + +;; ALWAYS: (func $return-call-ref_34 (type $i) (result i32) +;; ALWAYS-NEXT: (local $x i32) +;; ALWAYS-NEXT: (local.set $x +;; ALWAYS-NEXT: (i32.const 1) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (block (result i32) +;; ALWAYS-NEXT: (if +;; ALWAYS-NEXT: (local.get $x) +;; ALWAYS-NEXT: (then +;; ALWAYS-NEXT: (return_call_ref $i +;; ALWAYS-NEXT: (ref.func $import2) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (i32.const 1) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) + +;; CAREFUL: (func $work_20 (type $3) ;; CAREFUL-NEXT: (nop) ;; CAREFUL-NEXT: ) -;; CAREFUL: (func $work_11 (type $3) (param $0 i32) +;; CAREFUL: (func $work_21 (type $1) (param $0 i32) +;; CAREFUL-NEXT: (drop +;; CAREFUL-NEXT: (i32.div_s +;; CAREFUL-NEXT: (i32.const 3) +;; CAREFUL-NEXT: (local.get $0) +;; CAREFUL-NEXT: ) +;; CAREFUL-NEXT: ) +;; CAREFUL-NEXT: ) + +;; CAREFUL: (func $work_22 (type $5) (param $0 i32) (param $1 i32) +;; CAREFUL-NEXT: (drop +;; CAREFUL-NEXT: (i32.div_s +;; CAREFUL-NEXT: (local.get $0) +;; CAREFUL-NEXT: (local.get $1) +;; CAREFUL-NEXT: ) +;; CAREFUL-NEXT: ) +;; CAREFUL-NEXT: ) + +;; CAREFUL: (func $work_23 (type $i) (result i32) +;; CAREFUL-NEXT: (i32.const 0) +;; CAREFUL-NEXT: ) + +;; CAREFUL: (func $no-params_24 (type $3) ;; CAREFUL-NEXT: (nop) ;; CAREFUL-NEXT: ) -;; CAREFUL: (func $work_12 (type $5) (param $0 i32) (param $1 i32) +;; CAREFUL: (func $return-normal_25 (type $3) ;; CAREFUL-NEXT: (nop) ;; CAREFUL-NEXT: ) -;; CAREFUL: (func $work_13 (type $i) (result i32) -;; CAREFUL-NEXT: (i32.const 49) +;; CAREFUL: (func $return-normal_26 (type $3) +;; CAREFUL-NEXT: (drop +;; CAREFUL-NEXT: (block +;; CAREFUL-NEXT: (drop +;; CAREFUL-NEXT: (call $import2) +;; CAREFUL-NEXT: ) +;; CAREFUL-NEXT: (return) +;; CAREFUL-NEXT: ) +;; CAREFUL-NEXT: ) +;; CAREFUL-NEXT: ) + +;; CAREFUL: (func $return-normal_27 (type $1) (param $0 i32) +;; CAREFUL-NEXT: (if +;; CAREFUL-NEXT: (local.get $0) +;; CAREFUL-NEXT: (then +;; CAREFUL-NEXT: (drop +;; CAREFUL-NEXT: (call $import2) +;; CAREFUL-NEXT: ) +;; CAREFUL-NEXT: ) +;; CAREFUL-NEXT: ) +;; CAREFUL-NEXT: ) + +;; CAREFUL: (func $return-call_28 (type $i) (result i32) +;; CAREFUL-NEXT: (i32.const 1) +;; CAREFUL-NEXT: ) + +;; CAREFUL: (func $return-call_29 (type $i) (result i32) +;; CAREFUL-NEXT: (return_call $import2) +;; CAREFUL-NEXT: ) + +;; CAREFUL: (func $return-call-indirect_30 (type $i) (result i32) +;; CAREFUL-NEXT: (i32.const 1) +;; CAREFUL-NEXT: ) + +;; CAREFUL: (func $return-call-indirect_31 (type $i) (result i32) +;; CAREFUL-NEXT: (return_call_indirect $table (type $i) +;; CAREFUL-NEXT: (call $import2) +;; CAREFUL-NEXT: ) +;; CAREFUL-NEXT: ) + +;; CAREFUL: (func $return-call-ref_32 (type $i) (result i32) +;; CAREFUL-NEXT: (i32.const 1) +;; CAREFUL-NEXT: ) + +;; CAREFUL: (func $return-call-ref_33 (type $i) (result i32) +;; CAREFUL-NEXT: (return_call $import2) ;; CAREFUL-NEXT: ) From 4efae3dfc73717af524e3f67e493d263a335f020 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 12 Jul 2024 12:10:11 -0700 Subject: [PATCH 31/35] test --- test/lit/passes/monomorphize-drop.wast | 115 +++++++++++++------------ 1 file changed, 61 insertions(+), 54 deletions(-) diff --git a/test/lit/passes/monomorphize-drop.wast b/test/lit/passes/monomorphize-drop.wast index 6a05b24263b..08c62fe1a6f 100644 --- a/test/lit/passes/monomorphize-drop.wast +++ b/test/lit/passes/monomorphize-drop.wast @@ -22,11 +22,11 @@ ;; ALWAYS: (type $3 (func (param i32) (result i32))) ;; ALWAYS: (type $iii (func (param i32 i32) (result i32))) - ;; CAREFUL: (type $1 (func (param i32))) + ;; CAREFUL: (type $1 (func)) - ;; CAREFUL: (type $2 (func (param i32) (result i32))) + ;; CAREFUL: (type $2 (func (param i32))) - ;; CAREFUL: (type $3 (func)) + ;; CAREFUL: (type $3 (func (param i32) (result i32))) ;; CAREFUL: (type $iii (func (param i32 i32) (result i32))) (type $iii (func (param i32 i32) (result i32))) @@ -101,7 +101,7 @@ ;; ALWAYS-NEXT: (local.get $x) ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) - ;; CAREFUL: (func $calls (type $1) (param $x i32) + ;; CAREFUL: (func $calls (type $2) (param $x i32) ;; CAREFUL-NEXT: (call $work_20) ;; CAREFUL-NEXT: (call $work_20) ;; CAREFUL-NEXT: (call $work_21 @@ -152,7 +152,7 @@ ;; ALWAYS-NEXT: (local.get $x) ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) - ;; CAREFUL: (func $call-undropped-trivial (type $2) (param $x i32) (result i32) + ;; CAREFUL: (func $call-undropped-trivial (type $3) (param $x i32) (result i32) ;; CAREFUL-NEXT: (call $work ;; CAREFUL-NEXT: (local.get $x) ;; CAREFUL-NEXT: (local.get $x) @@ -239,7 +239,7 @@ ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) - ;; CAREFUL: (func $call-import (type $3) + ;; CAREFUL: (func $call-import (type $1) ;; CAREFUL-NEXT: (drop ;; CAREFUL-NEXT: (call $import ;; CAREFUL-NEXT: (i32.const 3) @@ -263,7 +263,7 @@ ;; ALWAYS-NEXT: (local.get $x) ;; ALWAYS-NEXT: (local.get $y) ;; ALWAYS-NEXT: ) - ;; ALWAYS-NEXT: (i32.add + ;; ALWAYS-NEXT: (i32.div_s ;; ALWAYS-NEXT: (local.get $x) ;; ALWAYS-NEXT: (local.get $y) ;; ALWAYS-NEXT: ) @@ -275,7 +275,7 @@ ;; CAREFUL-NEXT: (local.get $0) ;; CAREFUL-NEXT: (local.get $1) ;; CAREFUL-NEXT: ) - ;; CAREFUL-NEXT: (i32.add + ;; CAREFUL-NEXT: (i32.div_s ;; CAREFUL-NEXT: (local.get $0) ;; CAREFUL-NEXT: (local.get $1) ;; CAREFUL-NEXT: ) @@ -298,19 +298,11 @@ ;; ALWAYS: (func $call-import-work (type $1) ;; ALWAYS-NEXT: (call $import-work_25) ;; ALWAYS-NEXT: ) - ;; CAREFUL: (func $call-import-work (type $3) - ;; CAREFUL-NEXT: (drop - ;; CAREFUL-NEXT: (call $import-work - ;; CAREFUL-NEXT: (i32.const 3) - ;; CAREFUL-NEXT: (i32.const 4) - ;; CAREFUL-NEXT: ) - ;; CAREFUL-NEXT: ) + ;; CAREFUL: (func $call-import-work (type $1) + ;; CAREFUL-NEXT: (call $import-work_25) ;; CAREFUL-NEXT: ) (func $call-import-work - ;; This is monomorphized in ALWAYS (as the drop means the call context is - ;; not trivial), but not in CAREFUL mode (as there is no significant benefit - ;; from optimizations on the monomorphized function - the import is opaque - ;; work we cannot do anything with, even if we see it is handed consts). + ;; This is monomorphized with the drop. (drop (call $import-work (i32.const 3) @@ -333,7 +325,7 @@ ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: (i32.const 1) ;; ALWAYS-NEXT: ) - ;; CAREFUL: (func $return-normal (type $2) (param $0 i32) (result i32) + ;; CAREFUL: (func $return-normal (type $3) (param $0 i32) (result i32) ;; CAREFUL-NEXT: (if ;; CAREFUL-NEXT: (local.get $0) ;; CAREFUL-NEXT: (then @@ -372,16 +364,17 @@ ;; ALWAYS-NEXT: (local.get $x) ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) - ;; CAREFUL: (func $call-return-normal (type $1) (param $x i32) - ;; CAREFUL-NEXT: (call $return-normal_25) + ;; CAREFUL: (func $call-return-normal (type $2) (param $x i32) ;; CAREFUL-NEXT: (call $return-normal_26) - ;; CAREFUL-NEXT: (call $return-normal_27 + ;; CAREFUL-NEXT: (call $return-normal_27) + ;; CAREFUL-NEXT: (call $return-normal_28 ;; CAREFUL-NEXT: (local.get $x) ;; CAREFUL-NEXT: ) ;; CAREFUL-NEXT: ) (func $call-return-normal (param $x i32) ;; Call the above function with 0, 1, and an unknown value, to test the two - ;; code paths there + the case of the input being unknown. + ;; code paths there + the case of the input being unknown. We monomorphize + ;; them all (differently). (drop (call $return-normal (i32.const 0) @@ -408,7 +401,7 @@ ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: (i32.const 1) ;; ALWAYS-NEXT: ) - ;; CAREFUL: (func $return-call (type $2) (param $0 i32) (result i32) + ;; CAREFUL: (func $return-call (type $3) (param $0 i32) (result i32) ;; CAREFUL-NEXT: (if ;; CAREFUL-NEXT: (local.get $0) ;; CAREFUL-NEXT: (then @@ -443,12 +436,12 @@ ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) - ;; CAREFUL: (func $call-return-call (type $1) (param $x i32) + ;; CAREFUL: (func $call-return-call (type $2) (param $x i32) ;; CAREFUL-NEXT: (drop - ;; CAREFUL-NEXT: (call $return-call_28) + ;; CAREFUL-NEXT: (call $return-call_29) ;; CAREFUL-NEXT: ) ;; CAREFUL-NEXT: (drop - ;; CAREFUL-NEXT: (call $return-call_29) + ;; CAREFUL-NEXT: (call $return-call_30) ;; CAREFUL-NEXT: ) ;; CAREFUL-NEXT: (drop ;; CAREFUL-NEXT: (call $return-call @@ -457,7 +450,9 @@ ;; CAREFUL-NEXT: ) ;; CAREFUL-NEXT: ) (func $call-return-call (param $x i32) - ;; As above, but due to the return call we won't monomorphize the drop. + ;; As above, but due to the return call we won't monomorphize the drop. As + ;; a result we monomorphize the first two, leaving drops here, and do + ;; nothing for the last (as the call context is trivial). (drop (call $return-call (i32.const 0) @@ -486,7 +481,7 @@ ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: (i32.const 1) ;; ALWAYS-NEXT: ) - ;; CAREFUL: (func $return-call-indirect (type $2) (param $0 i32) (result i32) + ;; CAREFUL: (func $return-call-indirect (type $3) (param $0 i32) (result i32) ;; CAREFUL-NEXT: (if ;; CAREFUL-NEXT: (local.get $0) ;; CAREFUL-NEXT: (then @@ -498,7 +493,8 @@ ;; CAREFUL-NEXT: (i32.const 1) ;; CAREFUL-NEXT: ) (func $return-call-indirect (param $x i32) (result i32) - ;; As above, but now with a return_call_indirect. The outcome is similar. + ;; As above, but now with a return_call_indirect. The outcome below is + ;; similar. (if (local.get $x) (then @@ -523,12 +519,12 @@ ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) - ;; CAREFUL: (func $call-return-call-indirect (type $1) (param $x i32) + ;; CAREFUL: (func $call-return-call-indirect (type $2) (param $x i32) ;; CAREFUL-NEXT: (drop - ;; CAREFUL-NEXT: (call $return-call-indirect_30) + ;; CAREFUL-NEXT: (call $return-call-indirect_31) ;; CAREFUL-NEXT: ) ;; CAREFUL-NEXT: (drop - ;; CAREFUL-NEXT: (call $return-call-indirect_31) + ;; CAREFUL-NEXT: (call $return-call-indirect_32) ;; CAREFUL-NEXT: ) ;; CAREFUL-NEXT: (drop ;; CAREFUL-NEXT: (call $return-call-indirect @@ -565,7 +561,7 @@ ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: (i32.const 1) ;; ALWAYS-NEXT: ) - ;; CAREFUL: (func $return-call-ref (type $2) (param $0 i32) (result i32) + ;; CAREFUL: (func $return-call-ref (type $3) (param $0 i32) (result i32) ;; CAREFUL-NEXT: (if ;; CAREFUL-NEXT: (local.get $0) ;; CAREFUL-NEXT: (then @@ -575,7 +571,7 @@ ;; CAREFUL-NEXT: (i32.const 1) ;; CAREFUL-NEXT: ) (func $return-call-ref (param $x i32) (result i32) - ;; As above, but now with a return_call_ref. The outcome is similar. + ;; As above, but now with a return_call_ref. The outcome below is similar. (if (local.get $x) (then @@ -623,12 +619,12 @@ ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: (unreachable) ;; ALWAYS-NEXT: ) - ;; CAREFUL: (func $call-return-call-ref (type $2) (param $x i32) (result i32) + ;; CAREFUL: (func $call-return-call-ref (type $3) (param $x i32) (result i32) ;; CAREFUL-NEXT: (drop - ;; CAREFUL-NEXT: (call $return-call-ref_32) + ;; CAREFUL-NEXT: (call $return-call-ref_33) ;; CAREFUL-NEXT: ) ;; CAREFUL-NEXT: (drop - ;; CAREFUL-NEXT: (call $return-call-ref_33) + ;; CAREFUL-NEXT: (call $return-call-ref_34) ;; CAREFUL-NEXT: ) ;; CAREFUL-NEXT: (drop ;; CAREFUL-NEXT: (call $return-call-ref @@ -660,6 +656,8 @@ ;; CAREFUL-NEXT: (unreachable) ;; CAREFUL-NEXT: ) (func $call-return-call-ref (param $x i32) (result i32) + ;; As before, a set of three calls (with similar outcomes as before: the + ;; first two are monomorphized without the drop; the last is unchanged). (drop (call $return-call-ref (i32.const 0) @@ -677,8 +675,8 @@ ) ;; Also add some return calls here, to show that it is fine for the caller - ;; to have them: we can still monomorphize the previous calls (without their - ;; drops). + ;; to have them: we can still monomorphize some of the previous calls + ;; (without their drops). (if (local.get $x) (then @@ -822,7 +820,7 @@ ;; ALWAYS-NEXT: (local.get $x) ;; ALWAYS-NEXT: (local.get $y) ;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: (i32.add +;; ALWAYS-NEXT: (i32.div_s ;; ALWAYS-NEXT: (local.get $x) ;; ALWAYS-NEXT: (local.get $y) ;; ALWAYS-NEXT: ) @@ -1019,11 +1017,11 @@ ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) -;; CAREFUL: (func $work_20 (type $3) +;; CAREFUL: (func $work_20 (type $1) ;; CAREFUL-NEXT: (nop) ;; CAREFUL-NEXT: ) -;; CAREFUL: (func $work_21 (type $1) (param $0 i32) +;; CAREFUL: (func $work_21 (type $2) (param $0 i32) ;; CAREFUL-NEXT: (drop ;; CAREFUL-NEXT: (i32.div_s ;; CAREFUL-NEXT: (i32.const 3) @@ -1045,15 +1043,24 @@ ;; CAREFUL-NEXT: (i32.const 0) ;; CAREFUL-NEXT: ) -;; CAREFUL: (func $no-params_24 (type $3) +;; CAREFUL: (func $no-params_24 (type $1) ;; CAREFUL-NEXT: (nop) ;; CAREFUL-NEXT: ) -;; CAREFUL: (func $return-normal_25 (type $3) +;; CAREFUL: (func $import-work_25 (type $1) +;; CAREFUL-NEXT: (drop +;; CAREFUL-NEXT: (call $import +;; CAREFUL-NEXT: (i32.const 7) +;; CAREFUL-NEXT: (i32.const 0) +;; CAREFUL-NEXT: ) +;; CAREFUL-NEXT: ) +;; CAREFUL-NEXT: ) + +;; CAREFUL: (func $return-normal_26 (type $1) ;; CAREFUL-NEXT: (nop) ;; CAREFUL-NEXT: ) -;; CAREFUL: (func $return-normal_26 (type $3) +;; CAREFUL: (func $return-normal_27 (type $1) ;; CAREFUL-NEXT: (drop ;; CAREFUL-NEXT: (block ;; CAREFUL-NEXT: (drop @@ -1064,7 +1071,7 @@ ;; CAREFUL-NEXT: ) ;; CAREFUL-NEXT: ) -;; CAREFUL: (func $return-normal_27 (type $1) (param $0 i32) +;; CAREFUL: (func $return-normal_28 (type $2) (param $0 i32) ;; CAREFUL-NEXT: (if ;; CAREFUL-NEXT: (local.get $0) ;; CAREFUL-NEXT: (then @@ -1075,28 +1082,28 @@ ;; CAREFUL-NEXT: ) ;; CAREFUL-NEXT: ) -;; CAREFUL: (func $return-call_28 (type $i) (result i32) +;; CAREFUL: (func $return-call_29 (type $i) (result i32) ;; CAREFUL-NEXT: (i32.const 1) ;; CAREFUL-NEXT: ) -;; CAREFUL: (func $return-call_29 (type $i) (result i32) +;; CAREFUL: (func $return-call_30 (type $i) (result i32) ;; CAREFUL-NEXT: (return_call $import2) ;; CAREFUL-NEXT: ) -;; CAREFUL: (func $return-call-indirect_30 (type $i) (result i32) +;; CAREFUL: (func $return-call-indirect_31 (type $i) (result i32) ;; CAREFUL-NEXT: (i32.const 1) ;; CAREFUL-NEXT: ) -;; CAREFUL: (func $return-call-indirect_31 (type $i) (result i32) +;; CAREFUL: (func $return-call-indirect_32 (type $i) (result i32) ;; CAREFUL-NEXT: (return_call_indirect $table (type $i) ;; CAREFUL-NEXT: (call $import2) ;; CAREFUL-NEXT: ) ;; CAREFUL-NEXT: ) -;; CAREFUL: (func $return-call-ref_32 (type $i) (result i32) +;; CAREFUL: (func $return-call-ref_33 (type $i) (result i32) ;; CAREFUL-NEXT: (i32.const 1) ;; CAREFUL-NEXT: ) -;; CAREFUL: (func $return-call-ref_33 (type $i) (result i32) +;; CAREFUL: (func $return-call-ref_34 (type $i) (result i32) ;; CAREFUL-NEXT: (return_call $import2) ;; CAREFUL-NEXT: ) From b8b5fa739654601a48900e8564b2a7c2e2baa98e Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 12 Jul 2024 12:20:28 -0700 Subject: [PATCH 32/35] Avoid a libc++ compiler error --- src/ir/return-utils.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/ir/return-utils.cpp b/src/ir/return-utils.cpp index 7de1122dcaa..dd2b68793fa 100644 --- a/src/ir/return-utils.cpp +++ b/src/ir/return-utils.cpp @@ -57,7 +57,7 @@ void removeReturns(Function* func, Module& wasm) { } std::unordered_map findReturnCallers(Module& wasm) { - ModuleUtils::ParallelFunctionAnalysis + ModuleUtils::ParallelFunctionAnalysis analysis(wasm, [&](Function* func, bool& hasReturnCall) { if (func->imported()) { return; @@ -86,7 +86,14 @@ std::unordered_map findReturnCallers(Module& wasm) { finder.walk(func->body); hasReturnCall = finder.hasReturnCall; }); - return std::move(analysis.map); + + // Convert to an unordered map for fast lookups. + std::unordered_map ret; + ret.reserve(analysis.map.size()); + for (auto& [k, v] : analysis.map) { + ret[k] = v; + } + return ret; } } // namespace wasm::ReturnUtils From 916e73f5452c7808f9e741ceb5aa6b542809bfe1 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 12 Jul 2024 12:27:34 -0700 Subject: [PATCH 33/35] format --- src/ir/return-utils.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ir/return-utils.cpp b/src/ir/return-utils.cpp index dd2b68793fa..17484191659 100644 --- a/src/ir/return-utils.cpp +++ b/src/ir/return-utils.cpp @@ -57,8 +57,8 @@ void removeReturns(Function* func, Module& wasm) { } std::unordered_map findReturnCallers(Module& wasm) { - ModuleUtils::ParallelFunctionAnalysis - analysis(wasm, [&](Function* func, bool& hasReturnCall) { + ModuleUtils::ParallelFunctionAnalysis analysis( + wasm, [&](Function* func, bool& hasReturnCall) { if (func->imported()) { return; } From 6a0cbac46f4171ddca23961168f24ab44d491b00 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 12 Jul 2024 12:28:10 -0700 Subject: [PATCH 34/35] todo --- src/ir/return-utils.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ir/return-utils.cpp b/src/ir/return-utils.cpp index 17484191659..20b3a194b13 100644 --- a/src/ir/return-utils.cpp +++ b/src/ir/return-utils.cpp @@ -87,7 +87,7 @@ std::unordered_map findReturnCallers(Module& wasm) { hasReturnCall = finder.hasReturnCall; }); - // Convert to an unordered map for fast lookups. + // Convert to an unordered map for fast lookups. TODO: Avoid a copy here. std::unordered_map ret; ret.reserve(analysis.map.size()); for (auto& [k, v] : analysis.map) { From 339c96ce59af0ed4636f39ed5d3074782a5dde9c Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 12 Jul 2024 15:45:06 -0700 Subject: [PATCH 35/35] modularize test --- test/lit/passes/monomorphize-drop.wast | 1120 +++++++++++++----------- 1 file changed, 601 insertions(+), 519 deletions(-) diff --git a/test/lit/passes/monomorphize-drop.wast b/test/lit/passes/monomorphize-drop.wast index 08c62fe1a6f..63923f76841 100644 --- a/test/lit/passes/monomorphize-drop.wast +++ b/test/lit/passes/monomorphize-drop.wast @@ -11,45 +11,19 @@ ;; Test that dropped functions are monomorphized, and the drop is reverse- ;; inlined into the called function, enabling more optimizations. - ;; ALWAYS: (type $i (func (result i32))) - ;; CAREFUL: (type $i (func (result i32))) - (type $i (func (result i32))) + ;; ALWAYS: (type $0 (func (result i32))) - ;; ALWAYS: (type $1 (func)) + ;; ALWAYS: (type $1 (func (param i32))) - ;; ALWAYS: (type $2 (func (param i32))) + ;; ALWAYS: (type $2 (func (param i32 i32) (result i32))) ;; ALWAYS: (type $3 (func (param i32) (result i32))) - ;; ALWAYS: (type $iii (func (param i32 i32) (result i32))) - ;; CAREFUL: (type $1 (func)) - - ;; CAREFUL: (type $2 (func (param i32))) - - ;; CAREFUL: (type $3 (func (param i32) (result i32))) - - ;; CAREFUL: (type $iii (func (param i32 i32) (result i32))) - (type $iii (func (param i32 i32) (result i32))) + ;; ALWAYS: (type $4 (func)) ;; ALWAYS: (type $5 (func (param i32 i32))) - ;; ALWAYS: (import "a" "b" (func $import (type $iii) (param i32 i32) (result i32))) - ;; CAREFUL: (type $5 (func (param i32 i32))) - - ;; CAREFUL: (import "a" "b" (func $import (type $iii) (param i32 i32) (result i32))) - (import "a" "b" (func $import (param i32 i32) (result i32))) - - ;; ALWAYS: (import "a" "c" (func $import2 (type $i) (result i32))) - ;; CAREFUL: (import "a" "c" (func $import2 (type $i) (result i32))) - (import "a" "c" (func $import2 (result i32))) - - ;; ALWAYS: (table $table 10 10 funcref) - ;; CAREFUL: (table $table 10 10 funcref) - (table $table 10 10 funcref) - - ;; ALWAYS: (elem declare func $import2) - - ;; ALWAYS: (func $work (type $iii) (param $x i32) (param $y i32) (result i32) + ;; ALWAYS: (func $work (type $2) (param $x i32) (param $y i32) (result i32) ;; ALWAYS-NEXT: (i32.mul ;; ALWAYS-NEXT: (i32.xor ;; ALWAYS-NEXT: (local.get $x) @@ -61,9 +35,19 @@ ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) - ;; CAREFUL: (elem declare func $import2) + ;; CAREFUL: (type $0 (func (result i32))) + + ;; CAREFUL: (type $1 (func (param i32))) + + ;; CAREFUL: (type $2 (func (param i32 i32) (result i32))) + + ;; CAREFUL: (type $3 (func (param i32) (result i32))) + + ;; CAREFUL: (type $4 (func)) + + ;; CAREFUL: (type $5 (func (param i32 i32))) - ;; CAREFUL: (func $work (type $iii) (param $0 i32) (param $1 i32) (result i32) + ;; CAREFUL: (func $work (type $2) (param $0 i32) (param $1 i32) (result i32) ;; CAREFUL-NEXT: (i32.mul ;; CAREFUL-NEXT: (i32.div_s ;; CAREFUL-NEXT: (local.get $0) @@ -90,24 +74,24 @@ ) ) - ;; ALWAYS: (func $calls (type $2) (param $x i32) - ;; ALWAYS-NEXT: (call $work_20) - ;; ALWAYS-NEXT: (call $work_20) - ;; ALWAYS-NEXT: (call $work_21 + ;; ALWAYS: (func $calls (type $1) (param $x i32) + ;; ALWAYS-NEXT: (call $work_5) + ;; ALWAYS-NEXT: (call $work_5) + ;; ALWAYS-NEXT: (call $work_6 ;; ALWAYS-NEXT: (local.get $x) ;; ALWAYS-NEXT: ) - ;; ALWAYS-NEXT: (call $work_22 + ;; ALWAYS-NEXT: (call $work_7 ;; ALWAYS-NEXT: (local.get $x) ;; ALWAYS-NEXT: (local.get $x) ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) - ;; CAREFUL: (func $calls (type $2) (param $x i32) - ;; CAREFUL-NEXT: (call $work_20) - ;; CAREFUL-NEXT: (call $work_20) - ;; CAREFUL-NEXT: (call $work_21 + ;; CAREFUL: (func $calls (type $1) (param $x i32) + ;; CAREFUL-NEXT: (call $work_5) + ;; CAREFUL-NEXT: (call $work_5) + ;; CAREFUL-NEXT: (call $work_6 ;; CAREFUL-NEXT: (local.get $x) ;; CAREFUL-NEXT: ) - ;; CAREFUL-NEXT: (call $work_22 + ;; CAREFUL-NEXT: (call $work_7 ;; CAREFUL-NEXT: (local.get $x) ;; CAREFUL-NEXT: (local.get $x) ;; CAREFUL-NEXT: ) @@ -167,11 +151,11 @@ ) ) - ;; ALWAYS: (func $call-undropped (type $i) (result i32) - ;; ALWAYS-NEXT: (call $work_23) + ;; ALWAYS: (func $call-undropped (type $0) (result i32) + ;; ALWAYS-NEXT: (call $work_8) ;; ALWAYS-NEXT: ) - ;; CAREFUL: (func $call-undropped (type $i) (result i32) - ;; CAREFUL-NEXT: (call $work_23) + ;; CAREFUL: (func $call-undropped (type $0) (result i32) + ;; CAREFUL-NEXT: (call $work_8) ;; CAREFUL-NEXT: ) (func $call-undropped (result i32) ;; As above but now with constant params. We can monomorphize here - there @@ -183,10 +167,169 @@ ) ) - ;; ALWAYS: (func $no-params (type $i) (result i32) + ;; ALWAYS: (func $call-no-params-return (type $0) (result i32) + ;; ALWAYS-NEXT: (return_call $work + ;; ALWAYS-NEXT: (i32.const 10) + ;; ALWAYS-NEXT: (i32.const 20) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: ) + ;; CAREFUL: (func $call-no-params-return (type $0) (result i32) + ;; CAREFUL-NEXT: (return_call $work + ;; CAREFUL-NEXT: (i32.const 10) + ;; CAREFUL-NEXT: (i32.const 20) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: ) + (func $call-no-params-return (result i32) + ;; Return calls can be monomorphized too, but we have that as a TODO atm. + (return_call $work + (i32.const 10) + (i32.const 20) + ) + ) +) + +;; ALWAYS: (func $work_5 (type $4) +;; ALWAYS-NEXT: (local $x i32) +;; ALWAYS-NEXT: (local $y i32) +;; ALWAYS-NEXT: (drop +;; ALWAYS-NEXT: (block (result i32) +;; ALWAYS-NEXT: (local.set $x +;; ALWAYS-NEXT: (i32.const 3) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (local.set $y +;; ALWAYS-NEXT: (i32.const 4) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (i32.mul +;; ALWAYS-NEXT: (i32.xor +;; ALWAYS-NEXT: (local.get $x) +;; ALWAYS-NEXT: (local.get $y) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (i32.div_s +;; ALWAYS-NEXT: (local.get $x) +;; ALWAYS-NEXT: (local.get $y) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) + +;; ALWAYS: (func $work_6 (type $1) (param $0 i32) +;; ALWAYS-NEXT: (local $x i32) +;; ALWAYS-NEXT: (local $y i32) +;; ALWAYS-NEXT: (drop +;; ALWAYS-NEXT: (block (result i32) +;; ALWAYS-NEXT: (local.set $x +;; ALWAYS-NEXT: (i32.const 3) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (local.set $y +;; ALWAYS-NEXT: (local.get $0) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (i32.mul +;; ALWAYS-NEXT: (i32.xor +;; ALWAYS-NEXT: (local.get $x) +;; ALWAYS-NEXT: (local.get $y) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (i32.div_s +;; ALWAYS-NEXT: (local.get $x) +;; ALWAYS-NEXT: (local.get $y) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) + +;; ALWAYS: (func $work_7 (type $5) (param $0 i32) (param $1 i32) +;; ALWAYS-NEXT: (local $x i32) +;; ALWAYS-NEXT: (local $y i32) +;; ALWAYS-NEXT: (drop +;; ALWAYS-NEXT: (block (result i32) +;; ALWAYS-NEXT: (local.set $x +;; ALWAYS-NEXT: (local.get $0) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (local.set $y +;; ALWAYS-NEXT: (local.get $1) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (i32.mul +;; ALWAYS-NEXT: (i32.xor +;; ALWAYS-NEXT: (local.get $x) +;; ALWAYS-NEXT: (local.get $y) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (i32.div_s +;; ALWAYS-NEXT: (local.get $x) +;; ALWAYS-NEXT: (local.get $y) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) + +;; ALWAYS: (func $work_8 (type $0) (result i32) +;; ALWAYS-NEXT: (local $x i32) +;; ALWAYS-NEXT: (local $y i32) +;; ALWAYS-NEXT: (local.set $x +;; ALWAYS-NEXT: (i32.const 3) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (local.set $y +;; ALWAYS-NEXT: (i32.const 4) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (i32.mul +;; ALWAYS-NEXT: (i32.xor +;; ALWAYS-NEXT: (local.get $x) +;; ALWAYS-NEXT: (local.get $y) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (i32.div_s +;; ALWAYS-NEXT: (local.get $x) +;; ALWAYS-NEXT: (local.get $y) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) + +;; CAREFUL: (func $work_5 (type $4) +;; CAREFUL-NEXT: (nop) +;; CAREFUL-NEXT: ) + +;; CAREFUL: (func $work_6 (type $1) (param $0 i32) +;; CAREFUL-NEXT: (drop +;; CAREFUL-NEXT: (i32.div_s +;; CAREFUL-NEXT: (i32.const 3) +;; CAREFUL-NEXT: (local.get $0) +;; CAREFUL-NEXT: ) +;; CAREFUL-NEXT: ) +;; CAREFUL-NEXT: ) + +;; CAREFUL: (func $work_7 (type $5) (param $0 i32) (param $1 i32) +;; CAREFUL-NEXT: (drop +;; CAREFUL-NEXT: (i32.div_s +;; CAREFUL-NEXT: (local.get $0) +;; CAREFUL-NEXT: (local.get $1) +;; CAREFUL-NEXT: ) +;; CAREFUL-NEXT: ) +;; CAREFUL-NEXT: ) + +;; CAREFUL: (func $work_8 (type $0) (result i32) +;; CAREFUL-NEXT: (i32.const 0) +;; CAREFUL-NEXT: ) +(module + ;; ALWAYS: (type $0 (func)) + + ;; ALWAYS: (type $1 (func (param i32 i32) (result i32))) + + ;; ALWAYS: (type $2 (func (result i32))) + + ;; ALWAYS: (import "a" "b" (func $import (type $1) (param i32 i32) (result i32))) + ;; CAREFUL: (type $0 (func)) + + ;; CAREFUL: (type $1 (func (param i32 i32) (result i32))) + + ;; CAREFUL: (type $2 (func (result i32))) + + ;; CAREFUL: (import "a" "b" (func $import (type $1) (param i32 i32) (result i32))) + (import "a" "b" (func $import (param i32 i32) (result i32))) + + ;; ALWAYS: (func $no-params (type $2) (result i32) ;; ALWAYS-NEXT: (i32.const 42) ;; ALWAYS-NEXT: ) - ;; CAREFUL: (func $no-params (type $i) (result i32) + ;; CAREFUL: (func $no-params (type $2) (result i32) ;; CAREFUL-NEXT: (i32.const 42) ;; CAREFUL-NEXT: ) (func $no-params (result i32) @@ -194,12 +337,12 @@ (i32.const 42) ) - ;; ALWAYS: (func $call-no-params (type $i) (result i32) - ;; ALWAYS-NEXT: (call $no-params_24) + ;; ALWAYS: (func $call-no-params (type $2) (result i32) + ;; ALWAYS-NEXT: (call $no-params_6) ;; ALWAYS-NEXT: (call $no-params) ;; ALWAYS-NEXT: ) - ;; CAREFUL: (func $call-no-params (type $i) (result i32) - ;; CAREFUL-NEXT: (call $no-params_24) + ;; CAREFUL: (func $call-no-params (type $2) (result i32) + ;; CAREFUL-NEXT: (call $no-params_6) ;; CAREFUL-NEXT: (call $no-params) ;; CAREFUL-NEXT: ) (func $call-no-params (result i32) @@ -211,27 +354,7 @@ (call $no-params) ) - ;; ALWAYS: (func $call-no-params-return (type $i) (result i32) - ;; ALWAYS-NEXT: (return_call $work - ;; ALWAYS-NEXT: (i32.const 10) - ;; ALWAYS-NEXT: (i32.const 20) - ;; ALWAYS-NEXT: ) - ;; ALWAYS-NEXT: ) - ;; CAREFUL: (func $call-no-params-return (type $i) (result i32) - ;; CAREFUL-NEXT: (return_call $work - ;; CAREFUL-NEXT: (i32.const 10) - ;; CAREFUL-NEXT: (i32.const 20) - ;; CAREFUL-NEXT: ) - ;; CAREFUL-NEXT: ) - (func $call-no-params-return (result i32) - ;; Return calls can be monomorphized too, but we have that as a TODO atm. - (return_call $work - (i32.const 10) - (i32.const 20) - ) - ) - - ;; ALWAYS: (func $call-import (type $1) + ;; ALWAYS: (func $call-import (type $0) ;; ALWAYS-NEXT: (drop ;; ALWAYS-NEXT: (call $import ;; ALWAYS-NEXT: (i32.const 3) @@ -239,7 +362,7 @@ ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) - ;; CAREFUL: (func $call-import (type $1) + ;; CAREFUL: (func $call-import (type $0) ;; CAREFUL-NEXT: (drop ;; CAREFUL-NEXT: (call $import ;; CAREFUL-NEXT: (i32.const 3) @@ -257,7 +380,7 @@ ) ) - ;; ALWAYS: (func $import-work (type $iii) (param $x i32) (param $y i32) (result i32) + ;; ALWAYS: (func $import-work (type $1) (param $x i32) (param $y i32) (result i32) ;; ALWAYS-NEXT: (call $import ;; ALWAYS-NEXT: (i32.xor ;; ALWAYS-NEXT: (local.get $x) @@ -269,7 +392,7 @@ ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) - ;; CAREFUL: (func $import-work (type $iii) (param $0 i32) (param $1 i32) (result i32) + ;; CAREFUL: (func $import-work (type $1) (param $0 i32) (param $1 i32) (result i32) ;; CAREFUL-NEXT: (call $import ;; CAREFUL-NEXT: (i32.xor ;; CAREFUL-NEXT: (local.get $0) @@ -295,11 +418,11 @@ ) ) - ;; ALWAYS: (func $call-import-work (type $1) - ;; ALWAYS-NEXT: (call $import-work_25) + ;; ALWAYS: (func $call-import-work (type $0) + ;; ALWAYS-NEXT: (call $import-work_7) ;; ALWAYS-NEXT: ) - ;; CAREFUL: (func $call-import-work (type $1) - ;; CAREFUL-NEXT: (call $import-work_25) + ;; CAREFUL: (func $call-import-work (type $0) + ;; CAREFUL-NEXT: (call $import-work_7) ;; CAREFUL-NEXT: ) (func $call-import-work ;; This is monomorphized with the drop. @@ -310,13 +433,78 @@ ) ) ) +) + +;; ALWAYS: (func $no-params_6 (type $0) +;; ALWAYS-NEXT: (drop +;; ALWAYS-NEXT: (i32.const 42) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) + +;; ALWAYS: (func $import-work_7 (type $0) +;; ALWAYS-NEXT: (local $x i32) +;; ALWAYS-NEXT: (local $y i32) +;; ALWAYS-NEXT: (drop +;; ALWAYS-NEXT: (block (result i32) +;; ALWAYS-NEXT: (local.set $x +;; ALWAYS-NEXT: (i32.const 3) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (local.set $y +;; ALWAYS-NEXT: (i32.const 4) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (call $import +;; ALWAYS-NEXT: (i32.xor +;; ALWAYS-NEXT: (local.get $x) +;; ALWAYS-NEXT: (local.get $y) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (i32.div_s +;; ALWAYS-NEXT: (local.get $x) +;; ALWAYS-NEXT: (local.get $y) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) + +;; CAREFUL: (func $no-params_6 (type $0) +;; CAREFUL-NEXT: (nop) +;; CAREFUL-NEXT: ) + +;; CAREFUL: (func $import-work_7 (type $0) +;; CAREFUL-NEXT: (drop +;; CAREFUL-NEXT: (call $import +;; CAREFUL-NEXT: (i32.const 7) +;; CAREFUL-NEXT: (i32.const 0) +;; CAREFUL-NEXT: ) +;; CAREFUL-NEXT: ) +;; CAREFUL-NEXT: ) +(module + ;; ALWAYS: (type $0 (func (param i32))) + + ;; ALWAYS: (type $1 (func)) + + ;; ALWAYS: (type $2 (func (result i32))) + + ;; ALWAYS: (type $3 (func (param i32) (result i32))) + + ;; ALWAYS: (import "a" "c" (func $import (type $2) (result i32))) + ;; CAREFUL: (type $0 (func (param i32))) + + ;; CAREFUL: (type $1 (func)) + + ;; CAREFUL: (type $2 (func (result i32))) + + ;; CAREFUL: (type $3 (func (param i32) (result i32))) + + ;; CAREFUL: (import "a" "c" (func $import (type $2) (result i32))) + (import "a" "c" (func $import (result i32))) ;; ALWAYS: (func $return-normal (type $3) (param $x i32) (result i32) ;; ALWAYS-NEXT: (if ;; ALWAYS-NEXT: (local.get $x) ;; ALWAYS-NEXT: (then ;; ALWAYS-NEXT: (drop - ;; ALWAYS-NEXT: (call $import2) + ;; ALWAYS-NEXT: (call $import) ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: (return ;; ALWAYS-NEXT: (i32.const 0) @@ -330,7 +518,7 @@ ;; CAREFUL-NEXT: (local.get $0) ;; CAREFUL-NEXT: (then ;; CAREFUL-NEXT: (drop - ;; CAREFUL-NEXT: (call $import2) + ;; CAREFUL-NEXT: (call $import) ;; CAREFUL-NEXT: ) ;; CAREFUL-NEXT: (return ;; CAREFUL-NEXT: (i32.const 0) @@ -346,7 +534,7 @@ (local.get $x) (then (drop - (call $import2) + (call $import) ) (return (i32.const 0) @@ -357,17 +545,17 @@ (i32.const 1) ) - ;; ALWAYS: (func $call-return-normal (type $2) (param $x i32) - ;; ALWAYS-NEXT: (call $return-normal_26) - ;; ALWAYS-NEXT: (call $return-normal_27) - ;; ALWAYS-NEXT: (call $return-normal_28 + ;; ALWAYS: (func $call-return-normal (type $0) (param $x i32) + ;; ALWAYS-NEXT: (call $return-normal_3) + ;; ALWAYS-NEXT: (call $return-normal_4) + ;; ALWAYS-NEXT: (call $return-normal_5 ;; ALWAYS-NEXT: (local.get $x) ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) - ;; CAREFUL: (func $call-return-normal (type $2) (param $x i32) - ;; CAREFUL-NEXT: (call $return-normal_26) - ;; CAREFUL-NEXT: (call $return-normal_27) - ;; CAREFUL-NEXT: (call $return-normal_28 + ;; CAREFUL: (func $call-return-normal (type $0) (param $x i32) + ;; CAREFUL-NEXT: (call $return-normal_3) + ;; CAREFUL-NEXT: (call $return-normal_4) + ;; CAREFUL-NEXT: (call $return-normal_5 ;; CAREFUL-NEXT: (local.get $x) ;; CAREFUL-NEXT: ) ;; CAREFUL-NEXT: ) @@ -391,25 +579,152 @@ ) ) ) +) - ;; ALWAYS: (func $return-call (type $3) (param $x i32) (result i32) - ;; ALWAYS-NEXT: (if - ;; ALWAYS-NEXT: (local.get $x) - ;; ALWAYS-NEXT: (then - ;; ALWAYS-NEXT: (return_call $import2) - ;; ALWAYS-NEXT: ) - ;; ALWAYS-NEXT: ) - ;; ALWAYS-NEXT: (i32.const 1) - ;; ALWAYS-NEXT: ) - ;; CAREFUL: (func $return-call (type $3) (param $0 i32) (result i32) - ;; CAREFUL-NEXT: (if - ;; CAREFUL-NEXT: (local.get $0) - ;; CAREFUL-NEXT: (then - ;; CAREFUL-NEXT: (return_call $import2) - ;; CAREFUL-NEXT: ) - ;; CAREFUL-NEXT: ) - ;; CAREFUL-NEXT: (i32.const 1) - ;; CAREFUL-NEXT: ) +;; ALWAYS: (func $return-normal_3 (type $1) +;; ALWAYS-NEXT: (local $x i32) +;; ALWAYS-NEXT: (drop +;; ALWAYS-NEXT: (block (result i32) +;; ALWAYS-NEXT: (local.set $x +;; ALWAYS-NEXT: (i32.const 0) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (block (result i32) +;; ALWAYS-NEXT: (if +;; ALWAYS-NEXT: (local.get $x) +;; ALWAYS-NEXT: (then +;; ALWAYS-NEXT: (drop +;; ALWAYS-NEXT: (call $import) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (block +;; ALWAYS-NEXT: (drop +;; ALWAYS-NEXT: (i32.const 0) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (return) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (i32.const 1) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) + +;; ALWAYS: (func $return-normal_4 (type $1) +;; ALWAYS-NEXT: (local $x i32) +;; ALWAYS-NEXT: (drop +;; ALWAYS-NEXT: (block (result i32) +;; ALWAYS-NEXT: (local.set $x +;; ALWAYS-NEXT: (i32.const 1) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (block (result i32) +;; ALWAYS-NEXT: (if +;; ALWAYS-NEXT: (local.get $x) +;; ALWAYS-NEXT: (then +;; ALWAYS-NEXT: (drop +;; ALWAYS-NEXT: (call $import) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (block +;; ALWAYS-NEXT: (drop +;; ALWAYS-NEXT: (i32.const 0) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (return) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (i32.const 1) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) + +;; ALWAYS: (func $return-normal_5 (type $0) (param $0 i32) +;; ALWAYS-NEXT: (local $x i32) +;; ALWAYS-NEXT: (drop +;; ALWAYS-NEXT: (block (result i32) +;; ALWAYS-NEXT: (local.set $x +;; ALWAYS-NEXT: (local.get $0) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (block (result i32) +;; ALWAYS-NEXT: (if +;; ALWAYS-NEXT: (local.get $x) +;; ALWAYS-NEXT: (then +;; ALWAYS-NEXT: (drop +;; ALWAYS-NEXT: (call $import) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (block +;; ALWAYS-NEXT: (drop +;; ALWAYS-NEXT: (i32.const 0) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (return) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (i32.const 1) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) + +;; CAREFUL: (func $return-normal_3 (type $1) +;; CAREFUL-NEXT: (nop) +;; CAREFUL-NEXT: ) + +;; CAREFUL: (func $return-normal_4 (type $1) +;; CAREFUL-NEXT: (drop +;; CAREFUL-NEXT: (block +;; CAREFUL-NEXT: (drop +;; CAREFUL-NEXT: (call $import) +;; CAREFUL-NEXT: ) +;; CAREFUL-NEXT: (return) +;; CAREFUL-NEXT: ) +;; CAREFUL-NEXT: ) +;; CAREFUL-NEXT: ) + +;; CAREFUL: (func $return-normal_5 (type $0) (param $0 i32) +;; CAREFUL-NEXT: (if +;; CAREFUL-NEXT: (local.get $0) +;; CAREFUL-NEXT: (then +;; CAREFUL-NEXT: (drop +;; CAREFUL-NEXT: (call $import) +;; CAREFUL-NEXT: ) +;; CAREFUL-NEXT: ) +;; CAREFUL-NEXT: ) +;; CAREFUL-NEXT: ) +(module + ;; ALWAYS: (type $0 (func (result i32))) + + ;; ALWAYS: (type $1 (func (param i32) (result i32))) + + ;; ALWAYS: (type $2 (func (param i32))) + + ;; ALWAYS: (import "a" "c" (func $import (type $0) (result i32))) + ;; CAREFUL: (type $0 (func (result i32))) + + ;; CAREFUL: (type $1 (func (param i32) (result i32))) + + ;; CAREFUL: (type $2 (func (param i32))) + + ;; CAREFUL: (import "a" "c" (func $import (type $0) (result i32))) + (import "a" "c" (func $import (result i32))) + + ;; ALWAYS: (func $return-call (type $1) (param $x i32) (result i32) + ;; ALWAYS-NEXT: (if + ;; ALWAYS-NEXT: (local.get $x) + ;; ALWAYS-NEXT: (then + ;; ALWAYS-NEXT: (return_call $import) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: (i32.const 1) + ;; ALWAYS-NEXT: ) + ;; CAREFUL: (func $return-call (type $1) (param $0 i32) (result i32) + ;; CAREFUL-NEXT: (if + ;; CAREFUL-NEXT: (local.get $0) + ;; CAREFUL-NEXT: (then + ;; CAREFUL-NEXT: (return_call $import) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: (i32.const 1) + ;; CAREFUL-NEXT: ) (func $return-call (param $x i32) (result i32) ;; As above, but now with a return_call. We do not monomorphize the drop ;; part, as if we included the drop we'd turn the call into a non-return @@ -417,7 +732,7 @@ (if (local.get $x) (then - (return_call $import2) + (return_call $import) ) ) (i32.const 1) @@ -425,10 +740,10 @@ ;; ALWAYS: (func $call-return-call (type $2) (param $x i32) ;; ALWAYS-NEXT: (drop - ;; ALWAYS-NEXT: (call $return-call_29) + ;; ALWAYS-NEXT: (call $return-call_3) ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: (drop - ;; ALWAYS-NEXT: (call $return-call_30) + ;; ALWAYS-NEXT: (call $return-call_4) ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: (drop ;; ALWAYS-NEXT: (call $return-call @@ -438,10 +753,10 @@ ;; ALWAYS-NEXT: ) ;; CAREFUL: (func $call-return-call (type $2) (param $x i32) ;; CAREFUL-NEXT: (drop - ;; CAREFUL-NEXT: (call $return-call_29) + ;; CAREFUL-NEXT: (call $return-call_3) ;; CAREFUL-NEXT: ) ;; CAREFUL-NEXT: (drop - ;; CAREFUL-NEXT: (call $return-call_30) + ;; CAREFUL-NEXT: (call $return-call_4) ;; CAREFUL-NEXT: ) ;; CAREFUL-NEXT: (drop ;; CAREFUL-NEXT: (call $return-call @@ -469,24 +784,85 @@ ) ) ) +) + +;; ALWAYS: (func $return-call_3 (type $0) (result i32) +;; ALWAYS-NEXT: (local $x i32) +;; ALWAYS-NEXT: (local.set $x +;; ALWAYS-NEXT: (i32.const 0) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (block (result i32) +;; ALWAYS-NEXT: (if +;; ALWAYS-NEXT: (local.get $x) +;; ALWAYS-NEXT: (then +;; ALWAYS-NEXT: (return_call $import) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (i32.const 1) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) + +;; ALWAYS: (func $return-call_4 (type $0) (result i32) +;; ALWAYS-NEXT: (local $x i32) +;; ALWAYS-NEXT: (local.set $x +;; ALWAYS-NEXT: (i32.const 1) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (block (result i32) +;; ALWAYS-NEXT: (if +;; ALWAYS-NEXT: (local.get $x) +;; ALWAYS-NEXT: (then +;; ALWAYS-NEXT: (return_call $import) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (i32.const 1) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) + +;; CAREFUL: (func $return-call_3 (type $0) (result i32) +;; CAREFUL-NEXT: (i32.const 1) +;; CAREFUL-NEXT: ) + +;; CAREFUL: (func $return-call_4 (type $0) (result i32) +;; CAREFUL-NEXT: (return_call $import) +;; CAREFUL-NEXT: ) +(module + ;; ALWAYS: (type $i (func (result i32))) + ;; CAREFUL: (type $i (func (result i32))) + (type $i (func (result i32))) - ;; ALWAYS: (func $return-call-indirect (type $3) (param $x i32) (result i32) + ;; ALWAYS: (type $1 (func (param i32) (result i32))) + + ;; ALWAYS: (type $2 (func (param i32))) + + ;; ALWAYS: (import "a" "c" (func $import (type $i) (result i32))) + ;; CAREFUL: (type $1 (func (param i32) (result i32))) + + ;; CAREFUL: (type $2 (func (param i32))) + + ;; CAREFUL: (import "a" "c" (func $import (type $i) (result i32))) + (import "a" "c" (func $import (result i32))) + + ;; ALWAYS: (table $table 10 10 funcref) + ;; CAREFUL: (table $table 10 10 funcref) + (table $table 10 10 funcref) + + ;; ALWAYS: (func $return-call-indirect (type $1) (param $x i32) (result i32) ;; ALWAYS-NEXT: (if ;; ALWAYS-NEXT: (local.get $x) ;; ALWAYS-NEXT: (then ;; ALWAYS-NEXT: (return_call_indirect $table (type $i) - ;; ALWAYS-NEXT: (call $import2) + ;; ALWAYS-NEXT: (call $import) ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: (i32.const 1) ;; ALWAYS-NEXT: ) - ;; CAREFUL: (func $return-call-indirect (type $3) (param $0 i32) (result i32) + ;; CAREFUL: (func $return-call-indirect (type $1) (param $0 i32) (result i32) ;; CAREFUL-NEXT: (if ;; CAREFUL-NEXT: (local.get $0) ;; CAREFUL-NEXT: (then ;; CAREFUL-NEXT: (return_call_indirect $table (type $i) - ;; CAREFUL-NEXT: (call $import2) + ;; CAREFUL-NEXT: (call $import) ;; CAREFUL-NEXT: ) ;; CAREFUL-NEXT: ) ;; CAREFUL-NEXT: ) @@ -499,7 +875,7 @@ (local.get $x) (then (return_call_indirect (type $i) - (call $import2) + (call $import) ) ) ) @@ -508,10 +884,10 @@ ;; ALWAYS: (func $call-return-call-indirect (type $2) (param $x i32) ;; ALWAYS-NEXT: (drop - ;; ALWAYS-NEXT: (call $return-call-indirect_31) + ;; ALWAYS-NEXT: (call $return-call-indirect_3) ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: (drop - ;; ALWAYS-NEXT: (call $return-call-indirect_32) + ;; ALWAYS-NEXT: (call $return-call-indirect_4) ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: (drop ;; ALWAYS-NEXT: (call $return-call-indirect @@ -521,10 +897,10 @@ ;; ALWAYS-NEXT: ) ;; CAREFUL: (func $call-return-call-indirect (type $2) (param $x i32) ;; CAREFUL-NEXT: (drop - ;; CAREFUL-NEXT: (call $return-call-indirect_31) + ;; CAREFUL-NEXT: (call $return-call-indirect_3) ;; CAREFUL-NEXT: ) ;; CAREFUL-NEXT: (drop - ;; CAREFUL-NEXT: (call $return-call-indirect_32) + ;; CAREFUL-NEXT: (call $return-call-indirect_4) ;; CAREFUL-NEXT: ) ;; CAREFUL-NEXT: (drop ;; CAREFUL-NEXT: (call $return-call-indirect @@ -549,23 +925,90 @@ ) ) ) +) + +;; ALWAYS: (func $return-call-indirect_3 (type $i) (result i32) +;; ALWAYS-NEXT: (local $x i32) +;; ALWAYS-NEXT: (local.set $x +;; ALWAYS-NEXT: (i32.const 0) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (block (result i32) +;; ALWAYS-NEXT: (if +;; ALWAYS-NEXT: (local.get $x) +;; ALWAYS-NEXT: (then +;; ALWAYS-NEXT: (return_call_indirect $table (type $i) +;; ALWAYS-NEXT: (call $import) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (i32.const 1) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) + +;; ALWAYS: (func $return-call-indirect_4 (type $i) (result i32) +;; ALWAYS-NEXT: (local $x i32) +;; ALWAYS-NEXT: (local.set $x +;; ALWAYS-NEXT: (i32.const 1) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (block (result i32) +;; ALWAYS-NEXT: (if +;; ALWAYS-NEXT: (local.get $x) +;; ALWAYS-NEXT: (then +;; ALWAYS-NEXT: (return_call_indirect $table (type $i) +;; ALWAYS-NEXT: (call $import) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (i32.const 1) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) + +;; CAREFUL: (func $return-call-indirect_3 (type $i) (result i32) +;; CAREFUL-NEXT: (i32.const 1) +;; CAREFUL-NEXT: ) + +;; CAREFUL: (func $return-call-indirect_4 (type $i) (result i32) +;; CAREFUL-NEXT: (return_call_indirect $table (type $i) +;; CAREFUL-NEXT: (call $import) +;; CAREFUL-NEXT: ) +;; CAREFUL-NEXT: ) +(module + ;; ALWAYS: (type $i (func (result i32))) + ;; CAREFUL: (type $i (func (result i32))) + (type $i (func (result i32))) + + ;; ALWAYS: (type $1 (func (param i32) (result i32))) - ;; ALWAYS: (func $return-call-ref (type $3) (param $x i32) (result i32) + ;; ALWAYS: (import "a" "c" (func $import (type $i) (result i32))) + ;; CAREFUL: (type $1 (func (param i32) (result i32))) + + ;; CAREFUL: (import "a" "c" (func $import (type $i) (result i32))) + (import "a" "c" (func $import (result i32))) + + ;; ALWAYS: (table $table 10 10 funcref) + ;; CAREFUL: (table $table 10 10 funcref) + (table $table 10 10 funcref) + + ;; ALWAYS: (elem declare func $import) + + ;; ALWAYS: (func $return-call-ref (type $1) (param $x i32) (result i32) ;; ALWAYS-NEXT: (if ;; ALWAYS-NEXT: (local.get $x) ;; ALWAYS-NEXT: (then ;; ALWAYS-NEXT: (return_call_ref $i - ;; ALWAYS-NEXT: (ref.func $import2) + ;; ALWAYS-NEXT: (ref.func $import) ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: (i32.const 1) ;; ALWAYS-NEXT: ) - ;; CAREFUL: (func $return-call-ref (type $3) (param $0 i32) (result i32) + ;; CAREFUL: (elem declare func $import) + + ;; CAREFUL: (func $return-call-ref (type $1) (param $0 i32) (result i32) ;; CAREFUL-NEXT: (if ;; CAREFUL-NEXT: (local.get $0) ;; CAREFUL-NEXT: (then - ;; CAREFUL-NEXT: (return_call $import2) + ;; CAREFUL-NEXT: (return_call $import) ;; CAREFUL-NEXT: ) ;; CAREFUL-NEXT: ) ;; CAREFUL-NEXT: (i32.const 1) @@ -576,19 +1019,19 @@ (local.get $x) (then (return_call_ref $i - (ref.func $import2) + (ref.func $import) ) ) ) (i32.const 1) ) - ;; ALWAYS: (func $call-return-call-ref (type $3) (param $x i32) (result i32) + ;; ALWAYS: (func $call-return-call-ref (type $1) (param $x i32) (result i32) ;; ALWAYS-NEXT: (drop - ;; ALWAYS-NEXT: (call $return-call-ref_33) + ;; ALWAYS-NEXT: (call $return-call-ref_3) ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: (drop - ;; ALWAYS-NEXT: (call $return-call-ref_34) + ;; ALWAYS-NEXT: (call $return-call-ref_4) ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: (drop ;; ALWAYS-NEXT: (call $return-call-ref @@ -598,7 +1041,7 @@ ;; ALWAYS-NEXT: (if ;; ALWAYS-NEXT: (local.get $x) ;; ALWAYS-NEXT: (then - ;; ALWAYS-NEXT: (return_call $import2) + ;; ALWAYS-NEXT: (return_call $import) ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: (if @@ -613,18 +1056,18 @@ ;; ALWAYS-NEXT: (local.get $x) ;; ALWAYS-NEXT: (then ;; ALWAYS-NEXT: (return_call_ref $i - ;; ALWAYS-NEXT: (ref.func $import2) + ;; ALWAYS-NEXT: (ref.func $import) ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: (unreachable) ;; ALWAYS-NEXT: ) - ;; CAREFUL: (func $call-return-call-ref (type $3) (param $x i32) (result i32) + ;; CAREFUL: (func $call-return-call-ref (type $1) (param $x i32) (result i32) ;; CAREFUL-NEXT: (drop - ;; CAREFUL-NEXT: (call $return-call-ref_33) + ;; CAREFUL-NEXT: (call $return-call-ref_3) ;; CAREFUL-NEXT: ) ;; CAREFUL-NEXT: (drop - ;; CAREFUL-NEXT: (call $return-call-ref_34) + ;; CAREFUL-NEXT: (call $return-call-ref_4) ;; CAREFUL-NEXT: ) ;; CAREFUL-NEXT: (drop ;; CAREFUL-NEXT: (call $return-call-ref @@ -634,7 +1077,7 @@ ;; CAREFUL-NEXT: (if ;; CAREFUL-NEXT: (local.get $x) ;; CAREFUL-NEXT: (then - ;; CAREFUL-NEXT: (return_call $import2) + ;; CAREFUL-NEXT: (return_call $import) ;; CAREFUL-NEXT: ) ;; CAREFUL-NEXT: ) ;; CAREFUL-NEXT: (if @@ -649,7 +1092,7 @@ ;; CAREFUL-NEXT: (local.get $x) ;; CAREFUL-NEXT: (then ;; CAREFUL-NEXT: (return_call_ref $i - ;; CAREFUL-NEXT: (ref.func $import2) + ;; CAREFUL-NEXT: (ref.func $import) ;; CAREFUL-NEXT: ) ;; CAREFUL-NEXT: ) ;; CAREFUL-NEXT: ) @@ -680,7 +1123,7 @@ (if (local.get $x) (then - (return_call $import2) + (return_call $import) ) ) (if @@ -695,311 +1138,33 @@ (local.get $x) (then (return_call_ref $i - (ref.func $import2) + (ref.func $import) ) ) ) (unreachable) ) ) -;; ALWAYS: (func $work_20 (type $1) + +;; ALWAYS: (func $return-call-ref_3 (type $i) (result i32) ;; ALWAYS-NEXT: (local $x i32) -;; ALWAYS-NEXT: (local $y i32) -;; ALWAYS-NEXT: (drop -;; ALWAYS-NEXT: (block (result i32) -;; ALWAYS-NEXT: (local.set $x -;; ALWAYS-NEXT: (i32.const 3) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: (local.set $y -;; ALWAYS-NEXT: (i32.const 4) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: (i32.mul -;; ALWAYS-NEXT: (i32.xor -;; ALWAYS-NEXT: (local.get $x) -;; ALWAYS-NEXT: (local.get $y) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: (i32.div_s -;; ALWAYS-NEXT: (local.get $x) -;; ALWAYS-NEXT: (local.get $y) +;; ALWAYS-NEXT: (local.set $x +;; ALWAYS-NEXT: (i32.const 0) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (block (result i32) +;; ALWAYS-NEXT: (if +;; ALWAYS-NEXT: (local.get $x) +;; ALWAYS-NEXT: (then +;; ALWAYS-NEXT: (return_call_ref $i +;; ALWAYS-NEXT: (ref.func $import) ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (i32.const 1) ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) -;; ALWAYS: (func $work_21 (type $2) (param $0 i32) -;; ALWAYS-NEXT: (local $x i32) -;; ALWAYS-NEXT: (local $y i32) -;; ALWAYS-NEXT: (drop -;; ALWAYS-NEXT: (block (result i32) -;; ALWAYS-NEXT: (local.set $x -;; ALWAYS-NEXT: (i32.const 3) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: (local.set $y -;; ALWAYS-NEXT: (local.get $0) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: (i32.mul -;; ALWAYS-NEXT: (i32.xor -;; ALWAYS-NEXT: (local.get $x) -;; ALWAYS-NEXT: (local.get $y) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: (i32.div_s -;; ALWAYS-NEXT: (local.get $x) -;; ALWAYS-NEXT: (local.get $y) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: ) - -;; ALWAYS: (func $work_22 (type $5) (param $0 i32) (param $1 i32) -;; ALWAYS-NEXT: (local $x i32) -;; ALWAYS-NEXT: (local $y i32) -;; ALWAYS-NEXT: (drop -;; ALWAYS-NEXT: (block (result i32) -;; ALWAYS-NEXT: (local.set $x -;; ALWAYS-NEXT: (local.get $0) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: (local.set $y -;; ALWAYS-NEXT: (local.get $1) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: (i32.mul -;; ALWAYS-NEXT: (i32.xor -;; ALWAYS-NEXT: (local.get $x) -;; ALWAYS-NEXT: (local.get $y) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: (i32.div_s -;; ALWAYS-NEXT: (local.get $x) -;; ALWAYS-NEXT: (local.get $y) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: ) - -;; ALWAYS: (func $work_23 (type $i) (result i32) -;; ALWAYS-NEXT: (local $x i32) -;; ALWAYS-NEXT: (local $y i32) -;; ALWAYS-NEXT: (local.set $x -;; ALWAYS-NEXT: (i32.const 3) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: (local.set $y -;; ALWAYS-NEXT: (i32.const 4) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: (i32.mul -;; ALWAYS-NEXT: (i32.xor -;; ALWAYS-NEXT: (local.get $x) -;; ALWAYS-NEXT: (local.get $y) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: (i32.div_s -;; ALWAYS-NEXT: (local.get $x) -;; ALWAYS-NEXT: (local.get $y) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: ) - -;; ALWAYS: (func $no-params_24 (type $1) -;; ALWAYS-NEXT: (drop -;; ALWAYS-NEXT: (i32.const 42) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: ) - -;; ALWAYS: (func $import-work_25 (type $1) -;; ALWAYS-NEXT: (local $x i32) -;; ALWAYS-NEXT: (local $y i32) -;; ALWAYS-NEXT: (drop -;; ALWAYS-NEXT: (block (result i32) -;; ALWAYS-NEXT: (local.set $x -;; ALWAYS-NEXT: (i32.const 3) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: (local.set $y -;; ALWAYS-NEXT: (i32.const 4) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: (call $import -;; ALWAYS-NEXT: (i32.xor -;; ALWAYS-NEXT: (local.get $x) -;; ALWAYS-NEXT: (local.get $y) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: (i32.div_s -;; ALWAYS-NEXT: (local.get $x) -;; ALWAYS-NEXT: (local.get $y) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: ) - -;; ALWAYS: (func $return-normal_26 (type $1) -;; ALWAYS-NEXT: (local $x i32) -;; ALWAYS-NEXT: (drop -;; ALWAYS-NEXT: (block (result i32) -;; ALWAYS-NEXT: (local.set $x -;; ALWAYS-NEXT: (i32.const 0) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: (block (result i32) -;; ALWAYS-NEXT: (if -;; ALWAYS-NEXT: (local.get $x) -;; ALWAYS-NEXT: (then -;; ALWAYS-NEXT: (drop -;; ALWAYS-NEXT: (call $import2) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: (block -;; ALWAYS-NEXT: (drop -;; ALWAYS-NEXT: (i32.const 0) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: (return) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: (i32.const 1) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: ) - -;; ALWAYS: (func $return-normal_27 (type $1) -;; ALWAYS-NEXT: (local $x i32) -;; ALWAYS-NEXT: (drop -;; ALWAYS-NEXT: (block (result i32) -;; ALWAYS-NEXT: (local.set $x -;; ALWAYS-NEXT: (i32.const 1) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: (block (result i32) -;; ALWAYS-NEXT: (if -;; ALWAYS-NEXT: (local.get $x) -;; ALWAYS-NEXT: (then -;; ALWAYS-NEXT: (drop -;; ALWAYS-NEXT: (call $import2) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: (block -;; ALWAYS-NEXT: (drop -;; ALWAYS-NEXT: (i32.const 0) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: (return) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: (i32.const 1) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: ) - -;; ALWAYS: (func $return-normal_28 (type $2) (param $0 i32) -;; ALWAYS-NEXT: (local $x i32) -;; ALWAYS-NEXT: (drop -;; ALWAYS-NEXT: (block (result i32) -;; ALWAYS-NEXT: (local.set $x -;; ALWAYS-NEXT: (local.get $0) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: (block (result i32) -;; ALWAYS-NEXT: (if -;; ALWAYS-NEXT: (local.get $x) -;; ALWAYS-NEXT: (then -;; ALWAYS-NEXT: (drop -;; ALWAYS-NEXT: (call $import2) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: (block -;; ALWAYS-NEXT: (drop -;; ALWAYS-NEXT: (i32.const 0) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: (return) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: (i32.const 1) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: ) - -;; ALWAYS: (func $return-call_29 (type $i) (result i32) -;; ALWAYS-NEXT: (local $x i32) -;; ALWAYS-NEXT: (local.set $x -;; ALWAYS-NEXT: (i32.const 0) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: (block (result i32) -;; ALWAYS-NEXT: (if -;; ALWAYS-NEXT: (local.get $x) -;; ALWAYS-NEXT: (then -;; ALWAYS-NEXT: (return_call $import2) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: (i32.const 1) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: ) - -;; ALWAYS: (func $return-call_30 (type $i) (result i32) -;; ALWAYS-NEXT: (local $x i32) -;; ALWAYS-NEXT: (local.set $x -;; ALWAYS-NEXT: (i32.const 1) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: (block (result i32) -;; ALWAYS-NEXT: (if -;; ALWAYS-NEXT: (local.get $x) -;; ALWAYS-NEXT: (then -;; ALWAYS-NEXT: (return_call $import2) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: (i32.const 1) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: ) - -;; ALWAYS: (func $return-call-indirect_31 (type $i) (result i32) -;; ALWAYS-NEXT: (local $x i32) -;; ALWAYS-NEXT: (local.set $x -;; ALWAYS-NEXT: (i32.const 0) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: (block (result i32) -;; ALWAYS-NEXT: (if -;; ALWAYS-NEXT: (local.get $x) -;; ALWAYS-NEXT: (then -;; ALWAYS-NEXT: (return_call_indirect $table (type $i) -;; ALWAYS-NEXT: (call $import2) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: (i32.const 1) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: ) - -;; ALWAYS: (func $return-call-indirect_32 (type $i) (result i32) -;; ALWAYS-NEXT: (local $x i32) -;; ALWAYS-NEXT: (local.set $x -;; ALWAYS-NEXT: (i32.const 1) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: (block (result i32) -;; ALWAYS-NEXT: (if -;; ALWAYS-NEXT: (local.get $x) -;; ALWAYS-NEXT: (then -;; ALWAYS-NEXT: (return_call_indirect $table (type $i) -;; ALWAYS-NEXT: (call $import2) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: (i32.const 1) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: ) - -;; ALWAYS: (func $return-call-ref_33 (type $i) (result i32) -;; ALWAYS-NEXT: (local $x i32) -;; ALWAYS-NEXT: (local.set $x -;; ALWAYS-NEXT: (i32.const 0) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: (block (result i32) -;; ALWAYS-NEXT: (if -;; ALWAYS-NEXT: (local.get $x) -;; ALWAYS-NEXT: (then -;; ALWAYS-NEXT: (return_call_ref $i -;; ALWAYS-NEXT: (ref.func $import2) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: (i32.const 1) -;; ALWAYS-NEXT: ) -;; ALWAYS-NEXT: ) - -;; ALWAYS: (func $return-call-ref_34 (type $i) (result i32) +;; ALWAYS: (func $return-call-ref_4 (type $i) (result i32) ;; ALWAYS-NEXT: (local $x i32) ;; ALWAYS-NEXT: (local.set $x ;; ALWAYS-NEXT: (i32.const 1) @@ -1009,7 +1174,7 @@ ;; ALWAYS-NEXT: (local.get $x) ;; ALWAYS-NEXT: (then ;; ALWAYS-NEXT: (return_call_ref $i -;; ALWAYS-NEXT: (ref.func $import2) +;; ALWAYS-NEXT: (ref.func $import) ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) @@ -1017,93 +1182,10 @@ ;; ALWAYS-NEXT: ) ;; ALWAYS-NEXT: ) -;; CAREFUL: (func $work_20 (type $1) -;; CAREFUL-NEXT: (nop) -;; CAREFUL-NEXT: ) - -;; CAREFUL: (func $work_21 (type $2) (param $0 i32) -;; CAREFUL-NEXT: (drop -;; CAREFUL-NEXT: (i32.div_s -;; CAREFUL-NEXT: (i32.const 3) -;; CAREFUL-NEXT: (local.get $0) -;; CAREFUL-NEXT: ) -;; CAREFUL-NEXT: ) -;; CAREFUL-NEXT: ) - -;; CAREFUL: (func $work_22 (type $5) (param $0 i32) (param $1 i32) -;; CAREFUL-NEXT: (drop -;; CAREFUL-NEXT: (i32.div_s -;; CAREFUL-NEXT: (local.get $0) -;; CAREFUL-NEXT: (local.get $1) -;; CAREFUL-NEXT: ) -;; CAREFUL-NEXT: ) -;; CAREFUL-NEXT: ) - -;; CAREFUL: (func $work_23 (type $i) (result i32) -;; CAREFUL-NEXT: (i32.const 0) -;; CAREFUL-NEXT: ) - -;; CAREFUL: (func $no-params_24 (type $1) -;; CAREFUL-NEXT: (nop) -;; CAREFUL-NEXT: ) - -;; CAREFUL: (func $import-work_25 (type $1) -;; CAREFUL-NEXT: (drop -;; CAREFUL-NEXT: (call $import -;; CAREFUL-NEXT: (i32.const 7) -;; CAREFUL-NEXT: (i32.const 0) -;; CAREFUL-NEXT: ) -;; CAREFUL-NEXT: ) -;; CAREFUL-NEXT: ) - -;; CAREFUL: (func $return-normal_26 (type $1) -;; CAREFUL-NEXT: (nop) -;; CAREFUL-NEXT: ) - -;; CAREFUL: (func $return-normal_27 (type $1) -;; CAREFUL-NEXT: (drop -;; CAREFUL-NEXT: (block -;; CAREFUL-NEXT: (drop -;; CAREFUL-NEXT: (call $import2) -;; CAREFUL-NEXT: ) -;; CAREFUL-NEXT: (return) -;; CAREFUL-NEXT: ) -;; CAREFUL-NEXT: ) -;; CAREFUL-NEXT: ) - -;; CAREFUL: (func $return-normal_28 (type $2) (param $0 i32) -;; CAREFUL-NEXT: (if -;; CAREFUL-NEXT: (local.get $0) -;; CAREFUL-NEXT: (then -;; CAREFUL-NEXT: (drop -;; CAREFUL-NEXT: (call $import2) -;; CAREFUL-NEXT: ) -;; CAREFUL-NEXT: ) -;; CAREFUL-NEXT: ) -;; CAREFUL-NEXT: ) - -;; CAREFUL: (func $return-call_29 (type $i) (result i32) -;; CAREFUL-NEXT: (i32.const 1) -;; CAREFUL-NEXT: ) - -;; CAREFUL: (func $return-call_30 (type $i) (result i32) -;; CAREFUL-NEXT: (return_call $import2) -;; CAREFUL-NEXT: ) - -;; CAREFUL: (func $return-call-indirect_31 (type $i) (result i32) -;; CAREFUL-NEXT: (i32.const 1) -;; CAREFUL-NEXT: ) - -;; CAREFUL: (func $return-call-indirect_32 (type $i) (result i32) -;; CAREFUL-NEXT: (return_call_indirect $table (type $i) -;; CAREFUL-NEXT: (call $import2) -;; CAREFUL-NEXT: ) -;; CAREFUL-NEXT: ) - -;; CAREFUL: (func $return-call-ref_33 (type $i) (result i32) +;; CAREFUL: (func $return-call-ref_3 (type $i) (result i32) ;; CAREFUL-NEXT: (i32.const 1) ;; CAREFUL-NEXT: ) -;; CAREFUL: (func $return-call-ref_34 (type $i) (result i32) -;; CAREFUL-NEXT: (return_call $import2) +;; CAREFUL: (func $return-call-ref_4 (type $i) (result i32) +;; CAREFUL-NEXT: (return_call $import) ;; CAREFUL-NEXT: )