add support for clobbering xer, cr, and cr[0-7] for asm! on OpenPower/PowerPC

Fixes #88315
This commit is contained in:
Jacob Lifshay 2021-08-25 21:45:37 -07:00
parent 0afc20860e
commit 5802f60355
7 changed files with 135 additions and 10 deletions

View File

@ -615,6 +615,10 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'tcx>>)
InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg) => "r",
InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg_nonzero) => "b",
InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::freg) => "f",
InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::cr)
| InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::xer) => {
unreachable!("clobber-only")
}
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) => "r",
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => "f",
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::vreg) => {
@ -751,6 +755,10 @@ fn dummy_output_type(cx: &CodegenCx<'ll, 'tcx>, reg: InlineAsmRegClass) -> &'ll
InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg) => cx.type_i32(),
InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg_nonzero) => cx.type_i32(),
InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::freg) => cx.type_f64(),
InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::cr)
| InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::xer) => {
unreachable!("clobber-only")
}
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) => cx.type_i32(),
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => cx.type_f32(),
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::vreg) => {

View File

@ -478,6 +478,7 @@ symbols! {
core_panic_macro,
cosf32,
cosf64,
cr,
crate_id,
crate_in_paths,
crate_local,
@ -1415,6 +1416,7 @@ symbols! {
wreg,
write_bytes,
x87_reg,
xer,
xmm_reg,
ymm_reg,
zmm_reg,

View File

@ -344,7 +344,7 @@ impl InlineAsmReg {
Self::Arm(r) => r.overlapping_regs(|r| cb(Self::Arm(r))),
Self::AArch64(_) => cb(self),
Self::RiscV(_) => cb(self),
Self::PowerPC(_) => cb(self),
Self::PowerPC(r) => r.overlapping_regs(|r| cb(Self::PowerPC(r))),
Self::Hexagon(r) => r.overlapping_regs(|r| cb(Self::Hexagon(r))),
Self::Mips(_) => cb(self),
Self::Bpf(r) => r.overlapping_regs(|r| cb(Self::Bpf(r))),

View File

@ -7,6 +7,8 @@ def_reg_class! {
reg,
reg_nonzero,
freg,
cr,
xer,
}
}
@ -44,6 +46,7 @@ impl PowerPCInlineAsmRegClass {
}
}
Self::freg => types! { _: F32, F64; },
Self::cr | Self::xer => &[],
}
}
}
@ -108,6 +111,16 @@ def_regs! {
f29: freg = ["f29", "fr29"],
f30: freg = ["f30", "fr30"],
f31: freg = ["f31", "fr31"],
cr: cr = ["cr"],
cr0: cr = ["cr0"],
cr1: cr = ["cr1"],
cr2: cr = ["cr2"],
cr3: cr = ["cr3"],
cr4: cr = ["cr4"],
cr5: cr = ["cr5"],
cr6: cr = ["cr6"],
cr7: cr = ["cr7"],
xer: xer = ["xer"],
#error = ["r1", "1", "sp"] =>
"the stack pointer cannot be used as an operand for inline asm",
#error = ["r2", "2"] =>
@ -136,17 +149,55 @@ impl PowerPCInlineAsmReg {
_arch: InlineAsmArch,
_modifier: Option<char>,
) -> fmt::Result {
macro_rules! do_emit {
(
$($(($reg:ident, $value:literal)),*;)*
) => {
out.write_str(match self {
$($(Self::$reg => $value,)*)*
})
};
}
// Strip off the leading prefix.
if self as u32 <= Self::r28 as u32 {
let index = self as u32 - Self::r28 as u32;
write!(out, "{}", index)
} else if self as u32 >= Self::f0 as u32 && self as u32 <= Self::f31 as u32 {
let index = self as u32 - Self::f31 as u32;
write!(out, "{}", index)
} else {
unreachable!()
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");
(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");
(cr, "cr");
(cr0, "0"), (cr1, "1"), (cr2, "2"), (cr3, "3"), (cr4, "4"), (cr5, "5"), (cr6, "6"), (cr7, "7");
(xer, "xer");
}
}
pub fn overlapping_regs(self, mut _cb: impl FnMut(PowerPCInlineAsmReg)) {}
pub fn overlapping_regs(self, mut cb: impl FnMut(PowerPCInlineAsmReg)) {
macro_rules! reg_conflicts {
(
$(
$full:ident : $($field:ident)*
),*;
) => {
match self {
$(
Self::$full => {
cb(Self::$full);
$(cb(Self::$field);)*
}
$(Self::$field)|* => {
cb(Self::$full);
cb(self);
}
)*
r => cb(r),
}
};
}
reg_conflicts! {
cr : cr0 cr1 cr2 cr3 cr4 cr5 cr6 cr7;
}
}
}

View File

@ -584,6 +584,8 @@ Here is the list of currently supported register classes:
| PowerPC | `reg` | `r[0-31]` | `r` |
| PowerPC | `reg_nonzero` | | `r[1-31]` | `b` |
| PowerPC | `freg` | `f[0-31]` | `f` |
| PowerPC | `cr` | `cr[0-7]`, `cr` | Only clobbers |
| PowerPC | `xer` | `xer` | Only clobbers |
| wasm32 | `local` | None\* | `r` |
| BPF | `reg` | `r[0-10]` | `r` |
| BPF | `wreg` | `w[0-10]` | `w` |
@ -637,6 +639,8 @@ Each register class has constraints on which value types they can be used with.
| PowerPC | `reg` | None | `i8`, `i16`, `i32` |
| PowerPC | `reg_nonzero` | None | `i8`, `i16`, `i32` |
| PowerPC | `freg` | None | `f32`, `f64` |
| PowerPC | `cr` | N/A | Only clobbers |
| PowerPC | `xer` | N/A | Only clobbers |
| wasm32 | `local` | None | `i8` `i16` `i32` `i64` `f32` `f64` |
| BPF | `reg` | None | `i8` `i16` `i32` `i64` |
| BPF | `wreg` | `alu32` | `i8` `i16` `i32` |

View File

@ -194,3 +194,15 @@ check_reg!(reg_f32_f0, f32, "0", "f0", "fmr");
// CHECK: fmr 0, 0
// CHECK: #NO_APP
check_reg!(reg_f64_f0, f64, "0", "f0", "fmr");
// CHECK-LABEL: reg_f32_f18:
// CHECK: #APP
// CHECK: fmr 18, 18
// CHECK: #NO_APP
check_reg!(reg_f32_f18, f32, "18", "f18", "fmr");
// CHECK-LABEL: reg_f64_f18:
// CHECK: #APP
// CHECK: fmr 18, 18
// CHECK: #NO_APP
check_reg!(reg_f64_f18, f64, "18", "f18", "fmr");

View File

@ -0,0 +1,48 @@
// min-llvm-version: 10.0.1
// revisions: powerpc powerpc64 powerpc64le
//[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
#![crate_type = "rlib"]
#![feature(no_core, rustc_attrs, lang_items)]
#![no_core]
#[lang = "sized"]
trait Sized {}
#[rustc_builtin_macro]
macro_rules! asm {
() => {};
}
// CHECK-LABEL: @cr_clobber
// CHECK: call void asm sideeffect "", "~{cr}"()
#[no_mangle]
pub unsafe fn cr_clobber() {
asm!("", out("cr") _, options(nostack, nomem));
}
// CHECK-LABEL: @cr0_clobber
// CHECK: call void asm sideeffect "", "~{cr0}"()
#[no_mangle]
pub unsafe fn cr0_clobber() {
asm!("", out("cr0") _, options(nostack, nomem));
}
// CHECK-LABEL: @cr5_clobber
// CHECK: call void asm sideeffect "", "~{cr5}"()
#[no_mangle]
pub unsafe fn cr5_clobber() {
asm!("", out("cr5") _, options(nostack, nomem));
}
// CHECK-LABEL: @xer_clobber
// CHECK: call void asm sideeffect "", "~{xer}"()
#[no_mangle]
pub unsafe fn xer_clobber() {
asm!("", out("xer") _, options(nostack, nomem));
}