JIT: Add RangeOps::Xor and RangeOps::Not#126553
JIT: Add RangeOps::Xor and RangeOps::Not#126553BoyBaykiller wants to merge 3 commits intodotnet:mainfrom
RangeOps::Xor and RangeOps::Not#126553Conversation
|
Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch |
|
CI is down so we can't see the diffs.
um.. I don't see XOR there - does it appear there after some jit transformation? |
There was a problem hiding this comment.
Pull request overview
This PR updates CoreCLR JIT range analysis to understand xor so that range tightening (and downstream optimizations like branch removal) keep working after the CONST - x → xor x, CONST transformation from #126529.
Changes:
- Add
RangeOps::Xorto compute ranges for a limited set of XOR patterns (constant-folding and^ -1/^ INT_MAX). - Teach
RangeCheck::GetRangeFromAssertionsto compute XOR ranges from VN assertions (VNF_XOR). - Use
RangeOps::XorinRangeCheck::ComputeRangeForBinOpforGT_XOR(while preserving the existing Log2 special-case).
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
src/coreclr/jit/rangecheck.h |
Adds RangeOps::Xor to enable tighter range inference for certain XOR cases. |
src/coreclr/jit/rangecheck.cpp |
Wires XOR into assertion-based range derivation and general binop range computation. |
src/coreclr/jit/rangecheck.h
Outdated
| // x ^ -1 is equivalent to -1 - x | ||
| // x ^ INT_MAX is equivalent to INT_MAX - x | ||
| // Example: [3..5] ^ [-1..-1] = [-6..-4] | ||
| if (r1IsConstVal && (r1ConstVal == -1 || r1ConstVal == INT_MAX)) | ||
| { | ||
| return Subtract(r1, r2); | ||
| } |
There was a problem hiding this comment.
RangeOps::Xor maps the ^ -1 case to Subtract, but Subtract delegates through Negate which returns unknown for constant ranges that include INT_MIN. Since XOR/bitwise-NOT has no overflow semantics, this unnecessarily loses precision for ranges like [INT_MIN..k] ^ [-1..-1]. Consider handling the -1 case directly (e.g., by computing bitwise-NOT of constant limits) so it can still produce a constant range when the input range is constant.
src/coreclr/jit/rangecheck.h
Outdated
| { | ||
| return Subtract(r2, r1); | ||
| } | ||
|
|
There was a problem hiding this comment.
Remove the trailing whitespace on this blank line to satisfy repo formatting/linting expectations.
| case GT_XOR: | ||
| r = RangeOps::Xor(op1Range, op2Range); | ||
| break; |
There was a problem hiding this comment.
This change is meant to prevent a performance regression by allowing range tightening through XOR (e.g., x ^ int.MaxValue) again. Please add a JIT regression test (likely under src/tests/JIT/opt/RangeChecks or similar) that fails without this change and verifies the relevant optimization (e.g., absence of the throw helper / simplified control flow) so future range-analysis tweaks don’t reintroduce the regression.
Yes it gets produced by my other PR which I linked. |
You're touching code |
well, then for now it's just a bunch of untested/never-triggered code without tests? It looks correct to me, although, I think we should make Xor handling a bit smarter than focusing only on -1/maxvalue constants. E.g. the Log2 pattern involves ^ 31/^ 63 - if we can remove special handling for log2 and recognize it naturally.. |
Well my hope is that the other PR gets merged first soon (which is why this is draft for now)
Yeah that'd be nice. But it seems like XOR alone is not enough to handle that. So maybe for an other PR? Although let me see if xor has a more general pattern |
* add Not too
…ssion in System.Data.SqlTypes.SqlDecimal:AdjustScale 114664 libraries.pmi * add Not handling to ComputeRange
RangeOps::XorRangeOps::Xor and RangeOps::Not
Fix multiple regression from #126529.
One example: ParallelEnumerable.Range.
Simplified: