]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_target/src/asm/mod.rs
Rollup merge of #85715 - fee1-dead:document-string, r=JohnTitor
[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_rules! def_reg_class {
10     ($arch:ident $arch_regclass:ident {
11         $(
12             $class:ident,
13         )*
14     }) => {
15         #[derive(Copy, Clone, Encodable, Decodable, Debug, Eq, PartialEq, PartialOrd, Hash, HashStable_Generic)]
16         #[allow(non_camel_case_types)]
17         pub enum $arch_regclass {
18             $($class,)*
19         }
20
21         impl $arch_regclass {
22             pub fn name(self) -> rustc_span::Symbol {
23                 match self {
24                     $(Self::$class => rustc_span::symbol::sym::$class,)*
25                 }
26             }
27
28             pub fn parse(_arch: super::InlineAsmArch, name: rustc_span::Symbol) -> Result<Self, &'static str> {
29                 match name {
30                     $(
31                         rustc_span::sym::$class => Ok(Self::$class),
32                     )*
33                     _ => Err("unknown register class"),
34                 }
35             }
36         }
37
38         pub(super) fn regclass_map() -> rustc_data_structures::fx::FxHashMap<
39             super::InlineAsmRegClass,
40             rustc_data_structures::fx::FxHashSet<super::InlineAsmReg>,
41         > {
42             use rustc_data_structures::fx::{FxHashMap, FxHashSet};
43             use super::InlineAsmRegClass;
44             let mut map = FxHashMap::default();
45             $(
46                 map.insert(InlineAsmRegClass::$arch($arch_regclass::$class), FxHashSet::default());
47             )*
48             map
49         }
50     }
51 }
52
53 macro_rules! def_regs {
54     ($arch:ident $arch_reg:ident $arch_regclass:ident {
55         $(
56             $reg:ident: $class:ident $(, $extra_class:ident)* = [$reg_name:literal $(, $alias:literal)*] $(% $filter:ident)?,
57         )*
58         $(
59             #error = [$($bad_reg:literal),+] => $error:literal,
60         )*
61     }) => {
62         #[allow(unreachable_code)]
63         #[derive(Copy, Clone, Encodable, Decodable, Debug, Eq, PartialEq, PartialOrd, Hash, HashStable_Generic)]
64         #[allow(non_camel_case_types)]
65         pub enum $arch_reg {
66             $($reg,)*
67         }
68
69         impl $arch_reg {
70             pub fn name(self) -> &'static str {
71                 match self {
72                     $(Self::$reg => $reg_name,)*
73                 }
74             }
75
76             pub fn reg_class(self) -> $arch_regclass {
77                 match self {
78                     $(Self::$reg => $arch_regclass::$class,)*
79                 }
80             }
81
82             pub fn parse(
83                 _arch: super::InlineAsmArch,
84                 mut _has_feature: impl FnMut(&str) -> bool,
85                 _target: &crate::spec::Target,
86                 name: &str,
87             ) -> Result<Self, &'static str> {
88                 match name {
89                     $(
90                         $($alias)|* | $reg_name => {
91                             $($filter(_arch, &mut _has_feature, _target)?;)?
92                             Ok(Self::$reg)
93                         }
94                     )*
95                     $(
96                         $($bad_reg)|* => Err($error),
97                     )*
98                     _ => Err("unknown register"),
99                 }
100             }
101         }
102
103         pub(super) fn fill_reg_map(
104             _arch: super::InlineAsmArch,
105             mut _has_feature: impl FnMut(&str) -> bool,
106             _target: &crate::spec::Target,
107             _map: &mut rustc_data_structures::fx::FxHashMap<
108                 super::InlineAsmRegClass,
109                 rustc_data_structures::fx::FxHashSet<super::InlineAsmReg>,
110             >,
111         ) {
112             #[allow(unused_imports)]
113             use super::{InlineAsmReg, InlineAsmRegClass};
114             $(
115                 if $($filter(_arch, &mut _has_feature, _target).is_ok() &&)? true {
116                     if let Some(set) = _map.get_mut(&InlineAsmRegClass::$arch($arch_regclass::$class)) {
117                         set.insert(InlineAsmReg::$arch($arch_reg::$reg));
118                     }
119                     $(
120                         if let Some(set) = _map.get_mut(&InlineAsmRegClass::$arch($arch_regclass::$extra_class)) {
121                             set.insert(InlineAsmReg::$arch($arch_reg::$reg));
122                         }
123                     )*
124                 }
125             )*
126         }
127     }
128 }
129
130 macro_rules! types {
131     (
132         $(_ : $($ty:expr),+;)?
133         $($feature:literal: $($ty2:expr),+;)*
134     ) => {
135         {
136             use super::InlineAsmType::*;
137             &[
138                 $($(
139                     ($ty, None),
140                 )*)?
141                 $($(
142                     ($ty2, Some($feature)),
143                 )*)*
144             ]
145         }
146     };
147 }
148
149 mod aarch64;
150 mod arm;
151 mod bpf;
152 mod hexagon;
153 mod mips;
154 mod nvptx;
155 mod powerpc;
156 mod riscv;
157 mod spirv;
158 mod wasm;
159 mod x86;
160
161 pub use aarch64::{AArch64InlineAsmReg, AArch64InlineAsmRegClass};
162 pub use arm::{ArmInlineAsmReg, ArmInlineAsmRegClass};
163 pub use bpf::{BpfInlineAsmReg, BpfInlineAsmRegClass};
164 pub use hexagon::{HexagonInlineAsmReg, HexagonInlineAsmRegClass};
165 pub use mips::{MipsInlineAsmReg, MipsInlineAsmRegClass};
166 pub use nvptx::{NvptxInlineAsmReg, NvptxInlineAsmRegClass};
167 pub use powerpc::{PowerPCInlineAsmReg, PowerPCInlineAsmRegClass};
168 pub use riscv::{RiscVInlineAsmReg, RiscVInlineAsmRegClass};
169 pub use spirv::{SpirVInlineAsmReg, SpirVInlineAsmRegClass};
170 pub use wasm::{WasmInlineAsmReg, WasmInlineAsmRegClass};
171 pub use x86::{X86InlineAsmReg, X86InlineAsmRegClass};
172
173 #[derive(Copy, Clone, Encodable, Decodable, Debug, Eq, PartialEq, Hash)]
174 pub enum InlineAsmArch {
175     X86,
176     X86_64,
177     Arm,
178     AArch64,
179     RiscV32,
180     RiscV64,
181     Nvptx64,
182     Hexagon,
183     Mips,
184     Mips64,
185     PowerPC,
186     PowerPC64,
187     SpirV,
188     Wasm32,
189     Bpf,
190 }
191
192 impl FromStr for InlineAsmArch {
193     type Err = ();
194
195     fn from_str(s: &str) -> Result<InlineAsmArch, ()> {
196         match s {
197             "x86" => Ok(Self::X86),
198             "x86_64" => Ok(Self::X86_64),
199             "arm" => Ok(Self::Arm),
200             "aarch64" => Ok(Self::AArch64),
201             "riscv32" => Ok(Self::RiscV32),
202             "riscv64" => Ok(Self::RiscV64),
203             "nvptx64" => Ok(Self::Nvptx64),
204             "powerpc" => Ok(Self::PowerPC),
205             "powerpc64" => Ok(Self::PowerPC64),
206             "hexagon" => Ok(Self::Hexagon),
207             "mips" => Ok(Self::Mips),
208             "mips64" => Ok(Self::Mips64),
209             "spirv" => Ok(Self::SpirV),
210             "wasm32" => Ok(Self::Wasm32),
211             "bpf" => Ok(Self::Bpf),
212             _ => Err(()),
213         }
214     }
215 }
216
217 #[derive(
218     Copy,
219     Clone,
220     Encodable,
221     Decodable,
222     Debug,
223     Eq,
224     PartialEq,
225     PartialOrd,
226     Hash,
227     HashStable_Generic
228 )]
229 pub enum InlineAsmReg {
230     X86(X86InlineAsmReg),
231     Arm(ArmInlineAsmReg),
232     AArch64(AArch64InlineAsmReg),
233     RiscV(RiscVInlineAsmReg),
234     Nvptx(NvptxInlineAsmReg),
235     PowerPC(PowerPCInlineAsmReg),
236     Hexagon(HexagonInlineAsmReg),
237     Mips(MipsInlineAsmReg),
238     SpirV(SpirVInlineAsmReg),
239     Wasm(WasmInlineAsmReg),
240     Bpf(BpfInlineAsmReg),
241     // Placeholder for invalid register constraints for the current target
242     Err,
243 }
244
245 impl InlineAsmReg {
246     pub fn name(self) -> &'static str {
247         match self {
248             Self::X86(r) => r.name(),
249             Self::Arm(r) => r.name(),
250             Self::AArch64(r) => r.name(),
251             Self::RiscV(r) => r.name(),
252             Self::PowerPC(r) => r.name(),
253             Self::Hexagon(r) => r.name(),
254             Self::Mips(r) => r.name(),
255             Self::Bpf(r) => r.name(),
256             Self::Err => "<reg>",
257         }
258     }
259
260     pub fn reg_class(self) -> InlineAsmRegClass {
261         match self {
262             Self::X86(r) => InlineAsmRegClass::X86(r.reg_class()),
263             Self::Arm(r) => InlineAsmRegClass::Arm(r.reg_class()),
264             Self::AArch64(r) => InlineAsmRegClass::AArch64(r.reg_class()),
265             Self::RiscV(r) => InlineAsmRegClass::RiscV(r.reg_class()),
266             Self::PowerPC(r) => InlineAsmRegClass::PowerPC(r.reg_class()),
267             Self::Hexagon(r) => InlineAsmRegClass::Hexagon(r.reg_class()),
268             Self::Mips(r) => InlineAsmRegClass::Mips(r.reg_class()),
269             Self::Bpf(r) => InlineAsmRegClass::Bpf(r.reg_class()),
270             Self::Err => InlineAsmRegClass::Err,
271         }
272     }
273
274     pub fn parse(
275         arch: InlineAsmArch,
276         has_feature: impl FnMut(&str) -> bool,
277         target: &Target,
278         name: Symbol,
279     ) -> Result<Self, &'static str> {
280         // FIXME: use direct symbol comparison for register names
281         // Use `Symbol::as_str` instead of `Symbol::with` here because `has_feature` may access `Symbol`.
282         let name = name.as_str();
283         Ok(match arch {
284             InlineAsmArch::X86 | InlineAsmArch::X86_64 => {
285                 Self::X86(X86InlineAsmReg::parse(arch, has_feature, target, &name)?)
286             }
287             InlineAsmArch::Arm => {
288                 Self::Arm(ArmInlineAsmReg::parse(arch, has_feature, target, &name)?)
289             }
290             InlineAsmArch::AArch64 => {
291                 Self::AArch64(AArch64InlineAsmReg::parse(arch, has_feature, target, &name)?)
292             }
293             InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
294                 Self::RiscV(RiscVInlineAsmReg::parse(arch, has_feature, target, &name)?)
295             }
296             InlineAsmArch::Nvptx64 => {
297                 Self::Nvptx(NvptxInlineAsmReg::parse(arch, has_feature, target, &name)?)
298             }
299             InlineAsmArch::PowerPC | InlineAsmArch::PowerPC64 => {
300                 Self::PowerPC(PowerPCInlineAsmReg::parse(arch, has_feature, target, &name)?)
301             }
302             InlineAsmArch::Hexagon => {
303                 Self::Hexagon(HexagonInlineAsmReg::parse(arch, has_feature, target, &name)?)
304             }
305             InlineAsmArch::Mips | InlineAsmArch::Mips64 => {
306                 Self::Mips(MipsInlineAsmReg::parse(arch, has_feature, target, &name)?)
307             }
308             InlineAsmArch::SpirV => {
309                 Self::SpirV(SpirVInlineAsmReg::parse(arch, has_feature, target, &name)?)
310             }
311             InlineAsmArch::Wasm32 => {
312                 Self::Wasm(WasmInlineAsmReg::parse(arch, has_feature, target, &name)?)
313             }
314             InlineAsmArch::Bpf => {
315                 Self::Bpf(BpfInlineAsmReg::parse(arch, has_feature, target, &name)?)
316             }
317         })
318     }
319
320     // NOTE: This function isn't used at the moment, but is needed to support
321     // falling back to an external assembler.
322     pub fn emit(
323         self,
324         out: &mut dyn fmt::Write,
325         arch: InlineAsmArch,
326         modifier: Option<char>,
327     ) -> fmt::Result {
328         match self {
329             Self::X86(r) => r.emit(out, arch, modifier),
330             Self::Arm(r) => r.emit(out, arch, modifier),
331             Self::AArch64(r) => r.emit(out, arch, modifier),
332             Self::RiscV(r) => r.emit(out, arch, modifier),
333             Self::PowerPC(r) => r.emit(out, arch, modifier),
334             Self::Hexagon(r) => r.emit(out, arch, modifier),
335             Self::Mips(r) => r.emit(out, arch, modifier),
336             Self::Bpf(r) => r.emit(out, arch, modifier),
337             Self::Err => unreachable!("Use of InlineAsmReg::Err"),
338         }
339     }
340
341     pub fn overlapping_regs(self, mut cb: impl FnMut(InlineAsmReg)) {
342         match self {
343             Self::X86(r) => r.overlapping_regs(|r| cb(Self::X86(r))),
344             Self::Arm(r) => r.overlapping_regs(|r| cb(Self::Arm(r))),
345             Self::AArch64(_) => cb(self),
346             Self::RiscV(_) => cb(self),
347             Self::PowerPC(_) => cb(self),
348             Self::Hexagon(r) => r.overlapping_regs(|r| cb(Self::Hexagon(r))),
349             Self::Mips(_) => cb(self),
350             Self::Bpf(r) => r.overlapping_regs(|r| cb(Self::Bpf(r))),
351             Self::Err => unreachable!("Use of InlineAsmReg::Err"),
352         }
353     }
354 }
355
356 #[derive(
357     Copy,
358     Clone,
359     Encodable,
360     Decodable,
361     Debug,
362     Eq,
363     PartialEq,
364     PartialOrd,
365     Hash,
366     HashStable_Generic
367 )]
368 pub enum InlineAsmRegClass {
369     X86(X86InlineAsmRegClass),
370     Arm(ArmInlineAsmRegClass),
371     AArch64(AArch64InlineAsmRegClass),
372     RiscV(RiscVInlineAsmRegClass),
373     Nvptx(NvptxInlineAsmRegClass),
374     PowerPC(PowerPCInlineAsmRegClass),
375     Hexagon(HexagonInlineAsmRegClass),
376     Mips(MipsInlineAsmRegClass),
377     SpirV(SpirVInlineAsmRegClass),
378     Wasm(WasmInlineAsmRegClass),
379     Bpf(BpfInlineAsmRegClass),
380     // Placeholder for invalid register constraints for the current target
381     Err,
382 }
383
384 impl InlineAsmRegClass {
385     pub fn name(self) -> Symbol {
386         match self {
387             Self::X86(r) => r.name(),
388             Self::Arm(r) => r.name(),
389             Self::AArch64(r) => r.name(),
390             Self::RiscV(r) => r.name(),
391             Self::Nvptx(r) => r.name(),
392             Self::PowerPC(r) => r.name(),
393             Self::Hexagon(r) => r.name(),
394             Self::Mips(r) => r.name(),
395             Self::SpirV(r) => r.name(),
396             Self::Wasm(r) => r.name(),
397             Self::Bpf(r) => r.name(),
398             Self::Err => rustc_span::symbol::sym::reg,
399         }
400     }
401
402     /// Returns a suggested register class to use for this type. This is called
403     /// after type checking via `supported_types` fails to give a better error
404     /// message to the user.
405     pub fn suggest_class(self, arch: InlineAsmArch, ty: InlineAsmType) -> Option<Self> {
406         match self {
407             Self::X86(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::X86),
408             Self::Arm(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Arm),
409             Self::AArch64(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::AArch64),
410             Self::RiscV(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::RiscV),
411             Self::Nvptx(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Nvptx),
412             Self::PowerPC(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::PowerPC),
413             Self::Hexagon(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Hexagon),
414             Self::Mips(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Mips),
415             Self::SpirV(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::SpirV),
416             Self::Wasm(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Wasm),
417             Self::Bpf(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Bpf),
418             Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
419         }
420     }
421
422     /// Returns a suggested template modifier to use for this type and an
423     /// example of a  register named formatted with it.
424     ///
425     /// Such suggestions are useful if a type smaller than the full register
426     /// size is used and a modifier can be used to point to the subregister of
427     /// the correct size.
428     pub fn suggest_modifier(
429         self,
430         arch: InlineAsmArch,
431         ty: InlineAsmType,
432     ) -> Option<(char, &'static str)> {
433         match self {
434             Self::X86(r) => r.suggest_modifier(arch, ty),
435             Self::Arm(r) => r.suggest_modifier(arch, ty),
436             Self::AArch64(r) => r.suggest_modifier(arch, ty),
437             Self::RiscV(r) => r.suggest_modifier(arch, ty),
438             Self::Nvptx(r) => r.suggest_modifier(arch, ty),
439             Self::PowerPC(r) => r.suggest_modifier(arch, ty),
440             Self::Hexagon(r) => r.suggest_modifier(arch, ty),
441             Self::Mips(r) => r.suggest_modifier(arch, ty),
442             Self::SpirV(r) => r.suggest_modifier(arch, ty),
443             Self::Wasm(r) => r.suggest_modifier(arch, ty),
444             Self::Bpf(r) => r.suggest_modifier(arch, ty),
445             Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
446         }
447     }
448
449     /// Returns the default modifier for this register and an example of a
450     /// register named formatted with it.
451     ///
452     /// This is only needed when the register class can suggest a modifier, so
453     /// that the user can be shown how to get the default behavior without a
454     /// warning.
455     pub fn default_modifier(self, arch: InlineAsmArch) -> Option<(char, &'static str)> {
456         match self {
457             Self::X86(r) => r.default_modifier(arch),
458             Self::Arm(r) => r.default_modifier(arch),
459             Self::AArch64(r) => r.default_modifier(arch),
460             Self::RiscV(r) => r.default_modifier(arch),
461             Self::Nvptx(r) => r.default_modifier(arch),
462             Self::PowerPC(r) => r.default_modifier(arch),
463             Self::Hexagon(r) => r.default_modifier(arch),
464             Self::Mips(r) => r.default_modifier(arch),
465             Self::SpirV(r) => r.default_modifier(arch),
466             Self::Wasm(r) => r.default_modifier(arch),
467             Self::Bpf(r) => r.default_modifier(arch),
468             Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
469         }
470     }
471
472     /// Returns a list of supported types for this register class, each with a
473     /// options target feature required to use this type.
474     pub fn supported_types(
475         self,
476         arch: InlineAsmArch,
477     ) -> &'static [(InlineAsmType, Option<&'static str>)] {
478         match self {
479             Self::X86(r) => r.supported_types(arch),
480             Self::Arm(r) => r.supported_types(arch),
481             Self::AArch64(r) => r.supported_types(arch),
482             Self::RiscV(r) => r.supported_types(arch),
483             Self::Nvptx(r) => r.supported_types(arch),
484             Self::PowerPC(r) => r.supported_types(arch),
485             Self::Hexagon(r) => r.supported_types(arch),
486             Self::Mips(r) => r.supported_types(arch),
487             Self::SpirV(r) => r.supported_types(arch),
488             Self::Wasm(r) => r.supported_types(arch),
489             Self::Bpf(r) => r.supported_types(arch),
490             Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
491         }
492     }
493
494     pub fn parse(arch: InlineAsmArch, name: Symbol) -> Result<Self, &'static str> {
495         Ok(match arch {
496             InlineAsmArch::X86 | InlineAsmArch::X86_64 => {
497                 Self::X86(X86InlineAsmRegClass::parse(arch, name)?)
498             }
499             InlineAsmArch::Arm => Self::Arm(ArmInlineAsmRegClass::parse(arch, name)?),
500             InlineAsmArch::AArch64 => Self::AArch64(AArch64InlineAsmRegClass::parse(arch, name)?),
501             InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
502                 Self::RiscV(RiscVInlineAsmRegClass::parse(arch, name)?)
503             }
504             InlineAsmArch::Nvptx64 => Self::Nvptx(NvptxInlineAsmRegClass::parse(arch, name)?),
505             InlineAsmArch::PowerPC | InlineAsmArch::PowerPC64 => {
506                 Self::PowerPC(PowerPCInlineAsmRegClass::parse(arch, name)?)
507             }
508             InlineAsmArch::Hexagon => Self::Hexagon(HexagonInlineAsmRegClass::parse(arch, name)?),
509             InlineAsmArch::Mips | InlineAsmArch::Mips64 => {
510                 Self::Mips(MipsInlineAsmRegClass::parse(arch, name)?)
511             }
512             InlineAsmArch::SpirV => Self::SpirV(SpirVInlineAsmRegClass::parse(arch, name)?),
513             InlineAsmArch::Wasm32 => Self::Wasm(WasmInlineAsmRegClass::parse(arch, name)?),
514             InlineAsmArch::Bpf => Self::Bpf(BpfInlineAsmRegClass::parse(arch, name)?),
515         })
516     }
517
518     /// Returns the list of template modifiers that can be used with this
519     /// register class.
520     pub fn valid_modifiers(self, arch: InlineAsmArch) -> &'static [char] {
521         match self {
522             Self::X86(r) => r.valid_modifiers(arch),
523             Self::Arm(r) => r.valid_modifiers(arch),
524             Self::AArch64(r) => r.valid_modifiers(arch),
525             Self::RiscV(r) => r.valid_modifiers(arch),
526             Self::Nvptx(r) => r.valid_modifiers(arch),
527             Self::PowerPC(r) => r.valid_modifiers(arch),
528             Self::Hexagon(r) => r.valid_modifiers(arch),
529             Self::Mips(r) => r.valid_modifiers(arch),
530             Self::SpirV(r) => r.valid_modifiers(arch),
531             Self::Wasm(r) => r.valid_modifiers(arch),
532             Self::Bpf(r) => r.valid_modifiers(arch),
533             Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
534         }
535     }
536 }
537
538 #[derive(
539     Copy,
540     Clone,
541     Encodable,
542     Decodable,
543     Debug,
544     Eq,
545     PartialEq,
546     PartialOrd,
547     Hash,
548     HashStable_Generic
549 )]
550 pub enum InlineAsmRegOrRegClass {
551     Reg(InlineAsmReg),
552     RegClass(InlineAsmRegClass),
553 }
554
555 impl InlineAsmRegOrRegClass {
556     pub fn reg_class(self) -> InlineAsmRegClass {
557         match self {
558             Self::Reg(r) => r.reg_class(),
559             Self::RegClass(r) => r,
560         }
561     }
562 }
563
564 impl fmt::Display for InlineAsmRegOrRegClass {
565     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
566         match self {
567             Self::Reg(r) => write!(f, "\"{}\"", r.name()),
568             Self::RegClass(r) => write!(f, "{}", r.name()),
569         }
570     }
571 }
572
573 /// Set of types which can be used with a particular register class.
574 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
575 pub enum InlineAsmType {
576     I8,
577     I16,
578     I32,
579     I64,
580     I128,
581     F32,
582     F64,
583     VecI8(u64),
584     VecI16(u64),
585     VecI32(u64),
586     VecI64(u64),
587     VecI128(u64),
588     VecF32(u64),
589     VecF64(u64),
590 }
591
592 impl InlineAsmType {
593     pub fn is_integer(self) -> bool {
594         matches!(self, Self::I8 | Self::I16 | Self::I32 | Self::I64 | Self::I128)
595     }
596
597     pub fn size(self) -> Size {
598         Size::from_bytes(match self {
599             Self::I8 => 1,
600             Self::I16 => 2,
601             Self::I32 => 4,
602             Self::I64 => 8,
603             Self::I128 => 16,
604             Self::F32 => 4,
605             Self::F64 => 8,
606             Self::VecI8(n) => n * 1,
607             Self::VecI16(n) => n * 2,
608             Self::VecI32(n) => n * 4,
609             Self::VecI64(n) => n * 8,
610             Self::VecI128(n) => n * 16,
611             Self::VecF32(n) => n * 4,
612             Self::VecF64(n) => n * 8,
613         })
614     }
615 }
616
617 impl fmt::Display for InlineAsmType {
618     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
619         match *self {
620             Self::I8 => f.write_str("i8"),
621             Self::I16 => f.write_str("i16"),
622             Self::I32 => f.write_str("i32"),
623             Self::I64 => f.write_str("i64"),
624             Self::I128 => f.write_str("i128"),
625             Self::F32 => f.write_str("f32"),
626             Self::F64 => f.write_str("f64"),
627             Self::VecI8(n) => write!(f, "i8x{}", n),
628             Self::VecI16(n) => write!(f, "i16x{}", n),
629             Self::VecI32(n) => write!(f, "i32x{}", n),
630             Self::VecI64(n) => write!(f, "i64x{}", n),
631             Self::VecI128(n) => write!(f, "i128x{}", n),
632             Self::VecF32(n) => write!(f, "f32x{}", n),
633             Self::VecF64(n) => write!(f, "f64x{}", n),
634         }
635     }
636 }
637
638 /// Returns the full set of allocatable registers for a given architecture.
639 ///
640 /// The registers are structured as a map containing the set of allocatable
641 /// registers in each register class. A particular register may be allocatable
642 /// from multiple register classes, in which case it will appear multiple times
643 /// in the map.
644 // NOTE: This function isn't used at the moment, but is needed to support
645 // falling back to an external assembler.
646 pub fn allocatable_registers(
647     arch: InlineAsmArch,
648     has_feature: impl FnMut(&str) -> bool,
649     target: &crate::spec::Target,
650 ) -> FxHashMap<InlineAsmRegClass, FxHashSet<InlineAsmReg>> {
651     match arch {
652         InlineAsmArch::X86 | InlineAsmArch::X86_64 => {
653             let mut map = x86::regclass_map();
654             x86::fill_reg_map(arch, has_feature, target, &mut map);
655             map
656         }
657         InlineAsmArch::Arm => {
658             let mut map = arm::regclass_map();
659             arm::fill_reg_map(arch, has_feature, target, &mut map);
660             map
661         }
662         InlineAsmArch::AArch64 => {
663             let mut map = aarch64::regclass_map();
664             aarch64::fill_reg_map(arch, has_feature, target, &mut map);
665             map
666         }
667         InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
668             let mut map = riscv::regclass_map();
669             riscv::fill_reg_map(arch, has_feature, target, &mut map);
670             map
671         }
672         InlineAsmArch::Nvptx64 => {
673             let mut map = nvptx::regclass_map();
674             nvptx::fill_reg_map(arch, has_feature, target, &mut map);
675             map
676         }
677         InlineAsmArch::PowerPC | InlineAsmArch::PowerPC64 => {
678             let mut map = powerpc::regclass_map();
679             powerpc::fill_reg_map(arch, has_feature, target, &mut map);
680             map
681         }
682         InlineAsmArch::Hexagon => {
683             let mut map = hexagon::regclass_map();
684             hexagon::fill_reg_map(arch, has_feature, target, &mut map);
685             map
686         }
687         InlineAsmArch::Mips | InlineAsmArch::Mips64 => {
688             let mut map = mips::regclass_map();
689             mips::fill_reg_map(arch, has_feature, target, &mut map);
690             map
691         }
692         InlineAsmArch::SpirV => {
693             let mut map = spirv::regclass_map();
694             spirv::fill_reg_map(arch, has_feature, target, &mut map);
695             map
696         }
697         InlineAsmArch::Wasm32 => {
698             let mut map = wasm::regclass_map();
699             wasm::fill_reg_map(arch, has_feature, target, &mut map);
700             map
701         }
702         InlineAsmArch::Bpf => {
703             let mut map = bpf::regclass_map();
704             bpf::fill_reg_map(arch, has_feature, target, &mut map);
705             map
706         }
707     }
708 }