From 5f6fa960c254dfda8ba1d5dc2fb281b6908d8005 Mon Sep 17 00:00:00 2001 From: Paul Murphy Date: Tue, 4 Nov 2025 10:58:10 -0600 Subject: [PATCH] Relax r29 inline asm restriction on PowerPC64 targets LLVM uses r29 to hold a base pointer for some PowerPC target configurations. It is usable on all 64 bit targets as a callee save register. --- compiler/rustc_target/src/asm/powerpc.rs | 19 ++++++++++++++++--- .../asm-experimental-arch.md | 8 +++++--- tests/ui/asm/powerpc/bad-reg.aix64.stderr | 8 +------- tests/ui/asm/powerpc/bad-reg.powerpc.stderr | 12 ++++++------ tests/ui/asm/powerpc/bad-reg.powerpc64.stderr | 8 +------- .../ui/asm/powerpc/bad-reg.powerpc64le.stderr | 8 +------- tests/ui/asm/powerpc/bad-reg.rs | 2 +- 7 files changed, 31 insertions(+), 34 deletions(-) diff --git a/compiler/rustc_target/src/asm/powerpc.rs b/compiler/rustc_target/src/asm/powerpc.rs index 2824d5dde9d84..09682ee9d4e67 100644 --- a/compiler/rustc_target/src/asm/powerpc.rs +++ b/compiler/rustc_target/src/asm/powerpc.rs @@ -82,6 +82,20 @@ fn reserved_r13( } } +fn reserved_r29( + arch: InlineAsmArch, + _reloc_model: RelocModel, + _target_features: &FxIndexSet, + _target: &Target, + _is_clobber: bool, +) -> Result<(), &'static str> { + if arch != InlineAsmArch::PowerPC { + Ok(()) + } else { + Err("r29 is used internally by LLVM and cannot be used as an operand for inline asm") + } +} + fn reserved_v20to31( _arch: InlineAsmArch, _reloc_model: RelocModel, @@ -129,6 +143,7 @@ def_regs! { r26: reg, reg_nonzero = ["r26", "26"], r27: reg, reg_nonzero = ["r27", "27"], r28: reg, reg_nonzero = ["r28", "28"], + r29: reg, reg_nonzero = ["r29", "29"] % reserved_r29, f0: freg = ["f0", "fr0"], f1: freg = ["f1", "fr1"], f2: freg = ["f2", "fr2"], @@ -274,8 +289,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 = ["r29", "29"] => - "r29 is used internally by LLVM and cannot be used as an operand for inline asm", #error = ["r30", "30"] => "r30 is used internally by LLVM and cannot be used as an operand for inline asm", #error = ["r31", "31", "fp"] => @@ -306,7 +319,7 @@ impl PowerPCInlineAsmReg { (r0, "0"), (r3, "3"), (r4, "4"), (r5, "5"), (r6, "6"), (r7, "7"); (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"); + (r24, "24"), (r25, "25"), (r26, "26"), (r27, "27"), (r28, "28"), (r29, "29"); (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"); 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 94de948a480eb..c96605fb7944c 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,8 +31,8 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | NVPTX | `reg64` | None\* | `l` | | Hexagon | `reg` | `r[0-28]` | `r` | | Hexagon | `preg` | `p[0-3]` | Only clobbers | -| PowerPC | `reg` | `r0`, `r[3-12]`, `r[14-28]` | `r` | -| PowerPC | `reg_nonzero` | `r[3-12]`, `r[14-28]` | `b` | +| PowerPC | `reg` | `r0`, `r[3-12]`, `r[14-29]`\* | `r` | +| PowerPC | `reg_nonzero` | `r[3-12]`, `r[14-29]`\* | `b` | | PowerPC | `freg` | `f[0-31]` | `f` | | PowerPC | `vreg` | `v[0-31]` | `v` | | PowerPC | `vsreg | `vs[0-63]` | `wa` | @@ -61,6 +61,8 @@ This feature tracks `asm!` and `global_asm!` support for the following architect > - NVPTX doesn't have a fixed register set, so named registers are not supported. > > - WebAssembly doesn't have registers, so named registers are not supported. +> +> - r29 is reserved only on 32 bit PowerPC targets. # Register class supported types @@ -148,7 +150,7 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | ------------ | --------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | All | `sp`, `r14`/`o6` (SPARC) | The stack pointer must be restored to its original value at the end of an asm code block. | | All | `fr` (Hexagon), `fp` (PowerPC), `$fp` (MIPS), `Y` (AVR), `r4` (MSP430), `a6` (M68k), `r30`/`i6` (SPARC) | The frame pointer cannot be used as an input or output. | -| All | `r19` (Hexagon), `r29` (PowerPC), `r30` (PowerPC) | These are used internally by LLVM as "base pointer" for functions with complex stack frames. | +| All | `r19` (Hexagon), `r29` (PowerPC 32 bit only), `r30` (PowerPC) | These are used internally by LLVM as "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. | diff --git a/tests/ui/asm/powerpc/bad-reg.aix64.stderr b/tests/ui/asm/powerpc/bad-reg.aix64.stderr index 67ad0a5d2c45a..4490053215b5d 100644 --- a/tests/ui/asm/powerpc/bad-reg.aix64.stderr +++ b/tests/ui/asm/powerpc/bad-reg.aix64.stderr @@ -10,12 +10,6 @@ error: invalid register `r2`: r2 is a system reserved register and cannot be use LL | asm!("", out("r2") _); | ^^^^^^^^^^^ -error: invalid register `r29`: r29 is used internally by LLVM and cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:42:18 - | -LL | asm!("", out("r29") _); - | ^^^^^^^^^^^^ - error: invalid register `r30`: r30 is used internally by LLVM and cannot be used as an operand for inline asm --> $DIR/bad-reg.rs:44:18 | @@ -856,5 +850,5 @@ LL | asm!("/* {} */", in(xer) x); | = note: register class `xer` supports these types: -error: aborting due to 113 previous errors +error: aborting due to 112 previous errors diff --git a/tests/ui/asm/powerpc/bad-reg.powerpc.stderr b/tests/ui/asm/powerpc/bad-reg.powerpc.stderr index 64a8f6a3d5b93..651e8cdfd3d51 100644 --- a/tests/ui/asm/powerpc/bad-reg.powerpc.stderr +++ b/tests/ui/asm/powerpc/bad-reg.powerpc.stderr @@ -10,12 +10,6 @@ error: invalid register `r2`: r2 is a system reserved register and cannot be use LL | asm!("", out("r2") _); | ^^^^^^^^^^^ -error: invalid register `r29`: r29 is used internally by LLVM and cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:42:18 - | -LL | asm!("", out("r29") _); - | ^^^^^^^^^^^^ - error: invalid register `r30`: r30 is used internally by LLVM and cannot be used as an operand for inline asm --> $DIR/bad-reg.rs:44:18 | @@ -712,6 +706,12 @@ error: cannot use register `r13`: r13 is a reserved register on this target LL | asm!("", out("r13") _); | ^^^^^^^^^^^^ +error: cannot use register `r29`: r29 is used internally by LLVM and cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:42:18 + | +LL | asm!("", out("r29") _); + | ^^^^^^^^^^^^ + error: register class `vreg` requires at least one of the following target features: altivec, vsx --> $DIR/bad-reg.rs:53:18 | diff --git a/tests/ui/asm/powerpc/bad-reg.powerpc64.stderr b/tests/ui/asm/powerpc/bad-reg.powerpc64.stderr index 3315a00cc1ab4..552fb0504b8de 100644 --- a/tests/ui/asm/powerpc/bad-reg.powerpc64.stderr +++ b/tests/ui/asm/powerpc/bad-reg.powerpc64.stderr @@ -10,12 +10,6 @@ error: invalid register `r2`: r2 is a system reserved register and cannot be use LL | asm!("", out("r2") _); | ^^^^^^^^^^^ -error: invalid register `r29`: r29 is used internally by LLVM and cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:42:18 - | -LL | asm!("", out("r29") _); - | ^^^^^^^^^^^^ - error: invalid register `r30`: r30 is used internally by LLVM and cannot be used as an operand for inline asm --> $DIR/bad-reg.rs:44:18 | @@ -916,5 +910,5 @@ LL | asm!("/* {} */", in(xer) x); | = note: register class `xer` supports these types: -error: aborting due to 123 previous errors +error: aborting due to 122 previous errors diff --git a/tests/ui/asm/powerpc/bad-reg.powerpc64le.stderr b/tests/ui/asm/powerpc/bad-reg.powerpc64le.stderr index 67ad0a5d2c45a..4490053215b5d 100644 --- a/tests/ui/asm/powerpc/bad-reg.powerpc64le.stderr +++ b/tests/ui/asm/powerpc/bad-reg.powerpc64le.stderr @@ -10,12 +10,6 @@ error: invalid register `r2`: r2 is a system reserved register and cannot be use LL | asm!("", out("r2") _); | ^^^^^^^^^^^ -error: invalid register `r29`: r29 is used internally by LLVM and cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:42:18 - | -LL | asm!("", out("r29") _); - | ^^^^^^^^^^^^ - error: invalid register `r30`: r30 is used internally by LLVM and cannot be used as an operand for inline asm --> $DIR/bad-reg.rs:44:18 | @@ -856,5 +850,5 @@ LL | asm!("/* {} */", in(xer) x); | = note: register class `xer` supports these types: -error: aborting due to 113 previous errors +error: aborting due to 112 previous errors diff --git a/tests/ui/asm/powerpc/bad-reg.rs b/tests/ui/asm/powerpc/bad-reg.rs index 6ded9b97eb88f..7ceae5c6d8d36 100644 --- a/tests/ui/asm/powerpc/bad-reg.rs +++ b/tests/ui/asm/powerpc/bad-reg.rs @@ -40,7 +40,7 @@ fn f() { asm!("", out("r13") _); //~^ ERROR cannot use register `r13`: r13 is a reserved register on this target asm!("", out("r29") _); - //~^ ERROR invalid register `r29`: r29 is used internally by LLVM and cannot be used as an operand for inline asm + //[powerpc]~^ ERROR cannot use register `r29`: r29 is used internally by LLVM and cannot be used as an operand for inline asm asm!("", out("r30") _); //~^ ERROR invalid register `r30`: r30 is used internally by LLVM and cannot be used as an operand for inline asm asm!("", out("fp") _);