Skip to content

Enable must-throw for unsupported intrinsics under optimizations#129007

Merged
tannergooding merged 11 commits into
dotnet:mainfrom
tannergooding:copilot/update-impsupportednamedintrinsic
Jun 6, 2026
Merged

Enable must-throw for unsupported intrinsics under optimizations#129007
tannergooding merged 11 commits into
dotnet:mainfrom
tannergooding:copilot/update-impsupportednamedintrinsic

Conversation

@tannergooding
Copy link
Copy Markdown
Member

@tannergooding tannergooding commented Jun 4, 2026

This should put less pressure on the doing repetitive work and should allow merging of the various must throw blocks. The general issue was noticed in #128513 (comment), where we had some size regressions due to cold blocks for throwing intrinsics not being merged as they callee was unique for each; even though we don't really care about it being in the stack trace (its optimized code, inlining and loss of that stack trace entry was already possible).

Copilot AI and others added 5 commits June 4, 2026 17:50
Co-authored-by: tannergooding <10487869+tannergooding@users.noreply.github.com>
…4/128/256/512 ISAs in lookupId

Co-authored-by: tannergooding <10487869+tannergooding@users.noreply.github.com>
Co-authored-by: tannergooding <10487869+tannergooding@users.noreply.github.com>
Copilot AI review requested due to automatic review settings June 4, 2026 18:55
@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 Jun 4, 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.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

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 adjusts CoreCLR JIT intrinsic recognition so that unsupported intrinsics are handled more consistently under optimizations: cross-platform intrinsic APIs (with managed fallbacks) no longer hard-throw PlatformNotSupportedException when the ISA isn’t available, while platform-specific intrinsic APIs (and platform-mismatched sub-namespaces) are forced to throw. It also changes unsupported-intrinsic expansion to prefer emitting a MustThrowException in optimized codegen, avoiding a redundant managed call that would only throw anyway.

Changes:

  • Extend HWIntrinsicInfo::lookupId with an isXplatIntrinsic flag to distinguish cross-platform intrinsics (managed fallback) from platform-specific intrinsics (must throw PNSE when unsupported).
  • In lookupNamedIntrinsic, correctly classify intrinsics under System.Runtime.Intrinsics including platform-mismatched sub-namespaces (e.g., .X86 on ARM64) as must-throw PNSE.
  • In impUnsupportedNamedIntrinsic, return a MustThrowException node not only for mustExpand, but also when optimizations are enabled.

Reviewed changes

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

File Description
src/coreclr/jit/importercalls.cpp Classifies cross-platform vs platform-specific intrinsics and forces PNSE for platform-mismatched intrinsic namespaces; enables must-throw emission under optimizations for unsupported intrinsics.
src/coreclr/jit/hwintrinsic.h Updates HWIntrinsicInfo::lookupId declaration to accept the new isXplatIntrinsic parameter.
src/coreclr/jit/hwintrinsic.cpp Implements the new isXplatIntrinsic behavior: cross-platform intrinsics with unsupported ISA return NI_Illegal (allowing managed fallback), platform-specific intrinsics return PNSE.

Copilot AI review requested due to automatic review settings June 4, 2026 23:45
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

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 3 out of 3 changed files in this pull request and generated 2 comments.

Comment thread src/coreclr/jit/hwintrinsic.cpp Outdated
Comment thread src/coreclr/jit/importercalls.cpp Outdated
Copilot AI review requested due to automatic review settings June 5, 2026 01:34
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

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 3 out of 3 changed files in this pull request and generated 2 comments.

Comment thread src/coreclr/jit/importercalls.cpp Outdated
Comment thread src/coreclr/jit/importercalls.cpp
@tannergooding
Copy link
Copy Markdown
Member Author

CC. @AndyAyersMS. Provides a small TP improvement (-0.03%) and reduction in bytes allocated (-0.04%). Provides a larger reduction in inline count (-0.20%). It then picks up a few diffs, mostly on the Linux boxes where we test hardware without AVX512 support.

Most of the scenarios are ultimately handled via DCE, so this namely just avoids the duplicative work and more importantly ensures the exception we produce in the JIT actually matches what managed was producing, with the nit that R2R remains incorrect for an edge case and is dependent on a version bump

@tannergooding
Copy link
Copy Markdown
Member Author

Test failures are #129037

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

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 3 out of 3 changed files in this pull request and generated 1 comment.

Comment thread src/coreclr/jit/importercalls.cpp
@AndyAyersMS
Copy link
Copy Markdown
Member

Diffs seem pretty sparse -- I thought I had looked at the prior diff set and there were more (though almost all in test collections).

@tannergooding
Copy link
Copy Markdown
Member Author

I was surprised at the sparseness as well, perhaps its SPMI specific and related to the R2R/NAOT limitation (needing a version bump to ensure the correct exception is handled) here?

@tannergooding
Copy link
Copy Markdown
Member Author

Ah, @AndyAyersMS it looks like its because of missed contexts. Previously we returned nullptr and so we never queried the info for a given helper call for Inliner, only in the actual intrinsic (the Inlinee that fails). Now we expand that directly and so the query happens and fails the context.

I'm getting direct diffs locally and will share here in a bit.

@tannergooding
Copy link
Copy Markdown
Member Author

This is indeed where a lot of it went. For tests, as an example:

Found 4140 files with textual diffs.
Total bytes of delta: -6325 (-0.01 % of base)

Some of the SPMI diffs look to be because the Linux binaries used by SPMI don't have the Arm64 stuff trimmed, but it is trimmed when done locally, I presume this is some artifact of us doing some cross coverage.

In places I've looked, we appear to be merging the multiple throw blocks as expected, with most secondary throws already being DCE so we only end up with one. The two block case is mostly from places where we had two separate inlinees, each that has such a throw case.

Copilot AI review requested due to automatic review settings June 6, 2026 02:38
@tannergooding tannergooding enabled auto-merge (squash) June 6, 2026 02:39
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

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 3 out of 3 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (1)

src/coreclr/jit/importercalls.cpp:12052

  • impUnsupportedNamedIntrinsic now returns a MustThrowException whenever opts.OptimizationEnabled() is true. This changes behavior for helper kinds that were intentionally falling back to a managed call to preserve exception details.

In particular, hwintrinsic.cpp uses impUnsupportedNamedIntrinsic(CORINFO_HELP_THROW_ARGUMENTOUTOFRANGEEXCEPTION, ...) when an immediate argument is a known out-of-range constant (see the existing comment there: "convert the intrinsic into a user call (or throw if we must expand)"). If we emit a must-throw helper under opts, the exception will come from ThrowHelpers.ThrowArgumentOutOfRangeException() (no param name/message) instead of the managed intrinsic body which often throws new ArgumentOutOfRangeException(nameof(scale))/etc (e.g., Avx2.GatherVector128 in System.Private.CoreLib).

Consider limiting the new "return must-throw under opts" behavior to helpers where we don't lose observable exception details (e.g., PNSE/NIE/TypeNotSupported), and keep returning nullptr for CORINFO_HELP_THROW_ARGUMENTOUTOFRANGEEXCEPTION unless mustExpand==true.

    if (mustExpand || opts.OptimizationEnabled())
    {
        impSpillSideEffects(true, CHECK_SPILL_ALL DEBUGARG("impUnsupportedNamedIntrinsic"));

        for (unsigned i = 0; i < sig->numArgs; i++)
        {
            impPopStack();
        }

        return gtNewMustThrowException(helper, JITtype2varType(sig->retType), sig->retTypeClass);

@tannergooding tannergooding merged commit 849bb26 into dotnet:main Jun 6, 2026
139 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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.

4 participants