-
Notifications
You must be signed in to change notification settings - Fork 760
Optimizer Cookbook
All the wasm-opt
flags are documented in --help
, of course, but maybe it's not obvious which of the various flags are more important and worth trying first. This page has suggestions for that.
There is also a special page for Wasm GC, which has many more considerations.
--low-memory-unused
is a flag (not a pass) which means "addresses below 1024 are unused", which avoids load/store ptr overflows in situations that prevent certain optimizations. Specifically it can fold added constants into load/store offsets, which are smaller and more efficient.
You need to tell wasm-ld not to use address 1024 or below for globals (emcc does it automatically) for that to be safe.
--gufa
is a new pass that is not on by default yet, so you need to run it manually. It infers constant values in a whole-program manner. It mostly helps wasm GC by inferring exact types and such, but it can also infer function results on wasm MVP that then lead to more benefits.
--flatten --rereloop -Oz -Oz
Flattening the IR is necessary for running "re-reloop" which completely rewrites the control flow graph. That's sometimes slow and so it's not on by default. But sometimes it helps by a few %.
-Oz
twice is useful after it, as flattening the IR requires additional work to clean up. One way to think about this is that wasm-opt
's default pipeline has been tuned on optimized LLVM output, and so if you give it something less optimized it might take more than one cycle of the pipeline. And the IR after flattening is less optimized than LLVM's optimized form, so it takes more work.
-tnh
is a flag that means "assume traps never happen" which lets the optimizer remove code on paths leading to traps (since it is allowed to assume they never happen in practice when the program runs).
That can interferes with things like crash reporting, if you save info right before crashing. And it will remove runtime asserts in the form of "if error, trap". But if you can live without those it can help. For example, if we assume traps never happen then we can move a load into an if arm and sometimes not run it (but if it trapped, we couldn't change the observable behavior of the trap).
--converge
runs all the opts you told it to in a loop while the file keeps shrinking. That is, --converge -Oz
will keep running all the passes in -Oz
until we reach a fixed point.
Usually the benefit of such additional cycles is limited, but sometimes it matters quite a lot, especially in larger programs.