From 5802f60355b8b9a1eaf0c0fc193de3b9c48853df Mon Sep 17 00:00:00 2001 From: Jacob Lifshay Date: Wed, 25 Aug 2021 21:45:37 -0700 Subject: [PATCH] add support for clobbering xer, cr, and cr[0-7] for asm! on OpenPower/PowerPC Fixes #88315 --- compiler/rustc_codegen_llvm/src/asm.rs | 8 +++ compiler/rustc_span/src/symbol.rs | 2 + compiler/rustc_target/src/asm/mod.rs | 2 +- compiler/rustc_target/src/asm/powerpc.rs | 69 ++++++++++++++++--- .../unstable-book/src/library-features/asm.md | 4 ++ src/test/assembly/asm/powerpc-types.rs | 12 ++++ src/test/codegen/asm-powerpc-clobbers.rs | 48 +++++++++++++ 7 files changed, 135 insertions(+), 10 deletions(-) create mode 100644 src/test/codegen/asm-powerpc-clobbers.rs diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index 4387f5301a5..527ad1c7b0b 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -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) => { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index f788eb7d212..8ce2e7b06f8 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -478,6 +478,7 @@ core_panic_macro, cosf32, cosf64, + cr, crate_id, crate_in_paths, crate_local, @@ -1415,6 +1416,7 @@ wreg, write_bytes, x87_reg, + xer, xmm_reg, ymm_reg, zmm_reg, diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs index bb24f7bb135..2a3591566a9 100644 --- a/compiler/rustc_target/src/asm/mod.rs +++ b/compiler/rustc_target/src/asm/mod.rs @@ -344,7 +344,7 @@ pub fn overlapping_regs(self, mut cb: impl FnMut(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))), diff --git a/compiler/rustc_target/src/asm/powerpc.rs b/compiler/rustc_target/src/asm/powerpc.rs index 42fc25c4ff5..51a4303689e 100644 --- a/compiler/rustc_target/src/asm/powerpc.rs +++ b/compiler/rustc_target/src/asm/powerpc.rs @@ -7,6 +7,8 @@ reg, reg_nonzero, freg, + cr, + xer, } } @@ -44,6 +46,7 @@ pub fn supported_types( } } Self::freg => types! { _: F32, F64; }, + Self::cr | Self::xer => &[], } } } @@ -108,6 +111,16 @@ pub fn supported_types( 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 @@ pub fn emit( _arch: InlineAsmArch, _modifier: Option, ) -> 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; + } + } } diff --git a/src/doc/unstable-book/src/library-features/asm.md b/src/doc/unstable-book/src/library-features/asm.md index 220b74ca6e6..fd929d842c9 100644 --- a/src/doc/unstable-book/src/library-features/asm.md +++ b/src/doc/unstable-book/src/library-features/asm.md @@ -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` | diff --git a/src/test/assembly/asm/powerpc-types.rs b/src/test/assembly/asm/powerpc-types.rs index 1e263649e86..55ca8ee836c 100644 --- a/src/test/assembly/asm/powerpc-types.rs +++ b/src/test/assembly/asm/powerpc-types.rs @@ -194,3 +194,15 @@ pub unsafe fn $func(x: $ty) -> $ty { // 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"); diff --git a/src/test/codegen/asm-powerpc-clobbers.rs b/src/test/codegen/asm-powerpc-clobbers.rs new file mode 100644 index 00000000000..91a82c60120 --- /dev/null +++ b/src/test/codegen/asm-powerpc-clobbers.rs @@ -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)); +} -- 2.44.0