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, 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, Encodable, Decodable, 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, Encodable, Decodable, 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),
196 #[derive(Copy, Clone, Encodable, Decodable, Debug, Eq, PartialEq, Hash, HashStable_Generic)]
197 pub enum InlineAsmReg {
198 X86(X86InlineAsmReg),
199 Arm(ArmInlineAsmReg),
200 AArch64(AArch64InlineAsmReg),
201 RiscV(RiscVInlineAsmReg),
202 Nvptx(NvptxInlineAsmReg),
203 Hexagon(HexagonInlineAsmReg),
207 pub fn name(self) -> &'static str {
209 Self::X86(r) => r.name(),
210 Self::Arm(r) => r.name(),
211 Self::AArch64(r) => r.name(),
212 Self::RiscV(r) => r.name(),
213 Self::Hexagon(r) => r.name(),
217 pub fn reg_class(self) -> InlineAsmRegClass {
219 Self::X86(r) => InlineAsmRegClass::X86(r.reg_class()),
220 Self::Arm(r) => InlineAsmRegClass::Arm(r.reg_class()),
221 Self::AArch64(r) => InlineAsmRegClass::AArch64(r.reg_class()),
222 Self::RiscV(r) => InlineAsmRegClass::RiscV(r.reg_class()),
223 Self::Hexagon(r) => InlineAsmRegClass::Hexagon(r.reg_class()),
229 has_feature: impl FnMut(&str) -> bool,
232 ) -> Result<Self, &'static str> {
233 // FIXME: use direct symbol comparison for register names
234 // Use `Symbol::as_str` instead of `Symbol::with` here because `has_feature` may access `Symbol`.
235 let name = name.as_str();
237 InlineAsmArch::X86 | InlineAsmArch::X86_64 => {
238 Self::X86(X86InlineAsmReg::parse(arch, has_feature, target, &name)?)
240 InlineAsmArch::Arm => {
241 Self::Arm(ArmInlineAsmReg::parse(arch, has_feature, target, &name)?)
243 InlineAsmArch::AArch64 => {
244 Self::AArch64(AArch64InlineAsmReg::parse(arch, has_feature, target, &name)?)
246 InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
247 Self::RiscV(RiscVInlineAsmReg::parse(arch, has_feature, target, &name)?)
249 InlineAsmArch::Nvptx64 => {
250 Self::Nvptx(NvptxInlineAsmReg::parse(arch, has_feature, target, &name)?)
252 InlineAsmArch::Hexagon => {
253 Self::Hexagon(HexagonInlineAsmReg::parse(arch, has_feature, target, &name)?)
258 // NOTE: This function isn't used at the moment, but is needed to support
259 // falling back to an external assembler.
262 out: &mut dyn fmt::Write,
264 modifier: Option<char>,
267 Self::X86(r) => r.emit(out, arch, modifier),
268 Self::Arm(r) => r.emit(out, arch, modifier),
269 Self::AArch64(r) => r.emit(out, arch, modifier),
270 Self::RiscV(r) => r.emit(out, arch, modifier),
271 Self::Hexagon(r) => r.emit(out, arch, modifier),
275 pub fn overlapping_regs(self, mut cb: impl FnMut(InlineAsmReg)) {
277 Self::X86(r) => r.overlapping_regs(|r| cb(Self::X86(r))),
278 Self::Arm(r) => r.overlapping_regs(|r| cb(Self::Arm(r))),
279 Self::AArch64(_) => cb(self),
280 Self::RiscV(_) => cb(self),
281 Self::Hexagon(r) => r.overlapping_regs(|r| cb(Self::Hexagon(r))),
286 #[derive(Copy, Clone, Encodable, Decodable, Debug, Eq, PartialEq, Hash, HashStable_Generic)]
287 pub enum InlineAsmRegClass {
288 X86(X86InlineAsmRegClass),
289 Arm(ArmInlineAsmRegClass),
290 AArch64(AArch64InlineAsmRegClass),
291 RiscV(RiscVInlineAsmRegClass),
292 Nvptx(NvptxInlineAsmRegClass),
293 Hexagon(HexagonInlineAsmRegClass),
296 impl InlineAsmRegClass {
297 pub fn name(self) -> &'static str {
299 Self::X86(r) => r.name(),
300 Self::Arm(r) => r.name(),
301 Self::AArch64(r) => r.name(),
302 Self::RiscV(r) => r.name(),
303 Self::Nvptx(r) => r.name(),
304 Self::Hexagon(r) => r.name(),
308 /// Returns a suggested register class to use for this type. This is called
309 /// after type checking via `supported_types` fails to give a better error
310 /// message to the user.
311 pub fn suggest_class(self, arch: InlineAsmArch, ty: InlineAsmType) -> Option<Self> {
313 Self::X86(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::X86),
314 Self::Arm(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Arm),
315 Self::AArch64(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::AArch64),
316 Self::RiscV(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::RiscV),
317 Self::Nvptx(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Nvptx),
318 Self::Hexagon(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Hexagon),
322 /// Returns a suggested template modifier to use for this type and an
323 /// example of a register named formatted with it.
325 /// Such suggestions are useful if a type smaller than the full register
326 /// size is used and a modifier can be used to point to the subregister of
327 /// the correct size.
328 pub fn suggest_modifier(
332 ) -> Option<(char, &'static str)> {
334 Self::X86(r) => r.suggest_modifier(arch, ty),
335 Self::Arm(r) => r.suggest_modifier(arch, ty),
336 Self::AArch64(r) => r.suggest_modifier(arch, ty),
337 Self::RiscV(r) => r.suggest_modifier(arch, ty),
338 Self::Nvptx(r) => r.suggest_modifier(arch, ty),
339 Self::Hexagon(r) => r.suggest_modifier(arch, ty),
343 /// Returns the default modifier for this register and an example of a
344 /// register named formatted with it.
346 /// This is only needed when the register class can suggest a modifier, so
347 /// that the user can be shown how to get the default behavior without a
349 pub fn default_modifier(self, arch: InlineAsmArch) -> Option<(char, &'static str)> {
351 Self::X86(r) => r.default_modifier(arch),
352 Self::Arm(r) => r.default_modifier(arch),
353 Self::AArch64(r) => r.default_modifier(arch),
354 Self::RiscV(r) => r.default_modifier(arch),
355 Self::Nvptx(r) => r.default_modifier(arch),
356 Self::Hexagon(r) => r.default_modifier(arch),
360 /// Returns a list of supported types for this register class, each with a
361 /// options target feature required to use this type.
362 pub fn supported_types(
365 ) -> &'static [(InlineAsmType, Option<&'static str>)] {
367 Self::X86(r) => r.supported_types(arch),
368 Self::Arm(r) => r.supported_types(arch),
369 Self::AArch64(r) => r.supported_types(arch),
370 Self::RiscV(r) => r.supported_types(arch),
371 Self::Nvptx(r) => r.supported_types(arch),
372 Self::Hexagon(r) => r.supported_types(arch),
376 pub fn parse(arch: InlineAsmArch, name: Symbol) -> Result<Self, &'static str> {
377 // FIXME: use direct symbol comparison for register class names
380 InlineAsmArch::X86 | InlineAsmArch::X86_64 => {
381 Self::X86(X86InlineAsmRegClass::parse(arch, name)?)
383 InlineAsmArch::Arm => Self::Arm(ArmInlineAsmRegClass::parse(arch, name)?),
384 InlineAsmArch::AArch64 => {
385 Self::AArch64(AArch64InlineAsmRegClass::parse(arch, name)?)
387 InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
388 Self::RiscV(RiscVInlineAsmRegClass::parse(arch, name)?)
390 InlineAsmArch::Nvptx64 => Self::Nvptx(NvptxInlineAsmRegClass::parse(arch, name)?),
391 InlineAsmArch::Hexagon => {
392 Self::Hexagon(HexagonInlineAsmRegClass::parse(arch, name)?)
398 /// Returns the list of template modifiers that can be used with this
400 pub fn valid_modifiers(self, arch: InlineAsmArch) -> &'static [char] {
402 Self::X86(r) => r.valid_modifiers(arch),
403 Self::Arm(r) => r.valid_modifiers(arch),
404 Self::AArch64(r) => r.valid_modifiers(arch),
405 Self::RiscV(r) => r.valid_modifiers(arch),
406 Self::Nvptx(r) => r.valid_modifiers(arch),
407 Self::Hexagon(r) => r.valid_modifiers(arch),
412 #[derive(Copy, Clone, Encodable, Decodable, Debug, Eq, PartialEq, Hash, HashStable_Generic)]
413 pub enum InlineAsmRegOrRegClass {
415 RegClass(InlineAsmRegClass),
418 impl InlineAsmRegOrRegClass {
419 pub fn reg_class(self) -> InlineAsmRegClass {
421 Self::Reg(r) => r.reg_class(),
422 Self::RegClass(r) => r,
427 impl fmt::Display for InlineAsmRegOrRegClass {
428 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
430 Self::Reg(r) => write!(f, "\"{}\"", r.name()),
431 Self::RegClass(r) => f.write_str(r.name()),
436 /// Set of types which can be used with a particular register class.
437 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
438 pub enum InlineAsmType {
456 pub fn is_integer(self) -> bool {
458 Self::I8 | Self::I16 | Self::I32 | Self::I64 | Self::I128 => true,
463 pub fn size(self) -> Size {
464 Size::from_bytes(match self {
472 Self::VecI8(n) => n * 1,
473 Self::VecI16(n) => n * 2,
474 Self::VecI32(n) => n * 4,
475 Self::VecI64(n) => n * 8,
476 Self::VecI128(n) => n * 16,
477 Self::VecF32(n) => n * 4,
478 Self::VecF64(n) => n * 8,
483 impl fmt::Display for InlineAsmType {
484 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
486 Self::I8 => f.write_str("i8"),
487 Self::I16 => f.write_str("i16"),
488 Self::I32 => f.write_str("i32"),
489 Self::I64 => f.write_str("i64"),
490 Self::I128 => f.write_str("i128"),
491 Self::F32 => f.write_str("f32"),
492 Self::F64 => f.write_str("f64"),
493 Self::VecI8(n) => write!(f, "i8x{}", n),
494 Self::VecI16(n) => write!(f, "i16x{}", n),
495 Self::VecI32(n) => write!(f, "i32x{}", n),
496 Self::VecI64(n) => write!(f, "i64x{}", n),
497 Self::VecI128(n) => write!(f, "i128x{}", n),
498 Self::VecF32(n) => write!(f, "f32x{}", n),
499 Self::VecF64(n) => write!(f, "f64x{}", n),
504 /// Returns the full set of allocatable registers for a given architecture.
506 /// The registers are structured as a map containing the set of allocatable
507 /// registers in each register class. A particular register may be allocatable
508 /// from multiple register classes, in which case it will appear multiple times
510 // NOTE: This function isn't used at the moment, but is needed to support
511 // falling back to an external assembler.
512 pub fn allocatable_registers(
514 has_feature: impl FnMut(&str) -> bool,
515 target: &crate::spec::Target,
516 ) -> FxHashMap<InlineAsmRegClass, FxHashSet<InlineAsmReg>> {
518 InlineAsmArch::X86 | InlineAsmArch::X86_64 => {
519 let mut map = x86::regclass_map();
520 x86::fill_reg_map(arch, has_feature, target, &mut map);
523 InlineAsmArch::Arm => {
524 let mut map = arm::regclass_map();
525 arm::fill_reg_map(arch, has_feature, target, &mut map);
528 InlineAsmArch::AArch64 => {
529 let mut map = aarch64::regclass_map();
530 aarch64::fill_reg_map(arch, has_feature, target, &mut map);
533 InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
534 let mut map = riscv::regclass_map();
535 riscv::fill_reg_map(arch, has_feature, target, &mut map);
538 InlineAsmArch::Nvptx64 => {
539 let mut map = nvptx::regclass_map();
540 nvptx::fill_reg_map(arch, has_feature, target, &mut map);
543 InlineAsmArch::Hexagon => {
544 let mut map = hexagon::regclass_map();
545 hexagon::fill_reg_map(arch, has_feature, target, &mut map);