Stream: git-wasmtime

Topic: wasmtime / PR #13806 Cranelift: extend alias analysis to ...


view this post on Zulip Wasmtime GitHub notifications bot (Jul 02 2026 at 18:52):

fitzgen opened PR #13806 from fitzgen:dead-store-elimination to bytecodealliance:main:

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 https://github.com/bytecodealliance/wasmtime/issues/4167

<!--
Please make sure you include the following information:

Our development process is documented in the Wasmtime book:
https://docs.wasmtime.dev/contributing-development-process.html

Please ensure all communication follows the code of conduct:
https://github.com/bytecodealliance/wasmtime/blob/main/CODE_OF_CONDUCT.md
-->

view this post on Zulip Wasmtime GitHub notifications bot (Jul 02 2026 at 18:52):

fitzgen requested alexcrichton for a review on PR #13806.

view this post on Zulip Wasmtime GitHub notifications bot (Jul 02 2026 at 18:52):

fitzgen requested wasmtime-compiler-reviewers for a review on PR #13806.

view this post on Zulip Wasmtime GitHub notifications bot (Jul 02 2026 at 18:52):

fitzgen requested wasmtime-core-reviewers for a review on PR #13806.

view this post on Zulip Wasmtime GitHub notifications bot (Jul 02 2026 at 19:02):

fitzgen commented on PR #13806:

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:

<details>

<summary>Sightglass results</summary>

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

instantiatio
[message truncated]

view this post on Zulip Wasmtime GitHub notifications bot (Jul 02 2026 at 19:31):

alexcrichton requested cfallin for a review on PR #13806.

view this post on Zulip Wasmtime GitHub notifications bot (Jul 02 2026 at 19:31):

alexcrichton unassigned alexcrichton from PR #13806 Cranelift: extend alias analysis to eliminate dead stores.

view this post on Zulip Wasmtime GitHub notifications bot (Jul 02 2026 at 19:32):

alexcrichton commented on PR #13806:

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

view this post on Zulip Wasmtime GitHub notifications bot (Jul 02 2026 at 19:58):

cfallin commented on PR #13806:

(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)

view this post on Zulip Wasmtime GitHub notifications bot (Jul 02 2026 at 21:04):

github-actions[bot] added the label cranelift on PR #13806.

view this post on Zulip Wasmtime GitHub notifications bot (Jul 20 2026 at 18:37):

:thumbs_up: cfallin submitted PR review:

This looks correct to me -- thanks for the really careful work here!

A few points below but nothing fundamental.

view this post on Zulip Wasmtime GitHub notifications bot (Jul 20 2026 at 18:37):

:speech_balloon: cfallin created PR review comment:

minor subjective point but although compiler jargon can be pretty... forceful... at times, it might be a little nicer to read to call the "killer" something like shadower or overwriter? :-)

view this post on Zulip Wasmtime GitHub notifications bot (Jul 20 2026 at 18:37):

:speech_balloon: cfallin created PR review comment:

What happens if the shadowing ("killing") store had a conflicting trap code? Do we avoid that by construction in alias analysis by not deciding to merge (we don't actually shadow if the trap-code is different)? Should we assert the trap-code is the same here?

(One way to get that behavior in alias analysis if we don't already is to make the trap-code a field in the last-store tuple in the carried flow-sensitive state)

And actually, if we do match in that way, then I believe we don't need memflags_mut anymore, nor this logic. I believe "trap code must match" should cover all of our desired dead-store cases?

view this post on Zulip Wasmtime GitHub notifications bot (Jul 20 2026 at 18:37):

:speech_balloon: cfallin created PR review comment:

Any reason that this moved out of inst_predicates? It seems more natural to me to put it there; it's better not to have a distributed set of opcode sets throughout the code, IMHO, rather than reading through that module when we add a new opcode. (Lack of fallthrough to enforce consideration would be best but that's not practical on predicates like this imho)

view this post on Zulip Wasmtime GitHub notifications bot (Jul 20 2026 at 18:37):

:speech_balloon: cfallin created PR review comment:

To clarify the comment (because this sounds a little bit like a handwave "too complex" case or something): when we have both can_store() and can_load(), the expected semantics are that the load happens before the store, so the last store is in fact observed (just-in-time, right before processing the store effect). That's why we skip in this case, just as we skip when observed.

view this post on Zulip Wasmtime GitHub notifications bot (Jul 20 2026 at 18:37):

:speech_balloon: cfallin created PR review comment:

Noting that this now falls through and invokes AliasAnalysis::process_inst on instructions that are is_mergeable_for_egraph, which includes all non-loads/stores as well -- is that intentional? I believe that anything with memory semantics cannot be is_mergeable_for_egraph so we shouldn't need to see these ops / spend time processing them in AliasAnalysis IMHO.

view this post on Zulip Wasmtime GitHub notifications bot (Jul 20 2026 at 20:35):

fitzgen commented on PR #13806:

Regarding the compilation hit that this PR implies: I have a handful of optimizations that I will start making PRs for that recover that compile time in other areas.

view this post on Zulip Wasmtime GitHub notifications bot (Jul 20 2026 at 22:17):

:memo: cfallin submitted PR review.

view this post on Zulip Wasmtime GitHub notifications bot (Jul 20 2026 at 22:17):

:speech_balloon: cfallin created PR review comment:

Talked with Nick offline to learn more about this one -- (i) this is within the context of skeleton optimization, and (ii) it's indeed needed to see all possibly-trapping ops because those observe alias regions. So this is fine I think.

view this post on Zulip Wasmtime GitHub notifications bot (Jul 20 2026 at 22:20):

cfallin commented on PR #13806:

One point to track as a followup further improvement, possibly: if we have a mode (enforced by Wasmtime API) that ensures that the Store no longer exposes state after a trap occurs (i.e., disallows reads from memories/tables/globals), we could then set a bit on an alias-region definition stating trap_unobservable, and then we could avoid "observing" (and making live) any trap-unobservable stores. This might be a nice performance improvement wherever one runs a Wasm component in the (frankly most common) case that the driver throws away the store upon trap...

view this post on Zulip Wasmtime GitHub notifications bot (Jul 21 2026 at 19:24):

:memo: fitzgen submitted PR review.

view this post on Zulip Wasmtime GitHub notifications bot (Jul 21 2026 at 19:24):

:speech_balloon: fitzgen created PR review comment:

It wasn't used elsewhere so I figured moving it closer to where it was used was nice for easy cross-checking. That and the subtleties involved in the LastStores::update method involving things like can_trap not including loads/stores that can trap, but that this actually being what we want in certain cases but not others, etc and it just felt easier for me to have it all in one place I could look at altogether. That said, I don't mind moving it back (and presumably also the alias_regions_observed function, in that case) if you prefer.

view this post on Zulip Wasmtime GitHub notifications bot (Jul 21 2026 at 19:50):

:memo: fitzgen submitted PR review.

view this post on Zulip Wasmtime GitHub notifications bot (Jul 21 2026 at 19:50):

:speech_balloon: fitzgen created PR review comment:

What we do is the following:

Dead store's trap code Overwriting store's initial trap code Overwriting store's final trap code
None None None
None Some(c) Some(c) (arbitrary choice; see below)
Some(c) Some(c) Some(c)
Some(c1) Some(c2) Some(c1)
Some(c) None Some(c)

Also note that we have filetests for each of these cases.

Do we avoid that by construction in alias analysis by not deciding to merge (we don't actually shadow if the trap-code is different)? Should we assert the trap-code is the same here?

We will merge even when the trap code is different (as described just above). We could conservatively not do DSE if they do not match, but I think it is fine because if either store will trap, then when running the non-DSE version of the code, it would have trapped with with the dead store's code and not the overwriter's code. Anything that changes that, so that after the dead store didn't trap we could then see the overwriter trap, must be a memory fence (e.g. a call to the host) and we won't DSE it anyways. So that's why we always prefer the dead store's trap code, when it exists.

What about when the dead store doesn't have a trap code but the overwriter does? This is an arbitrary choice because, as we just reasoned through, the dead store and the overwriting store have the exact same "trappability" (anything that can change their trappability must be a memory fence). So the dead store not having a trap code is the CLIF producer saying, by contract, that the dead store cannot trap which means that the overwriting store cannot trap either. And therefore, it doesn't matter what the overwriter's trap code is because it will never trap. So maybe it is morally more correct to remove the trap code from the overwriter, but leaving it felt a little more conservative.

Thoughts?

view this post on Zulip Wasmtime GitHub notifications bot (Jul 21 2026 at 19:51):

:speech_balloon: fitzgen edited PR review comment.

view this post on Zulip Wasmtime GitHub notifications bot (Jul 21 2026 at 20:27):

fitzgen updated PR #13806.

view this post on Zulip Wasmtime GitHub notifications bot (Jul 21 2026 at 21:20):

fitzgen updated PR #13806.

view this post on Zulip Wasmtime GitHub notifications bot (Jul 21 2026 at 21:39):

:memo: cfallin submitted PR review.

view this post on Zulip Wasmtime GitHub notifications bot (Jul 21 2026 at 21:39):

:speech_balloon: cfallin created PR review comment:

Ah, OK, yes, that makes it really clear, thanks. I would summarize it as: one of the three cases will occur:

There's one pretty subtle bit here though (at least, it was for me): we check that the second store post-doms the first (so first executing implies second executing); but we do NOT directly check that first store doms the second (so second executing implies first executing). The latter is what we relied on above: otherwise, say we have a diamond, and only one branch has a store that is shadowed by a store after the join-point (making the ultimately trapping store and its code conditional on runtime state). The thing that prevents this is that the analysis itself has a meet-function that intersects conservatively, so at the join-point, we will say "unknown last store" in that case. Effectively we're computing dominance (of last store on current point) by iterative dataflow analysis.

I think we should document that reasoning since it's pretty subtle -- trap trap code is not just "best effort" here, we should uphold a "as-if" guarantee as with any optimization.

One other thing: the identity of the trapping store may be important too, right? E.g. in Wasm, we should provide an accurate backtrace pointing to the PC that faults. Do we mark all stores that come from Wasm as somehow not dead-store-mergeable?

(Realizing and writing that last paragraph makes me realize: perhaps this should only apply to notrap stores, making all of the above moot?)

view this post on Zulip Wasmtime GitHub notifications bot (Jul 21 2026 at 21:40):

:speech_balloon: cfallin edited PR review comment.

view this post on Zulip Wasmtime GitHub notifications bot (Jul 21 2026 at 21:51):

:memo: fitzgen submitted PR review.

view this post on Zulip Wasmtime GitHub notifications bot (Jul 21 2026 at 21:51):

:speech_balloon: fitzgen created PR review comment:

One other thing: the _identity_ of the trapping store may be important too, right? E.g. in Wasm, we should provide an accurate backtrace pointing to the PC that faults. Do we mark all stores that come from Wasm as somehow not dead-store-mergeable?

(Realizing and writing that last paragraph makes me realize: perhaps this should only apply to notrap stores, making all of the above moot?)

The identity of the trapping store, the backtrace, etc... is not part of the Wasm spec, it is something we preserve on a best-effort basis, similar to other optimizations and their handling of debug source locations.

We specifically do _not_ want to ignore Wasm stores in this optimization because the component-model adapters that motivate this optimization's addition are themselves Wasm functions!

view this post on Zulip Wasmtime GitHub notifications bot (Jul 21 2026 at 21:54):

:memo: cfallin submitted PR review.

view this post on Zulip Wasmtime GitHub notifications bot (Jul 21 2026 at 21:54):

:speech_balloon: cfallin created PR review comment:

Ah! Yes, that's a good point, I had forgotten about the compilation path with FACT via Wasm.

OK, this does make me think, though: the Debug API more or less promises a view of Wasm execution semantics as-if stepping through the interpreter; so we really do need a flag indicating "individually visible" / "semantically meaningful PC if I trap" / ... on all Wasm-origin stores when guest-debugging instrumentation is enabled. (I'd prefer not to just disable the optimization -- we should get the IR semantics clear, either trap location is an output or it is not for a given op, then we should encode what we want, IMHO.)

view this post on Zulip Wasmtime GitHub notifications bot (Jul 21 2026 at 22:07):

:memo: fitzgen submitted PR review.

view this post on Zulip Wasmtime GitHub notifications bot (Jul 21 2026 at 22:07):

:speech_balloon: fitzgen created PR review comment:

OK, this does make me think, though: the Debug API more or less promises a view of Wasm execution semantics as-if stepping through the interpreter; so we really do need a flag indicating "individually visible" / "semantically meaningful PC if I trap" / ... on all Wasm-origin stores when guest-debugging instrumentation is enabled. (I'd prefer not to just disable the optimization -- we should get the IR semantics clear, either trap location is an output or it is not for a given op, then we should encode what we want, IMHO.)

We treat the sequence_point instructions as memory fences, so I think the desired behavior should naturally fall out from that, no?

view this post on Zulip Wasmtime GitHub notifications bot (Jul 21 2026 at 22:11):

:memo: fitzgen submitted PR review.

view this post on Zulip Wasmtime GitHub notifications bot (Jul 21 2026 at 22:11):

:speech_balloon: fitzgen created PR review comment:

There's one pretty subtle bit here though (at least, it was for me): we check that the second store post-doms the first (so first executing implies second executing); but we do _NOT_ directly check that first store doms the second (so second executing implies first executing). The latter is what we relied on above: otherwise, say we have a diamond, and only one branch has a store that is shadowed by a store after the join-point (making the ultimately trapping store and its code _conditional_ on runtime state). The thing that prevents this is that the analysis itself has a meet-function that intersects conservatively, so at the join-point, we will say "unknown last store" in that case. Effectively we're computing dominance (of last store on current point) by iterative dataflow analysis.

This subtlety is actually pushing me back towards your original suggestion of requiring the trap codes to match. In practice, having different trap codes for a dead store and its overwriter seems really rare, and isn't something that Wasmtime's translation will ever produce, for example.

view this post on Zulip Wasmtime GitHub notifications bot (Jul 21 2026 at 22:20):

:memo: cfallin submitted PR review.

view this post on Zulip Wasmtime GitHub notifications bot (Jul 21 2026 at 22:20):

:speech_balloon: cfallin created PR review comment:

We treat the sequence_point instructions as memory fences, so I think the desired behavior should naturally fall out from that, no?

Ah, great point! Forgetfulness of old age strikes again; yes, last-year-me made sure that we do the right thing here. Thanks.

view this post on Zulip Wasmtime GitHub notifications bot (Jul 21 2026 at 22:34):

fitzgen updated PR #13806.

view this post on Zulip Wasmtime GitHub notifications bot (Jul 21 2026 at 23:26):

:memo: cfallin submitted PR review.

view this post on Zulip Wasmtime GitHub notifications bot (Jul 21 2026 at 23:27):

:speech_balloon: cfallin created PR review comment:

I guess it's just a matter of taste and I don't feel too strongly, so this seems fine too; thanks.

view this post on Zulip Wasmtime GitHub notifications bot (Jul 22 2026 at 20:06):

fitzgen commented on PR #13806:

We talked about this a bit at today's Cranelift meeting and the conclusion was to go ahead and merge; I'll also have a couple more perf follow ups soon.

view this post on Zulip Wasmtime GitHub notifications bot (Jul 22 2026 at 20:06):

fitzgen added PR #13806 Cranelift: extend alias analysis to eliminate dead stores to the merge queue.

view this post on Zulip Wasmtime GitHub notifications bot (Jul 22 2026 at 20:34):

github-merge-queue[bot] removed PR #13806 Cranelift: extend alias analysis to eliminate dead stores from the merge queue.

view this post on Zulip Wasmtime GitHub notifications bot (Jul 23 2026 at 00:01):

fitzgen added PR #13806 Cranelift: extend alias analysis to eliminate dead stores to the merge queue.

view this post on Zulip Wasmtime GitHub notifications bot (Jul 23 2026 at 00:26):

:check: fitzgen merged PR #13806.

view this post on Zulip Wasmtime GitHub notifications bot (Jul 23 2026 at 00:26):

fitzgen removed PR #13806 Cranelift: extend alias analysis to eliminate dead stores from the merge queue.


Last updated: Jul 29 2026 at 05:03 UTC