Skip to content
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

Merged
merged 5 commits into from
Apr 26, 2024

Conversation

jakobbotsch
Copy link
Member

@jakobbotsch jakobbotsch commented Apr 22, 2024

  • 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
[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

- 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
@dotnet-issue-labeler dotnet-issue-labeler bot added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Apr 22, 2024
Copy link
Contributor

Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch
See info in area-owners.md if you want to be subscribed.

{
const ABIPassingSegment& segment = abiInfo.Segments[i];
assert(segment.Size > 0);
assert(segment.Offset + segment.Size <= lvaLclExactSize(lclNum));
Copy link
Contributor

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.

Copy link
Member Author

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?

Copy link
Contributor

@shushanhf shushanhf Apr 22, 2024

Choose a reason for hiding this comment

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

#101365 (comment)

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

Copy link
Member Author

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?

Copy link
Member Author

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.

Copy link
Contributor

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.
@jakobbotsch jakobbotsch marked this pull request as ready for review April 24, 2024 08:37
@jakobbotsch jakobbotsch changed the title JIT: Check more invariants on ABI info JIT: Check more invariants on ABI info and fix some arm32 bugs Apr 24, 2024
@jakobbotsch
Copy link
Member Author

cc @dotnet/jit-contrib PTAL @EgorBo

@jakobbotsch
Copy link
Member Author

@AndyAyersMS Can you take a look since Egor is out?

@jakobbotsch jakobbotsch requested a review from AndyAyersMS April 25, 2024 20:10
@jakobbotsch jakobbotsch merged commit 99dd60d into dotnet:main Apr 26, 2024
106 of 110 checks passed
@jakobbotsch jakobbotsch deleted the value-size-invariant branch April 26, 2024 08:00
matouskozak pushed a commit to matouskozak/runtime that referenced this pull request Apr 30, 2024
…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
michaelgsharp pushed a commit to michaelgsharp/runtime that referenced this pull request May 9, 2024
…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
@github-actions github-actions bot locked and limited conversation to collaborators May 27, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants