Conversation
There was a problem hiding this comment.
Pull request overview
This PR enables the "pass-params" optimization (internally known as g0m0) by default in the LLVM compiler backend based on benchmark results showing significant performance improvements. The optimization passes the first global (#0) and first memory (#0) as explicit parameters between guest functions.
Changes:
- Changed default value of
enable_g0m0_optfromfalsetotruein the LLVM config - Renamed the configuration method from
enable_pass_params_opttodisable_pass_params_optto reflect the new default-on behavior - Added
g0m0_enabled_for_modulehelper function that checks both the config flag and module prerequisites (memory #0 exists, global #0 exists and is i32) - Fixed a bug where g0m0 parameters were incorrectly passed to imported (host) functions
- Updated CLI to deprecate
--enable-pass-params-optflag and add--disable-pass-params-optflag
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| lib/compiler-llvm/src/config.rs | Changed default value of enable_g0m0_opt to true and renamed method from enable_pass_params_opt to disable_pass_params_opt |
| lib/compiler-llvm/src/compiler.rs | Updated with_opts to only disable the optimization when explicitly requested; added g0m0_enabled_for_module helper function with module validation |
| lib/cli/src/backend.rs | Deprecated --enable-pass-params-opt flag (renamed to _enable_pass_params_opt and ignored), added --disable-pass-params-opt flag |
| lib/compiler-llvm/src/translator/code.rs | Updated to use g0m0_enabled_for_module helper; fixed bug by passing None instead of g0m0 params for imported function calls |
| lib/compiler-llvm/src/translator/intrinsics.rs | Updated to use g0m0_enabled_for_module helper function |
| lib/compiler-llvm/src/trampoline/wasm.rs | Updated to use g0m0_enabled_for_module helper function in multiple locations |
| /// Deprecated, "pass-params" optimization enabled by default, where the first (#0) | ||
| /// global and the first (#0) memory passed between guest functions as explicit parameters. |
There was a problem hiding this comment.
The sentence is grammatically incorrect. It should read "global and the first (#0) memory are passed" (with "are" instead of "passed").
| /// Disable the "pass-params" optimization, where the first (#0) | ||
| /// global and the first (#0) memory passed between guest functions as explicit parameters. |
There was a problem hiding this comment.
The sentence is grammatically incorrect. It should read "global and the first (#0) memory are passed" (with "are" instead of "passed").
|
|
||
| /// (warning: experimental) Pass the value of the first (#0) global and the base pointer of the | ||
| /// Disable the passing of the value of the first (#0) global and the base pointer of the | ||
| /// first (#0) memory as parameter between guest functions. |
There was a problem hiding this comment.
The phrase "as parameter" should be "as parameters" (plural) to match the grammatical structure of passing two items (global and memory).
| /// first (#0) memory as parameter between guest functions. | |
| /// first (#0) memory as parameters between guest functions. |
|
I'm not sure about this. RIght now pass params embeds the stack pointer so it's not actually a variable from the outside. This has wide implications, for example when using dynamic linked modules. However, if we move the strategy of the stack pointer being in one register (rather than in a local function variable that is "passed" as a copy), then we should be good to merge |
|
All right, I am getting into the nitty-gritty. First, now I understand the That being said, I tried an experimental branch where I replaced the
Can you depict the exact scenario where that would break? Still, I am getting into all the WA aspects.
There appears to be recent activity on this front: llvm/llvm-project#179036. At the moment, support for x86_64 is still missing for a critical LLVM option. It’s worth emphasizing that in this case we must rely entirely on the compiler—otherwise subtle but serious issues can arise, for example with exception handling and correct stack unwinding. |
I guess depends on what benchmark you run. If you run the interpreter I attached in slack a few days ago, the major speedup came from g0 (if I recall correctly).
In the scenario that you run multiple threads (or you fork). Right now, things are cloned as you call it (namely, the globals, in which the stack pointer is included). When you move the stack pointer out of the global to be a function variable (that gets passed as value, not reference), then cloning will do nothing, and might break the Wasm behavior. |
|
Once #6187 gets in, we can basically enable the |
Based on the recent benchmark effort, I measured a significant speed-up with

pass-params(aka.g0m0aka. stack-pointer and heap arguments) across the board:The PR preserves the
suggested_compiler_optslogic for the package files - currently only:is taken into account (pass_params = true is on by default). Similarly for the Wasmer CLI, I ignore
--enable-pass-params-optoption and a user can disable the optimization with--disable-pass-params-opt.Apart from that, the PR addresses one bug where we wrongly included the 2 extra arguments for host-fn call.