Skip to content

Collapse inner loops with union-find during WTO construction - #9241

Merged
tlively merged 29 commits into
mainfrom
wto-union-find
Oct 9, 2026
Merged

tlively merged 29 commits into
mainfrom
wto-union-find

Conversation

@tlively

@tlively tlively commented Oct 9, 2026

Copy link
Copy Markdown
Member

During reverse-RPO natural loop discovery in WeakTopologicalOrdering,
collapse each discovered loop body into its header using union-find with
path compression, and skip over already-collapsed inner loops when
walking immediate dominators in dominates(). This prevents outer loops
from re-traversing inner loop bodies, bounding natural loop discovery to
O(E alpha(N)) instead of O(N * depth) on deeply nested loops.

Benchmark results across 16 WebAssembly modules (3 iterations,
interleaved):

  • --constraint-analysis:
    • Geomean: 1.576s -> 1.564s (-0.7%)
    • Total time: 62.82s -> 62.40s (-0.7%)
  • --rse:
    • Geomean: 0.859s -> 0.853s (-0.7%)
    • Total time: 25.40s -> 25.06s (-1.3%)

tlively added 29 commits October 6, 2026 00:00
Add `src/cfg/wto.h` with `WeakTopologicalOrdering` (`WTO`) and `WTOWorklist` built on top of `DomTree`. In a reducible CFG ordered in reverse postorder, every cycle is a natural loop headed by a block that dominates all blocks in the cycle, allowing a Bourdoncle Weak Topological Ordering to be constructed directly from the dominator tree and natural loops of the CFG.

Include unit tests in `test/gtest/wto.cpp` and `TODO` comments noting follow-on optimizations.
Replace RPOQueue with WTOWorklist in ConstraintAnalysis and
RedundantSetElimination so that loops stabilize before flow values
propagate to downstream blocks. This avoids quadratic/cubic blowups on
functions with sequential loops while also speeding up general workloads.

Benchmark results across 16 WebAssembly modules (3 iterations):
- --constraint-analysis:
  - esbuild.wasm: 381.60s -> 7.59s (-98.0%, 50.3x speedup)
  - 15 non-esbuild modules geomean: 1.564s -> 1.487s (-4.9%)
  - 15 non-esbuild modules total: 72.00s -> 57.24s (-20.5%)
  - All 16 modules geomean: 2.205s -> 1.646s (-25.4%)
  - All 16 modules total: 453.60s -> 64.83s (-85.7%)
- --rse:
  - esbuild.wasm: >600s (timeout) -> 1.62s (>370x speedup)
  - 15 non-esbuild modules total: 26.40s -> 25.47s (-3.5%)
  - All 16 modules geomean: N/A -> 0.922s (total: 27.09s)
Read each basic block's reverse-postorder index from contents.index in
DomTree instead of allocating and populating an
unordered_map<BasicBlock*, Index>, and skip self-loop backedges
immediately with predIndex >= index. Update OnceReduction and
test/example/domtree.cpp to initialize contents.index, and remove the
redundant index initialization loop in WeakTopologicalOrdering.

Benchmark results across 16 WebAssembly modules (3 iterations,
interleaved):
- --constraint-analysis:
  - Geomean: 1.646s -> 1.576s (-4.3%)
  - Total time: 64.83s -> 62.82s (-3.1%)
- --rse:
  - Geomean: 0.922s -> 0.859s (-6.8%)
  - Total time: 27.09s -> 25.40s (-6.3%)
During reverse-RPO natural loop discovery in WeakTopologicalOrdering,
collapse each discovered loop body into its header using union-find with
path compression, and skip over already-collapsed inner loops when
walking immediate dominators in dominates(). This prevents outer loops
from re-traversing inner loop bodies, bounding natural loop discovery to
O(E alpha(N)) instead of O(N * depth) on deeply nested loops.

Benchmark results across 16 WebAssembly modules (3 iterations,
interleaved):
- --constraint-analysis:
  - Geomean: 1.576s -> 1.564s (-0.7%)
  - Total time: 62.82s -> 62.40s (-0.7%)
- --rse:
  - Geomean: 0.859s -> 0.853s (-0.7%)
  - Total time: 25.40s -> 25.06s (-1.3%)
# Conflicts:
#	test/gtest/wto.cpp
@tlively
tlively requested a review from a team as a code owner October 9, 2026 04:48
@tlively
tlively requested review from aheejin and removed request for a team October 9, 2026 04:48
@tlively

tlively commented Oct 9, 2026 •

Copy link
Copy Markdown
Member Author

This was already reviewed in #9218, which I merged prematurely into the previous PR branch rather than main.

Base automatically changed from domtree-block-indices to main October 9, 2026 17:00
@tlively
tlively merged commit 233ae9c into main Oct 9, 2026
32 checks passed
@tlively
tlively deleted the wto-union-find branch October 9, 2026 17:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant