Disable AVX/AVX2 on interpreter-only x64 builds to fix Vector256 NRE - #129574
Conversation
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>
|
Tagging subscribers to this area: @JulieLeeMSFT, @BrzVlad, @janvorli, @kg |
There was a problem hiding this comment.
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(), clearInstructionSet_AVXwheninterpreterOnlyon x86/x64 underFEATURE_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
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>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
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>
|
@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: Probably unlikely to happen in practice, but something to watch out for. |
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
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>
…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>
Description
On interpreter-only x64 builds such as Apple mobile, code using
Vector256<T>can throw aNullReferenceExceptioninVector256.get_IsHardwareAccelerated(). These targets compile R2R against the x86-64-v2 baseline with no AVX, so crossgen2 foldsVector256.IsHardwareAcceleratedtofalseand guards the body with aCHECK_InstructionSetSupportAVX2-unsupported fixup. HoweverSetCpuInfo()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 clearsInstructionSet_AVXwheninterpreterOnly, 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
interpreterOnlyflag as the adjacentVector<T>cap, and fixes the runtime side of dotnet/macios#25734.Validation
I compiled CoreLib to R2R for two targets and disassembled
Vector256.get_IsHardwareAcceleratedin each. Onmaccatalyst-x64(v2 baseline) it is hard-coded to return false and carries anAvx2-fixup, meaning the runtime only keeps this body if the CPU has no AVX2. Onlinux-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 theAvx2-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:linux-x64, x86-64-v3 baseline: