fix(#278,#281): preserve traps in operand-discarding folds (zero-annihilation + constant-condition select)#280
Open
avrabe wants to merge 2 commits into
Open
fix(#278,#281): preserve traps in operand-discarding folds (zero-annihilation + constant-condition select)#280avrabe wants to merge 2 commits into
avrabe wants to merge 2 commits into
Conversation
Gate x*0/0*x/x&0 (and other operand-discarding identities) on the discarded operand being trap-free (is_no_trap), so an OOB load / div / other trapping op inside the annihilated operand is preserved instead of silently deleted. Fixes: #278 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…rded-arm trap-freedom The #278 trap-free negative/positive suite drove its `optimize()` helper through `optimize_fused_module`, the component-fusion pipeline (adapter devirt / dedup / DCE) — which never runs the algebraic simplifier, so the zero-annihilation / absorption / constant-condition-`select` folds it meant to exercise were NEVER applied. That made `t278_trap_free_mul_by_zero_still_folds_to_zero` fail (the trap-free `(local.get 0)*0` was left un-folded) while the trapping cases passed only vacuously (nothing was optimized). Point the helper at `constant_folding`, the pass that drives ISLE `rewrite_pure` over the term IR where the `is_no_trap_expr`-gated folds live. Now: - trap-free operand-discards (`(local.get 0)*0`, const*0, …) DO fold to the absorbing constant, and - may-trap operands (OOB load, div-by-zero) still block the fold — the #278 negative cases stay green (function-with-load is skipped / Z3-rejected, so the trapping op survives). #281 (5th trap-drop): WASM `select` is eager — both value operands are evaluated before the condition (Core §4.4.1) — so folding `select(const, a, b)` to the taken arm silently deletes a trap in the DISCARDED arm. The constant-condition select fold in `loom-shared` `rewrite_pure` is already gated on the discarded arm being `is_no_trap_expr` (the same predicate as #278); add end-to-end regression coverage in `issue_281_select_trap.rs`: the discarded OOB-load / div arm is preserved (optimized module still traps in wasmtime) with the trapping op on EITHER side, and a trap-free discarded arm STILL folds to the taken arm. Fixes: #278 Fixes: #281 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #278. Fixes #281. Two trap-elimination miscompiles of the operand-discarding class.
#278 —
x*0→0/0*x→0/x&0→0discarded a trapping operand (OOB load, div). #281 — constant-conditionselect(const,a,b)dropped the non-taken arm (WASM select is EAGER — both arms evaluated). Both are gated on the discarded operand/arm being trap-free (is_no_trap_expr, reused not duplicated): trap-free operands still fold; may-trap operands keep the op so the trap is preserved.Verified behaviorally via wasmtime (trap outcome matches original) on both arms for select, and OOB-load / div-by-zero for annihilation. #278 suite 9 green, #281 suite 5 green, full workspace green, clippy clean. (Note: the earlier test harness ran the fusion pipeline which never applies these folds — repointed to
constant_foldingso the tests actually exercise + prove the gates.)Last of the per-identity trap stopgaps — the systemic cure is loom#279 (v1.2.1). Folds into v1.2.0.