summaryrefslogtreecommitdiff
path: root/user/rust/ppc64-abi.patch
diff options
context:
space:
mode:
Diffstat (limited to 'user/rust/ppc64-abi.patch')
-rw-r--r--user/rust/ppc64-abi.patch251
1 files changed, 251 insertions, 0 deletions
diff --git a/user/rust/ppc64-abi.patch b/user/rust/ppc64-abi.patch
new file mode 100644
index 000000000..763ebdec5
--- /dev/null
+++ b/user/rust/ppc64-abi.patch
@@ -0,0 +1,251 @@
+From dd2fc075aa673d06dff5f90a44b0162649dac52b Mon Sep 17 00:00:00 2001
+From: beetrees <b@beetr.ee>
+Date: Sun, 4 Aug 2024 15:01:58 +0100
+Subject: [PATCH] Refactor `powerpc64` call ABI handling
+
+---
+ .../rustc_target/src/abi/call/powerpc64.rs | 67 ++-------
+ tests/assembly/powerpc64-struct-abi.rs | 130 ++++++++++++++++++
+ 2 files changed, 142 insertions(+), 55 deletions(-)
+ create mode 100644 tests/assembly/powerpc64-struct-abi.rs
+
+diff --git a/compiler/rustc_target/src/abi/call/powerpc64.rs b/compiler/rustc_target/src/abi/call/powerpc64.rs
+index 11a6cb52babc9..749eea0ef6350 100644
+--- a/compiler/rustc_target/src/abi/call/powerpc64.rs
++++ b/compiler/rustc_target/src/abi/call/powerpc64.rs
+@@ -41,64 +41,23 @@ where
+ })
+ }
+
+-fn classify_ret<'a, Ty, C>(cx: &C, ret: &mut ArgAbi<'a, Ty>, abi: ABI)
++fn classify<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>, abi: ABI, is_ret: bool)
+ where
+ Ty: TyAbiInterface<'a, C> + Copy,
+ C: HasDataLayout,
+ {
+- if !ret.layout.is_sized() {
++ if arg.is_ignore() || !arg.layout.is_sized() {
+ // Not touching this...
+ return;
+ }
+- if !ret.layout.is_aggregate() {
+- ret.extend_integer_width_to(64);
++ if !arg.layout.is_aggregate() {
++ arg.extend_integer_width_to(64);
+ return;
+ }
+
+ // The ELFv1 ABI doesn't return aggregates in registers
+- if abi == ELFv1 {
+- ret.make_indirect();
+- return;
+- }
+-
+- if let Some(uniform) = is_homogeneous_aggregate(cx, ret, abi) {
+- ret.cast_to(uniform);
+- return;
+- }
+-
+- let size = ret.layout.size;
+- let bits = size.bits();
+- if bits <= 128 {
+- let unit = if cx.data_layout().endian == Endian::Big {
+- Reg { kind: RegKind::Integer, size }
+- } else if bits <= 8 {
+- Reg::i8()
+- } else if bits <= 16 {
+- Reg::i16()
+- } else if bits <= 32 {
+- Reg::i32()
+- } else {
+- Reg::i64()
+- };
+-
+- ret.cast_to(Uniform::new(unit, size));
+- return;
+- }
+-
+- ret.make_indirect();
+-}
+-
+-fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>, abi: ABI)
+-where
+- Ty: TyAbiInterface<'a, C> + Copy,
+- C: HasDataLayout,
+-{
+- if !arg.layout.is_sized() {
+- // Not touching this...
+- return;
+- }
+- if !arg.layout.is_aggregate() {
+- arg.extend_integer_width_to(64);
++ if is_ret && abi == ELFv1 {
++ arg.make_indirect();
+ return;
+ }
+
+@@ -108,7 +67,10 @@ where
+ }
+
+ let size = arg.layout.size;
+- if size.bits() <= 64 {
++ if is_ret && size.bits() > 128 {
++ // Non-homogeneous aggregates larger than two doublewords are returned indirectly.
++ arg.make_indirect();
++ } else if size.bits() <= 64 {
+ // Aggregates smaller than a doubleword should appear in
+ // the least-significant bits of the parameter doubleword.
+ arg.cast_to(Reg { kind: RegKind::Integer, size })
+@@ -138,14 +100,9 @@ where
+ }
+ };
+
+- if !fn_abi.ret.is_ignore() {
+- classify_ret(cx, &mut fn_abi.ret, abi);
+- }
++ classify(cx, &mut fn_abi.ret, abi, true);
+
+ for arg in fn_abi.args.iter_mut() {
+- if arg.is_ignore() {
+- continue;
+- }
+- classify_arg(cx, arg, abi);
++ classify(cx, arg, abi, false);
+ }
+ }
+diff --git a/tests/assembly/powerpc64-struct-abi.rs b/tests/assembly/powerpc64-struct-abi.rs
+new file mode 100644
+index 0000000000000..c36e3f2b62251
+--- /dev/null
++++ b/tests/assembly/powerpc64-struct-abi.rs
+@@ -0,0 +1,130 @@
++//@ revisions: elfv1-be elfv2-be elfv2-le
++//@ assembly-output: emit-asm
++//@[elfv1-be] compile-flags: --target powerpc64-unknown-linux-gnu
++//@[elfv1-be] needs-llvm-components: powerpc
++//@[elfv2-be] compile-flags: --target powerpc64-unknown-linux-musl
++//@[elfv2-be] needs-llvm-components: powerpc
++//@[elfv2-le] compile-flags: --target powerpc64le-unknown-linux-gnu
++//@[elfv2-le] needs-llvm-components: powerpc
++//@[elfv1-be] filecheck-flags: --check-prefix be
++//@[elfv2-be] filecheck-flags: --check-prefix be
++
++#![feature(no_core, lang_items)]
++#![no_std]
++#![no_core]
++#![crate_type = "lib"]
++
++#[lang = "sized"]
++trait Sized {}
++
++#[lang = "copy"]
++trait Copy {}
++
++#[lang = "freeze"]
++trait Freeze {}
++
++#[lang = "unpin"]
++trait Unpin {}
++
++impl Copy for u8 {}
++impl Copy for u16 {}
++impl Copy for u32 {}
++impl Copy for FiveU32s {}
++impl Copy for FiveU16s {}
++impl Copy for ThreeU8s {}
++
++#[repr(C)]
++struct FiveU32s(u32, u32, u32, u32, u32);
++
++#[repr(C)]
++struct FiveU16s(u16, u16, u16, u16, u16);
++
++#[repr(C)]
++struct ThreeU8s(u8, u8, u8);
++
++// CHECK-LABEL: read_large
++// be: lwz [[REG1:.*]], 16(4)
++// be-NEXT: stw [[REG1]], 16(3)
++// be-NEXT: ld [[REG2:.*]], 8(4)
++// be-NEXT: ld [[REG3:.*]], 0(4)
++// be-NEXT: std [[REG2]], 8(3)
++// be-NEXT: std [[REG3]], 0(3)
++// elfv2-le: lxvd2x [[REG1:.*]], 0, 4
++// elfv2-le-NEXT: lwz [[REG2:.*]], 16(4)
++// elfv2-le-NEXT: stw [[REG2]], 16(3)
++// elfv2-le-NEXT: stxvd2x [[REG1]], 0, 3
++// CHECK-NEXT: blr
++#[no_mangle]
++extern "C" fn read_large(x: &FiveU32s) -> FiveU32s {
++ *x
++}
++
++// CHECK-LABEL: read_medium
++// elfv1-be: lhz [[REG1:.*]], 8(4)
++// elfv1-be-NEXT: ld [[REG2:.*]], 0(4)
++// elfv1-be-NEXT: sth [[REG1]], 8(3)
++// elfv1-be-NEXT: std [[REG2]], 0(3)
++// elfv2-be: lhz [[REG1:.*]], 8(3)
++// elfv2-be-NEXT: ld 3, 0(3)
++// elfv2-be-NEXT: sldi 4, [[REG1]], 48
++// elfv2-le: ld [[REG1:.*]], 0(3)
++// elfv2-le-NEXT: lhz 4, 8(3)
++// elfv2-le-NEXT: mr 3, [[REG1]]
++// CHECK-NEXT: blr
++#[no_mangle]
++extern "C" fn read_medium(x: &FiveU16s) -> FiveU16s {
++ *x
++}
++
++// CHECK-LABEL: read_small
++// elfv1-be: lbz [[REG1:.*]], 2(4)
++// elfv1-be-NEXT: lhz [[REG2:.*]], 0(4)
++// elfv1-be-NEXT: stb [[REG1]], 2(3)
++// elfv1-be-NEXT: sth [[REG2]], 0(3)
++// elfv2-be: lhz [[REG1:.*]], 0(3)
++// elfv2-be-NEXT: lbz 3, 2(3)
++// elfv2-be-NEXT: rldimi 3, [[REG1]], 8, 0
++// elfv2-le: lbz [[REG1:.*]], 2(3)
++// elfv2-le-NEXT: lhz 3, 0(3)
++// elfv2-le-NEXT: rldimi 3, [[REG1]], 16, 0
++// CHECK-NEXT: blr
++#[no_mangle]
++extern "C" fn read_small(x: &ThreeU8s) -> ThreeU8s {
++ *x
++}
++
++// CHECK-LABEL: write_large
++// CHECK: std 3, 0(6)
++// be-NEXT: rldicl [[REG1:.*]], 5, 32, 32
++// CHECK-NEXT: std 4, 8(6)
++// be-NEXT: stw [[REG1]], 16(6)
++// elfv2-le-NEXT: stw 5, 16(6)
++// CHECK-NEXT: blr
++#[no_mangle]
++extern "C" fn write_large(x: FiveU32s, dest: &mut FiveU32s) {
++ *dest = x;
++}
++
++// CHECK-LABEL: write_medium
++// CHECK: std 3, 0(5)
++// be-NEXT: rldicl [[REG1:.*]], 4, 16, 48
++// be-NEXT: sth [[REG1]], 8(5)
++// elfv2-le-NEXT: sth 4, 8(5)
++// CHECK-NEXT: blr
++#[no_mangle]
++extern "C" fn write_medium(x: FiveU16s, dest: &mut FiveU16s) {
++ *dest = x;
++}
++
++// CHECK-LABEL: write_small
++// be: stb 3, 2(4)
++// be-NEXT: srwi [[REG1:.*]], 3, 8
++// be-NEXT: sth [[REG1]], 0(4)
++// elfv2-le: sth 3, 0(4)
++// elfv2-le-NEXT: srwi [[REG1:.*]], 3, 16
++// elfv2-le-NEXT: stb [[REG1]], 2(4)
++// CHECK-NEXT: blr
++#[no_mangle]
++extern "C" fn write_small(x: ThreeU8s, dest: &mut ThreeU8s) {
++ *dest = x;
++}