diff --git a/compiler/rustc_codegen_gcc/src/asm.rs b/compiler/rustc_codegen_gcc/src/asm.rs index a04cd4735f478..b44d4aa8cc82b 100644 --- a/compiler/rustc_codegen_gcc/src/asm.rs +++ b/compiler/rustc_codegen_gcc/src/asm.rs @@ -654,7 +654,8 @@ fn reg_to_gcc(reg: InlineAsmRegOrRegClass) -> ConstraintOrRegister { InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg_nonzero) => "b", InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::freg) => "f", InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::cr) - | InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::xer) => { + | InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::xer) + | InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::vreg) => { unreachable!("clobber-only") } InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) => "r", @@ -729,7 +730,8 @@ fn dummy_output_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, reg: InlineAsmRegCl InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg_nonzero) => cx.type_i32(), InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::freg) => cx.type_f64(), InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::cr) - | InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::xer) => { + | InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::xer) + | InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::vreg) => { unreachable!("clobber-only") } InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) => cx.type_i32(), diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index 82ca3f519f740..82ee8af4c301b 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -679,7 +679,9 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'_>>) -> PowerPC(PowerPCInlineAsmRegClass::reg) => "r", PowerPC(PowerPCInlineAsmRegClass::reg_nonzero) => "b", PowerPC(PowerPCInlineAsmRegClass::freg) => "f", - PowerPC(PowerPCInlineAsmRegClass::cr) | PowerPC(PowerPCInlineAsmRegClass::xer) => { + PowerPC(PowerPCInlineAsmRegClass::cr) + | PowerPC(PowerPCInlineAsmRegClass::xer) + | PowerPC(PowerPCInlineAsmRegClass::vreg) => { unreachable!("clobber-only") } RiscV(RiscVInlineAsmRegClass::reg) => "r", @@ -841,7 +843,9 @@ fn dummy_output_type<'ll>(cx: &CodegenCx<'ll, '_>, reg: InlineAsmRegClass) -> &' PowerPC(PowerPCInlineAsmRegClass::reg) => cx.type_i32(), PowerPC(PowerPCInlineAsmRegClass::reg_nonzero) => cx.type_i32(), PowerPC(PowerPCInlineAsmRegClass::freg) => cx.type_f64(), - PowerPC(PowerPCInlineAsmRegClass::cr) | PowerPC(PowerPCInlineAsmRegClass::xer) => { + PowerPC(PowerPCInlineAsmRegClass::cr) + | PowerPC(PowerPCInlineAsmRegClass::xer) + | PowerPC(PowerPCInlineAsmRegClass::vreg) => { unreachable!("clobber-only") } RiscV(RiscVInlineAsmRegClass::reg) => cx.type_i32(), diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs index 73ae1ae96ae23..933f23d9b2468 100644 --- a/compiler/rustc_target/src/asm/mod.rs +++ b/compiler/rustc_target/src/asm/mod.rs @@ -892,6 +892,7 @@ pub enum InlineAsmClobberAbi { AArch64NoX18, RiscV, LoongArch, + PowerPC, S390x, Msp430, } @@ -943,6 +944,10 @@ impl InlineAsmClobberAbi { "C" | "system" => Ok(InlineAsmClobberAbi::LoongArch), _ => Err(&["C", "system"]), }, + InlineAsmArch::PowerPC | InlineAsmArch::PowerPC64 => match name { + "C" | "system" => Ok(InlineAsmClobberAbi::PowerPC), + _ => Err(&["C", "system"]), + }, InlineAsmArch::S390x => match name { "C" | "system" => Ok(InlineAsmClobberAbi::S390x), _ => Err(&["C", "system"]), @@ -1108,6 +1113,31 @@ impl InlineAsmClobberAbi { f16, f17, f18, f19, f20, f21, f22, f23, } }, + InlineAsmClobberAbi::PowerPC => clobbered_regs! { + PowerPC PowerPCInlineAsmReg { + // r0, r3-r12 + r0, + r3, r4, r5, r6, r7, + r8, r9, r10, r11, r12, + + // f0-f13 + f0, f1, f2, f3, f4, f5, f6, f7, + f8, f9, f10, f11, f12, f13, + + // v0-v19 + // FIXME: PPC32 SysV ABI does not mention vector registers processing. + // https://refspecs.linuxfoundation.org/elf/elfspec_ppc.pdf + v0, v1, v2, v3, v4, v5, v6, v7, + v8, v9, v10, v11, v12, v13, v14, + v15, v16, v17, v18, v19, + + // cr0-cr1, cr5-cr7, xer + cr0, cr1, + cr5, cr6, cr7, + xer, + // lr and ctr are reserved + } + }, InlineAsmClobberAbi::S390x => clobbered_regs! { S390x S390xInlineAsmReg { r0, r1, r2, r3, r4, r5, diff --git a/compiler/rustc_target/src/asm/powerpc.rs b/compiler/rustc_target/src/asm/powerpc.rs index b2416466132d7..aa8b26170bee1 100644 --- a/compiler/rustc_target/src/asm/powerpc.rs +++ b/compiler/rustc_target/src/asm/powerpc.rs @@ -1,14 +1,17 @@ use std::fmt; +use rustc_data_structures::fx::FxIndexSet; use rustc_span::Symbol; use super::{InlineAsmArch, InlineAsmType, ModifierInfo}; +use crate::spec::{RelocModel, Target}; def_reg_class! { PowerPC PowerPCInlineAsmRegClass { reg, reg_nonzero, freg, + vreg, cr, xer, } @@ -48,11 +51,44 @@ impl PowerPCInlineAsmRegClass { } } Self::freg => types! { _: F32, F64; }, + Self::vreg => &[], Self::cr | Self::xer => &[], } } } +fn reserved_r13( + arch: InlineAsmArch, + _reloc_model: RelocModel, + _target_features: &FxIndexSet, + target: &Target, + _is_clobber: bool, +) -> Result<(), &'static str> { + if target.is_like_aix && arch == InlineAsmArch::PowerPC { + Ok(()) + } else { + Err("r13 is a reserved register on this target") + } +} + +fn reserved_v20to31( + _arch: InlineAsmArch, + _reloc_model: RelocModel, + _target_features: &FxIndexSet, + target: &Target, + _is_clobber: bool, +) -> Result<(), &'static str> { + if target.is_like_aix { + match &*target.options.abi { + "vec-default" => Err("v20-v31 are reserved on vec-default ABI"), + "vec-extabi" => Ok(()), + _ => unreachable!("unrecognized AIX ABI"), + } + } else { + Ok(()) + } +} + def_regs! { PowerPC PowerPCInlineAsmReg PowerPCInlineAsmRegClass { r0: reg = ["r0", "0"], @@ -66,6 +102,7 @@ def_regs! { r10: reg, reg_nonzero = ["r10", "10"], r11: reg, reg_nonzero = ["r11", "11"], r12: reg, reg_nonzero = ["r12", "12"], + r13: reg, reg_nonzero = ["r13", "13"] % reserved_r13, r14: reg, reg_nonzero = ["r14", "14"], r15: reg, reg_nonzero = ["r15", "15"], r16: reg, reg_nonzero = ["r16", "16"], @@ -113,6 +150,38 @@ def_regs! { f29: freg = ["f29", "fr29"], f30: freg = ["f30", "fr30"], f31: freg = ["f31", "fr31"], + v0: vreg = ["v0"], + v1: vreg = ["v1"], + v2: vreg = ["v2"], + v3: vreg = ["v3"], + v4: vreg = ["v4"], + v5: vreg = ["v5"], + v6: vreg = ["v6"], + v7: vreg = ["v7"], + v8: vreg = ["v8"], + v9: vreg = ["v9"], + v10: vreg = ["v10"], + v11: vreg = ["v11"], + v12: vreg = ["v12"], + v13: vreg = ["v13"], + v14: vreg = ["v14"], + v15: vreg = ["v15"], + v16: vreg = ["v16"], + v17: vreg = ["v17"], + v18: vreg = ["v18"], + v19: vreg = ["v19"], + v20: vreg = ["v20"] % reserved_v20to31, + v21: vreg = ["v21"] % reserved_v20to31, + v22: vreg = ["v22"] % reserved_v20to31, + v23: vreg = ["v23"] % reserved_v20to31, + v24: vreg = ["v24"] % reserved_v20to31, + v25: vreg = ["v25"] % reserved_v20to31, + v26: vreg = ["v26"] % reserved_v20to31, + v27: vreg = ["v27"] % reserved_v20to31, + v28: vreg = ["v28"] % reserved_v20to31, + v29: vreg = ["v29"] % reserved_v20to31, + v30: vreg = ["v30"] % reserved_v20to31, + v31: vreg = ["v31"] % reserved_v20to31, cr: cr = ["cr"], cr0: cr = ["cr0"], cr1: cr = ["cr1"], @@ -127,8 +196,6 @@ def_regs! { "the stack pointer cannot be used as an operand for inline asm", #error = ["r2", "2"] => "r2 is a system reserved register and cannot be used as an operand for inline asm", - #error = ["r13", "13"] => - "r13 is a system reserved register and cannot be used as an operand for inline asm", #error = ["r29", "29"] => "r29 is used internally by LLVM and cannot be used as an operand for inline asm", #error = ["r30", "30"] => @@ -163,13 +230,17 @@ impl PowerPCInlineAsmReg { // Strip off the leading prefix. do_emit! { (r0, "0"), (r3, "3"), (r4, "4"), (r5, "5"), (r6, "6"), (r7, "7"); - (r8, "8"), (r9, "9"), (r10, "10"), (r11, "11"), (r12, "12"), (r14, "14"), (r15, "15"); + (r8, "8"), (r9, "9"), (r10, "10"), (r11, "11"), (r12, "12"), (r13, "13"), (r14, "14"), (r15, "15"); (r16, "16"), (r17, "17"), (r18, "18"), (r19, "19"), (r20, "20"), (r21, "21"), (r22, "22"), (r23, "23"); (r24, "24"), (r25, "25"), (r26, "26"), (r27, "27"), (r28, "28"); (f0, "0"), (f1, "1"), (f2, "2"), (f3, "3"), (f4, "4"), (f5, "5"), (f6, "6"), (f7, "7"); (f8, "8"), (f9, "9"), (f10, "10"), (f11, "11"), (f12, "12"), (f13, "13"), (f14, "14"), (f15, "15"); (f16, "16"), (f17, "17"), (f18, "18"), (f19, "19"), (f20, "20"), (f21, "21"), (f22, "22"), (f23, "23"); (f24, "24"), (f25, "25"), (f26, "26"), (f27, "27"), (f28, "28"), (f29, "29"), (f30, "30"), (f31, "31"); + (v0, "0"), (v1, "1"), (v2, "2"), (v3, "3"), (v4, "4"), (v5, "5"), (v6, "6"), (v7, "7"); + (v8, "8"), (v9, "9"), (v10, "10"), (v11, "11"), (v12, "12"), (v13, "13"), (v14, "14"), (v15, "15"); + (v16, "16"), (v17, "17"), (v18, "18"), (v19, "19"), (v20, "20"), (v21, "21"), (v22, "22"), (v23, "23"); + (v24, "24"), (v25, "25"), (v26, "26"), (v27, "27"), (v28, "28"), (v29, "29"), (v30, "30"), (v31, "31"); (cr, "cr"); (cr0, "0"), (cr1, "1"), (cr2, "2"), (cr3, "3"), (cr4, "4"), (cr5, "5"), (cr6, "6"), (cr7, "7"); (xer, "xer"); @@ -201,5 +272,6 @@ impl PowerPCInlineAsmReg { reg_conflicts! { cr : cr0 cr1 cr2 cr3 cr4 cr5 cr6 cr7; } + // f0-f31 (vsr0-vsr31) and v0-v31 (vsr32-vsr63) do not conflict. } } diff --git a/src/doc/unstable-book/src/language-features/asm-experimental-arch.md b/src/doc/unstable-book/src/language-features/asm-experimental-arch.md index b1c429c7676ef..19badee39ba86 100644 --- a/src/doc/unstable-book/src/language-features/asm-experimental-arch.md +++ b/src/doc/unstable-book/src/language-features/asm-experimental-arch.md @@ -31,9 +31,10 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | NVPTX | `reg32` | None\* | `r` | | NVPTX | `reg64` | None\* | `l` | | Hexagon | `reg` | `r[0-28]` | `r` | -| PowerPC | `reg` | `r[0-31]` | `r` | -| PowerPC | `reg_nonzero` | `r[1-31]` | `b` | +| PowerPC | `reg` | `r0`, `r[3-12]`, `r[14-28]` | `r` | +| PowerPC | `reg_nonzero` | `r[3-12]`, `r[14-28]` | `b` | | PowerPC | `freg` | `f[0-31]` | `f` | +| PowerPC | `vreg` | `v[0-31]` | Only clobbers | | PowerPC | `cr` | `cr[0-7]`, `cr` | Only clobbers | | PowerPC | `xer` | `xer` | Only clobbers | | wasm32 | `local` | None\* | `r` | @@ -76,9 +77,10 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | NVPTX | `reg32` | None | `i8`, `i16`, `i32`, `f32` | | NVPTX | `reg64` | None | `i8`, `i16`, `i32`, `f32`, `i64`, `f64` | | Hexagon | `reg` | None | `i8`, `i16`, `i32`, `f32` | -| PowerPC | `reg` | None | `i8`, `i16`, `i32` | -| PowerPC | `reg_nonzero` | None | `i8`, `i16`, `i32` | +| PowerPC | `reg` | None | `i8`, `i16`, `i32`, `i64` (powerpc64 only) | +| PowerPC | `reg_nonzero` | None | `i8`, `i16`, `i32`, `i64` (powerpc64 only) | | PowerPC | `freg` | None | `f32`, `f64` | +| PowerPC | `vreg` | N/A | Only clobbers | | PowerPC | `cr` | N/A | Only clobbers | | PowerPC | `xer` | N/A | Only clobbers | | wasm32 | `local` | None | `i8` `i16` `i32` `i64` `f32` `f64` | @@ -105,6 +107,10 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | Hexagon | `r29` | `sp` | | Hexagon | `r30` | `fr` | | Hexagon | `r31` | `lr` | +| PowerPC | `r1` | `sp` | +| PowerPC | `r31` | `fp` | +| PowerPC | `r[0-31]` | `[0-31]` | +| PowerPC | `f[0-31]` | `fr[0-31]`| | BPF | `r[0-10]` | `w[0-10]` | | AVR | `XH` | `r27` | | AVR | `XL` | `r26` | @@ -145,14 +151,18 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | Architecture | Unsupported register | Reason | | ------------ | --------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | All | `sp`, `r15` (s390x) | The stack pointer must be restored to its original value at the end of an asm code block. | -| All | `fr` (Hexagon), `$fp` (MIPS), `Y` (AVR), `r4` (MSP430), `a6` (M68k), `r11` (s390x), `x29` (Arm64EC) | The frame pointer cannot be used as an input or output. | -| All | `r19` (Hexagon), `x19` (Arm64EC) | This is used internally by LLVM as a "base pointer" for functions with complex stack frames. | +| All | `fr` (Hexagon), `fp` (PowerPC), `$fp` (MIPS), `Y` (AVR), `r4` (MSP430), `a6` (M68k), `r11` (s390x), `x29` (Arm64EC) | The frame pointer cannot be used as an input or output. | +| All | `r19` (Hexagon), `r29` (PowerPC), `r30` (PowerPC), `x19` (Arm64EC) | These are used internally by LLVM as a "base pointer" for functions with complex stack frames. | | MIPS | `$0` or `$zero` | This is a constant zero register which can't be modified. | | MIPS | `$1` or `$at` | Reserved for assembler. | | MIPS | `$26`/`$k0`, `$27`/`$k1` | OS-reserved registers. | | MIPS | `$28`/`$gp` | Global pointer cannot be used as inputs or outputs. | | MIPS | `$ra` | Return address cannot be used as inputs or outputs. | | Hexagon | `lr` | This is the link register which cannot be used as an input or output. | +| PowerPC | `r2`, `r13` | These are system reserved registers. | +| PowerPC | `lr` | The link register cannot be used as an input or output. | +| PowerPC | `ctr` | The counter register cannot be used as an input or output. | +| PowerPC | `vrsave` | The vrsave register cannot be used as an input or output. | | AVR | `r0`, `r1`, `r1r0` | Due to an issue in LLVM, the `r0` and `r1` registers cannot be used as inputs or outputs. If modified, they must be restored to their original values before the end of the block. | |MSP430 | `r0`, `r2`, `r3` | These are the program counter, status register, and constant generator respectively. Neither the status register nor constant generator can be written to. | | M68k | `a4`, `a5` | Used internally by LLVM for the base pointer and global base pointer. | diff --git a/tests/codegen/asm-powerpc-clobbers.rs b/tests/codegen/asm-powerpc-clobbers.rs index 0be1b66bd99ea..e97e8300ca74b 100644 --- a/tests/codegen/asm-powerpc-clobbers.rs +++ b/tests/codegen/asm-powerpc-clobbers.rs @@ -1,10 +1,12 @@ -//@ revisions: powerpc powerpc64 powerpc64le +//@ revisions: powerpc powerpc64 powerpc64le aix64 //@[powerpc] compile-flags: --target powerpc-unknown-linux-gnu //@[powerpc] needs-llvm-components: powerpc //@[powerpc64] compile-flags: --target powerpc64-unknown-linux-gnu //@[powerpc64] needs-llvm-components: powerpc //@[powerpc64le] compile-flags: --target powerpc64le-unknown-linux-gnu //@[powerpc64le] needs-llvm-components: powerpc +//@[aix64] compile-flags: --target powerpc64-ibm-aix +//@[aix64] needs-llvm-components: powerpc #![crate_type = "rlib"] #![feature(no_core, rustc_attrs, lang_items, asm_experimental_arch)] @@ -22,26 +24,40 @@ macro_rules! asm { // CHECK: call void asm sideeffect "", "~{cr}"() #[no_mangle] pub unsafe fn cr_clobber() { - asm!("", out("cr") _, options(nostack, nomem)); + asm!("", out("cr") _, options(nostack, nomem, preserves_flags)); } // CHECK-LABEL: @cr0_clobber // CHECK: call void asm sideeffect "", "~{cr0}"() #[no_mangle] pub unsafe fn cr0_clobber() { - asm!("", out("cr0") _, options(nostack, nomem)); + asm!("", out("cr0") _, options(nostack, nomem, preserves_flags)); } // CHECK-LABEL: @cr5_clobber // CHECK: call void asm sideeffect "", "~{cr5}"() #[no_mangle] pub unsafe fn cr5_clobber() { - asm!("", out("cr5") _, options(nostack, nomem)); + asm!("", out("cr5") _, options(nostack, nomem, preserves_flags)); } // CHECK-LABEL: @xer_clobber // CHECK: call void asm sideeffect "", "~{xer}"() #[no_mangle] pub unsafe fn xer_clobber() { - asm!("", out("xer") _, options(nostack, nomem)); + asm!("", out("xer") _, options(nostack, nomem, preserves_flags)); +} + +// CHECK-LABEL: @v0_clobber +// CHECK: call void asm sideeffect "", "~{v0}"() +#[no_mangle] +pub unsafe fn v0_clobber() { + asm!("", out("v0") _, options(nostack, nomem, preserves_flags)); +} + +// CHECK-LABEL: @clobber_abi +// CHECK: asm sideeffect "", "={r0},={r3},={r4},={r5},={r6},={r7},={r8},={r9},={r10},={r11},={r12},={f0},={f1},={f2},={f3},={f4},={f5},={f6},={f7},={f8},={f9},={f10},={f11},={f12},={f13},~{v0},~{v1},~{v2},~{v3},~{v4},~{v5},~{v6},~{v7},~{v8},~{v9},~{v10},~{v11},~{v12},~{v13},~{v14},~{v15},~{v16},~{v17},~{v18},~{v19},~{cr0},~{cr1},~{cr5},~{cr6},~{cr7},~{xer}"() +#[no_mangle] +pub unsafe fn clobber_abi() { + asm!("", clobber_abi("C"), options(nostack, nomem, preserves_flags)); }