]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_target/src/asm/mod.rs
Add support for clobber_abi to asm!
[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     /// Returns whether registers in this class can only be used as clobbers
538     /// and not as inputs/outputs.
539     pub fn is_clobber_only(self, arch: InlineAsmArch) -> bool {
540         self.supported_types(arch).is_empty()
541     }
542 }
543
544 #[derive(
545     Copy,
546     Clone,
547     Encodable,
548     Decodable,
549     Debug,
550     Eq,
551     PartialEq,
552     PartialOrd,
553     Hash,
554     HashStable_Generic
555 )]
556 pub enum InlineAsmRegOrRegClass {
557     Reg(InlineAsmReg),
558     RegClass(InlineAsmRegClass),
559 }
560
561 impl InlineAsmRegOrRegClass {
562     pub fn reg_class(self) -> InlineAsmRegClass {
563         match self {
564             Self::Reg(r) => r.reg_class(),
565             Self::RegClass(r) => r,
566         }
567     }
568 }
569
570 impl fmt::Display for InlineAsmRegOrRegClass {
571     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
572         match self {
573             Self::Reg(r) => write!(f, "\"{}\"", r.name()),
574             Self::RegClass(r) => write!(f, "{}", r.name()),
575         }
576     }
577 }
578
579 /// Set of types which can be used with a particular register class.
580 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
581 pub enum InlineAsmType {
582     I8,
583     I16,
584     I32,
585     I64,
586     I128,
587     F32,
588     F64,
589     VecI8(u64),
590     VecI16(u64),
591     VecI32(u64),
592     VecI64(u64),
593     VecI128(u64),
594     VecF32(u64),
595     VecF64(u64),
596 }
597
598 impl InlineAsmType {
599     pub fn is_integer(self) -> bool {
600         matches!(self, Self::I8 | Self::I16 | Self::I32 | Self::I64 | Self::I128)
601     }
602
603     pub fn size(self) -> Size {
604         Size::from_bytes(match self {
605             Self::I8 => 1,
606             Self::I16 => 2,
607             Self::I32 => 4,
608             Self::I64 => 8,
609             Self::I128 => 16,
610             Self::F32 => 4,
611             Self::F64 => 8,
612             Self::VecI8(n) => n * 1,
613             Self::VecI16(n) => n * 2,
614             Self::VecI32(n) => n * 4,
615             Self::VecI64(n) => n * 8,
616             Self::VecI128(n) => n * 16,
617             Self::VecF32(n) => n * 4,
618             Self::VecF64(n) => n * 8,
619         })
620     }
621 }
622
623 impl fmt::Display for InlineAsmType {
624     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
625         match *self {
626             Self::I8 => f.write_str("i8"),
627             Self::I16 => f.write_str("i16"),
628             Self::I32 => f.write_str("i32"),
629             Self::I64 => f.write_str("i64"),
630             Self::I128 => f.write_str("i128"),
631             Self::F32 => f.write_str("f32"),
632             Self::F64 => f.write_str("f64"),
633             Self::VecI8(n) => write!(f, "i8x{}", n),
634             Self::VecI16(n) => write!(f, "i16x{}", n),
635             Self::VecI32(n) => write!(f, "i32x{}", n),
636             Self::VecI64(n) => write!(f, "i64x{}", n),
637             Self::VecI128(n) => write!(f, "i128x{}", n),
638             Self::VecF32(n) => write!(f, "f32x{}", n),
639             Self::VecF64(n) => write!(f, "f64x{}", n),
640         }
641     }
642 }
643
644 /// Returns the full set of allocatable registers for a given architecture.
645 ///
646 /// The registers are structured as a map containing the set of allocatable
647 /// registers in each register class. A particular register may be allocatable
648 /// from multiple register classes, in which case it will appear multiple times
649 /// in the map.
650 // NOTE: This function isn't used at the moment, but is needed to support
651 // falling back to an external assembler.
652 pub fn allocatable_registers(
653     arch: InlineAsmArch,
654     has_feature: impl FnMut(&str) -> bool,
655     target: &crate::spec::Target,
656 ) -> FxHashMap<InlineAsmRegClass, FxHashSet<InlineAsmReg>> {
657     match arch {
658         InlineAsmArch::X86 | InlineAsmArch::X86_64 => {
659             let mut map = x86::regclass_map();
660             x86::fill_reg_map(arch, has_feature, target, &mut map);
661             map
662         }
663         InlineAsmArch::Arm => {
664             let mut map = arm::regclass_map();
665             arm::fill_reg_map(arch, has_feature, target, &mut map);
666             map
667         }
668         InlineAsmArch::AArch64 => {
669             let mut map = aarch64::regclass_map();
670             aarch64::fill_reg_map(arch, has_feature, target, &mut map);
671             map
672         }
673         InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
674             let mut map = riscv::regclass_map();
675             riscv::fill_reg_map(arch, has_feature, target, &mut map);
676             map
677         }
678         InlineAsmArch::Nvptx64 => {
679             let mut map = nvptx::regclass_map();
680             nvptx::fill_reg_map(arch, has_feature, target, &mut map);
681             map
682         }
683         InlineAsmArch::PowerPC | InlineAsmArch::PowerPC64 => {
684             let mut map = powerpc::regclass_map();
685             powerpc::fill_reg_map(arch, has_feature, target, &mut map);
686             map
687         }
688         InlineAsmArch::Hexagon => {
689             let mut map = hexagon::regclass_map();
690             hexagon::fill_reg_map(arch, has_feature, target, &mut map);
691             map
692         }
693         InlineAsmArch::Mips | InlineAsmArch::Mips64 => {
694             let mut map = mips::regclass_map();
695             mips::fill_reg_map(arch, has_feature, target, &mut map);
696             map
697         }
698         InlineAsmArch::SpirV => {
699             let mut map = spirv::regclass_map();
700             spirv::fill_reg_map(arch, has_feature, target, &mut map);
701             map
702         }
703         InlineAsmArch::Wasm32 => {
704             let mut map = wasm::regclass_map();
705             wasm::fill_reg_map(arch, has_feature, target, &mut map);
706             map
707         }
708         InlineAsmArch::Bpf => {
709             let mut map = bpf::regclass_map();
710             bpf::fill_reg_map(arch, has_feature, target, &mut map);
711             map
712         }
713     }
714 }
715
716 #[derive(
717     Copy,
718     Clone,
719     Encodable,
720     Decodable,
721     Debug,
722     Eq,
723     PartialEq,
724     PartialOrd,
725     Hash,
726     HashStable_Generic
727 )]
728 pub enum InlineAsmClobberAbi {
729     X86,
730     X86_64Win,
731     X86_64SysV,
732     Arm,
733     AArch64,
734     RiscV,
735 }
736
737 impl InlineAsmClobberAbi {
738     /// Parses a clobber ABI for the given target, or returns a list of supported
739     /// clobber ABIs for the target.
740     pub fn parse(
741         arch: InlineAsmArch,
742         target: &Target,
743         name: Symbol,
744     ) -> Result<Self, &'static [&'static str]> {
745         let name = &*name.as_str();
746         match arch {
747             InlineAsmArch::X86 => match name {
748                 "C" | "system" | "efiapi" | "cdecl" | "stdcall" | "fastcall" => {
749                     Ok(InlineAsmClobberAbi::X86)
750                 }
751                 _ => Err(&["C", "system", "efiapi", "cdecl", "stdcall", "fastcall"]),
752             },
753             InlineAsmArch::X86_64 => match name {
754                 "C" | "system" if !target.is_like_windows => Ok(InlineAsmClobberAbi::X86_64SysV),
755                 "C" | "system" if target.is_like_windows => Ok(InlineAsmClobberAbi::X86_64Win),
756                 "win64" | "efiapi" => Ok(InlineAsmClobberAbi::X86_64Win),
757                 "sysv64" => Ok(InlineAsmClobberAbi::X86_64SysV),
758                 _ => Err(&["C", "system", "efiapi", "win64", "sysv64"]),
759             },
760             InlineAsmArch::Arm => match name {
761                 "C" | "system" | "efiapi" | "aapcs" => Ok(InlineAsmClobberAbi::Arm),
762                 _ => Err(&["C", "system", "efiapi", "aapcs"]),
763             },
764             InlineAsmArch::AArch64 => match name {
765                 "C" | "system" | "efiapi" => Ok(InlineAsmClobberAbi::AArch64),
766                 _ => Err(&["C", "system", "efiapi"]),
767             },
768             InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => match name {
769                 "C" | "system" | "efiapi" => Ok(InlineAsmClobberAbi::RiscV),
770                 _ => Err(&["C", "system", "efiapi"]),
771             },
772             _ => Err(&[]),
773         }
774     }
775
776     /// Returns the set of registers which are clobbered by this ABI.
777     pub fn clobbered_regs(self) -> &'static [InlineAsmReg] {
778         macro_rules! clobbered_regs {
779             ($arch:ident $arch_reg:ident {
780                 $(
781                     $reg:ident,
782                 )*
783             }) => {
784                 &[
785                     $(InlineAsmReg::$arch($arch_reg::$reg),)*
786                 ]
787             };
788         }
789         match self {
790             InlineAsmClobberAbi::X86 => clobbered_regs! {
791                 X86 X86InlineAsmReg {
792                     ax, cx, dx,
793
794                     xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7,
795
796                     k1, k2, k3, k4, k5, k6, k7,
797
798                     mm0, mm1, mm2, mm3, mm4, mm5, mm6, mm7,
799                     st0, st1, st2, st3, st4, st5, st6, st7,
800                 }
801             },
802             InlineAsmClobberAbi::X86_64SysV => clobbered_regs! {
803                 X86 X86InlineAsmReg {
804                     ax, cx, dx, si, di, r8, r9, r10, r11,
805
806                     xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7,
807                     xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15,
808                     zmm16, zmm17, zmm18, zmm19, zmm20, zmm21, zmm22, zmm23,
809                     zmm24, zmm25, zmm26, zmm27, zmm28, zmm29, zmm30, zmm31,
810
811                     k1, k2, k3, k4, k5, k6, k7,
812
813                     mm0, mm1, mm2, mm3, mm4, mm5, mm6, mm7,
814                     st0, st1, st2, st3, st4, st5, st6, st7,
815                 }
816             },
817             InlineAsmClobberAbi::X86_64Win => clobbered_regs! {
818                 X86 X86InlineAsmReg {
819                     // rdi and rsi are callee-saved on windows
820                     ax, cx, dx, r8, r9, r10, r11,
821
822                     // xmm6-xmm15 are callee-saved on windows, but we need to
823                     // mark them as clobbered anyways because the upper portions
824                     // of ymm6-ymm15 are volatile.
825                     xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7,
826                     xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15,
827                     zmm16, zmm17, zmm18, zmm19, zmm20, zmm21, zmm22, zmm23,
828                     zmm24, zmm25, zmm26, zmm27, zmm28, zmm29, zmm30, zmm31,
829
830                     k1, k2, k3, k4, k5, k6, k7,
831
832                     mm0, mm1, mm2, mm3, mm4, mm5, mm6, mm7,
833                     st0, st1, st2, st3, st4, st5, st6, st7,
834                 }
835             },
836             InlineAsmClobberAbi::AArch64 => clobbered_regs! {
837                 AArch64 AArch64InlineAsmReg {
838                     x0, x1, x2, x3, x4, x5, x6, x7,
839                     x8, x9, x10, x11, x12, x13, x14, x15,
840                     // x18 is platform-reserved or temporary, but we exclude it
841                     // here since it is a reserved register.
842                     x16, x17, x30,
843
844                     // Technically the low 64 bits of v8-v15 are preserved, but
845                     // we have no way of expressing this using clobbers.
846                     v0, v1, v2, v3, v4, v5, v6, v7,
847                     v8, v9, v10, v11, v12, v13, v14, v15,
848                     v16, v17, v18, v19, v20, v21, v22, v23,
849                     v24, v25, v26, v27, v28, v29, v30, v31,
850
851                     p0, p1, p2, p3, p4, p5, p6, p7,
852                     p8, p9, p10, p11, p12, p13, p14, p15,
853                     ffr,
854
855                 }
856             },
857             InlineAsmClobberAbi::Arm => clobbered_regs! {
858                 Arm ArmInlineAsmReg {
859                     // r9 is platform-reserved and is treated as callee-saved.
860                     r0, r1, r2, r3, r12, r14,
861
862                     // The finest-grained register variant is used here so that
863                     // partial uses of larger registers are properly handled.
864                     s0, s1, s2, s3, s4, s5, s6, s7,
865                     s8, s9, s10, s11, s12, s13, s14, s15,
866                     // s16-s31 are callee-saved
867                     d16, d17, d18, d19, d20, d21, d22, d23,
868                     d24, d25, d26, d27, d28, d29, d30, d31,
869                 }
870             },
871             InlineAsmClobberAbi::RiscV => clobbered_regs! {
872                 RiscV RiscVInlineAsmReg {
873                     // ra
874                     x1,
875                     // t0-t2
876                     x5, x6, x7,
877                     // a0-a7
878                     x10, x11, x12, x13, x14, x15, x16, x17,
879                     // t3-t6
880                     x28, x29, x30, x31,
881                     // ft0-ft7
882                     f0, f1, f2, f3, f4, f5, f6, f7,
883                     // fa0-fa7
884                     f10, f11, f12, f13, f14, f15, f16, f17,
885                     // ft8-ft11
886                     f28, f29, f30, f31,
887
888                     v0, v1, v2, v3, v4, v5, v6, v7,
889                     v8, v9, v10, v11, v12, v13, v14, v15,
890                     v16, v17, v18, v19, v20, v21, v22, v23,
891                     v24, v25, v26, v27, v28, v29, v30, v31,
892                 }
893             },
894         }
895     }
896 }