-
Notifications
You must be signed in to change notification settings - Fork 4.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
HFA/Vector calling convention representation in the Jit on arm64. #37341
Comments
Is there any reason we can't keep it as That is, we already have issues today with
There are also issues like #904, which talk about broadening the Given all this, it seems like the most covering solution would be to just keep the node as |
@sandreenko - thanks for the thorough write-up! Overall, I think the right direction to pursue is toward keeping A few more detailed comments:
I think that's definitely the right approach. |
Thank you, @tannergooding and @CarolEidt !
I will do that then, it means in all cases 1-3
It requires more work and benefits are not clear, there are problems with it even on VM side (see #35144). Another example is #36868, if you change
we don't have an existing function to tell us if it is a SIMD or not. As I have shown |
Thanks for the explanation @sandreenko! Just as a note, however:
|
While that's true, it must be handled in a way that doesn't cause the JIT to crash, or otherwise generate code that would cause the program to give the wrong exception. That's actually another reason that leaving the type-to-machine mapping until |
Closes dotnet#37341, closes dotnet#37880.
* Reenable GitHub_26491. Closes #13355 * Reenable crossgen2 tests failing with old retyping/ They were fixed both with and without retyping. Closes #37883. * Reenable HVA merge cases. Closes #37341, closes #37880. * Reenable GitHub_35821. Closes #36206, closes #36418. The issue was fixed by #37499. * Delete extra lines that are no longer needed. #37506 was fixed in #38241. * delete a throwing init.
Hello, I could use some help with a new model for our
return/call SIMD*
typing that I am implementing, but first a few examples of what is happening now.1 example:
IL for
ReturnVector4UsingCall
is very simple:call ReturnVector4; ret
,IR would be
ASG(LCL_VAR, call); return LCL_VAR
;The complexity is that Arm64 supports both vector and HFA calling conventions, in this case
Vector4 is an HFA value, so we have to return it as
v0.s[0], v1.s[0], v2.s[0], v3.s[0]
.Now let's see how we import this call and with which type:
TYP_STRUCT
, usingcallRetTyp = JITtype2varType(calliSig.retType)
inimpImportCall
;TYP_SIMD16
inimpImportCall
:callRetTyp = impNormStructType(actualMethodRetTypeSigClass); call->gtType = callRetTyp;
;TYP_STRUCT
inimpAssignStructPtr
:src->gtType = genActualType(returnType);
and that is the final value of the type.a fun side-effect: even if call result is not used we are still creating
ASG(LCL_VAR, call)
, change call type to struct and only later delete theASG
leavingcall
with the correct struct type.Note for !compDoOldStructRetyping(): I don't do 2. and 3., so create as
TYP_STRUCT
and keep it.and the return in this case is
STRUCT
, so we end up with nice IR:Note/todo/fun fact: if we did not set
LCL_VAR
type as SIMD16 and keep it as a struct, then copy prop would optimize it as:Summary 1: in HFA case we type
call
andreturn
asTYP_STRUCT
with some confusing transformations in the middle.2 example:
TYP_STRUCT
, usingcallRetTyp = JITtype2varType(calliSig.retType)
inimpImportCall
;TYP_SIMD16
inimpImportCall
:callRetTyp = impNormStructType(actualMethodRetTypeSigClass); call->gtType = callRetTyp;
;TYP_SIMD16
inimpAssignStructPtr
:src->gtType = genActualType(returnType);
.and IR looks good:
Summary 1,2: based on these 2 examples we could think that
TYP_SIMD16
on a call or a return means passed in a single vector register and it will haveTYP_STRUCT
when it is an HFA,and
TYP_STRUCT
can be assigned toTYP_SIMD16
, but...3 example:
guess which type Jit will use for it before you read the answer :-)
The IR after importation will be:
because for the return TYPE we ask VM and for call type we use
getBaseTypeAndSizeOfSIMDType
that can only parse known primitive types, so we get a nice mistyping out of nowhere,does not look like a problem so far, JIT can handle it using
morph::fgFixupStructReturn
that sets call type to simd16.3.1. example:
add a temp local var to the last example:
and we have IR that we want right after importation, thanks to
impAssignStructPtr
from the first example:but
V00
is created as STRUCT, so can't put it in a register, sad:Note for !compDoOldStructRetyping(): we do not want all these retyping to happens in random places, so we want types not to change after we create them during importation until they reach lowering.
Question: but what type should we use in the last example?
TYP_STRUCT
works much better, because then we don't need access LCL_VAR asLCL_FLD
, they have exactly the same types and Jit knows that!For now, I am stick with
TYP_STRUCT
in all cases for allcall
types, keepRETURN
as VM sees them, but it cases asserts that I can't avoid without implementing #11413, because we start gettingIND SIMD16(ADDR byref(call STRUCT)
for such calls andADDR(call)
is not a valid IR (we sometimes create them, but we are lucky in those examples and I am not lucky in mine).Summary 1, 2, 3: do not try to guess Jit TYP looking at C# code.
4 example:
so we know that
return->gtType == TYP_SIMD
and call types would beTYP_STRUCT
, and we know that it is working finesomehow
and after morph, we changecall
types toTYP_SIMD
and it is great.but here comes my favorite thing: return merging, we create a 1 local var where we put all return results and it is happening before global morph, during
PHASE Morph - Add internal blocks
,can you guess the type of this LCL_VAR?
and return knows it is a struct somehow... But maybe morph will fix it like it fixes calls? Nop... it will bail out with an assert that you can easily repro in the current master, see #37247:
when we try to do
ASG(LCL_VAR struct our merge lclVar, LCL_FLD SIMD16 from our calls
It doesn't nowadays lead to a bad codegen in release, because lower has a handling for it under
compDoOldStructRetyping() == false
and we ignore assertsthat is actually
compDoOldStructRetyping() == false
and do the right thing of settingRETURN TYP
back toSIMD16
, I do not have an older version or runtime to check what was happening beforecompDoOldStructRetyping
.Summary 1, 2, 3, 4: with
compDoOldStructRetyping == true
the old system is very unpredictable and fragile, with failures in simple cases.compDoOldStructRetyping == false
that I am trying to support on arm64 has the same difficulties and I would like to hear @CarolEidt , @tannergooding , @dotnet/jit-contrib opinions about types that we should choose in each case. I have tried many options and none of them was good enough.I have started working on #11413, so I could keep
calls
asTYP_STRUCT
always, ignoringSIMD
and avoiding creatingIND(ADDR(CALL)
when we assign their results toLCL_VAR/FLD SIMD*
, what do you think?The text was updated successfully, but these errors were encountered: