Skip to content

Use an explicit allow list for SIMD types in getTypeLayout - #131479

Merged
tannergooding merged 1 commit into
dotnet:mainfrom
tannergooding:tannergooding-fuzzy-tribble
Jul 29, 2026
Merged

Use an explicit allow list for SIMD types in getTypeLayout#131479
tannergooding merged 1 commit into
dotnet:mainfrom
tannergooding:tannergooding-fuzzy-tribble

Conversation

@tannergooding

Copy link
Copy Markdown
Member

Follow-up to #131345 (comment).

The intrinsic check in getTypeLayout was a deny form: every [Intrinsic] type in System.Numerics and System.Runtime.Intrinsics was reported to the JIT as an opaque SIMD node, with the decimal floating-point types carved back out via IsDecimalFloatingPointOrHasDecimalFloatingPointFields. That only held while every intrinsic type in those namespaces happened to be SIMD, so each new non-SIMD intrinsic type needs another carve-out.

This names the SIMD types explicitly instead, via a new IsSimdIntrinsicType helper on both the native VM and the managed (crossgen2 / ILCompiler) side, mirroring the set recognized by Compiler::getBaseTypeAndSizeOfSIMDType:

  • System.Runtime.Intrinsics: Vector64<T>, Vector128<T>, Vector256<T>, Vector512<T>
  • System.Numerics: Vector<T>, Vector2, Vector3, Vector4, Plane, Quaternion

The managed helper reuses the existing VectorFieldLayoutAlgorithm.IsVectorType and VectorOfTFieldLayoutAlgorithm.IsVectorOfTType rather than duplicating those name checks. IsDecimalFloatingPointOrHasDecimalFloatingPointFields is untouched -- it's still used for the by-value marshal restriction in dllimport.cpp, mlinfo.cpp, classlayoutinfo.cpp, and MarshalHelpers.cs.


Matrix3x2/Matrix4x4 fall out of the set as well. They're [Intrinsic] and live in System.Numerics, so the old namespace-only test caught them, but getBaseTypeAndSizeOfSIMDType returns TYP_UNDEF for them, so their simdTypeHnd was never usable. Their fields are now enumerated like any other struct:

  • TryPromoteValueClassAsPrimitive rejected a Matrix field before (SIMD lookup fails, then numFields == 0 != 1) and rejects it now (simdTypeHnd == null, then numFields == 6 or 16 != 1), so no promotion can be lost.
  • TryPromoteStructVar has a 1 + MAX_NumOfFieldsInPromotableStruct * 2 == 9 node budget; a Matrix4x4 field overflows it into Partial -> return false, the same outcome as before.
  • ClassLayout::GetNonPadding treats a simdTypeHnd node as entirely non-padding. Matrices have no padding, and SegmentList::Add merges the adjacent per-field segments, so the resulting map is identical.
  • For R2R, Matrix types no longer hit the NeedsTypeLayoutCheck -> Failure bail and take the ordinary field-enumeration path. Their fields are primitive floats, which CheckTypeLayout handles; the getClassSize fixup concern applies only to types reported via simdTypeHnd.

No JIT-EE GUID bump -- the interface signature and CORINFO_TYPE_LAYOUT_NODE are unchanged.

Deliberately out of scope: MethodTable::ClassifyEightBytes* and SystemVStructClassificator also do intrinsic-type name checks, but against a deliberately smaller set (only Vector64/128/256/512<T> and Vector<T> -- Vector2/3/4, Plane, and Quaternion are passed in registers), so they can't share this helper.

Validation

SuperPMI can't cover this -- it replays recorded getTypeLayout responses, so a VM-side change is invisible to asmdiffs. Validated with a real build instead:

  • build.cmd clr -rc checked -- 0 warnings, 0 errors. Both ILCompiler.RyuJit and ILCompiler.ReadyToRun relink, so both #if READYTORUN arms compile.
  • A/B JitDump over wrapper structs for all 15 affected types (10 SIMD + Matrix3x2/Matrix4x4 + Decimal32/64/128), before vs. after, address-normalized: 0 differing lines out of 83,382. This confirms empirically that the Matrix delta is inert, including the Matrix3x2 case that fits within the node budget.
  • JIT/SIMD: 116/116 passed. JIT/Directed/StructPromote + JIT/Directed/physicalpromotion: 9/9 passed.

Note

This PR description and the accompanying code changes were drafted with GitHub Copilot.

The intrinsic check was a deny form: every [Intrinsic] type in System.Numerics
and System.Runtime.Intrinsics was reported to the JIT as an opaque SIMD node,
with the decimal floating-point types carved back out. That only held while
every intrinsic type in those namespaces happened to be SIMD, so each new
non-SIMD intrinsic type needs another carve-out.

Name the SIMD types explicitly instead, mirroring the set recognized by
Compiler::getBaseTypeAndSizeOfSIMDType. Matrix3x2/Matrix4x4 now fall out of the
set as well; the JIT already returned TYP_UNDEF for them, so their simdTypeHnd
was never usable.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 28, 2026 16:51
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 3 pipeline(s).
13 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @agocke
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 tightens getTypeLayout’s SIMD “primitive” detection by replacing a broad namespace-based intrinsic check with an explicit allow list of SIMD types, ensuring non-SIMD [Intrinsic] types in System.Numerics / System.Runtime.Intrinsics have their fields enumerated and reported to the JIT.

Changes:

  • Add a VM-side IsSimdIntrinsicType(MethodTable*) helper and use it to decide when to set simdTypeHnd in CEEInfo::GetTypeLayoutHelper.
  • Add a managed (crossgen2/ILCompiler) IsSimdIntrinsicType(MetadataType) helper and use it for the analogous GetTypeLayoutHelper logic.
  • Remove the previous “deny-form” namespace-only SIMD detection (and associated decimal carve-out) from both implementations.
Show a summary per file
File Description
src/coreclr/vm/jitinterface.cpp Introduces an explicit SIMD allow list helper and uses it to drive simdTypeHnd in getTypeLayout.
src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs Mirrors the VM behavior for AOT/tooling by introducing the same allow-list concept using existing vector type helpers.

Copilot's findings

  • Files reviewed: 2/2 changed files
  • Comments generated: 0

@tannergooding

Copy link
Copy Markdown
Member Author

CC. @MichalStrehovsky, this does the explicit filtering to avoid any potential future issues, only skipping for the types we definitely know are safe (because they map to TYP_SIMD*)

@MichalStrehovsky MichalStrehovsky left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Is the purpose of this basically a compile-time perf optimization? I assume that would mean it's sufficient to match a subset of types recognized by Compiler::getBaseTypeAndSizeOfSIMDType that has many fields. If all of these have many fields, than exact mirror makes sense. If only some of these, we could potentially delete some lines of code. I'll leave this up to you, I'll not pretend I know about SIMD!

@tannergooding

Copy link
Copy Markdown
Member Author

Is the purpose of this basically a compile-time perf optimization?

@jakobbotsch added this particular path as part of the promotion feature and so I'd defer to him as the expert for that particular portion. As far as I understand it, however, it is essentially just part of ensuring that these are viewed as enregistered primitives and stopping the consideration of the underlying fields that they are made up of. -- It's actually possible that this may be leaving some on the table since V256/V512, for example, aren't such cases on platforms like WASM/Arm64, but that's a pre-existing limitation, not something newly introduced.

@jakobbotsch jakobbotsch left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This looks fine to me

@tannergooding
tannergooding enabled auto-merge (squash) July 29, 2026 14:33
@tannergooding
tannergooding merged commit 3dad2c9 into dotnet:main Jul 29, 2026
110 of 112 checks passed
@tannergooding
tannergooding deleted the tannergooding-fuzzy-tribble branch July 29, 2026 14:50
@dotnet-milestone-bot dotnet-milestone-bot Bot added this to the 11.0-rc1 milestone Jul 29, 2026
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.

4 participants