Skip to content

More precise ranges for casts in GetRangeFromAssertions - #124415

Merged
EgorBo merged 12 commits into
dotnet:mainfrom
EgorBo:precise-cast-ranges
May 12, 2026
Merged

More precise ranges for casts in GetRangeFromAssertions#124415
EgorBo merged 12 commits into
dotnet:mainfrom
EgorBo:precise-cast-ranges

Conversation

@EgorBo

@EgorBo EgorBo commented Feb 14, 2026

Copy link
Copy Markdown
Member

Copilot AI review requested due to automatic review settings February 14, 2026 01:24
@github-actions github-actions Bot added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Feb 14, 2026
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch
See info in area-owners.md if you want to be subscribed.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR improves range analysis in the JIT's range check optimization pass by enabling more precise range propagation through cast operations and adding support for TYP_INT in GetRangeFromType.

Changes:

  • Add early range tightening based on VN type for small types in GetRangeFromAssertions (though this appears to be dead code due to VN normalization)
  • Change cast source type check from exact TYP_INT match to using genActualType, making the code more defensive
  • Add TYP_INT case to GetRangeFromType to return the full int32 range instead of Unknown

Comment thread src/coreclr/jit/rangecheck.cpp Outdated
Copilot AI review requested due to automatic review settings February 14, 2026 03:05

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated 2 comments.

Comment thread src/coreclr/jit/rangecheck.cpp
Comment thread src/coreclr/jit/rangecheck.cpp
Copilot AI review requested due to automatic review settings February 14, 2026 15:04

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

Comment thread src/coreclr/jit/rangecheck.cpp
@EgorBo
EgorBo force-pushed the precise-cast-ranges branch from 2704ba3 to e492c87 Compare February 14, 2026 18:54
Copilot AI review requested due to automatic review settings February 14, 2026 18:54

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.

@EgorBo
EgorBo marked this pull request as ready for review February 14, 2026 21:17
Copilot AI review requested due to automatic review settings February 14, 2026 21:19

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.

Comment thread src/coreclr/jit/assertionprop.cpp Outdated
Per @jakobbotsch review feedback: NOL locals can live in registers where
the JIT does not insert any normalization without the cast. Retyping the
LCL_VAR to its small type and dropping the cast lets codegen read the
register without a normalizing load (e.g., movzx), exposing potentially
undefined upper bits for register-resident NOL params.

The reason morph.cpp:3230 can perform a similar retype-and-drop is that
it gates on local subrange assertions, which only exist after a
JIT-controlled store that normalized the bits. VN-based subrange proofs
have no such guarantee — they can come from comparisons, casts, joins,
or phi merges that say nothing about the physical register state.

Restore the original PR behavior of skipping NOL locals entirely in the
VN-based path. The local-prop path below is unchanged and still
performs the safe retyping based on local assertions.

Cost on benchmarks.run: +4,482 bytes vs the (unsafe) prior commit, but
still -3,670 bytes net vs origin/main. SPMI replay clean on aspnet,
libraries (incl. tests), benchmarks. JIT/opt/Or/IntOr disasm pattern
preserved by the small-cast-on-non-LCL_VAR guard introduced earlier.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings May 10, 2026 22:37

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.

Reverts 0a3a858 ("Remove unreachable GC early return ...") which
broke 32-bit crossgen2 of System.Private.CoreLib (Memmove and others
asserting `genActualType(vnType) == TYP_INT` at rangecheck.cpp:698).

Why the GC return is actually needed (and my prior analysis missed):

On 32-bit targets TYP_INT/TYP_BYREF/TYP_REF are all 4 bytes, so the
JIT can legally write a byref-valued expression (e.g. LCL_ADDR) into
an int-typed local. The local is TYP_INT but its VN is a TYP_BYREF
function such as PtrToLoc.

Repro context (libraries.crossgen2 MC 146148, F# SubstHelperRaw):

    STORE_LCL_VAR int V06 <- LCL_ADDR int V15      # V06 has VN PtrToLoc(...) (BYREF)
    ...PHI int V06 across blocks $340 = PhiDef(...)
    NE int (LCL_VAR int V06, CNS_INT int 0)        # asks for range of $340

PR dotnet#127117 (Apr 23) added PhiDef recursion in
GetRangeFromAssertionsWorker; the visitor walks reaching VNs of the
phi, and on 32-bit one of them can be the BYREF PtrToLoc VN even
though the public caller passed an int-typed tree. The pre-existing
GC early-return guard catches exactly this case; the explanatory
comment is updated so the next reader doesn't repeat my mistake.

x64 SPMI didn't catch it because TYP_BYREF (8 bytes) and TYP_INT (4
bytes) cannot alias in the same local, so `LCL_ADDR int` doesn't
appear and the phi recursion never reaches a BYREF VN.

Validation: x86 libraries.crossgen2 SPMI replay clean (279,521 ctx).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings May 11, 2026 11:39
@EgorBo

EgorBo commented May 11, 2026

Copy link
Copy Markdown
Member Author

@EgorBot -arm -amd

using BenchmarkDotNet.Attributes;

public class Benchmarks
{
    private byte b = 42;

    [Benchmark]
    public string ByteToString() => b.ToString();
}

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.

@EgorBo

EgorBo commented May 12, 2026

Copy link
Copy Markdown
Member Author

I think this is ready, PTAL @jakobbotsch @dotnet/jit-contrib
Some nice diffs

An example of what it folds:

internal static string UInt32ToDecStr(uint value)
{
// For small numbers, consult a lazily-populated cache.
if (value < SmallNumberCacheLength)
{
return UInt32ToDecStrForKnownSmallNumber(value);
}

When Byte.cs pass itself on its ToString() we can fold the value < 300 check

@EgorBo
EgorBo requested a review from jakobbotsch May 12, 2026 09:58
Comment thread src/coreclr/jit/rangecheck.cpp
Comment thread src/coreclr/jit/assertionprop.cpp
Comment thread src/coreclr/jit/assertionprop.cpp
@EgorBo

EgorBo commented May 12, 2026

Copy link
Copy Markdown
Member Author

/ba-g timeouts

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants