rustc_target/asm/
mod.rs

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