Repository: rust
Issue: The sparc64, riscv64, loongarch64 `extern "C" fn` ABIs are all wrong when aligned/packed structs are involved
Labels: A-FFI,P-medium,T-compiler,I-unsound,O-SPARC,O-riscv,A-ABI,O-loongarch

All of these ABIs have in common that they are looking at `layout.fields` to compute the ABI for the function, and they are all getting it wrong, in various different ways. (I previously reported bugs against all of these because `repr(transparent)` is not properly respected; those bugs have the same cause -- relying on `layout.fields` -- but they are orthogonal.)

For instance, this type
```
#[repr(packed)]
struct P(i8, f32);
```
on riscv64 gets a PassMode::Cast of
```
                           prefix: [
                               Some(
                                   Reg {
                                       kind: Integer,
                                       size: Size(1 bytes),
                                   },
                               ),
                               None,
                               None,
                               None,
                               None,
                               None,
                               None,
                               None,
                           ],
                           rest: Uniform {
                               unit: Reg {
                                   kind: Float,
                                   size: Size(4 bytes),
                               },
                               total: Size(4 bytes),
                           },
```
which gets translated to the LLVM type `{ i8, f32 }`, and that's a *non-packed* LLVM struct. On a call, `P` gets transmuted to that LLVM type, which obviously produces garbage since the fields are at different offsets.

On sparc64, the type translates into `{ i32, f32 }` which is wrong as well.

As another example, this type
```
#[repr(align(8))]
struct Aligned8Int(i32);

#[repr(C)]
struct S2(Aligned8Int, f32);
```
on loongarch64 gets a PassMode::Cast of
```
                           prefix: [
                               Some(
                                   Reg {
                                       kind: Integer,
                                       size: Size(4 bytes),
                                   },
                               ),
                               None,
                               None,
                               None,
                               None,
                               None,
                               None,
                               None,
                           ],
                           rest: Uniform {
                               unit: Reg {
                                   kind: Float,
                                   size: Size(4 bytes),
                               },
                               total: Size(4 bytes),
                           },


```
which is the LLVM type `{ i32, f32 }`, and that's obviously not the right type for `S2`.

(Caveat: I can't actually run code on these targets, so there's a small chance that I am completely misinterpreting what these `PassMode` mean. I hope that's not the case...)

I don't know what the C ABI on those platforms has to say about packed and aligned structs. Currently, we don't even provide ABIs a way to generate a packed LLVM struct for the arguments -- `PassMode::Cast` always uses an un-packed LLVM struct.