Skip to content

Disable AVX/AVX2 on interpreter-only x64 builds to fix Vector256 NRE - #129574

Merged
kotlarmilos merged 10 commits into
dotnet:mainfrom
kotlarmilos:fix-128901-interpreter-avx2
Jun 30, 2026
Merged

Disable AVX/AVX2 on interpreter-only x64 builds to fix Vector256 NRE#129574
kotlarmilos merged 10 commits into
dotnet:mainfrom
kotlarmilos:fix-128901-interpreter-avx2

Conversation

@kotlarmilos

@kotlarmilos kotlarmilos commented Jun 18, 2026

Copy link
Copy Markdown
Member

Description

On interpreter-only x64 builds such as Apple mobile, code using Vector256<T> can throw a NullReferenceException in Vector256.get_IsHardwareAccelerated(). These targets compile R2R against the x86-64-v2 baseline with no AVX, so crossgen2 folds Vector256.IsHardwareAccelerated to false and guards the body with a CHECK_InstructionSetSupport AVX2-unsupported fixup. However SetCpuInfo() enables AVX and AVX2 from the host CPU with no no-JIT gate, so on AVX2 hardware that fixup fails, the runtime discards the correct 128-bit R2R body and falls back to the interpreter, which mishandles the 256-bit path and throws the NRE. The fix clears InstructionSet_AVX when interpreterOnly, and the dependency resolver then cascade-removes AVX2, AVX512, Vector256 and Vector512 while keeping Vector128 and SSE, re-aligning the reported ISA with the v2 R2R baseline so the fixup validates and the 128-bit path is used.

This is a follow-up to #129012 that keys off the same interpreterOnly flag as the adjacent Vector<T> cap, and fixes the runtime side of dotnet/macios#25734.

Validation

I compiled CoreLib to R2R for two targets and disassembled Vector256.get_IsHardwareAccelerated in each. On maccatalyst-x64 (v2 baseline) it is hard-coded to return false and carries an Avx2- fixup, meaning the runtime only keeps this body if the CPU has no AVX2. On linux-x64 (v3 baseline) it is hard-coded to return true with no fixup. This shows the value is baked in at compile time, and that on Apple x64 the Avx2- fixup is what fails on a real AVX2 CPU, causing the runtime to drop the correct body and fall back to the interpreter that crashes.

maccatalyst-x64, x86-64-v2 baseline:

bool System.Runtime.Intrinsics.Vector256.get_IsHardwareAccelerated()
Number of fixups: 1
    CHECK_InstructionSetSupport Avx- Avx2- Evex- ... VectorT256- VectorT512- ...

561faa: 33 c0      xor    eax, eax        ; returns false
561fb2: 0f b6 c0   movzx  eax, al
561fba: c3         ret

linux-x64, x86-64-v3 baseline:

bool System.Runtime.Intrinsics.Vector256.get_IsHardwareAccelerated()
(no fixups)

55201a: c7 45 fc 01 00 00 00   mov    dword ptr [rbp - 4], 1   ; returns true
552024: 0f b6 c0               movzx  eax, al
55202c: c3                     ret

On JIT-less x64 builds such as Mac Catalyst and the iOS or tvOS simulator,
code using Vector256<T> can throw a NullReferenceException in
Vector256.get_IsHardwareAccelerated. These targets compile R2R against the
x86-64-v2 baseline with no AVX, so crossgen2 folds Vector256.IsHardwareAccelerated
to false and guards the body with a CHECK_InstructionSetSupport AVX2-unsupported
fixup. However SetCpuInfo enables AVX and AVX2 from the host CPU with no no-JIT
gate, so on AVX2 hardware that fixup fails, the runtime discards the correct
128-bit R2R body and falls back to the interpreter, which mishandles the 256-bit
path and throws the NRE.

Clear InstructionSet_AVX when interpreterOnly so the dependency resolver
cascade-removes AVX2, AVX512, Vector256 and Vector512 while keeping Vector128 and
SSE, re-aligning the reported ISA with the v2 R2R baseline so the fixup validates
and the 128-bit path is used. Follow-up to dotnet#129012 that keys off the same
interpreterOnly flag as the adjacent Vector<T> cap.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings June 18, 2026 12:57
@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 18, 2026
@kotlarmilos kotlarmilos added os-ios Apple iOS area-CodeGen-Interpreter-coreclr and removed area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI labels Jun 18, 2026
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @JulieLeeMSFT, @BrzVlad, @janvorli, @kg
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 updates CoreCLR’s CPU ISA reporting on x86/x64 when running in interpreter-only mode by clearing AVX so that subsequent ISA dependency normalization removes AVX2/AVX512-class capabilities. This helps keep runtime-reported ISA support aligned with the ReadyToRun baseline used for interpreter-only x64 targets, avoiding mismatches that can cause incorrect code path selection.

Changes:

  • In EEJitManager::SetCpuInfo(), clear InstructionSet_AVX when interpreterOnly on x86/x64 under FEATURE_INTERPRETER.
  • Rely on existing ISA dependency normalization (EnsureValidInstructionSetSupport) to cascade-remove dependent ISAs (e.g., AVX2/AVX512-class).
Show a summary per file
File Description
src/coreclr/vm/codeman.cpp Clears AVX for interpreter-only x86/x64 to force consistent ISA dependency resolution and avoid AVX2+ being reported enabled in no-JIT interpreter-only scenarios.

Copilot's findings

  • Files reviewed: 1/1 changed files
  • Comments generated: 1

Comment thread src/coreclr/vm/codeman.cpp Outdated
Copilot AI review requested due to automatic review settings June 19, 2026 09:10

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.

Copilot's findings

  • Files reviewed: 1/1 changed files
  • Comments generated: 1

Comment thread src/coreclr/vm/codeman.cpp Outdated
Comment thread src/coreclr/vm/codeman.cpp Outdated
kotlarmilos and others added 2 commits June 29, 2026 17:17
Address review feedback: skip enabling InstructionSet_AVX up front when
interpreter-only on x86/x64, letting EnsureValidInstructionSetSupport remove
AVX2/AVX512 and dependent VectorT256/VectorT512, rather than setting AVX and
clearing it later. Also tighten the comment.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings June 29, 2026 15:47
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@kotlarmilos
kotlarmilos requested a review from janvorli June 29, 2026 15:51

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.

Copilot's findings

  • Files reviewed: 1/1 changed files
  • Comments generated: 1

Comment thread src/coreclr/vm/codeman.cpp
Copilot AI review requested due to automatic review settings June 29, 2026 15:52

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.

Copilot's findings

  • Files reviewed: 1/1 changed files
  • Comments generated: 0 new

Address review feedback: the PreferredVectorBitWidth block sets the
Vector256/Vector512 marker ISAs after EnsureValidInstructionSetSupport runs.
With AVX left disabled for interpreter-only, clamp the preferred vector width
to 128 so those markers aren't reintroduced, keeping the reported ISA set
consistent.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@BrzVlad

BrzVlad commented Jun 30, 2026

Copy link
Copy Markdown
Member

@kotlarmilos Note that I believe the intrinsic interaction with interpreter is still fragile. I believe invalid execution can still happen due to the interpreter hardcoding all hardware intrinsics support to false. https://github.com/dotnet/runtime/blob/main/src/coreclr/interpreter/intrinsics.cpp#L74. Normally, I believe interpreter should return true if it knows that it has access to this api via r2r, if not for performance, at least for correctness.

I believe you could have something like:

MethodR2R()
{
     if (HardwareCapabilityExists) // r2r could hardcode this check to true
            MethodInterp();
}

MethodInterp()
{
     Assert(HardwareCapabilityExists); // interp doesn't support anything so this would throw.
}

Probably unlikely to happen in practice, but something to watch out for.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings June 30, 2026 09:00

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.

Copilot's findings

  • Files reviewed: 1/1 changed files
  • Comments generated: 1

Comment thread src/coreclr/vm/codeman.cpp Outdated
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Comment thread src/coreclr/vm/codeman.cpp Outdated
Both blocks already sit inside the function's TARGET_X86 || TARGET_AMD64
region, so guard only on FEATURE_INTERPRETER. Also reword the AVX comment to
not mention VectorT256/VectorT512, which are never set in interpreter-only
mode (maxVectorTBitWidth is already clamped to 128 earlier).

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

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.

Copilot's findings

  • Files reviewed: 1/1 changed files
  • Comments generated: 0 new

@kotlarmilos
kotlarmilos enabled auto-merge (squash) June 30, 2026 12:17
@kotlarmilos
kotlarmilos merged commit dc6840e into dotnet:main Jun 30, 2026
111 checks passed
@dotnet-milestone-bot dotnet-milestone-bot Bot added this to the 11.0-preview7 milestone Jun 30, 2026
eiriktsarpalis pushed a commit that referenced this pull request Jul 15, 2026
…129574)

## Description

On interpreter-only x64 builds such as Apple mobile, code using
`Vector256<T>` can throw a `NullReferenceException` in
`Vector256.get_IsHardwareAccelerated()`. These targets compile R2R
against the x86-64-v2 baseline with no AVX, so crossgen2 folds
`Vector256.IsHardwareAccelerated` to `false` and guards the body with a
`CHECK_InstructionSetSupport` AVX2-unsupported fixup. However
`SetCpuInfo()` enables AVX and AVX2 from the host CPU with no no-JIT
gate, so on AVX2 hardware that fixup fails, the runtime discards the
correct 128-bit R2R body and falls back to the interpreter, which
mishandles the 256-bit path and throws the NRE. The fix clears
`InstructionSet_AVX` when `interpreterOnly`, and the dependency resolver
then cascade-removes AVX2, AVX512, Vector256 and Vector512 while keeping
Vector128 and SSE, re-aligning the reported ISA with the v2 R2R baseline
so the fixup validates and the 128-bit path is used.

This is a follow-up to #129012 that keys off the same `interpreterOnly`
flag as the adjacent `Vector<T>` cap, and fixes the runtime side of
dotnet/macios#25734.

## Validation

I compiled CoreLib to R2R for two targets and disassembled
`Vector256.get_IsHardwareAccelerated` in each. On `maccatalyst-x64` (v2
baseline) it is hard-coded to return **false** and carries an `Avx2-`
fixup, meaning the runtime only keeps this body if the CPU has no AVX2.
On `linux-x64` (v3 baseline) it is hard-coded to return **true** with no
fixup. This shows the value is baked in at compile time, and that on
Apple x64 the `Avx2-` fixup is what fails on a real AVX2 CPU, causing
the runtime to drop the correct body and fall back to the interpreter
that crashes.

`maccatalyst-x64`, x86-64-v2 baseline:

```
bool System.Runtime.Intrinsics.Vector256.get_IsHardwareAccelerated()
Number of fixups: 1
    CHECK_InstructionSetSupport Avx- Avx2- Evex- ... VectorT256- VectorT512- ...

561faa: 33 c0      xor    eax, eax        ; returns false
561fb2: 0f b6 c0   movzx  eax, al
561fba: c3         ret
```

`linux-x64`, x86-64-v3 baseline:

```
bool System.Runtime.Intrinsics.Vector256.get_IsHardwareAccelerated()
(no fixups)

55201a: c7 45 fc 01 00 00 00   mov    dword ptr [rbp - 4], 1   ; returns true
552024: 0f b6 c0               movzx  eax, al
55202c: c3                     ret
```

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions github-actions Bot locked and limited conversation to collaborators Jul 31, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants