rustc_target/asm/
mod.rs

1use std::fmt;
2use std::str::FromStr;
3
4use rustc_abi::Size;
5use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
6use rustc_macros::{Decodable, Encodable, HashStable_Generic};
7use rustc_span::Symbol;
8
9use crate::spec::{RelocModel, Target};
10
11pub struct ModifierInfo {
12    pub modifier: char,
13    pub result: &'static str,
14    pub size: u16,
15}
16
17impl From<(char, &'static str, u16)> for ModifierInfo {
18    fn from((modifier, result, size): (char, &'static str, u16)) -> Self {
19        Self { modifier, result, size }
20    }
21}
22
23macro_rules! def_reg_class {
24    ($arch:ident $arch_regclass:ident {
25        $(
26            $class:ident,
27        )*
28    }) => {
29        #[derive(Copy, Clone, rustc_macros::Encodable, rustc_macros::Decodable, Debug, Eq, PartialEq, PartialOrd, Hash, rustc_macros::HashStable_Generic)]
30        #[allow(non_camel_case_types)]
31        pub enum $arch_regclass {
32            $($class,)*
33        }
34
35        impl $arch_regclass {
36            pub fn name(self) -> rustc_span::Symbol {
37                match self {
38                    $(Self::$class => rustc_span::sym::$class,)*
39                }
40            }
41
42            pub fn parse(name: rustc_span::Symbol) -> Result<Self, &'static [rustc_span::Symbol]> {
43                match name {
44                    $(
45                        rustc_span::sym::$class => Ok(Self::$class),
46                    )*
47                    _ => Err(&[$(rustc_span::sym::$class),*]),
48                }
49            }
50        }
51
52        pub(super) fn regclass_map() -> rustc_data_structures::fx::FxHashMap<
53            super::InlineAsmRegClass,
54            rustc_data_structures::fx::FxIndexSet<super::InlineAsmReg>,
55        > {
56            use rustc_data_structures::fx::FxHashMap;
57            use rustc_data_structures::fx::FxIndexSet;
58            use super::InlineAsmRegClass;
59            let mut map = FxHashMap::default();
60            $(
61                map.insert(InlineAsmRegClass::$arch($arch_regclass::$class), FxIndexSet::default());
62            )*
63            map
64        }
65    }
66}
67
68macro_rules! def_regs {
69    ($arch:ident $arch_reg:ident $arch_regclass:ident {
70        $(
71            $reg:ident: $class:ident $(, $extra_class:ident)* = [$reg_name:literal $(, $alias:literal)*] $(% $filter:ident)?,
72        )*
73        $(
74            #error = [$($bad_reg:literal),+] => $error:literal,
75        )*
76    }) => {
77        #[allow(unreachable_code)]
78        #[derive(Copy, Clone, rustc_macros::Encodable, rustc_macros::Decodable, Debug, Eq, PartialEq, PartialOrd, Hash, rustc_macros::HashStable_Generic)]
79        #[allow(non_camel_case_types)]
80        pub enum $arch_reg {
81            $($reg,)*
82        }
83
84        impl $arch_reg {
85            pub fn name(self) -> &'static str {
86                match self {
87                    $(Self::$reg => $reg_name,)*
88                }
89            }
90
91            pub fn reg_class(self) -> $arch_regclass {
92                match self {
93                    $(Self::$reg => $arch_regclass::$class,)*
94                }
95            }
96
97            pub fn parse(name: &str) -> Result<Self, &'static str> {
98                match name {
99                    $(
100                        $($alias)|* | $reg_name => Ok(Self::$reg),
101                    )*
102                    $(
103                        $($bad_reg)|* => Err($error),
104                    )*
105                    _ => Err("unknown register"),
106                }
107            }
108
109            pub fn validate(self,
110                _arch: super::InlineAsmArch,
111                _reloc_model: crate::spec::RelocModel,
112                _target_features: &rustc_data_structures::fx::FxIndexSet<Symbol>,
113                _target: &crate::spec::Target,
114                _is_clobber: bool,
115            ) -> Result<(), &'static str> {
116                match self {
117                    $(
118                        Self::$reg => {
119                            $($filter(
120                                _arch,
121                                _reloc_model,
122                                _target_features,
123                                _target,
124                                _is_clobber
125                            )?;)?
126                            Ok(())
127                        }
128                    )*
129                }
130            }
131        }
132
133        pub(super) fn fill_reg_map(
134            _arch: super::InlineAsmArch,
135            _reloc_model: crate::spec::RelocModel,
136            _target_features: &rustc_data_structures::fx::FxIndexSet<Symbol>,
137            _target: &crate::spec::Target,
138            _map: &mut rustc_data_structures::fx::FxHashMap<
139                super::InlineAsmRegClass,
140                rustc_data_structures::fx::FxIndexSet<super::InlineAsmReg>,
141            >,
142        ) {
143            #[allow(unused_imports)]
144            use super::{InlineAsmReg, InlineAsmRegClass};
145            $(
146                if $($filter(_arch, _reloc_model, _target_features, _target, false).is_ok() &&)? true {
147                    if let Some(set) = _map.get_mut(&InlineAsmRegClass::$arch($arch_regclass::$class)) {
148                        set.insert(InlineAsmReg::$arch($arch_reg::$reg));
149                    }
150                    $(
151                        if let Some(set) = _map.get_mut(&InlineAsmRegClass::$arch($arch_regclass::$extra_class)) {
152                            set.insert(InlineAsmReg::$arch($arch_reg::$reg));
153                        }
154                    )*
155                }
156            )*
157        }
158    }
159}
160
161macro_rules! types {
162    (
163        $(_ : $($ty:expr),+;)?
164        $($feature:ident: $($ty2:expr),+;)*
165    ) => {
166        {
167            use super::InlineAsmType::*;
168            &[
169                $($(
170                    ($ty, None),
171                )*)?
172                $($(
173                    ($ty2, Some(rustc_span::sym::$feature)),
174                )*)*
175            ]
176        }
177    };
178}
179
180mod aarch64;
181mod arm;
182mod avr;
183mod bpf;
184mod csky;
185mod hexagon;
186mod loongarch;
187mod m68k;
188mod mips;
189mod msp430;
190mod nvptx;
191mod powerpc;
192mod riscv;
193mod s390x;
194mod sparc;
195mod spirv;
196mod wasm;
197mod x86;
198
199pub use aarch64::{AArch64InlineAsmReg, AArch64InlineAsmRegClass};
200pub use arm::{ArmInlineAsmReg, ArmInlineAsmRegClass};
201pub use avr::{AvrInlineAsmReg, AvrInlineAsmRegClass};
202pub use bpf::{BpfInlineAsmReg, BpfInlineAsmRegClass};
203pub use csky::{CSKYInlineAsmReg, CSKYInlineAsmRegClass};
204pub use hexagon::{HexagonInlineAsmReg, HexagonInlineAsmRegClass};
205pub use loongarch::{LoongArchInlineAsmReg, LoongArchInlineAsmRegClass};
206pub use m68k::{M68kInlineAsmReg, M68kInlineAsmRegClass};
207pub use mips::{MipsInlineAsmReg, MipsInlineAsmRegClass};
208pub use msp430::{Msp430InlineAsmReg, Msp430InlineAsmRegClass};
209pub use nvptx::{NvptxInlineAsmReg, NvptxInlineAsmRegClass};
210pub use powerpc::{PowerPCInlineAsmReg, PowerPCInlineAsmRegClass};
211pub use riscv::{RiscVInlineAsmReg, RiscVInlineAsmRegClass};
212pub use s390x::{S390xInlineAsmReg, S390xInlineAsmRegClass};
213pub use sparc::{SparcInlineAsmReg, SparcInlineAsmRegClass};
214pub use spirv::{SpirVInlineAsmReg, SpirVInlineAsmRegClass};
215pub use wasm::{WasmInlineAsmReg, WasmInlineAsmRegClass};
216pub use x86::{X86InlineAsmReg, X86InlineAsmRegClass};
217
218#[derive(Copy, Clone, Encodable, Decodable, Debug, Eq, PartialEq, Hash)]
219pub enum InlineAsmArch {
220    X86,
221    X86_64,
222    Arm,
223    AArch64,
224    Arm64EC,
225    RiscV32,
226    RiscV64,
227    Nvptx64,
228    Hexagon,
229    LoongArch64,
230    Mips,
231    Mips64,
232    PowerPC,
233    PowerPC64,
234    S390x,
235    Sparc,
236    Sparc64,
237    SpirV,
238    Wasm32,
239    Wasm64,
240    Bpf,
241    Avr,
242    Msp430,
243    M68k,
244    CSKY,
245}
246
247impl FromStr for InlineAsmArch {
248    type Err = ();
249
250    fn from_str(s: &str) -> Result<InlineAsmArch, ()> {
251        match s {
252            "x86" => Ok(Self::X86),
253            "x86_64" => Ok(Self::X86_64),
254            "arm" => Ok(Self::Arm),
255            "aarch64" => Ok(Self::AArch64),
256            "arm64ec" => Ok(Self::Arm64EC),
257            "riscv32" => Ok(Self::RiscV32),
258            "riscv64" => Ok(Self::RiscV64),
259            "nvptx64" => Ok(Self::Nvptx64),
260            "powerpc" => Ok(Self::PowerPC),
261            "powerpc64" => Ok(Self::PowerPC64),
262            "hexagon" => Ok(Self::Hexagon),
263            "loongarch64" => Ok(Self::LoongArch64),
264            "mips" | "mips32r6" => Ok(Self::Mips),
265            "mips64" | "mips64r6" => Ok(Self::Mips64),
266            "s390x" => Ok(Self::S390x),
267            "sparc" => Ok(Self::Sparc),
268            "sparc64" => Ok(Self::Sparc64),
269            "spirv" => Ok(Self::SpirV),
270            "wasm32" => Ok(Self::Wasm32),
271            "wasm64" => Ok(Self::Wasm64),
272            "bpf" => Ok(Self::Bpf),
273            "avr" => Ok(Self::Avr),
274            "msp430" => Ok(Self::Msp430),
275            "m68k" => Ok(Self::M68k),
276            "csky" => Ok(Self::CSKY),
277            _ => Err(()),
278        }
279    }
280}
281
282#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Hash)]
283#[derive(HashStable_Generic, Encodable, Decodable)]
284pub enum InlineAsmReg {
285    X86(X86InlineAsmReg),
286    Arm(ArmInlineAsmReg),
287    AArch64(AArch64InlineAsmReg),
288    RiscV(RiscVInlineAsmReg),
289    Nvptx(NvptxInlineAsmReg),
290    PowerPC(PowerPCInlineAsmReg),
291    Hexagon(HexagonInlineAsmReg),
292    LoongArch(LoongArchInlineAsmReg),
293    Mips(MipsInlineAsmReg),
294    S390x(S390xInlineAsmReg),
295    Sparc(SparcInlineAsmReg),
296    SpirV(SpirVInlineAsmReg),
297    Wasm(WasmInlineAsmReg),
298    Bpf(BpfInlineAsmReg),
299    Avr(AvrInlineAsmReg),
300    Msp430(Msp430InlineAsmReg),
301    M68k(M68kInlineAsmReg),
302    CSKY(CSKYInlineAsmReg),
303    // Placeholder for invalid register constraints for the current target
304    Err,
305}
306
307impl InlineAsmReg {
308    pub fn name(self) -> &'static str {
309        match self {
310            Self::X86(r) => r.name(),
311            Self::Arm(r) => r.name(),
312            Self::AArch64(r) => r.name(),
313            Self::RiscV(r) => r.name(),
314            Self::PowerPC(r) => r.name(),
315            Self::Hexagon(r) => r.name(),
316            Self::LoongArch(r) => r.name(),
317            Self::Mips(r) => r.name(),
318            Self::S390x(r) => r.name(),
319            Self::Sparc(r) => r.name(),
320            Self::Bpf(r) => r.name(),
321            Self::Avr(r) => r.name(),
322            Self::Msp430(r) => r.name(),
323            Self::M68k(r) => r.name(),
324            Self::CSKY(r) => r.name(),
325            Self::Err => "<reg>",
326        }
327    }
328
329    pub fn reg_class(self) -> InlineAsmRegClass {
330        match self {
331            Self::X86(r) => InlineAsmRegClass::X86(r.reg_class()),
332            Self::Arm(r) => InlineAsmRegClass::Arm(r.reg_class()),
333            Self::AArch64(r) => InlineAsmRegClass::AArch64(r.reg_class()),
334            Self::RiscV(r) => InlineAsmRegClass::RiscV(r.reg_class()),
335            Self::PowerPC(r) => InlineAsmRegClass::PowerPC(r.reg_class()),
336            Self::Hexagon(r) => InlineAsmRegClass::Hexagon(r.reg_class()),
337            Self::LoongArch(r) => InlineAsmRegClass::LoongArch(r.reg_class()),
338            Self::Mips(r) => InlineAsmRegClass::Mips(r.reg_class()),
339            Self::S390x(r) => InlineAsmRegClass::S390x(r.reg_class()),
340            Self::Sparc(r) => InlineAsmRegClass::Sparc(r.reg_class()),
341            Self::Bpf(r) => InlineAsmRegClass::Bpf(r.reg_class()),
342            Self::Avr(r) => InlineAsmRegClass::Avr(r.reg_class()),
343            Self::Msp430(r) => InlineAsmRegClass::Msp430(r.reg_class()),
344            Self::M68k(r) => InlineAsmRegClass::M68k(r.reg_class()),
345            Self::CSKY(r) => InlineAsmRegClass::CSKY(r.reg_class()),
346            Self::Err => InlineAsmRegClass::Err,
347        }
348    }
349
350    pub fn parse(arch: InlineAsmArch, name: Symbol) -> Result<Self, &'static str> {
351        // FIXME: use direct symbol comparison for register names
352        // Use `Symbol::as_str` instead of `Symbol::with` here because `has_feature` may access `Symbol`.
353        let name = name.as_str();
354        Ok(match arch {
355            InlineAsmArch::X86 | InlineAsmArch::X86_64 => Self::X86(X86InlineAsmReg::parse(name)?),
356            InlineAsmArch::Arm => Self::Arm(ArmInlineAsmReg::parse(name)?),
357            InlineAsmArch::AArch64 | InlineAsmArch::Arm64EC => {
358                Self::AArch64(AArch64InlineAsmReg::parse(name)?)
359            }
360            InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
361                Self::RiscV(RiscVInlineAsmReg::parse(name)?)
362            }
363            InlineAsmArch::Nvptx64 => Self::Nvptx(NvptxInlineAsmReg::parse(name)?),
364            InlineAsmArch::PowerPC | InlineAsmArch::PowerPC64 => {
365                Self::PowerPC(PowerPCInlineAsmReg::parse(name)?)
366            }
367            InlineAsmArch::Hexagon => Self::Hexagon(HexagonInlineAsmReg::parse(name)?),
368            InlineAsmArch::LoongArch64 => Self::LoongArch(LoongArchInlineAsmReg::parse(name)?),
369            InlineAsmArch::Mips | InlineAsmArch::Mips64 => {
370                Self::Mips(MipsInlineAsmReg::parse(name)?)
371            }
372            InlineAsmArch::S390x => Self::S390x(S390xInlineAsmReg::parse(name)?),
373            InlineAsmArch::Sparc | InlineAsmArch::Sparc64 => {
374                Self::Sparc(SparcInlineAsmReg::parse(name)?)
375            }
376            InlineAsmArch::SpirV => Self::SpirV(SpirVInlineAsmReg::parse(name)?),
377            InlineAsmArch::Wasm32 | InlineAsmArch::Wasm64 => {
378                Self::Wasm(WasmInlineAsmReg::parse(name)?)
379            }
380            InlineAsmArch::Bpf => Self::Bpf(BpfInlineAsmReg::parse(name)?),
381            InlineAsmArch::Avr => Self::Avr(AvrInlineAsmReg::parse(name)?),
382            InlineAsmArch::Msp430 => Self::Msp430(Msp430InlineAsmReg::parse(name)?),
383            InlineAsmArch::M68k => Self::M68k(M68kInlineAsmReg::parse(name)?),
384            InlineAsmArch::CSKY => Self::CSKY(CSKYInlineAsmReg::parse(name)?),
385        })
386    }
387
388    pub fn validate(
389        self,
390        arch: InlineAsmArch,
391        reloc_model: RelocModel,
392        target_features: &FxIndexSet<Symbol>,
393        target: &Target,
394        is_clobber: bool,
395    ) -> Result<(), &'static str> {
396        match self {
397            Self::X86(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
398            Self::Arm(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
399            Self::AArch64(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
400            Self::RiscV(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
401            Self::PowerPC(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
402            Self::Hexagon(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
403            Self::LoongArch(r) => {
404                r.validate(arch, reloc_model, target_features, target, is_clobber)
405            }
406            Self::Mips(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
407            Self::S390x(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
408            Self::Sparc(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
409            Self::Bpf(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
410            Self::Avr(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
411            Self::Msp430(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
412            Self::M68k(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
413            Self::CSKY(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
414            Self::Err => unreachable!(),
415        }
416    }
417
418    // NOTE: This function isn't used at the moment, but is needed to support
419    // falling back to an external assembler.
420    pub fn emit(
421        self,
422        out: &mut dyn fmt::Write,
423        arch: InlineAsmArch,
424        modifier: Option<char>,
425    ) -> fmt::Result {
426        match self {
427            Self::X86(r) => r.emit(out, arch, modifier),
428            Self::Arm(r) => r.emit(out, arch, modifier),
429            Self::AArch64(r) => r.emit(out, arch, modifier),
430            Self::RiscV(r) => r.emit(out, arch, modifier),
431            Self::PowerPC(r) => r.emit(out, arch, modifier),
432            Self::Hexagon(r) => r.emit(out, arch, modifier),
433            Self::LoongArch(r) => r.emit(out, arch, modifier),
434            Self::Mips(r) => r.emit(out, arch, modifier),
435            Self::S390x(r) => r.emit(out, arch, modifier),
436            Self::Sparc(r) => r.emit(out, arch, modifier),
437            Self::Bpf(r) => r.emit(out, arch, modifier),
438            Self::Avr(r) => r.emit(out, arch, modifier),
439            Self::Msp430(r) => r.emit(out, arch, modifier),
440            Self::M68k(r) => r.emit(out, arch, modifier),
441            Self::CSKY(r) => r.emit(out, arch, modifier),
442            Self::Err => unreachable!("Use of InlineAsmReg::Err"),
443        }
444    }
445
446    pub fn overlapping_regs(self, mut cb: impl FnMut(InlineAsmReg)) {
447        match self {
448            Self::X86(r) => r.overlapping_regs(|r| cb(Self::X86(r))),
449            Self::Arm(r) => r.overlapping_regs(|r| cb(Self::Arm(r))),
450            Self::AArch64(_) => cb(self),
451            Self::RiscV(_) => cb(self),
452            Self::PowerPC(r) => r.overlapping_regs(|r| cb(Self::PowerPC(r))),
453            Self::Hexagon(r) => r.overlapping_regs(|r| cb(Self::Hexagon(r))),
454            Self::LoongArch(_) => cb(self),
455            Self::Mips(_) => cb(self),
456            Self::S390x(r) => r.overlapping_regs(|r| cb(Self::S390x(r))),
457            Self::Sparc(_) => cb(self),
458            Self::Bpf(r) => r.overlapping_regs(|r| cb(Self::Bpf(r))),
459            Self::Avr(r) => r.overlapping_regs(|r| cb(Self::Avr(r))),
460            Self::Msp430(_) => cb(self),
461            Self::M68k(_) => cb(self),
462            Self::CSKY(_) => cb(self),
463            Self::Err => unreachable!("Use of InlineAsmReg::Err"),
464        }
465    }
466}
467
468#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Hash)]
469#[derive(HashStable_Generic, Encodable, Decodable)]
470pub enum InlineAsmRegClass {
471    X86(X86InlineAsmRegClass),
472    Arm(ArmInlineAsmRegClass),
473    AArch64(AArch64InlineAsmRegClass),
474    RiscV(RiscVInlineAsmRegClass),
475    Nvptx(NvptxInlineAsmRegClass),
476    PowerPC(PowerPCInlineAsmRegClass),
477    Hexagon(HexagonInlineAsmRegClass),
478    LoongArch(LoongArchInlineAsmRegClass),
479    Mips(MipsInlineAsmRegClass),
480    S390x(S390xInlineAsmRegClass),
481    Sparc(SparcInlineAsmRegClass),
482    SpirV(SpirVInlineAsmRegClass),
483    Wasm(WasmInlineAsmRegClass),
484    Bpf(BpfInlineAsmRegClass),
485    Avr(AvrInlineAsmRegClass),
486    Msp430(Msp430InlineAsmRegClass),
487    M68k(M68kInlineAsmRegClass),
488    CSKY(CSKYInlineAsmRegClass),
489    // Placeholder for invalid register constraints for the current target
490    Err,
491}
492
493impl InlineAsmRegClass {
494    pub fn name(self) -> Symbol {
495        match self {
496            Self::X86(r) => r.name(),
497            Self::Arm(r) => r.name(),
498            Self::AArch64(r) => r.name(),
499            Self::RiscV(r) => r.name(),
500            Self::Nvptx(r) => r.name(),
501            Self::PowerPC(r) => r.name(),
502            Self::Hexagon(r) => r.name(),
503            Self::LoongArch(r) => r.name(),
504            Self::Mips(r) => r.name(),
505            Self::S390x(r) => r.name(),
506            Self::Sparc(r) => r.name(),
507            Self::SpirV(r) => r.name(),
508            Self::Wasm(r) => r.name(),
509            Self::Bpf(r) => r.name(),
510            Self::Avr(r) => r.name(),
511            Self::Msp430(r) => r.name(),
512            Self::M68k(r) => r.name(),
513            Self::CSKY(r) => r.name(),
514            Self::Err => rustc_span::sym::reg,
515        }
516    }
517
518    /// Returns a suggested register class to use for this type. This is called
519    /// when `supported_types` fails to give a better error
520    /// message to the user.
521    pub fn suggest_class(self, arch: InlineAsmArch, ty: InlineAsmType) -> Option<Self> {
522        match self {
523            Self::X86(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::X86),
524            Self::Arm(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Arm),
525            Self::AArch64(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::AArch64),
526            Self::RiscV(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::RiscV),
527            Self::Nvptx(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Nvptx),
528            Self::PowerPC(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::PowerPC),
529            Self::Hexagon(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Hexagon),
530            Self::LoongArch(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::LoongArch),
531            Self::Mips(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Mips),
532            Self::S390x(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::S390x),
533            Self::Sparc(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Sparc),
534            Self::SpirV(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::SpirV),
535            Self::Wasm(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Wasm),
536            Self::Bpf(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Bpf),
537            Self::Avr(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Avr),
538            Self::Msp430(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Msp430),
539            Self::M68k(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::M68k),
540            Self::CSKY(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::CSKY),
541            Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
542        }
543    }
544
545    /// Returns a suggested template modifier to use for this type and an
546    /// example of a register named formatted with it.
547    ///
548    /// Such suggestions are useful if a type smaller than the full register
549    /// size is used and a modifier can be used to point to the subregister of
550    /// the correct size.
551    pub fn suggest_modifier(self, arch: InlineAsmArch, ty: InlineAsmType) -> Option<ModifierInfo> {
552        match self {
553            Self::X86(r) => r.suggest_modifier(arch, ty),
554            Self::Arm(r) => r.suggest_modifier(arch, ty),
555            Self::AArch64(r) => r.suggest_modifier(arch, ty),
556            Self::RiscV(r) => r.suggest_modifier(arch, ty),
557            Self::Nvptx(r) => r.suggest_modifier(arch, ty),
558            Self::PowerPC(r) => r.suggest_modifier(arch, ty),
559            Self::Hexagon(r) => r.suggest_modifier(arch, ty),
560            Self::LoongArch(r) => r.suggest_modifier(arch, ty),
561            Self::Mips(r) => r.suggest_modifier(arch, ty),
562            Self::S390x(r) => r.suggest_modifier(arch, ty),
563            Self::Sparc(r) => r.suggest_modifier(arch, ty),
564            Self::SpirV(r) => r.suggest_modifier(arch, ty),
565            Self::Wasm(r) => r.suggest_modifier(arch, ty),
566            Self::Bpf(r) => r.suggest_modifier(arch, ty),
567            Self::Avr(r) => r.suggest_modifier(arch, ty),
568            Self::Msp430(r) => r.suggest_modifier(arch, ty),
569            Self::M68k(r) => r.suggest_modifier(arch, ty),
570            Self::CSKY(r) => r.suggest_modifier(arch, ty),
571            Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
572        }
573    }
574
575    /// Returns the default modifier for this register and an example of a
576    /// register named formatted with it.
577    ///
578    /// This is only needed when the register class can suggest a modifier, so
579    /// that the user can be shown how to get the default behavior without a
580    /// warning.
581    pub fn default_modifier(self, arch: InlineAsmArch) -> Option<ModifierInfo> {
582        match self {
583            Self::X86(r) => r.default_modifier(arch),
584            Self::Arm(r) => r.default_modifier(arch),
585            Self::AArch64(r) => r.default_modifier(arch),
586            Self::RiscV(r) => r.default_modifier(arch),
587            Self::Nvptx(r) => r.default_modifier(arch),
588            Self::PowerPC(r) => r.default_modifier(arch),
589            Self::Hexagon(r) => r.default_modifier(arch),
590            Self::LoongArch(r) => r.default_modifier(arch),
591            Self::Mips(r) => r.default_modifier(arch),
592            Self::S390x(r) => r.default_modifier(arch),
593            Self::Sparc(r) => r.default_modifier(arch),
594            Self::SpirV(r) => r.default_modifier(arch),
595            Self::Wasm(r) => r.default_modifier(arch),
596            Self::Bpf(r) => r.default_modifier(arch),
597            Self::Avr(r) => r.default_modifier(arch),
598            Self::Msp430(r) => r.default_modifier(arch),
599            Self::M68k(r) => r.default_modifier(arch),
600            Self::CSKY(r) => r.default_modifier(arch),
601            Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
602        }
603    }
604
605    /// Returns a list of supported types for this register class, each with an
606    /// options target feature required to use this type.
607    ///
608    /// At the codegen stage, it is fine to always pass true for `allow_experimental_reg`,
609    /// since all the stability checking will have been done in prior stages.
610    pub fn supported_types(
611        self,
612        arch: InlineAsmArch,
613        allow_experimental_reg: bool,
614    ) -> &'static [(InlineAsmType, Option<Symbol>)] {
615        match self {
616            Self::X86(r) => r.supported_types(arch),
617            Self::Arm(r) => r.supported_types(arch),
618            Self::AArch64(r) => r.supported_types(arch),
619            Self::RiscV(r) => r.supported_types(arch),
620            Self::Nvptx(r) => r.supported_types(arch),
621            Self::PowerPC(r) => r.supported_types(arch),
622            Self::Hexagon(r) => r.supported_types(arch),
623            Self::LoongArch(r) => r.supported_types(arch),
624            Self::Mips(r) => r.supported_types(arch),
625            Self::S390x(r) => r.supported_types(arch, allow_experimental_reg),
626            Self::Sparc(r) => r.supported_types(arch),
627            Self::SpirV(r) => r.supported_types(arch),
628            Self::Wasm(r) => r.supported_types(arch),
629            Self::Bpf(r) => r.supported_types(arch),
630            Self::Avr(r) => r.supported_types(arch),
631            Self::Msp430(r) => r.supported_types(arch),
632            Self::M68k(r) => r.supported_types(arch),
633            Self::CSKY(r) => r.supported_types(arch),
634            Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
635        }
636    }
637
638    pub fn parse(arch: InlineAsmArch, name: Symbol) -> Result<Self, &'static [rustc_span::Symbol]> {
639        Ok(match arch {
640            InlineAsmArch::X86 | InlineAsmArch::X86_64 => {
641                Self::X86(X86InlineAsmRegClass::parse(name)?)
642            }
643            InlineAsmArch::Arm => Self::Arm(ArmInlineAsmRegClass::parse(name)?),
644            InlineAsmArch::AArch64 | InlineAsmArch::Arm64EC => {
645                Self::AArch64(AArch64InlineAsmRegClass::parse(name)?)
646            }
647            InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
648                Self::RiscV(RiscVInlineAsmRegClass::parse(name)?)
649            }
650            InlineAsmArch::Nvptx64 => Self::Nvptx(NvptxInlineAsmRegClass::parse(name)?),
651            InlineAsmArch::PowerPC | InlineAsmArch::PowerPC64 => {
652                Self::PowerPC(PowerPCInlineAsmRegClass::parse(name)?)
653            }
654            InlineAsmArch::Hexagon => Self::Hexagon(HexagonInlineAsmRegClass::parse(name)?),
655            InlineAsmArch::LoongArch64 => Self::LoongArch(LoongArchInlineAsmRegClass::parse(name)?),
656            InlineAsmArch::Mips | InlineAsmArch::Mips64 => {
657                Self::Mips(MipsInlineAsmRegClass::parse(name)?)
658            }
659            InlineAsmArch::S390x => Self::S390x(S390xInlineAsmRegClass::parse(name)?),
660            InlineAsmArch::Sparc | InlineAsmArch::Sparc64 => {
661                Self::Sparc(SparcInlineAsmRegClass::parse(name)?)
662            }
663            InlineAsmArch::SpirV => Self::SpirV(SpirVInlineAsmRegClass::parse(name)?),
664            InlineAsmArch::Wasm32 | InlineAsmArch::Wasm64 => {
665                Self::Wasm(WasmInlineAsmRegClass::parse(name)?)
666            }
667            InlineAsmArch::Bpf => Self::Bpf(BpfInlineAsmRegClass::parse(name)?),
668            InlineAsmArch::Avr => Self::Avr(AvrInlineAsmRegClass::parse(name)?),
669            InlineAsmArch::Msp430 => Self::Msp430(Msp430InlineAsmRegClass::parse(name)?),
670            InlineAsmArch::M68k => Self::M68k(M68kInlineAsmRegClass::parse(name)?),
671            InlineAsmArch::CSKY => Self::CSKY(CSKYInlineAsmRegClass::parse(name)?),
672        })
673    }
674
675    /// Returns the list of template modifiers that can be used with this
676    /// register class.
677    pub fn valid_modifiers(self, arch: InlineAsmArch) -> &'static [char] {
678        match self {
679            Self::X86(r) => r.valid_modifiers(arch),
680            Self::Arm(r) => r.valid_modifiers(arch),
681            Self::AArch64(r) => r.valid_modifiers(arch),
682            Self::RiscV(r) => r.valid_modifiers(arch),
683            Self::Nvptx(r) => r.valid_modifiers(arch),
684            Self::PowerPC(r) => r.valid_modifiers(arch),
685            Self::Hexagon(r) => r.valid_modifiers(arch),
686            Self::LoongArch(r) => r.valid_modifiers(arch),
687            Self::Mips(r) => r.valid_modifiers(arch),
688            Self::S390x(r) => r.valid_modifiers(arch),
689            Self::Sparc(r) => r.valid_modifiers(arch),
690            Self::SpirV(r) => r.valid_modifiers(arch),
691            Self::Wasm(r) => r.valid_modifiers(arch),
692            Self::Bpf(r) => r.valid_modifiers(arch),
693            Self::Avr(r) => r.valid_modifiers(arch),
694            Self::Msp430(r) => r.valid_modifiers(arch),
695            Self::M68k(r) => r.valid_modifiers(arch),
696            Self::CSKY(r) => r.valid_modifiers(arch),
697            Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
698        }
699    }
700
701    /// Returns whether registers in this class can only be used as clobbers
702    /// and not as inputs/outputs.
703    ///
704    /// At the codegen stage, it is fine to always pass true for `allow_experimental_reg`,
705    /// since all the stability checking will have been done in prior stages.
706    pub fn is_clobber_only(self, arch: InlineAsmArch, allow_experimental_reg: bool) -> bool {
707        self.supported_types(arch, allow_experimental_reg).is_empty()
708    }
709}
710
711#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Hash)]
712#[derive(HashStable_Generic, Encodable, Decodable)]
713pub enum InlineAsmRegOrRegClass {
714    Reg(InlineAsmReg),
715    RegClass(InlineAsmRegClass),
716}
717
718impl InlineAsmRegOrRegClass {
719    pub fn reg_class(self) -> InlineAsmRegClass {
720        match self {
721            Self::Reg(r) => r.reg_class(),
722            Self::RegClass(r) => r,
723        }
724    }
725}
726
727impl fmt::Display for InlineAsmRegOrRegClass {
728    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
729        match self {
730            Self::Reg(r) => write!(f, "\"{}\"", r.name()),
731            Self::RegClass(r) => write!(f, "{}", r.name()),
732        }
733    }
734}
735
736/// Set of types which can be used with a particular register class.
737#[derive(Copy, Clone, Debug, Eq, PartialEq)]
738pub enum InlineAsmType {
739    I8,
740    I16,
741    I32,
742    I64,
743    I128,
744    F16,
745    F32,
746    F64,
747    F128,
748    VecI8(u64),
749    VecI16(u64),
750    VecI32(u64),
751    VecI64(u64),
752    VecI128(u64),
753    VecF16(u64),
754    VecF32(u64),
755    VecF64(u64),
756    VecF128(u64),
757}
758
759impl InlineAsmType {
760    pub fn is_integer(self) -> bool {
761        matches!(self, Self::I8 | Self::I16 | Self::I32 | Self::I64 | Self::I128)
762    }
763
764    pub fn size(self) -> Size {
765        Size::from_bytes(match self {
766            Self::I8 => 1,
767            Self::I16 => 2,
768            Self::I32 => 4,
769            Self::I64 => 8,
770            Self::I128 => 16,
771            Self::F16 => 2,
772            Self::F32 => 4,
773            Self::F64 => 8,
774            Self::F128 => 16,
775            Self::VecI8(n) => n * 1,
776            Self::VecI16(n) => n * 2,
777            Self::VecI32(n) => n * 4,
778            Self::VecI64(n) => n * 8,
779            Self::VecI128(n) => n * 16,
780            Self::VecF16(n) => n * 2,
781            Self::VecF32(n) => n * 4,
782            Self::VecF64(n) => n * 8,
783            Self::VecF128(n) => n * 16,
784        })
785    }
786}
787
788impl fmt::Display for InlineAsmType {
789    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
790        match *self {
791            Self::I8 => f.write_str("i8"),
792            Self::I16 => f.write_str("i16"),
793            Self::I32 => f.write_str("i32"),
794            Self::I64 => f.write_str("i64"),
795            Self::I128 => f.write_str("i128"),
796            Self::F16 => f.write_str("f16"),
797            Self::F32 => f.write_str("f32"),
798            Self::F64 => f.write_str("f64"),
799            Self::F128 => f.write_str("f128"),
800            Self::VecI8(n) => write!(f, "i8x{n}"),
801            Self::VecI16(n) => write!(f, "i16x{n}"),
802            Self::VecI32(n) => write!(f, "i32x{n}"),
803            Self::VecI64(n) => write!(f, "i64x{n}"),
804            Self::VecI128(n) => write!(f, "i128x{n}"),
805            Self::VecF16(n) => write!(f, "f16x{n}"),
806            Self::VecF32(n) => write!(f, "f32x{n}"),
807            Self::VecF64(n) => write!(f, "f64x{n}"),
808            Self::VecF128(n) => write!(f, "f128x{n}"),
809        }
810    }
811}
812
813/// Returns the full set of allocatable registers for a given architecture.
814///
815/// The registers are structured as a map containing the set of allocatable
816/// registers in each register class. A particular register may be allocatable
817/// from multiple register classes, in which case it will appear multiple times
818/// in the map.
819// NOTE: This function isn't used at the moment, but is needed to support
820// falling back to an external assembler.
821pub fn allocatable_registers(
822    arch: InlineAsmArch,
823    reloc_model: RelocModel,
824    target_features: &FxIndexSet<Symbol>,
825    target: &crate::spec::Target,
826) -> FxHashMap<InlineAsmRegClass, FxIndexSet<InlineAsmReg>> {
827    match arch {
828        InlineAsmArch::X86 | InlineAsmArch::X86_64 => {
829            let mut map = x86::regclass_map();
830            x86::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
831            map
832        }
833        InlineAsmArch::Arm => {
834            let mut map = arm::regclass_map();
835            arm::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
836            map
837        }
838        InlineAsmArch::AArch64 | InlineAsmArch::Arm64EC => {
839            let mut map = aarch64::regclass_map();
840            aarch64::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
841            map
842        }
843        InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
844            let mut map = riscv::regclass_map();
845            riscv::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
846            map
847        }
848        InlineAsmArch::Nvptx64 => {
849            let mut map = nvptx::regclass_map();
850            nvptx::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
851            map
852        }
853        InlineAsmArch::PowerPC | InlineAsmArch::PowerPC64 => {
854            let mut map = powerpc::regclass_map();
855            powerpc::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
856            map
857        }
858        InlineAsmArch::Hexagon => {
859            let mut map = hexagon::regclass_map();
860            hexagon::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
861            map
862        }
863        InlineAsmArch::LoongArch64 => {
864            let mut map = loongarch::regclass_map();
865            loongarch::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
866            map
867        }
868        InlineAsmArch::Mips | InlineAsmArch::Mips64 => {
869            let mut map = mips::regclass_map();
870            mips::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
871            map
872        }
873        InlineAsmArch::S390x => {
874            let mut map = s390x::regclass_map();
875            s390x::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
876            map
877        }
878        InlineAsmArch::Sparc | InlineAsmArch::Sparc64 => {
879            let mut map = sparc::regclass_map();
880            sparc::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
881            map
882        }
883        InlineAsmArch::SpirV => {
884            let mut map = spirv::regclass_map();
885            spirv::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
886            map
887        }
888        InlineAsmArch::Wasm32 | InlineAsmArch::Wasm64 => {
889            let mut map = wasm::regclass_map();
890            wasm::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
891            map
892        }
893        InlineAsmArch::Bpf => {
894            let mut map = bpf::regclass_map();
895            bpf::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
896            map
897        }
898        InlineAsmArch::Avr => {
899            let mut map = avr::regclass_map();
900            avr::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
901            map
902        }
903        InlineAsmArch::Msp430 => {
904            let mut map = msp430::regclass_map();
905            msp430::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
906            map
907        }
908        InlineAsmArch::M68k => {
909            let mut map = m68k::regclass_map();
910            m68k::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
911            map
912        }
913        InlineAsmArch::CSKY => {
914            let mut map = csky::regclass_map();
915            csky::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
916            map
917        }
918    }
919}
920
921#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Hash)]
922#[derive(HashStable_Generic, Encodable, Decodable)]
923pub enum InlineAsmClobberAbi {
924    X86,
925    X86_64Win,
926    X86_64SysV,
927    Arm,
928    AArch64,
929    AArch64NoX18,
930    Arm64EC,
931    Avr,
932    RiscV,
933    RiscVE,
934    LoongArch,
935    PowerPC,
936    S390x,
937    Bpf,
938    Msp430,
939}
940
941impl InlineAsmClobberAbi {
942    /// Parses a clobber ABI for the given target, or returns a list of supported
943    /// clobber ABIs for the target.
944    pub fn parse(
945        arch: InlineAsmArch,
946        target: &Target,
947        target_features: &FxIndexSet<Symbol>,
948        name: Symbol,
949    ) -> Result<Self, &'static [&'static str]> {
950        let name = name.as_str();
951        match arch {
952            InlineAsmArch::X86 => match name {
953                "C" | "system" | "efiapi" | "cdecl" | "stdcall" | "fastcall" => {
954                    Ok(InlineAsmClobberAbi::X86)
955                }
956                _ => Err(&["C", "system", "efiapi", "cdecl", "stdcall", "fastcall"]),
957            },
958            InlineAsmArch::X86_64 => match name {
959                "C" | "system" if !target.is_like_windows => Ok(InlineAsmClobberAbi::X86_64SysV),
960                "C" | "system" if target.is_like_windows => Ok(InlineAsmClobberAbi::X86_64Win),
961                "win64" | "efiapi" => Ok(InlineAsmClobberAbi::X86_64Win),
962                "sysv64" => Ok(InlineAsmClobberAbi::X86_64SysV),
963                _ => Err(&["C", "system", "efiapi", "win64", "sysv64"]),
964            },
965            InlineAsmArch::Arm => match name {
966                "C" | "system" | "efiapi" | "aapcs" => Ok(InlineAsmClobberAbi::Arm),
967                _ => Err(&["C", "system", "efiapi", "aapcs"]),
968            },
969            InlineAsmArch::AArch64 => match name {
970                "C" | "system" | "efiapi" => {
971                    Ok(if aarch64::target_reserves_x18(target, target_features) {
972                        InlineAsmClobberAbi::AArch64NoX18
973                    } else {
974                        InlineAsmClobberAbi::AArch64
975                    })
976                }
977                _ => Err(&["C", "system", "efiapi"]),
978            },
979            InlineAsmArch::Arm64EC => match name {
980                "C" | "system" => Ok(InlineAsmClobberAbi::Arm64EC),
981                _ => Err(&["C", "system"]),
982            },
983            InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => match name {
984                "C" | "system" | "efiapi" => Ok(if riscv::is_e(target_features) {
985                    InlineAsmClobberAbi::RiscVE
986                } else {
987                    InlineAsmClobberAbi::RiscV
988                }),
989                _ => Err(&["C", "system", "efiapi"]),
990            },
991            InlineAsmArch::Avr => match name {
992                "C" | "system" => Ok(InlineAsmClobberAbi::Avr),
993                _ => Err(&["C", "system"]),
994            },
995            InlineAsmArch::LoongArch64 => match name {
996                "C" | "system" => Ok(InlineAsmClobberAbi::LoongArch),
997                _ => Err(&["C", "system"]),
998            },
999            InlineAsmArch::PowerPC | InlineAsmArch::PowerPC64 => match name {
1000                "C" | "system" => Ok(InlineAsmClobberAbi::PowerPC),
1001                _ => Err(&["C", "system"]),
1002            },
1003            InlineAsmArch::S390x => match name {
1004                "C" | "system" => Ok(InlineAsmClobberAbi::S390x),
1005                _ => Err(&["C", "system"]),
1006            },
1007            InlineAsmArch::Bpf => match name {
1008                "C" | "system" => Ok(InlineAsmClobberAbi::Bpf),
1009                _ => Err(&["C", "system"]),
1010            },
1011            InlineAsmArch::Msp430 => match name {
1012                "C" | "system" => Ok(InlineAsmClobberAbi::Msp430),
1013                _ => Err(&["C", "system"]),
1014            },
1015            _ => Err(&[]),
1016        }
1017    }
1018
1019    /// Returns the set of registers which are clobbered by this ABI.
1020    pub fn clobbered_regs(self) -> &'static [InlineAsmReg] {
1021        macro_rules! clobbered_regs {
1022            ($arch:ident $arch_reg:ident {
1023                $(
1024                    $reg:ident,
1025                )*
1026            }) => {
1027                &[
1028                    $(InlineAsmReg::$arch($arch_reg::$reg),)*
1029                ]
1030            };
1031        }
1032        match self {
1033            InlineAsmClobberAbi::X86 => clobbered_regs! {
1034                X86 X86InlineAsmReg {
1035                    ax, cx, dx,
1036
1037                    xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7,
1038
1039                    k0, k1, k2, k3, k4, k5, k6, k7,
1040
1041                    mm0, mm1, mm2, mm3, mm4, mm5, mm6, mm7,
1042                    st0, st1, st2, st3, st4, st5, st6, st7,
1043                }
1044            },
1045            InlineAsmClobberAbi::X86_64SysV => clobbered_regs! {
1046                X86 X86InlineAsmReg {
1047                    ax, cx, dx, si, di, r8, r9, r10, r11,
1048
1049                    xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7,
1050                    xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15,
1051                    zmm16, zmm17, zmm18, zmm19, zmm20, zmm21, zmm22, zmm23,
1052                    zmm24, zmm25, zmm26, zmm27, zmm28, zmm29, zmm30, zmm31,
1053
1054                    k0, k1, k2, k3, k4, k5, k6, k7,
1055
1056                    mm0, mm1, mm2, mm3, mm4, mm5, mm6, mm7,
1057                    st0, st1, st2, st3, st4, st5, st6, st7,
1058                    tmm0, tmm1, tmm2, tmm3, tmm4, tmm5, tmm6, tmm7,
1059                }
1060            },
1061            InlineAsmClobberAbi::X86_64Win => clobbered_regs! {
1062                X86 X86InlineAsmReg {
1063                    // rdi and rsi are callee-saved on windows
1064                    ax, cx, dx, r8, r9, r10, r11,
1065
1066                    // xmm6-xmm15 are callee-saved on windows, but we need to
1067                    // mark them as clobbered anyways because the upper portions
1068                    // of ymm6-ymm15 are volatile.
1069                    xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7,
1070                    xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15,
1071                    zmm16, zmm17, zmm18, zmm19, zmm20, zmm21, zmm22, zmm23,
1072                    zmm24, zmm25, zmm26, zmm27, zmm28, zmm29, zmm30, zmm31,
1073
1074                    k0, k1, k2, k3, k4, k5, k6, k7,
1075
1076                    mm0, mm1, mm2, mm3, mm4, mm5, mm6, mm7,
1077                    st0, st1, st2, st3, st4, st5, st6, st7,
1078                    tmm0, tmm1, tmm2, tmm3, tmm4, tmm5, tmm6, tmm7,
1079                }
1080            },
1081            InlineAsmClobberAbi::AArch64 => clobbered_regs! {
1082                AArch64 AArch64InlineAsmReg {
1083                    x0, x1, x2, x3, x4, x5, x6, x7,
1084                    x8, x9, x10, x11, x12, x13, x14, x15,
1085                    x16, x17, x18, x30,
1086
1087                    // Technically the low 64 bits of v8-v15 are preserved, but
1088                    // we have no way of expressing this using clobbers.
1089                    v0, v1, v2, v3, v4, v5, v6, v7,
1090                    v8, v9, v10, v11, v12, v13, v14, v15,
1091                    v16, v17, v18, v19, v20, v21, v22, v23,
1092                    v24, v25, v26, v27, v28, v29, v30, v31,
1093
1094                    p0, p1, p2, p3, p4, p5, p6, p7,
1095                    p8, p9, p10, p11, p12, p13, p14, p15,
1096                    ffr,
1097                }
1098            },
1099            InlineAsmClobberAbi::AArch64NoX18 => clobbered_regs! {
1100                AArch64 AArch64InlineAsmReg {
1101                    x0, x1, x2, x3, x4, x5, x6, x7,
1102                    x8, x9, x10, x11, x12, x13, x14, x15,
1103                    x16, x17, x30,
1104
1105                    // Technically the low 64 bits of v8-v15 are preserved, but
1106                    // we have no way of expressing this using clobbers.
1107                    v0, v1, v2, v3, v4, v5, v6, v7,
1108                    v8, v9, v10, v11, v12, v13, v14, v15,
1109                    v16, v17, v18, v19, v20, v21, v22, v23,
1110                    v24, v25, v26, v27, v28, v29, v30, v31,
1111
1112                    p0, p1, p2, p3, p4, p5, p6, p7,
1113                    p8, p9, p10, p11, p12, p13, p14, p15,
1114                    ffr,
1115                }
1116            },
1117            InlineAsmClobberAbi::Arm64EC => clobbered_regs! {
1118                AArch64 AArch64InlineAsmReg {
1119                    // x13 and x14 cannot be used in Arm64EC.
1120                    x0, x1, x2, x3, x4, x5, x6, x7,
1121                    x8, x9, x10, x11, x12, x15,
1122                    x16, x17, x30,
1123
1124                    // Technically the low 64 bits of v8-v15 are preserved, but
1125                    // we have no way of expressing this using clobbers.
1126                    v0, v1, v2, v3, v4, v5, v6, v7,
1127                    v8, v9, v10, v11, v12, v13, v14, v15,
1128                    // v16-v31, p*, and ffr cannot be used in Arm64EC.
1129                }
1130            },
1131            InlineAsmClobberAbi::Arm => clobbered_regs! {
1132                Arm ArmInlineAsmReg {
1133                    // r9 is either platform-reserved or callee-saved. Either
1134                    // way we don't need to clobber it.
1135                    r0, r1, r2, r3, r12, r14,
1136
1137                    // The finest-grained register variant is used here so that
1138                    // partial uses of larger registers are properly handled.
1139                    s0, s1, s2, s3, s4, s5, s6, s7,
1140                    s8, s9, s10, s11, s12, s13, s14, s15,
1141                    // s16-s31 are callee-saved
1142                    d16, d17, d18, d19, d20, d21, d22, d23,
1143                    d24, d25, d26, d27, d28, d29, d30, d31,
1144                }
1145            },
1146            InlineAsmClobberAbi::Avr => clobbered_regs! {
1147                Avr AvrInlineAsmReg {
1148                    // The list of "Call-Used Registers" according to
1149                    // https://gcc.gnu.org/wiki/avr-gcc#Call-Used_Registers
1150
1151                    // Clobbered registers available in inline assembly
1152                    r18, r19, r20, r21, r22, r23, r24, r25, r26, r27, r30, r31,
1153                    // As per the AVR-GCC-ABI documentation linked above, the R0
1154                    // register is a clobbered register as well. Since we don't
1155                    // allow the usage of R0 in inline assembly, nothing has to
1156                    // be done here.
1157                    // Likewise, the T-flag in the SREG should be clobbered, but
1158                    // this is not necessary to be listed here, since the SREG
1159                    // is considered clobbered anyways unless `preserve_flags`
1160                    // is used.
1161                }
1162            },
1163            InlineAsmClobberAbi::RiscV => clobbered_regs! {
1164                RiscV RiscVInlineAsmReg {
1165                    // ra
1166                    x1,
1167                    // t0-t2
1168                    x5, x6, x7,
1169                    // a0-a7
1170                    x10, x11, x12, x13, x14, x15, x16, x17,
1171                    // t3-t6
1172                    x28, x29, x30, x31,
1173                    // ft0-ft7
1174                    f0, f1, f2, f3, f4, f5, f6, f7,
1175                    // fa0-fa7
1176                    f10, f11, f12, f13, f14, f15, f16, f17,
1177                    // ft8-ft11
1178                    f28, f29, f30, f31,
1179
1180                    v0, v1, v2, v3, v4, v5, v6, v7,
1181                    v8, v9, v10, v11, v12, v13, v14, v15,
1182                    v16, v17, v18, v19, v20, v21, v22, v23,
1183                    v24, v25, v26, v27, v28, v29, v30, v31,
1184                }
1185            },
1186            InlineAsmClobberAbi::RiscVE => clobbered_regs! {
1187                RiscV RiscVInlineAsmReg {
1188                    // Refs:
1189                    // - ILP32E https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/draft-20240829-13bfa9f54634cb60d86b9b333e109f077805b4b3/riscv-cc.adoc#ilp32e-calling-convention
1190                    // - LP64E https://github.com/riscv-non-isa/riscv-elf-psabi-doc/pull/299
1191
1192                    // ra
1193                    x1,
1194                    // t0-t2
1195                    x5, x6, x7,
1196                    // a0-a5
1197                    x10, x11, x12, x13, x14, x15,
1198                    // ft0-ft7
1199                    f0, f1, f2, f3, f4, f5, f6, f7,
1200                    // fa0-fa7
1201                    f10, f11, f12, f13, f14, f15, f16, f17,
1202                    // ft8-ft11
1203                    f28, f29, f30, f31,
1204
1205                    v0, v1, v2, v3, v4, v5, v6, v7,
1206                    v8, v9, v10, v11, v12, v13, v14, v15,
1207                    v16, v17, v18, v19, v20, v21, v22, v23,
1208                    v24, v25, v26, v27, v28, v29, v30, v31,
1209                }
1210            },
1211            InlineAsmClobberAbi::LoongArch => clobbered_regs! {
1212                LoongArch LoongArchInlineAsmReg {
1213                    // ra
1214                    r1,
1215                    // a0-a7
1216                    r4, r5, r6, r7, r8, r9, r10, r11,
1217                    // t0-t8
1218                    r12, r13, r14, r15, r16, r17, r18, r19, r20,
1219                    // fa0-fa7
1220                    f0, f1, f2, f3, f4, f5, f6, f7,
1221                    // ft0-ft15
1222                    f8, f9, f10, f11, f12, f13, f14, f15,
1223                    f16, f17, f18, f19, f20, f21, f22, f23,
1224                }
1225            },
1226            InlineAsmClobberAbi::PowerPC => clobbered_regs! {
1227                PowerPC PowerPCInlineAsmReg {
1228                    // Refs:
1229                    // - PPC32 SysV: "3.2. Function Calling Sequence" in Power Architecture® 32-bit Application Binary Interface Supplement 1.0 - Linux® & Embedded
1230                    //   https://web.archive.org/web/20120608163804/https://www.power.org/resources/downloads/Power-Arch-32-bit-ABI-supp-1.0-Unified.pdf
1231                    // - PPC64 ELFv1: "3.2. Function Calling Sequence" in 64-bit PowerPC ELF Application Binary Interface Supplement 1.9
1232                    //   https://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi.html#FUNC-CALL
1233                    // - PPC64 ELFv2: "2.2 Function Calling Sequence" in 64-Bit ELF V2 ABI Specification: Power Architecture, Revision 1.5
1234                    //   https://openpowerfoundation.org/specifications/64bitelfabi/
1235                    // - AIX:
1236                    //   - Register usage and conventions
1237                    //     https://www.ibm.com/docs/en/aix/7.3?topic=overview-register-usage-conventions
1238                    //   - Special registers in the PowerPC®
1239                    //     https://www.ibm.com/docs/en/aix/7.3?topic=overview-special-registers-in-powerpc
1240                    //   - AIX vector programming
1241                    //     https://www.ibm.com/docs/en/aix/7.3?topic=concepts-aix-vector-programming
1242
1243                    // r0, r3-r12
1244                    r0,
1245                    r3, r4, r5, r6, r7,
1246                    r8, r9, r10, r11, r12,
1247
1248                    // f0-f13
1249                    f0, f1, f2, f3, f4, f5, f6, f7,
1250                    f8, f9, f10, f11, f12, f13,
1251
1252                    // v0-v19
1253                    v0, v1, v2, v3, v4, v5, v6, v7,
1254                    v8, v9, v10, v11, v12, v13, v14,
1255                    v15, v16, v17, v18, v19,
1256
1257                    // cr0-cr1, cr5-cr7, xer
1258                    cr0, cr1,
1259                    cr5, cr6, cr7,
1260                    xer,
1261                    // lr and ctr are reserved
1262                }
1263            },
1264            InlineAsmClobberAbi::S390x => clobbered_regs! {
1265                S390x S390xInlineAsmReg {
1266                    r0, r1, r2, r3, r4, r5,
1267                    r14,
1268
1269                    // f0-f7, v0-v7
1270                    f0, f1, f2, f3, f4, f5, f6, f7,
1271                    v0, v1, v2, v3, v4, v5, v6, v7,
1272
1273                    // Technically the left halves of v8-v15 (i.e., f8-f15) are saved, but
1274                    // we have no way of expressing this using clobbers.
1275                    v8, v9, v10, v11, v12, v13, v14, v15,
1276
1277                    // Other vector registers are volatile
1278                    v16, v17, v18, v19, v20, v21, v22, v23,
1279                    v24, v25, v26, v27, v28, v29, v30, v31,
1280
1281                    // a0-a1 are reserved, other access registers are volatile
1282                    a2, a3, a4, a5, a6, a7,
1283                    a8, a9, a10, a11, a12, a13, a14, a15,
1284                }
1285            },
1286            InlineAsmClobberAbi::Bpf => clobbered_regs! {
1287                Bpf BpfInlineAsmReg {
1288                    // Refs: Section 1.1 "Registers and calling convention" in BPF ABI Recommended Conventions and Guidelines v1.0
1289                    // https://www.kernel.org/doc/html/latest/bpf/standardization/abi.html#registers-and-calling-convention
1290
1291                    r0, r1, r2, r3, r4, r5,
1292                }
1293            },
1294            InlineAsmClobberAbi::Msp430 => clobbered_regs! {
1295                Msp430 Msp430InlineAsmReg {
1296                    r11, r12, r13, r14, r15,
1297                }
1298            },
1299        }
1300    }
1301}