Use SSA-based TryGetRange to fold conditions#129354
Conversation
|
Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch |
There was a problem hiding this comment.
Pull request overview
This PR extends JIT assertion propagation to opportunistically fold ordered integer relational operators (<, <=, >, >=) to constant true/false using the SSA-based RangeCheck::TryGetRange analysis, and adds a small constant fast-path in TryGetRange itself to make such queries cheaper.
Changes:
- Add a constant fast-path to
RangeCheck::TryGetRangefor int/nint constants that fit inint32. - In
optAssertionPropGlobal_RelOp, when assertion-based range evaluation can’t prove a relop constant, attempt SSA-based operand range discovery viaTryGetRangeand fold when the relop becomes provably constant.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| src/coreclr/jit/rangecheck.cpp | Adds a fast-path for constant expressions in RangeCheck::TryGetRange. |
| src/coreclr/jit/assertionprop.cpp | Adds SSA-based range evaluation to fold certain ordered relops during global assertion propagation. |
|
/azp list |
This comment was marked as resolved.
This comment was marked as resolved.
|
/azp run runtime-coreclr outerloop, runtime-coreclr jitstress, runtime-coreclr libraries-pgo, Fuzzlyn |
|
Azure Pipelines successfully started running 4 pipeline(s). |
…ed type The VNF_Cast handling in RangeCheck::GetRangeFromAssertionsWorker reused the source-type range for any widening cast, assuming the value is preserved. That is wrong when widening a signed source into a smaller-than-int unsigned type (e.g. (ushort)(sbyte)): negative source values are zero-extended into large positive values ((ushort)(-1) == 65535), so the source range no longer bounds the result. The new SSA-based relop folding then folded conditions such as 30997 > (ushort)s_F3 to a wrong constant. Use the destination-type range in that case. Found by Fuzzlyn. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
/azp run Fuzzlyn |
|
Azure Pipelines successfully started running 1 pipeline(s). |
|
PTAL @AndyAyersMS @dotnet/jit-contrib see description |
| // RangeCheck does not understand reads through LCL_FLD nodes: a LCL_FLD use reads a | ||
| // sub-range of the local (a different offset and/or a narrower type), so the value | ||
| // produced by the (full-width) definition does not describe the value being read. | ||
| if (lclUse->OperIs(GT_LCL_FLD)) |
There was a problem hiding this comment.
a correctness issue I found as part of this PR.
| // signed source into a smaller-than-int unsigned type (e.g. (ushort)(sbyte)). There, negative | ||
| // source values are zero-extended into large positive values (e.g. (ushort)(-1) == 65535), so | ||
| // the source range no longer bounds the result. | ||
| bool widensToSmallUnsigned = varTypeIsUnsigned(castToType) && |
There was a problem hiding this comment.
another pre-existing correctness issue we had
| assert(block != nullptr); | ||
| assert(tree != nullptr); | ||
|
|
||
| int budget = 64; |
There was a problem hiding this comment.
How do we arrive at these budget values?
|
/azp run Fuzzlyn |
|
Azure Pipelines successfully started running 1 pipeline(s). |
Diffs (~ -1.2Mb on linux-x64)
We have two ways of computing a
Range {int lo;int hi}for a tree:GetRangeFromAssertions(purely on top of VN and assertions, handles PHIs as well)TryGetRange- SSA-based approach + assertions +GetRangeFromAssertions, used for GT_BOUNDS_CHECK only today.This PR enables
TryGetRangefor folding relops in global assertion prop. The TP Impact is 0.3-0.4% on average, I have some ideas how to improve it inside RangeCheck, but I think it's worth it.Mainly, it helps folding various Span.Slice checks we don't use GT_BOUNDS_CHECK for.
NOTE: we don't set preferred bound yet when we call it, I'll experiment with that separately.