-
Notifications
You must be signed in to change notification settings - Fork 4.9k
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
[mono] Check for Vector{64,128,256}<T>
element type validity before emitting unchecked intrinsic IR for AsByte
etc.
#53707
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are the relevant HWIntrinsic tests covering this still disabled for Mono?
I would've expected one or more of the tests under https://github.com/dotnet/runtime/tree/main/src/tests/JIT/HardwareIntrinsics/General/NotSupported to have caught this. https://github.com/dotnet/runtime/blob/main/src/tests/JIT/HardwareIntrinsics/General/NotSupported/Vector128BooleanAsGeneric_UInt64.cs is the one covering the specific example from the related issue.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
They've been enabled since #44930. These tests pass because we currently implement
operator ==
forType
via an intrinsic. This, combined with the fact that we currently link Mono with LLVM built with assertions disabled, means that this:is optimized into this:
Because we don't run tests with LLVM assertions enabled, we won't fail-fast when emitting an invalid bitcast.
#52791 changes this; we don't inline this managed implementation of
operator ==
, and the invalid bitcasts aren't elided. So the test later fails when attempting to do isel for a bogus bitcast.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, I'm a bit confused here as to why this means the tests "pass". The tests in question are doing code similar to the following:
Given this, I'd expect
NotSupportedException
to be throw for any invalidT
being used withAs
. However, as seen with #53132 and with what this PR is fixing, unsupportedT
were being allowed and invalid IR generated.That is, I'm not connecting the dots here on why these tests "pass" but
public static Vector128<T> WithLower<T>(this Vector128<T> vector, Vector64<T> value
was getting invalid LLVM IR.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here's the definition of
WithLower
:Today, on arm64, for function parameters, we map
Vector128<T>
to[2 x i64]
andVector64<T>
to[1 x i64]
, regardless of the validity of the element type.On function entry, when
T
is supported, we construct an LLVM vector of the right shape via a sequence ofload
s andinsertelement
s, and then we associate the resulting LLVM vector value with the mini IR register that represents that function parameter. The rest of our intrinsics-related code assumes that vectors are normal LLVM values.When
T
is unsupprted, we manipulate it using our generic "value type" convention, which represents instances of value types via an indirection and usesload
s andstore
s to manipulate different fields. In this case the mini IR registers associated with each function parameter are mapped directly to these array-typed LLVM function parameters (these are promptlystore
d inalloca
d memory for later "value type" use). My previous PR added a hack to stub in an LLVM undef value for .NET vector types with unsupported element types.On arm64,
AdvSimd.IsSupported
is implemented via an intrinsic that binds a constant1
to a mini IR register.Vector128:AsUInt64
, before this change, was implemented as an intrinsic that emits an unchecked mini IROP_XCAST
, even for unsupportedT
. This is translated to an LLVM bitcast, under the assumption that the source mini IR register in the originatingOP_XCAST
is associated with a valid LLVM vector value. This is the source ofin the unoptimized LLVM IR in my previous comment.
As
is later inlined. We (contrary to my incorrect PR description in my now-closed PR) don't intrinsifyAs
. So we then translate two inlined invocations ofThrowForUnsupportedIntrinsicsVectorBaseType
. Because we happen to be JIT-compiling this System.Private.CoreLib.dll code (rather than AOT compiling it--the only things AOTed right now in the llvmaot test lanes are the individual runtime test assemblies), the exact addresses of all associatedType
instances are "JIT-statically" known in each invocation ofThrowForUnsupportedIntrinsicsVectorBaseType
. The intrinsified inequality comparisons between JIT-time constants are all true and are "optimized" via mini IR-specific passes that run before translation to LLVM IR. This is the source ofin the unoptimized LLVM IR in my previous comment.
The passes that we've enabled for LLVM as a JIT then apparently elide all side-effect-free instructions (including the invalid
AsUInt64
bitcasts), even if they're located in basic blocks that dominate the basic block that contains the invocation ofSystem.ThrowHelper:ThrowNotSupportedException
. So we've been generating invalid IR for a while but because our implementation ofType
operator ==
is an intrinsic (and because we're JIT compiling functions from System.Private.CoreLib.dll, which I should have mentioned in my previous comment), this invalid IR has been getting optimized away. This happened to make these tests "pass".If we were running these tests with an assertion-enabled LLVM, this would have been caught much earlier.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems potentially problematic for ABI handling since vector types get special handling. In particular
Vector128<T>
, for a validT
, is contracted to map to the__m128
ABI type on x86/x64 (there are corresponding ABI type forVector256
and similar types for Vector64/Vector128 on ARM32/ARM64). This can also be impactful for understanding of things likeHFA
vsHVA
asstruct S { float x, y, z, w; }
and__m128
are different types on some platforms, as are2 x i64
vs4 x float
.Is there any particular reason this isn't just specially handling valid types as a
n x ...
element vector and handling unsupported types as a regular struct definition, so that things "work" and match the type and ABI handling that RyuJIT has?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have no idea why our calling convention bounces
Vector{64,128,256}<T>
through GPRs or through memory. This is something I'd like to improve.EDIT: Probably most accurate to say that the work to make the CC computation code SIMD-aware just hasn't happened yet, so all the existing code piggybacks off the existing support for "value types".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The passing/receiving of simd types as simd is just not implemented right now, there is no particular reason for it afaik.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, I was mostly trying to figure out why it was that things were handled as SIMD at all for unrecognized types.
In RyuJIT, we specially recognize a few
T
and everything else just falls back to as if it were any plain old struct type.