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)),
161 pub use aarch64::{AArch64InlineAsmReg, AArch64InlineAsmRegClass};
162 pub use arm::{ArmInlineAsmReg, ArmInlineAsmRegClass};
163 pub use bpf::{BpfInlineAsmReg, BpfInlineAsmRegClass};
164 pub use hexagon::{HexagonInlineAsmReg, HexagonInlineAsmRegClass};
165 pub use mips::{MipsInlineAsmReg, MipsInlineAsmRegClass};
166 pub use nvptx::{NvptxInlineAsmReg, NvptxInlineAsmRegClass};
167 pub use powerpc::{PowerPCInlineAsmReg, PowerPCInlineAsmRegClass};
168 pub use riscv::{RiscVInlineAsmReg, RiscVInlineAsmRegClass};
169 pub use spirv::{SpirVInlineAsmReg, SpirVInlineAsmRegClass};
170 pub use wasm::{WasmInlineAsmReg, WasmInlineAsmRegClass};
171 pub use x86::{X86InlineAsmReg, X86InlineAsmRegClass};
173 #[derive(Copy, Clone, Encodable, Decodable, Debug, Eq, PartialEq, Hash)]
174 pub enum InlineAsmArch {
192 impl FromStr for InlineAsmArch {
195 fn from_str(s: &str) -> Result<InlineAsmArch, ()> {
197 "x86" => Ok(Self::X86),
198 "x86_64" => Ok(Self::X86_64),
199 "arm" => Ok(Self::Arm),
200 "aarch64" => Ok(Self::AArch64),
201 "riscv32" => Ok(Self::RiscV32),
202 "riscv64" => Ok(Self::RiscV64),
203 "nvptx64" => Ok(Self::Nvptx64),
204 "powerpc" => Ok(Self::PowerPC),
205 "powerpc64" => Ok(Self::PowerPC64),
206 "hexagon" => Ok(Self::Hexagon),
207 "mips" => Ok(Self::Mips),
208 "mips64" => Ok(Self::Mips64),
209 "spirv" => Ok(Self::SpirV),
210 "wasm32" => Ok(Self::Wasm32),
211 "bpf" => Ok(Self::Bpf),
229 pub enum InlineAsmReg {
230 X86(X86InlineAsmReg),
231 Arm(ArmInlineAsmReg),
232 AArch64(AArch64InlineAsmReg),
233 RiscV(RiscVInlineAsmReg),
234 Nvptx(NvptxInlineAsmReg),
235 PowerPC(PowerPCInlineAsmReg),
236 Hexagon(HexagonInlineAsmReg),
237 Mips(MipsInlineAsmReg),
238 SpirV(SpirVInlineAsmReg),
239 Wasm(WasmInlineAsmReg),
240 Bpf(BpfInlineAsmReg),
241 // Placeholder for invalid register constraints for the current target
246 pub fn name(self) -> &'static str {
248 Self::X86(r) => r.name(),
249 Self::Arm(r) => r.name(),
250 Self::AArch64(r) => r.name(),
251 Self::RiscV(r) => r.name(),
252 Self::PowerPC(r) => r.name(),
253 Self::Hexagon(r) => r.name(),
254 Self::Mips(r) => r.name(),
255 Self::Bpf(r) => r.name(),
256 Self::Err => "<reg>",
260 pub fn reg_class(self) -> InlineAsmRegClass {
262 Self::X86(r) => InlineAsmRegClass::X86(r.reg_class()),
263 Self::Arm(r) => InlineAsmRegClass::Arm(r.reg_class()),
264 Self::AArch64(r) => InlineAsmRegClass::AArch64(r.reg_class()),
265 Self::RiscV(r) => InlineAsmRegClass::RiscV(r.reg_class()),
266 Self::PowerPC(r) => InlineAsmRegClass::PowerPC(r.reg_class()),
267 Self::Hexagon(r) => InlineAsmRegClass::Hexagon(r.reg_class()),
268 Self::Mips(r) => InlineAsmRegClass::Mips(r.reg_class()),
269 Self::Bpf(r) => InlineAsmRegClass::Bpf(r.reg_class()),
270 Self::Err => InlineAsmRegClass::Err,
276 has_feature: impl FnMut(&str) -> bool,
279 ) -> Result<Self, &'static str> {
280 // FIXME: use direct symbol comparison for register names
281 // Use `Symbol::as_str` instead of `Symbol::with` here because `has_feature` may access `Symbol`.
282 let name = name.as_str();
284 InlineAsmArch::X86 | InlineAsmArch::X86_64 => {
285 Self::X86(X86InlineAsmReg::parse(arch, has_feature, target, &name)?)
287 InlineAsmArch::Arm => {
288 Self::Arm(ArmInlineAsmReg::parse(arch, has_feature, target, &name)?)
290 InlineAsmArch::AArch64 => {
291 Self::AArch64(AArch64InlineAsmReg::parse(arch, has_feature, target, &name)?)
293 InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
294 Self::RiscV(RiscVInlineAsmReg::parse(arch, has_feature, target, &name)?)
296 InlineAsmArch::Nvptx64 => {
297 Self::Nvptx(NvptxInlineAsmReg::parse(arch, has_feature, target, &name)?)
299 InlineAsmArch::PowerPC | InlineAsmArch::PowerPC64 => {
300 Self::PowerPC(PowerPCInlineAsmReg::parse(arch, has_feature, target, &name)?)
302 InlineAsmArch::Hexagon => {
303 Self::Hexagon(HexagonInlineAsmReg::parse(arch, has_feature, target, &name)?)
305 InlineAsmArch::Mips | InlineAsmArch::Mips64 => {
306 Self::Mips(MipsInlineAsmReg::parse(arch, has_feature, target, &name)?)
308 InlineAsmArch::SpirV => {
309 Self::SpirV(SpirVInlineAsmReg::parse(arch, has_feature, target, &name)?)
311 InlineAsmArch::Wasm32 => {
312 Self::Wasm(WasmInlineAsmReg::parse(arch, has_feature, target, &name)?)
314 InlineAsmArch::Bpf => {
315 Self::Bpf(BpfInlineAsmReg::parse(arch, has_feature, target, &name)?)
320 // NOTE: This function isn't used at the moment, but is needed to support
321 // falling back to an external assembler.
324 out: &mut dyn fmt::Write,
326 modifier: Option<char>,
329 Self::X86(r) => r.emit(out, arch, modifier),
330 Self::Arm(r) => r.emit(out, arch, modifier),
331 Self::AArch64(r) => r.emit(out, arch, modifier),
332 Self::RiscV(r) => r.emit(out, arch, modifier),
333 Self::PowerPC(r) => r.emit(out, arch, modifier),
334 Self::Hexagon(r) => r.emit(out, arch, modifier),
335 Self::Mips(r) => r.emit(out, arch, modifier),
336 Self::Bpf(r) => r.emit(out, arch, modifier),
337 Self::Err => unreachable!("Use of InlineAsmReg::Err"),
341 pub fn overlapping_regs(self, mut cb: impl FnMut(InlineAsmReg)) {
343 Self::X86(r) => r.overlapping_regs(|r| cb(Self::X86(r))),
344 Self::Arm(r) => r.overlapping_regs(|r| cb(Self::Arm(r))),
345 Self::AArch64(_) => cb(self),
346 Self::RiscV(_) => cb(self),
347 Self::PowerPC(_) => cb(self),
348 Self::Hexagon(r) => r.overlapping_regs(|r| cb(Self::Hexagon(r))),
349 Self::Mips(_) => cb(self),
350 Self::Bpf(r) => r.overlapping_regs(|r| cb(Self::Bpf(r))),
351 Self::Err => unreachable!("Use of InlineAsmReg::Err"),
368 pub enum InlineAsmRegClass {
369 X86(X86InlineAsmRegClass),
370 Arm(ArmInlineAsmRegClass),
371 AArch64(AArch64InlineAsmRegClass),
372 RiscV(RiscVInlineAsmRegClass),
373 Nvptx(NvptxInlineAsmRegClass),
374 PowerPC(PowerPCInlineAsmRegClass),
375 Hexagon(HexagonInlineAsmRegClass),
376 Mips(MipsInlineAsmRegClass),
377 SpirV(SpirVInlineAsmRegClass),
378 Wasm(WasmInlineAsmRegClass),
379 Bpf(BpfInlineAsmRegClass),
380 // Placeholder for invalid register constraints for the current target
384 impl InlineAsmRegClass {
385 pub fn name(self) -> Symbol {
387 Self::X86(r) => r.name(),
388 Self::Arm(r) => r.name(),
389 Self::AArch64(r) => r.name(),
390 Self::RiscV(r) => r.name(),
391 Self::Nvptx(r) => r.name(),
392 Self::PowerPC(r) => r.name(),
393 Self::Hexagon(r) => r.name(),
394 Self::Mips(r) => r.name(),
395 Self::SpirV(r) => r.name(),
396 Self::Wasm(r) => r.name(),
397 Self::Bpf(r) => r.name(),
398 Self::Err => rustc_span::symbol::sym::reg,
402 /// Returns a suggested register class to use for this type. This is called
403 /// after type checking via `supported_types` fails to give a better error
404 /// message to the user.
405 pub fn suggest_class(self, arch: InlineAsmArch, ty: InlineAsmType) -> Option<Self> {
407 Self::X86(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::X86),
408 Self::Arm(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Arm),
409 Self::AArch64(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::AArch64),
410 Self::RiscV(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::RiscV),
411 Self::Nvptx(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Nvptx),
412 Self::PowerPC(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::PowerPC),
413 Self::Hexagon(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Hexagon),
414 Self::Mips(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Mips),
415 Self::SpirV(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::SpirV),
416 Self::Wasm(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Wasm),
417 Self::Bpf(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Bpf),
418 Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
422 /// Returns a suggested template modifier to use for this type and an
423 /// example of a register named formatted with it.
425 /// Such suggestions are useful if a type smaller than the full register
426 /// size is used and a modifier can be used to point to the subregister of
427 /// the correct size.
428 pub fn suggest_modifier(
432 ) -> Option<(char, &'static str)> {
434 Self::X86(r) => r.suggest_modifier(arch, ty),
435 Self::Arm(r) => r.suggest_modifier(arch, ty),
436 Self::AArch64(r) => r.suggest_modifier(arch, ty),
437 Self::RiscV(r) => r.suggest_modifier(arch, ty),
438 Self::Nvptx(r) => r.suggest_modifier(arch, ty),
439 Self::PowerPC(r) => r.suggest_modifier(arch, ty),
440 Self::Hexagon(r) => r.suggest_modifier(arch, ty),
441 Self::Mips(r) => r.suggest_modifier(arch, ty),
442 Self::SpirV(r) => r.suggest_modifier(arch, ty),
443 Self::Wasm(r) => r.suggest_modifier(arch, ty),
444 Self::Bpf(r) => r.suggest_modifier(arch, ty),
445 Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
449 /// Returns the default modifier for this register and an example of a
450 /// register named formatted with it.
452 /// This is only needed when the register class can suggest a modifier, so
453 /// that the user can be shown how to get the default behavior without a
455 pub fn default_modifier(self, arch: InlineAsmArch) -> Option<(char, &'static str)> {
457 Self::X86(r) => r.default_modifier(arch),
458 Self::Arm(r) => r.default_modifier(arch),
459 Self::AArch64(r) => r.default_modifier(arch),
460 Self::RiscV(r) => r.default_modifier(arch),
461 Self::Nvptx(r) => r.default_modifier(arch),
462 Self::PowerPC(r) => r.default_modifier(arch),
463 Self::Hexagon(r) => r.default_modifier(arch),
464 Self::Mips(r) => r.default_modifier(arch),
465 Self::SpirV(r) => r.default_modifier(arch),
466 Self::Wasm(r) => r.default_modifier(arch),
467 Self::Bpf(r) => r.default_modifier(arch),
468 Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
472 /// Returns a list of supported types for this register class, each with a
473 /// options target feature required to use this type.
474 pub fn supported_types(
477 ) -> &'static [(InlineAsmType, Option<&'static str>)] {
479 Self::X86(r) => r.supported_types(arch),
480 Self::Arm(r) => r.supported_types(arch),
481 Self::AArch64(r) => r.supported_types(arch),
482 Self::RiscV(r) => r.supported_types(arch),
483 Self::Nvptx(r) => r.supported_types(arch),
484 Self::PowerPC(r) => r.supported_types(arch),
485 Self::Hexagon(r) => r.supported_types(arch),
486 Self::Mips(r) => r.supported_types(arch),
487 Self::SpirV(r) => r.supported_types(arch),
488 Self::Wasm(r) => r.supported_types(arch),
489 Self::Bpf(r) => r.supported_types(arch),
490 Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
494 pub fn parse(arch: InlineAsmArch, name: Symbol) -> Result<Self, &'static str> {
496 InlineAsmArch::X86 | InlineAsmArch::X86_64 => {
497 Self::X86(X86InlineAsmRegClass::parse(arch, name)?)
499 InlineAsmArch::Arm => Self::Arm(ArmInlineAsmRegClass::parse(arch, name)?),
500 InlineAsmArch::AArch64 => Self::AArch64(AArch64InlineAsmRegClass::parse(arch, name)?),
501 InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
502 Self::RiscV(RiscVInlineAsmRegClass::parse(arch, name)?)
504 InlineAsmArch::Nvptx64 => Self::Nvptx(NvptxInlineAsmRegClass::parse(arch, name)?),
505 InlineAsmArch::PowerPC | InlineAsmArch::PowerPC64 => {
506 Self::PowerPC(PowerPCInlineAsmRegClass::parse(arch, name)?)
508 InlineAsmArch::Hexagon => Self::Hexagon(HexagonInlineAsmRegClass::parse(arch, name)?),
509 InlineAsmArch::Mips | InlineAsmArch::Mips64 => {
510 Self::Mips(MipsInlineAsmRegClass::parse(arch, name)?)
512 InlineAsmArch::SpirV => Self::SpirV(SpirVInlineAsmRegClass::parse(arch, name)?),
513 InlineAsmArch::Wasm32 => Self::Wasm(WasmInlineAsmRegClass::parse(arch, name)?),
514 InlineAsmArch::Bpf => Self::Bpf(BpfInlineAsmRegClass::parse(arch, name)?),
518 /// Returns the list of template modifiers that can be used with this
520 pub fn valid_modifiers(self, arch: InlineAsmArch) -> &'static [char] {
522 Self::X86(r) => r.valid_modifiers(arch),
523 Self::Arm(r) => r.valid_modifiers(arch),
524 Self::AArch64(r) => r.valid_modifiers(arch),
525 Self::RiscV(r) => r.valid_modifiers(arch),
526 Self::Nvptx(r) => r.valid_modifiers(arch),
527 Self::PowerPC(r) => r.valid_modifiers(arch),
528 Self::Hexagon(r) => r.valid_modifiers(arch),
529 Self::Mips(r) => r.valid_modifiers(arch),
530 Self::SpirV(r) => r.valid_modifiers(arch),
531 Self::Wasm(r) => r.valid_modifiers(arch),
532 Self::Bpf(r) => r.valid_modifiers(arch),
533 Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
550 pub enum InlineAsmRegOrRegClass {
552 RegClass(InlineAsmRegClass),
555 impl InlineAsmRegOrRegClass {
556 pub fn reg_class(self) -> InlineAsmRegClass {
558 Self::Reg(r) => r.reg_class(),
559 Self::RegClass(r) => r,
564 impl fmt::Display for InlineAsmRegOrRegClass {
565 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
567 Self::Reg(r) => write!(f, "\"{}\"", r.name()),
568 Self::RegClass(r) => write!(f, "{}", r.name()),
573 /// Set of types which can be used with a particular register class.
574 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
575 pub enum InlineAsmType {
593 pub fn is_integer(self) -> bool {
594 matches!(self, Self::I8 | Self::I16 | Self::I32 | Self::I64 | Self::I128)
597 pub fn size(self) -> Size {
598 Size::from_bytes(match self {
606 Self::VecI8(n) => n * 1,
607 Self::VecI16(n) => n * 2,
608 Self::VecI32(n) => n * 4,
609 Self::VecI64(n) => n * 8,
610 Self::VecI128(n) => n * 16,
611 Self::VecF32(n) => n * 4,
612 Self::VecF64(n) => n * 8,
617 impl fmt::Display for InlineAsmType {
618 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
620 Self::I8 => f.write_str("i8"),
621 Self::I16 => f.write_str("i16"),
622 Self::I32 => f.write_str("i32"),
623 Self::I64 => f.write_str("i64"),
624 Self::I128 => f.write_str("i128"),
625 Self::F32 => f.write_str("f32"),
626 Self::F64 => f.write_str("f64"),
627 Self::VecI8(n) => write!(f, "i8x{}", n),
628 Self::VecI16(n) => write!(f, "i16x{}", n),
629 Self::VecI32(n) => write!(f, "i32x{}", n),
630 Self::VecI64(n) => write!(f, "i64x{}", n),
631 Self::VecI128(n) => write!(f, "i128x{}", n),
632 Self::VecF32(n) => write!(f, "f32x{}", n),
633 Self::VecF64(n) => write!(f, "f64x{}", n),
638 /// Returns the full set of allocatable registers for a given architecture.
640 /// The registers are structured as a map containing the set of allocatable
641 /// registers in each register class. A particular register may be allocatable
642 /// from multiple register classes, in which case it will appear multiple times
644 // NOTE: This function isn't used at the moment, but is needed to support
645 // falling back to an external assembler.
646 pub fn allocatable_registers(
648 has_feature: impl FnMut(&str) -> bool,
649 target: &crate::spec::Target,
650 ) -> FxHashMap<InlineAsmRegClass, FxHashSet<InlineAsmReg>> {
652 InlineAsmArch::X86 | InlineAsmArch::X86_64 => {
653 let mut map = x86::regclass_map();
654 x86::fill_reg_map(arch, has_feature, target, &mut map);
657 InlineAsmArch::Arm => {
658 let mut map = arm::regclass_map();
659 arm::fill_reg_map(arch, has_feature, target, &mut map);
662 InlineAsmArch::AArch64 => {
663 let mut map = aarch64::regclass_map();
664 aarch64::fill_reg_map(arch, has_feature, target, &mut map);
667 InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
668 let mut map = riscv::regclass_map();
669 riscv::fill_reg_map(arch, has_feature, target, &mut map);
672 InlineAsmArch::Nvptx64 => {
673 let mut map = nvptx::regclass_map();
674 nvptx::fill_reg_map(arch, has_feature, target, &mut map);
677 InlineAsmArch::PowerPC | InlineAsmArch::PowerPC64 => {
678 let mut map = powerpc::regclass_map();
679 powerpc::fill_reg_map(arch, has_feature, target, &mut map);
682 InlineAsmArch::Hexagon => {
683 let mut map = hexagon::regclass_map();
684 hexagon::fill_reg_map(arch, has_feature, target, &mut map);
687 InlineAsmArch::Mips | InlineAsmArch::Mips64 => {
688 let mut map = mips::regclass_map();
689 mips::fill_reg_map(arch, has_feature, target, &mut map);
692 InlineAsmArch::SpirV => {
693 let mut map = spirv::regclass_map();
694 spirv::fill_reg_map(arch, has_feature, target, &mut map);
697 InlineAsmArch::Wasm32 => {
698 let mut map = wasm::regclass_map();
699 wasm::fill_reg_map(arch, has_feature, target, &mut map);
702 InlineAsmArch::Bpf => {
703 let mut map = bpf::regclass_map();
704 bpf::fill_reg_map(arch, has_feature, target, &mut map);