2 use crate::spec::Target;
3 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
4 use rustc_macros::HashStable_Generic;
5 use rustc_span::Symbol;
10 macro_rules! def_reg_class {
11 ($arch:ident $arch_regclass:ident {
16 #[derive(Copy, Clone, Encodable, Decodable, Debug, Eq, PartialEq, PartialOrd, Hash, HashStable_Generic)]
17 #[allow(non_camel_case_types)]
18 pub enum $arch_regclass {
23 pub fn name(self) -> rustc_span::Symbol {
25 $(Self::$class => rustc_span::symbol::sym::$class,)*
29 pub fn parse(_arch: super::InlineAsmArch, name: rustc_span::Symbol) -> Result<Self, &'static str> {
32 rustc_span::sym::$class => Ok(Self::$class),
34 _ => Err("unknown register class"),
39 pub(super) fn regclass_map() -> rustc_data_structures::fx::FxHashMap<
40 super::InlineAsmRegClass,
41 rustc_data_structures::fx::FxHashSet<super::InlineAsmReg>,
43 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
44 use super::InlineAsmRegClass;
45 let mut map = FxHashMap::default();
47 map.insert(InlineAsmRegClass::$arch($arch_regclass::$class), FxHashSet::default());
55 macro_rules! def_regs {
56 ($arch:ident $arch_reg:ident $arch_regclass:ident {
58 $reg:ident: $class:ident $(, $extra_class:ident)* = [$reg_name:literal $(, $alias:literal)*] $(% $filter:ident)?,
61 #error = [$($bad_reg:literal),+] => $error:literal,
64 #[allow(unreachable_code)]
65 #[derive(Copy, Clone, Encodable, Decodable, Debug, Eq, PartialEq, PartialOrd, Hash, HashStable_Generic)]
66 #[allow(non_camel_case_types)]
72 pub fn name(self) -> &'static str {
74 $(Self::$reg => $reg_name,)*
78 pub fn reg_class(self) -> $arch_regclass {
80 $(Self::$reg => $arch_regclass::$class,)*
85 _arch: super::InlineAsmArch,
86 mut _has_feature: impl FnMut(&str) -> bool,
87 _target: &crate::spec::Target,
89 ) -> Result<Self, &'static str> {
92 $($alias)|* | $reg_name => {
93 $($filter(_arch, &mut _has_feature, _target)?;)?
98 $($bad_reg)|* => Err($error),
100 _ => Err("unknown register"),
105 pub(super) fn fill_reg_map(
106 _arch: super::InlineAsmArch,
107 mut _has_feature: impl FnMut(&str) -> bool,
108 _target: &crate::spec::Target,
109 _map: &mut rustc_data_structures::fx::FxHashMap<
110 super::InlineAsmRegClass,
111 rustc_data_structures::fx::FxHashSet<super::InlineAsmReg>,
114 #[allow(unused_imports)]
115 use super::{InlineAsmReg, InlineAsmRegClass};
117 if $($filter(_arch, &mut _has_feature, _target).is_ok() &&)? true {
118 if let Some(set) = _map.get_mut(&InlineAsmRegClass::$arch($arch_regclass::$class)) {
119 set.insert(InlineAsmReg::$arch($arch_reg::$reg));
122 if let Some(set) = _map.get_mut(&InlineAsmRegClass::$arch($arch_regclass::$extra_class)) {
123 set.insert(InlineAsmReg::$arch($arch_reg::$reg));
135 $(_ : $($ty:expr),+;)?
136 $($feature:literal: $($ty2:expr),+;)*
139 use super::InlineAsmType::*;
145 ($ty2, Some($feature)),
162 pub use aarch64::{AArch64InlineAsmReg, AArch64InlineAsmRegClass};
163 pub use arm::{ArmInlineAsmReg, ArmInlineAsmRegClass};
164 pub use hexagon::{HexagonInlineAsmReg, HexagonInlineAsmRegClass};
165 pub use mips::{MipsInlineAsmReg, MipsInlineAsmRegClass};
166 pub use nvptx::{NvptxInlineAsmReg, NvptxInlineAsmRegClass};
167 pub use riscv::{RiscVInlineAsmReg, RiscVInlineAsmRegClass};
168 pub use spirv::{SpirVInlineAsmReg, SpirVInlineAsmRegClass};
169 pub use wasm::{WasmInlineAsmReg, WasmInlineAsmRegClass};
170 pub use x86::{X86InlineAsmReg, X86InlineAsmRegClass};
172 #[derive(Copy, Clone, Encodable, Decodable, Debug, Eq, PartialEq, Hash)]
173 pub enum InlineAsmArch {
188 impl FromStr for InlineAsmArch {
191 fn from_str(s: &str) -> Result<InlineAsmArch, ()> {
193 "x86" => Ok(Self::X86),
194 "x86_64" => Ok(Self::X86_64),
195 "arm" => Ok(Self::Arm),
196 "aarch64" => Ok(Self::AArch64),
197 "riscv32" => Ok(Self::RiscV32),
198 "riscv64" => Ok(Self::RiscV64),
199 "nvptx64" => Ok(Self::Nvptx64),
200 "hexagon" => Ok(Self::Hexagon),
201 "mips" => Ok(Self::Mips),
202 "mips64" => Ok(Self::Mips64),
203 "spirv" => Ok(Self::SpirV),
204 "wasm32" => Ok(Self::Wasm32),
222 pub enum InlineAsmReg {
223 X86(X86InlineAsmReg),
224 Arm(ArmInlineAsmReg),
225 AArch64(AArch64InlineAsmReg),
226 RiscV(RiscVInlineAsmReg),
227 Nvptx(NvptxInlineAsmReg),
228 Hexagon(HexagonInlineAsmReg),
229 Mips(MipsInlineAsmReg),
230 SpirV(SpirVInlineAsmReg),
231 Wasm(WasmInlineAsmReg),
232 // Placeholder for invalid register constraints for the current target
237 pub fn name(self) -> &'static str {
239 Self::X86(r) => r.name(),
240 Self::Arm(r) => r.name(),
241 Self::AArch64(r) => r.name(),
242 Self::RiscV(r) => r.name(),
243 Self::Hexagon(r) => r.name(),
244 Self::Mips(r) => r.name(),
245 Self::Err => "<reg>",
249 pub fn reg_class(self) -> InlineAsmRegClass {
251 Self::X86(r) => InlineAsmRegClass::X86(r.reg_class()),
252 Self::Arm(r) => InlineAsmRegClass::Arm(r.reg_class()),
253 Self::AArch64(r) => InlineAsmRegClass::AArch64(r.reg_class()),
254 Self::RiscV(r) => InlineAsmRegClass::RiscV(r.reg_class()),
255 Self::Hexagon(r) => InlineAsmRegClass::Hexagon(r.reg_class()),
256 Self::Mips(r) => InlineAsmRegClass::Mips(r.reg_class()),
257 Self::Err => InlineAsmRegClass::Err,
263 has_feature: impl FnMut(&str) -> bool,
266 ) -> Result<Self, &'static str> {
267 // FIXME: use direct symbol comparison for register names
268 // Use `Symbol::as_str` instead of `Symbol::with` here because `has_feature` may access `Symbol`.
269 let name = name.as_str();
271 InlineAsmArch::X86 | InlineAsmArch::X86_64 => {
272 Self::X86(X86InlineAsmReg::parse(arch, has_feature, target, &name)?)
274 InlineAsmArch::Arm => {
275 Self::Arm(ArmInlineAsmReg::parse(arch, has_feature, target, &name)?)
277 InlineAsmArch::AArch64 => {
278 Self::AArch64(AArch64InlineAsmReg::parse(arch, has_feature, target, &name)?)
280 InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
281 Self::RiscV(RiscVInlineAsmReg::parse(arch, has_feature, target, &name)?)
283 InlineAsmArch::Nvptx64 => {
284 Self::Nvptx(NvptxInlineAsmReg::parse(arch, has_feature, target, &name)?)
286 InlineAsmArch::Hexagon => {
287 Self::Hexagon(HexagonInlineAsmReg::parse(arch, has_feature, target, &name)?)
289 InlineAsmArch::Mips | InlineAsmArch::Mips64 => {
290 Self::Mips(MipsInlineAsmReg::parse(arch, has_feature, target, &name)?)
292 InlineAsmArch::SpirV => {
293 Self::SpirV(SpirVInlineAsmReg::parse(arch, has_feature, target, &name)?)
295 InlineAsmArch::Wasm32 => {
296 Self::Wasm(WasmInlineAsmReg::parse(arch, has_feature, target, &name)?)
301 // NOTE: This function isn't used at the moment, but is needed to support
302 // falling back to an external assembler.
305 out: &mut dyn fmt::Write,
307 modifier: Option<char>,
310 Self::X86(r) => r.emit(out, arch, modifier),
311 Self::Arm(r) => r.emit(out, arch, modifier),
312 Self::AArch64(r) => r.emit(out, arch, modifier),
313 Self::RiscV(r) => r.emit(out, arch, modifier),
314 Self::Hexagon(r) => r.emit(out, arch, modifier),
315 Self::Mips(r) => r.emit(out, arch, modifier),
316 Self::Err => unreachable!("Use of InlineAsmReg::Err"),
320 pub fn overlapping_regs(self, mut cb: impl FnMut(InlineAsmReg)) {
322 Self::X86(r) => r.overlapping_regs(|r| cb(Self::X86(r))),
323 Self::Arm(r) => r.overlapping_regs(|r| cb(Self::Arm(r))),
324 Self::AArch64(_) => cb(self),
325 Self::RiscV(_) => cb(self),
326 Self::Hexagon(r) => r.overlapping_regs(|r| cb(Self::Hexagon(r))),
327 Self::Mips(_) => cb(self),
328 Self::Err => unreachable!("Use of InlineAsmReg::Err"),
345 pub enum InlineAsmRegClass {
346 X86(X86InlineAsmRegClass),
347 Arm(ArmInlineAsmRegClass),
348 AArch64(AArch64InlineAsmRegClass),
349 RiscV(RiscVInlineAsmRegClass),
350 Nvptx(NvptxInlineAsmRegClass),
351 Hexagon(HexagonInlineAsmRegClass),
352 Mips(MipsInlineAsmRegClass),
353 SpirV(SpirVInlineAsmRegClass),
354 Wasm(WasmInlineAsmRegClass),
355 // Placeholder for invalid register constraints for the current target
359 impl InlineAsmRegClass {
360 pub fn name(self) -> Symbol {
362 Self::X86(r) => r.name(),
363 Self::Arm(r) => r.name(),
364 Self::AArch64(r) => r.name(),
365 Self::RiscV(r) => r.name(),
366 Self::Nvptx(r) => r.name(),
367 Self::Hexagon(r) => r.name(),
368 Self::Mips(r) => r.name(),
369 Self::SpirV(r) => r.name(),
370 Self::Wasm(r) => r.name(),
371 Self::Err => rustc_span::symbol::sym::reg,
375 /// Returns a suggested register class to use for this type. This is called
376 /// after type checking via `supported_types` fails to give a better error
377 /// message to the user.
378 pub fn suggest_class(self, arch: InlineAsmArch, ty: InlineAsmType) -> Option<Self> {
380 Self::X86(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::X86),
381 Self::Arm(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Arm),
382 Self::AArch64(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::AArch64),
383 Self::RiscV(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::RiscV),
384 Self::Nvptx(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Nvptx),
385 Self::Hexagon(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Hexagon),
386 Self::Mips(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Mips),
387 Self::SpirV(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::SpirV),
388 Self::Wasm(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Wasm),
389 Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
393 /// Returns a suggested template modifier to use for this type and an
394 /// example of a register named formatted with it.
396 /// Such suggestions are useful if a type smaller than the full register
397 /// size is used and a modifier can be used to point to the subregister of
398 /// the correct size.
399 pub fn suggest_modifier(
403 ) -> Option<(char, &'static str)> {
405 Self::X86(r) => r.suggest_modifier(arch, ty),
406 Self::Arm(r) => r.suggest_modifier(arch, ty),
407 Self::AArch64(r) => r.suggest_modifier(arch, ty),
408 Self::RiscV(r) => r.suggest_modifier(arch, ty),
409 Self::Nvptx(r) => r.suggest_modifier(arch, ty),
410 Self::Hexagon(r) => r.suggest_modifier(arch, ty),
411 Self::Mips(r) => r.suggest_modifier(arch, ty),
412 Self::SpirV(r) => r.suggest_modifier(arch, ty),
413 Self::Wasm(r) => r.suggest_modifier(arch, ty),
414 Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
418 /// Returns the default modifier for this register and an example of a
419 /// register named formatted with it.
421 /// This is only needed when the register class can suggest a modifier, so
422 /// that the user can be shown how to get the default behavior without a
424 pub fn default_modifier(self, arch: InlineAsmArch) -> Option<(char, &'static str)> {
426 Self::X86(r) => r.default_modifier(arch),
427 Self::Arm(r) => r.default_modifier(arch),
428 Self::AArch64(r) => r.default_modifier(arch),
429 Self::RiscV(r) => r.default_modifier(arch),
430 Self::Nvptx(r) => r.default_modifier(arch),
431 Self::Hexagon(r) => r.default_modifier(arch),
432 Self::Mips(r) => r.default_modifier(arch),
433 Self::SpirV(r) => r.default_modifier(arch),
434 Self::Wasm(r) => r.default_modifier(arch),
435 Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
439 /// Returns a list of supported types for this register class, each with a
440 /// options target feature required to use this type.
441 pub fn supported_types(
444 ) -> &'static [(InlineAsmType, Option<&'static str>)] {
446 Self::X86(r) => r.supported_types(arch),
447 Self::Arm(r) => r.supported_types(arch),
448 Self::AArch64(r) => r.supported_types(arch),
449 Self::RiscV(r) => r.supported_types(arch),
450 Self::Nvptx(r) => r.supported_types(arch),
451 Self::Hexagon(r) => r.supported_types(arch),
452 Self::Mips(r) => r.supported_types(arch),
453 Self::SpirV(r) => r.supported_types(arch),
454 Self::Wasm(r) => r.supported_types(arch),
455 Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
459 pub fn parse(arch: InlineAsmArch, name: Symbol) -> Result<Self, &'static str> {
461 InlineAsmArch::X86 | InlineAsmArch::X86_64 => {
462 Self::X86(X86InlineAsmRegClass::parse(arch, name)?)
464 InlineAsmArch::Arm => Self::Arm(ArmInlineAsmRegClass::parse(arch, name)?),
465 InlineAsmArch::AArch64 => Self::AArch64(AArch64InlineAsmRegClass::parse(arch, name)?),
466 InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
467 Self::RiscV(RiscVInlineAsmRegClass::parse(arch, name)?)
469 InlineAsmArch::Nvptx64 => Self::Nvptx(NvptxInlineAsmRegClass::parse(arch, name)?),
470 InlineAsmArch::Hexagon => Self::Hexagon(HexagonInlineAsmRegClass::parse(arch, name)?),
471 InlineAsmArch::Mips | InlineAsmArch::Mips64 => {
472 Self::Mips(MipsInlineAsmRegClass::parse(arch, name)?)
474 InlineAsmArch::SpirV => Self::SpirV(SpirVInlineAsmRegClass::parse(arch, name)?),
475 InlineAsmArch::Wasm32 => Self::Wasm(WasmInlineAsmRegClass::parse(arch, name)?),
479 /// Returns the list of template modifiers that can be used with this
481 pub fn valid_modifiers(self, arch: InlineAsmArch) -> &'static [char] {
483 Self::X86(r) => r.valid_modifiers(arch),
484 Self::Arm(r) => r.valid_modifiers(arch),
485 Self::AArch64(r) => r.valid_modifiers(arch),
486 Self::RiscV(r) => r.valid_modifiers(arch),
487 Self::Nvptx(r) => r.valid_modifiers(arch),
488 Self::Hexagon(r) => r.valid_modifiers(arch),
489 Self::Mips(r) => r.valid_modifiers(arch),
490 Self::SpirV(r) => r.valid_modifiers(arch),
491 Self::Wasm(r) => r.valid_modifiers(arch),
492 Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
509 pub enum InlineAsmRegOrRegClass {
511 RegClass(InlineAsmRegClass),
514 impl InlineAsmRegOrRegClass {
515 pub fn reg_class(self) -> InlineAsmRegClass {
517 Self::Reg(r) => r.reg_class(),
518 Self::RegClass(r) => r,
523 impl fmt::Display for InlineAsmRegOrRegClass {
524 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
526 Self::Reg(r) => write!(f, "\"{}\"", r.name()),
527 Self::RegClass(r) => write!(f, "{}", r.name()),
532 /// Set of types which can be used with a particular register class.
533 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
534 pub enum InlineAsmType {
552 pub fn is_integer(self) -> bool {
553 matches!(self, Self::I8 | Self::I16 | Self::I32 | Self::I64 | Self::I128)
556 pub fn size(self) -> Size {
557 Size::from_bytes(match self {
565 Self::VecI8(n) => n * 1,
566 Self::VecI16(n) => n * 2,
567 Self::VecI32(n) => n * 4,
568 Self::VecI64(n) => n * 8,
569 Self::VecI128(n) => n * 16,
570 Self::VecF32(n) => n * 4,
571 Self::VecF64(n) => n * 8,
576 impl fmt::Display for InlineAsmType {
577 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
579 Self::I8 => f.write_str("i8"),
580 Self::I16 => f.write_str("i16"),
581 Self::I32 => f.write_str("i32"),
582 Self::I64 => f.write_str("i64"),
583 Self::I128 => f.write_str("i128"),
584 Self::F32 => f.write_str("f32"),
585 Self::F64 => f.write_str("f64"),
586 Self::VecI8(n) => write!(f, "i8x{}", n),
587 Self::VecI16(n) => write!(f, "i16x{}", n),
588 Self::VecI32(n) => write!(f, "i32x{}", n),
589 Self::VecI64(n) => write!(f, "i64x{}", n),
590 Self::VecI128(n) => write!(f, "i128x{}", n),
591 Self::VecF32(n) => write!(f, "f32x{}", n),
592 Self::VecF64(n) => write!(f, "f64x{}", n),
597 /// Returns the full set of allocatable registers for a given architecture.
599 /// The registers are structured as a map containing the set of allocatable
600 /// registers in each register class. A particular register may be allocatable
601 /// from multiple register classes, in which case it will appear multiple times
603 // NOTE: This function isn't used at the moment, but is needed to support
604 // falling back to an external assembler.
605 pub fn allocatable_registers(
607 has_feature: impl FnMut(&str) -> bool,
608 target: &crate::spec::Target,
609 ) -> FxHashMap<InlineAsmRegClass, FxHashSet<InlineAsmReg>> {
611 InlineAsmArch::X86 | InlineAsmArch::X86_64 => {
612 let mut map = x86::regclass_map();
613 x86::fill_reg_map(arch, has_feature, target, &mut map);
616 InlineAsmArch::Arm => {
617 let mut map = arm::regclass_map();
618 arm::fill_reg_map(arch, has_feature, target, &mut map);
621 InlineAsmArch::AArch64 => {
622 let mut map = aarch64::regclass_map();
623 aarch64::fill_reg_map(arch, has_feature, target, &mut map);
626 InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
627 let mut map = riscv::regclass_map();
628 riscv::fill_reg_map(arch, has_feature, target, &mut map);
631 InlineAsmArch::Nvptx64 => {
632 let mut map = nvptx::regclass_map();
633 nvptx::fill_reg_map(arch, has_feature, target, &mut map);
636 InlineAsmArch::Hexagon => {
637 let mut map = hexagon::regclass_map();
638 hexagon::fill_reg_map(arch, has_feature, target, &mut map);
641 InlineAsmArch::Mips | InlineAsmArch::Mips64 => {
642 let mut map = mips::regclass_map();
643 mips::fill_reg_map(arch, has_feature, target, &mut map);
646 InlineAsmArch::SpirV => {
647 let mut map = spirv::regclass_map();
648 spirv::fill_reg_map(arch, has_feature, target, &mut map);
651 InlineAsmArch::Wasm32 => {
652 let mut map = wasm::regclass_map();
653 wasm::fill_reg_map(arch, has_feature, target, &mut map);