Skip to content

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

Open
kotlarmilos wants to merge 1 commit into
dotnet:mainfrom
kotlarmilos:fix-128901-interpreter-avx2
Open

Disable AVX/AVX2 on interpreter-only x64 builds to fix Vector256 NRE#129574
kotlarmilos wants to merge 1 commit 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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants