-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
JIT: Check more invariants on ABI info and fix some arm32 bugs #101372
Conversation
- Implicit byref parameters should be passed as a single pointer sized segment - Segments should not point outside the local size - Segments should not overlap each other
Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch |
{ | ||
const ABIPassingSegment& segment = abiInfo.Segments[i]; | ||
assert(segment.Size > 0); | ||
assert(segment.Offset + segment.Size <= lvaLclExactSize(lclNum)); |
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 old ABI-style used LclVarDsc::lvSize()
to get some struct's size as the LclVarDsc::lvExactSize()
is not always we expected size.
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.
lvaLclExactSize
is the correct size to use. lvSize
is what is allocated by the backend on the stack frame, but this is not the real size of the struct being passed.
I want the ABI information to contain the real size to be as precise as possible. If the backend wants it can round this size up when stores/loads are generated by using the knowledge about how it allocates more space in some cases.
What error did you run into around this?
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.
For the V02 arg2 [V02 ] ( 1, 1 ) struct ( 8) [fp-0x18] do-not-enreg[S] System.Threading.Tasks.VoidTaskResult>
, the size is 1 which returned by lvaLclExactSize(lclNum)
or GetLayout()->GetSize()
, but the old ABI-style is 8.
/// new-ABI-style:
{ Start Jitting Method 615 System.Threading.Tasks.Task`1[System.Threading.Tasks.VoidTaskResult]:.ctor(ubyte,System.Threading.Tasks.VoidTaskResult,int,System.Threading.CancellationToken):this (MethodHash=05f08360) MinOpts
; Assembly listing for method System.Threading.Tasks.Task`1[System.Threading.Tasks.VoidTaskResult]:.ctor(ubyte,System.Threading.Tasks.VoidTaskResult,int,System.Threading.CancellationToken):this (MinOpts)
; Emitting BLENDED_CODE for generic LOONGARCH64 - Unix
; MinOpts code
; debuggable code
; fp based frame
; fully interruptible
; No PGO data
; Final local variable assignments
;
; V00 this [V00 ] ( 1, 1 ) ref -> [fp-0x08] do-not-enreg[] this class-hnd <System.Threading.Tasks.Task`1[System.Threading.Tasks.VoidTaskResult]>
; V01 arg1 [V01 ] ( 1, 1 ) ubyte -> [fp-0x0C] do-not-enreg[]
; V02 arg2 [V02 ] ( 1, 1 ) struct ( 8) [fp-0x18] do-not-enreg[S] <System.Threading.Tasks.VoidTaskResult>
; V03 arg3 [V03 ] ( 1, 1 ) int -> [fp-0x1C] do-not-enreg[]
; V04 arg4 [V04 ] ( 1, 1 ) struct ( 8) [fp-0x28] do-not-enreg[S] <System.Threading.CancellationToken>
; V05 loc0 [V05 ] ( 1, 1 ) ubyte -> [fp-0x2C] do-not-enreg[]
;# V06 OutArgs [V06 ] ( 1, 1 ) struct ( 0) [sp+0x00] do-not-enreg[XS] addr-exposed "OutgoingArgSpace"
;
; Lcl frame size = 48
Frame info. #outsz=0; #framesz=64; lcl=48
G_M31903_IG01: ;; offset=0x0000
0xff76b50e98 02FF0063 addi.d sp, sp, -64
0xff76b50e9c 29C0C076 st.d fp, sp, 48
0xff76b50ea0 29C0E061 st.d ra, sp, 56
0xff76b50ea4 02C0C076 addi.d fp, sp, 48
0xff76b50ea8 29FFE2C4 st.d a0, fp, -8
0xff76b50eac 29BFD2C5 st.w a1, fp, -12
0xff76b50eb0 29BFA2C6 st.w a2, fp, -24 //error.
0xff76b50eb4 29BF92C7 st.w a3, fp, -28
0xff76b50eb8 29FF62C8 st.d a4, fp, -40
;; size=36 bbWeight=1 PerfScore 0.00
/// old-ABI-style:
G_M31903_IG01: ;; offset=0x0000
0xff74170e98 02FF0063 addi.d sp, sp, -64
0xff74170e9c 29C0C076 st.d fp, sp, 48
0xff74170ea0 29C0E061 st.d ra, sp, 56
0xff74170ea4 02C0C076 addi.d fp, sp, 48
0xff74170ea8 29FFE2C4 st.d a0, fp, -8
0xff74170eac 29BFD2C5 st.w a1, fp, -12
0xff74170eb0 29FFA2C6 st.d a2, fp, -24 /// this is ok and we expected.
0xff74170eb4 29BF92C7 st.w a3, fp, -28
0xff74170eb8 29FF62C8 st.d a4, fp, -40
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.
Why is the 4 byte store an error when the struct is only 1 byte in size?
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.
FWIW, according to https://loongson.github.io/LoongArch-Documentation/LoongArch-ELF-ABI-EN.html
Bits unused due to padding, and bits past the end of a structure whose size in bits is not divisible by GRLEN, are undefined.
IIUC the upper 7 bytes of a2
are undefined. So either st.d
or st.w
leave the 7 extra bytes allocated for V02
as undefined.
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 just diff the new-style ABI with the old-style ABI, then I just recover the old-style's instruction.
I had deleted the roundup of struct size.
Thanks
The previous code would consider a struct like ```csharp [StructLayout(LayoutKind.Sequential, Size = 12)] struct S { public double X; public float Y; } ``` to take 4 slots, which is wrong.
cc @dotnet/jit-contrib PTAL @EgorBo |
@AndyAyersMS Can you take a look since Egor is out? |
…t#101372) - Implicit byref parameters should be passed as a single pointer sized segment - Segments should not point outside the local size - Segments should not overlap each other - Segments should have size > 0 - Segments should be ordered by offset - Fix a bug in the arm32 classifier when structs are split - Fix a bug in the arm32 classifier for odd-sized structs with 8 byte alignment. For example ```csharp [StructLayout(LayoutKind.Sequential, Size = 12)] struct S { public double X; public float Y; } ``` would be considered to take 4 slots before. - Fix a bug in the Swift classifier that would cause the tail segments to have an out-of-bounds size
…t#101372) - Implicit byref parameters should be passed as a single pointer sized segment - Segments should not point outside the local size - Segments should not overlap each other - Segments should have size > 0 - Segments should be ordered by offset - Fix a bug in the arm32 classifier when structs are split - Fix a bug in the arm32 classifier for odd-sized structs with 8 byte alignment. For example ```csharp [StructLayout(LayoutKind.Sequential, Size = 12)] struct S { public double X; public float Y; } ``` would be considered to take 4 slots before. - Fix a bug in the Swift classifier that would cause the tail segments to have an out-of-bounds size
would be considered to take 4 slots before.