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 hexagon;
152 mod mips;
153 mod nvptx;
154 mod powerpc;
155 mod riscv;
156 mod spirv;
157 mod wasm;
158 mod x86;
159 
160 pub use aarch64::{AArch64InlineAsmReg, AArch64InlineAsmRegClass};
161 pub use arm::{ArmInlineAsmReg, ArmInlineAsmRegClass};
162 pub use hexagon::{HexagonInlineAsmReg, HexagonInlineAsmRegClass};
163 pub use mips::{MipsInlineAsmReg, MipsInlineAsmRegClass};
164 pub use nvptx::{NvptxInlineAsmReg, NvptxInlineAsmRegClass};
165 pub use powerpc::{PowerPCInlineAsmReg, PowerPCInlineAsmRegClass};
166 pub use riscv::{RiscVInlineAsmReg, RiscVInlineAsmRegClass};
167 pub use spirv::{SpirVInlineAsmReg, SpirVInlineAsmRegClass};
168 pub use wasm::{WasmInlineAsmReg, WasmInlineAsmRegClass};
169 pub use x86::{X86InlineAsmReg, X86InlineAsmRegClass};
170 
171 #[derive(Copy, Clone, Encodable, Decodable, Debug, Eq, PartialEq, Hash)]
172 pub enum InlineAsmArch {
173     X86,
174     X86_64,
175     Arm,
176     AArch64,
177     RiscV32,
178     RiscV64,
179     Nvptx64,
180     Hexagon,
181     Mips,
182     Mips64,
183     PowerPC,
184     PowerPC64,
185     SpirV,
186     Wasm32,
187 }
188 
189 impl FromStr for InlineAsmArch {
190     type Err = ();
191 
from_str(s: &str) -> Result<InlineAsmArch, ()>192     fn from_str(s: &str) -> Result<InlineAsmArch, ()> {
193         match s {
194             "x86" => Ok(Self::X86),
195             "x86_64" => Ok(Self::X86_64),
196             "arm" => Ok(Self::Arm),
197             "aarch64" => Ok(Self::AArch64),
198             "riscv32" => Ok(Self::RiscV32),
199             "riscv64" => Ok(Self::RiscV64),
200             "nvptx64" => Ok(Self::Nvptx64),
201             "powerpc" => Ok(Self::PowerPC),
202             "powerpc64" => Ok(Self::PowerPC64),
203             "hexagon" => Ok(Self::Hexagon),
204             "mips" => Ok(Self::Mips),
205             "mips64" => Ok(Self::Mips64),
206             "spirv" => Ok(Self::SpirV),
207             "wasm32" => Ok(Self::Wasm32),
208             _ => Err(()),
209         }
210     }
211 }
212 
213 #[derive(
214     Copy,
215     Clone,
216     Encodable,
217     Decodable,
218     Debug,
219     Eq,
220     PartialEq,
221     PartialOrd,
222     Hash,
223     HashStable_Generic
224 )]
225 pub enum InlineAsmReg {
226     X86(X86InlineAsmReg),
227     Arm(ArmInlineAsmReg),
228     AArch64(AArch64InlineAsmReg),
229     RiscV(RiscVInlineAsmReg),
230     Nvptx(NvptxInlineAsmReg),
231     PowerPC(PowerPCInlineAsmReg),
232     Hexagon(HexagonInlineAsmReg),
233     Mips(MipsInlineAsmReg),
234     SpirV(SpirVInlineAsmReg),
235     Wasm(WasmInlineAsmReg),
236     // Placeholder for invalid register constraints for the current target
237     Err,
238 }
239 
240 impl InlineAsmReg {
name(self) -> &'static str241     pub fn name(self) -> &'static str {
242         match self {
243             Self::X86(r) => r.name(),
244             Self::Arm(r) => r.name(),
245             Self::AArch64(r) => r.name(),
246             Self::RiscV(r) => r.name(),
247             Self::PowerPC(r) => r.name(),
248             Self::Hexagon(r) => r.name(),
249             Self::Mips(r) => r.name(),
250             Self::Err => "<reg>",
251         }
252     }
253 
reg_class(self) -> InlineAsmRegClass254     pub fn reg_class(self) -> InlineAsmRegClass {
255         match self {
256             Self::X86(r) => InlineAsmRegClass::X86(r.reg_class()),
257             Self::Arm(r) => InlineAsmRegClass::Arm(r.reg_class()),
258             Self::AArch64(r) => InlineAsmRegClass::AArch64(r.reg_class()),
259             Self::RiscV(r) => InlineAsmRegClass::RiscV(r.reg_class()),
260             Self::PowerPC(r) => InlineAsmRegClass::PowerPC(r.reg_class()),
261             Self::Hexagon(r) => InlineAsmRegClass::Hexagon(r.reg_class()),
262             Self::Mips(r) => InlineAsmRegClass::Mips(r.reg_class()),
263             Self::Err => InlineAsmRegClass::Err,
264         }
265     }
266 
parse( arch: InlineAsmArch, has_feature: impl FnMut(&str) -> bool, target: &Target, name: Symbol, ) -> Result<Self, &'static str>267     pub fn parse(
268         arch: InlineAsmArch,
269         has_feature: impl FnMut(&str) -> bool,
270         target: &Target,
271         name: Symbol,
272     ) -> Result<Self, &'static str> {
273         // FIXME: use direct symbol comparison for register names
274         // Use `Symbol::as_str` instead of `Symbol::with` here because `has_feature` may access `Symbol`.
275         let name = name.as_str();
276         Ok(match arch {
277             InlineAsmArch::X86 | InlineAsmArch::X86_64 => {
278                 Self::X86(X86InlineAsmReg::parse(arch, has_feature, target, &name)?)
279             }
280             InlineAsmArch::Arm => {
281                 Self::Arm(ArmInlineAsmReg::parse(arch, has_feature, target, &name)?)
282             }
283             InlineAsmArch::AArch64 => {
284                 Self::AArch64(AArch64InlineAsmReg::parse(arch, has_feature, target, &name)?)
285             }
286             InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
287                 Self::RiscV(RiscVInlineAsmReg::parse(arch, has_feature, target, &name)?)
288             }
289             InlineAsmArch::Nvptx64 => {
290                 Self::Nvptx(NvptxInlineAsmReg::parse(arch, has_feature, target, &name)?)
291             }
292             InlineAsmArch::PowerPC | InlineAsmArch::PowerPC64 => {
293                 Self::PowerPC(PowerPCInlineAsmReg::parse(arch, has_feature, target, &name)?)
294             }
295             InlineAsmArch::Hexagon => {
296                 Self::Hexagon(HexagonInlineAsmReg::parse(arch, has_feature, target, &name)?)
297             }
298             InlineAsmArch::Mips | InlineAsmArch::Mips64 => {
299                 Self::Mips(MipsInlineAsmReg::parse(arch, has_feature, target, &name)?)
300             }
301             InlineAsmArch::SpirV => {
302                 Self::SpirV(SpirVInlineAsmReg::parse(arch, has_feature, target, &name)?)
303             }
304             InlineAsmArch::Wasm32 => {
305                 Self::Wasm(WasmInlineAsmReg::parse(arch, has_feature, target, &name)?)
306             }
307         })
308     }
309 
310     // NOTE: This function isn't used at the moment, but is needed to support
311     // falling back to an external assembler.
emit( self, out: &mut dyn fmt::Write, arch: InlineAsmArch, modifier: Option<char>, ) -> fmt::Result312     pub fn emit(
313         self,
314         out: &mut dyn fmt::Write,
315         arch: InlineAsmArch,
316         modifier: Option<char>,
317     ) -> fmt::Result {
318         match self {
319             Self::X86(r) => r.emit(out, arch, modifier),
320             Self::Arm(r) => r.emit(out, arch, modifier),
321             Self::AArch64(r) => r.emit(out, arch, modifier),
322             Self::RiscV(r) => r.emit(out, arch, modifier),
323             Self::PowerPC(r) => r.emit(out, arch, modifier),
324             Self::Hexagon(r) => r.emit(out, arch, modifier),
325             Self::Mips(r) => r.emit(out, arch, modifier),
326             Self::Err => unreachable!("Use of InlineAsmReg::Err"),
327         }
328     }
329 
overlapping_regs(self, mut cb: impl FnMut(InlineAsmReg))330     pub fn overlapping_regs(self, mut cb: impl FnMut(InlineAsmReg)) {
331         match self {
332             Self::X86(r) => r.overlapping_regs(|r| cb(Self::X86(r))),
333             Self::Arm(r) => r.overlapping_regs(|r| cb(Self::Arm(r))),
334             Self::AArch64(_) => cb(self),
335             Self::RiscV(_) => cb(self),
336             Self::PowerPC(_) => cb(self),
337             Self::Hexagon(r) => r.overlapping_regs(|r| cb(Self::Hexagon(r))),
338             Self::Mips(_) => cb(self),
339             Self::Err => unreachable!("Use of InlineAsmReg::Err"),
340         }
341     }
342 }
343 
344 #[derive(
345     Copy,
346     Clone,
347     Encodable,
348     Decodable,
349     Debug,
350     Eq,
351     PartialEq,
352     PartialOrd,
353     Hash,
354     HashStable_Generic
355 )]
356 pub enum InlineAsmRegClass {
357     X86(X86InlineAsmRegClass),
358     Arm(ArmInlineAsmRegClass),
359     AArch64(AArch64InlineAsmRegClass),
360     RiscV(RiscVInlineAsmRegClass),
361     Nvptx(NvptxInlineAsmRegClass),
362     PowerPC(PowerPCInlineAsmRegClass),
363     Hexagon(HexagonInlineAsmRegClass),
364     Mips(MipsInlineAsmRegClass),
365     SpirV(SpirVInlineAsmRegClass),
366     Wasm(WasmInlineAsmRegClass),
367     // Placeholder for invalid register constraints for the current target
368     Err,
369 }
370 
371 impl InlineAsmRegClass {
name(self) -> Symbol372     pub fn name(self) -> Symbol {
373         match self {
374             Self::X86(r) => r.name(),
375             Self::Arm(r) => r.name(),
376             Self::AArch64(r) => r.name(),
377             Self::RiscV(r) => r.name(),
378             Self::Nvptx(r) => r.name(),
379             Self::PowerPC(r) => r.name(),
380             Self::Hexagon(r) => r.name(),
381             Self::Mips(r) => r.name(),
382             Self::SpirV(r) => r.name(),
383             Self::Wasm(r) => r.name(),
384             Self::Err => rustc_span::symbol::sym::reg,
385         }
386     }
387 
388     /// Returns a suggested register class to use for this type. This is called
389     /// after type checking via `supported_types` fails to give a better error
390     /// message to the user.
suggest_class(self, arch: InlineAsmArch, ty: InlineAsmType) -> Option<Self>391     pub fn suggest_class(self, arch: InlineAsmArch, ty: InlineAsmType) -> Option<Self> {
392         match self {
393             Self::X86(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::X86),
394             Self::Arm(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Arm),
395             Self::AArch64(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::AArch64),
396             Self::RiscV(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::RiscV),
397             Self::Nvptx(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Nvptx),
398             Self::PowerPC(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::PowerPC),
399             Self::Hexagon(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Hexagon),
400             Self::Mips(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Mips),
401             Self::SpirV(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::SpirV),
402             Self::Wasm(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Wasm),
403             Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
404         }
405     }
406 
407     /// Returns a suggested template modifier to use for this type and an
408     /// example of a  register named formatted with it.
409     ///
410     /// Such suggestions are useful if a type smaller than the full register
411     /// size is used and a modifier can be used to point to the subregister of
412     /// the correct size.
suggest_modifier( self, arch: InlineAsmArch, ty: InlineAsmType, ) -> Option<(char, &'static str)>413     pub fn suggest_modifier(
414         self,
415         arch: InlineAsmArch,
416         ty: InlineAsmType,
417     ) -> Option<(char, &'static str)> {
418         match self {
419             Self::X86(r) => r.suggest_modifier(arch, ty),
420             Self::Arm(r) => r.suggest_modifier(arch, ty),
421             Self::AArch64(r) => r.suggest_modifier(arch, ty),
422             Self::RiscV(r) => r.suggest_modifier(arch, ty),
423             Self::Nvptx(r) => r.suggest_modifier(arch, ty),
424             Self::PowerPC(r) => r.suggest_modifier(arch, ty),
425             Self::Hexagon(r) => r.suggest_modifier(arch, ty),
426             Self::Mips(r) => r.suggest_modifier(arch, ty),
427             Self::SpirV(r) => r.suggest_modifier(arch, ty),
428             Self::Wasm(r) => r.suggest_modifier(arch, ty),
429             Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
430         }
431     }
432 
433     /// Returns the default modifier for this register and an example of a
434     /// register named formatted with it.
435     ///
436     /// This is only needed when the register class can suggest a modifier, so
437     /// that the user can be shown how to get the default behavior without a
438     /// warning.
default_modifier(self, arch: InlineAsmArch) -> Option<(char, &'static str)>439     pub fn default_modifier(self, arch: InlineAsmArch) -> Option<(char, &'static str)> {
440         match self {
441             Self::X86(r) => r.default_modifier(arch),
442             Self::Arm(r) => r.default_modifier(arch),
443             Self::AArch64(r) => r.default_modifier(arch),
444             Self::RiscV(r) => r.default_modifier(arch),
445             Self::Nvptx(r) => r.default_modifier(arch),
446             Self::PowerPC(r) => r.default_modifier(arch),
447             Self::Hexagon(r) => r.default_modifier(arch),
448             Self::Mips(r) => r.default_modifier(arch),
449             Self::SpirV(r) => r.default_modifier(arch),
450             Self::Wasm(r) => r.default_modifier(arch),
451             Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
452         }
453     }
454 
455     /// Returns a list of supported types for this register class, each with a
456     /// options target feature required to use this type.
supported_types( self, arch: InlineAsmArch, ) -> &'static [(InlineAsmType, Option<&'static str>)]457     pub fn supported_types(
458         self,
459         arch: InlineAsmArch,
460     ) -> &'static [(InlineAsmType, Option<&'static str>)] {
461         match self {
462             Self::X86(r) => r.supported_types(arch),
463             Self::Arm(r) => r.supported_types(arch),
464             Self::AArch64(r) => r.supported_types(arch),
465             Self::RiscV(r) => r.supported_types(arch),
466             Self::Nvptx(r) => r.supported_types(arch),
467             Self::PowerPC(r) => r.supported_types(arch),
468             Self::Hexagon(r) => r.supported_types(arch),
469             Self::Mips(r) => r.supported_types(arch),
470             Self::SpirV(r) => r.supported_types(arch),
471             Self::Wasm(r) => r.supported_types(arch),
472             Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
473         }
474     }
475 
parse(arch: InlineAsmArch, name: Symbol) -> Result<Self, &'static str>476     pub fn parse(arch: InlineAsmArch, name: Symbol) -> Result<Self, &'static str> {
477         Ok(match arch {
478             InlineAsmArch::X86 | InlineAsmArch::X86_64 => {
479                 Self::X86(X86InlineAsmRegClass::parse(arch, name)?)
480             }
481             InlineAsmArch::Arm => Self::Arm(ArmInlineAsmRegClass::parse(arch, name)?),
482             InlineAsmArch::AArch64 => Self::AArch64(AArch64InlineAsmRegClass::parse(arch, name)?),
483             InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
484                 Self::RiscV(RiscVInlineAsmRegClass::parse(arch, name)?)
485             }
486             InlineAsmArch::Nvptx64 => Self::Nvptx(NvptxInlineAsmRegClass::parse(arch, name)?),
487             InlineAsmArch::PowerPC | InlineAsmArch::PowerPC64 => {
488                 Self::PowerPC(PowerPCInlineAsmRegClass::parse(arch, name)?)
489             }
490             InlineAsmArch::Hexagon => Self::Hexagon(HexagonInlineAsmRegClass::parse(arch, name)?),
491             InlineAsmArch::Mips | InlineAsmArch::Mips64 => {
492                 Self::Mips(MipsInlineAsmRegClass::parse(arch, name)?)
493             }
494             InlineAsmArch::SpirV => Self::SpirV(SpirVInlineAsmRegClass::parse(arch, name)?),
495             InlineAsmArch::Wasm32 => Self::Wasm(WasmInlineAsmRegClass::parse(arch, name)?),
496         })
497     }
498 
499     /// Returns the list of template modifiers that can be used with this
500     /// register class.
valid_modifiers(self, arch: InlineAsmArch) -> &'static [char]501     pub fn valid_modifiers(self, arch: InlineAsmArch) -> &'static [char] {
502         match self {
503             Self::X86(r) => r.valid_modifiers(arch),
504             Self::Arm(r) => r.valid_modifiers(arch),
505             Self::AArch64(r) => r.valid_modifiers(arch),
506             Self::RiscV(r) => r.valid_modifiers(arch),
507             Self::Nvptx(r) => r.valid_modifiers(arch),
508             Self::PowerPC(r) => r.valid_modifiers(arch),
509             Self::Hexagon(r) => r.valid_modifiers(arch),
510             Self::Mips(r) => r.valid_modifiers(arch),
511             Self::SpirV(r) => r.valid_modifiers(arch),
512             Self::Wasm(r) => r.valid_modifiers(arch),
513             Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
514         }
515     }
516 }
517 
518 #[derive(
519     Copy,
520     Clone,
521     Encodable,
522     Decodable,
523     Debug,
524     Eq,
525     PartialEq,
526     PartialOrd,
527     Hash,
528     HashStable_Generic
529 )]
530 pub enum InlineAsmRegOrRegClass {
531     Reg(InlineAsmReg),
532     RegClass(InlineAsmRegClass),
533 }
534 
535 impl InlineAsmRegOrRegClass {
reg_class(self) -> InlineAsmRegClass536     pub fn reg_class(self) -> InlineAsmRegClass {
537         match self {
538             Self::Reg(r) => r.reg_class(),
539             Self::RegClass(r) => r,
540         }
541     }
542 }
543 
544 impl fmt::Display for InlineAsmRegOrRegClass {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result545     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
546         match self {
547             Self::Reg(r) => write!(f, "\"{}\"", r.name()),
548             Self::RegClass(r) => write!(f, "{}", r.name()),
549         }
550     }
551 }
552 
553 /// Set of types which can be used with a particular register class.
554 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
555 pub enum InlineAsmType {
556     I8,
557     I16,
558     I32,
559     I64,
560     I128,
561     F32,
562     F64,
563     VecI8(u64),
564     VecI16(u64),
565     VecI32(u64),
566     VecI64(u64),
567     VecI128(u64),
568     VecF32(u64),
569     VecF64(u64),
570 }
571 
572 impl InlineAsmType {
is_integer(self) -> bool573     pub fn is_integer(self) -> bool {
574         matches!(self, Self::I8 | Self::I16 | Self::I32 | Self::I64 | Self::I128)
575     }
576 
size(self) -> Size577     pub fn size(self) -> Size {
578         Size::from_bytes(match self {
579             Self::I8 => 1,
580             Self::I16 => 2,
581             Self::I32 => 4,
582             Self::I64 => 8,
583             Self::I128 => 16,
584             Self::F32 => 4,
585             Self::F64 => 8,
586             Self::VecI8(n) => n * 1,
587             Self::VecI16(n) => n * 2,
588             Self::VecI32(n) => n * 4,
589             Self::VecI64(n) => n * 8,
590             Self::VecI128(n) => n * 16,
591             Self::VecF32(n) => n * 4,
592             Self::VecF64(n) => n * 8,
593         })
594     }
595 }
596 
597 impl fmt::Display for InlineAsmType {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result598     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
599         match *self {
600             Self::I8 => f.write_str("i8"),
601             Self::I16 => f.write_str("i16"),
602             Self::I32 => f.write_str("i32"),
603             Self::I64 => f.write_str("i64"),
604             Self::I128 => f.write_str("i128"),
605             Self::F32 => f.write_str("f32"),
606             Self::F64 => f.write_str("f64"),
607             Self::VecI8(n) => write!(f, "i8x{}", n),
608             Self::VecI16(n) => write!(f, "i16x{}", n),
609             Self::VecI32(n) => write!(f, "i32x{}", n),
610             Self::VecI64(n) => write!(f, "i64x{}", n),
611             Self::VecI128(n) => write!(f, "i128x{}", n),
612             Self::VecF32(n) => write!(f, "f32x{}", n),
613             Self::VecF64(n) => write!(f, "f64x{}", n),
614         }
615     }
616 }
617 
618 /// Returns the full set of allocatable registers for a given architecture.
619 ///
620 /// The registers are structured as a map containing the set of allocatable
621 /// registers in each register class. A particular register may be allocatable
622 /// from multiple register classes, in which case it will appear multiple times
623 /// in the map.
624 // NOTE: This function isn't used at the moment, but is needed to support
625 // falling back to an external assembler.
allocatable_registers( arch: InlineAsmArch, has_feature: impl FnMut(&str) -> bool, target: &crate::spec::Target, ) -> FxHashMap<InlineAsmRegClass, FxHashSet<InlineAsmReg>>626 pub fn allocatable_registers(
627     arch: InlineAsmArch,
628     has_feature: impl FnMut(&str) -> bool,
629     target: &crate::spec::Target,
630 ) -> FxHashMap<InlineAsmRegClass, FxHashSet<InlineAsmReg>> {
631     match arch {
632         InlineAsmArch::X86 | InlineAsmArch::X86_64 => {
633             let mut map = x86::regclass_map();
634             x86::fill_reg_map(arch, has_feature, target, &mut map);
635             map
636         }
637         InlineAsmArch::Arm => {
638             let mut map = arm::regclass_map();
639             arm::fill_reg_map(arch, has_feature, target, &mut map);
640             map
641         }
642         InlineAsmArch::AArch64 => {
643             let mut map = aarch64::regclass_map();
644             aarch64::fill_reg_map(arch, has_feature, target, &mut map);
645             map
646         }
647         InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
648             let mut map = riscv::regclass_map();
649             riscv::fill_reg_map(arch, has_feature, target, &mut map);
650             map
651         }
652         InlineAsmArch::Nvptx64 => {
653             let mut map = nvptx::regclass_map();
654             nvptx::fill_reg_map(arch, has_feature, target, &mut map);
655             map
656         }
657         InlineAsmArch::PowerPC | InlineAsmArch::PowerPC64 => {
658             let mut map = powerpc::regclass_map();
659             powerpc::fill_reg_map(arch, has_feature, target, &mut map);
660             map
661         }
662         InlineAsmArch::Hexagon => {
663             let mut map = hexagon::regclass_map();
664             hexagon::fill_reg_map(arch, has_feature, target, &mut map);
665             map
666         }
667         InlineAsmArch::Mips | InlineAsmArch::Mips64 => {
668             let mut map = mips::regclass_map();
669             mips::fill_reg_map(arch, has_feature, target, &mut map);
670             map
671         }
672         InlineAsmArch::SpirV => {
673             let mut map = spirv::regclass_map();
674             spirv::fill_reg_map(arch, has_feature, target, &mut map);
675             map
676         }
677         InlineAsmArch::Wasm32 => {
678             let mut map = wasm::regclass_map();
679             wasm::fill_reg_map(arch, has_feature, target, &mut map);
680             map
681         }
682     }
683 }
684