Skip to content

Cranelift: extend alias analysis to eliminate dead stores#13806

Open
fitzgen wants to merge 1 commit into
bytecodealliance:mainfrom
fitzgen:dead-store-elimination
Open

Cranelift: extend alias analysis to eliminate dead stores#13806
fitzgen wants to merge 1 commit into
bytecodealliance:mainfrom
fitzgen:dead-store-elimination

Conversation

@fitzgen

@fitzgen fitzgen commented Jul 2, 2026

Copy link
Copy Markdown
Member

This commit adds an "observed?" bit to every alias region in the alias analysis's LastStores data. Loads from a region set the bit, as do instructions that act as memory fences, like calls. When we see a store to a region that hasn't been observed, and the store is to the same memory location as the last store to that region, then the last store is dead and can be removed. This integrates with alias analysis's existing single forwards pass that is fused with the egraph pass; it doesn't require additional passes or iterations. However, because it is a single pass and not a fixed point, updates do not cascade, and removing a dead store does not then recompute LastStores and reveal that (for example) the dead store's killer is an idempotent store which could also be removed. See the new check-unset-reset-flag.clif filetest, which roughly reflects what component-model fused adapters do with the MAY_LEAVE flag, for an example of this behavior.

Fixes #4167

This commit adds an "observed?" bit to every alias region in the alias
analysis's `LastStores` data. Loads from a region set the bit, as do
instructions that act as memory fences, like calls. When we see a store to a
region that hasn't been observed, and the store is to the same memory location
as the last store to that region, then the last store is dead and can be
removed. This integrates with alias analysis's existing single forwards pass
that is fused with the egraph pass; it doesn't require additional passes or
iterations. However, because it is a single pass and not a fixed point, updates
do not cascade, and removing a dead store does not then recompute `LastStores`
and reveal that (for example) the dead store's killer is an idempotent store
which could also be removed. See the new `check-unset-reset-flag.clif` filetest,
which roughly reflects what component-model fused adapters do with the
`MAY_LEAVE` flag, for an example of this behavior.

Fixes bytecodealliance#4167
@fitzgen fitzgen requested review from a team as code owners July 2, 2026 18:52
@fitzgen fitzgen requested review from alexcrichton and removed request for a team July 2, 2026 18:52
@fitzgen

fitzgen commented Jul 2, 2026

Copy link
Copy Markdown
Member Author

This is a speed up for our compile-time builtins benchmarks, as mentioned here:

increment-each-byte-in-buf/concurrency_support=true/compile-time-builtins-host-buf-api
                        time:   [760.93 µs 763.02 µs 765.31 µs]
                        change: [+0.7952% +1.0940% +1.4500%] (p = 0.00 < 0.05)
                        Change within noise threshold.

increment-random-byte-in-buf/concurrency_support=true/compile-time-builtins-host-buf-api
                        time:   [396.16 ns 397.44 ns 398.85 ns]
                        change: [−12.682% −10.658% −8.7674%] (p = 0.00 < 0.05)
                        Performance has improved.

increment-each-byte-in-buf/concurrency_support=false/compile-time-builtins-host-buf-api
                        time:   [296.47 µs 297.83 µs 299.17 µs]
                        change: [−26.293% −24.048% −21.729%] (p = 0.00 < 0.05)
                        Performance has improved.

increment-random-byte-in-buf/concurrency_support=false/compile-time-builtins-host-buf-api
                        time:   [99.568 ns 99.805 ns 100.05 ns]
                        change: [−25.627% −23.111% −20.554%] (p = 0.00 < 0.05)
                        Performance has improved.

On a PCA-based subset of Sightglass:

  • No statistically significant difference for execution
  • No statistically significant difference for compilation on 15/24 benchmarks
  • Statistically significant compilation slowdowns on 9/24 benchmarks, ranging from 1.0x-1.2x to 1.01x-1.08x
Sightglass results
Finished benchmarking in 00h:12m:58s

compilation :: cycles :: benchmarks/kotlin-richards/kotlin-richards.wasm

  Δ = 14913.90 ± 11273.49 (confidence = 99%)

  main.dylib is 1.01x to 1.08x faster than dse.dylib!

  [301551 351870.08 390568] dse.dylib
  [292431 336956.18 367624] main.dylib

compilation :: cycles :: benchmarks/libsodium/libsodium-sodium_utils2.wasm

  Δ = 11259.46 ± 9154.49 (confidence = 99%)

  main.dylib is 1.01x to 1.08x faster than dse.dylib!

  [241739 274766.10 304721] dse.dylib
  [227971 263506.64 305211] main.dylib

compilation :: cycles :: benchmarks/regex/benchmark.wasm

  Δ = 32952.12 ± 30840.00 (confidence = 99%)

  main.dylib is 1.00x to 1.06x faster than dse.dylib!

  [970289 1035352.48 1438627] dse.dylib
  [943980 1002400.36 1232649] main.dylib

compilation :: cycles :: benchmarks/rust-protobuf/benchmark.wasm

  Δ = 8122.94 ± 7198.78 (confidence = 99%)

  main.dylib is 1.00x to 1.06x faster than dse.dylib!

  [257869 277932.68 324798] dse.dylib
  [247861 269809.74 305491] main.dylib

compilation :: cycles :: benchmarks/spidermonkey/spidermonkey-regex.wasm

  Δ = 313441.64 ± 208711.36 (confidence = 99%)

  main.dylib is 1.01x to 1.04x faster than dse.dylib!

  [12750292 13253845.16 14541050] dse.dylib
  [12534325 12940403.52 14251931] main.dylib

compilation :: cycles :: benchmarks/rust-html-rewriter/benchmark.wasm

  Δ = 18136.88 ± 17507.14 (confidence = 99%)

  main.dylib is 1.00x to 1.04x faster than dse.dylib!

  [963333 1003994.12 1098845] dse.dylib
  [944430 985857.24 1117108] main.dylib

compilation :: cycles :: benchmarks/shootout/shootout-switch.wasm

  Δ = 20047.00 ± 14264.82 (confidence = 99%)

  main.dylib is 1.00x to 1.02x faster than dse.dylib!

  [1520847 1563117.68 1632339] dse.dylib
  [1499991 1543070.68 1599627] main.dylib

compilation :: cycles :: benchmarks/tract-onnx-image-classification/benchmark.wasm

  Δ = 262510.32 ± 164289.72 (confidence = 99%)

  main.dylib is 1.00x to 1.02x faster than dse.dylib!

  [21804152 22232734.92 23028528] dse.dylib
  [21495450 21970224.60 23077832] main.dylib

compilation :: cycles :: benchmarks/hashset/benchmark.wasm

  Δ = 25563.28 ± 18660.26 (confidence = 99%)

  main.dylib is 1.00x to 1.02x faster than dse.dylib!

  [2222646 2281357.80 2374406] dse.dylib
  [2169797 2255794.52 2343737] main.dylib

instantiation :: cycles :: benchmarks/libsodium/libsodium-onetimeauth7.wasm

  No difference in performance.

  [1269 1881.36 5494] dse.dylib
  [1422 1760.06 2264] main.dylib

instantiation :: cycles :: benchmarks/hex-simd/benchmark.wasm

  No difference in performance.

  [1313 1820.08 2677] dse.dylib
  [1472 1917.64 2969] main.dylib

instantiation :: cycles :: benchmarks/rust-html-rewriter/benchmark.wasm

  No difference in performance.

  [2036 2465.42 3994] dse.dylib
  [1909 2585.84 6553] main.dylib

instantiation :: cycles :: benchmarks/libsodium/libsodium-sodium_utils2.wasm

  No difference in performance.

  [1373 1861.58 2697] dse.dylib
  [1456 1777.52 2183] main.dylib

instantiation :: cycles :: benchmarks/cm-online-stats/cm-online-stats.wasm

  No difference in performance.

  [2228 2854.96 4322] dse.dylib
  [2117 2734.44 3505] main.dylib

instantiation :: cycles :: benchmarks/splay/splay.wasm

  No difference in performance.

  [1489 1986.74 2954] dse.dylib
  [1523 1904.84 3232] main.dylib

compilation :: cycles :: benchmarks/tinygo/tinygo-json.wasm

  No difference in performance.

  [1453970 1658897.36 1910534] dse.dylib
  [1343060 1591412.80 1877167] main.dylib

instantiation :: cycles :: benchmarks/spidermonkey/spidermonkey-regex.wasm

  No difference in performance.

  [2817 3216.34 4192] dse.dylib
  [2817 3348.50 5011] main.dylib

instantiation :: cycles :: benchmarks/meshoptimizer/benchmark.wasm

  No difference in performance.

  [1446 1788.92 2349] dse.dylib
  [1531 1846.82 2265] main.dylib

compilation :: cycles :: benchmarks/cm-online-stats/cm-online-stats.wasm

  No difference in performance.

  [64689 74000.16 83595] dse.dylib
  [62536 76361.92 323740] main.dylib

compilation :: cycles :: benchmarks/quicksort/benchmark.wasm

  No difference in performance.

  [196717 223366.08 248556] dse.dylib
  [195536 216784.46 250824] main.dylib

compilation :: cycles :: benchmarks/bz2/benchmark.wasm

  No difference in performance.

  [414079 462718.52 509915] dse.dylib
  [406949 449318.56 511436] main.dylib

instantiation :: cycles :: benchmarks/rust-protobuf/benchmark.wasm

  No difference in performance.

  [1504 1965.40 2699] dse.dylib
  [1515 1913.04 2567] main.dylib

instantiation :: cycles :: benchmarks/blake3-scalar/benchmark.wasm

  No difference in performance.

  [1444 1901.52 2644] dse.dylib
  [1542 1950.04 2659] main.dylib

instantiation :: cycles :: benchmarks/shootout/shootout-switch.wasm

  No difference in performance.

  [1372 1634.40 2208] dse.dylib
  [1332 1675.20 2204] main.dylib

instantiation :: cycles :: benchmarks/shootout/shootout-random.wasm

  No difference in performance.

  [1287 1768.64 2418] dse.dylib
  [1368 1729.40 2601] main.dylib

compilation :: cycles :: benchmarks/sqlite3/sqlite3.wasm

  No difference in performance.

  [2028978 2150582.12 2426111] dse.dylib
  [1992886 2103457.22 2361924] main.dylib

compilation :: cycles :: benchmarks/splay/splay.wasm

  No difference in performance.

  [40752 50227.08 65703] dse.dylib
  [41510 49142.34 80924] main.dylib

instantiation :: cycles :: benchmarks/rust-compression/benchmark.wasm

  No difference in performance.

  [3236 3782.54 4717] dse.dylib
  [3325 3864.02 5487] main.dylib

instantiation :: cycles :: benchmarks/regex/benchmark.wasm

  No difference in performance.

  [2343 2897.28 4140] dse.dylib
  [2321 2840.90 3979] main.dylib

execution :: cycles :: benchmarks/libsodium/libsodium-onetimeauth7.wasm

  No difference in performance.

  [131143 137337.38 150095] dse.dylib
  [131473 140004.64 152778] main.dylib

instantiation :: cycles :: benchmarks/hashset/benchmark.wasm

  No difference in performance.

  [1661 1939.42 2366] dse.dylib
  [1670 1904.18 2322] main.dylib

execution :: cycles :: benchmarks/hashset/benchmark.wasm

  No difference in performance.

  [364284 383346.66 430711] dse.dylib
  [367406 390113.94 437923] main.dylib

instantiation :: cycles :: benchmarks/shootout/shootout-keccak.wasm

  No difference in performance.

  [1356 1682.50 2233] dse.dylib
  [1375 1654.66 2407] main.dylib

execution :: cycles :: benchmarks/quicksort/benchmark.wasm

  No difference in performance.

  [216322 237900.00 258167] dse.dylib
  [214027 234091.34 262504] main.dylib

execution :: cycles :: benchmarks/meshoptimizer/benchmark.wasm

  No difference in performance.

  [75675 79689.82 85614] dse.dylib
  [75515 80746.90 86866] main.dylib

compilation :: cycles :: benchmarks/hex-simd/benchmark.wasm

  No difference in performance.

  [193538 214353.42 266493] dse.dylib
  [188717 211563.14 258833] main.dylib

compilation :: cycles :: benchmarks/shootout/shootout-minicsv.wasm

  No difference in performance.

  [40587 46959.44 55809] dse.dylib
  [41479 46364.46 67529] main.dylib

compilation :: cycles :: benchmarks/shootout/shootout-keccak.wasm

  No difference in performance.

  [387820 421629.22 474935] dse.dylib
  [390590 426937.38 464010] main.dylib

instantiation :: cycles :: benchmarks/libsodium/libsodium-scalarmult_ed25519.wasm

  No difference in performance.

  [1521 2032.48 3011] dse.dylib
  [1483 2008.26 2869] main.dylib

execution :: cycles :: benchmarks/shootout/shootout-keccak.wasm

  No difference in performance.

  [68304 72161.40 76890] dse.dylib
  [69138 72965.48 78470] main.dylib

compilation :: cycles :: benchmarks/rust-compression/benchmark.wasm

  No difference in performance.

  [1142122 1741647.68 2082353] dse.dylib
  [1142814 1760990.44 2013696] main.dylib

instantiation :: cycles :: benchmarks/kotlin-richards/kotlin-richards.wasm

  No difference in performance.

  [3420 4276.56 5723] dse.dylib
  [3516 4322.76 7282] main.dylib

instantiation :: cycles :: benchmarks/tract-onnx-image-classification/benchmark.wasm

  No difference in performance.

  [34874 42264.54 57053] dse.dylib
  [34251 42704.50 63048] main.dylib

execution :: cycles :: benchmarks/rust-compression/benchmark.wasm

  No difference in performance.

  [158340 166201.44 191822] dse.dylib
  [158476 167888.06 177944] main.dylib

instantiation :: cycles :: benchmarks/sqlite3/sqlite3.wasm

  No difference in performance.

  [2010 2319.86 2837] dse.dylib
  [1904 2342.14 3099] main.dylib

compilation :: cycles :: benchmarks/blake3-scalar/benchmark.wasm

  No difference in performance.

  [190639 230120.58 283396] dse.dylib
  [199892 227969.50 303630] main.dylib

execution :: cycles :: benchmarks/kotlin-richards/kotlin-richards.wasm

  No difference in performance.

  [444643 463732.58 482387] dse.dylib
  [449079 468074.72 491842] main.dylib

instantiation :: cycles :: benchmarks/tinygo/tinygo-json.wasm

  No difference in performance.

  [1653 2113.88 3052] dse.dylib
  [1793 2096.16 3172] main.dylib

execution :: cycles :: benchmarks/splay/splay.wasm

  No difference in performance.

  [44587672 45155858.02 47174850] dse.dylib
  [44761966 45434209.28 47298269] main.dylib

compilation :: cycles :: benchmarks/shootout/shootout-random.wasm

  No difference in performance.

  [189936 208566.76 234468] dse.dylib
  [184041 207320.00 234296] main.dylib

execution :: cycles :: benchmarks/libsodium/libsodium-scalarmult_ed25519.wasm

  No difference in performance.

  [63755 68012.82 71741] dse.dylib
  [63893 68418.42 76321] main.dylib

compilation :: cycles :: benchmarks/libsodium/libsodium-onetimeauth7.wasm

  No difference in performance.

  [253475 286339.86 369066] dse.dylib
  [249413 284748.24 320236] main.dylib

execution :: cycles :: benchmarks/shootout/shootout-switch.wasm

  No difference in performance.

  [815544 838446.92 863197] dse.dylib
  [812779 842966.12 874425] main.dylib

instantiation :: cycles :: benchmarks/shootout/shootout-minicsv.wasm

  No difference in performance.

  [1291 1664.46 2279] dse.dylib
  [1336 1656.94 2295] main.dylib

instantiation :: cycles :: benchmarks/bz2/benchmark.wasm

  No difference in performance.

  [1532 1879.10 2385] dse.dylib
  [1454 1870.90 2519] main.dylib

execution :: cycles :: benchmarks/rust-protobuf/benchmark.wasm

  No difference in performance.

  [201520 213823.90 231508] dse.dylib
  [201450 212934.06 243603] main.dylib

execution :: cycles :: benchmarks/cm-online-stats/cm-online-stats.wasm

  No difference in performance.

  [10449954 10705319.54 11151990] dse.dylib
  [10514805 10748090.08 11208289] main.dylib

execution :: cycles :: benchmarks/hex-simd/benchmark.wasm

  No difference in performance.

  [65938 70924.48 98382] dse.dylib
  [64564 70653.40 89504] main.dylib

instantiation :: cycles :: benchmarks/quicksort/benchmark.wasm

  No difference in performance.

  [1474 1800.20 2507] dse.dylib
  [1441 1793.84 2453] main.dylib

execution :: cycles :: benchmarks/bz2/benchmark.wasm

  No difference in performance.

  [110230 117605.04 125873] dse.dylib
  [113169 117967.76 142068] main.dylib

execution :: cycles :: benchmarks/shootout/shootout-minicsv.wasm

  No difference in performance.

  [7148613 7333797.64 7632231] dse.dylib
  [7119934 7354849.84 7645026] main.dylib

execution :: cycles :: benchmarks/regex/benchmark.wasm

  No difference in performance.

  [95889 98818.38 108010] dse.dylib
  [95064 98550.76 102502] main.dylib

execution :: cycles :: benchmarks/blake3-scalar/benchmark.wasm

  No difference in performance.

  [92550 98629.78 108287] dse.dylib
  [92312 98363.70 106838] main.dylib

execution :: cycles :: benchmarks/tract-onnx-image-classification/benchmark.wasm

  No difference in performance.

  [3854443 3930013.78 4086243] dse.dylib
  [3873545 3938115.28 4107499] main.dylib

execution :: cycles :: benchmarks/shootout/shootout-random.wasm

  No difference in performance.

  [3344464 3435485.56 3570093] dse.dylib
  [3324341 3428700.84 3604256] main.dylib

execution :: cycles :: benchmarks/rust-html-rewriter/benchmark.wasm

  No difference in performance.

  [146798 151977.58 157691] dse.dylib
  [147479 151692.08 156738] main.dylib

execution :: cycles :: benchmarks/sqlite3/sqlite3.wasm

  No difference in performance.

  [14218916 14415792.74 15383184] dse.dylib
  [14197184 14434728.14 15175099] main.dylib

compilation :: cycles :: benchmarks/meshoptimizer/benchmark.wasm

  No difference in performance.

  [367176 400341.12 437304] dse.dylib
  [362980 399916.12 432478] main.dylib

compilation :: cycles :: benchmarks/libsodium/libsodium-scalarmult_ed25519.wasm

  No difference in performance.

  [340288 380227.20 526483] dse.dylib
  [339950 380512.48 518440] main.dylib

execution :: cycles :: benchmarks/spidermonkey/spidermonkey-regex.wasm

  No difference in performance.

  [66098 68167.70 71128] dse.dylib
  [66336 68190.04 71532] main.dylib

execution :: cycles :: benchmarks/tinygo/tinygo-json.wasm

  No difference in performance.

  [119820 125794.90 129823] dse.dylib
  [122013 125824.44 136271] main.dylib

I can look into speeding things up a bit more, but we should probably discuss this at the next Cranelift meeting.

@alexcrichton alexcrichton requested review from cfallin and removed request for a team and alexcrichton July 2, 2026 19:31
@alexcrichton

Copy link
Copy Markdown
Member

I'm going to move this to being reviewed by @cfallin who I know is on PTO right now but I think will have sufficiently more context about this that he'll do a much better job than I

@cfallin

cfallin commented Jul 2, 2026

Copy link
Copy Markdown
Member

(happy to do so; logistical note that I'm out on PTO this week and next, then traveling-for-work the following week, so I can't guarantee I'll get to this before Mon Jul 20)

@github-actions github-actions Bot added the cranelift Issues related to the Cranelift code generator label Jul 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cranelift Issues related to the Cranelift code generator

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Cranelift: eliminate dead stores

3 participants