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, RustcEncodable, RustcDecodable, Debug, Eq, PartialEq, Hash, HashStable_Generic)]
17 #[allow(non_camel_case_types)]
18 pub enum $arch_regclass {
23 pub fn name(self) -> &'static str {
25 $(Self::$class => stringify!($class),)*
29 pub fn parse(_arch: super::InlineAsmArch, name: &str) -> Result<Self, &'static str> {
32 stringify!($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, RustcEncodable, RustcDecodable, Debug, Eq, PartialEq, 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)),
159 pub use aarch64::{AArch64InlineAsmReg, AArch64InlineAsmRegClass};
160 pub use arm::{ArmInlineAsmReg, ArmInlineAsmRegClass};
161 pub use hexagon::{HexagonInlineAsmReg, HexagonInlineAsmRegClass};
162 pub use nvptx::{NvptxInlineAsmReg, NvptxInlineAsmRegClass};
163 pub use riscv::{RiscVInlineAsmReg, RiscVInlineAsmRegClass};
164 pub use x86::{X86InlineAsmReg, X86InlineAsmRegClass};
166 #[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug, Eq, PartialEq, Hash)]
167 pub enum InlineAsmArch {
178 impl FromStr for InlineAsmArch {
181 fn from_str(s: &str) -> Result<InlineAsmArch, ()> {
183 "x86" => Ok(Self::X86),
184 "x86_64" => Ok(Self::X86_64),
185 "arm" => Ok(Self::Arm),
186 "aarch64" => Ok(Self::AArch64),
187 "riscv32" => Ok(Self::RiscV32),
188 "riscv64" => Ok(Self::RiscV64),
189 "nvptx64" => Ok(Self::Nvptx64),
190 "hexagon" => Ok(Self::Hexagon),
207 pub enum InlineAsmReg {
208 X86(X86InlineAsmReg),
209 Arm(ArmInlineAsmReg),
210 AArch64(AArch64InlineAsmReg),
211 RiscV(RiscVInlineAsmReg),
212 Nvptx(NvptxInlineAsmReg),
213 Hexagon(HexagonInlineAsmReg),
217 pub fn name(self) -> &'static str {
219 Self::X86(r) => r.name(),
220 Self::Arm(r) => r.name(),
221 Self::AArch64(r) => r.name(),
222 Self::RiscV(r) => r.name(),
223 Self::Hexagon(r) => r.name(),
227 pub fn reg_class(self) -> InlineAsmRegClass {
229 Self::X86(r) => InlineAsmRegClass::X86(r.reg_class()),
230 Self::Arm(r) => InlineAsmRegClass::Arm(r.reg_class()),
231 Self::AArch64(r) => InlineAsmRegClass::AArch64(r.reg_class()),
232 Self::RiscV(r) => InlineAsmRegClass::RiscV(r.reg_class()),
233 Self::Hexagon(r) => InlineAsmRegClass::Hexagon(r.reg_class()),
239 has_feature: impl FnMut(&str) -> bool,
242 ) -> Result<Self, &'static str> {
243 // FIXME: use direct symbol comparison for register names
244 // Use `Symbol::as_str` instead of `Symbol::with` here because `has_feature` may access `Symbol`.
245 let name = name.as_str();
247 InlineAsmArch::X86 | InlineAsmArch::X86_64 => {
248 Self::X86(X86InlineAsmReg::parse(arch, has_feature, target, &name)?)
250 InlineAsmArch::Arm => {
251 Self::Arm(ArmInlineAsmReg::parse(arch, has_feature, target, &name)?)
253 InlineAsmArch::AArch64 => {
254 Self::AArch64(AArch64InlineAsmReg::parse(arch, has_feature, target, &name)?)
256 InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
257 Self::RiscV(RiscVInlineAsmReg::parse(arch, has_feature, target, &name)?)
259 InlineAsmArch::Nvptx64 => {
260 Self::Nvptx(NvptxInlineAsmReg::parse(arch, has_feature, target, &name)?)
262 InlineAsmArch::Hexagon => {
263 Self::Hexagon(HexagonInlineAsmReg::parse(arch, has_feature, target, &name)?)
268 // NOTE: This function isn't used at the moment, but is needed to support
269 // falling back to an external assembler.
272 out: &mut dyn fmt::Write,
274 modifier: Option<char>,
277 Self::X86(r) => r.emit(out, arch, modifier),
278 Self::Arm(r) => r.emit(out, arch, modifier),
279 Self::AArch64(r) => r.emit(out, arch, modifier),
280 Self::RiscV(r) => r.emit(out, arch, modifier),
281 Self::Hexagon(r) => r.emit(out, arch, modifier),
285 pub fn overlapping_regs(self, mut cb: impl FnMut(InlineAsmReg)) {
287 Self::X86(r) => r.overlapping_regs(|r| cb(Self::X86(r))),
288 Self::Arm(r) => r.overlapping_regs(|r| cb(Self::Arm(r))),
289 Self::AArch64(_) => cb(self),
290 Self::RiscV(_) => cb(self),
291 Self::Hexagon(r) => r.overlapping_regs(|r| cb(Self::Hexagon(r))),
307 pub enum InlineAsmRegClass {
308 X86(X86InlineAsmRegClass),
309 Arm(ArmInlineAsmRegClass),
310 AArch64(AArch64InlineAsmRegClass),
311 RiscV(RiscVInlineAsmRegClass),
312 Nvptx(NvptxInlineAsmRegClass),
313 Hexagon(HexagonInlineAsmRegClass),
316 impl InlineAsmRegClass {
317 pub fn name(self) -> &'static str {
319 Self::X86(r) => r.name(),
320 Self::Arm(r) => r.name(),
321 Self::AArch64(r) => r.name(),
322 Self::RiscV(r) => r.name(),
323 Self::Nvptx(r) => r.name(),
324 Self::Hexagon(r) => r.name(),
328 /// Returns a suggested register class to use for this type. This is called
329 /// after type checking via `supported_types` fails to give a better error
330 /// message to the user.
331 pub fn suggest_class(self, arch: InlineAsmArch, ty: InlineAsmType) -> Option<Self> {
333 Self::X86(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::X86),
334 Self::Arm(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Arm),
335 Self::AArch64(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::AArch64),
336 Self::RiscV(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::RiscV),
337 Self::Nvptx(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Nvptx),
338 Self::Hexagon(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Hexagon),
342 /// Returns a suggested template modifier to use for this type and an
343 /// example of a register named formatted with it.
345 /// Such suggestions are useful if a type smaller than the full register
346 /// size is used and a modifier can be used to point to the subregister of
347 /// the correct size.
348 pub fn suggest_modifier(
352 ) -> Option<(char, &'static str)> {
354 Self::X86(r) => r.suggest_modifier(arch, ty),
355 Self::Arm(r) => r.suggest_modifier(arch, ty),
356 Self::AArch64(r) => r.suggest_modifier(arch, ty),
357 Self::RiscV(r) => r.suggest_modifier(arch, ty),
358 Self::Nvptx(r) => r.suggest_modifier(arch, ty),
359 Self::Hexagon(r) => r.suggest_modifier(arch, ty),
363 /// Returns the default modifier for this register and an example of a
364 /// register named formatted with it.
366 /// This is only needed when the register class can suggest a modifier, so
367 /// that the user can be shown how to get the default behavior without a
369 pub fn default_modifier(self, arch: InlineAsmArch) -> Option<(char, &'static str)> {
371 Self::X86(r) => r.default_modifier(arch),
372 Self::Arm(r) => r.default_modifier(arch),
373 Self::AArch64(r) => r.default_modifier(arch),
374 Self::RiscV(r) => r.default_modifier(arch),
375 Self::Nvptx(r) => r.default_modifier(arch),
376 Self::Hexagon(r) => r.default_modifier(arch),
380 /// Returns a list of supported types for this register class, each with a
381 /// options target feature required to use this type.
382 pub fn supported_types(
385 ) -> &'static [(InlineAsmType, Option<&'static str>)] {
387 Self::X86(r) => r.supported_types(arch),
388 Self::Arm(r) => r.supported_types(arch),
389 Self::AArch64(r) => r.supported_types(arch),
390 Self::RiscV(r) => r.supported_types(arch),
391 Self::Nvptx(r) => r.supported_types(arch),
392 Self::Hexagon(r) => r.supported_types(arch),
396 pub fn parse(arch: InlineAsmArch, name: Symbol) -> Result<Self, &'static str> {
397 // FIXME: use direct symbol comparison for register class names
400 InlineAsmArch::X86 | InlineAsmArch::X86_64 => {
401 Self::X86(X86InlineAsmRegClass::parse(arch, name)?)
403 InlineAsmArch::Arm => Self::Arm(ArmInlineAsmRegClass::parse(arch, name)?),
404 InlineAsmArch::AArch64 => {
405 Self::AArch64(AArch64InlineAsmRegClass::parse(arch, name)?)
407 InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
408 Self::RiscV(RiscVInlineAsmRegClass::parse(arch, name)?)
410 InlineAsmArch::Nvptx64 => Self::Nvptx(NvptxInlineAsmRegClass::parse(arch, name)?),
411 InlineAsmArch::Hexagon => {
412 Self::Hexagon(HexagonInlineAsmRegClass::parse(arch, name)?)
418 /// Returns the list of template modifiers that can be used with this
420 pub fn valid_modifiers(self, arch: InlineAsmArch) -> &'static [char] {
422 Self::X86(r) => r.valid_modifiers(arch),
423 Self::Arm(r) => r.valid_modifiers(arch),
424 Self::AArch64(r) => r.valid_modifiers(arch),
425 Self::RiscV(r) => r.valid_modifiers(arch),
426 Self::Nvptx(r) => r.valid_modifiers(arch),
427 Self::Hexagon(r) => r.valid_modifiers(arch),
443 pub enum InlineAsmRegOrRegClass {
445 RegClass(InlineAsmRegClass),
448 impl InlineAsmRegOrRegClass {
449 pub fn reg_class(self) -> InlineAsmRegClass {
451 Self::Reg(r) => r.reg_class(),
452 Self::RegClass(r) => r,
457 impl fmt::Display for InlineAsmRegOrRegClass {
458 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
460 Self::Reg(r) => write!(f, "\"{}\"", r.name()),
461 Self::RegClass(r) => f.write_str(r.name()),
466 /// Set of types which can be used with a particular register class.
467 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
468 pub enum InlineAsmType {
486 pub fn is_integer(self) -> bool {
488 Self::I8 | Self::I16 | Self::I32 | Self::I64 | Self::I128 => true,
493 pub fn size(self) -> Size {
494 Size::from_bytes(match self {
502 Self::VecI8(n) => n * 1,
503 Self::VecI16(n) => n * 2,
504 Self::VecI32(n) => n * 4,
505 Self::VecI64(n) => n * 8,
506 Self::VecI128(n) => n * 16,
507 Self::VecF32(n) => n * 4,
508 Self::VecF64(n) => n * 8,
513 impl fmt::Display for InlineAsmType {
514 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
516 Self::I8 => f.write_str("i8"),
517 Self::I16 => f.write_str("i16"),
518 Self::I32 => f.write_str("i32"),
519 Self::I64 => f.write_str("i64"),
520 Self::I128 => f.write_str("i128"),
521 Self::F32 => f.write_str("f32"),
522 Self::F64 => f.write_str("f64"),
523 Self::VecI8(n) => write!(f, "i8x{}", n),
524 Self::VecI16(n) => write!(f, "i16x{}", n),
525 Self::VecI32(n) => write!(f, "i32x{}", n),
526 Self::VecI64(n) => write!(f, "i64x{}", n),
527 Self::VecI128(n) => write!(f, "i128x{}", n),
528 Self::VecF32(n) => write!(f, "f32x{}", n),
529 Self::VecF64(n) => write!(f, "f64x{}", n),
534 /// Returns the full set of allocatable registers for a given architecture.
536 /// The registers are structured as a map containing the set of allocatable
537 /// registers in each register class. A particular register may be allocatable
538 /// from multiple register classes, in which case it will appear multiple times
540 // NOTE: This function isn't used at the moment, but is needed to support
541 // falling back to an external assembler.
542 pub fn allocatable_registers(
544 has_feature: impl FnMut(&str) -> bool,
545 target: &crate::spec::Target,
546 ) -> FxHashMap<InlineAsmRegClass, FxHashSet<InlineAsmReg>> {
548 InlineAsmArch::X86 | InlineAsmArch::X86_64 => {
549 let mut map = x86::regclass_map();
550 x86::fill_reg_map(arch, has_feature, target, &mut map);
553 InlineAsmArch::Arm => {
554 let mut map = arm::regclass_map();
555 arm::fill_reg_map(arch, has_feature, target, &mut map);
558 InlineAsmArch::AArch64 => {
559 let mut map = aarch64::regclass_map();
560 aarch64::fill_reg_map(arch, has_feature, target, &mut map);
563 InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
564 let mut map = riscv::regclass_map();
565 riscv::fill_reg_map(arch, has_feature, target, &mut map);
568 InlineAsmArch::Nvptx64 => {
569 let mut map = nvptx::regclass_map();
570 nvptx::fill_reg_map(arch, has_feature, target, &mut map);
573 InlineAsmArch::Hexagon => {
574 let mut map = hexagon::regclass_map();
575 hexagon::fill_reg_map(arch, has_feature, target, &mut map);