Auto merge of #101069 - zhaixiaojuan:loongarch64-inline-asm, r=Amanieu

Add loongarch64 asm! support
This commit is contained in:
bors 2023-04-25 09:18:58 +00:00
commit 999e6e5afb
6 changed files with 380 additions and 1 deletions

View File

@ -593,6 +593,8 @@ fn reg_to_gcc(reg: InlineAsmRegOrRegClass) -> ConstraintOrRegister {
InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::reg) => "r",
InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::wreg) => "w",
InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => "r",
InlineAsmRegClass::LoongArch(LoongArchInlineAsmRegClass::reg) => "r",
InlineAsmRegClass::LoongArch(LoongArchInlineAsmRegClass::freg) => "f",
InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg) => "r",
InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg_addr) => "a",
InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg_data) => "d",
@ -667,6 +669,8 @@ fn dummy_output_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, reg: InlineAsmRegCl
InlineAsmRegClass::Avr(_) => unimplemented!(),
InlineAsmRegClass::Bpf(_) => unimplemented!(),
InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => cx.type_i32(),
InlineAsmRegClass::LoongArch(LoongArchInlineAsmRegClass::reg) => cx.type_i32(),
InlineAsmRegClass::LoongArch(LoongArchInlineAsmRegClass::freg) => cx.type_f32(),
InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg) => cx.type_i32(),
InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg_addr) => cx.type_i32(),
InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg_data) => cx.type_i32(),
@ -804,6 +808,7 @@ fn modifier_to_gcc(arch: InlineAsmArch, reg: InlineAsmRegClass, modifier: Option
}
}
InlineAsmRegClass::Hexagon(_) => None,
InlineAsmRegClass::LoongArch(_) => None,
InlineAsmRegClass::Mips(_) => None,
InlineAsmRegClass::Nvptx(_) => None,
InlineAsmRegClass::PowerPC(_) => None,

View File

@ -236,6 +236,7 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
InlineAsmArch::Nvptx64 => {}
InlineAsmArch::PowerPC | InlineAsmArch::PowerPC64 => {}
InlineAsmArch::Hexagon => {}
InlineAsmArch::LoongArch64 => {}
InlineAsmArch::Mips | InlineAsmArch::Mips64 => {}
InlineAsmArch::S390x => {}
InlineAsmArch::SpirV => {}
@ -633,6 +634,8 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'_>>) ->
InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg)
| InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg) => "w",
InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => "r",
InlineAsmRegClass::LoongArch(LoongArchInlineAsmRegClass::reg) => "r",
InlineAsmRegClass::LoongArch(LoongArchInlineAsmRegClass::freg) => "f",
InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg) => "r",
InlineAsmRegClass::Mips(MipsInlineAsmRegClass::freg) => "f",
InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg16) => "h",
@ -719,6 +722,7 @@ fn modifier_to_llvm(
}
}
InlineAsmRegClass::Hexagon(_) => None,
InlineAsmRegClass::LoongArch(_) => None,
InlineAsmRegClass::Mips(_) => None,
InlineAsmRegClass::Nvptx(_) => None,
InlineAsmRegClass::PowerPC(_) => None,
@ -803,6 +807,8 @@ fn dummy_output_type<'ll>(cx: &CodegenCx<'ll, '_>, reg: InlineAsmRegClass) -> &'
cx.type_vector(cx.type_i64(), 2)
}
InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => cx.type_i32(),
InlineAsmRegClass::LoongArch(LoongArchInlineAsmRegClass::reg) => cx.type_i32(),
InlineAsmRegClass::LoongArch(LoongArchInlineAsmRegClass::freg) => cx.type_f32(),
InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg) => cx.type_i32(),
InlineAsmRegClass::Mips(MipsInlineAsmRegClass::freg) => cx.type_f32(),
InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg16) => cx.type_i16(),

View File

@ -0,0 +1,131 @@
use super::{InlineAsmArch, InlineAsmType};
use rustc_macros::HashStable_Generic;
use rustc_span::Symbol;
use std::fmt;
def_reg_class! {
LoongArch LoongArchInlineAsmRegClass {
reg,
freg,
}
}
impl LoongArchInlineAsmRegClass {
pub fn valid_modifiers(self, _arch: super::InlineAsmArch) -> &'static [char] {
&[]
}
pub fn suggest_class(self, _arch: InlineAsmArch, _ty: InlineAsmType) -> Option<Self> {
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<Symbol>)] {
match (self, arch) {
(Self::reg, InlineAsmArch::LoongArch64) => types! { _: I8, I16, I32, I64, F32, F64; },
(Self::reg, _) => types! { _: I8, I16, I32, F32; },
(Self::freg, _) => types! { _: F32, F64; },
}
}
}
// The reserved registers are taken from <https://github.com/llvm/llvm-project/blob/main/llvm/lib/Target/LoongArch/LoongArchRegisterInfo.cpp#79>
def_regs! {
LoongArch LoongArchInlineAsmReg LoongArchInlineAsmRegClass {
r1: reg = ["$r1","$ra"],
r4: reg = ["$r4","$a0"],
r5: reg = ["$r5","$a1"],
r6: reg = ["$r6","$a2"],
r7: reg = ["$r7","$a3"],
r8: reg = ["$r8","$a4"],
r9: reg = ["$r9","$a5"],
r10: reg = ["$r10","$a6"],
r11: reg = ["$r11","$a7"],
r12: reg = ["$r12","$t0"],
r13: reg = ["$r13","$t1"],
r14: reg = ["$r14","$t2"],
r15: reg = ["$r15","$t3"],
r16: reg = ["$r16","$t4"],
r17: reg = ["$r17","$t5"],
r18: reg = ["$r18","$t6"],
r19: reg = ["$r19","$t7"],
r20: reg = ["$r20","$t8"],
r23: reg = ["$r23","$s0"],
r24: reg = ["$r24","$s1"],
r25: reg = ["$r25","$s2"],
r26: reg = ["$r26","$s3"],
r27: reg = ["$r27","$s4"],
r28: reg = ["$r28","$s5"],
r29: reg = ["$r29","$s6"],
r30: reg = ["$r30","$s7"],
f0: freg = ["$f0","$fa0"],
f1: freg = ["$f1","$fa1"],
f2: freg = ["$f2","$fa2"],
f3: freg = ["$f3","$fa3"],
f4: freg = ["$f4","$fa4"],
f5: freg = ["$f5","$fa5"],
f6: freg = ["$f6","$fa6"],
f7: freg = ["$f7","$fa7"],
f8: freg = ["$f8","$ft0"],
f9: freg = ["$f9","$ft1"],
f10: freg = ["$f10","$ft2"],
f11: freg = ["$f11","$ft3"],
f12: freg = ["$f12","$ft4"],
f13: freg = ["$f13","$ft5"],
f14: freg = ["$f14","$ft6"],
f15: freg = ["$f15","$ft7"],
f16: freg = ["$f16","$ft8"],
f17: freg = ["$f17","$ft9"],
f18: freg = ["$f18","$ft10"],
f19: freg = ["$f19","$ft11"],
f20: freg = ["$f20","$ft12"],
f21: freg = ["$f21","$ft13"],
f22: freg = ["$f22","$ft14"],
f23: freg = ["$f23","$ft15"],
f24: freg = ["$f24","$fs0"],
f25: freg = ["$f25","$fs1"],
f26: freg = ["$f26","$fs2"],
f27: freg = ["$f27","$fs3"],
f28: freg = ["$f28","$fs4"],
f29: freg = ["$f29","$fs5"],
f30: freg = ["$f30","$fs6"],
f31: freg = ["$f31","$fs7"],
#error = ["$r0","$zero"] =>
"constant zero cannot be used as an operand for inline asm",
#error = ["$r2","$tp"] =>
"reserved for TLS",
#error = ["$r3","$sp"] =>
"the stack pointer cannot be used as an operand for inline asm",
#error = ["$r21"] =>
"reserved by the ABI",
#error = ["$r22","$fp"] =>
"the frame pointer cannot be used as an operand for inline asm",
#error = ["$r31","$s8"] =>
"$r31 is used internally by LLVM and cannot be used as an operand for inline asm",
}
}
impl LoongArchInlineAsmReg {
pub fn emit(
self,
out: &mut dyn fmt::Write,
_arch: InlineAsmArch,
_modifier: Option<char>,
) -> fmt::Result {
out.write_str(self.name())
}
}

View File

@ -168,6 +168,7 @@ mod arm;
mod avr;
mod bpf;
mod hexagon;
mod loongarch;
mod m68k;
mod mips;
mod msp430;
@ -184,6 +185,7 @@ pub use arm::{ArmInlineAsmReg, ArmInlineAsmRegClass};
pub use avr::{AvrInlineAsmReg, AvrInlineAsmRegClass};
pub use bpf::{BpfInlineAsmReg, BpfInlineAsmRegClass};
pub use hexagon::{HexagonInlineAsmReg, HexagonInlineAsmRegClass};
pub use loongarch::{LoongArchInlineAsmReg, LoongArchInlineAsmRegClass};
pub use m68k::{M68kInlineAsmReg, M68kInlineAsmRegClass};
pub use mips::{MipsInlineAsmReg, MipsInlineAsmRegClass};
pub use msp430::{Msp430InlineAsmReg, Msp430InlineAsmRegClass};
@ -205,6 +207,7 @@ pub enum InlineAsmArch {
RiscV64,
Nvptx64,
Hexagon,
LoongArch64,
Mips,
Mips64,
PowerPC,
@ -234,6 +237,7 @@ impl FromStr for InlineAsmArch {
"powerpc" => Ok(Self::PowerPC),
"powerpc64" => Ok(Self::PowerPC64),
"hexagon" => Ok(Self::Hexagon),
"loongarch64" => Ok(Self::LoongArch64),
"mips" => Ok(Self::Mips),
"mips64" => Ok(Self::Mips64),
"s390x" => Ok(Self::S390x),
@ -259,6 +263,7 @@ pub enum InlineAsmReg {
Nvptx(NvptxInlineAsmReg),
PowerPC(PowerPCInlineAsmReg),
Hexagon(HexagonInlineAsmReg),
LoongArch(LoongArchInlineAsmReg),
Mips(MipsInlineAsmReg),
S390x(S390xInlineAsmReg),
SpirV(SpirVInlineAsmReg),
@ -280,6 +285,7 @@ impl InlineAsmReg {
Self::RiscV(r) => r.name(),
Self::PowerPC(r) => r.name(),
Self::Hexagon(r) => r.name(),
Self::LoongArch(r) => r.name(),
Self::Mips(r) => r.name(),
Self::S390x(r) => r.name(),
Self::Bpf(r) => r.name(),
@ -298,6 +304,7 @@ impl InlineAsmReg {
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::LoongArch(r) => InlineAsmRegClass::LoongArch(r.reg_class()),
Self::Mips(r) => InlineAsmRegClass::Mips(r.reg_class()),
Self::S390x(r) => InlineAsmRegClass::S390x(r.reg_class()),
Self::Bpf(r) => InlineAsmRegClass::Bpf(r.reg_class()),
@ -324,6 +331,7 @@ impl InlineAsmReg {
Self::PowerPC(PowerPCInlineAsmReg::parse(name)?)
}
InlineAsmArch::Hexagon => Self::Hexagon(HexagonInlineAsmReg::parse(name)?),
InlineAsmArch::LoongArch64 => Self::LoongArch(LoongArchInlineAsmReg::parse(name)?),
InlineAsmArch::Mips | InlineAsmArch::Mips64 => {
Self::Mips(MipsInlineAsmReg::parse(name)?)
}
@ -354,6 +362,9 @@ impl InlineAsmReg {
Self::RiscV(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
Self::PowerPC(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
Self::Hexagon(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
Self::LoongArch(r) => {
r.validate(arch, reloc_model, target_features, target, is_clobber)
}
Self::Mips(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
Self::S390x(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
Self::Bpf(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
@ -379,6 +390,7 @@ impl InlineAsmReg {
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::LoongArch(r) => r.emit(out, arch, modifier),
Self::Mips(r) => r.emit(out, arch, modifier),
Self::S390x(r) => r.emit(out, arch, modifier),
Self::Bpf(r) => r.emit(out, arch, modifier),
@ -397,6 +409,7 @@ impl InlineAsmReg {
Self::RiscV(_) => 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::LoongArch(_) => cb(self),
Self::Mips(_) => cb(self),
Self::S390x(_) => cb(self),
Self::Bpf(r) => r.overlapping_regs(|r| cb(Self::Bpf(r))),
@ -418,6 +431,7 @@ pub enum InlineAsmRegClass {
Nvptx(NvptxInlineAsmRegClass),
PowerPC(PowerPCInlineAsmRegClass),
Hexagon(HexagonInlineAsmRegClass),
LoongArch(LoongArchInlineAsmRegClass),
Mips(MipsInlineAsmRegClass),
S390x(S390xInlineAsmRegClass),
SpirV(SpirVInlineAsmRegClass),
@ -440,6 +454,7 @@ impl InlineAsmRegClass {
Self::Nvptx(r) => r.name(),
Self::PowerPC(r) => r.name(),
Self::Hexagon(r) => r.name(),
Self::LoongArch(r) => r.name(),
Self::Mips(r) => r.name(),
Self::S390x(r) => r.name(),
Self::SpirV(r) => r.name(),
@ -464,6 +479,7 @@ impl InlineAsmRegClass {
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::LoongArch(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::LoongArch),
Self::Mips(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Mips),
Self::S390x(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::S390x),
Self::SpirV(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::SpirV),
@ -495,6 +511,7 @@ impl InlineAsmRegClass {
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::LoongArch(r) => r.suggest_modifier(arch, ty),
Self::Mips(r) => r.suggest_modifier(arch, ty),
Self::S390x(r) => r.suggest_modifier(arch, ty),
Self::SpirV(r) => r.suggest_modifier(arch, ty),
@ -522,6 +539,7 @@ impl InlineAsmRegClass {
Self::Nvptx(r) => r.default_modifier(arch),
Self::PowerPC(r) => r.default_modifier(arch),
Self::Hexagon(r) => r.default_modifier(arch),
Self::LoongArch(r) => r.default_modifier(arch),
Self::Mips(r) => r.default_modifier(arch),
Self::S390x(r) => r.default_modifier(arch),
Self::SpirV(r) => r.default_modifier(arch),
@ -548,6 +566,7 @@ impl InlineAsmRegClass {
Self::Nvptx(r) => r.supported_types(arch),
Self::PowerPC(r) => r.supported_types(arch),
Self::Hexagon(r) => r.supported_types(arch),
Self::LoongArch(r) => r.supported_types(arch),
Self::Mips(r) => r.supported_types(arch),
Self::S390x(r) => r.supported_types(arch),
Self::SpirV(r) => r.supported_types(arch),
@ -575,6 +594,7 @@ impl InlineAsmRegClass {
Self::PowerPC(PowerPCInlineAsmRegClass::parse(name)?)
}
InlineAsmArch::Hexagon => Self::Hexagon(HexagonInlineAsmRegClass::parse(name)?),
InlineAsmArch::LoongArch64 => Self::LoongArch(LoongArchInlineAsmRegClass::parse(name)?),
InlineAsmArch::Mips | InlineAsmArch::Mips64 => {
Self::Mips(MipsInlineAsmRegClass::parse(name)?)
}
@ -601,6 +621,7 @@ impl InlineAsmRegClass {
Self::Nvptx(r) => r.valid_modifiers(arch),
Self::PowerPC(r) => r.valid_modifiers(arch),
Self::Hexagon(r) => r.valid_modifiers(arch),
Self::LoongArch(r) => r.valid_modifiers(arch),
Self::Mips(r) => r.valid_modifiers(arch),
Self::S390x(r) => r.valid_modifiers(arch),
Self::SpirV(r) => r.valid_modifiers(arch),
@ -760,6 +781,11 @@ pub fn allocatable_registers(
hexagon::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
map
}
InlineAsmArch::LoongArch64 => {
let mut map = loongarch::regclass_map();
loongarch::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
map
}
InlineAsmArch::Mips | InlineAsmArch::Mips64 => {
let mut map = mips::regclass_map();
mips::fill_reg_map(arch, reloc_model, target_features, target, &mut map);

View File

@ -17,6 +17,7 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
- AVR
- MSP430
- M68k
- LoongArch
## Register classes
@ -45,6 +46,8 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
| M68k | `reg` | `d[0-7]`, `a[0-7]` | `r` |
| M68k | `reg_data` | `d[0-7]` | `d` |
| M68k | `reg_addr` | `a[0-3]` | `a` |
| LoongArch | `reg` | `$r1`, `$r[4-20]`, `$r[23,30]` | `r` |
| LoongArch | `freg` | `$f[0-31]` | `f` |
> **Notes**:
> - NVPTX doesn't have a fixed register set, so named registers are not supported.
@ -76,6 +79,8 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
| MSP430 | `reg` | None | `i8`, `i16` |
| M68k | `reg`, `reg_addr` | None | `i16`, `i32` |
| M68k | `reg_data` | None | `i8`, `i16`, `i32` |
| LoongArch64 | `reg` | None | `i8`, `i16`, `i32`, `i64`, `f32`, `f64` |
| LoongArch64 | `freg` | None | `f32`, `f64` |
## Register aliases
@ -97,6 +102,10 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
| M68k | `a5` | `bp` |
| M68k | `a6` | `fp` |
| M68k | `a7` | `sp`, `usp`, `ssp`, `isp` |
| LoongArch | `$r0` | `zero` |
| LoongArch | `$r2` | `tp` |
| LoongArch | `$r3` | `sp` |
| LoongArch | `$r22` | `fp` |
> **Notes**:
> - TI does not mandate a frame pointer for MSP430, but toolchains are allowed
@ -107,7 +116,7 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
| Architecture | Unsupported register | Reason |
| ------------ | --------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| All | `sp` | The stack pointer must be restored to its original value at the end of an asm code block. |
| All | `fr` (Hexagon), `$fp` (MIPS), `Y` (AVR), `r4` (MSP430), `a6` (M68k) | The frame pointer cannot be used as an input or output. |
| All | `fr` (Hexagon), `$fp` (MIPS), `Y` (AVR), `r4` (MSP430), `a6` (M68k), `$fp` (LoongArch) | The frame pointer cannot be used as an input or output. |
| All | `r19` (Hexagon) | This is used internally by LLVM as a "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. |
@ -118,6 +127,10 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
| 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. |
|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. |
| M68k | `a4`, `a5` | Used internally by LLVM for the base pointer and global base pointer. |
| LoongArch | `$r0` or `$zero` | This is a constant zero register which can't be modified. |
| LoongArch | `$r2` or `$tp` | This is reserved for TLS. |
| LoongArch | `$r21` | This is reserved by the ABI. |
| LoongArch | `$r31` or `$s8` | This is used internally by LLVM. |
## Template modifiers
@ -132,6 +145,8 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
| PowerPC | `reg` | None | `0` | None |
| PowerPC | `reg_nonzero` | None | `3` | `b` |
| PowerPC | `freg` | None | `0` | None |
| LoongArch | `reg` | None | `$r2` | None |
| LoongArch | `freg` | None | `$f0` | None |
# Flags covered by `preserves_flags`

View File

@ -0,0 +1,196 @@
// min-llvm-version: 16.0
// assembly-output: emit-asm
// compile-flags: --target loongarch64-unknown-linux-gnu
// needs-llvm-components: loongarch
#![feature(no_core, lang_items, rustc_attrs, asm_experimental_arch)]
#![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 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);
}
// CHECK-LABEL: sym_fn:
// CHECK: #APP
// CHECK: pcalau12i $t0, %got_pc_hi20(extern_func)
// CHECK: ld.d $t0, $t0, %got_pc_lo12(extern_func)
// CHECK: #NO_APP
#[no_mangle]
pub unsafe fn sym_fn() {
asm!("la.got $r12, {}", sym extern_func);
}
// CHECK-LABEL: sym_static:
// CHECK: #APP
// CHECK: pcalau12i $t0, %got_pc_hi20(extern_static)
// CHECK: ld.d $t0, $t0, %got_pc_lo12(extern_static)
// CHECK: #NO_APP
#[no_mangle]
pub unsafe fn sym_static() {
asm!("la.got $r12, {}", sym extern_static);
}
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, $reg:tt, $mov:literal) => {
#[no_mangle]
pub unsafe fn $func(x: $ty) -> $ty {
dont_merge(stringify!($func));
let y;
asm!(concat!($mov, " ", $reg, ", ", $reg), lateout($reg) y, in($reg) x);
y
}
};}
// CHECK-LABEL: reg_i8:
// CHECK: #APP
// CHECK: move ${{[a-z0-9]+}}, ${{[a-z0-9]+}}
// CHECK: #NO_APP
check!(reg_i8, i8, reg, "move");
// CHECK-LABEL: reg_i16:
// CHECK: #APP
// CHECK: move ${{[a-z0-9]+}}, ${{[a-z0-9]+}}
// CHECK: #NO_APP
check!(reg_i16, i16, reg, "move");
// CHECK-LABEL: reg_i32:
// CHECK: #APP
// CHECK: move ${{[a-z0-9]+}}, ${{[a-z0-9]+}}
// CHECK: #NO_APP
check!(reg_i32, i32, reg, "move");
// CHECK-LABEL: reg_f32:
// CHECK: #APP
// CHECK: move ${{[a-z0-9]+}}, ${{[a-z0-9]+}}
// CHECK: #NO_APP
check!(reg_f32, f32, reg, "move");
// CHECK-LABEL: reg_i64:
// CHECK: #APP
// CHECK: move ${{[a-z0-9]+}}, ${{[a-z0-9]+}}
// CHECK: #NO_APP
check!(reg_i64, i64, reg, "move");
// CHECK-LABEL: reg_f64:
// CHECK: #APP
// CHECK: move ${{[a-z0-9]+}}, ${{[a-z0-9]+}}
// CHECK: #NO_APP
check!(reg_f64, f64, reg, "move");
// CHECK-LABEL: reg_ptr:
// CHECK: #APP
// CHECK: move ${{[a-z0-9]+}}, ${{[a-z0-9]+}}
// CHECK: #NO_APP
check!(reg_ptr, ptr, reg, "move");
// CHECK-LABEL: freg_f32:
// CHECK: #APP
// CHECK: fmov.s $f{{[a-z0-9]+}}, $f{{[a-z0-9]+}}
// CHECK: #NO_APP
check!(freg_f32, f32, freg, "fmov.s");
// CHECK-LABEL: freg_f64:
// CHECK: #APP
// CHECK: fmov.d $f{{[a-z0-9]+}}, $f{{[a-z0-9]+}}
// CHECK: #NO_APP
check!(freg_f64, f64, freg, "fmov.d");
// CHECK-LABEL: r4_i8:
// CHECK: #APP
// CHECK: move $a0, $a0
// CHECK: #NO_APP
check_reg!(r4_i8, i8, "$r4", "move");
// CHECK-LABEL: r4_i16:
// CHECK: #APP
// CHECK: move $a0, $a0
// CHECK: #NO_APP
check_reg!(r4_i16, i16, "$r4", "move");
// CHECK-LABEL: r4_i32:
// CHECK: #APP
// CHECK: move $a0, $a0
// CHECK: #NO_APP
check_reg!(r4_i32, i32, "$r4", "move");
// CHECK-LABEL: r4_f32:
// CHECK: #APP
// CHECK: move $a0, $a0
// CHECK: #NO_APP
check_reg!(r4_f32, f32, "$r4", "move");
// CHECK-LABEL: r4_i64:
// CHECK: #APP
// CHECK: move $a0, $a0
// CHECK: #NO_APP
check_reg!(r4_i64, i64, "$r4", "move");
// CHECK-LABEL: r4_f64:
// CHECK: #APP
// CHECK: move $a0, $a0
// CHECK: #NO_APP
check_reg!(r4_f64, f64, "$r4", "move");
// CHECK-LABEL: r4_ptr:
// CHECK: #APP
// CHECK: move $a0, $a0
// CHECK: #NO_APP
check_reg!(r4_ptr, ptr, "$r4", "move");
// CHECK-LABEL: f0_f32:
// CHECK: #APP
// CHECK: fmov.s $f{{[a-z0-9]+}}, $f{{[a-z0-9]+}}
// CHECK: #NO_APP
check_reg!(f0_f32, f32, "$f0", "fmov.s");
// CHECK-LABEL: f0_f64:
// CHECK: #APP
// CHECK: fmov.d $f{{[a-z0-9]+}}, $f{{[a-z0-9]+}}
// CHECK: #NO_APP
check_reg!(f0_f64, f64, "$f0", "fmov.d");