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, false)?;)?
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, true).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),
235 pub fn name(self) -> &'static str {
237 Self::X86(r) => r.name(),
238 Self::Arm(r) => r.name(),
239 Self::AArch64(r) => r.name(),
240 Self::RiscV(r) => r.name(),
241 Self::Hexagon(r) => r.name(),
242 Self::Mips(r) => r.name(),
246 pub fn reg_class(self) -> InlineAsmRegClass {
248 Self::X86(r) => InlineAsmRegClass::X86(r.reg_class()),
249 Self::Arm(r) => InlineAsmRegClass::Arm(r.reg_class()),
250 Self::AArch64(r) => InlineAsmRegClass::AArch64(r.reg_class()),
251 Self::RiscV(r) => InlineAsmRegClass::RiscV(r.reg_class()),
252 Self::Hexagon(r) => InlineAsmRegClass::Hexagon(r.reg_class()),
253 Self::Mips(r) => InlineAsmRegClass::Mips(r.reg_class()),
259 has_feature: impl FnMut(&str) -> bool,
262 ) -> Result<Self, &'static str> {
263 // FIXME: use direct symbol comparison for register names
264 // Use `Symbol::as_str` instead of `Symbol::with` here because `has_feature` may access `Symbol`.
265 let name = name.as_str();
267 InlineAsmArch::X86 | InlineAsmArch::X86_64 => {
268 Self::X86(X86InlineAsmReg::parse(arch, has_feature, target, &name)?)
270 InlineAsmArch::Arm => {
271 Self::Arm(ArmInlineAsmReg::parse(arch, has_feature, target, &name)?)
273 InlineAsmArch::AArch64 => {
274 Self::AArch64(AArch64InlineAsmReg::parse(arch, has_feature, target, &name)?)
276 InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
277 Self::RiscV(RiscVInlineAsmReg::parse(arch, has_feature, target, &name)?)
279 InlineAsmArch::Nvptx64 => {
280 Self::Nvptx(NvptxInlineAsmReg::parse(arch, has_feature, target, &name)?)
282 InlineAsmArch::Hexagon => {
283 Self::Hexagon(HexagonInlineAsmReg::parse(arch, has_feature, target, &name)?)
285 InlineAsmArch::Mips | InlineAsmArch::Mips64 => {
286 Self::Mips(MipsInlineAsmReg::parse(arch, has_feature, target, &name)?)
288 InlineAsmArch::SpirV => {
289 Self::SpirV(SpirVInlineAsmReg::parse(arch, has_feature, target, &name)?)
291 InlineAsmArch::Wasm32 => {
292 Self::Wasm(WasmInlineAsmReg::parse(arch, has_feature, target, &name)?)
297 // NOTE: This function isn't used at the moment, but is needed to support
298 // falling back to an external assembler.
301 out: &mut dyn fmt::Write,
303 modifier: Option<char>,
306 Self::X86(r) => r.emit(out, arch, modifier),
307 Self::Arm(r) => r.emit(out, arch, modifier),
308 Self::AArch64(r) => r.emit(out, arch, modifier),
309 Self::RiscV(r) => r.emit(out, arch, modifier),
310 Self::Hexagon(r) => r.emit(out, arch, modifier),
311 Self::Mips(r) => r.emit(out, arch, modifier),
315 pub fn overlapping_regs(self, mut cb: impl FnMut(InlineAsmReg)) {
317 Self::X86(r) => r.overlapping_regs(|r| cb(Self::X86(r))),
318 Self::Arm(r) => r.overlapping_regs(|r| cb(Self::Arm(r))),
319 Self::AArch64(_) => cb(self),
320 Self::RiscV(_) => cb(self),
321 Self::Hexagon(r) => r.overlapping_regs(|r| cb(Self::Hexagon(r))),
322 Self::Mips(_) => cb(self),
339 pub enum InlineAsmRegClass {
340 X86(X86InlineAsmRegClass),
341 Arm(ArmInlineAsmRegClass),
342 AArch64(AArch64InlineAsmRegClass),
343 RiscV(RiscVInlineAsmRegClass),
344 Nvptx(NvptxInlineAsmRegClass),
345 Hexagon(HexagonInlineAsmRegClass),
346 Mips(MipsInlineAsmRegClass),
347 SpirV(SpirVInlineAsmRegClass),
348 Wasm(WasmInlineAsmRegClass),
351 impl InlineAsmRegClass {
352 pub fn name(self) -> Symbol {
354 Self::X86(r) => r.name(),
355 Self::Arm(r) => r.name(),
356 Self::AArch64(r) => r.name(),
357 Self::RiscV(r) => r.name(),
358 Self::Nvptx(r) => r.name(),
359 Self::Hexagon(r) => r.name(),
360 Self::Mips(r) => r.name(),
361 Self::SpirV(r) => r.name(),
362 Self::Wasm(r) => r.name(),
366 /// Returns a suggested register class to use for this type. This is called
367 /// after type checking via `supported_types` fails to give a better error
368 /// message to the user.
369 pub fn suggest_class(self, arch: InlineAsmArch, ty: InlineAsmType) -> Option<Self> {
371 Self::X86(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::X86),
372 Self::Arm(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Arm),
373 Self::AArch64(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::AArch64),
374 Self::RiscV(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::RiscV),
375 Self::Nvptx(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Nvptx),
376 Self::Hexagon(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Hexagon),
377 Self::Mips(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Mips),
378 Self::SpirV(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::SpirV),
379 Self::Wasm(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Wasm),
383 /// Returns a suggested template modifier to use for this type and an
384 /// example of a register named formatted with it.
386 /// Such suggestions are useful if a type smaller than the full register
387 /// size is used and a modifier can be used to point to the subregister of
388 /// the correct size.
389 pub fn suggest_modifier(
393 ) -> Option<(char, &'static str)> {
395 Self::X86(r) => r.suggest_modifier(arch, ty),
396 Self::Arm(r) => r.suggest_modifier(arch, ty),
397 Self::AArch64(r) => r.suggest_modifier(arch, ty),
398 Self::RiscV(r) => r.suggest_modifier(arch, ty),
399 Self::Nvptx(r) => r.suggest_modifier(arch, ty),
400 Self::Hexagon(r) => r.suggest_modifier(arch, ty),
401 Self::Mips(r) => r.suggest_modifier(arch, ty),
402 Self::SpirV(r) => r.suggest_modifier(arch, ty),
403 Self::Wasm(r) => r.suggest_modifier(arch, ty),
407 /// Returns the default modifier for this register and an example of a
408 /// register named formatted with it.
410 /// This is only needed when the register class can suggest a modifier, so
411 /// that the user can be shown how to get the default behavior without a
413 pub fn default_modifier(self, arch: InlineAsmArch) -> Option<(char, &'static str)> {
415 Self::X86(r) => r.default_modifier(arch),
416 Self::Arm(r) => r.default_modifier(arch),
417 Self::AArch64(r) => r.default_modifier(arch),
418 Self::RiscV(r) => r.default_modifier(arch),
419 Self::Nvptx(r) => r.default_modifier(arch),
420 Self::Hexagon(r) => r.default_modifier(arch),
421 Self::Mips(r) => r.default_modifier(arch),
422 Self::SpirV(r) => r.default_modifier(arch),
423 Self::Wasm(r) => r.default_modifier(arch),
427 /// Returns a list of supported types for this register class, each with a
428 /// options target feature required to use this type.
429 pub fn supported_types(
432 ) -> &'static [(InlineAsmType, Option<&'static str>)] {
434 Self::X86(r) => r.supported_types(arch),
435 Self::Arm(r) => r.supported_types(arch),
436 Self::AArch64(r) => r.supported_types(arch),
437 Self::RiscV(r) => r.supported_types(arch),
438 Self::Nvptx(r) => r.supported_types(arch),
439 Self::Hexagon(r) => r.supported_types(arch),
440 Self::Mips(r) => r.supported_types(arch),
441 Self::SpirV(r) => r.supported_types(arch),
442 Self::Wasm(r) => r.supported_types(arch),
446 pub fn parse(arch: InlineAsmArch, name: Symbol) -> Result<Self, &'static str> {
448 InlineAsmArch::X86 | InlineAsmArch::X86_64 => {
449 Self::X86(X86InlineAsmRegClass::parse(arch, name)?)
451 InlineAsmArch::Arm => Self::Arm(ArmInlineAsmRegClass::parse(arch, name)?),
452 InlineAsmArch::AArch64 => Self::AArch64(AArch64InlineAsmRegClass::parse(arch, name)?),
453 InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
454 Self::RiscV(RiscVInlineAsmRegClass::parse(arch, name)?)
456 InlineAsmArch::Nvptx64 => Self::Nvptx(NvptxInlineAsmRegClass::parse(arch, name)?),
457 InlineAsmArch::Hexagon => Self::Hexagon(HexagonInlineAsmRegClass::parse(arch, name)?),
458 InlineAsmArch::Mips | InlineAsmArch::Mips64 => {
459 Self::Mips(MipsInlineAsmRegClass::parse(arch, name)?)
461 InlineAsmArch::SpirV => Self::SpirV(SpirVInlineAsmRegClass::parse(arch, name)?),
462 InlineAsmArch::Wasm32 => Self::Wasm(WasmInlineAsmRegClass::parse(arch, name)?),
466 /// Returns the list of template modifiers that can be used with this
468 pub fn valid_modifiers(self, arch: InlineAsmArch) -> &'static [char] {
470 Self::X86(r) => r.valid_modifiers(arch),
471 Self::Arm(r) => r.valid_modifiers(arch),
472 Self::AArch64(r) => r.valid_modifiers(arch),
473 Self::RiscV(r) => r.valid_modifiers(arch),
474 Self::Nvptx(r) => r.valid_modifiers(arch),
475 Self::Hexagon(r) => r.valid_modifiers(arch),
476 Self::Mips(r) => r.valid_modifiers(arch),
477 Self::SpirV(r) => r.valid_modifiers(arch),
478 Self::Wasm(r) => r.valid_modifiers(arch),
495 pub enum InlineAsmRegOrRegClass {
497 RegClass(InlineAsmRegClass),
500 impl InlineAsmRegOrRegClass {
501 pub fn reg_class(self) -> InlineAsmRegClass {
503 Self::Reg(r) => r.reg_class(),
504 Self::RegClass(r) => r,
509 impl fmt::Display for InlineAsmRegOrRegClass {
510 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
512 Self::Reg(r) => write!(f, "\"{}\"", r.name()),
513 Self::RegClass(r) => write!(f, "{}", r.name()),
518 /// Set of types which can be used with a particular register class.
519 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
520 pub enum InlineAsmType {
538 pub fn is_integer(self) -> bool {
539 matches!(self, Self::I8 | Self::I16 | Self::I32 | Self::I64 | Self::I128)
542 pub fn size(self) -> Size {
543 Size::from_bytes(match self {
551 Self::VecI8(n) => n * 1,
552 Self::VecI16(n) => n * 2,
553 Self::VecI32(n) => n * 4,
554 Self::VecI64(n) => n * 8,
555 Self::VecI128(n) => n * 16,
556 Self::VecF32(n) => n * 4,
557 Self::VecF64(n) => n * 8,
562 impl fmt::Display for InlineAsmType {
563 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
565 Self::I8 => f.write_str("i8"),
566 Self::I16 => f.write_str("i16"),
567 Self::I32 => f.write_str("i32"),
568 Self::I64 => f.write_str("i64"),
569 Self::I128 => f.write_str("i128"),
570 Self::F32 => f.write_str("f32"),
571 Self::F64 => f.write_str("f64"),
572 Self::VecI8(n) => write!(f, "i8x{}", n),
573 Self::VecI16(n) => write!(f, "i16x{}", n),
574 Self::VecI32(n) => write!(f, "i32x{}", n),
575 Self::VecI64(n) => write!(f, "i64x{}", n),
576 Self::VecI128(n) => write!(f, "i128x{}", n),
577 Self::VecF32(n) => write!(f, "f32x{}", n),
578 Self::VecF64(n) => write!(f, "f64x{}", n),
583 /// Returns the full set of allocatable registers for a given architecture.
585 /// The registers are structured as a map containing the set of allocatable
586 /// registers in each register class. A particular register may be allocatable
587 /// from multiple register classes, in which case it will appear multiple times
589 // NOTE: This function isn't used at the moment, but is needed to support
590 // falling back to an external assembler.
591 pub fn allocatable_registers(
593 has_feature: impl FnMut(&str) -> bool,
594 target: &crate::spec::Target,
595 ) -> FxHashMap<InlineAsmRegClass, FxHashSet<InlineAsmReg>> {
597 InlineAsmArch::X86 | InlineAsmArch::X86_64 => {
598 let mut map = x86::regclass_map();
599 x86::fill_reg_map(arch, has_feature, target, &mut map);
602 InlineAsmArch::Arm => {
603 let mut map = arm::regclass_map();
604 arm::fill_reg_map(arch, has_feature, target, &mut map);
607 InlineAsmArch::AArch64 => {
608 let mut map = aarch64::regclass_map();
609 aarch64::fill_reg_map(arch, has_feature, target, &mut map);
612 InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
613 let mut map = riscv::regclass_map();
614 riscv::fill_reg_map(arch, has_feature, target, &mut map);
617 InlineAsmArch::Nvptx64 => {
618 let mut map = nvptx::regclass_map();
619 nvptx::fill_reg_map(arch, has_feature, target, &mut map);
622 InlineAsmArch::Hexagon => {
623 let mut map = hexagon::regclass_map();
624 hexagon::fill_reg_map(arch, has_feature, target, &mut map);
627 InlineAsmArch::Mips | InlineAsmArch::Mips64 => {
628 let mut map = mips::regclass_map();
629 mips::fill_reg_map(arch, has_feature, target, &mut map);
632 InlineAsmArch::SpirV => {
633 let mut map = spirv::regclass_map();
634 spirv::fill_reg_map(arch, has_feature, target, &mut map);
637 InlineAsmArch::Wasm32 => {
638 let mut map = wasm::regclass_map();
639 wasm::fill_reg_map(arch, has_feature, target, &mut map);