Fix subtle ISLE extractor issue leading to incorrect matching in *mul_overflow lowering. - #14295
Open
cfallin wants to merge 1 commit into
Open
Fix subtle ISLE extractor issue leading to incorrect matching in *mul_overflow lowering.#14295cfallin wants to merge 1 commit into
*mul_overflow lowering.#14295cfallin wants to merge 1 commit into
Conversation
…l_overflow` lowering. In bytecodealliance#14293, a test case that uses the *first* result (i.e., the product) of an `smul_overflow` operator as a condition (e.g. as part of `icmp eq` comparing to zero) incorrectly triggers the lowering rule I added in bytecodealliance#14254 which was meant to match only compare-to-zero on the *second* (overflow) result. This was a result if a fairly subtle issue involving auto-conversions in ISLE. I had written ``` (rule (is_nonzero (second_result umul @ (smul_overflow ...))) ...) ``` where the intent was to match an `is_nonzero` (which is a helper term) lowering with the second result (overflow flag) of the `smul_overflow`. `second_result` has a term signature `(Value) Inst`, in other words it takes an `Inst` and returns an `Option<Value>`.` `is_nonzero` takes a `Value`. So we auto-convert the `Value` in the first arg position of `is_nonzer` to an `Inst`; that uses `def_inst`, which looks up the defining instruction of the given value. Then `second_result` takes that `Inst` and gives the second value. But then the next level, `(smul_overflow ...)`, *again* uses `def_inst` and goes from the (second result) `Value` back to the inst and matches. In other words, we're too permissive with the autoconversions on `Value` to `Inst`; all of this was designed at a time when we more or less only handled single-result instructions with any nontrivial lowering rule, so the two were mostly interchangeable. The handling for the overflow-flag ops changes that. The specific step in that chain above that is unambiguously wrong wrt intent is (first result) `Value` -> `Inst` -> `second_result` matching. So this PR instead introduces `is_second_result` that is `Value` -> `Option<Value>` and matches only when the specific `Value` is the second result of an instruction. This does have me thinking a bit more about the role that the `Value` -> `Inst` autoconvert matching plays. It is absolutely essential to the ergonomics of ISLE: without it, we couldn't write ``` (rule (lower (iadd (imul a b) c)) ...) ``` because `iadd`'s args are `Value`s and we need to match back to an `Inst` for `imul`. *But* we also have cases like the one in this PR where we really shouldn't be so permissive. Perhaps we want a kind of type modifier (`=Value` ?) that means "exactly this type, not autoconverted". I'll bring this up in the Cranelift meeting this week. Fixes bytecodealliance#14293.
Member
|
I don't really understand what's going on here, and I also didn't catch this in prior review, so I'm going to swap in @fitzgen |
alexcrichton
requested review from
fitzgen
and removed request for
alexcrichton
September 8, 2026 14:30
fitzgen
approved these changes
Sep 8, 2026
Comment on lines
+219
to
+227
| let is_match = self | ||
| .lower_ctx | ||
| .dfg() | ||
| .inst_results(inst) | ||
| .iter() | ||
| .skip(1) | ||
| .next() | ||
| .copied() | ||
| == Some(val); |
Member
There was a problem hiding this comment.
self.lower_ctx.dfg().inst_results(inst).get(1) == Some(&val) is a little shorter and more clear to me
Member
There was a problem hiding this comment.
Seems like we could probably minimize this test case a bit
Comment on lines
+305
to
+310
| ;; Be careful using this: if used to match on a *`Value`*, the | ||
| ;; auto-converter will take that `Value` to its defining `Inst`, then | ||
| ;; the inner result of this extractor will be the second def of the | ||
| ;; value; in other words, it will *fetch* the second result but will | ||
| ;; not *assert/only match if* the initial `Value` is the second | ||
| ;; result. Use `is_second_result` for that. |
Member
There was a problem hiding this comment.
Do we still even want to have second_result? Is anything still using it that couldn't move to is_second_result?
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.
In #14293, a test case that uses the first result (i.e., the product) of an
smul_overflowoperator as a condition (e.g. as part oficmp eqcomparing to zero) incorrectly triggers the lowering rule I added in #14254 which was meant to match only compare-to-zero on the second (overflow) result.This was a result of a fairly subtle issue involving auto-conversions in ISLE. I had written
where the intent was to match an
is_nonzero(which is a helper term) lowering with the second result (overflow flag) of thesmul_overflow.second_resulthas a term signature(Value) Inst, in other words it takes anInstand returns anOption<Value>.is_nonzerotakes aValue. So we auto-convert theValuein the first arg position ofis_nonzerto anInst; that usesdef_inst, which looks up the defining instruction of the given value. Thensecond_resulttakes thatInstand gives the second value. But then the next level,(smul_overflow ...), again usesdef_instand goes from the (second result)Valueback to the inst and matches.In other words, we're too permissive with the autoconversions on
ValuetoInst; all of this was designed at a time when we more or less only handled single-result instructions with any nontrivial lowering rule, so the two were mostly interchangeable. The handling for the overflow-flag ops changes that.The specific step in that chain above that is unambiguously wrong wrt intent is (first result)
Value->Inst->second_resultmatching. So this PR instead introducesis_second_resultthat isValue->Option<Value>and matches only when the specificValueis the second result of an instruction.This does have me thinking a bit more about the role that the
Value->Instautoconvert matching plays. It is absolutely essential to the ergonomics of ISLE: without it, we couldn't writebecause
iadd's args areValues and we need to match back to anInstforimul. But we also have cases like the one in this PR where we really shouldn't be so permissive. Perhaps we want a kind of type modifier (=Value?) that means "exactly this type, not autoconverted". I'll bring this up in the Cranelift meeting this week.Fixes #14293.