2 use crate::spec::Target;
3 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
4 use rustc_macros::HashStable_Generic;
5 use rustc_span::Symbol;
9 macro_rules! def_reg_class {
10 ($arch:ident $arch_regclass:ident {
15 #[derive(Copy, Clone, Encodable, Decodable, Debug, Eq, PartialEq, PartialOrd, Hash, HashStable_Generic)]
16 #[allow(non_camel_case_types)]
17 pub enum $arch_regclass {
22 pub fn name(self) -> rustc_span::Symbol {
24 $(Self::$class => rustc_span::symbol::sym::$class,)*
28 pub fn parse(_arch: super::InlineAsmArch, name: rustc_span::Symbol) -> Result<Self, &'static str> {
31 rustc_span::sym::$class => Ok(Self::$class),
33 _ => Err("unknown register class"),
38 pub(super) fn regclass_map() -> rustc_data_structures::fx::FxHashMap<
39 super::InlineAsmRegClass,
40 rustc_data_structures::fx::FxHashSet<super::InlineAsmReg>,
42 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
43 use super::InlineAsmRegClass;
44 let mut map = FxHashMap::default();
46 map.insert(InlineAsmRegClass::$arch($arch_regclass::$class), FxHashSet::default());
53 macro_rules! def_regs {
54 ($arch:ident $arch_reg:ident $arch_regclass:ident {
56 $reg:ident: $class:ident $(, $extra_class:ident)* = [$reg_name:literal $(, $alias:literal)*] $(% $filter:ident)?,
59 #error = [$($bad_reg:literal),+] => $error:literal,
62 #[allow(unreachable_code)]
63 #[derive(Copy, Clone, Encodable, Decodable, Debug, Eq, PartialEq, PartialOrd, Hash, HashStable_Generic)]
64 #[allow(non_camel_case_types)]
70 pub fn name(self) -> &'static str {
72 $(Self::$reg => $reg_name,)*
76 pub fn reg_class(self) -> $arch_regclass {
78 $(Self::$reg => $arch_regclass::$class,)*
83 _arch: super::InlineAsmArch,
84 mut _has_feature: impl FnMut(&str) -> bool,
85 _target: &crate::spec::Target,
87 ) -> Result<Self, &'static str> {
90 $($alias)|* | $reg_name => {
91 $($filter(_arch, &mut _has_feature, _target)?;)?
96 $($bad_reg)|* => Err($error),
98 _ => Err("unknown register"),
103 pub(super) fn fill_reg_map(
104 _arch: super::InlineAsmArch,
105 mut _has_feature: impl FnMut(&str) -> bool,
106 _target: &crate::spec::Target,
107 _map: &mut rustc_data_structures::fx::FxHashMap<
108 super::InlineAsmRegClass,
109 rustc_data_structures::fx::FxHashSet<super::InlineAsmReg>,
112 #[allow(unused_imports)]
113 use super::{InlineAsmReg, InlineAsmRegClass};
115 if $($filter(_arch, &mut _has_feature, _target).is_ok() &&)? true {
116 if let Some(set) = _map.get_mut(&InlineAsmRegClass::$arch($arch_regclass::$class)) {
117 set.insert(InlineAsmReg::$arch($arch_reg::$reg));
120 if let Some(set) = _map.get_mut(&InlineAsmRegClass::$arch($arch_regclass::$extra_class)) {
121 set.insert(InlineAsmReg::$arch($arch_reg::$reg));
132 $(_ : $($ty:expr),+;)?
133 $($feature:literal: $($ty2:expr),+;)*
136 use super::InlineAsmType::*;
142 ($ty2, Some($feature)),
160 pub use aarch64::{AArch64InlineAsmReg, AArch64InlineAsmRegClass};
161 pub use arm::{ArmInlineAsmReg, ArmInlineAsmRegClass};
162 pub use hexagon::{HexagonInlineAsmReg, HexagonInlineAsmRegClass};
163 pub use mips::{MipsInlineAsmReg, MipsInlineAsmRegClass};
164 pub use nvptx::{NvptxInlineAsmReg, NvptxInlineAsmRegClass};
165 pub use powerpc::{PowerPCInlineAsmReg, PowerPCInlineAsmRegClass};
166 pub use riscv::{RiscVInlineAsmReg, RiscVInlineAsmRegClass};
167 pub use spirv::{SpirVInlineAsmReg, SpirVInlineAsmRegClass};
168 pub use wasm::{WasmInlineAsmReg, WasmInlineAsmRegClass};
169 pub use x86::{X86InlineAsmReg, X86InlineAsmRegClass};
171 #[derive(Copy, Clone, Encodable, Decodable, Debug, Eq, PartialEq, Hash)]
172 pub enum InlineAsmArch {
189 impl FromStr for InlineAsmArch {
192 fn from_str(s: &str) -> Result<InlineAsmArch, ()> {
194 "x86" => Ok(Self::X86),
195 "x86_64" => Ok(Self::X86_64),
196 "arm" => Ok(Self::Arm),
197 "aarch64" => Ok(Self::AArch64),
198 "riscv32" => Ok(Self::RiscV32),
199 "riscv64" => Ok(Self::RiscV64),
200 "nvptx64" => Ok(Self::Nvptx64),
201 "powerpc" => Ok(Self::PowerPC),
202 "powerpc64" => Ok(Self::PowerPC64),
203 "hexagon" => Ok(Self::Hexagon),
204 "mips" => Ok(Self::Mips),
205 "mips64" => Ok(Self::Mips64),
206 "spirv" => Ok(Self::SpirV),
207 "wasm32" => Ok(Self::Wasm32),
225 pub enum InlineAsmReg {
226 X86(X86InlineAsmReg),
227 Arm(ArmInlineAsmReg),
228 AArch64(AArch64InlineAsmReg),
229 RiscV(RiscVInlineAsmReg),
230 Nvptx(NvptxInlineAsmReg),
231 PowerPC(PowerPCInlineAsmReg),
232 Hexagon(HexagonInlineAsmReg),
233 Mips(MipsInlineAsmReg),
234 SpirV(SpirVInlineAsmReg),
235 Wasm(WasmInlineAsmReg),
236 // Placeholder for invalid register constraints for the current target
241 pub fn name(self) -> &'static str {
243 Self::X86(r) => r.name(),
244 Self::Arm(r) => r.name(),
245 Self::AArch64(r) => r.name(),
246 Self::RiscV(r) => r.name(),
247 Self::PowerPC(r) => r.name(),
248 Self::Hexagon(r) => r.name(),
249 Self::Mips(r) => r.name(),
250 Self::Err => "<reg>",
254 pub fn reg_class(self) -> InlineAsmRegClass {
256 Self::X86(r) => InlineAsmRegClass::X86(r.reg_class()),
257 Self::Arm(r) => InlineAsmRegClass::Arm(r.reg_class()),
258 Self::AArch64(r) => InlineAsmRegClass::AArch64(r.reg_class()),
259 Self::RiscV(r) => InlineAsmRegClass::RiscV(r.reg_class()),
260 Self::PowerPC(r) => InlineAsmRegClass::PowerPC(r.reg_class()),
261 Self::Hexagon(r) => InlineAsmRegClass::Hexagon(r.reg_class()),
262 Self::Mips(r) => InlineAsmRegClass::Mips(r.reg_class()),
263 Self::Err => InlineAsmRegClass::Err,
269 has_feature: impl FnMut(&str) -> bool,
272 ) -> Result<Self, &'static str> {
273 // FIXME: use direct symbol comparison for register names
274 // Use `Symbol::as_str` instead of `Symbol::with` here because `has_feature` may access `Symbol`.
275 let name = name.as_str();
277 InlineAsmArch::X86 | InlineAsmArch::X86_64 => {
278 Self::X86(X86InlineAsmReg::parse(arch, has_feature, target, &name)?)
280 InlineAsmArch::Arm => {
281 Self::Arm(ArmInlineAsmReg::parse(arch, has_feature, target, &name)?)
283 InlineAsmArch::AArch64 => {
284 Self::AArch64(AArch64InlineAsmReg::parse(arch, has_feature, target, &name)?)
286 InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
287 Self::RiscV(RiscVInlineAsmReg::parse(arch, has_feature, target, &name)?)
289 InlineAsmArch::Nvptx64 => {
290 Self::Nvptx(NvptxInlineAsmReg::parse(arch, has_feature, target, &name)?)
292 InlineAsmArch::PowerPC | InlineAsmArch::PowerPC64 => {
293 Self::PowerPC(PowerPCInlineAsmReg::parse(arch, has_feature, target, &name)?)
295 InlineAsmArch::Hexagon => {
296 Self::Hexagon(HexagonInlineAsmReg::parse(arch, has_feature, target, &name)?)
298 InlineAsmArch::Mips | InlineAsmArch::Mips64 => {
299 Self::Mips(MipsInlineAsmReg::parse(arch, has_feature, target, &name)?)
301 InlineAsmArch::SpirV => {
302 Self::SpirV(SpirVInlineAsmReg::parse(arch, has_feature, target, &name)?)
304 InlineAsmArch::Wasm32 => {
305 Self::Wasm(WasmInlineAsmReg::parse(arch, has_feature, target, &name)?)
310 // NOTE: This function isn't used at the moment, but is needed to support
311 // falling back to an external assembler.
314 out: &mut dyn fmt::Write,
316 modifier: Option<char>,
319 Self::X86(r) => r.emit(out, arch, modifier),
320 Self::Arm(r) => r.emit(out, arch, modifier),
321 Self::AArch64(r) => r.emit(out, arch, modifier),
322 Self::RiscV(r) => r.emit(out, arch, modifier),
323 Self::PowerPC(r) => r.emit(out, arch, modifier),
324 Self::Hexagon(r) => r.emit(out, arch, modifier),
325 Self::Mips(r) => r.emit(out, arch, modifier),
326 Self::Err => unreachable!("Use of InlineAsmReg::Err"),
330 pub fn overlapping_regs(self, mut cb: impl FnMut(InlineAsmReg)) {
332 Self::X86(r) => r.overlapping_regs(|r| cb(Self::X86(r))),
333 Self::Arm(r) => r.overlapping_regs(|r| cb(Self::Arm(r))),
334 Self::AArch64(_) => cb(self),
335 Self::RiscV(_) => cb(self),
336 Self::PowerPC(_) => cb(self),
337 Self::Hexagon(r) => r.overlapping_regs(|r| cb(Self::Hexagon(r))),
338 Self::Mips(_) => cb(self),
339 Self::Err => unreachable!("Use of InlineAsmReg::Err"),
356 pub enum InlineAsmRegClass {
357 X86(X86InlineAsmRegClass),
358 Arm(ArmInlineAsmRegClass),
359 AArch64(AArch64InlineAsmRegClass),
360 RiscV(RiscVInlineAsmRegClass),
361 Nvptx(NvptxInlineAsmRegClass),
362 PowerPC(PowerPCInlineAsmRegClass),
363 Hexagon(HexagonInlineAsmRegClass),
364 Mips(MipsInlineAsmRegClass),
365 SpirV(SpirVInlineAsmRegClass),
366 Wasm(WasmInlineAsmRegClass),
367 // Placeholder for invalid register constraints for the current target
371 impl InlineAsmRegClass {
372 pub fn name(self) -> Symbol {
374 Self::X86(r) => r.name(),
375 Self::Arm(r) => r.name(),
376 Self::AArch64(r) => r.name(),
377 Self::RiscV(r) => r.name(),
378 Self::Nvptx(r) => r.name(),
379 Self::PowerPC(r) => r.name(),
380 Self::Hexagon(r) => r.name(),
381 Self::Mips(r) => r.name(),
382 Self::SpirV(r) => r.name(),
383 Self::Wasm(r) => r.name(),
384 Self::Err => rustc_span::symbol::sym::reg,
388 /// Returns a suggested register class to use for this type. This is called
389 /// after type checking via `supported_types` fails to give a better error
390 /// message to the user.
391 pub fn suggest_class(self, arch: InlineAsmArch, ty: InlineAsmType) -> Option<Self> {
393 Self::X86(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::X86),
394 Self::Arm(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Arm),
395 Self::AArch64(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::AArch64),
396 Self::RiscV(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::RiscV),
397 Self::Nvptx(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Nvptx),
398 Self::PowerPC(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::PowerPC),
399 Self::Hexagon(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Hexagon),
400 Self::Mips(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Mips),
401 Self::SpirV(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::SpirV),
402 Self::Wasm(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Wasm),
403 Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
407 /// Returns a suggested template modifier to use for this type and an
408 /// example of a register named formatted with it.
410 /// Such suggestions are useful if a type smaller than the full register
411 /// size is used and a modifier can be used to point to the subregister of
412 /// the correct size.
413 pub fn suggest_modifier(
417 ) -> Option<(char, &'static str)> {
419 Self::X86(r) => r.suggest_modifier(arch, ty),
420 Self::Arm(r) => r.suggest_modifier(arch, ty),
421 Self::AArch64(r) => r.suggest_modifier(arch, ty),
422 Self::RiscV(r) => r.suggest_modifier(arch, ty),
423 Self::Nvptx(r) => r.suggest_modifier(arch, ty),
424 Self::PowerPC(r) => r.suggest_modifier(arch, ty),
425 Self::Hexagon(r) => r.suggest_modifier(arch, ty),
426 Self::Mips(r) => r.suggest_modifier(arch, ty),
427 Self::SpirV(r) => r.suggest_modifier(arch, ty),
428 Self::Wasm(r) => r.suggest_modifier(arch, ty),
429 Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
433 /// Returns the default modifier for this register and an example of a
434 /// register named formatted with it.
436 /// This is only needed when the register class can suggest a modifier, so
437 /// that the user can be shown how to get the default behavior without a
439 pub fn default_modifier(self, arch: InlineAsmArch) -> Option<(char, &'static str)> {
441 Self::X86(r) => r.default_modifier(arch),
442 Self::Arm(r) => r.default_modifier(arch),
443 Self::AArch64(r) => r.default_modifier(arch),
444 Self::RiscV(r) => r.default_modifier(arch),
445 Self::Nvptx(r) => r.default_modifier(arch),
446 Self::PowerPC(r) => r.default_modifier(arch),
447 Self::Hexagon(r) => r.default_modifier(arch),
448 Self::Mips(r) => r.default_modifier(arch),
449 Self::SpirV(r) => r.default_modifier(arch),
450 Self::Wasm(r) => r.default_modifier(arch),
451 Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
455 /// Returns a list of supported types for this register class, each with a
456 /// options target feature required to use this type.
457 pub fn supported_types(
460 ) -> &'static [(InlineAsmType, Option<&'static str>)] {
462 Self::X86(r) => r.supported_types(arch),
463 Self::Arm(r) => r.supported_types(arch),
464 Self::AArch64(r) => r.supported_types(arch),
465 Self::RiscV(r) => r.supported_types(arch),
466 Self::Nvptx(r) => r.supported_types(arch),
467 Self::PowerPC(r) => r.supported_types(arch),
468 Self::Hexagon(r) => r.supported_types(arch),
469 Self::Mips(r) => r.supported_types(arch),
470 Self::SpirV(r) => r.supported_types(arch),
471 Self::Wasm(r) => r.supported_types(arch),
472 Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
476 pub fn parse(arch: InlineAsmArch, name: Symbol) -> Result<Self, &'static str> {
478 InlineAsmArch::X86 | InlineAsmArch::X86_64 => {
479 Self::X86(X86InlineAsmRegClass::parse(arch, name)?)
481 InlineAsmArch::Arm => Self::Arm(ArmInlineAsmRegClass::parse(arch, name)?),
482 InlineAsmArch::AArch64 => Self::AArch64(AArch64InlineAsmRegClass::parse(arch, name)?),
483 InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
484 Self::RiscV(RiscVInlineAsmRegClass::parse(arch, name)?)
486 InlineAsmArch::Nvptx64 => Self::Nvptx(NvptxInlineAsmRegClass::parse(arch, name)?),
487 InlineAsmArch::PowerPC | InlineAsmArch::PowerPC64 => {
488 Self::PowerPC(PowerPCInlineAsmRegClass::parse(arch, name)?)
490 InlineAsmArch::Hexagon => Self::Hexagon(HexagonInlineAsmRegClass::parse(arch, name)?),
491 InlineAsmArch::Mips | InlineAsmArch::Mips64 => {
492 Self::Mips(MipsInlineAsmRegClass::parse(arch, name)?)
494 InlineAsmArch::SpirV => Self::SpirV(SpirVInlineAsmRegClass::parse(arch, name)?),
495 InlineAsmArch::Wasm32 => Self::Wasm(WasmInlineAsmRegClass::parse(arch, name)?),
499 /// Returns the list of template modifiers that can be used with this
501 pub fn valid_modifiers(self, arch: InlineAsmArch) -> &'static [char] {
503 Self::X86(r) => r.valid_modifiers(arch),
504 Self::Arm(r) => r.valid_modifiers(arch),
505 Self::AArch64(r) => r.valid_modifiers(arch),
506 Self::RiscV(r) => r.valid_modifiers(arch),
507 Self::Nvptx(r) => r.valid_modifiers(arch),
508 Self::PowerPC(r) => r.valid_modifiers(arch),
509 Self::Hexagon(r) => r.valid_modifiers(arch),
510 Self::Mips(r) => r.valid_modifiers(arch),
511 Self::SpirV(r) => r.valid_modifiers(arch),
512 Self::Wasm(r) => r.valid_modifiers(arch),
513 Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
530 pub enum InlineAsmRegOrRegClass {
532 RegClass(InlineAsmRegClass),
535 impl InlineAsmRegOrRegClass {
536 pub fn reg_class(self) -> InlineAsmRegClass {
538 Self::Reg(r) => r.reg_class(),
539 Self::RegClass(r) => r,
544 impl fmt::Display for InlineAsmRegOrRegClass {
545 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
547 Self::Reg(r) => write!(f, "\"{}\"", r.name()),
548 Self::RegClass(r) => write!(f, "{}", r.name()),
553 /// Set of types which can be used with a particular register class.
554 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
555 pub enum InlineAsmType {
573 pub fn is_integer(self) -> bool {
574 matches!(self, Self::I8 | Self::I16 | Self::I32 | Self::I64 | Self::I128)
577 pub fn size(self) -> Size {
578 Size::from_bytes(match self {
586 Self::VecI8(n) => n * 1,
587 Self::VecI16(n) => n * 2,
588 Self::VecI32(n) => n * 4,
589 Self::VecI64(n) => n * 8,
590 Self::VecI128(n) => n * 16,
591 Self::VecF32(n) => n * 4,
592 Self::VecF64(n) => n * 8,
597 impl fmt::Display for InlineAsmType {
598 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
600 Self::I8 => f.write_str("i8"),
601 Self::I16 => f.write_str("i16"),
602 Self::I32 => f.write_str("i32"),
603 Self::I64 => f.write_str("i64"),
604 Self::I128 => f.write_str("i128"),
605 Self::F32 => f.write_str("f32"),
606 Self::F64 => f.write_str("f64"),
607 Self::VecI8(n) => write!(f, "i8x{}", n),
608 Self::VecI16(n) => write!(f, "i16x{}", n),
609 Self::VecI32(n) => write!(f, "i32x{}", n),
610 Self::VecI64(n) => write!(f, "i64x{}", n),
611 Self::VecI128(n) => write!(f, "i128x{}", n),
612 Self::VecF32(n) => write!(f, "f32x{}", n),
613 Self::VecF64(n) => write!(f, "f64x{}", n),
618 /// Returns the full set of allocatable registers for a given architecture.
620 /// The registers are structured as a map containing the set of allocatable
621 /// registers in each register class. A particular register may be allocatable
622 /// from multiple register classes, in which case it will appear multiple times
624 // NOTE: This function isn't used at the moment, but is needed to support
625 // falling back to an external assembler.
626 pub fn allocatable_registers(
628 has_feature: impl FnMut(&str) -> bool,
629 target: &crate::spec::Target,
630 ) -> FxHashMap<InlineAsmRegClass, FxHashSet<InlineAsmReg>> {
632 InlineAsmArch::X86 | InlineAsmArch::X86_64 => {
633 let mut map = x86::regclass_map();
634 x86::fill_reg_map(arch, has_feature, target, &mut map);
637 InlineAsmArch::Arm => {
638 let mut map = arm::regclass_map();
639 arm::fill_reg_map(arch, has_feature, target, &mut map);
642 InlineAsmArch::AArch64 => {
643 let mut map = aarch64::regclass_map();
644 aarch64::fill_reg_map(arch, has_feature, target, &mut map);
647 InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
648 let mut map = riscv::regclass_map();
649 riscv::fill_reg_map(arch, has_feature, target, &mut map);
652 InlineAsmArch::Nvptx64 => {
653 let mut map = nvptx::regclass_map();
654 nvptx::fill_reg_map(arch, has_feature, target, &mut map);
657 InlineAsmArch::PowerPC | InlineAsmArch::PowerPC64 => {
658 let mut map = powerpc::regclass_map();
659 powerpc::fill_reg_map(arch, has_feature, target, &mut map);
662 InlineAsmArch::Hexagon => {
663 let mut map = hexagon::regclass_map();
664 hexagon::fill_reg_map(arch, has_feature, target, &mut map);
667 InlineAsmArch::Mips | InlineAsmArch::Mips64 => {
668 let mut map = mips::regclass_map();
669 mips::fill_reg_map(arch, has_feature, target, &mut map);
672 InlineAsmArch::SpirV => {
673 let mut map = spirv::regclass_map();
674 spirv::fill_reg_map(arch, has_feature, target, &mut map);
677 InlineAsmArch::Wasm32 => {
678 let mut map = wasm::regclass_map();
679 wasm::fill_reg_map(arch, has_feature, target, &mut map);