Skip to content

Commit eb83c42

Browse files
authored
Partial inlining via function splitting (WebAssembly#4152)
This PR helps with functions like this: function foo(x) { if (x) { .. lots of work here .. } } If "lots of work" is large enough, then we won't inline such a function. However, we may end up calling into the function only to get a false on that if and immediately exit. So it is useful to partially inline this function, basically by creating a split of it into a condition part that is inlineable function foo$inlineable(x) { if (x) { foo$outlined(); } } and an outlined part that is not inlineable: function foo$outlined(x) { .. lots of work here .. } We can then inline the inlineable part. That means that a call like foo(param); turns into if (param) { foo$outlined(); } In other words, we end up replacing a call and then a check with a check and then a call. Any time that the condition is false, this will be a speedup. The cost here is increased size, as we duplicate the condition into the callsites. For that reason, only do this when heavily optimizing for size. This is a 10% speedup on j2cl. This helps two types of functions there: Java class inits, which often look like "have I been initialized before? if not, do all this work", and also assertion methods which look like "if the input is null, throw an exception".
1 parent 8e8bce1 commit eb83c42

5 files changed

Lines changed: 2921 additions & 623 deletions

File tree

scripts/fuzz_opt.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,7 @@ def randomize_fuzz_settings():
176176
os.path.join('lit', 'passes', 'optimize-instructions-bulk-memory.wast'),
177177
os.path.join('lit', 'passes', 'optimize-instructions-ignore-traps.wast'),
178178
os.path.join('lit', 'passes', 'optimize-instructions-gc.wast'),
179+
os.path.join('lit', 'passes', 'inlining_splitting.wast'),
179180
]
180181
IMPORTANT_INITIAL_CONTENTS = [os.path.join(shared.get_test_dir('.'), t) for t in IMPORTANT_INITIAL_CONTENTS]
181182

src/ir/module-utils.h

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,12 @@ namespace wasm {
3030

3131
namespace ModuleUtils {
3232

33-
inline Function* copyFunction(Function* func, Module& out) {
34-
auto* ret = new Function();
35-
ret->name = func->name;
33+
// Copies a function into a module. If newName is provided it is used as the
34+
// name of the function (otherwise the original name is copied).
35+
inline Function*
36+
copyFunction(Function* func, Module& out, Name newName = Name()) {
37+
auto ret = std::make_unique<Function>();
38+
ret->name = newName.is() ? newName : func->name;
3639
ret->type = func->type;
3740
ret->vars = func->vars;
3841
ret->localNames = func->localNames;
@@ -43,8 +46,7 @@ inline Function* copyFunction(Function* func, Module& out) {
4346
ret->base = func->base;
4447
// TODO: copy Stack IR
4548
assert(!func->stackIR);
46-
out.addFunction(ret);
47-
return ret;
49+
return out.addFunction(std::move(ret));
4850
}
4951

5052
inline Global* copyGlobal(Global* global, Module& out) {

0 commit comments

Comments
 (0)