From b1bb5d662c394cea82ebb212373015ef4684b551 Mon Sep 17 00:00:00 2001 From: "Dr. Chat" Date: Thu, 29 Apr 2021 23:03:08 -0500 Subject: [PATCH] Add initial asm!() support for PowerPC This includes GPRs and FPRs only --- compiler/rustc_codegen_llvm/src/asm.rs | 8 + compiler/rustc_span/src/symbol.rs | 1 + compiler/rustc_target/src/asm/mod.rs | 25 +++ compiler/rustc_target/src/asm/powerpc.rs | 146 ++++++++++++++++ .../unstable-book/src/library-features/asm.md | 12 +- src/test/assembly/asm/powerpc-types.rs | 165 ++++++++++++++++++ 6 files changed, 356 insertions(+), 1 deletion(-) create mode 100644 compiler/rustc_target/src/asm/powerpc.rs create mode 100644 src/test/assembly/asm/powerpc-types.rs diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index 84b091d8d4d..ea08052a9d0 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -283,6 +283,7 @@ impl AsmBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> { } InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {} InlineAsmArch::Nvptx64 => {} + InlineAsmArch::PowerPC => {} InlineAsmArch::Hexagon => {} InlineAsmArch::Mips | InlineAsmArch::Mips64 => {} InlineAsmArch::SpirV => {} @@ -540,6 +541,9 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'tcx>>) InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg16) => "h", InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg32) => "r", InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg64) => "l", + InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg) => "r", + InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg_nonzero) => "b", + InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::freg) => "f", InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) => "r", InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => "f", InlineAsmRegClass::X86(X86InlineAsmRegClass::reg) => "r", @@ -590,6 +594,7 @@ fn modifier_to_llvm( InlineAsmRegClass::Hexagon(_) => None, InlineAsmRegClass::Mips(_) => None, InlineAsmRegClass::Nvptx(_) => None, + InlineAsmRegClass::PowerPC(_) => None, InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) | InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => None, InlineAsmRegClass::X86(X86InlineAsmRegClass::reg) @@ -651,6 +656,9 @@ fn dummy_output_type(cx: &CodegenCx<'ll, 'tcx>, reg: InlineAsmRegClass) -> &'ll InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg16) => cx.type_i16(), InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg32) => cx.type_i32(), InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg64) => cx.type_i64(), + InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg) => cx.type_i32(), + InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg_nonzero) => cx.type_i32(), + InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::freg) => cx.type_f64(), InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) => cx.type_i32(), InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => cx.type_f32(), InlineAsmRegClass::X86(X86InlineAsmRegClass::reg) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 4c80b84e3d2..98aee199632 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -947,6 +947,7 @@ symbols! { reg64, reg_abcd, reg_byte, + reg_nonzero, reg_thumb, register_attr, register_tool, diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs index e2268a61a42..f12debb5a34 100644 --- a/compiler/rustc_target/src/asm/mod.rs +++ b/compiler/rustc_target/src/asm/mod.rs @@ -154,6 +154,7 @@ mod arm; mod hexagon; mod mips; mod nvptx; +mod powerpc; mod riscv; mod spirv; mod wasm; @@ -164,6 +165,7 @@ pub use arm::{ArmInlineAsmReg, ArmInlineAsmRegClass}; pub use hexagon::{HexagonInlineAsmReg, HexagonInlineAsmRegClass}; pub use mips::{MipsInlineAsmReg, MipsInlineAsmRegClass}; pub use nvptx::{NvptxInlineAsmReg, NvptxInlineAsmRegClass}; +pub use powerpc::{PowerPCInlineAsmReg, PowerPCInlineAsmRegClass}; pub use riscv::{RiscVInlineAsmReg, RiscVInlineAsmRegClass}; pub use spirv::{SpirVInlineAsmReg, SpirVInlineAsmRegClass}; pub use wasm::{WasmInlineAsmReg, WasmInlineAsmRegClass}; @@ -181,6 +183,7 @@ pub enum InlineAsmArch { Hexagon, Mips, Mips64, + PowerPC, SpirV, Wasm32, } @@ -197,6 +200,7 @@ impl FromStr for InlineAsmArch { "riscv32" => Ok(Self::RiscV32), "riscv64" => Ok(Self::RiscV64), "nvptx64" => Ok(Self::Nvptx64), + "powerpc" => Ok(Self::PowerPC), "hexagon" => Ok(Self::Hexagon), "mips" => Ok(Self::Mips), "mips64" => Ok(Self::Mips64), @@ -225,6 +229,7 @@ pub enum InlineAsmReg { AArch64(AArch64InlineAsmReg), RiscV(RiscVInlineAsmReg), Nvptx(NvptxInlineAsmReg), + PowerPC(PowerPCInlineAsmReg), Hexagon(HexagonInlineAsmReg), Mips(MipsInlineAsmReg), SpirV(SpirVInlineAsmReg), @@ -240,6 +245,7 @@ impl InlineAsmReg { Self::Arm(r) => r.name(), Self::AArch64(r) => r.name(), Self::RiscV(r) => r.name(), + Self::PowerPC(r) => r.name(), Self::Hexagon(r) => r.name(), Self::Mips(r) => r.name(), Self::Err => "", @@ -252,6 +258,7 @@ impl InlineAsmReg { Self::Arm(r) => InlineAsmRegClass::Arm(r.reg_class()), Self::AArch64(r) => InlineAsmRegClass::AArch64(r.reg_class()), Self::RiscV(r) => InlineAsmRegClass::RiscV(r.reg_class()), + Self::PowerPC(r) => InlineAsmRegClass::PowerPC(r.reg_class()), Self::Hexagon(r) => InlineAsmRegClass::Hexagon(r.reg_class()), Self::Mips(r) => InlineAsmRegClass::Mips(r.reg_class()), Self::Err => InlineAsmRegClass::Err, @@ -283,6 +290,9 @@ impl InlineAsmReg { InlineAsmArch::Nvptx64 => { Self::Nvptx(NvptxInlineAsmReg::parse(arch, has_feature, target, &name)?) } + InlineAsmArch::PowerPC => { + Self::PowerPC(PowerPCInlineAsmReg::parse(arch, has_feature, target, &name)?) + } InlineAsmArch::Hexagon => { Self::Hexagon(HexagonInlineAsmReg::parse(arch, has_feature, target, &name)?) } @@ -311,6 +321,7 @@ impl InlineAsmReg { Self::Arm(r) => r.emit(out, arch, modifier), Self::AArch64(r) => r.emit(out, arch, modifier), Self::RiscV(r) => r.emit(out, arch, modifier), + Self::PowerPC(r) => r.emit(out, arch, modifier), Self::Hexagon(r) => r.emit(out, arch, modifier), Self::Mips(r) => r.emit(out, arch, modifier), Self::Err => unreachable!("Use of InlineAsmReg::Err"), @@ -323,6 +334,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::Hexagon(r) => r.overlapping_regs(|r| cb(Self::Hexagon(r))), Self::Mips(_) => cb(self), Self::Err => unreachable!("Use of InlineAsmReg::Err"), @@ -348,6 +360,7 @@ pub enum InlineAsmRegClass { AArch64(AArch64InlineAsmRegClass), RiscV(RiscVInlineAsmRegClass), Nvptx(NvptxInlineAsmRegClass), + PowerPC(PowerPCInlineAsmRegClass), Hexagon(HexagonInlineAsmRegClass), Mips(MipsInlineAsmRegClass), SpirV(SpirVInlineAsmRegClass), @@ -364,6 +377,7 @@ impl InlineAsmRegClass { Self::AArch64(r) => r.name(), Self::RiscV(r) => r.name(), Self::Nvptx(r) => r.name(), + Self::PowerPC(r) => r.name(), Self::Hexagon(r) => r.name(), Self::Mips(r) => r.name(), Self::SpirV(r) => r.name(), @@ -382,6 +396,7 @@ impl InlineAsmRegClass { Self::AArch64(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::AArch64), Self::RiscV(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::RiscV), Self::Nvptx(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Nvptx), + Self::PowerPC(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::PowerPC), Self::Hexagon(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Hexagon), Self::Mips(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Mips), Self::SpirV(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::SpirV), @@ -407,6 +422,7 @@ impl InlineAsmRegClass { Self::AArch64(r) => r.suggest_modifier(arch, ty), Self::RiscV(r) => r.suggest_modifier(arch, ty), Self::Nvptx(r) => r.suggest_modifier(arch, ty), + Self::PowerPC(r) => r.suggest_modifier(arch, ty), Self::Hexagon(r) => r.suggest_modifier(arch, ty), Self::Mips(r) => r.suggest_modifier(arch, ty), Self::SpirV(r) => r.suggest_modifier(arch, ty), @@ -428,6 +444,7 @@ impl InlineAsmRegClass { Self::AArch64(r) => r.default_modifier(arch), Self::RiscV(r) => r.default_modifier(arch), Self::Nvptx(r) => r.default_modifier(arch), + Self::PowerPC(r) => r.default_modifier(arch), Self::Hexagon(r) => r.default_modifier(arch), Self::Mips(r) => r.default_modifier(arch), Self::SpirV(r) => r.default_modifier(arch), @@ -448,6 +465,7 @@ impl InlineAsmRegClass { Self::AArch64(r) => r.supported_types(arch), Self::RiscV(r) => r.supported_types(arch), Self::Nvptx(r) => r.supported_types(arch), + Self::PowerPC(r) => r.supported_types(arch), Self::Hexagon(r) => r.supported_types(arch), Self::Mips(r) => r.supported_types(arch), Self::SpirV(r) => r.supported_types(arch), @@ -467,6 +485,7 @@ impl InlineAsmRegClass { Self::RiscV(RiscVInlineAsmRegClass::parse(arch, name)?) } InlineAsmArch::Nvptx64 => Self::Nvptx(NvptxInlineAsmRegClass::parse(arch, name)?), + InlineAsmArch::PowerPC => Self::PowerPC(PowerPCInlineAsmRegClass::parse(arch, name)?), InlineAsmArch::Hexagon => Self::Hexagon(HexagonInlineAsmRegClass::parse(arch, name)?), InlineAsmArch::Mips | InlineAsmArch::Mips64 => { Self::Mips(MipsInlineAsmRegClass::parse(arch, name)?) @@ -485,6 +504,7 @@ impl InlineAsmRegClass { Self::AArch64(r) => r.valid_modifiers(arch), Self::RiscV(r) => r.valid_modifiers(arch), Self::Nvptx(r) => r.valid_modifiers(arch), + Self::PowerPC(r) => r.valid_modifiers(arch), Self::Hexagon(r) => r.valid_modifiers(arch), Self::Mips(r) => r.valid_modifiers(arch), Self::SpirV(r) => r.valid_modifiers(arch), @@ -633,6 +653,11 @@ pub fn allocatable_registers( nvptx::fill_reg_map(arch, has_feature, target, &mut map); map } + InlineAsmArch::PowerPC => { + let mut map = powerpc::regclass_map(); + powerpc::fill_reg_map(arch, has_feature, target, &mut map); + map + } InlineAsmArch::Hexagon => { let mut map = hexagon::regclass_map(); hexagon::fill_reg_map(arch, has_feature, target, &mut map); diff --git a/compiler/rustc_target/src/asm/powerpc.rs b/compiler/rustc_target/src/asm/powerpc.rs new file mode 100644 index 00000000000..b254e5f3aaa --- /dev/null +++ b/compiler/rustc_target/src/asm/powerpc.rs @@ -0,0 +1,146 @@ +use super::{InlineAsmArch, InlineAsmType}; +use rustc_macros::HashStable_Generic; +use std::fmt; + +def_reg_class! { + PowerPC PowerPCInlineAsmRegClass { + reg, + reg_nonzero, + freg, + } +} + +impl PowerPCInlineAsmRegClass { + pub fn valid_modifiers(self, _arch: super::InlineAsmArch) -> &'static [char] { + &[] + } + + pub fn suggest_class(self, _arch: InlineAsmArch, _ty: InlineAsmType) -> Option { + None + } + + pub fn suggest_modifier( + self, + _arch: InlineAsmArch, + _ty: InlineAsmType, + ) -> Option<(char, &'static str)> { + None + } + + pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> { + None + } + + pub fn supported_types( + self, + _arch: InlineAsmArch, + ) -> &'static [(InlineAsmType, Option<&'static str>)] { + match self { + Self::reg | Self::reg_nonzero => types! { _: I8, I16, I32; }, + Self::freg => types! { _: F32, F64; }, + } + } +} + +def_regs! { + PowerPC PowerPCInlineAsmReg PowerPCInlineAsmRegClass { + r0: reg = ["r0", "0"], + r3: reg, reg_nonzero = ["r3", "3"], + r4: reg, reg_nonzero = ["r4", "4"], + r5: reg, reg_nonzero = ["r5", "5"], + r6: reg, reg_nonzero = ["r6", "6"], + r7: reg, reg_nonzero = ["r7", "7"], + r8: reg, reg_nonzero = ["r8", "8"], + r9: reg, reg_nonzero = ["r9", "9"], + r10: reg, reg_nonzero = ["r10", "10"], + r11: reg, reg_nonzero = ["r11", "11"], + r12: reg, reg_nonzero = ["r12", "12"], + r14: reg, reg_nonzero = ["r14", "14"], + r15: reg, reg_nonzero = ["r15", "15"], + r16: reg, reg_nonzero = ["r16", "16"], + r17: reg, reg_nonzero = ["r17", "17"], + r18: reg, reg_nonzero = ["r18", "18"], + r19: reg, reg_nonzero = ["r19", "19"], + r20: reg, reg_nonzero = ["r20", "20"], + r21: reg, reg_nonzero = ["r21", "21"], + r22: reg, reg_nonzero = ["r22", "22"], + r23: reg, reg_nonzero = ["r23", "23"], + r24: reg, reg_nonzero = ["r24", "24"], + r25: reg, reg_nonzero = ["r25", "25"], + r26: reg, reg_nonzero = ["r26", "26"], + r27: reg, reg_nonzero = ["r27", "27"], + r28: reg, reg_nonzero = ["r28", "28"], + f0: freg = ["f0", "fr0"], + f1: freg = ["f1", "fr1"], + f2: freg = ["f2", "fr2"], + f3: freg = ["f3", "fr3"], + f4: freg = ["f4", "fr4"], + f5: freg = ["f5", "fr5"], + f6: freg = ["f6", "fr6"], + f7: freg = ["f7", "fr7"], + f8: freg = ["f8", "fr8"], + f9: freg = ["f9", "fr9"], + f10: freg = ["f10", "fr10"], + f11: freg = ["f11", "fr11"], + f12: freg = ["f12", "fr12"], + f13: freg = ["f13", "fr13"], + f14: freg = ["f14", "fr14"], + f15: freg = ["f15", "fr15"], + f16: freg = ["f16", "fr16"], + f17: freg = ["f17", "fr17"], + f18: freg = ["f18", "fr18"], + f19: freg = ["f19", "fr19"], + f20: freg = ["f20", "fr20"], + f21: freg = ["f21", "fr21"], + f22: freg = ["f22", "fr22"], + f23: freg = ["f23", "fr23"], + f24: freg = ["f24", "fr24"], + f25: freg = ["f25", "fr25"], + f26: freg = ["f26", "fr26"], + f27: freg = ["f27", "fr27"], + f28: freg = ["f28", "fr28"], + f29: freg = ["f29", "fr29"], + f30: freg = ["f30", "fr30"], + f31: freg = ["f31", "fr31"], + #error = ["r1", "1", "sp"] => + "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"] => + "r30 is used internally by LLVM and cannot be used as an operand for inline asm", + #error = ["r31", "31", "fp"] => + "the frame pointer cannot be used as an operand for inline asm", + #error = ["lr"] => + "the link register cannot be used as an operand for inline asm", + #error = ["ctr"] => + "the counter register cannot be used as an operand for inline asm", + #error = ["vrsave"] => + "the vrsave register cannot be used as an operand for inline asm", + } +} + +impl PowerPCInlineAsmReg { + pub fn emit( + self, + out: &mut dyn fmt::Write, + _arch: InlineAsmArch, + _modifier: Option, + ) -> fmt::Result { + // 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!() + } + } + + pub fn overlapping_regs(self, mut _cb: impl FnMut(PowerPCInlineAsmReg)) {} +} diff --git a/src/doc/unstable-book/src/library-features/asm.md b/src/doc/unstable-book/src/library-features/asm.md index fa96e47ee03..107fc6d42cf 100644 --- a/src/doc/unstable-book/src/library-features/asm.md +++ b/src/doc/unstable-book/src/library-features/asm.md @@ -26,6 +26,7 @@ Inline assembly is currently supported on the following architectures: - AArch64 - RISC-V - NVPTX +- PowerPC - Hexagon - MIPS32r2 and MIPS64r2 - wasm32 @@ -459,7 +460,7 @@ options := "options(" option *["," option] [","] ")" asm := "asm!(" format_string *("," format_string) *("," [ident "="] operand) ["," options] [","] ")" ``` -The macro will initially be supported only on ARM, AArch64, Hexagon, x86, x86-64 and RISC-V targets. Support for more targets may be added in the future. The compiler will emit an error if `asm!` is used on an unsupported target. +The macro will initially be supported only on ARM, AArch64, Hexagon, PowerPC, x86, x86-64 and RISC-V targets. Support for more targets may be added in the future. The compiler will emit an error if `asm!` is used on an unsupported target. [format-syntax]: https://doc.rust-lang.org/std/fmt/#syntax @@ -565,6 +566,9 @@ Here is the list of currently supported register classes: | RISC-V | `reg` | `x1`, `x[5-7]`, `x[9-15]`, `x[16-31]` (non-RV32E) | `r` | | RISC-V | `freg` | `f[0-31]` | `f` | | Hexagon | `reg` | `r[0-28]` | `r` | +| PowerPC | `reg` | `r[0-31]` | `r` | +| PowerPC | `reg_nonzero` | | `r[1-31]` | `b` | +| PowerPC | `freg` | `f[0-31]` | `f` | | wasm32 | `local` | None\* | `r` | > **Note**: On x86 we treat `reg_byte` differently from `reg` because the compiler can allocate `al` and `ah` separately whereas `reg` reserves the whole register. @@ -607,6 +611,9 @@ Each register class has constraints on which value types they can be used with. | RISC-V | `freg` | `f` | `f32` | | RISC-V | `freg` | `d` | `f64` | | Hexagon | `reg` | None | `i8`, `i16`, `i32`, `f32` | +| PowerPC | `reg` | None | `i8`, `i16`, `i32` | +| PowerPC | `reg_nonzero` | None | `i8`, `i16`, `i32` | +| PowerPC | `freg` | None | `f32`, `f64` | | wasm32 | `local` | None | `i8` `i16` `i32` `i64` `f32` `f64` | > **Note**: For the purposes of the above table pointers, function pointers and `isize`/`usize` are treated as the equivalent integer type (`i16`/`i32`/`i64` depending on the target). @@ -744,6 +751,9 @@ The supported modifiers are a subset of LLVM's (and GCC's) [asm template argumen | RISC-V | `reg` | None | `x1` | None | | RISC-V | `freg` | None | `f0` | None | | Hexagon | `reg` | None | `r0` | None | +| PowerPC | `reg` | None | `0` | None | +| PowerPC | `reg_nonzero` | None | `3` | `b` | +| PowerPC | `freg` | None | `0` | None | > Notes: > - on ARM `e` / `f`: this prints the low or high doubleword register name of a NEON quad (128-bit) register. diff --git a/src/test/assembly/asm/powerpc-types.rs b/src/test/assembly/asm/powerpc-types.rs new file mode 100644 index 00000000000..26c891392f2 --- /dev/null +++ b/src/test/assembly/asm/powerpc-types.rs @@ -0,0 +1,165 @@ +// min-llvm-version: 10.0.1 +// assembly-output: emit-asm +// compile-flags: --target powerpc-unknown-linux-gnu +// needs-llvm-components: powerpc + +#![feature(no_core, lang_items, rustc_attrs, repr_simd)] +#![crate_type = "rlib"] +#![no_core] +#![allow(asm_sub_register, non_camel_case_types)] + +#[rustc_builtin_macro] +macro_rules! asm { + () => {}; +} +#[rustc_builtin_macro] +macro_rules! concat { + () => {}; +} +#[rustc_builtin_macro] +macro_rules! stringify { + () => {}; +} + +#[lang = "sized"] +trait Sized {} +#[lang = "copy"] +trait Copy {} + +type ptr = *const i32; + +impl Copy for i8 {} +impl Copy for u8 {} +impl Copy for i16 {} +impl Copy for i32 {} +impl Copy for i64 {} +impl Copy for f32 {} +impl Copy for f64 {} +impl Copy for ptr {} +extern "C" { + fn extern_func(); + static extern_static: u8; +} + +// Hack to avoid function merging +extern "Rust" { + fn dont_merge(s: &str); +} + +macro_rules! check { ($func:ident, $ty:ty, $class:ident, $mov:literal) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + dont_merge(stringify!($func)); + + let y; + asm!(concat!($mov," {}, {}"), out($class) y, in($class) x); + y + } +};} + +macro_rules! check_reg { ($func:ident, $ty:ty, $rego:tt, $regc:tt, $mov:literal) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + dont_merge(stringify!($func)); + + let y; + asm!(concat!($mov, " ", $rego, ", ", $rego), lateout($regc) y, in($regc) x); + y + } +};} + +// CHECK-LABEL: reg_i8: +// CHECK: #APP +// CHECK: mr {{[0-9]+}}, {{[0-9]+}} +// CHECK: #NO_APP +check!(reg_i8, i8, reg, "mr"); + +// CHECK-LABEL: reg_i16: +// CHECK: #APP +// CHECK: mr {{[0-9]+}}, {{[0-9]+}} +// CHECK: #NO_APP +check!(reg_i16, i16, reg, "mr"); + +// CHECK-LABEL: reg_i32: +// CHECK: #APP +// CHECK: mr {{[0-9]+}}, {{[0-9]+}} +// CHECK: #NO_APP +check!(reg_i32, i32, reg, "mr"); + +// CHECK-LABEL: reg_i8_nz: +// CHECK: #APP +// CHECK: mr {{[0-9]+}}, {{[0-9]+}} +// CHECK: #NO_APP +check!(reg_i8_nz, i8, reg_nonzero, "mr"); + +// CHECK-LABEL: reg_i16_nz: +// CHECK: #APP +// CHECK: mr {{[0-9]+}}, {{[0-9]+}} +// CHECK: #NO_APP +check!(reg_i16_nz, i16, reg_nonzero, "mr"); + +// CHECK-LABEL: reg_i32_nz: +// CHECK: #APP +// CHECK: mr {{[0-9]+}}, {{[0-9]+}} +// CHECK: #NO_APP +check!(reg_i32_nz, i32, reg_nonzero, "mr"); + +// CHECK-LABEL: reg_f32: +// CHECK: #APP +// CHECK: fmr {{[0-9]+}}, {{[0-9]+}} +// CHECK: #NO_APP +check!(reg_f32, f32, freg, "fmr"); + +// CHECK-LABEL: reg_f64: +// CHECK: #APP +// CHECK: fmr {{[0-9]+}}, {{[0-9]+}} +// CHECK: #NO_APP +check!(reg_f64, f64, freg, "fmr"); + +// CHECK-LABEL: reg_i8_r0: +// CHECK: #APP +// CHECK: mr 0, 0 +// CHECK: #NO_APP +check_reg!(reg_i8_r0, i8, "0", "0", "mr"); + +// CHECK-LABEL: reg_i16_r0: +// CHECK: #APP +// CHECK: mr 0, 0 +// CHECK: #NO_APP +check_reg!(reg_i16_r0, i16, "0", "0", "mr"); + +// CHECK-LABEL: reg_i32_r0: +// CHECK: #APP +// CHECK: mr 0, 0 +// CHECK: #NO_APP +check_reg!(reg_i32_r0, i32, "0", "0", "mr"); + +// CHECK-LABEL: reg_i8_r18: +// CHECK: #APP +// CHECK: mr 18, 18 +// CHECK: #NO_APP +check_reg!(reg_i8_r18, i8, "18", "18", "mr"); + +// CHECK-LABEL: reg_i16_r18: +// CHECK: #APP +// CHECK: mr 18, 18 +// CHECK: #NO_APP +check_reg!(reg_i16_r18, i16, "18", "18", "mr"); + +// CHECK-LABEL: reg_i32_r18: +// CHECK: #APP +// CHECK: mr 18, 18 +// CHECK: #NO_APP +check_reg!(reg_i32_r18, i32, "18", "18", "mr"); + +// CHECK-LABEL: reg_f32_f0: +// CHECK: #APP +// CHECK: fmr 0, 0 +// CHECK: #NO_APP +check_reg!(reg_f32_f0, f32, "0", "f0", "fmr"); + +// CHECK-LABEL: reg_f64_f0: +// CHECK: #APP +// CHECK: fmr 0, 0 +// CHECK: #NO_APP +check_reg!(reg_f64_f0, f64, "0", "f0", "fmr");