JIT: fold relop on ADD(base, 1) using base-vs-other assertion#128101
JIT: fold relop on ADD(base, 1) using base-vs-other assertion#128101EgorBo wants to merge 6 commits into
Conversation
|
Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch |
1aae4b7 to
812bcc3
Compare
There was a problem hiding this comment.
Pull request overview
This PR enhances CoreCLR JIT range-check elimination by using existing relational assertions to fold comparisons involving ADD(base, 1) (e.g., enabling removal of redundant ReadOnlySpan<T>.Slice(offset + 1) bounds checks when guarded by (uint)offset < (uint)len).
Changes:
- Add a new JIT regression test covering the
Slice(offset + 1)pattern and asserting no remaining range-check-fail helper in the generated code. - Extend
RangeCheck::GetRangeFromAssertionsWorkerto fold certainADD(base, 1)relops to constant true/false when a matching strict<assertion exists (with matching signedness). - Refine unsigned assertion/range handling: allow some unsigned VN-vs-VN assertion tightening in
MergeEdgeAssertionsWorker, and reduce assertion-table pressure by skipping complementary assertions for some unsigned cases.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| src/tests/JIT/opt/RangeChecks/ElidedBoundsChecks.cs | Adds a regression test for eliding the redundant Slice(offset + 1) bounds check under a (uint)offset < (uint)Length guard. |
| src/coreclr/jit/rangecheck.cpp | Adds assertion-driven folding for ADD(base, 1) relops and improves unsigned VN-assertion range tightening rules. |
| src/coreclr/jit/assertionprop.cpp | Expands VN-relop assertion creation to include unsigned int32 relops (with existing pressure gating) and avoids generating low-value unsigned complementary assertions. |
This comment has been minimized.
This comment has been minimized.
Allows global assertion prop to remove the redundant Slice-style bounds
check in patterns like:
if ((uint)offset < (uint)span.Length)
return span.Slice(offset + 1);
Changes in src/coreclr/jit/:
* optCreateJTrueBoundsAssertion: also create O2K_VN relop assertions for
unsigned compares (still gated by optAssertionHasAssertionsForVN to
cap table pressure).
* optCreateComplementaryAssertion: skip the complementary for unsigned
LT_UN/LE_UN with O2K_VN op2, by analogy with the existing skip for
O2K_CHECKED_BOUND_ADD_CNS. Unsigned '>'/'>=' complementaries describe
non-contiguous regions in the signed-int domain that Range can't
represent and rarely match a direct relop fold.
* MergeEdgeAssertionsWorker: derive a constant range from unsigned LT/LE
O2K_VN assertions when the other operand has a non-negative range;
unsigned GT/GE remain skipped (non-contiguous range).
* GetRangeFromAssertionsWorker: when EvalRelop is inconclusive, fold
'<cmp>(ADD(base, 1), other)' using an asserted 'base < other' with
matching signedness. K is restricted to 1: the assertion itself rules
out base==INTxxx_MAX, so base+1 cannot overflow in either signedness.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
e673c2b to
8606c7c
Compare
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This comment has been minimized.
This comment has been minimized.
… into jit-fold-add-by-one
4a8e166 to
27352f6
Compare
|
Caution Security scanning requires review for Code Review DetailsThe threat detection results could not be parsed. The workflow output should be reviewed before merging. Review the workflow run logs for details. Note This review was generated by Copilot. 🤖 Copilot Code Review — PR #128101Holistic AssessmentMotivation: Justified. The linked issue (#112953) demonstrates a real missed optimization in a common Approach: Sound. The PR extends the existing assertion propagation and range-check infrastructure in two complementary ways: (1) creating unsigned relop VN assertions so the JIT records Summary: ✅ LGTM. The changes are well-scoped, the correctness argument is rigorous, edge cases are properly guarded, and the test validates the motivating pattern. Minor observations below. Detailed Findings✅ Correctness of
|
| // "X relop Y" where neither side is a constant nor a checked bound. | ||
| // For now, we only create such assertions for signed comparisons of int32 (and smaller, after promotion). | ||
| // We create such assertions for both signed and unsigned comparisons of int32 (and smaller, after promotion). | ||
| // This widens what global assertion prop can reason about: e.g. "b > a" combined with "a > 10" | ||
| // can be used to deduce "b > 10". | ||
| // can be used to deduce "b > 10". The unsigned variant enables folding patterns like | ||
| // "(uint)(i + 1) <= (uint)len" given "(uint)i < (uint)len". | ||
| // | ||
| // To keep table pressure under control, we only create the assertion if at least one of the | ||
| // operands already has assertions registered. Otherwise the new assertion has no other facts | ||
| // it can chain with and is unlikely to enable any deduction, while still consuming a slot | ||
| // (and potentially crowding out useful ones). | ||
| if (!isUnsignedRelop && (op1VN != op2VN) && !vnStore->IsVNConstant(op1VN) && !vnStore->IsVNConstant(op2VN) && | ||
| if ((op1VN != op2VN) && !vnStore->IsVNConstant(op1VN) && !vnStore->IsVNConstant(op2VN) && | ||
| (optAssertionHasAssertionsForVN(op1VN) || optAssertionHasAssertionsForVN(op2VN))) | ||
| { |
Fixes #112953
Allows the JIT to remove the redundant
Slicebounds check in patterns like:G_M56038_IG02: mov rsi, bword ptr [rdx] mov edi, dword ptr [rdx+0x08] cmp r8d, edi jae SHORT G_M56038_IG08 G_M56038_IG03: inc r8d - cmp r8d, edi - ja SHORT G_M56038_IG09 mov ecx, r8d lea rsi, bword ptr [rsi+2*rcx] sub edi, r8d jns SHORT G_M56038_IG05 -G_M56038_IG09: - call [System.ThrowHelper:ThrowArgumentOutOfRangeException()] - int3