Skip to content

Add compile-time and run-time methods to obtain Vector<T> byte length#130023

Open
snickolls-arm wants to merge 7 commits into
dotnet:mainfrom
snickolls-arm:vectort-length-helpers
Open

Add compile-time and run-time methods to obtain Vector<T> byte length#130023
snickolls-arm wants to merge 7 commits into
dotnet:mainfrom
snickolls-arm:vectort-length-helpers

Conversation

@snickolls-arm

Copy link
Copy Markdown
Contributor

Renames getVectorTByteLength to getCompileTimeVectorTByteLength, which evaluates the size of Vector<T> using available ISA features.

Adds getRuntimeVectorTByteLength which queries the actual size of Vector<T> using a cached class handle discovered during import.

On Arm64 with SVE available, ISA features alone are not enough to predict the size of Vector<T>, motivating this change. The JIT can use getRuntimeVectorTByteLength to discover the SVE vector length in scenarios where an exact size is required, such as when generating OSR patchpoints.

Renames getVectorTByteLength to getCompileTimeVectorTByteLength, which
evaluates the size of Vector<T> using available ISA features.

Adds getRuntimeVectorTByteLength which queries the actual size of Vector<T>
using a cached class handle discovered during import. This can be used for
example when trying to evaluate the size of the Tier0 frame.

On Arm64 with SVE available, ISA features alone are not enough to predict
the size of Vector<T>, motivating this change. The JIT can use
getRuntimeVectorTByteLength to discover the SVE vector length in scenarios
where an exact size is required, such as when generating OSR patchpoints.
@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 30, 2026
@dotnet-policy-service dotnet-policy-service Bot added the community-contribution Indicates that the PR has been added by a community member label Jun 30, 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.

@snickolls-arm

Copy link
Copy Markdown
Contributor Author

@dotnet/arm64-contrib Please could I have a review?

Comment thread src/coreclr/jit/simd.cpp Outdated
return TYP_UNDEF;
}

vectorTHandle = typeHnd;

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.

So this can be one of many different handles (it is unique per <T>) and we've recently dropped all the other handle caching we had been doing for SIMD types...

Is there a reason we're doing it this way rather than doing it via an explicit JIT/EE query that can report the exact size and which the compiler can cache?

What is then the expected behavior for AOT/R2R scenarios? Are such compilations simply expected to never call getRuntimeVectorTByteLength? Do we need some kind of validation to help ensure it is only used in JIT scenarios where that information can be known to be correct/accurate?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Is there a reason we're doing it this way rather than doing it via an explicit JIT/EE query that can report the exact size and which the compiler can cache?

No reason, I think this would be better. I'm not sure how to add a new function to the interface yet, but I'm happy to try and do this. On the VM side, I think it would trigger a load to Vector<T> through CorLibBinder and read the size from there?

What is then the expected behavior for AOT/R2R scenarios? Are such compilations simply expected to never call getRuntimeVectorTByteLength? Do we need some kind of validation to help ensure it is only used in JIT scenarios where that information can be known to be correct/accurate?

We want to avoid using this completely throughout the JIT. The only exceptions are JIT-only scenarios where we've deemed it most convenient to read VL, such as OSR where it will greatly simplify the implementation. We want to use it to compute an exact size of the tier0 stack frame rather than deal with an unknown sized chunk between the tier0 and tier1 frames.

Where it's been used in the implementation of intrinsics such as Sve.Load2xVectorAndUnzip, it's suggesting that the logic isn't VL-agnostic yet. So we'll need to make some changes there to make sure it works for AOT.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

A simple way to implement this would be to extend getBuiltinClass with an option for Vector<T>. Can Vector<T> be considered a 'builtin' class in this manner, or is there a special meaning behind it?

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.

There's not, we can use it for any of the corelib types that need it. That being said, you still have the open generic issue and that we'd prefer avoiding caching such handles.

What is the VM reporting for the size today if we query it via the normal getExactSize APIs? Is it 0? Should we maybe always have the VM report accurately and then we can override that in the simd name resolution we do here?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

As of #129852 I believe the VM reports the correct runtime size for all handles to Vector<T>, including the uninstantiated generic class.

I could make the cache private to the function using a static local, and I could cache either the handle from getBuiltinClass or the queried size from getClassSize, either is fine.

I could also just avoid caching until it becomes a performance concern. The only reason it's caching at the moment is because it can't find a handle to Vector<T> without it appearing somewhere in metadata.

For interest, why do we want to avoid caching generic handles? Can they change underneath you?

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.

It's rather just additional overhead and state growth for something we found was not a perf concern at all. It effectively regresses the 99% for the minority of hot functions that use vectorization themselves.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

2e997fb implements this suggestion using getBuiltinClass

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 community-contribution Indicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants