2 use crate::spec::Target;
3 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
4 use rustc_macros::HashStable_Generic;
5 use rustc_span::Symbol;
9 macro_rules! def_reg_class {
10 ($arch:ident $arch_regclass:ident {
15 #[derive(Copy, Clone, Encodable, Decodable, Debug, Eq, PartialEq, PartialOrd, Hash, HashStable_Generic)]
16 #[allow(non_camel_case_types)]
17 pub enum $arch_regclass {
22 pub fn name(self) -> rustc_span::Symbol {
24 $(Self::$class => rustc_span::symbol::sym::$class,)*
28 pub fn parse(_arch: super::InlineAsmArch, name: rustc_span::Symbol) -> Result<Self, &'static str> {
31 rustc_span::sym::$class => Ok(Self::$class),
33 _ => Err("unknown register class"),
38 pub(super) fn regclass_map() -> rustc_data_structures::fx::FxHashMap<
39 super::InlineAsmRegClass,
40 rustc_data_structures::fx::FxHashSet<super::InlineAsmReg>,
42 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
43 use super::InlineAsmRegClass;
44 let mut map = FxHashMap::default();
46 map.insert(InlineAsmRegClass::$arch($arch_regclass::$class), FxHashSet::default());
53 macro_rules! def_regs {
54 ($arch:ident $arch_reg:ident $arch_regclass:ident {
56 $reg:ident: $class:ident $(, $extra_class:ident)* = [$reg_name:literal $(, $alias:literal)*] $(% $filter:ident)?,
59 #error = [$($bad_reg:literal),+] => $error:literal,
62 #[allow(unreachable_code)]
63 #[derive(Copy, Clone, Encodable, Decodable, Debug, Eq, PartialEq, PartialOrd, Hash, HashStable_Generic)]
64 #[allow(non_camel_case_types)]
70 pub fn name(self) -> &'static str {
72 $(Self::$reg => $reg_name,)*
76 pub fn reg_class(self) -> $arch_regclass {
78 $(Self::$reg => $arch_regclass::$class,)*
83 _arch: super::InlineAsmArch,
84 mut _has_feature: impl FnMut(&str) -> bool,
85 _target: &crate::spec::Target,
87 ) -> Result<Self, &'static str> {
90 $($alias)|* | $reg_name => {
91 $($filter(_arch, &mut _has_feature, _target)?;)?
96 $($bad_reg)|* => Err($error),
98 _ => Err("unknown register"),
103 pub(super) fn fill_reg_map(
104 _arch: super::InlineAsmArch,
105 mut _has_feature: impl FnMut(&str) -> bool,
106 _target: &crate::spec::Target,
107 _map: &mut rustc_data_structures::fx::FxHashMap<
108 super::InlineAsmRegClass,
109 rustc_data_structures::fx::FxHashSet<super::InlineAsmReg>,
112 #[allow(unused_imports)]
113 use super::{InlineAsmReg, InlineAsmRegClass};
115 if $($filter(_arch, &mut _has_feature, _target).is_ok() &&)? true {
116 if let Some(set) = _map.get_mut(&InlineAsmRegClass::$arch($arch_regclass::$class)) {
117 set.insert(InlineAsmReg::$arch($arch_reg::$reg));
120 if let Some(set) = _map.get_mut(&InlineAsmRegClass::$arch($arch_regclass::$extra_class)) {
121 set.insert(InlineAsmReg::$arch($arch_reg::$reg));
132 $(_ : $($ty:expr),+;)?
133 $($feature:literal: $($ty2:expr),+;)*
136 use super::InlineAsmType::*;
142 ($ty2, Some($feature)),
161 pub use aarch64::{AArch64InlineAsmReg, AArch64InlineAsmRegClass};
162 pub use arm::{ArmInlineAsmReg, ArmInlineAsmRegClass};
163 pub use bpf::{BpfInlineAsmReg, BpfInlineAsmRegClass};
164 pub use hexagon::{HexagonInlineAsmReg, HexagonInlineAsmRegClass};
165 pub use mips::{MipsInlineAsmReg, MipsInlineAsmRegClass};
166 pub use nvptx::{NvptxInlineAsmReg, NvptxInlineAsmRegClass};
167 pub use powerpc::{PowerPCInlineAsmReg, PowerPCInlineAsmRegClass};
168 pub use riscv::{RiscVInlineAsmReg, RiscVInlineAsmRegClass};
169 pub use spirv::{SpirVInlineAsmReg, SpirVInlineAsmRegClass};
170 pub use wasm::{WasmInlineAsmReg, WasmInlineAsmRegClass};
171 pub use x86::{X86InlineAsmReg, X86InlineAsmRegClass};
173 #[derive(Copy, Clone, Encodable, Decodable, Debug, Eq, PartialEq, Hash)]
174 pub enum InlineAsmArch {
192 impl FromStr for InlineAsmArch {
195 fn from_str(s: &str) -> Result<InlineAsmArch, ()> {
197 "x86" => Ok(Self::X86),
198 "x86_64" => Ok(Self::X86_64),
199 "arm" => Ok(Self::Arm),
200 "aarch64" => Ok(Self::AArch64),
201 "riscv32" => Ok(Self::RiscV32),
202 "riscv64" => Ok(Self::RiscV64),
203 "nvptx64" => Ok(Self::Nvptx64),
204 "powerpc" => Ok(Self::PowerPC),
205 "powerpc64" => Ok(Self::PowerPC64),
206 "hexagon" => Ok(Self::Hexagon),
207 "mips" => Ok(Self::Mips),
208 "mips64" => Ok(Self::Mips64),
209 "spirv" => Ok(Self::SpirV),
210 "wasm32" => Ok(Self::Wasm32),
211 "bpf" => Ok(Self::Bpf),
229 pub enum InlineAsmReg {
230 X86(X86InlineAsmReg),
231 Arm(ArmInlineAsmReg),
232 AArch64(AArch64InlineAsmReg),
233 RiscV(RiscVInlineAsmReg),
234 Nvptx(NvptxInlineAsmReg),
235 PowerPC(PowerPCInlineAsmReg),
236 Hexagon(HexagonInlineAsmReg),
237 Mips(MipsInlineAsmReg),
238 SpirV(SpirVInlineAsmReg),
239 Wasm(WasmInlineAsmReg),
240 Bpf(BpfInlineAsmReg),
241 // Placeholder for invalid register constraints for the current target
246 pub fn name(self) -> &'static str {
248 Self::X86(r) => r.name(),
249 Self::Arm(r) => r.name(),
250 Self::AArch64(r) => r.name(),
251 Self::RiscV(r) => r.name(),
252 Self::PowerPC(r) => r.name(),
253 Self::Hexagon(r) => r.name(),
254 Self::Mips(r) => r.name(),
255 Self::Bpf(r) => r.name(),
256 Self::Err => "<reg>",
260 pub fn reg_class(self) -> InlineAsmRegClass {
262 Self::X86(r) => InlineAsmRegClass::X86(r.reg_class()),
263 Self::Arm(r) => InlineAsmRegClass::Arm(r.reg_class()),
264 Self::AArch64(r) => InlineAsmRegClass::AArch64(r.reg_class()),
265 Self::RiscV(r) => InlineAsmRegClass::RiscV(r.reg_class()),
266 Self::PowerPC(r) => InlineAsmRegClass::PowerPC(r.reg_class()),
267 Self::Hexagon(r) => InlineAsmRegClass::Hexagon(r.reg_class()),
268 Self::Mips(r) => InlineAsmRegClass::Mips(r.reg_class()),
269 Self::Bpf(r) => InlineAsmRegClass::Bpf(r.reg_class()),
270 Self::Err => InlineAsmRegClass::Err,
276 has_feature: impl FnMut(&str) -> bool,
279 ) -> Result<Self, &'static str> {
280 // FIXME: use direct symbol comparison for register names
281 // Use `Symbol::as_str` instead of `Symbol::with` here because `has_feature` may access `Symbol`.
282 let name = name.as_str();
284 InlineAsmArch::X86 | InlineAsmArch::X86_64 => {
285 Self::X86(X86InlineAsmReg::parse(arch, has_feature, target, &name)?)
287 InlineAsmArch::Arm => {
288 Self::Arm(ArmInlineAsmReg::parse(arch, has_feature, target, &name)?)
290 InlineAsmArch::AArch64 => {
291 Self::AArch64(AArch64InlineAsmReg::parse(arch, has_feature, target, &name)?)
293 InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
294 Self::RiscV(RiscVInlineAsmReg::parse(arch, has_feature, target, &name)?)
296 InlineAsmArch::Nvptx64 => {
297 Self::Nvptx(NvptxInlineAsmReg::parse(arch, has_feature, target, &name)?)
299 InlineAsmArch::PowerPC | InlineAsmArch::PowerPC64 => {
300 Self::PowerPC(PowerPCInlineAsmReg::parse(arch, has_feature, target, &name)?)
302 InlineAsmArch::Hexagon => {
303 Self::Hexagon(HexagonInlineAsmReg::parse(arch, has_feature, target, &name)?)
305 InlineAsmArch::Mips | InlineAsmArch::Mips64 => {
306 Self::Mips(MipsInlineAsmReg::parse(arch, has_feature, target, &name)?)
308 InlineAsmArch::SpirV => {
309 Self::SpirV(SpirVInlineAsmReg::parse(arch, has_feature, target, &name)?)
311 InlineAsmArch::Wasm32 => {
312 Self::Wasm(WasmInlineAsmReg::parse(arch, has_feature, target, &name)?)
314 InlineAsmArch::Bpf => {
315 Self::Bpf(BpfInlineAsmReg::parse(arch, has_feature, target, &name)?)
320 // NOTE: This function isn't used at the moment, but is needed to support
321 // falling back to an external assembler.
324 out: &mut dyn fmt::Write,
326 modifier: Option<char>,
329 Self::X86(r) => r.emit(out, arch, modifier),
330 Self::Arm(r) => r.emit(out, arch, modifier),
331 Self::AArch64(r) => r.emit(out, arch, modifier),
332 Self::RiscV(r) => r.emit(out, arch, modifier),
333 Self::PowerPC(r) => r.emit(out, arch, modifier),
334 Self::Hexagon(r) => r.emit(out, arch, modifier),
335 Self::Mips(r) => r.emit(out, arch, modifier),
336 Self::Bpf(r) => r.emit(out, arch, modifier),
337 Self::Err => unreachable!("Use of InlineAsmReg::Err"),
341 pub fn overlapping_regs(self, mut cb: impl FnMut(InlineAsmReg)) {
343 Self::X86(r) => r.overlapping_regs(|r| cb(Self::X86(r))),
344 Self::Arm(r) => r.overlapping_regs(|r| cb(Self::Arm(r))),
345 Self::AArch64(_) => cb(self),
346 Self::RiscV(_) => cb(self),
347 Self::PowerPC(_) => cb(self),
348 Self::Hexagon(r) => r.overlapping_regs(|r| cb(Self::Hexagon(r))),
349 Self::Mips(_) => cb(self),
350 Self::Bpf(r) => r.overlapping_regs(|r| cb(Self::Bpf(r))),
351 Self::Err => unreachable!("Use of InlineAsmReg::Err"),
368 pub enum InlineAsmRegClass {
369 X86(X86InlineAsmRegClass),
370 Arm(ArmInlineAsmRegClass),
371 AArch64(AArch64InlineAsmRegClass),
372 RiscV(RiscVInlineAsmRegClass),
373 Nvptx(NvptxInlineAsmRegClass),
374 PowerPC(PowerPCInlineAsmRegClass),
375 Hexagon(HexagonInlineAsmRegClass),
376 Mips(MipsInlineAsmRegClass),
377 SpirV(SpirVInlineAsmRegClass),
378 Wasm(WasmInlineAsmRegClass),
379 Bpf(BpfInlineAsmRegClass),
380 // Placeholder for invalid register constraints for the current target
384 impl InlineAsmRegClass {
385 pub fn name(self) -> Symbol {
387 Self::X86(r) => r.name(),
388 Self::Arm(r) => r.name(),
389 Self::AArch64(r) => r.name(),
390 Self::RiscV(r) => r.name(),
391 Self::Nvptx(r) => r.name(),
392 Self::PowerPC(r) => r.name(),
393 Self::Hexagon(r) => r.name(),
394 Self::Mips(r) => r.name(),
395 Self::SpirV(r) => r.name(),
396 Self::Wasm(r) => r.name(),
397 Self::Bpf(r) => r.name(),
398 Self::Err => rustc_span::symbol::sym::reg,
402 /// Returns a suggested register class to use for this type. This is called
403 /// after type checking via `supported_types` fails to give a better error
404 /// message to the user.
405 pub fn suggest_class(self, arch: InlineAsmArch, ty: InlineAsmType) -> Option<Self> {
407 Self::X86(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::X86),
408 Self::Arm(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Arm),
409 Self::AArch64(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::AArch64),
410 Self::RiscV(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::RiscV),
411 Self::Nvptx(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Nvptx),
412 Self::PowerPC(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::PowerPC),
413 Self::Hexagon(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Hexagon),
414 Self::Mips(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Mips),
415 Self::SpirV(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::SpirV),
416 Self::Wasm(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Wasm),
417 Self::Bpf(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Bpf),
418 Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
422 /// Returns a suggested template modifier to use for this type and an
423 /// example of a register named formatted with it.
425 /// Such suggestions are useful if a type smaller than the full register
426 /// size is used and a modifier can be used to point to the subregister of
427 /// the correct size.
428 pub fn suggest_modifier(
432 ) -> Option<(char, &'static str)> {
434 Self::X86(r) => r.suggest_modifier(arch, ty),
435 Self::Arm(r) => r.suggest_modifier(arch, ty),
436 Self::AArch64(r) => r.suggest_modifier(arch, ty),
437 Self::RiscV(r) => r.suggest_modifier(arch, ty),
438 Self::Nvptx(r) => r.suggest_modifier(arch, ty),
439 Self::PowerPC(r) => r.suggest_modifier(arch, ty),
440 Self::Hexagon(r) => r.suggest_modifier(arch, ty),
441 Self::Mips(r) => r.suggest_modifier(arch, ty),
442 Self::SpirV(r) => r.suggest_modifier(arch, ty),
443 Self::Wasm(r) => r.suggest_modifier(arch, ty),
444 Self::Bpf(r) => r.suggest_modifier(arch, ty),
445 Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
449 /// Returns the default modifier for this register and an example of a
450 /// register named formatted with it.
452 /// This is only needed when the register class can suggest a modifier, so
453 /// that the user can be shown how to get the default behavior without a
455 pub fn default_modifier(self, arch: InlineAsmArch) -> Option<(char, &'static str)> {
457 Self::X86(r) => r.default_modifier(arch),
458 Self::Arm(r) => r.default_modifier(arch),
459 Self::AArch64(r) => r.default_modifier(arch),
460 Self::RiscV(r) => r.default_modifier(arch),
461 Self::Nvptx(r) => r.default_modifier(arch),
462 Self::PowerPC(r) => r.default_modifier(arch),
463 Self::Hexagon(r) => r.default_modifier(arch),
464 Self::Mips(r) => r.default_modifier(arch),
465 Self::SpirV(r) => r.default_modifier(arch),
466 Self::Wasm(r) => r.default_modifier(arch),
467 Self::Bpf(r) => r.default_modifier(arch),
468 Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
472 /// Returns a list of supported types for this register class, each with a
473 /// options target feature required to use this type.
474 pub fn supported_types(
477 ) -> &'static [(InlineAsmType, Option<&'static str>)] {
479 Self::X86(r) => r.supported_types(arch),
480 Self::Arm(r) => r.supported_types(arch),
481 Self::AArch64(r) => r.supported_types(arch),
482 Self::RiscV(r) => r.supported_types(arch),
483 Self::Nvptx(r) => r.supported_types(arch),
484 Self::PowerPC(r) => r.supported_types(arch),
485 Self::Hexagon(r) => r.supported_types(arch),
486 Self::Mips(r) => r.supported_types(arch),
487 Self::SpirV(r) => r.supported_types(arch),
488 Self::Wasm(r) => r.supported_types(arch),
489 Self::Bpf(r) => r.supported_types(arch),
490 Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
494 pub fn parse(arch: InlineAsmArch, name: Symbol) -> Result<Self, &'static str> {
496 InlineAsmArch::X86 | InlineAsmArch::X86_64 => {
497 Self::X86(X86InlineAsmRegClass::parse(arch, name)?)
499 InlineAsmArch::Arm => Self::Arm(ArmInlineAsmRegClass::parse(arch, name)?),
500 InlineAsmArch::AArch64 => Self::AArch64(AArch64InlineAsmRegClass::parse(arch, name)?),
501 InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
502 Self::RiscV(RiscVInlineAsmRegClass::parse(arch, name)?)
504 InlineAsmArch::Nvptx64 => Self::Nvptx(NvptxInlineAsmRegClass::parse(arch, name)?),
505 InlineAsmArch::PowerPC | InlineAsmArch::PowerPC64 => {
506 Self::PowerPC(PowerPCInlineAsmRegClass::parse(arch, name)?)
508 InlineAsmArch::Hexagon => Self::Hexagon(HexagonInlineAsmRegClass::parse(arch, name)?),
509 InlineAsmArch::Mips | InlineAsmArch::Mips64 => {
510 Self::Mips(MipsInlineAsmRegClass::parse(arch, name)?)
512 InlineAsmArch::SpirV => Self::SpirV(SpirVInlineAsmRegClass::parse(arch, name)?),
513 InlineAsmArch::Wasm32 => Self::Wasm(WasmInlineAsmRegClass::parse(arch, name)?),
514 InlineAsmArch::Bpf => Self::Bpf(BpfInlineAsmRegClass::parse(arch, name)?),
518 /// Returns the list of template modifiers that can be used with this
520 pub fn valid_modifiers(self, arch: InlineAsmArch) -> &'static [char] {
522 Self::X86(r) => r.valid_modifiers(arch),
523 Self::Arm(r) => r.valid_modifiers(arch),
524 Self::AArch64(r) => r.valid_modifiers(arch),
525 Self::RiscV(r) => r.valid_modifiers(arch),
526 Self::Nvptx(r) => r.valid_modifiers(arch),
527 Self::PowerPC(r) => r.valid_modifiers(arch),
528 Self::Hexagon(r) => r.valid_modifiers(arch),
529 Self::Mips(r) => r.valid_modifiers(arch),
530 Self::SpirV(r) => r.valid_modifiers(arch),
531 Self::Wasm(r) => r.valid_modifiers(arch),
532 Self::Bpf(r) => r.valid_modifiers(arch),
533 Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
537 /// Returns whether registers in this class can only be used as clobbers
538 /// and not as inputs/outputs.
539 pub fn is_clobber_only(self, arch: InlineAsmArch) -> bool {
540 self.supported_types(arch).is_empty()
556 pub enum InlineAsmRegOrRegClass {
558 RegClass(InlineAsmRegClass),
561 impl InlineAsmRegOrRegClass {
562 pub fn reg_class(self) -> InlineAsmRegClass {
564 Self::Reg(r) => r.reg_class(),
565 Self::RegClass(r) => r,
570 impl fmt::Display for InlineAsmRegOrRegClass {
571 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
573 Self::Reg(r) => write!(f, "\"{}\"", r.name()),
574 Self::RegClass(r) => write!(f, "{}", r.name()),
579 /// Set of types which can be used with a particular register class.
580 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
581 pub enum InlineAsmType {
599 pub fn is_integer(self) -> bool {
600 matches!(self, Self::I8 | Self::I16 | Self::I32 | Self::I64 | Self::I128)
603 pub fn size(self) -> Size {
604 Size::from_bytes(match self {
612 Self::VecI8(n) => n * 1,
613 Self::VecI16(n) => n * 2,
614 Self::VecI32(n) => n * 4,
615 Self::VecI64(n) => n * 8,
616 Self::VecI128(n) => n * 16,
617 Self::VecF32(n) => n * 4,
618 Self::VecF64(n) => n * 8,
623 impl fmt::Display for InlineAsmType {
624 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
626 Self::I8 => f.write_str("i8"),
627 Self::I16 => f.write_str("i16"),
628 Self::I32 => f.write_str("i32"),
629 Self::I64 => f.write_str("i64"),
630 Self::I128 => f.write_str("i128"),
631 Self::F32 => f.write_str("f32"),
632 Self::F64 => f.write_str("f64"),
633 Self::VecI8(n) => write!(f, "i8x{}", n),
634 Self::VecI16(n) => write!(f, "i16x{}", n),
635 Self::VecI32(n) => write!(f, "i32x{}", n),
636 Self::VecI64(n) => write!(f, "i64x{}", n),
637 Self::VecI128(n) => write!(f, "i128x{}", n),
638 Self::VecF32(n) => write!(f, "f32x{}", n),
639 Self::VecF64(n) => write!(f, "f64x{}", n),
644 /// Returns the full set of allocatable registers for a given architecture.
646 /// The registers are structured as a map containing the set of allocatable
647 /// registers in each register class. A particular register may be allocatable
648 /// from multiple register classes, in which case it will appear multiple times
650 // NOTE: This function isn't used at the moment, but is needed to support
651 // falling back to an external assembler.
652 pub fn allocatable_registers(
654 has_feature: impl FnMut(&str) -> bool,
655 target: &crate::spec::Target,
656 ) -> FxHashMap<InlineAsmRegClass, FxHashSet<InlineAsmReg>> {
658 InlineAsmArch::X86 | InlineAsmArch::X86_64 => {
659 let mut map = x86::regclass_map();
660 x86::fill_reg_map(arch, has_feature, target, &mut map);
663 InlineAsmArch::Arm => {
664 let mut map = arm::regclass_map();
665 arm::fill_reg_map(arch, has_feature, target, &mut map);
668 InlineAsmArch::AArch64 => {
669 let mut map = aarch64::regclass_map();
670 aarch64::fill_reg_map(arch, has_feature, target, &mut map);
673 InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
674 let mut map = riscv::regclass_map();
675 riscv::fill_reg_map(arch, has_feature, target, &mut map);
678 InlineAsmArch::Nvptx64 => {
679 let mut map = nvptx::regclass_map();
680 nvptx::fill_reg_map(arch, has_feature, target, &mut map);
683 InlineAsmArch::PowerPC | InlineAsmArch::PowerPC64 => {
684 let mut map = powerpc::regclass_map();
685 powerpc::fill_reg_map(arch, has_feature, target, &mut map);
688 InlineAsmArch::Hexagon => {
689 let mut map = hexagon::regclass_map();
690 hexagon::fill_reg_map(arch, has_feature, target, &mut map);
693 InlineAsmArch::Mips | InlineAsmArch::Mips64 => {
694 let mut map = mips::regclass_map();
695 mips::fill_reg_map(arch, has_feature, target, &mut map);
698 InlineAsmArch::SpirV => {
699 let mut map = spirv::regclass_map();
700 spirv::fill_reg_map(arch, has_feature, target, &mut map);
703 InlineAsmArch::Wasm32 => {
704 let mut map = wasm::regclass_map();
705 wasm::fill_reg_map(arch, has_feature, target, &mut map);
708 InlineAsmArch::Bpf => {
709 let mut map = bpf::regclass_map();
710 bpf::fill_reg_map(arch, has_feature, target, &mut map);
728 pub enum InlineAsmClobberAbi {
737 impl InlineAsmClobberAbi {
738 /// Parses a clobber ABI for the given target, or returns a list of supported
739 /// clobber ABIs for the target.
744 ) -> Result<Self, &'static [&'static str]> {
745 let name = &*name.as_str();
747 InlineAsmArch::X86 => match name {
748 "C" | "system" | "efiapi" | "cdecl" | "stdcall" | "fastcall" => {
749 Ok(InlineAsmClobberAbi::X86)
751 _ => Err(&["C", "system", "efiapi", "cdecl", "stdcall", "fastcall"]),
753 InlineAsmArch::X86_64 => match name {
754 "C" | "system" if !target.is_like_windows => Ok(InlineAsmClobberAbi::X86_64SysV),
755 "C" | "system" if target.is_like_windows => Ok(InlineAsmClobberAbi::X86_64Win),
756 "win64" | "efiapi" => Ok(InlineAsmClobberAbi::X86_64Win),
757 "sysv64" => Ok(InlineAsmClobberAbi::X86_64SysV),
758 _ => Err(&["C", "system", "efiapi", "win64", "sysv64"]),
760 InlineAsmArch::Arm => match name {
761 "C" | "system" | "efiapi" | "aapcs" => Ok(InlineAsmClobberAbi::Arm),
762 _ => Err(&["C", "system", "efiapi", "aapcs"]),
764 InlineAsmArch::AArch64 => match name {
765 "C" | "system" | "efiapi" => Ok(InlineAsmClobberAbi::AArch64),
766 _ => Err(&["C", "system", "efiapi"]),
768 InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => match name {
769 "C" | "system" | "efiapi" => Ok(InlineAsmClobberAbi::RiscV),
770 _ => Err(&["C", "system", "efiapi"]),
776 /// Returns the set of registers which are clobbered by this ABI.
777 pub fn clobbered_regs(self) -> &'static [InlineAsmReg] {
778 macro_rules! clobbered_regs {
779 ($arch:ident $arch_reg:ident {
785 $(InlineAsmReg::$arch($arch_reg::$reg),)*
790 InlineAsmClobberAbi::X86 => clobbered_regs! {
791 X86 X86InlineAsmReg {
794 xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7,
796 k1, k2, k3, k4, k5, k6, k7,
798 mm0, mm1, mm2, mm3, mm4, mm5, mm6, mm7,
799 st0, st1, st2, st3, st4, st5, st6, st7,
802 InlineAsmClobberAbi::X86_64SysV => clobbered_regs! {
803 X86 X86InlineAsmReg {
804 ax, cx, dx, si, di, r8, r9, r10, r11,
806 xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7,
807 xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15,
808 zmm16, zmm17, zmm18, zmm19, zmm20, zmm21, zmm22, zmm23,
809 zmm24, zmm25, zmm26, zmm27, zmm28, zmm29, zmm30, zmm31,
811 k1, k2, k3, k4, k5, k6, k7,
813 mm0, mm1, mm2, mm3, mm4, mm5, mm6, mm7,
814 st0, st1, st2, st3, st4, st5, st6, st7,
817 InlineAsmClobberAbi::X86_64Win => clobbered_regs! {
818 X86 X86InlineAsmReg {
819 // rdi and rsi are callee-saved on windows
820 ax, cx, dx, r8, r9, r10, r11,
822 // xmm6-xmm15 are callee-saved on windows, but we need to
823 // mark them as clobbered anyways because the upper portions
824 // of ymm6-ymm15 are volatile.
825 xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7,
826 xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15,
827 zmm16, zmm17, zmm18, zmm19, zmm20, zmm21, zmm22, zmm23,
828 zmm24, zmm25, zmm26, zmm27, zmm28, zmm29, zmm30, zmm31,
830 k1, k2, k3, k4, k5, k6, k7,
832 mm0, mm1, mm2, mm3, mm4, mm5, mm6, mm7,
833 st0, st1, st2, st3, st4, st5, st6, st7,
836 InlineAsmClobberAbi::AArch64 => clobbered_regs! {
837 AArch64 AArch64InlineAsmReg {
838 x0, x1, x2, x3, x4, x5, x6, x7,
839 x8, x9, x10, x11, x12, x13, x14, x15,
840 // x18 is platform-reserved or temporary, but we exclude it
841 // here since it is a reserved register.
844 // Technically the low 64 bits of v8-v15 are preserved, but
845 // we have no way of expressing this using clobbers.
846 v0, v1, v2, v3, v4, v5, v6, v7,
847 v8, v9, v10, v11, v12, v13, v14, v15,
848 v16, v17, v18, v19, v20, v21, v22, v23,
849 v24, v25, v26, v27, v28, v29, v30, v31,
851 p0, p1, p2, p3, p4, p5, p6, p7,
852 p8, p9, p10, p11, p12, p13, p14, p15,
857 InlineAsmClobberAbi::Arm => clobbered_regs! {
858 Arm ArmInlineAsmReg {
859 // r9 is platform-reserved and is treated as callee-saved.
860 r0, r1, r2, r3, r12, r14,
862 // The finest-grained register variant is used here so that
863 // partial uses of larger registers are properly handled.
864 s0, s1, s2, s3, s4, s5, s6, s7,
865 s8, s9, s10, s11, s12, s13, s14, s15,
866 // s16-s31 are callee-saved
867 d16, d17, d18, d19, d20, d21, d22, d23,
868 d24, d25, d26, d27, d28, d29, d30, d31,
871 InlineAsmClobberAbi::RiscV => clobbered_regs! {
872 RiscV RiscVInlineAsmReg {
878 x10, x11, x12, x13, x14, x15, x16, x17,
882 f0, f1, f2, f3, f4, f5, f6, f7,
884 f10, f11, f12, f13, f14, f15, f16, f17,
888 v0, v1, v2, v3, v4, v5, v6, v7,
889 v8, v9, v10, v11, v12, v13, v14, v15,
890 v16, v17, v18, v19, v20, v21, v22, v23,
891 v24, v25, v26, v27, v28, v29, v30, v31,