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