]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_target/src/asm/mod.rs
Auto merge of #96116 - ouz-a:mir-opt, r=oli-obk
[rust.git] / compiler / rustc_target / src / asm / mod.rs
1 use crate::spec::Target;
2 use crate::{abi::Size, spec::RelocModel};
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(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(name: &str) -> Result<Self, &'static str> {
83                 match name {
84                     $(
85                         $($alias)|* | $reg_name => Ok(Self::$reg),
86                     )*
87                     $(
88                         $($bad_reg)|* => Err($error),
89                     )*
90                     _ => Err("unknown register"),
91                 }
92             }
93
94             pub fn validate(self,
95                 _arch: super::InlineAsmArch,
96                 _reloc_model: crate::spec::RelocModel,
97                 _target_features: &rustc_data_structures::fx::FxHashSet<Symbol>,
98                 _target: &crate::spec::Target,
99                 _is_clobber: bool,
100             ) -> Result<(), &'static str> {
101                 match self {
102                     $(
103                         Self::$reg => {
104                             $($filter(
105                                 _arch,
106                                 _reloc_model,
107                                 _target_features,
108                                 _target,
109                                 _is_clobber
110                             )?;)?
111                             Ok(())
112                         }
113                     )*
114                 }
115             }
116         }
117
118         pub(super) fn fill_reg_map(
119             _arch: super::InlineAsmArch,
120             _reloc_model: crate::spec::RelocModel,
121             _target_features: &rustc_data_structures::fx::FxHashSet<Symbol>,
122             _target: &crate::spec::Target,
123             _map: &mut rustc_data_structures::fx::FxHashMap<
124                 super::InlineAsmRegClass,
125                 rustc_data_structures::fx::FxHashSet<super::InlineAsmReg>,
126             >,
127         ) {
128             #[allow(unused_imports)]
129             use super::{InlineAsmReg, InlineAsmRegClass};
130             $(
131                 if $($filter(_arch, _reloc_model, _target_features, _target, false).is_ok() &&)? true {
132                     if let Some(set) = _map.get_mut(&InlineAsmRegClass::$arch($arch_regclass::$class)) {
133                         set.insert(InlineAsmReg::$arch($arch_reg::$reg));
134                     }
135                     $(
136                         if let Some(set) = _map.get_mut(&InlineAsmRegClass::$arch($arch_regclass::$extra_class)) {
137                             set.insert(InlineAsmReg::$arch($arch_reg::$reg));
138                         }
139                     )*
140                 }
141             )*
142         }
143     }
144 }
145
146 macro_rules! types {
147     (
148         $(_ : $($ty:expr),+;)?
149         $($feature:ident: $($ty2:expr),+;)*
150     ) => {
151         {
152             use super::InlineAsmType::*;
153             &[
154                 $($(
155                     ($ty, None),
156                 )*)?
157                 $($(
158                     ($ty2, Some(rustc_span::sym::$feature)),
159                 )*)*
160             ]
161         }
162     };
163 }
164
165 mod aarch64;
166 mod arm;
167 mod avr;
168 mod bpf;
169 mod hexagon;
170 mod mips;
171 mod msp430;
172 mod nvptx;
173 mod powerpc;
174 mod riscv;
175 mod s390x;
176 mod spirv;
177 mod wasm;
178 mod x86;
179
180 pub use aarch64::{AArch64InlineAsmReg, AArch64InlineAsmRegClass};
181 pub use arm::{ArmInlineAsmReg, ArmInlineAsmRegClass};
182 pub use avr::{AvrInlineAsmReg, AvrInlineAsmRegClass};
183 pub use bpf::{BpfInlineAsmReg, BpfInlineAsmRegClass};
184 pub use hexagon::{HexagonInlineAsmReg, HexagonInlineAsmRegClass};
185 pub use mips::{MipsInlineAsmReg, MipsInlineAsmRegClass};
186 pub use msp430::{Msp430InlineAsmReg, Msp430InlineAsmRegClass};
187 pub use nvptx::{NvptxInlineAsmReg, NvptxInlineAsmRegClass};
188 pub use powerpc::{PowerPCInlineAsmReg, PowerPCInlineAsmRegClass};
189 pub use riscv::{RiscVInlineAsmReg, RiscVInlineAsmRegClass};
190 pub use s390x::{S390xInlineAsmReg, S390xInlineAsmRegClass};
191 pub use spirv::{SpirVInlineAsmReg, SpirVInlineAsmRegClass};
192 pub use wasm::{WasmInlineAsmReg, WasmInlineAsmRegClass};
193 pub use x86::{X86InlineAsmReg, X86InlineAsmRegClass};
194
195 #[derive(Copy, Clone, Encodable, Decodable, Debug, Eq, PartialEq, Hash)]
196 pub enum InlineAsmArch {
197     X86,
198     X86_64,
199     Arm,
200     AArch64,
201     RiscV32,
202     RiscV64,
203     Nvptx64,
204     Hexagon,
205     Mips,
206     Mips64,
207     PowerPC,
208     PowerPC64,
209     S390x,
210     SpirV,
211     Wasm32,
212     Wasm64,
213     Bpf,
214     Avr,
215     Msp430,
216 }
217
218 impl FromStr for InlineAsmArch {
219     type Err = ();
220
221     fn from_str(s: &str) -> Result<InlineAsmArch, ()> {
222         match s {
223             "x86" => Ok(Self::X86),
224             "x86_64" => Ok(Self::X86_64),
225             "arm" => Ok(Self::Arm),
226             "aarch64" => Ok(Self::AArch64),
227             "riscv32" => Ok(Self::RiscV32),
228             "riscv64" => Ok(Self::RiscV64),
229             "nvptx64" => Ok(Self::Nvptx64),
230             "powerpc" => Ok(Self::PowerPC),
231             "powerpc64" => Ok(Self::PowerPC64),
232             "hexagon" => Ok(Self::Hexagon),
233             "mips" => Ok(Self::Mips),
234             "mips64" => Ok(Self::Mips64),
235             "s390x" => Ok(Self::S390x),
236             "spirv" => Ok(Self::SpirV),
237             "wasm32" => Ok(Self::Wasm32),
238             "wasm64" => Ok(Self::Wasm64),
239             "bpf" => Ok(Self::Bpf),
240             "avr" => Ok(Self::Avr),
241             "msp430" => Ok(Self::Msp430),
242             _ => Err(()),
243         }
244     }
245 }
246
247 #[derive(
248     Copy,
249     Clone,
250     Encodable,
251     Decodable,
252     Debug,
253     Eq,
254     PartialEq,
255     PartialOrd,
256     Hash,
257     HashStable_Generic
258 )]
259 pub enum InlineAsmReg {
260     X86(X86InlineAsmReg),
261     Arm(ArmInlineAsmReg),
262     AArch64(AArch64InlineAsmReg),
263     RiscV(RiscVInlineAsmReg),
264     Nvptx(NvptxInlineAsmReg),
265     PowerPC(PowerPCInlineAsmReg),
266     Hexagon(HexagonInlineAsmReg),
267     Mips(MipsInlineAsmReg),
268     S390x(S390xInlineAsmReg),
269     SpirV(SpirVInlineAsmReg),
270     Wasm(WasmInlineAsmReg),
271     Bpf(BpfInlineAsmReg),
272     Avr(AvrInlineAsmReg),
273     Msp430(Msp430InlineAsmReg),
274     // Placeholder for invalid register constraints for the current target
275     Err,
276 }
277
278 impl InlineAsmReg {
279     pub fn name(self) -> &'static str {
280         match self {
281             Self::X86(r) => r.name(),
282             Self::Arm(r) => r.name(),
283             Self::AArch64(r) => r.name(),
284             Self::RiscV(r) => r.name(),
285             Self::PowerPC(r) => r.name(),
286             Self::Hexagon(r) => r.name(),
287             Self::Mips(r) => r.name(),
288             Self::S390x(r) => r.name(),
289             Self::Bpf(r) => r.name(),
290             Self::Avr(r) => r.name(),
291             Self::Msp430(r) => r.name(),
292             Self::Err => "<reg>",
293         }
294     }
295
296     pub fn reg_class(self) -> InlineAsmRegClass {
297         match self {
298             Self::X86(r) => InlineAsmRegClass::X86(r.reg_class()),
299             Self::Arm(r) => InlineAsmRegClass::Arm(r.reg_class()),
300             Self::AArch64(r) => InlineAsmRegClass::AArch64(r.reg_class()),
301             Self::RiscV(r) => InlineAsmRegClass::RiscV(r.reg_class()),
302             Self::PowerPC(r) => InlineAsmRegClass::PowerPC(r.reg_class()),
303             Self::Hexagon(r) => InlineAsmRegClass::Hexagon(r.reg_class()),
304             Self::Mips(r) => InlineAsmRegClass::Mips(r.reg_class()),
305             Self::S390x(r) => InlineAsmRegClass::S390x(r.reg_class()),
306             Self::Bpf(r) => InlineAsmRegClass::Bpf(r.reg_class()),
307             Self::Avr(r) => InlineAsmRegClass::Avr(r.reg_class()),
308             Self::Msp430(r) => InlineAsmRegClass::Msp430(r.reg_class()),
309             Self::Err => InlineAsmRegClass::Err,
310         }
311     }
312
313     pub fn parse(arch: InlineAsmArch, name: Symbol) -> Result<Self, &'static str> {
314         // FIXME: use direct symbol comparison for register names
315         // Use `Symbol::as_str` instead of `Symbol::with` here because `has_feature` may access `Symbol`.
316         let name = name.as_str();
317         Ok(match arch {
318             InlineAsmArch::X86 | InlineAsmArch::X86_64 => Self::X86(X86InlineAsmReg::parse(name)?),
319             InlineAsmArch::Arm => Self::Arm(ArmInlineAsmReg::parse(name)?),
320             InlineAsmArch::AArch64 => Self::AArch64(AArch64InlineAsmReg::parse(name)?),
321             InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
322                 Self::RiscV(RiscVInlineAsmReg::parse(name)?)
323             }
324             InlineAsmArch::Nvptx64 => Self::Nvptx(NvptxInlineAsmReg::parse(name)?),
325             InlineAsmArch::PowerPC | InlineAsmArch::PowerPC64 => {
326                 Self::PowerPC(PowerPCInlineAsmReg::parse(name)?)
327             }
328             InlineAsmArch::Hexagon => Self::Hexagon(HexagonInlineAsmReg::parse(name)?),
329             InlineAsmArch::Mips | InlineAsmArch::Mips64 => {
330                 Self::Mips(MipsInlineAsmReg::parse(name)?)
331             }
332             InlineAsmArch::S390x => Self::S390x(S390xInlineAsmReg::parse(name)?),
333             InlineAsmArch::SpirV => Self::SpirV(SpirVInlineAsmReg::parse(name)?),
334             InlineAsmArch::Wasm32 | InlineAsmArch::Wasm64 => {
335                 Self::Wasm(WasmInlineAsmReg::parse(name)?)
336             }
337             InlineAsmArch::Bpf => Self::Bpf(BpfInlineAsmReg::parse(name)?),
338             InlineAsmArch::Avr => Self::Avr(AvrInlineAsmReg::parse(name)?),
339             InlineAsmArch::Msp430 => Self::Msp430(Msp430InlineAsmReg::parse(name)?),
340         })
341     }
342
343     pub fn validate(
344         self,
345         arch: InlineAsmArch,
346         reloc_model: RelocModel,
347         target_features: &FxHashSet<Symbol>,
348         target: &Target,
349         is_clobber: bool,
350     ) -> Result<(), &'static str> {
351         match self {
352             Self::X86(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
353             Self::Arm(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
354             Self::AArch64(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
355             Self::RiscV(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
356             Self::PowerPC(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
357             Self::Hexagon(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
358             Self::Mips(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
359             Self::S390x(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
360             Self::Bpf(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
361             Self::Avr(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
362             Self::Msp430(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
363             Self::Err => unreachable!(),
364         }
365     }
366
367     // NOTE: This function isn't used at the moment, but is needed to support
368     // falling back to an external assembler.
369     pub fn emit(
370         self,
371         out: &mut dyn fmt::Write,
372         arch: InlineAsmArch,
373         modifier: Option<char>,
374     ) -> fmt::Result {
375         match self {
376             Self::X86(r) => r.emit(out, arch, modifier),
377             Self::Arm(r) => r.emit(out, arch, modifier),
378             Self::AArch64(r) => r.emit(out, arch, modifier),
379             Self::RiscV(r) => r.emit(out, arch, modifier),
380             Self::PowerPC(r) => r.emit(out, arch, modifier),
381             Self::Hexagon(r) => r.emit(out, arch, modifier),
382             Self::Mips(r) => r.emit(out, arch, modifier),
383             Self::S390x(r) => r.emit(out, arch, modifier),
384             Self::Bpf(r) => r.emit(out, arch, modifier),
385             Self::Avr(r) => r.emit(out, arch, modifier),
386             Self::Msp430(r) => r.emit(out, arch, modifier),
387             Self::Err => unreachable!("Use of InlineAsmReg::Err"),
388         }
389     }
390
391     pub fn overlapping_regs(self, mut cb: impl FnMut(InlineAsmReg)) {
392         match self {
393             Self::X86(r) => r.overlapping_regs(|r| cb(Self::X86(r))),
394             Self::Arm(r) => r.overlapping_regs(|r| cb(Self::Arm(r))),
395             Self::AArch64(_) => cb(self),
396             Self::RiscV(_) => cb(self),
397             Self::PowerPC(r) => r.overlapping_regs(|r| cb(Self::PowerPC(r))),
398             Self::Hexagon(r) => r.overlapping_regs(|r| cb(Self::Hexagon(r))),
399             Self::Mips(_) => cb(self),
400             Self::S390x(_) => cb(self),
401             Self::Bpf(r) => r.overlapping_regs(|r| cb(Self::Bpf(r))),
402             Self::Avr(r) => r.overlapping_regs(|r| cb(Self::Avr(r))),
403             Self::Msp430(_) => cb(self),
404             Self::Err => unreachable!("Use of InlineAsmReg::Err"),
405         }
406     }
407 }
408
409 #[derive(
410     Copy,
411     Clone,
412     Encodable,
413     Decodable,
414     Debug,
415     Eq,
416     PartialEq,
417     PartialOrd,
418     Hash,
419     HashStable_Generic
420 )]
421 pub enum InlineAsmRegClass {
422     X86(X86InlineAsmRegClass),
423     Arm(ArmInlineAsmRegClass),
424     AArch64(AArch64InlineAsmRegClass),
425     RiscV(RiscVInlineAsmRegClass),
426     Nvptx(NvptxInlineAsmRegClass),
427     PowerPC(PowerPCInlineAsmRegClass),
428     Hexagon(HexagonInlineAsmRegClass),
429     Mips(MipsInlineAsmRegClass),
430     S390x(S390xInlineAsmRegClass),
431     SpirV(SpirVInlineAsmRegClass),
432     Wasm(WasmInlineAsmRegClass),
433     Bpf(BpfInlineAsmRegClass),
434     Avr(AvrInlineAsmRegClass),
435     Msp430(Msp430InlineAsmRegClass),
436     // Placeholder for invalid register constraints for the current target
437     Err,
438 }
439
440 impl InlineAsmRegClass {
441     pub fn name(self) -> Symbol {
442         match self {
443             Self::X86(r) => r.name(),
444             Self::Arm(r) => r.name(),
445             Self::AArch64(r) => r.name(),
446             Self::RiscV(r) => r.name(),
447             Self::Nvptx(r) => r.name(),
448             Self::PowerPC(r) => r.name(),
449             Self::Hexagon(r) => r.name(),
450             Self::Mips(r) => r.name(),
451             Self::S390x(r) => r.name(),
452             Self::SpirV(r) => r.name(),
453             Self::Wasm(r) => r.name(),
454             Self::Bpf(r) => r.name(),
455             Self::Avr(r) => r.name(),
456             Self::Msp430(r) => r.name(),
457             Self::Err => rustc_span::symbol::sym::reg,
458         }
459     }
460
461     /// Returns a suggested register class to use for this type. This is called
462     /// when `supported_types` fails to give a better error
463     /// message to the user.
464     pub fn suggest_class(self, arch: InlineAsmArch, ty: InlineAsmType) -> Option<Self> {
465         match self {
466             Self::X86(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::X86),
467             Self::Arm(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Arm),
468             Self::AArch64(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::AArch64),
469             Self::RiscV(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::RiscV),
470             Self::Nvptx(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Nvptx),
471             Self::PowerPC(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::PowerPC),
472             Self::Hexagon(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Hexagon),
473             Self::Mips(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Mips),
474             Self::S390x(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::S390x),
475             Self::SpirV(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::SpirV),
476             Self::Wasm(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Wasm),
477             Self::Bpf(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Bpf),
478             Self::Avr(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Avr),
479             Self::Msp430(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Msp430),
480             Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
481         }
482     }
483
484     /// Returns a suggested template modifier to use for this type and an
485     /// example of a  register named formatted with it.
486     ///
487     /// Such suggestions are useful if a type smaller than the full register
488     /// size is used and a modifier can be used to point to the subregister of
489     /// the correct size.
490     pub fn suggest_modifier(
491         self,
492         arch: InlineAsmArch,
493         ty: InlineAsmType,
494     ) -> Option<(char, &'static str)> {
495         match self {
496             Self::X86(r) => r.suggest_modifier(arch, ty),
497             Self::Arm(r) => r.suggest_modifier(arch, ty),
498             Self::AArch64(r) => r.suggest_modifier(arch, ty),
499             Self::RiscV(r) => r.suggest_modifier(arch, ty),
500             Self::Nvptx(r) => r.suggest_modifier(arch, ty),
501             Self::PowerPC(r) => r.suggest_modifier(arch, ty),
502             Self::Hexagon(r) => r.suggest_modifier(arch, ty),
503             Self::Mips(r) => r.suggest_modifier(arch, ty),
504             Self::S390x(r) => r.suggest_modifier(arch, ty),
505             Self::SpirV(r) => r.suggest_modifier(arch, ty),
506             Self::Wasm(r) => r.suggest_modifier(arch, ty),
507             Self::Bpf(r) => r.suggest_modifier(arch, ty),
508             Self::Avr(r) => r.suggest_modifier(arch, ty),
509             Self::Msp430(r) => r.suggest_modifier(arch, ty),
510             Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
511         }
512     }
513
514     /// Returns the default modifier for this register and an example of a
515     /// register named formatted with it.
516     ///
517     /// This is only needed when the register class can suggest a modifier, so
518     /// that the user can be shown how to get the default behavior without a
519     /// warning.
520     pub fn default_modifier(self, arch: InlineAsmArch) -> Option<(char, &'static str)> {
521         match self {
522             Self::X86(r) => r.default_modifier(arch),
523             Self::Arm(r) => r.default_modifier(arch),
524             Self::AArch64(r) => r.default_modifier(arch),
525             Self::RiscV(r) => r.default_modifier(arch),
526             Self::Nvptx(r) => r.default_modifier(arch),
527             Self::PowerPC(r) => r.default_modifier(arch),
528             Self::Hexagon(r) => r.default_modifier(arch),
529             Self::Mips(r) => r.default_modifier(arch),
530             Self::S390x(r) => r.default_modifier(arch),
531             Self::SpirV(r) => r.default_modifier(arch),
532             Self::Wasm(r) => r.default_modifier(arch),
533             Self::Bpf(r) => r.default_modifier(arch),
534             Self::Avr(r) => r.default_modifier(arch),
535             Self::Msp430(r) => r.default_modifier(arch),
536             Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
537         }
538     }
539
540     /// Returns a list of supported types for this register class, each with an
541     /// options target feature required to use this type.
542     pub fn supported_types(
543         self,
544         arch: InlineAsmArch,
545     ) -> &'static [(InlineAsmType, Option<Symbol>)] {
546         match self {
547             Self::X86(r) => r.supported_types(arch),
548             Self::Arm(r) => r.supported_types(arch),
549             Self::AArch64(r) => r.supported_types(arch),
550             Self::RiscV(r) => r.supported_types(arch),
551             Self::Nvptx(r) => r.supported_types(arch),
552             Self::PowerPC(r) => r.supported_types(arch),
553             Self::Hexagon(r) => r.supported_types(arch),
554             Self::Mips(r) => r.supported_types(arch),
555             Self::S390x(r) => r.supported_types(arch),
556             Self::SpirV(r) => r.supported_types(arch),
557             Self::Wasm(r) => r.supported_types(arch),
558             Self::Bpf(r) => r.supported_types(arch),
559             Self::Avr(r) => r.supported_types(arch),
560             Self::Msp430(r) => r.supported_types(arch),
561             Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
562         }
563     }
564
565     pub fn parse(arch: InlineAsmArch, name: Symbol) -> Result<Self, &'static str> {
566         Ok(match arch {
567             InlineAsmArch::X86 | InlineAsmArch::X86_64 => {
568                 Self::X86(X86InlineAsmRegClass::parse(name)?)
569             }
570             InlineAsmArch::Arm => Self::Arm(ArmInlineAsmRegClass::parse(name)?),
571             InlineAsmArch::AArch64 => Self::AArch64(AArch64InlineAsmRegClass::parse(name)?),
572             InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
573                 Self::RiscV(RiscVInlineAsmRegClass::parse(name)?)
574             }
575             InlineAsmArch::Nvptx64 => Self::Nvptx(NvptxInlineAsmRegClass::parse(name)?),
576             InlineAsmArch::PowerPC | InlineAsmArch::PowerPC64 => {
577                 Self::PowerPC(PowerPCInlineAsmRegClass::parse(name)?)
578             }
579             InlineAsmArch::Hexagon => Self::Hexagon(HexagonInlineAsmRegClass::parse(name)?),
580             InlineAsmArch::Mips | InlineAsmArch::Mips64 => {
581                 Self::Mips(MipsInlineAsmRegClass::parse(name)?)
582             }
583             InlineAsmArch::S390x => Self::S390x(S390xInlineAsmRegClass::parse(name)?),
584             InlineAsmArch::SpirV => Self::SpirV(SpirVInlineAsmRegClass::parse(name)?),
585             InlineAsmArch::Wasm32 | InlineAsmArch::Wasm64 => {
586                 Self::Wasm(WasmInlineAsmRegClass::parse(name)?)
587             }
588             InlineAsmArch::Bpf => Self::Bpf(BpfInlineAsmRegClass::parse(name)?),
589             InlineAsmArch::Avr => Self::Avr(AvrInlineAsmRegClass::parse(name)?),
590             InlineAsmArch::Msp430 => Self::Msp430(Msp430InlineAsmRegClass::parse(name)?),
591         })
592     }
593
594     /// Returns the list of template modifiers that can be used with this
595     /// register class.
596     pub fn valid_modifiers(self, arch: InlineAsmArch) -> &'static [char] {
597         match self {
598             Self::X86(r) => r.valid_modifiers(arch),
599             Self::Arm(r) => r.valid_modifiers(arch),
600             Self::AArch64(r) => r.valid_modifiers(arch),
601             Self::RiscV(r) => r.valid_modifiers(arch),
602             Self::Nvptx(r) => r.valid_modifiers(arch),
603             Self::PowerPC(r) => r.valid_modifiers(arch),
604             Self::Hexagon(r) => r.valid_modifiers(arch),
605             Self::Mips(r) => r.valid_modifiers(arch),
606             Self::S390x(r) => r.valid_modifiers(arch),
607             Self::SpirV(r) => r.valid_modifiers(arch),
608             Self::Wasm(r) => r.valid_modifiers(arch),
609             Self::Bpf(r) => r.valid_modifiers(arch),
610             Self::Avr(r) => r.valid_modifiers(arch),
611             Self::Msp430(r) => r.valid_modifiers(arch),
612             Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
613         }
614     }
615
616     /// Returns whether registers in this class can only be used as clobbers
617     /// and not as inputs/outputs.
618     pub fn is_clobber_only(self, arch: InlineAsmArch) -> bool {
619         self.supported_types(arch).is_empty()
620     }
621 }
622
623 #[derive(
624     Copy,
625     Clone,
626     Encodable,
627     Decodable,
628     Debug,
629     Eq,
630     PartialEq,
631     PartialOrd,
632     Hash,
633     HashStable_Generic
634 )]
635 pub enum InlineAsmRegOrRegClass {
636     Reg(InlineAsmReg),
637     RegClass(InlineAsmRegClass),
638 }
639
640 impl InlineAsmRegOrRegClass {
641     pub fn reg_class(self) -> InlineAsmRegClass {
642         match self {
643             Self::Reg(r) => r.reg_class(),
644             Self::RegClass(r) => r,
645         }
646     }
647 }
648
649 impl fmt::Display for InlineAsmRegOrRegClass {
650     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
651         match self {
652             Self::Reg(r) => write!(f, "\"{}\"", r.name()),
653             Self::RegClass(r) => write!(f, "{}", r.name()),
654         }
655     }
656 }
657
658 /// Set of types which can be used with a particular register class.
659 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
660 pub enum InlineAsmType {
661     I8,
662     I16,
663     I32,
664     I64,
665     I128,
666     F32,
667     F64,
668     VecI8(u64),
669     VecI16(u64),
670     VecI32(u64),
671     VecI64(u64),
672     VecI128(u64),
673     VecF32(u64),
674     VecF64(u64),
675 }
676
677 impl InlineAsmType {
678     pub fn is_integer(self) -> bool {
679         matches!(self, Self::I8 | Self::I16 | Self::I32 | Self::I64 | Self::I128)
680     }
681
682     pub fn size(self) -> Size {
683         Size::from_bytes(match self {
684             Self::I8 => 1,
685             Self::I16 => 2,
686             Self::I32 => 4,
687             Self::I64 => 8,
688             Self::I128 => 16,
689             Self::F32 => 4,
690             Self::F64 => 8,
691             Self::VecI8(n) => n * 1,
692             Self::VecI16(n) => n * 2,
693             Self::VecI32(n) => n * 4,
694             Self::VecI64(n) => n * 8,
695             Self::VecI128(n) => n * 16,
696             Self::VecF32(n) => n * 4,
697             Self::VecF64(n) => n * 8,
698         })
699     }
700 }
701
702 impl fmt::Display for InlineAsmType {
703     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
704         match *self {
705             Self::I8 => f.write_str("i8"),
706             Self::I16 => f.write_str("i16"),
707             Self::I32 => f.write_str("i32"),
708             Self::I64 => f.write_str("i64"),
709             Self::I128 => f.write_str("i128"),
710             Self::F32 => f.write_str("f32"),
711             Self::F64 => f.write_str("f64"),
712             Self::VecI8(n) => write!(f, "i8x{}", n),
713             Self::VecI16(n) => write!(f, "i16x{}", n),
714             Self::VecI32(n) => write!(f, "i32x{}", n),
715             Self::VecI64(n) => write!(f, "i64x{}", n),
716             Self::VecI128(n) => write!(f, "i128x{}", n),
717             Self::VecF32(n) => write!(f, "f32x{}", n),
718             Self::VecF64(n) => write!(f, "f64x{}", n),
719         }
720     }
721 }
722
723 /// Returns the full set of allocatable registers for a given architecture.
724 ///
725 /// The registers are structured as a map containing the set of allocatable
726 /// registers in each register class. A particular register may be allocatable
727 /// from multiple register classes, in which case it will appear multiple times
728 /// in the map.
729 // NOTE: This function isn't used at the moment, but is needed to support
730 // falling back to an external assembler.
731 pub fn allocatable_registers(
732     arch: InlineAsmArch,
733     reloc_model: RelocModel,
734     target_features: &FxHashSet<Symbol>,
735     target: &crate::spec::Target,
736 ) -> FxHashMap<InlineAsmRegClass, FxHashSet<InlineAsmReg>> {
737     match arch {
738         InlineAsmArch::X86 | InlineAsmArch::X86_64 => {
739             let mut map = x86::regclass_map();
740             x86::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
741             map
742         }
743         InlineAsmArch::Arm => {
744             let mut map = arm::regclass_map();
745             arm::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
746             map
747         }
748         InlineAsmArch::AArch64 => {
749             let mut map = aarch64::regclass_map();
750             aarch64::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
751             map
752         }
753         InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
754             let mut map = riscv::regclass_map();
755             riscv::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
756             map
757         }
758         InlineAsmArch::Nvptx64 => {
759             let mut map = nvptx::regclass_map();
760             nvptx::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
761             map
762         }
763         InlineAsmArch::PowerPC | InlineAsmArch::PowerPC64 => {
764             let mut map = powerpc::regclass_map();
765             powerpc::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
766             map
767         }
768         InlineAsmArch::Hexagon => {
769             let mut map = hexagon::regclass_map();
770             hexagon::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
771             map
772         }
773         InlineAsmArch::Mips | InlineAsmArch::Mips64 => {
774             let mut map = mips::regclass_map();
775             mips::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
776             map
777         }
778         InlineAsmArch::S390x => {
779             let mut map = s390x::regclass_map();
780             s390x::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
781             map
782         }
783         InlineAsmArch::SpirV => {
784             let mut map = spirv::regclass_map();
785             spirv::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
786             map
787         }
788         InlineAsmArch::Wasm32 | InlineAsmArch::Wasm64 => {
789             let mut map = wasm::regclass_map();
790             wasm::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
791             map
792         }
793         InlineAsmArch::Bpf => {
794             let mut map = bpf::regclass_map();
795             bpf::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
796             map
797         }
798         InlineAsmArch::Avr => {
799             let mut map = avr::regclass_map();
800             avr::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
801             map
802         }
803         InlineAsmArch::Msp430 => {
804             let mut map = msp430::regclass_map();
805             msp430::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
806             map
807         }
808     }
809 }
810
811 #[derive(
812     Copy,
813     Clone,
814     Encodable,
815     Decodable,
816     Debug,
817     Eq,
818     PartialEq,
819     PartialOrd,
820     Hash,
821     HashStable_Generic
822 )]
823 pub enum InlineAsmClobberAbi {
824     X86,
825     X86_64Win,
826     X86_64SysV,
827     Arm,
828     AArch64,
829     AArch64NoX18,
830     RiscV,
831 }
832
833 impl InlineAsmClobberAbi {
834     /// Parses a clobber ABI for the given target, or returns a list of supported
835     /// clobber ABIs for the target.
836     pub fn parse(
837         arch: InlineAsmArch,
838         target: &Target,
839         name: Symbol,
840     ) -> Result<Self, &'static [&'static str]> {
841         let name = name.as_str();
842         match arch {
843             InlineAsmArch::X86 => match name {
844                 "C" | "system" | "efiapi" | "cdecl" | "stdcall" | "fastcall" => {
845                     Ok(InlineAsmClobberAbi::X86)
846                 }
847                 _ => Err(&["C", "system", "efiapi", "cdecl", "stdcall", "fastcall"]),
848             },
849             InlineAsmArch::X86_64 => match name {
850                 "C" | "system" if !target.is_like_windows => Ok(InlineAsmClobberAbi::X86_64SysV),
851                 "C" | "system" if target.is_like_windows => Ok(InlineAsmClobberAbi::X86_64Win),
852                 "win64" | "efiapi" => Ok(InlineAsmClobberAbi::X86_64Win),
853                 "sysv64" => Ok(InlineAsmClobberAbi::X86_64SysV),
854                 _ => Err(&["C", "system", "efiapi", "win64", "sysv64"]),
855             },
856             InlineAsmArch::Arm => match name {
857                 "C" | "system" | "efiapi" | "aapcs" => Ok(InlineAsmClobberAbi::Arm),
858                 _ => Err(&["C", "system", "efiapi", "aapcs"]),
859             },
860             InlineAsmArch::AArch64 => match name {
861                 "C" | "system" | "efiapi" => Ok(if aarch64::target_reserves_x18(target) {
862                     InlineAsmClobberAbi::AArch64NoX18
863                 } else {
864                     InlineAsmClobberAbi::AArch64
865                 }),
866                 _ => Err(&["C", "system", "efiapi"]),
867             },
868             InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => match name {
869                 "C" | "system" | "efiapi" => Ok(InlineAsmClobberAbi::RiscV),
870                 _ => Err(&["C", "system", "efiapi"]),
871             },
872             _ => Err(&[]),
873         }
874     }
875
876     /// Returns the set of registers which are clobbered by this ABI.
877     pub fn clobbered_regs(self) -> &'static [InlineAsmReg] {
878         macro_rules! clobbered_regs {
879             ($arch:ident $arch_reg:ident {
880                 $(
881                     $reg:ident,
882                 )*
883             }) => {
884                 &[
885                     $(InlineAsmReg::$arch($arch_reg::$reg),)*
886                 ]
887             };
888         }
889         match self {
890             InlineAsmClobberAbi::X86 => clobbered_regs! {
891                 X86 X86InlineAsmReg {
892                     ax, cx, dx,
893
894                     xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7,
895
896                     k0, k1, k2, k3, k4, k5, k6, k7,
897
898                     mm0, mm1, mm2, mm3, mm4, mm5, mm6, mm7,
899                     st0, st1, st2, st3, st4, st5, st6, st7,
900                 }
901             },
902             InlineAsmClobberAbi::X86_64SysV => clobbered_regs! {
903                 X86 X86InlineAsmReg {
904                     ax, cx, dx, si, di, r8, r9, r10, r11,
905
906                     xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7,
907                     xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15,
908                     zmm16, zmm17, zmm18, zmm19, zmm20, zmm21, zmm22, zmm23,
909                     zmm24, zmm25, zmm26, zmm27, zmm28, zmm29, zmm30, zmm31,
910
911                     k0, k1, k2, k3, k4, k5, k6, k7,
912
913                     mm0, mm1, mm2, mm3, mm4, mm5, mm6, mm7,
914                     st0, st1, st2, st3, st4, st5, st6, st7,
915                 }
916             },
917             InlineAsmClobberAbi::X86_64Win => clobbered_regs! {
918                 X86 X86InlineAsmReg {
919                     // rdi and rsi are callee-saved on windows
920                     ax, cx, dx, r8, r9, r10, r11,
921
922                     // xmm6-xmm15 are callee-saved on windows, but we need to
923                     // mark them as clobbered anyways because the upper portions
924                     // of ymm6-ymm15 are volatile.
925                     xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7,
926                     xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15,
927                     zmm16, zmm17, zmm18, zmm19, zmm20, zmm21, zmm22, zmm23,
928                     zmm24, zmm25, zmm26, zmm27, zmm28, zmm29, zmm30, zmm31,
929
930                     k0, k1, k2, k3, k4, k5, k6, k7,
931
932                     mm0, mm1, mm2, mm3, mm4, mm5, mm6, mm7,
933                     st0, st1, st2, st3, st4, st5, st6, st7,
934                 }
935             },
936             InlineAsmClobberAbi::AArch64 => clobbered_regs! {
937                 AArch64 AArch64InlineAsmReg {
938                     x0, x1, x2, x3, x4, x5, x6, x7,
939                     x8, x9, x10, x11, x12, x13, x14, x15,
940                     x16, x17, x18, x30,
941
942                     // Technically the low 64 bits of v8-v15 are preserved, but
943                     // we have no way of expressing this using clobbers.
944                     v0, v1, v2, v3, v4, v5, v6, v7,
945                     v8, v9, v10, v11, v12, v13, v14, v15,
946                     v16, v17, v18, v19, v20, v21, v22, v23,
947                     v24, v25, v26, v27, v28, v29, v30, v31,
948
949                     p0, p1, p2, p3, p4, p5, p6, p7,
950                     p8, p9, p10, p11, p12, p13, p14, p15,
951                     ffr,
952
953                 }
954             },
955             InlineAsmClobberAbi::AArch64NoX18 => clobbered_regs! {
956                 AArch64 AArch64InlineAsmReg {
957                     x0, x1, x2, x3, x4, x5, x6, x7,
958                     x8, x9, x10, x11, x12, x13, x14, x15,
959                     x16, x17, x30,
960
961                     // Technically the low 64 bits of v8-v15 are preserved, but
962                     // we have no way of expressing this using clobbers.
963                     v0, v1, v2, v3, v4, v5, v6, v7,
964                     v8, v9, v10, v11, v12, v13, v14, v15,
965                     v16, v17, v18, v19, v20, v21, v22, v23,
966                     v24, v25, v26, v27, v28, v29, v30, v31,
967
968                     p0, p1, p2, p3, p4, p5, p6, p7,
969                     p8, p9, p10, p11, p12, p13, p14, p15,
970                     ffr,
971
972                 }
973             },
974             InlineAsmClobberAbi::Arm => clobbered_regs! {
975                 Arm ArmInlineAsmReg {
976                     // r9 is either platform-reserved or callee-saved. Either
977                     // way we don't need to clobber it.
978                     r0, r1, r2, r3, r12, r14,
979
980                     // The finest-grained register variant is used here so that
981                     // partial uses of larger registers are properly handled.
982                     s0, s1, s2, s3, s4, s5, s6, s7,
983                     s8, s9, s10, s11, s12, s13, s14, s15,
984                     // s16-s31 are callee-saved
985                     d16, d17, d18, d19, d20, d21, d22, d23,
986                     d24, d25, d26, d27, d28, d29, d30, d31,
987                 }
988             },
989             InlineAsmClobberAbi::RiscV => clobbered_regs! {
990                 RiscV RiscVInlineAsmReg {
991                     // ra
992                     x1,
993                     // t0-t2
994                     x5, x6, x7,
995                     // a0-a7
996                     x10, x11, x12, x13, x14, x15, x16, x17,
997                     // t3-t6
998                     x28, x29, x30, x31,
999                     // ft0-ft7
1000                     f0, f1, f2, f3, f4, f5, f6, f7,
1001                     // fa0-fa7
1002                     f10, f11, f12, f13, f14, f15, f16, f17,
1003                     // ft8-ft11
1004                     f28, f29, f30, f31,
1005
1006                     v0, v1, v2, v3, v4, v5, v6, v7,
1007                     v8, v9, v10, v11, v12, v13, v14, v15,
1008                     v16, v17, v18, v19, v20, v21, v22, v23,
1009                     v24, v25, v26, v27, v28, v29, v30, v31,
1010                 }
1011             },
1012         }
1013     }
1014 }