diff options
Diffstat (limited to 'user/rust/ppc64-abi.patch')
-rw-r--r-- | user/rust/ppc64-abi.patch | 251 |
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; ++} |