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 _target_features: &rustc_data_structures::fx::FxHashSet<Symbol>,
85 _target: &crate::spec::Target,
87 ) -> Result<Self, &'static str> {
90 $($alias)|* | $reg_name => {
91 $($filter(_arch, _target_features, _target)?;)?
96 $($bad_reg)|* => Err($error),
98 _ => Err("unknown register"),
103 pub(super) fn fill_reg_map(
104 _arch: super::InlineAsmArch,
105 _target_features: &rustc_data_structures::fx::FxHashSet<Symbol>,
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, _target_features, _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:ident: $($ty2:expr),+;)*
136 use super::InlineAsmType::*;
142 ($ty2, Some(rustc_span::sym::$feature)),
164 pub use aarch64::{AArch64InlineAsmReg, AArch64InlineAsmRegClass};
165 pub use arm::{ArmInlineAsmReg, ArmInlineAsmRegClass};
166 pub use avr::{AvrInlineAsmReg, AvrInlineAsmRegClass};
167 pub use bpf::{BpfInlineAsmReg, BpfInlineAsmRegClass};
168 pub use hexagon::{HexagonInlineAsmReg, HexagonInlineAsmRegClass};
169 pub use mips::{MipsInlineAsmReg, MipsInlineAsmRegClass};
170 pub use msp430::{Msp430InlineAsmReg, Msp430InlineAsmRegClass};
171 pub use nvptx::{NvptxInlineAsmReg, NvptxInlineAsmRegClass};
172 pub use powerpc::{PowerPCInlineAsmReg, PowerPCInlineAsmRegClass};
173 pub use riscv::{RiscVInlineAsmReg, RiscVInlineAsmRegClass};
174 pub use s390x::{S390xInlineAsmReg, S390xInlineAsmRegClass};
175 pub use spirv::{SpirVInlineAsmReg, SpirVInlineAsmRegClass};
176 pub use wasm::{WasmInlineAsmReg, WasmInlineAsmRegClass};
177 pub use x86::{X86InlineAsmReg, X86InlineAsmRegClass};
179 #[derive(Copy, Clone, Encodable, Decodable, Debug, Eq, PartialEq, Hash)]
180 pub enum InlineAsmArch {
202 impl FromStr for InlineAsmArch {
205 fn from_str(s: &str) -> Result<InlineAsmArch, ()> {
207 "x86" => Ok(Self::X86),
208 "x86_64" => Ok(Self::X86_64),
209 "arm" => Ok(Self::Arm),
210 "aarch64" => Ok(Self::AArch64),
211 "riscv32" => Ok(Self::RiscV32),
212 "riscv64" => Ok(Self::RiscV64),
213 "nvptx64" => Ok(Self::Nvptx64),
214 "powerpc" => Ok(Self::PowerPC),
215 "powerpc64" => Ok(Self::PowerPC64),
216 "hexagon" => Ok(Self::Hexagon),
217 "mips" => Ok(Self::Mips),
218 "mips64" => Ok(Self::Mips64),
219 "s390x" => Ok(Self::S390x),
220 "spirv" => Ok(Self::SpirV),
221 "wasm32" => Ok(Self::Wasm32),
222 "wasm64" => Ok(Self::Wasm64),
223 "bpf" => Ok(Self::Bpf),
224 "avr" => Ok(Self::Avr),
225 "msp430" => Ok(Self::Msp430),
243 pub enum InlineAsmReg {
244 X86(X86InlineAsmReg),
245 Arm(ArmInlineAsmReg),
246 AArch64(AArch64InlineAsmReg),
247 RiscV(RiscVInlineAsmReg),
248 Nvptx(NvptxInlineAsmReg),
249 PowerPC(PowerPCInlineAsmReg),
250 Hexagon(HexagonInlineAsmReg),
251 Mips(MipsInlineAsmReg),
252 S390x(S390xInlineAsmReg),
253 SpirV(SpirVInlineAsmReg),
254 Wasm(WasmInlineAsmReg),
255 Bpf(BpfInlineAsmReg),
256 Avr(AvrInlineAsmReg),
257 Msp430(Msp430InlineAsmReg),
258 // Placeholder for invalid register constraints for the current target
263 pub fn name(self) -> &'static str {
265 Self::X86(r) => r.name(),
266 Self::Arm(r) => r.name(),
267 Self::AArch64(r) => r.name(),
268 Self::RiscV(r) => r.name(),
269 Self::PowerPC(r) => r.name(),
270 Self::Hexagon(r) => r.name(),
271 Self::Mips(r) => r.name(),
272 Self::S390x(r) => r.name(),
273 Self::Bpf(r) => r.name(),
274 Self::Avr(r) => r.name(),
275 Self::Msp430(r) => r.name(),
276 Self::Err => "<reg>",
280 pub fn reg_class(self) -> InlineAsmRegClass {
282 Self::X86(r) => InlineAsmRegClass::X86(r.reg_class()),
283 Self::Arm(r) => InlineAsmRegClass::Arm(r.reg_class()),
284 Self::AArch64(r) => InlineAsmRegClass::AArch64(r.reg_class()),
285 Self::RiscV(r) => InlineAsmRegClass::RiscV(r.reg_class()),
286 Self::PowerPC(r) => InlineAsmRegClass::PowerPC(r.reg_class()),
287 Self::Hexagon(r) => InlineAsmRegClass::Hexagon(r.reg_class()),
288 Self::Mips(r) => InlineAsmRegClass::Mips(r.reg_class()),
289 Self::S390x(r) => InlineAsmRegClass::S390x(r.reg_class()),
290 Self::Bpf(r) => InlineAsmRegClass::Bpf(r.reg_class()),
291 Self::Avr(r) => InlineAsmRegClass::Avr(r.reg_class()),
292 Self::Msp430(r) => InlineAsmRegClass::Msp430(r.reg_class()),
293 Self::Err => InlineAsmRegClass::Err,
299 target_features: &FxHashSet<Symbol>,
302 ) -> Result<Self, &'static str> {
303 // FIXME: use direct symbol comparison for register names
304 // Use `Symbol::as_str` instead of `Symbol::with` here because `has_feature` may access `Symbol`.
305 let name = name.as_str();
307 InlineAsmArch::X86 | InlineAsmArch::X86_64 => {
308 Self::X86(X86InlineAsmReg::parse(arch, target_features, target, name)?)
310 InlineAsmArch::Arm => {
311 Self::Arm(ArmInlineAsmReg::parse(arch, target_features, target, name)?)
313 InlineAsmArch::AArch64 => {
314 Self::AArch64(AArch64InlineAsmReg::parse(arch, target_features, target, name)?)
316 InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
317 Self::RiscV(RiscVInlineAsmReg::parse(arch, target_features, target, name)?)
319 InlineAsmArch::Nvptx64 => {
320 Self::Nvptx(NvptxInlineAsmReg::parse(arch, target_features, target, name)?)
322 InlineAsmArch::PowerPC | InlineAsmArch::PowerPC64 => {
323 Self::PowerPC(PowerPCInlineAsmReg::parse(arch, target_features, target, name)?)
325 InlineAsmArch::Hexagon => {
326 Self::Hexagon(HexagonInlineAsmReg::parse(arch, target_features, target, name)?)
328 InlineAsmArch::Mips | InlineAsmArch::Mips64 => {
329 Self::Mips(MipsInlineAsmReg::parse(arch, target_features, target, name)?)
331 InlineAsmArch::S390x => {
332 Self::S390x(S390xInlineAsmReg::parse(arch, target_features, target, name)?)
334 InlineAsmArch::SpirV => {
335 Self::SpirV(SpirVInlineAsmReg::parse(arch, target_features, target, name)?)
337 InlineAsmArch::Wasm32 | InlineAsmArch::Wasm64 => {
338 Self::Wasm(WasmInlineAsmReg::parse(arch, target_features, target, name)?)
340 InlineAsmArch::Bpf => {
341 Self::Bpf(BpfInlineAsmReg::parse(arch, target_features, target, name)?)
343 InlineAsmArch::Avr => {
344 Self::Avr(AvrInlineAsmReg::parse(arch, target_features, target, name)?)
346 InlineAsmArch::Msp430 => {
347 Self::Msp430(Msp430InlineAsmReg::parse(arch, target_features, target, name)?)
352 // NOTE: This function isn't used at the moment, but is needed to support
353 // falling back to an external assembler.
356 out: &mut dyn fmt::Write,
358 modifier: Option<char>,
361 Self::X86(r) => r.emit(out, arch, modifier),
362 Self::Arm(r) => r.emit(out, arch, modifier),
363 Self::AArch64(r) => r.emit(out, arch, modifier),
364 Self::RiscV(r) => r.emit(out, arch, modifier),
365 Self::PowerPC(r) => r.emit(out, arch, modifier),
366 Self::Hexagon(r) => r.emit(out, arch, modifier),
367 Self::Mips(r) => r.emit(out, arch, modifier),
368 Self::S390x(r) => r.emit(out, arch, modifier),
369 Self::Bpf(r) => r.emit(out, arch, modifier),
370 Self::Avr(r) => r.emit(out, arch, modifier),
371 Self::Msp430(r) => r.emit(out, arch, modifier),
372 Self::Err => unreachable!("Use of InlineAsmReg::Err"),
376 pub fn overlapping_regs(self, mut cb: impl FnMut(InlineAsmReg)) {
378 Self::X86(r) => r.overlapping_regs(|r| cb(Self::X86(r))),
379 Self::Arm(r) => r.overlapping_regs(|r| cb(Self::Arm(r))),
380 Self::AArch64(_) => cb(self),
381 Self::RiscV(_) => cb(self),
382 Self::PowerPC(r) => r.overlapping_regs(|r| cb(Self::PowerPC(r))),
383 Self::Hexagon(r) => r.overlapping_regs(|r| cb(Self::Hexagon(r))),
384 Self::Mips(_) => cb(self),
385 Self::S390x(_) => cb(self),
386 Self::Bpf(r) => r.overlapping_regs(|r| cb(Self::Bpf(r))),
387 Self::Avr(r) => r.overlapping_regs(|r| cb(Self::Avr(r))),
388 Self::Msp430(_) => cb(self),
389 Self::Err => unreachable!("Use of InlineAsmReg::Err"),
406 pub enum InlineAsmRegClass {
407 X86(X86InlineAsmRegClass),
408 Arm(ArmInlineAsmRegClass),
409 AArch64(AArch64InlineAsmRegClass),
410 RiscV(RiscVInlineAsmRegClass),
411 Nvptx(NvptxInlineAsmRegClass),
412 PowerPC(PowerPCInlineAsmRegClass),
413 Hexagon(HexagonInlineAsmRegClass),
414 Mips(MipsInlineAsmRegClass),
415 S390x(S390xInlineAsmRegClass),
416 SpirV(SpirVInlineAsmRegClass),
417 Wasm(WasmInlineAsmRegClass),
418 Bpf(BpfInlineAsmRegClass),
419 Avr(AvrInlineAsmRegClass),
420 Msp430(Msp430InlineAsmRegClass),
421 // Placeholder for invalid register constraints for the current target
425 impl InlineAsmRegClass {
426 pub fn name(self) -> Symbol {
428 Self::X86(r) => r.name(),
429 Self::Arm(r) => r.name(),
430 Self::AArch64(r) => r.name(),
431 Self::RiscV(r) => r.name(),
432 Self::Nvptx(r) => r.name(),
433 Self::PowerPC(r) => r.name(),
434 Self::Hexagon(r) => r.name(),
435 Self::Mips(r) => r.name(),
436 Self::S390x(r) => r.name(),
437 Self::SpirV(r) => r.name(),
438 Self::Wasm(r) => r.name(),
439 Self::Bpf(r) => r.name(),
440 Self::Avr(r) => r.name(),
441 Self::Msp430(r) => r.name(),
442 Self::Err => rustc_span::symbol::sym::reg,
446 /// Returns a suggested register class to use for this type. This is called
447 /// when `supported_types` fails to give a better error
448 /// message to the user.
449 pub fn suggest_class(self, arch: InlineAsmArch, ty: InlineAsmType) -> Option<Self> {
451 Self::X86(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::X86),
452 Self::Arm(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Arm),
453 Self::AArch64(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::AArch64),
454 Self::RiscV(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::RiscV),
455 Self::Nvptx(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Nvptx),
456 Self::PowerPC(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::PowerPC),
457 Self::Hexagon(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Hexagon),
458 Self::Mips(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Mips),
459 Self::S390x(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::S390x),
460 Self::SpirV(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::SpirV),
461 Self::Wasm(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Wasm),
462 Self::Bpf(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Bpf),
463 Self::Avr(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Avr),
464 Self::Msp430(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Msp430),
465 Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
469 /// Returns a suggested template modifier to use for this type and an
470 /// example of a register named formatted with it.
472 /// Such suggestions are useful if a type smaller than the full register
473 /// size is used and a modifier can be used to point to the subregister of
474 /// the correct size.
475 pub fn suggest_modifier(
479 ) -> Option<(char, &'static str)> {
481 Self::X86(r) => r.suggest_modifier(arch, ty),
482 Self::Arm(r) => r.suggest_modifier(arch, ty),
483 Self::AArch64(r) => r.suggest_modifier(arch, ty),
484 Self::RiscV(r) => r.suggest_modifier(arch, ty),
485 Self::Nvptx(r) => r.suggest_modifier(arch, ty),
486 Self::PowerPC(r) => r.suggest_modifier(arch, ty),
487 Self::Hexagon(r) => r.suggest_modifier(arch, ty),
488 Self::Mips(r) => r.suggest_modifier(arch, ty),
489 Self::S390x(r) => r.suggest_modifier(arch, ty),
490 Self::SpirV(r) => r.suggest_modifier(arch, ty),
491 Self::Wasm(r) => r.suggest_modifier(arch, ty),
492 Self::Bpf(r) => r.suggest_modifier(arch, ty),
493 Self::Avr(r) => r.suggest_modifier(arch, ty),
494 Self::Msp430(r) => r.suggest_modifier(arch, ty),
495 Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
499 /// Returns the default modifier for this register and an example of a
500 /// register named formatted with it.
502 /// This is only needed when the register class can suggest a modifier, so
503 /// that the user can be shown how to get the default behavior without a
505 pub fn default_modifier(self, arch: InlineAsmArch) -> Option<(char, &'static str)> {
507 Self::X86(r) => r.default_modifier(arch),
508 Self::Arm(r) => r.default_modifier(arch),
509 Self::AArch64(r) => r.default_modifier(arch),
510 Self::RiscV(r) => r.default_modifier(arch),
511 Self::Nvptx(r) => r.default_modifier(arch),
512 Self::PowerPC(r) => r.default_modifier(arch),
513 Self::Hexagon(r) => r.default_modifier(arch),
514 Self::Mips(r) => r.default_modifier(arch),
515 Self::S390x(r) => r.default_modifier(arch),
516 Self::SpirV(r) => r.default_modifier(arch),
517 Self::Wasm(r) => r.default_modifier(arch),
518 Self::Bpf(r) => r.default_modifier(arch),
519 Self::Avr(r) => r.default_modifier(arch),
520 Self::Msp430(r) => r.default_modifier(arch),
521 Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
525 /// Returns a list of supported types for this register class, each with an
526 /// options target feature required to use this type.
527 pub fn supported_types(
530 ) -> &'static [(InlineAsmType, Option<Symbol>)] {
532 Self::X86(r) => r.supported_types(arch),
533 Self::Arm(r) => r.supported_types(arch),
534 Self::AArch64(r) => r.supported_types(arch),
535 Self::RiscV(r) => r.supported_types(arch),
536 Self::Nvptx(r) => r.supported_types(arch),
537 Self::PowerPC(r) => r.supported_types(arch),
538 Self::Hexagon(r) => r.supported_types(arch),
539 Self::Mips(r) => r.supported_types(arch),
540 Self::S390x(r) => r.supported_types(arch),
541 Self::SpirV(r) => r.supported_types(arch),
542 Self::Wasm(r) => r.supported_types(arch),
543 Self::Bpf(r) => r.supported_types(arch),
544 Self::Avr(r) => r.supported_types(arch),
545 Self::Msp430(r) => r.supported_types(arch),
546 Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
550 pub fn parse(arch: InlineAsmArch, name: Symbol) -> Result<Self, &'static str> {
552 InlineAsmArch::X86 | InlineAsmArch::X86_64 => {
553 Self::X86(X86InlineAsmRegClass::parse(arch, name)?)
555 InlineAsmArch::Arm => Self::Arm(ArmInlineAsmRegClass::parse(arch, name)?),
556 InlineAsmArch::AArch64 => Self::AArch64(AArch64InlineAsmRegClass::parse(arch, name)?),
557 InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
558 Self::RiscV(RiscVInlineAsmRegClass::parse(arch, name)?)
560 InlineAsmArch::Nvptx64 => Self::Nvptx(NvptxInlineAsmRegClass::parse(arch, name)?),
561 InlineAsmArch::PowerPC | InlineAsmArch::PowerPC64 => {
562 Self::PowerPC(PowerPCInlineAsmRegClass::parse(arch, name)?)
564 InlineAsmArch::Hexagon => Self::Hexagon(HexagonInlineAsmRegClass::parse(arch, name)?),
565 InlineAsmArch::Mips | InlineAsmArch::Mips64 => {
566 Self::Mips(MipsInlineAsmRegClass::parse(arch, name)?)
568 InlineAsmArch::S390x => Self::S390x(S390xInlineAsmRegClass::parse(arch, name)?),
569 InlineAsmArch::SpirV => Self::SpirV(SpirVInlineAsmRegClass::parse(arch, name)?),
570 InlineAsmArch::Wasm32 | InlineAsmArch::Wasm64 => {
571 Self::Wasm(WasmInlineAsmRegClass::parse(arch, name)?)
573 InlineAsmArch::Bpf => Self::Bpf(BpfInlineAsmRegClass::parse(arch, name)?),
574 InlineAsmArch::Avr => Self::Avr(AvrInlineAsmRegClass::parse(arch, name)?),
575 InlineAsmArch::Msp430 => Self::Msp430(Msp430InlineAsmRegClass::parse(arch, name)?),
579 /// Returns the list of template modifiers that can be used with this
581 pub fn valid_modifiers(self, arch: InlineAsmArch) -> &'static [char] {
583 Self::X86(r) => r.valid_modifiers(arch),
584 Self::Arm(r) => r.valid_modifiers(arch),
585 Self::AArch64(r) => r.valid_modifiers(arch),
586 Self::RiscV(r) => r.valid_modifiers(arch),
587 Self::Nvptx(r) => r.valid_modifiers(arch),
588 Self::PowerPC(r) => r.valid_modifiers(arch),
589 Self::Hexagon(r) => r.valid_modifiers(arch),
590 Self::Mips(r) => r.valid_modifiers(arch),
591 Self::S390x(r) => r.valid_modifiers(arch),
592 Self::SpirV(r) => r.valid_modifiers(arch),
593 Self::Wasm(r) => r.valid_modifiers(arch),
594 Self::Bpf(r) => r.valid_modifiers(arch),
595 Self::Avr(r) => r.valid_modifiers(arch),
596 Self::Msp430(r) => r.valid_modifiers(arch),
597 Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
601 /// Returns whether registers in this class can only be used as clobbers
602 /// and not as inputs/outputs.
603 pub fn is_clobber_only(self, arch: InlineAsmArch) -> bool {
604 self.supported_types(arch).is_empty()
620 pub enum InlineAsmRegOrRegClass {
622 RegClass(InlineAsmRegClass),
625 impl InlineAsmRegOrRegClass {
626 pub fn reg_class(self) -> InlineAsmRegClass {
628 Self::Reg(r) => r.reg_class(),
629 Self::RegClass(r) => r,
634 impl fmt::Display for InlineAsmRegOrRegClass {
635 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
637 Self::Reg(r) => write!(f, "\"{}\"", r.name()),
638 Self::RegClass(r) => write!(f, "{}", r.name()),
643 /// Set of types which can be used with a particular register class.
644 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
645 pub enum InlineAsmType {
663 pub fn is_integer(self) -> bool {
664 matches!(self, Self::I8 | Self::I16 | Self::I32 | Self::I64 | Self::I128)
667 pub fn size(self) -> Size {
668 Size::from_bytes(match self {
676 Self::VecI8(n) => n * 1,
677 Self::VecI16(n) => n * 2,
678 Self::VecI32(n) => n * 4,
679 Self::VecI64(n) => n * 8,
680 Self::VecI128(n) => n * 16,
681 Self::VecF32(n) => n * 4,
682 Self::VecF64(n) => n * 8,
687 impl fmt::Display for InlineAsmType {
688 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
690 Self::I8 => f.write_str("i8"),
691 Self::I16 => f.write_str("i16"),
692 Self::I32 => f.write_str("i32"),
693 Self::I64 => f.write_str("i64"),
694 Self::I128 => f.write_str("i128"),
695 Self::F32 => f.write_str("f32"),
696 Self::F64 => f.write_str("f64"),
697 Self::VecI8(n) => write!(f, "i8x{}", n),
698 Self::VecI16(n) => write!(f, "i16x{}", n),
699 Self::VecI32(n) => write!(f, "i32x{}", n),
700 Self::VecI64(n) => write!(f, "i64x{}", n),
701 Self::VecI128(n) => write!(f, "i128x{}", n),
702 Self::VecF32(n) => write!(f, "f32x{}", n),
703 Self::VecF64(n) => write!(f, "f64x{}", n),
708 /// Returns the full set of allocatable registers for a given architecture.
710 /// The registers are structured as a map containing the set of allocatable
711 /// registers in each register class. A particular register may be allocatable
712 /// from multiple register classes, in which case it will appear multiple times
714 // NOTE: This function isn't used at the moment, but is needed to support
715 // falling back to an external assembler.
716 pub fn allocatable_registers(
718 target_features: &FxHashSet<Symbol>,
719 target: &crate::spec::Target,
720 ) -> FxHashMap<InlineAsmRegClass, FxHashSet<InlineAsmReg>> {
722 InlineAsmArch::X86 | InlineAsmArch::X86_64 => {
723 let mut map = x86::regclass_map();
724 x86::fill_reg_map(arch, target_features, target, &mut map);
727 InlineAsmArch::Arm => {
728 let mut map = arm::regclass_map();
729 arm::fill_reg_map(arch, target_features, target, &mut map);
732 InlineAsmArch::AArch64 => {
733 let mut map = aarch64::regclass_map();
734 aarch64::fill_reg_map(arch, target_features, target, &mut map);
737 InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
738 let mut map = riscv::regclass_map();
739 riscv::fill_reg_map(arch, target_features, target, &mut map);
742 InlineAsmArch::Nvptx64 => {
743 let mut map = nvptx::regclass_map();
744 nvptx::fill_reg_map(arch, target_features, target, &mut map);
747 InlineAsmArch::PowerPC | InlineAsmArch::PowerPC64 => {
748 let mut map = powerpc::regclass_map();
749 powerpc::fill_reg_map(arch, target_features, target, &mut map);
752 InlineAsmArch::Hexagon => {
753 let mut map = hexagon::regclass_map();
754 hexagon::fill_reg_map(arch, target_features, target, &mut map);
757 InlineAsmArch::Mips | InlineAsmArch::Mips64 => {
758 let mut map = mips::regclass_map();
759 mips::fill_reg_map(arch, target_features, target, &mut map);
762 InlineAsmArch::S390x => {
763 let mut map = s390x::regclass_map();
764 s390x::fill_reg_map(arch, target_features, target, &mut map);
767 InlineAsmArch::SpirV => {
768 let mut map = spirv::regclass_map();
769 spirv::fill_reg_map(arch, target_features, target, &mut map);
772 InlineAsmArch::Wasm32 | InlineAsmArch::Wasm64 => {
773 let mut map = wasm::regclass_map();
774 wasm::fill_reg_map(arch, target_features, target, &mut map);
777 InlineAsmArch::Bpf => {
778 let mut map = bpf::regclass_map();
779 bpf::fill_reg_map(arch, target_features, target, &mut map);
782 InlineAsmArch::Avr => {
783 let mut map = avr::regclass_map();
784 avr::fill_reg_map(arch, target_features, target, &mut map);
787 InlineAsmArch::Msp430 => {
788 let mut map = msp430::regclass_map();
789 msp430::fill_reg_map(arch, target_features, target, &mut map);
807 pub enum InlineAsmClobberAbi {
817 impl InlineAsmClobberAbi {
818 /// Parses a clobber ABI for the given target, or returns a list of supported
819 /// clobber ABIs for the target.
822 target_features: &FxHashSet<Symbol>,
825 ) -> Result<Self, &'static [&'static str]> {
826 let name = name.as_str();
828 InlineAsmArch::X86 => match name {
829 "C" | "system" | "efiapi" | "cdecl" | "stdcall" | "fastcall" => {
830 Ok(InlineAsmClobberAbi::X86)
832 _ => Err(&["C", "system", "efiapi", "cdecl", "stdcall", "fastcall"]),
834 InlineAsmArch::X86_64 => match name {
835 "C" | "system" if !target.is_like_windows => Ok(InlineAsmClobberAbi::X86_64SysV),
836 "C" | "system" if target.is_like_windows => Ok(InlineAsmClobberAbi::X86_64Win),
837 "win64" | "efiapi" => Ok(InlineAsmClobberAbi::X86_64Win),
838 "sysv64" => Ok(InlineAsmClobberAbi::X86_64SysV),
839 _ => Err(&["C", "system", "efiapi", "win64", "sysv64"]),
841 InlineAsmArch::Arm => match name {
842 "C" | "system" | "efiapi" | "aapcs" => Ok(InlineAsmClobberAbi::Arm),
843 _ => Err(&["C", "system", "efiapi", "aapcs"]),
845 InlineAsmArch::AArch64 => match name {
846 "C" | "system" | "efiapi" => {
847 Ok(if aarch64::reserved_x18(arch, target_features, target).is_err() {
848 InlineAsmClobberAbi::AArch64NoX18
850 InlineAsmClobberAbi::AArch64
853 _ => Err(&["C", "system", "efiapi"]),
855 InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => match name {
856 "C" | "system" | "efiapi" => Ok(InlineAsmClobberAbi::RiscV),
857 _ => Err(&["C", "system", "efiapi"]),
863 /// Returns the set of registers which are clobbered by this ABI.
864 pub fn clobbered_regs(self) -> &'static [InlineAsmReg] {
865 macro_rules! clobbered_regs {
866 ($arch:ident $arch_reg:ident {
872 $(InlineAsmReg::$arch($arch_reg::$reg),)*
877 InlineAsmClobberAbi::X86 => clobbered_regs! {
878 X86 X86InlineAsmReg {
881 xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7,
883 k1, k2, k3, k4, k5, k6, k7,
885 mm0, mm1, mm2, mm3, mm4, mm5, mm6, mm7,
886 st0, st1, st2, st3, st4, st5, st6, st7,
889 InlineAsmClobberAbi::X86_64SysV => clobbered_regs! {
890 X86 X86InlineAsmReg {
891 ax, cx, dx, si, di, r8, r9, r10, r11,
893 xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7,
894 xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15,
895 zmm16, zmm17, zmm18, zmm19, zmm20, zmm21, zmm22, zmm23,
896 zmm24, zmm25, zmm26, zmm27, zmm28, zmm29, zmm30, zmm31,
898 k1, k2, k3, k4, k5, k6, k7,
900 mm0, mm1, mm2, mm3, mm4, mm5, mm6, mm7,
901 st0, st1, st2, st3, st4, st5, st6, st7,
904 InlineAsmClobberAbi::X86_64Win => clobbered_regs! {
905 X86 X86InlineAsmReg {
906 // rdi and rsi are callee-saved on windows
907 ax, cx, dx, r8, r9, r10, r11,
909 // xmm6-xmm15 are callee-saved on windows, but we need to
910 // mark them as clobbered anyways because the upper portions
911 // of ymm6-ymm15 are volatile.
912 xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7,
913 xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15,
914 zmm16, zmm17, zmm18, zmm19, zmm20, zmm21, zmm22, zmm23,
915 zmm24, zmm25, zmm26, zmm27, zmm28, zmm29, zmm30, zmm31,
917 k1, k2, k3, k4, k5, k6, k7,
919 mm0, mm1, mm2, mm3, mm4, mm5, mm6, mm7,
920 st0, st1, st2, st3, st4, st5, st6, st7,
923 InlineAsmClobberAbi::AArch64 => clobbered_regs! {
924 AArch64 AArch64InlineAsmReg {
925 x0, x1, x2, x3, x4, x5, x6, x7,
926 x8, x9, x10, x11, x12, x13, x14, x15,
929 // Technically the low 64 bits of v8-v15 are preserved, but
930 // we have no way of expressing this using clobbers.
931 v0, v1, v2, v3, v4, v5, v6, v7,
932 v8, v9, v10, v11, v12, v13, v14, v15,
933 v16, v17, v18, v19, v20, v21, v22, v23,
934 v24, v25, v26, v27, v28, v29, v30, v31,
936 p0, p1, p2, p3, p4, p5, p6, p7,
937 p8, p9, p10, p11, p12, p13, p14, p15,
942 InlineAsmClobberAbi::AArch64NoX18 => clobbered_regs! {
943 AArch64 AArch64InlineAsmReg {
944 x0, x1, x2, x3, x4, x5, x6, x7,
945 x8, x9, x10, x11, x12, x13, x14, x15,
948 // Technically the low 64 bits of v8-v15 are preserved, but
949 // we have no way of expressing this using clobbers.
950 v0, v1, v2, v3, v4, v5, v6, v7,
951 v8, v9, v10, v11, v12, v13, v14, v15,
952 v16, v17, v18, v19, v20, v21, v22, v23,
953 v24, v25, v26, v27, v28, v29, v30, v31,
955 p0, p1, p2, p3, p4, p5, p6, p7,
956 p8, p9, p10, p11, p12, p13, p14, p15,
961 InlineAsmClobberAbi::Arm => clobbered_regs! {
962 Arm ArmInlineAsmReg {
963 // r9 is either platform-reserved or callee-saved. Either
964 // way we don't need to clobber it.
965 r0, r1, r2, r3, r12, r14,
967 // The finest-grained register variant is used here so that
968 // partial uses of larger registers are properly handled.
969 s0, s1, s2, s3, s4, s5, s6, s7,
970 s8, s9, s10, s11, s12, s13, s14, s15,
971 // s16-s31 are callee-saved
972 d16, d17, d18, d19, d20, d21, d22, d23,
973 d24, d25, d26, d27, d28, d29, d30, d31,
976 InlineAsmClobberAbi::RiscV => clobbered_regs! {
977 RiscV RiscVInlineAsmReg {
983 x10, x11, x12, x13, x14, x15, x16, x17,
987 f0, f1, f2, f3, f4, f5, f6, f7,
989 f10, f11, f12, f13, f14, f15, f16, f17,
993 v0, v1, v2, v3, v4, v5, v6, v7,
994 v8, v9, v10, v11, v12, v13, v14, v15,
995 v16, v17, v18, v19, v20, v21, v22, v23,
996 v24, v25, v26, v27, v28, v29, v30, v31,