]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_target/src/asm/mod.rs
Rollup merge of #97113 - GuillaumeGomez:search-ui-fixes, r=notriddle
[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                     tmm0, tmm1, tmm2, tmm3, tmm4, tmm5, tmm6, tmm7,
916                 }
917             },
918             InlineAsmClobberAbi::X86_64Win => clobbered_regs! {
919                 X86 X86InlineAsmReg {
920                     // rdi and rsi are callee-saved on windows
921                     ax, cx, dx, r8, r9, r10, r11,
922
923                     // xmm6-xmm15 are callee-saved on windows, but we need to
924                     // mark them as clobbered anyways because the upper portions
925                     // of ymm6-ymm15 are volatile.
926                     xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7,
927                     xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15,
928                     zmm16, zmm17, zmm18, zmm19, zmm20, zmm21, zmm22, zmm23,
929                     zmm24, zmm25, zmm26, zmm27, zmm28, zmm29, zmm30, zmm31,
930
931                     k0, k1, k2, k3, k4, k5, k6, k7,
932
933                     mm0, mm1, mm2, mm3, mm4, mm5, mm6, mm7,
934                     st0, st1, st2, st3, st4, st5, st6, st7,
935                     tmm0, tmm1, tmm2, tmm3, tmm4, tmm5, tmm6, tmm7,
936                 }
937             },
938             InlineAsmClobberAbi::AArch64 => clobbered_regs! {
939                 AArch64 AArch64InlineAsmReg {
940                     x0, x1, x2, x3, x4, x5, x6, x7,
941                     x8, x9, x10, x11, x12, x13, x14, x15,
942                     x16, x17, x18, x30,
943
944                     // Technically the low 64 bits of v8-v15 are preserved, but
945                     // we have no way of expressing this using clobbers.
946                     v0, v1, v2, v3, v4, v5, v6, v7,
947                     v8, v9, v10, v11, v12, v13, v14, v15,
948                     v16, v17, v18, v19, v20, v21, v22, v23,
949                     v24, v25, v26, v27, v28, v29, v30, v31,
950
951                     p0, p1, p2, p3, p4, p5, p6, p7,
952                     p8, p9, p10, p11, p12, p13, p14, p15,
953                     ffr,
954
955                 }
956             },
957             InlineAsmClobberAbi::AArch64NoX18 => clobbered_regs! {
958                 AArch64 AArch64InlineAsmReg {
959                     x0, x1, x2, x3, x4, x5, x6, x7,
960                     x8, x9, x10, x11, x12, x13, x14, x15,
961                     x16, x17, x30,
962
963                     // Technically the low 64 bits of v8-v15 are preserved, but
964                     // we have no way of expressing this using clobbers.
965                     v0, v1, v2, v3, v4, v5, v6, v7,
966                     v8, v9, v10, v11, v12, v13, v14, v15,
967                     v16, v17, v18, v19, v20, v21, v22, v23,
968                     v24, v25, v26, v27, v28, v29, v30, v31,
969
970                     p0, p1, p2, p3, p4, p5, p6, p7,
971                     p8, p9, p10, p11, p12, p13, p14, p15,
972                     ffr,
973
974                 }
975             },
976             InlineAsmClobberAbi::Arm => clobbered_regs! {
977                 Arm ArmInlineAsmReg {
978                     // r9 is either platform-reserved or callee-saved. Either
979                     // way we don't need to clobber it.
980                     r0, r1, r2, r3, r12, r14,
981
982                     // The finest-grained register variant is used here so that
983                     // partial uses of larger registers are properly handled.
984                     s0, s1, s2, s3, s4, s5, s6, s7,
985                     s8, s9, s10, s11, s12, s13, s14, s15,
986                     // s16-s31 are callee-saved
987                     d16, d17, d18, d19, d20, d21, d22, d23,
988                     d24, d25, d26, d27, d28, d29, d30, d31,
989                 }
990             },
991             InlineAsmClobberAbi::RiscV => clobbered_regs! {
992                 RiscV RiscVInlineAsmReg {
993                     // ra
994                     x1,
995                     // t0-t2
996                     x5, x6, x7,
997                     // a0-a7
998                     x10, x11, x12, x13, x14, x15, x16, x17,
999                     // t3-t6
1000                     x28, x29, x30, x31,
1001                     // ft0-ft7
1002                     f0, f1, f2, f3, f4, f5, f6, f7,
1003                     // fa0-fa7
1004                     f10, f11, f12, f13, f14, f15, f16, f17,
1005                     // ft8-ft11
1006                     f28, f29, f30, f31,
1007
1008                     v0, v1, v2, v3, v4, v5, v6, v7,
1009                     v8, v9, v10, v11, v12, v13, v14, v15,
1010                     v16, v17, v18, v19, v20, v21, v22, v23,
1011                     v24, v25, v26, v27, v28, v29, v30, v31,
1012                 }
1013             },
1014         }
1015     }
1016 }