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