diff options
Diffstat (limited to 'compiler/rustc_target/src/asm/mod.rs')
| -rw-r--r-- | compiler/rustc_target/src/asm/mod.rs | 714 |
1 files changed, 714 insertions, 0 deletions
diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs new file mode 100644 index 00000000000..b52fa5bbcb2 --- /dev/null +++ b/compiler/rustc_target/src/asm/mod.rs @@ -0,0 +1,714 @@ +use crate::abi::Size; +use crate::spec::Target; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_macros::HashStable_Generic; +use rustc_span::Symbol; +use std::fmt; +use std::str::FromStr; + +macro_rules! def_reg_class { + ($arch:ident $arch_regclass:ident { + $( + $class:ident, + )* + }) => { + #[derive(Copy, Clone, Encodable, Decodable, Debug, Eq, PartialEq, PartialOrd, Hash, HashStable_Generic)] + #[allow(non_camel_case_types)] + pub enum $arch_regclass { + $($class,)* + } + + impl $arch_regclass { + pub fn name(self) -> rustc_span::Symbol { + match self { + $(Self::$class => rustc_span::symbol::sym::$class,)* + } + } + + pub fn parse(_arch: super::InlineAsmArch, name: rustc_span::Symbol) -> Result<Self, &'static str> { + match name { + $( + rustc_span::sym::$class => Ok(Self::$class), + )* + _ => Err("unknown register class"), + } + } + } + + pub(super) fn regclass_map() -> rustc_data_structures::fx::FxHashMap< + super::InlineAsmRegClass, + rustc_data_structures::fx::FxHashSet<super::InlineAsmReg>, + > { + use rustc_data_structures::fx::{FxHashMap, FxHashSet}; + use super::InlineAsmRegClass; + let mut map = FxHashMap::default(); + $( + map.insert(InlineAsmRegClass::$arch($arch_regclass::$class), FxHashSet::default()); + )* + map + } + } +} + +macro_rules! def_regs { + ($arch:ident $arch_reg:ident $arch_regclass:ident { + $( + $reg:ident: $class:ident $(, $extra_class:ident)* = [$reg_name:literal $(, $alias:literal)*] $(% $filter:ident)?, + )* + $( + #error = [$($bad_reg:literal),+] => $error:literal, + )* + }) => { + #[allow(unreachable_code)] + #[derive(Copy, Clone, Encodable, Decodable, Debug, Eq, PartialEq, PartialOrd, Hash, HashStable_Generic)] + #[allow(non_camel_case_types)] + pub enum $arch_reg { + $($reg,)* + } + + impl $arch_reg { + pub fn name(self) -> &'static str { + match self { + $(Self::$reg => $reg_name,)* + } + } + + pub fn reg_class(self) -> $arch_regclass { + match self { + $(Self::$reg => $arch_regclass::$class,)* + } + } + + pub fn parse( + _arch: super::InlineAsmArch, + mut _has_feature: impl FnMut(&str) -> bool, + _target: &crate::spec::Target, + name: &str, + ) -> Result<Self, &'static str> { + match name { + $( + $($alias)|* | $reg_name => { + $($filter(_arch, &mut _has_feature, _target)?;)? + Ok(Self::$reg) + } + )* + $( + $($bad_reg)|* => Err($error), + )* + _ => Err("unknown register"), + } + } + } + + pub(super) fn fill_reg_map( + _arch: super::InlineAsmArch, + mut _has_feature: impl FnMut(&str) -> bool, + _target: &crate::spec::Target, + _map: &mut rustc_data_structures::fx::FxHashMap< + super::InlineAsmRegClass, + rustc_data_structures::fx::FxHashSet<super::InlineAsmReg>, + >, + ) { + #[allow(unused_imports)] + use super::{InlineAsmReg, InlineAsmRegClass}; + $( + if $($filter(_arch, &mut _has_feature, _target).is_ok() &&)? true { + if let Some(set) = _map.get_mut(&InlineAsmRegClass::$arch($arch_regclass::$class)) { + set.insert(InlineAsmReg::$arch($arch_reg::$reg)); + } + $( + if let Some(set) = _map.get_mut(&InlineAsmRegClass::$arch($arch_regclass::$extra_class)) { + set.insert(InlineAsmReg::$arch($arch_reg::$reg)); + } + )* + } + )* + } + } +} + +macro_rules! types { + ( + $(_ : $($ty:expr),+;)? + $($feature:literal: $($ty2:expr),+;)* + ) => { + { + use super::InlineAsmType::*; + &[ + $($( + ($ty, None), + )*)? + $($( + ($ty2, Some($feature)), + )*)* + ] + } + }; +} + +mod aarch64; +mod arm; +mod bpf; +mod hexagon; +mod mips; +mod nvptx; +mod powerpc; +mod riscv; +mod spirv; +mod wasm; +mod x86; + +pub use aarch64::{AArch64InlineAsmReg, AArch64InlineAsmRegClass}; +pub use arm::{ArmInlineAsmReg, ArmInlineAsmRegClass}; +pub use bpf::{BpfInlineAsmReg, BpfInlineAsmRegClass}; +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}; +pub use x86::{X86InlineAsmReg, X86InlineAsmRegClass}; + +#[derive(Copy, Clone, Encodable, Decodable, Debug, Eq, PartialEq, Hash)] +pub enum InlineAsmArch { + X86, + X86_64, + Arm, + AArch64, + RiscV32, + RiscV64, + Nvptx64, + Hexagon, + Mips, + Mips64, + PowerPC, + PowerPC64, + SpirV, + Wasm32, + Bpf, +} + +impl FromStr for InlineAsmArch { + type Err = (); + + fn from_str(s: &str) -> Result<InlineAsmArch, ()> { + match s { + "x86" => Ok(Self::X86), + "x86_64" => Ok(Self::X86_64), + "arm" => Ok(Self::Arm), + "aarch64" => Ok(Self::AArch64), + "riscv32" => Ok(Self::RiscV32), + "riscv64" => Ok(Self::RiscV64), + "nvptx64" => Ok(Self::Nvptx64), + "powerpc" => Ok(Self::PowerPC), + "powerpc64" => Ok(Self::PowerPC64), + "hexagon" => Ok(Self::Hexagon), + "mips" => Ok(Self::Mips), + "mips64" => Ok(Self::Mips64), + "spirv" => Ok(Self::SpirV), + "wasm32" => Ok(Self::Wasm32), + "bpf" => Ok(Self::Bpf), + _ => Err(()), + } + } +} + +#[derive( + Copy, + Clone, + Encodable, + Decodable, + Debug, + Eq, + PartialEq, + PartialOrd, + Hash, + HashStable_Generic +)] +pub enum InlineAsmReg { + X86(X86InlineAsmReg), + Arm(ArmInlineAsmReg), + AArch64(AArch64InlineAsmReg), + RiscV(RiscVInlineAsmReg), + Nvptx(NvptxInlineAsmReg), + PowerPC(PowerPCInlineAsmReg), + Hexagon(HexagonInlineAsmReg), + Mips(MipsInlineAsmReg), + SpirV(SpirVInlineAsmReg), + Wasm(WasmInlineAsmReg), + Bpf(BpfInlineAsmReg), + // Placeholder for invalid register constraints for the current target + Err, +} + +impl InlineAsmReg { + pub fn name(self) -> &'static str { + match self { + Self::X86(r) => r.name(), + 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::Bpf(r) => r.name(), + Self::Err => "<reg>", + } + } + + pub fn reg_class(self) -> InlineAsmRegClass { + match self { + Self::X86(r) => InlineAsmRegClass::X86(r.reg_class()), + 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::Bpf(r) => InlineAsmRegClass::Bpf(r.reg_class()), + Self::Err => InlineAsmRegClass::Err, + } + } + + pub fn parse( + arch: InlineAsmArch, + has_feature: impl FnMut(&str) -> bool, + target: &Target, + name: Symbol, + ) -> Result<Self, &'static str> { + // FIXME: use direct symbol comparison for register names + // Use `Symbol::as_str` instead of `Symbol::with` here because `has_feature` may access `Symbol`. + let name = name.as_str(); + Ok(match arch { + InlineAsmArch::X86 | InlineAsmArch::X86_64 => { + Self::X86(X86InlineAsmReg::parse(arch, has_feature, target, &name)?) + } + InlineAsmArch::Arm => { + Self::Arm(ArmInlineAsmReg::parse(arch, has_feature, target, &name)?) + } + InlineAsmArch::AArch64 => { + Self::AArch64(AArch64InlineAsmReg::parse(arch, has_feature, target, &name)?) + } + InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => { + Self::RiscV(RiscVInlineAsmReg::parse(arch, has_feature, target, &name)?) + } + InlineAsmArch::Nvptx64 => { + Self::Nvptx(NvptxInlineAsmReg::parse(arch, has_feature, target, &name)?) + } + InlineAsmArch::PowerPC | InlineAsmArch::PowerPC64 => { + Self::PowerPC(PowerPCInlineAsmReg::parse(arch, has_feature, target, &name)?) + } + InlineAsmArch::Hexagon => { + Self::Hexagon(HexagonInlineAsmReg::parse(arch, has_feature, target, &name)?) + } + InlineAsmArch::Mips | InlineAsmArch::Mips64 => { + Self::Mips(MipsInlineAsmReg::parse(arch, has_feature, target, &name)?) + } + InlineAsmArch::SpirV => { + Self::SpirV(SpirVInlineAsmReg::parse(arch, has_feature, target, &name)?) + } + InlineAsmArch::Wasm32 => { + Self::Wasm(WasmInlineAsmReg::parse(arch, has_feature, target, &name)?) + } + InlineAsmArch::Bpf => { + Self::Bpf(BpfInlineAsmReg::parse(arch, has_feature, target, &name)?) + } + }) + } + + // NOTE: This function isn't used at the moment, but is needed to support + // falling back to an external assembler. + pub fn emit( + self, + out: &mut dyn fmt::Write, + arch: InlineAsmArch, + modifier: Option<char>, + ) -> fmt::Result { + match self { + Self::X86(r) => r.emit(out, arch, modifier), + 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::Bpf(r) => r.emit(out, arch, modifier), + Self::Err => unreachable!("Use of InlineAsmReg::Err"), + } + } + + pub fn overlapping_regs(self, mut cb: impl FnMut(InlineAsmReg)) { + match self { + Self::X86(r) => r.overlapping_regs(|r| cb(Self::X86(r))), + 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::Bpf(r) => r.overlapping_regs(|r| cb(Self::Bpf(r))), + Self::Err => unreachable!("Use of InlineAsmReg::Err"), + } + } +} + +#[derive( + Copy, + Clone, + Encodable, + Decodable, + Debug, + Eq, + PartialEq, + PartialOrd, + Hash, + HashStable_Generic +)] +pub enum InlineAsmRegClass { + X86(X86InlineAsmRegClass), + Arm(ArmInlineAsmRegClass), + AArch64(AArch64InlineAsmRegClass), + RiscV(RiscVInlineAsmRegClass), + Nvptx(NvptxInlineAsmRegClass), + PowerPC(PowerPCInlineAsmRegClass), + Hexagon(HexagonInlineAsmRegClass), + Mips(MipsInlineAsmRegClass), + SpirV(SpirVInlineAsmRegClass), + Wasm(WasmInlineAsmRegClass), + Bpf(BpfInlineAsmRegClass), + // Placeholder for invalid register constraints for the current target + Err, +} + +impl InlineAsmRegClass { + pub fn name(self) -> Symbol { + match self { + Self::X86(r) => r.name(), + Self::Arm(r) => r.name(), + 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(), + Self::Wasm(r) => r.name(), + Self::Bpf(r) => r.name(), + Self::Err => rustc_span::symbol::sym::reg, + } + } + + /// Returns a suggested register class to use for this type. This is called + /// after type checking via `supported_types` fails to give a better error + /// message to the user. + pub fn suggest_class(self, arch: InlineAsmArch, ty: InlineAsmType) -> Option<Self> { + match self { + Self::X86(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::X86), + Self::Arm(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Arm), + 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), + Self::Wasm(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Wasm), + Self::Bpf(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Bpf), + Self::Err => unreachable!("Use of InlineAsmRegClass::Err"), + } + } + + /// Returns a suggested template modifier to use for this type and an + /// example of a register named formatted with it. + /// + /// Such suggestions are useful if a type smaller than the full register + /// size is used and a modifier can be used to point to the subregister of + /// the correct size. + pub fn suggest_modifier( + self, + arch: InlineAsmArch, + ty: InlineAsmType, + ) -> Option<(char, &'static str)> { + match self { + Self::X86(r) => r.suggest_modifier(arch, ty), + Self::Arm(r) => r.suggest_modifier(arch, ty), + 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), + Self::Wasm(r) => r.suggest_modifier(arch, ty), + Self::Bpf(r) => r.suggest_modifier(arch, ty), + Self::Err => unreachable!("Use of InlineAsmRegClass::Err"), + } + } + + /// Returns the default modifier for this register and an example of a + /// register named formatted with it. + /// + /// This is only needed when the register class can suggest a modifier, so + /// that the user can be shown how to get the default behavior without a + /// warning. + pub fn default_modifier(self, arch: InlineAsmArch) -> Option<(char, &'static str)> { + match self { + Self::X86(r) => r.default_modifier(arch), + Self::Arm(r) => r.default_modifier(arch), + 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), + Self::Wasm(r) => r.default_modifier(arch), + Self::Bpf(r) => r.default_modifier(arch), + Self::Err => unreachable!("Use of InlineAsmRegClass::Err"), + } + } + + /// Returns a list of supported types for this register class, each with a + /// options target feature required to use this type. + pub fn supported_types( + self, + arch: InlineAsmArch, + ) -> &'static [(InlineAsmType, Option<&'static str>)] { + match self { + Self::X86(r) => r.supported_types(arch), + Self::Arm(r) => r.supported_types(arch), + 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), + Self::Wasm(r) => r.supported_types(arch), + Self::Bpf(r) => r.supported_types(arch), + Self::Err => unreachable!("Use of InlineAsmRegClass::Err"), + } + } + + pub fn parse(arch: InlineAsmArch, name: Symbol) -> Result<Self, &'static str> { + Ok(match arch { + InlineAsmArch::X86 | InlineAsmArch::X86_64 => { + Self::X86(X86InlineAsmRegClass::parse(arch, name)?) + } + InlineAsmArch::Arm => Self::Arm(ArmInlineAsmRegClass::parse(arch, name)?), + InlineAsmArch::AArch64 => Self::AArch64(AArch64InlineAsmRegClass::parse(arch, name)?), + InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => { + Self::RiscV(RiscVInlineAsmRegClass::parse(arch, name)?) + } + InlineAsmArch::Nvptx64 => Self::Nvptx(NvptxInlineAsmRegClass::parse(arch, name)?), + InlineAsmArch::PowerPC | InlineAsmArch::PowerPC64 => { + Self::PowerPC(PowerPCInlineAsmRegClass::parse(arch, name)?) + } + InlineAsmArch::Hexagon => Self::Hexagon(HexagonInlineAsmRegClass::parse(arch, name)?), + InlineAsmArch::Mips | InlineAsmArch::Mips64 => { + Self::Mips(MipsInlineAsmRegClass::parse(arch, name)?) + } + InlineAsmArch::SpirV => Self::SpirV(SpirVInlineAsmRegClass::parse(arch, name)?), + InlineAsmArch::Wasm32 => Self::Wasm(WasmInlineAsmRegClass::parse(arch, name)?), + InlineAsmArch::Bpf => Self::Bpf(BpfInlineAsmRegClass::parse(arch, name)?), + }) + } + + /// Returns the list of template modifiers that can be used with this + /// register class. + pub fn valid_modifiers(self, arch: InlineAsmArch) -> &'static [char] { + match self { + Self::X86(r) => r.valid_modifiers(arch), + Self::Arm(r) => r.valid_modifiers(arch), + 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), + Self::Wasm(r) => r.valid_modifiers(arch), + Self::Bpf(r) => r.valid_modifiers(arch), + Self::Err => unreachable!("Use of InlineAsmRegClass::Err"), + } + } + + /// Returns whether registers in this class can only be used as clobbers + /// and not as inputs/outputs. + pub fn is_clobber_only(self, arch: InlineAsmArch) -> bool { + self.supported_types(arch).is_empty() + } +} + +#[derive( + Copy, + Clone, + Encodable, + Decodable, + Debug, + Eq, + PartialEq, + PartialOrd, + Hash, + HashStable_Generic +)] +pub enum InlineAsmRegOrRegClass { + Reg(InlineAsmReg), + RegClass(InlineAsmRegClass), +} + +impl InlineAsmRegOrRegClass { + pub fn reg_class(self) -> InlineAsmRegClass { + match self { + Self::Reg(r) => r.reg_class(), + Self::RegClass(r) => r, + } + } +} + +impl fmt::Display for InlineAsmRegOrRegClass { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Reg(r) => write!(f, "\"{}\"", r.name()), + Self::RegClass(r) => write!(f, "{}", r.name()), + } + } +} + +/// Set of types which can be used with a particular register class. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum InlineAsmType { + I8, + I16, + I32, + I64, + I128, + F32, + F64, + VecI8(u64), + VecI16(u64), + VecI32(u64), + VecI64(u64), + VecI128(u64), + VecF32(u64), + VecF64(u64), +} + +impl InlineAsmType { + pub fn is_integer(self) -> bool { + matches!(self, Self::I8 | Self::I16 | Self::I32 | Self::I64 | Self::I128) + } + + pub fn size(self) -> Size { + Size::from_bytes(match self { + Self::I8 => 1, + Self::I16 => 2, + Self::I32 => 4, + Self::I64 => 8, + Self::I128 => 16, + Self::F32 => 4, + Self::F64 => 8, + Self::VecI8(n) => n * 1, + Self::VecI16(n) => n * 2, + Self::VecI32(n) => n * 4, + Self::VecI64(n) => n * 8, + Self::VecI128(n) => n * 16, + Self::VecF32(n) => n * 4, + Self::VecF64(n) => n * 8, + }) + } +} + +impl fmt::Display for InlineAsmType { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + Self::I8 => f.write_str("i8"), + Self::I16 => f.write_str("i16"), + Self::I32 => f.write_str("i32"), + Self::I64 => f.write_str("i64"), + Self::I128 => f.write_str("i128"), + Self::F32 => f.write_str("f32"), + Self::F64 => f.write_str("f64"), + Self::VecI8(n) => write!(f, "i8x{}", n), + Self::VecI16(n) => write!(f, "i16x{}", n), + Self::VecI32(n) => write!(f, "i32x{}", n), + Self::VecI64(n) => write!(f, "i64x{}", n), + Self::VecI128(n) => write!(f, "i128x{}", n), + Self::VecF32(n) => write!(f, "f32x{}", n), + Self::VecF64(n) => write!(f, "f64x{}", n), + } + } +} + +/// Returns the full set of allocatable registers for a given architecture. +/// +/// The registers are structured as a map containing the set of allocatable +/// registers in each register class. A particular register may be allocatable +/// from multiple register classes, in which case it will appear multiple times +/// in the map. +// NOTE: This function isn't used at the moment, but is needed to support +// falling back to an external assembler. +pub fn allocatable_registers( + arch: InlineAsmArch, + has_feature: impl FnMut(&str) -> bool, + target: &crate::spec::Target, +) -> FxHashMap<InlineAsmRegClass, FxHashSet<InlineAsmReg>> { + match arch { + InlineAsmArch::X86 | InlineAsmArch::X86_64 => { + let mut map = x86::regclass_map(); + x86::fill_reg_map(arch, has_feature, target, &mut map); + map + } + InlineAsmArch::Arm => { + let mut map = arm::regclass_map(); + arm::fill_reg_map(arch, has_feature, target, &mut map); + map + } + InlineAsmArch::AArch64 => { + let mut map = aarch64::regclass_map(); + aarch64::fill_reg_map(arch, has_feature, target, &mut map); + map + } + InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => { + let mut map = riscv::regclass_map(); + riscv::fill_reg_map(arch, has_feature, target, &mut map); + map + } + InlineAsmArch::Nvptx64 => { + let mut map = nvptx::regclass_map(); + nvptx::fill_reg_map(arch, has_feature, target, &mut map); + map + } + InlineAsmArch::PowerPC | InlineAsmArch::PowerPC64 => { + 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); + map + } + InlineAsmArch::Mips | InlineAsmArch::Mips64 => { + let mut map = mips::regclass_map(); + mips::fill_reg_map(arch, has_feature, target, &mut map); + map + } + InlineAsmArch::SpirV => { + let mut map = spirv::regclass_map(); + spirv::fill_reg_map(arch, has_feature, target, &mut map); + map + } + InlineAsmArch::Wasm32 => { + let mut map = wasm::regclass_map(); + wasm::fill_reg_map(arch, has_feature, target, &mut map); + map + } + InlineAsmArch::Bpf => { + let mut map = bpf::regclass_map(); + bpf::fill_reg_map(arch, has_feature, target, &mut map); + map + } + } +} |
