diff options
author | Alon Zakai <alonzakai@gmail.com> | 2018-09-04 16:37:22 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-09-04 16:37:22 -0700 |
commit | ff5d6f922555469d59e04268a143a201197cdce7 (patch) | |
tree | fed84379a8e0b4f7090654b4f5bc2a4c330d2512 /src/passes/pass.cpp | |
parent | a852156980986d6c5875981a49c16fe8b98875c3 (diff) | |
download | binaryen-ff5d6f922555469d59e04268a143a201197cdce7.tar.gz binaryen-ff5d6f922555469d59e04268a143a201197cdce7.tar.bz2 binaryen-ff5d6f922555469d59e04268a143a201197cdce7.zip |
Loop Invariant Code Motion (#1658)
This adds an licm pass. Not that important for LLVM-originating code obviously, but for AssemblyScript and other non-LLVM compilers this might help a lot. Also when wasm has GC a bunch more non-LLVM languages may arrive that can benefit.
The pass is mostly straightforward. I considered using the DataFlow IR since it's in SSA form, or the CFG IR, but in the end it's actually pretty convenient to use the main IR as it is - with explicit loops already present - plus LocalGraph which connects each get to the sets influencing it.
Passed a bunch of fuzzing, and also the emscripten test suite at -O1 with licm added to the default passes (but I don't think it would make sense to run this by default, as LLVM doesn't need it).
We limit code moved by this pass as follows: An increased code size on fuzz testcases (and, more rarely, on real inputs) can happen due to stuff like this:
(loop
(set_local $x (i32.const 1))
..
)
=>
(set_local $x (i32.const 1))
(loop
..
)
For a const or a get_local, such an assignment to a local is both very cheap (a copy to another local may be optimized out later), and moving it out may prevent other optimizations (since we have no pass that tries to move code back in to a loop edit well, not by default, precompute-propagate etc. would do it, but are only run on high opt levels). So I made the pass not move such trivial code (sets/tees of consts or gets). However, the risk remains if code is moved out that is later reduced to a constant, so something like -Os --flatten --licm -Os may make sense.
Diffstat (limited to 'src/passes/pass.cpp')
-rw-r--r-- | src/passes/pass.cpp | 1 |
1 files changed, 1 insertions, 0 deletions
diff --git a/src/passes/pass.cpp b/src/passes/pass.cpp index c8d02f445..aa3ed8eb3 100644 --- a/src/passes/pass.cpp +++ b/src/passes/pass.cpp @@ -87,6 +87,7 @@ void PassRegistry::registerPasses() { registerPass("i64-to-i32-lowering", "lower all uses of i64s to use i32s instead", createI64ToI32LoweringPass); registerPass("instrument-locals", "instrument the build with code to intercept all loads and stores", createInstrumentLocalsPass); registerPass("instrument-memory", "instrument the build with code to intercept all loads and stores", createInstrumentMemoryPass); + registerPass("licm", "loop invariant code motion", createLoopInvariantCodeMotionPass); registerPass("memory-packing", "packs memory into separate segments, skipping zeros", createMemoryPackingPass); registerPass("merge-blocks", "merges blocks to their parents", createMergeBlocksPass); registerPass("merge-locals", "merges locals when beneficial", createMergeLocalsPass); |