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