The sparc64, riscv64, loongarch64 extern "C" fn
ABIs are all wrong when aligned/packed structs are involved #115609
Description
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.