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