Skip to content

Commit 369edf1

Browse files
committed
Support clobber_abi and vector registers (clobber-only) in PowerPC inline assembly
1 parent 8f8bee4 commit 369edf1

File tree

6 files changed

+184
-17
lines changed

6 files changed

+184
-17
lines changed

compiler/rustc_codegen_gcc/src/asm.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -654,7 +654,8 @@ fn reg_to_gcc(reg: InlineAsmRegOrRegClass) -> ConstraintOrRegister {
654654
InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg_nonzero) => "b",
655655
InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::freg) => "f",
656656
InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::cr)
657-
| InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::xer) => {
657+
| InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::xer)
658+
| InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::vreg) => {
658659
unreachable!("clobber-only")
659660
}
660661
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) => "r",
@@ -729,7 +730,8 @@ fn dummy_output_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, reg: InlineAsmRegCl
729730
InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg_nonzero) => cx.type_i32(),
730731
InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::freg) => cx.type_f64(),
731732
InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::cr)
732-
| InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::xer) => {
733+
| InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::xer)
734+
| InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::vreg) => {
733735
unreachable!("clobber-only")
734736
}
735737
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) => cx.type_i32(),

compiler/rustc_codegen_llvm/src/asm.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -679,7 +679,9 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'_>>) ->
679679
PowerPC(PowerPCInlineAsmRegClass::reg) => "r",
680680
PowerPC(PowerPCInlineAsmRegClass::reg_nonzero) => "b",
681681
PowerPC(PowerPCInlineAsmRegClass::freg) => "f",
682-
PowerPC(PowerPCInlineAsmRegClass::cr) | PowerPC(PowerPCInlineAsmRegClass::xer) => {
682+
PowerPC(PowerPCInlineAsmRegClass::cr)
683+
| PowerPC(PowerPCInlineAsmRegClass::xer)
684+
| PowerPC(PowerPCInlineAsmRegClass::vreg) => {
683685
unreachable!("clobber-only")
684686
}
685687
RiscV(RiscVInlineAsmRegClass::reg) => "r",
@@ -841,7 +843,9 @@ fn dummy_output_type<'ll>(cx: &CodegenCx<'ll, '_>, reg: InlineAsmRegClass) -> &'
841843
PowerPC(PowerPCInlineAsmRegClass::reg) => cx.type_i32(),
842844
PowerPC(PowerPCInlineAsmRegClass::reg_nonzero) => cx.type_i32(),
843845
PowerPC(PowerPCInlineAsmRegClass::freg) => cx.type_f64(),
844-
PowerPC(PowerPCInlineAsmRegClass::cr) | PowerPC(PowerPCInlineAsmRegClass::xer) => {
846+
PowerPC(PowerPCInlineAsmRegClass::cr)
847+
| PowerPC(PowerPCInlineAsmRegClass::xer)
848+
| PowerPC(PowerPCInlineAsmRegClass::vreg) => {
845849
unreachable!("clobber-only")
846850
}
847851
RiscV(RiscVInlineAsmRegClass::reg) => cx.type_i32(),

compiler/rustc_target/src/asm/mod.rs

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -892,6 +892,8 @@ pub enum InlineAsmClobberAbi {
892892
AArch64NoX18,
893893
RiscV,
894894
LoongArch,
895+
PowerPC,
896+
PowerPCNoR13,
895897
S390x,
896898
Msp430,
897899
}
@@ -943,6 +945,14 @@ impl InlineAsmClobberAbi {
943945
"C" | "system" => Ok(InlineAsmClobberAbi::LoongArch),
944946
_ => Err(&["C", "system"]),
945947
},
948+
InlineAsmArch::PowerPC | InlineAsmArch::PowerPC64 => match name {
949+
"C" | "system" => Ok(if powerpc::target_reserves_r13(arch, target) {
950+
InlineAsmClobberAbi::PowerPCNoR13
951+
} else {
952+
InlineAsmClobberAbi::PowerPC
953+
}),
954+
_ => Err(&["C", "system"]),
955+
},
946956
InlineAsmArch::S390x => match name {
947957
"C" | "system" => Ok(InlineAsmClobberAbi::S390x),
948958
_ => Err(&["C", "system"]),
@@ -1108,6 +1118,54 @@ impl InlineAsmClobberAbi {
11081118
f16, f17, f18, f19, f20, f21, f22, f23,
11091119
}
11101120
},
1121+
InlineAsmClobberAbi::PowerPC => clobbered_regs! {
1122+
PowerPC PowerPCInlineAsmReg {
1123+
// r0, r3-r13
1124+
r0,
1125+
r3, r4, r5, r6, r7,
1126+
r8, r9, r10, r11, r12, r13,
1127+
1128+
// f0-f13
1129+
f0, f1, f2, f3, f4, f5, f6, f7,
1130+
f8, f9, f10, f11, f12, f13,
1131+
1132+
// v0-v19
1133+
v0, v1, v2, v3, v4, v5, v6, v7,
1134+
v8, v9, v10, v11, v12, v13, v14,
1135+
v15, v16, v17, v18, v19,
1136+
1137+
// cr0-cr1, cr5-cr7, xer
1138+
cr0, cr1,
1139+
cr5, cr6, cr7,
1140+
xer,
1141+
// lr and ctr are reserved
1142+
}
1143+
},
1144+
InlineAsmClobberAbi::PowerPCNoR13 => clobbered_regs! {
1145+
PowerPC PowerPCInlineAsmReg {
1146+
// r0, r3-r12
1147+
r0,
1148+
r3, r4, r5, r6, r7,
1149+
r8, r9, r10, r11, r12,
1150+
1151+
// f0-f13
1152+
f0, f1, f2, f3, f4, f5, f6, f7,
1153+
f8, f9, f10, f11, f12, f13,
1154+
1155+
// v0-v19
1156+
// FIXME: PPC32 SysV ABI does not mention vector registers processing.
1157+
// https://refspecs.linuxfoundation.org/elf/elfspec_ppc.pdf
1158+
v0, v1, v2, v3, v4, v5, v6, v7,
1159+
v8, v9, v10, v11, v12, v13, v14,
1160+
v15, v16, v17, v18, v19,
1161+
1162+
// cr0-cr1, cr5-cr7, xer
1163+
cr0, cr1,
1164+
cr5, cr6, cr7,
1165+
xer,
1166+
// lr and ctr are reserved
1167+
}
1168+
},
11111169
InlineAsmClobberAbi::S390x => clobbered_regs! {
11121170
S390x S390xInlineAsmReg {
11131171
r0, r1, r2, r3, r4, r5,

compiler/rustc_target/src/asm/powerpc.rs

Lines changed: 79 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
use std::fmt;
22

3+
use rustc_data_structures::fx::FxIndexSet;
34
use rustc_span::Symbol;
45

56
use super::{InlineAsmArch, InlineAsmType, ModifierInfo};
7+
use crate::spec::{RelocModel, Target};
68

79
def_reg_class! {
810
PowerPC PowerPCInlineAsmRegClass {
911
reg,
1012
reg_nonzero,
1113
freg,
14+
vreg,
1215
cr,
1316
xer,
1417
}
@@ -48,11 +51,48 @@ impl PowerPCInlineAsmRegClass {
4851
}
4952
}
5053
Self::freg => types! { _: F32, F64; },
54+
Self::vreg => &[],
5155
Self::cr | Self::xer => &[],
5256
}
5357
}
5458
}
5559

60+
pub(crate) fn target_reserves_r13(arch: InlineAsmArch, target: &Target) -> bool {
61+
!(target.is_like_aix && arch == InlineAsmArch::PowerPC)
62+
}
63+
64+
fn reserved_r13(
65+
arch: InlineAsmArch,
66+
_reloc_model: RelocModel,
67+
_target_features: &FxIndexSet<Symbol>,
68+
target: &Target,
69+
_is_clobber: bool,
70+
) -> Result<(), &'static str> {
71+
if target_reserves_r13(arch, target) {
72+
Err("r13 is a reserved register on this target")
73+
} else {
74+
Ok(())
75+
}
76+
}
77+
78+
fn reserved_v20to31(
79+
_arch: InlineAsmArch,
80+
_reloc_model: RelocModel,
81+
_target_features: &FxIndexSet<Symbol>,
82+
target: &Target,
83+
_is_clobber: bool,
84+
) -> Result<(), &'static str> {
85+
if target.is_like_aix {
86+
match &*target.options.abi {
87+
"vec-default" => Err("v20-v31 are reserved on vec-default ABI"),
88+
"vec-extabi" => Ok(()),
89+
_ => unreachable!("unrecognized AIX ABI"),
90+
}
91+
} else {
92+
Ok(())
93+
}
94+
}
95+
5696
def_regs! {
5797
PowerPC PowerPCInlineAsmReg PowerPCInlineAsmRegClass {
5898
r0: reg = ["r0", "0"],
@@ -66,6 +106,7 @@ def_regs! {
66106
r10: reg, reg_nonzero = ["r10", "10"],
67107
r11: reg, reg_nonzero = ["r11", "11"],
68108
r12: reg, reg_nonzero = ["r12", "12"],
109+
r13: reg, reg_nonzero = ["r13", "13"] % reserved_r13,
69110
r14: reg, reg_nonzero = ["r14", "14"],
70111
r15: reg, reg_nonzero = ["r15", "15"],
71112
r16: reg, reg_nonzero = ["r16", "16"],
@@ -113,6 +154,38 @@ def_regs! {
113154
f29: freg = ["f29", "fr29"],
114155
f30: freg = ["f30", "fr30"],
115156
f31: freg = ["f31", "fr31"],
157+
v0: vreg = ["v0"],
158+
v1: vreg = ["v1"],
159+
v2: vreg = ["v2"],
160+
v3: vreg = ["v3"],
161+
v4: vreg = ["v4"],
162+
v5: vreg = ["v5"],
163+
v6: vreg = ["v6"],
164+
v7: vreg = ["v7"],
165+
v8: vreg = ["v8"],
166+
v9: vreg = ["v9"],
167+
v10: vreg = ["v10"],
168+
v11: vreg = ["v11"],
169+
v12: vreg = ["v12"],
170+
v13: vreg = ["v13"],
171+
v14: vreg = ["v14"],
172+
v15: vreg = ["v15"],
173+
v16: vreg = ["v16"],
174+
v17: vreg = ["v17"],
175+
v18: vreg = ["v18"],
176+
v19: vreg = ["v19"],
177+
v20: vreg = ["v20"] % reserved_v20to31,
178+
v21: vreg = ["v21"] % reserved_v20to31,
179+
v22: vreg = ["v22"] % reserved_v20to31,
180+
v23: vreg = ["v23"] % reserved_v20to31,
181+
v24: vreg = ["v24"] % reserved_v20to31,
182+
v25: vreg = ["v25"] % reserved_v20to31,
183+
v26: vreg = ["v26"] % reserved_v20to31,
184+
v27: vreg = ["v27"] % reserved_v20to31,
185+
v28: vreg = ["v28"] % reserved_v20to31,
186+
v29: vreg = ["v29"] % reserved_v20to31,
187+
v30: vreg = ["v30"] % reserved_v20to31,
188+
v31: vreg = ["v31"] % reserved_v20to31,
116189
cr: cr = ["cr"],
117190
cr0: cr = ["cr0"],
118191
cr1: cr = ["cr1"],
@@ -127,8 +200,6 @@ def_regs! {
127200
"the stack pointer cannot be used as an operand for inline asm",
128201
#error = ["r2", "2"] =>
129202
"r2 is a system reserved register and cannot be used as an operand for inline asm",
130-
#error = ["r13", "13"] =>
131-
"r13 is a system reserved register and cannot be used as an operand for inline asm",
132203
#error = ["r29", "29"] =>
133204
"r29 is used internally by LLVM and cannot be used as an operand for inline asm",
134205
#error = ["r30", "30"] =>
@@ -163,13 +234,17 @@ impl PowerPCInlineAsmReg {
163234
// Strip off the leading prefix.
164235
do_emit! {
165236
(r0, "0"), (r3, "3"), (r4, "4"), (r5, "5"), (r6, "6"), (r7, "7");
166-
(r8, "8"), (r9, "9"), (r10, "10"), (r11, "11"), (r12, "12"), (r14, "14"), (r15, "15");
237+
(r8, "8"), (r9, "9"), (r10, "10"), (r11, "11"), (r12, "12"), (r13, "13"), (r14, "14"), (r15, "15");
167238
(r16, "16"), (r17, "17"), (r18, "18"), (r19, "19"), (r20, "20"), (r21, "21"), (r22, "22"), (r23, "23");
168239
(r24, "24"), (r25, "25"), (r26, "26"), (r27, "27"), (r28, "28");
169240
(f0, "0"), (f1, "1"), (f2, "2"), (f3, "3"), (f4, "4"), (f5, "5"), (f6, "6"), (f7, "7");
170241
(f8, "8"), (f9, "9"), (f10, "10"), (f11, "11"), (f12, "12"), (f13, "13"), (f14, "14"), (f15, "15");
171242
(f16, "16"), (f17, "17"), (f18, "18"), (f19, "19"), (f20, "20"), (f21, "21"), (f22, "22"), (f23, "23");
172243
(f24, "24"), (f25, "25"), (f26, "26"), (f27, "27"), (f28, "28"), (f29, "29"), (f30, "30"), (f31, "31");
244+
(v0, "0"), (v1, "1"), (v2, "2"), (v3, "3"), (v4, "4"), (v5, "5"), (v6, "6"), (v7, "7");
245+
(v8, "8"), (v9, "9"), (v10, "10"), (v11, "11"), (v12, "12"), (v13, "13"), (v14, "14"), (v15, "15");
246+
(v16, "16"), (v17, "17"), (v18, "18"), (v19, "19"), (v20, "20"), (v21, "21"), (v22, "22"), (v23, "23");
247+
(v24, "24"), (v25, "25"), (v26, "26"), (v27, "27"), (v28, "28"), (v29, "29"), (v30, "30"), (v31, "31");
173248
(cr, "cr");
174249
(cr0, "0"), (cr1, "1"), (cr2, "2"), (cr3, "3"), (cr4, "4"), (cr5, "5"), (cr6, "6"), (cr7, "7");
175250
(xer, "xer");
@@ -201,5 +276,6 @@ impl PowerPCInlineAsmReg {
201276
reg_conflicts! {
202277
cr : cr0 cr1 cr2 cr3 cr4 cr5 cr6 cr7;
203278
}
279+
// f0-f31 (vsr0-vsr31) and v0-v31 (vsr32-vsr63) do not conflict.
204280
}
205281
}

src/doc/unstable-book/src/language-features/asm-experimental-arch.md

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,10 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
3131
| NVPTX | `reg32` | None\* | `r` |
3232
| NVPTX | `reg64` | None\* | `l` |
3333
| Hexagon | `reg` | `r[0-28]` | `r` |
34-
| PowerPC | `reg` | `r[0-31]` | `r` |
35-
| PowerPC | `reg_nonzero` | `r[1-31]` | `b` |
34+
| PowerPC | `reg` | `r0`, `r[3-12]`, `r[14-28]` | `r` |
35+
| PowerPC | `reg_nonzero` | `r[3-12]`, `r[14-28]` | `b` |
3636
| PowerPC | `freg` | `f[0-31]` | `f` |
37+
| PowerPC | `vreg` | `v[0-31]` | Only clobbers |
3738
| PowerPC | `cr` | `cr[0-7]`, `cr` | Only clobbers |
3839
| PowerPC | `xer` | `xer` | Only clobbers |
3940
| wasm32 | `local` | None\* | `r` |
@@ -76,9 +77,10 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
7677
| NVPTX | `reg32` | None | `i8`, `i16`, `i32`, `f32` |
7778
| NVPTX | `reg64` | None | `i8`, `i16`, `i32`, `f32`, `i64`, `f64` |
7879
| Hexagon | `reg` | None | `i8`, `i16`, `i32`, `f32` |
79-
| PowerPC | `reg` | None | `i8`, `i16`, `i32` |
80-
| PowerPC | `reg_nonzero` | None | `i8`, `i16`, `i32` |
80+
| PowerPC | `reg` | None | `i8`, `i16`, `i32`, `i64` (powerpc64 only) |
81+
| PowerPC | `reg_nonzero` | None | `i8`, `i16`, `i32`, `i64` (powerpc64 only) |
8182
| PowerPC | `freg` | None | `f32`, `f64` |
83+
| PowerPC | `vreg` | N/A | Only clobbers |
8284
| PowerPC | `cr` | N/A | Only clobbers |
8385
| PowerPC | `xer` | N/A | Only clobbers |
8486
| 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
105107
| Hexagon | `r29` | `sp` |
106108
| Hexagon | `r30` | `fr` |
107109
| Hexagon | `r31` | `lr` |
110+
| PowerPC | `r1` | `sp` |
111+
| PowerPC | `r31` | `fp` |
112+
| PowerPC | `r[0-31]` | `[0-31]` |
113+
| PowerPC | `f[0-31]` | `fr[0-31]`|
108114
| BPF | `r[0-10]` | `w[0-10]` |
109115
| AVR | `XH` | `r27` |
110116
| AVR | `XL` | `r26` |
@@ -145,14 +151,19 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
145151
| Architecture | Unsupported register | Reason |
146152
| ------------ | --------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
147153
| All | `sp`, `r15` (s390x) | The stack pointer must be restored to its original value at the end of an asm code block. |
148-
| 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. |
154+
| 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. |
149155
| All | `r19` (Hexagon), `x19` (Arm64EC) | This is used internally by LLVM as a "base pointer" for functions with complex stack frames. |
150156
| MIPS | `$0` or `$zero` | This is a constant zero register which can't be modified. |
151157
| MIPS | `$1` or `$at` | Reserved for assembler. |
152158
| MIPS | `$26`/`$k0`, `$27`/`$k1` | OS-reserved registers. |
153159
| MIPS | `$28`/`$gp` | Global pointer cannot be used as inputs or outputs. |
154160
| MIPS | `$ra` | Return address cannot be used as inputs or outputs. |
155161
| Hexagon | `lr` | This is the link register which cannot be used as an input or output. |
162+
| PowerPC | `$r2`, `$r13` | These are system reserved registers. |
163+
| PowerPC | `$r29`, `$r30` | These are used internally by LLVM. |
164+
| PowerPC | `lr` | The link register cannot be used as an input or output. |
165+
| PowerPC | `ctr` | The counter register cannot be used as an input or output. |
166+
| PowerPC | `vrsave` | The vrsave register cannot be used as an input or output. |
156167
| 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. |
157168
|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. |
158169
| M68k | `a4`, `a5` | Used internally by LLVM for the base pointer and global base pointer. |

0 commit comments

Comments
 (0)