]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_target/src/asm/mod.rs
Auto merge of #80339 - jyn514:no-span, r=GuillaumeGomez
[rust.git] / compiler / rustc_target / src / asm / mod.rs
1 use crate::abi::Size;
2 use crate::spec::Target;
3 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
4 use rustc_macros::HashStable_Generic;
5 use rustc_span::Symbol;
6 use std::fmt;
7 use std::str::FromStr;
8
9 #[macro_use]
10 macro_rules! def_reg_class {
11     ($arch:ident $arch_regclass:ident {
12         $(
13             $class:ident,
14         )*
15     }) => {
16         #[derive(Copy, Clone, Encodable, Decodable, Debug, Eq, PartialEq, PartialOrd, Hash, HashStable_Generic)]
17         #[allow(non_camel_case_types)]
18         pub enum $arch_regclass {
19             $($class,)*
20         }
21
22         impl $arch_regclass {
23             pub fn name(self) -> rustc_span::Symbol {
24                 match self {
25                     $(Self::$class => rustc_span::symbol::sym::$class,)*
26                 }
27             }
28
29             pub fn parse(_arch: super::InlineAsmArch, name: rustc_span::Symbol) -> Result<Self, &'static str> {
30                 match name {
31                     $(
32                         rustc_span::sym::$class => Ok(Self::$class),
33                     )*
34                     _ => Err("unknown register class"),
35                 }
36             }
37         }
38
39         pub(super) fn regclass_map() -> rustc_data_structures::fx::FxHashMap<
40             super::InlineAsmRegClass,
41             rustc_data_structures::fx::FxHashSet<super::InlineAsmReg>,
42         > {
43             use rustc_data_structures::fx::{FxHashMap, FxHashSet};
44             use super::InlineAsmRegClass;
45             let mut map = FxHashMap::default();
46             $(
47                 map.insert(InlineAsmRegClass::$arch($arch_regclass::$class), FxHashSet::default());
48             )*
49             map
50         }
51     }
52 }
53
54 #[macro_use]
55 macro_rules! def_regs {
56     ($arch:ident $arch_reg:ident $arch_regclass:ident {
57         $(
58             $reg:ident: $class:ident $(, $extra_class:ident)* = [$reg_name:literal $(, $alias:literal)*] $(% $filter:ident)?,
59         )*
60         $(
61             #error = [$($bad_reg:literal),+] => $error:literal,
62         )*
63     }) => {
64         #[allow(unreachable_code)]
65         #[derive(Copy, Clone, Encodable, Decodable, Debug, Eq, PartialEq, PartialOrd, Hash, HashStable_Generic)]
66         #[allow(non_camel_case_types)]
67         pub enum $arch_reg {
68             $($reg,)*
69         }
70
71         impl $arch_reg {
72             pub fn name(self) -> &'static str {
73                 match self {
74                     $(Self::$reg => $reg_name,)*
75                 }
76             }
77
78             pub fn reg_class(self) -> $arch_regclass {
79                 match self {
80                     $(Self::$reg => $arch_regclass::$class,)*
81                 }
82             }
83
84             pub fn parse(
85                 _arch: super::InlineAsmArch,
86                 mut _has_feature: impl FnMut(&str) -> bool,
87                 _target: &crate::spec::Target,
88                 name: &str,
89             ) -> Result<Self, &'static str> {
90                 match name {
91                     $(
92                         $($alias)|* | $reg_name => {
93                             $($filter(_arch, &mut _has_feature, _target)?;)?
94                             Ok(Self::$reg)
95                         }
96                     )*
97                     $(
98                         $($bad_reg)|* => Err($error),
99                     )*
100                     _ => Err("unknown register"),
101                 }
102             }
103         }
104
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>,
112             >,
113         ) {
114             #[allow(unused_imports)]
115             use super::{InlineAsmReg, InlineAsmRegClass};
116             $(
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));
120                     }
121                     $(
122                         if let Some(set) = _map.get_mut(&InlineAsmRegClass::$arch($arch_regclass::$extra_class)) {
123                             set.insert(InlineAsmReg::$arch($arch_reg::$reg));
124                         }
125                     )*
126                 }
127             )*
128         }
129     }
130 }
131
132 #[macro_use]
133 macro_rules! types {
134     (
135         $(_ : $($ty:expr),+;)?
136         $($feature:literal: $($ty2:expr),+;)*
137     ) => {
138         {
139             use super::InlineAsmType::*;
140             &[
141                 $($(
142                     ($ty, None),
143                 )*)?
144                 $($(
145                     ($ty2, Some($feature)),
146                 )*)*
147             ]
148         }
149     };
150 }
151
152 mod aarch64;
153 mod arm;
154 mod hexagon;
155 mod mips;
156 mod nvptx;
157 mod riscv;
158 mod spirv;
159 mod wasm;
160 mod x86;
161
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};
171
172 #[derive(Copy, Clone, Encodable, Decodable, Debug, Eq, PartialEq, Hash)]
173 pub enum InlineAsmArch {
174     X86,
175     X86_64,
176     Arm,
177     AArch64,
178     RiscV32,
179     RiscV64,
180     Nvptx64,
181     Hexagon,
182     Mips,
183     Mips64,
184     SpirV,
185     Wasm32,
186 }
187
188 impl FromStr for InlineAsmArch {
189     type Err = ();
190
191     fn from_str(s: &str) -> Result<InlineAsmArch, ()> {
192         match s {
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),
205             _ => Err(()),
206         }
207     }
208 }
209
210 #[derive(
211     Copy,
212     Clone,
213     Encodable,
214     Decodable,
215     Debug,
216     Eq,
217     PartialEq,
218     PartialOrd,
219     Hash,
220     HashStable_Generic
221 )]
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
233     Err,
234 }
235
236 impl InlineAsmReg {
237     pub fn name(self) -> &'static str {
238         match self {
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>",
246         }
247     }
248
249     pub fn reg_class(self) -> InlineAsmRegClass {
250         match self {
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,
258         }
259     }
260
261     pub fn parse(
262         arch: InlineAsmArch,
263         has_feature: impl FnMut(&str) -> bool,
264         target: &Target,
265         name: Symbol,
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();
270         Ok(match arch {
271             InlineAsmArch::X86 | InlineAsmArch::X86_64 => {
272                 Self::X86(X86InlineAsmReg::parse(arch, has_feature, target, &name)?)
273             }
274             InlineAsmArch::Arm => {
275                 Self::Arm(ArmInlineAsmReg::parse(arch, has_feature, target, &name)?)
276             }
277             InlineAsmArch::AArch64 => {
278                 Self::AArch64(AArch64InlineAsmReg::parse(arch, has_feature, target, &name)?)
279             }
280             InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
281                 Self::RiscV(RiscVInlineAsmReg::parse(arch, has_feature, target, &name)?)
282             }
283             InlineAsmArch::Nvptx64 => {
284                 Self::Nvptx(NvptxInlineAsmReg::parse(arch, has_feature, target, &name)?)
285             }
286             InlineAsmArch::Hexagon => {
287                 Self::Hexagon(HexagonInlineAsmReg::parse(arch, has_feature, target, &name)?)
288             }
289             InlineAsmArch::Mips | InlineAsmArch::Mips64 => {
290                 Self::Mips(MipsInlineAsmReg::parse(arch, has_feature, target, &name)?)
291             }
292             InlineAsmArch::SpirV => {
293                 Self::SpirV(SpirVInlineAsmReg::parse(arch, has_feature, target, &name)?)
294             }
295             InlineAsmArch::Wasm32 => {
296                 Self::Wasm(WasmInlineAsmReg::parse(arch, has_feature, target, &name)?)
297             }
298         })
299     }
300
301     // NOTE: This function isn't used at the moment, but is needed to support
302     // falling back to an external assembler.
303     pub fn emit(
304         self,
305         out: &mut dyn fmt::Write,
306         arch: InlineAsmArch,
307         modifier: Option<char>,
308     ) -> fmt::Result {
309         match self {
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"),
317         }
318     }
319
320     pub fn overlapping_regs(self, mut cb: impl FnMut(InlineAsmReg)) {
321         match self {
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"),
329         }
330     }
331 }
332
333 #[derive(
334     Copy,
335     Clone,
336     Encodable,
337     Decodable,
338     Debug,
339     Eq,
340     PartialEq,
341     PartialOrd,
342     Hash,
343     HashStable_Generic
344 )]
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
356     Err,
357 }
358
359 impl InlineAsmRegClass {
360     pub fn name(self) -> Symbol {
361         match self {
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,
372         }
373     }
374
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> {
379         match 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"),
390         }
391     }
392
393     /// Returns a suggested template modifier to use for this type and an
394     /// example of a  register named formatted with it.
395     ///
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(
400         self,
401         arch: InlineAsmArch,
402         ty: InlineAsmType,
403     ) -> Option<(char, &'static str)> {
404         match self {
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"),
415         }
416     }
417
418     /// Returns the default modifier for this register and an example of a
419     /// register named formatted with it.
420     ///
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
423     /// warning.
424     pub fn default_modifier(self, arch: InlineAsmArch) -> Option<(char, &'static str)> {
425         match self {
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"),
436         }
437     }
438
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(
442         self,
443         arch: InlineAsmArch,
444     ) -> &'static [(InlineAsmType, Option<&'static str>)] {
445         match self {
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"),
456         }
457     }
458
459     pub fn parse(arch: InlineAsmArch, name: Symbol) -> Result<Self, &'static str> {
460         Ok(match arch {
461             InlineAsmArch::X86 | InlineAsmArch::X86_64 => {
462                 Self::X86(X86InlineAsmRegClass::parse(arch, name)?)
463             }
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)?)
468             }
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)?)
473             }
474             InlineAsmArch::SpirV => Self::SpirV(SpirVInlineAsmRegClass::parse(arch, name)?),
475             InlineAsmArch::Wasm32 => Self::Wasm(WasmInlineAsmRegClass::parse(arch, name)?),
476         })
477     }
478
479     /// Returns the list of template modifiers that can be used with this
480     /// register class.
481     pub fn valid_modifiers(self, arch: InlineAsmArch) -> &'static [char] {
482         match self {
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"),
493         }
494     }
495 }
496
497 #[derive(
498     Copy,
499     Clone,
500     Encodable,
501     Decodable,
502     Debug,
503     Eq,
504     PartialEq,
505     PartialOrd,
506     Hash,
507     HashStable_Generic
508 )]
509 pub enum InlineAsmRegOrRegClass {
510     Reg(InlineAsmReg),
511     RegClass(InlineAsmRegClass),
512 }
513
514 impl InlineAsmRegOrRegClass {
515     pub fn reg_class(self) -> InlineAsmRegClass {
516         match self {
517             Self::Reg(r) => r.reg_class(),
518             Self::RegClass(r) => r,
519         }
520     }
521 }
522
523 impl fmt::Display for InlineAsmRegOrRegClass {
524     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
525         match self {
526             Self::Reg(r) => write!(f, "\"{}\"", r.name()),
527             Self::RegClass(r) => write!(f, "{}", r.name()),
528         }
529     }
530 }
531
532 /// Set of types which can be used with a particular register class.
533 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
534 pub enum InlineAsmType {
535     I8,
536     I16,
537     I32,
538     I64,
539     I128,
540     F32,
541     F64,
542     VecI8(u64),
543     VecI16(u64),
544     VecI32(u64),
545     VecI64(u64),
546     VecI128(u64),
547     VecF32(u64),
548     VecF64(u64),
549 }
550
551 impl InlineAsmType {
552     pub fn is_integer(self) -> bool {
553         matches!(self, Self::I8 | Self::I16 | Self::I32 | Self::I64 | Self::I128)
554     }
555
556     pub fn size(self) -> Size {
557         Size::from_bytes(match self {
558             Self::I8 => 1,
559             Self::I16 => 2,
560             Self::I32 => 4,
561             Self::I64 => 8,
562             Self::I128 => 16,
563             Self::F32 => 4,
564             Self::F64 => 8,
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,
572         })
573     }
574 }
575
576 impl fmt::Display for InlineAsmType {
577     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
578         match *self {
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),
593         }
594     }
595 }
596
597 /// Returns the full set of allocatable registers for a given architecture.
598 ///
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
602 /// in the map.
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(
606     arch: InlineAsmArch,
607     has_feature: impl FnMut(&str) -> bool,
608     target: &crate::spec::Target,
609 ) -> FxHashMap<InlineAsmRegClass, FxHashSet<InlineAsmReg>> {
610     match arch {
611         InlineAsmArch::X86 | InlineAsmArch::X86_64 => {
612             let mut map = x86::regclass_map();
613             x86::fill_reg_map(arch, has_feature, target, &mut map);
614             map
615         }
616         InlineAsmArch::Arm => {
617             let mut map = arm::regclass_map();
618             arm::fill_reg_map(arch, has_feature, target, &mut map);
619             map
620         }
621         InlineAsmArch::AArch64 => {
622             let mut map = aarch64::regclass_map();
623             aarch64::fill_reg_map(arch, has_feature, target, &mut map);
624             map
625         }
626         InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
627             let mut map = riscv::regclass_map();
628             riscv::fill_reg_map(arch, has_feature, target, &mut map);
629             map
630         }
631         InlineAsmArch::Nvptx64 => {
632             let mut map = nvptx::regclass_map();
633             nvptx::fill_reg_map(arch, has_feature, target, &mut map);
634             map
635         }
636         InlineAsmArch::Hexagon => {
637             let mut map = hexagon::regclass_map();
638             hexagon::fill_reg_map(arch, has_feature, target, &mut map);
639             map
640         }
641         InlineAsmArch::Mips | InlineAsmArch::Mips64 => {
642             let mut map = mips::regclass_map();
643             mips::fill_reg_map(arch, has_feature, target, &mut map);
644             map
645         }
646         InlineAsmArch::SpirV => {
647             let mut map = spirv::regclass_map();
648             spirv::fill_reg_map(arch, has_feature, target, &mut map);
649             map
650         }
651         InlineAsmArch::Wasm32 => {
652             let mut map = wasm::regclass_map();
653             wasm::fill_reg_map(arch, has_feature, target, &mut map);
654             map
655         }
656     }
657 }