1 use crate::spec::Target;
2 use crate::{abi::Size, spec::RelocModel};
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(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,)*
82 pub fn parse(name: &str) -> Result<Self, &'static str> {
85 $($alias)|* | $reg_name => Ok(Self::$reg),
88 $($bad_reg)|* => Err($error),
90 _ => Err("unknown register"),
95 _arch: super::InlineAsmArch,
96 _reloc_model: crate::spec::RelocModel,
97 _target_features: &rustc_data_structures::fx::FxHashSet<Symbol>,
98 _target: &crate::spec::Target,
100 ) -> Result<(), &'static str> {
118 pub(super) fn fill_reg_map(
119 _arch: super::InlineAsmArch,
120 _reloc_model: crate::spec::RelocModel,
121 _target_features: &rustc_data_structures::fx::FxHashSet<Symbol>,
122 _target: &crate::spec::Target,
123 _map: &mut rustc_data_structures::fx::FxHashMap<
124 super::InlineAsmRegClass,
125 rustc_data_structures::fx::FxHashSet<super::InlineAsmReg>,
128 #[allow(unused_imports)]
129 use super::{InlineAsmReg, InlineAsmRegClass};
131 if $($filter(_arch, _reloc_model, _target_features, _target, false).is_ok() &&)? true {
132 if let Some(set) = _map.get_mut(&InlineAsmRegClass::$arch($arch_regclass::$class)) {
133 set.insert(InlineAsmReg::$arch($arch_reg::$reg));
136 if let Some(set) = _map.get_mut(&InlineAsmRegClass::$arch($arch_regclass::$extra_class)) {
137 set.insert(InlineAsmReg::$arch($arch_reg::$reg));
148 $(_ : $($ty:expr),+;)?
149 $($feature:ident: $($ty2:expr),+;)*
152 use super::InlineAsmType::*;
158 ($ty2, Some(rustc_span::sym::$feature)),
180 pub use aarch64::{AArch64InlineAsmReg, AArch64InlineAsmRegClass};
181 pub use arm::{ArmInlineAsmReg, ArmInlineAsmRegClass};
182 pub use avr::{AvrInlineAsmReg, AvrInlineAsmRegClass};
183 pub use bpf::{BpfInlineAsmReg, BpfInlineAsmRegClass};
184 pub use hexagon::{HexagonInlineAsmReg, HexagonInlineAsmRegClass};
185 pub use mips::{MipsInlineAsmReg, MipsInlineAsmRegClass};
186 pub use msp430::{Msp430InlineAsmReg, Msp430InlineAsmRegClass};
187 pub use nvptx::{NvptxInlineAsmReg, NvptxInlineAsmRegClass};
188 pub use powerpc::{PowerPCInlineAsmReg, PowerPCInlineAsmRegClass};
189 pub use riscv::{RiscVInlineAsmReg, RiscVInlineAsmRegClass};
190 pub use s390x::{S390xInlineAsmReg, S390xInlineAsmRegClass};
191 pub use spirv::{SpirVInlineAsmReg, SpirVInlineAsmRegClass};
192 pub use wasm::{WasmInlineAsmReg, WasmInlineAsmRegClass};
193 pub use x86::{X86InlineAsmReg, X86InlineAsmRegClass};
195 #[derive(Copy, Clone, Encodable, Decodable, Debug, Eq, PartialEq, Hash)]
196 pub enum InlineAsmArch {
218 impl FromStr for InlineAsmArch {
221 fn from_str(s: &str) -> Result<InlineAsmArch, ()> {
223 "x86" => Ok(Self::X86),
224 "x86_64" => Ok(Self::X86_64),
225 "arm" => Ok(Self::Arm),
226 "aarch64" => Ok(Self::AArch64),
227 "riscv32" => Ok(Self::RiscV32),
228 "riscv64" => Ok(Self::RiscV64),
229 "nvptx64" => Ok(Self::Nvptx64),
230 "powerpc" => Ok(Self::PowerPC),
231 "powerpc64" => Ok(Self::PowerPC64),
232 "hexagon" => Ok(Self::Hexagon),
233 "mips" => Ok(Self::Mips),
234 "mips64" => Ok(Self::Mips64),
235 "s390x" => Ok(Self::S390x),
236 "spirv" => Ok(Self::SpirV),
237 "wasm32" => Ok(Self::Wasm32),
238 "wasm64" => Ok(Self::Wasm64),
239 "bpf" => Ok(Self::Bpf),
240 "avr" => Ok(Self::Avr),
241 "msp430" => Ok(Self::Msp430),
247 #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Hash)]
248 #[derive(HashStable_Generic, Encodable, Decodable)]
249 pub enum InlineAsmReg {
250 X86(X86InlineAsmReg),
251 Arm(ArmInlineAsmReg),
252 AArch64(AArch64InlineAsmReg),
253 RiscV(RiscVInlineAsmReg),
254 Nvptx(NvptxInlineAsmReg),
255 PowerPC(PowerPCInlineAsmReg),
256 Hexagon(HexagonInlineAsmReg),
257 Mips(MipsInlineAsmReg),
258 S390x(S390xInlineAsmReg),
259 SpirV(SpirVInlineAsmReg),
260 Wasm(WasmInlineAsmReg),
261 Bpf(BpfInlineAsmReg),
262 Avr(AvrInlineAsmReg),
263 Msp430(Msp430InlineAsmReg),
264 // Placeholder for invalid register constraints for the current target
269 pub fn name(self) -> &'static str {
271 Self::X86(r) => r.name(),
272 Self::Arm(r) => r.name(),
273 Self::AArch64(r) => r.name(),
274 Self::RiscV(r) => r.name(),
275 Self::PowerPC(r) => r.name(),
276 Self::Hexagon(r) => r.name(),
277 Self::Mips(r) => r.name(),
278 Self::S390x(r) => r.name(),
279 Self::Bpf(r) => r.name(),
280 Self::Avr(r) => r.name(),
281 Self::Msp430(r) => r.name(),
282 Self::Err => "<reg>",
286 pub fn reg_class(self) -> InlineAsmRegClass {
288 Self::X86(r) => InlineAsmRegClass::X86(r.reg_class()),
289 Self::Arm(r) => InlineAsmRegClass::Arm(r.reg_class()),
290 Self::AArch64(r) => InlineAsmRegClass::AArch64(r.reg_class()),
291 Self::RiscV(r) => InlineAsmRegClass::RiscV(r.reg_class()),
292 Self::PowerPC(r) => InlineAsmRegClass::PowerPC(r.reg_class()),
293 Self::Hexagon(r) => InlineAsmRegClass::Hexagon(r.reg_class()),
294 Self::Mips(r) => InlineAsmRegClass::Mips(r.reg_class()),
295 Self::S390x(r) => InlineAsmRegClass::S390x(r.reg_class()),
296 Self::Bpf(r) => InlineAsmRegClass::Bpf(r.reg_class()),
297 Self::Avr(r) => InlineAsmRegClass::Avr(r.reg_class()),
298 Self::Msp430(r) => InlineAsmRegClass::Msp430(r.reg_class()),
299 Self::Err => InlineAsmRegClass::Err,
303 pub fn parse(arch: InlineAsmArch, name: Symbol) -> Result<Self, &'static str> {
304 // FIXME: use direct symbol comparison for register names
305 // Use `Symbol::as_str` instead of `Symbol::with` here because `has_feature` may access `Symbol`.
306 let name = name.as_str();
308 InlineAsmArch::X86 | InlineAsmArch::X86_64 => Self::X86(X86InlineAsmReg::parse(name)?),
309 InlineAsmArch::Arm => Self::Arm(ArmInlineAsmReg::parse(name)?),
310 InlineAsmArch::AArch64 => Self::AArch64(AArch64InlineAsmReg::parse(name)?),
311 InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
312 Self::RiscV(RiscVInlineAsmReg::parse(name)?)
314 InlineAsmArch::Nvptx64 => Self::Nvptx(NvptxInlineAsmReg::parse(name)?),
315 InlineAsmArch::PowerPC | InlineAsmArch::PowerPC64 => {
316 Self::PowerPC(PowerPCInlineAsmReg::parse(name)?)
318 InlineAsmArch::Hexagon => Self::Hexagon(HexagonInlineAsmReg::parse(name)?),
319 InlineAsmArch::Mips | InlineAsmArch::Mips64 => {
320 Self::Mips(MipsInlineAsmReg::parse(name)?)
322 InlineAsmArch::S390x => Self::S390x(S390xInlineAsmReg::parse(name)?),
323 InlineAsmArch::SpirV => Self::SpirV(SpirVInlineAsmReg::parse(name)?),
324 InlineAsmArch::Wasm32 | InlineAsmArch::Wasm64 => {
325 Self::Wasm(WasmInlineAsmReg::parse(name)?)
327 InlineAsmArch::Bpf => Self::Bpf(BpfInlineAsmReg::parse(name)?),
328 InlineAsmArch::Avr => Self::Avr(AvrInlineAsmReg::parse(name)?),
329 InlineAsmArch::Msp430 => Self::Msp430(Msp430InlineAsmReg::parse(name)?),
336 reloc_model: RelocModel,
337 target_features: &FxHashSet<Symbol>,
340 ) -> Result<(), &'static str> {
342 Self::X86(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
343 Self::Arm(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
344 Self::AArch64(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
345 Self::RiscV(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
346 Self::PowerPC(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
347 Self::Hexagon(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
348 Self::Mips(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
349 Self::S390x(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
350 Self::Bpf(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
351 Self::Avr(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
352 Self::Msp430(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
353 Self::Err => unreachable!(),
357 // NOTE: This function isn't used at the moment, but is needed to support
358 // falling back to an external assembler.
361 out: &mut dyn fmt::Write,
363 modifier: Option<char>,
366 Self::X86(r) => r.emit(out, arch, modifier),
367 Self::Arm(r) => r.emit(out, arch, modifier),
368 Self::AArch64(r) => r.emit(out, arch, modifier),
369 Self::RiscV(r) => r.emit(out, arch, modifier),
370 Self::PowerPC(r) => r.emit(out, arch, modifier),
371 Self::Hexagon(r) => r.emit(out, arch, modifier),
372 Self::Mips(r) => r.emit(out, arch, modifier),
373 Self::S390x(r) => r.emit(out, arch, modifier),
374 Self::Bpf(r) => r.emit(out, arch, modifier),
375 Self::Avr(r) => r.emit(out, arch, modifier),
376 Self::Msp430(r) => r.emit(out, arch, modifier),
377 Self::Err => unreachable!("Use of InlineAsmReg::Err"),
381 pub fn overlapping_regs(self, mut cb: impl FnMut(InlineAsmReg)) {
383 Self::X86(r) => r.overlapping_regs(|r| cb(Self::X86(r))),
384 Self::Arm(r) => r.overlapping_regs(|r| cb(Self::Arm(r))),
385 Self::AArch64(_) => cb(self),
386 Self::RiscV(_) => cb(self),
387 Self::PowerPC(r) => r.overlapping_regs(|r| cb(Self::PowerPC(r))),
388 Self::Hexagon(r) => r.overlapping_regs(|r| cb(Self::Hexagon(r))),
389 Self::Mips(_) => cb(self),
390 Self::S390x(_) => cb(self),
391 Self::Bpf(r) => r.overlapping_regs(|r| cb(Self::Bpf(r))),
392 Self::Avr(r) => r.overlapping_regs(|r| cb(Self::Avr(r))),
393 Self::Msp430(_) => cb(self),
394 Self::Err => unreachable!("Use of InlineAsmReg::Err"),
399 #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Hash)]
400 #[derive(HashStable_Generic, Encodable, Decodable)]
401 pub enum InlineAsmRegClass {
402 X86(X86InlineAsmRegClass),
403 Arm(ArmInlineAsmRegClass),
404 AArch64(AArch64InlineAsmRegClass),
405 RiscV(RiscVInlineAsmRegClass),
406 Nvptx(NvptxInlineAsmRegClass),
407 PowerPC(PowerPCInlineAsmRegClass),
408 Hexagon(HexagonInlineAsmRegClass),
409 Mips(MipsInlineAsmRegClass),
410 S390x(S390xInlineAsmRegClass),
411 SpirV(SpirVInlineAsmRegClass),
412 Wasm(WasmInlineAsmRegClass),
413 Bpf(BpfInlineAsmRegClass),
414 Avr(AvrInlineAsmRegClass),
415 Msp430(Msp430InlineAsmRegClass),
416 // Placeholder for invalid register constraints for the current target
420 impl InlineAsmRegClass {
421 pub fn name(self) -> Symbol {
423 Self::X86(r) => r.name(),
424 Self::Arm(r) => r.name(),
425 Self::AArch64(r) => r.name(),
426 Self::RiscV(r) => r.name(),
427 Self::Nvptx(r) => r.name(),
428 Self::PowerPC(r) => r.name(),
429 Self::Hexagon(r) => r.name(),
430 Self::Mips(r) => r.name(),
431 Self::S390x(r) => r.name(),
432 Self::SpirV(r) => r.name(),
433 Self::Wasm(r) => r.name(),
434 Self::Bpf(r) => r.name(),
435 Self::Avr(r) => r.name(),
436 Self::Msp430(r) => r.name(),
437 Self::Err => rustc_span::symbol::sym::reg,
441 /// Returns a suggested register class to use for this type. This is called
442 /// when `supported_types` fails to give a better error
443 /// message to the user.
444 pub fn suggest_class(self, arch: InlineAsmArch, ty: InlineAsmType) -> Option<Self> {
446 Self::X86(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::X86),
447 Self::Arm(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Arm),
448 Self::AArch64(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::AArch64),
449 Self::RiscV(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::RiscV),
450 Self::Nvptx(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Nvptx),
451 Self::PowerPC(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::PowerPC),
452 Self::Hexagon(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Hexagon),
453 Self::Mips(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Mips),
454 Self::S390x(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::S390x),
455 Self::SpirV(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::SpirV),
456 Self::Wasm(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Wasm),
457 Self::Bpf(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Bpf),
458 Self::Avr(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Avr),
459 Self::Msp430(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Msp430),
460 Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
464 /// Returns a suggested template modifier to use for this type and an
465 /// example of a register named formatted with it.
467 /// Such suggestions are useful if a type smaller than the full register
468 /// size is used and a modifier can be used to point to the subregister of
469 /// the correct size.
470 pub fn suggest_modifier(
474 ) -> Option<(char, &'static str)> {
476 Self::X86(r) => r.suggest_modifier(arch, ty),
477 Self::Arm(r) => r.suggest_modifier(arch, ty),
478 Self::AArch64(r) => r.suggest_modifier(arch, ty),
479 Self::RiscV(r) => r.suggest_modifier(arch, ty),
480 Self::Nvptx(r) => r.suggest_modifier(arch, ty),
481 Self::PowerPC(r) => r.suggest_modifier(arch, ty),
482 Self::Hexagon(r) => r.suggest_modifier(arch, ty),
483 Self::Mips(r) => r.suggest_modifier(arch, ty),
484 Self::S390x(r) => r.suggest_modifier(arch, ty),
485 Self::SpirV(r) => r.suggest_modifier(arch, ty),
486 Self::Wasm(r) => r.suggest_modifier(arch, ty),
487 Self::Bpf(r) => r.suggest_modifier(arch, ty),
488 Self::Avr(r) => r.suggest_modifier(arch, ty),
489 Self::Msp430(r) => r.suggest_modifier(arch, ty),
490 Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
494 /// Returns the default modifier for this register and an example of a
495 /// register named formatted with it.
497 /// This is only needed when the register class can suggest a modifier, so
498 /// that the user can be shown how to get the default behavior without a
500 pub fn default_modifier(self, arch: InlineAsmArch) -> Option<(char, &'static str)> {
502 Self::X86(r) => r.default_modifier(arch),
503 Self::Arm(r) => r.default_modifier(arch),
504 Self::AArch64(r) => r.default_modifier(arch),
505 Self::RiscV(r) => r.default_modifier(arch),
506 Self::Nvptx(r) => r.default_modifier(arch),
507 Self::PowerPC(r) => r.default_modifier(arch),
508 Self::Hexagon(r) => r.default_modifier(arch),
509 Self::Mips(r) => r.default_modifier(arch),
510 Self::S390x(r) => r.default_modifier(arch),
511 Self::SpirV(r) => r.default_modifier(arch),
512 Self::Wasm(r) => r.default_modifier(arch),
513 Self::Bpf(r) => r.default_modifier(arch),
514 Self::Avr(r) => r.default_modifier(arch),
515 Self::Msp430(r) => r.default_modifier(arch),
516 Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
520 /// Returns a list of supported types for this register class, each with an
521 /// options target feature required to use this type.
522 pub fn supported_types(
525 ) -> &'static [(InlineAsmType, Option<Symbol>)] {
527 Self::X86(r) => r.supported_types(arch),
528 Self::Arm(r) => r.supported_types(arch),
529 Self::AArch64(r) => r.supported_types(arch),
530 Self::RiscV(r) => r.supported_types(arch),
531 Self::Nvptx(r) => r.supported_types(arch),
532 Self::PowerPC(r) => r.supported_types(arch),
533 Self::Hexagon(r) => r.supported_types(arch),
534 Self::Mips(r) => r.supported_types(arch),
535 Self::S390x(r) => r.supported_types(arch),
536 Self::SpirV(r) => r.supported_types(arch),
537 Self::Wasm(r) => r.supported_types(arch),
538 Self::Bpf(r) => r.supported_types(arch),
539 Self::Avr(r) => r.supported_types(arch),
540 Self::Msp430(r) => r.supported_types(arch),
541 Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
545 pub fn parse(arch: InlineAsmArch, name: Symbol) -> Result<Self, &'static str> {
547 InlineAsmArch::X86 | InlineAsmArch::X86_64 => {
548 Self::X86(X86InlineAsmRegClass::parse(name)?)
550 InlineAsmArch::Arm => Self::Arm(ArmInlineAsmRegClass::parse(name)?),
551 InlineAsmArch::AArch64 => Self::AArch64(AArch64InlineAsmRegClass::parse(name)?),
552 InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
553 Self::RiscV(RiscVInlineAsmRegClass::parse(name)?)
555 InlineAsmArch::Nvptx64 => Self::Nvptx(NvptxInlineAsmRegClass::parse(name)?),
556 InlineAsmArch::PowerPC | InlineAsmArch::PowerPC64 => {
557 Self::PowerPC(PowerPCInlineAsmRegClass::parse(name)?)
559 InlineAsmArch::Hexagon => Self::Hexagon(HexagonInlineAsmRegClass::parse(name)?),
560 InlineAsmArch::Mips | InlineAsmArch::Mips64 => {
561 Self::Mips(MipsInlineAsmRegClass::parse(name)?)
563 InlineAsmArch::S390x => Self::S390x(S390xInlineAsmRegClass::parse(name)?),
564 InlineAsmArch::SpirV => Self::SpirV(SpirVInlineAsmRegClass::parse(name)?),
565 InlineAsmArch::Wasm32 | InlineAsmArch::Wasm64 => {
566 Self::Wasm(WasmInlineAsmRegClass::parse(name)?)
568 InlineAsmArch::Bpf => Self::Bpf(BpfInlineAsmRegClass::parse(name)?),
569 InlineAsmArch::Avr => Self::Avr(AvrInlineAsmRegClass::parse(name)?),
570 InlineAsmArch::Msp430 => Self::Msp430(Msp430InlineAsmRegClass::parse(name)?),
574 /// Returns the list of template modifiers that can be used with this
576 pub fn valid_modifiers(self, arch: InlineAsmArch) -> &'static [char] {
578 Self::X86(r) => r.valid_modifiers(arch),
579 Self::Arm(r) => r.valid_modifiers(arch),
580 Self::AArch64(r) => r.valid_modifiers(arch),
581 Self::RiscV(r) => r.valid_modifiers(arch),
582 Self::Nvptx(r) => r.valid_modifiers(arch),
583 Self::PowerPC(r) => r.valid_modifiers(arch),
584 Self::Hexagon(r) => r.valid_modifiers(arch),
585 Self::Mips(r) => r.valid_modifiers(arch),
586 Self::S390x(r) => r.valid_modifiers(arch),
587 Self::SpirV(r) => r.valid_modifiers(arch),
588 Self::Wasm(r) => r.valid_modifiers(arch),
589 Self::Bpf(r) => r.valid_modifiers(arch),
590 Self::Avr(r) => r.valid_modifiers(arch),
591 Self::Msp430(r) => r.valid_modifiers(arch),
592 Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
596 /// Returns whether registers in this class can only be used as clobbers
597 /// and not as inputs/outputs.
598 pub fn is_clobber_only(self, arch: InlineAsmArch) -> bool {
599 self.supported_types(arch).is_empty()
603 #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Hash)]
604 #[derive(HashStable_Generic, Encodable, Decodable)]
605 pub enum InlineAsmRegOrRegClass {
607 RegClass(InlineAsmRegClass),
610 impl InlineAsmRegOrRegClass {
611 pub fn reg_class(self) -> InlineAsmRegClass {
613 Self::Reg(r) => r.reg_class(),
614 Self::RegClass(r) => r,
619 impl fmt::Display for InlineAsmRegOrRegClass {
620 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
622 Self::Reg(r) => write!(f, "\"{}\"", r.name()),
623 Self::RegClass(r) => write!(f, "{}", r.name()),
628 /// Set of types which can be used with a particular register class.
629 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
630 pub enum InlineAsmType {
648 pub fn is_integer(self) -> bool {
649 matches!(self, Self::I8 | Self::I16 | Self::I32 | Self::I64 | Self::I128)
652 pub fn size(self) -> Size {
653 Size::from_bytes(match self {
661 Self::VecI8(n) => n * 1,
662 Self::VecI16(n) => n * 2,
663 Self::VecI32(n) => n * 4,
664 Self::VecI64(n) => n * 8,
665 Self::VecI128(n) => n * 16,
666 Self::VecF32(n) => n * 4,
667 Self::VecF64(n) => n * 8,
672 impl fmt::Display for InlineAsmType {
673 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
675 Self::I8 => f.write_str("i8"),
676 Self::I16 => f.write_str("i16"),
677 Self::I32 => f.write_str("i32"),
678 Self::I64 => f.write_str("i64"),
679 Self::I128 => f.write_str("i128"),
680 Self::F32 => f.write_str("f32"),
681 Self::F64 => f.write_str("f64"),
682 Self::VecI8(n) => write!(f, "i8x{n}"),
683 Self::VecI16(n) => write!(f, "i16x{n}"),
684 Self::VecI32(n) => write!(f, "i32x{n}"),
685 Self::VecI64(n) => write!(f, "i64x{n}"),
686 Self::VecI128(n) => write!(f, "i128x{n}"),
687 Self::VecF32(n) => write!(f, "f32x{n}"),
688 Self::VecF64(n) => write!(f, "f64x{n}"),
693 /// Returns the full set of allocatable registers for a given architecture.
695 /// The registers are structured as a map containing the set of allocatable
696 /// registers in each register class. A particular register may be allocatable
697 /// from multiple register classes, in which case it will appear multiple times
699 // NOTE: This function isn't used at the moment, but is needed to support
700 // falling back to an external assembler.
701 pub fn allocatable_registers(
703 reloc_model: RelocModel,
704 target_features: &FxHashSet<Symbol>,
705 target: &crate::spec::Target,
706 ) -> FxHashMap<InlineAsmRegClass, FxHashSet<InlineAsmReg>> {
708 InlineAsmArch::X86 | InlineAsmArch::X86_64 => {
709 let mut map = x86::regclass_map();
710 x86::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
713 InlineAsmArch::Arm => {
714 let mut map = arm::regclass_map();
715 arm::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
718 InlineAsmArch::AArch64 => {
719 let mut map = aarch64::regclass_map();
720 aarch64::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
723 InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
724 let mut map = riscv::regclass_map();
725 riscv::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
728 InlineAsmArch::Nvptx64 => {
729 let mut map = nvptx::regclass_map();
730 nvptx::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
733 InlineAsmArch::PowerPC | InlineAsmArch::PowerPC64 => {
734 let mut map = powerpc::regclass_map();
735 powerpc::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
738 InlineAsmArch::Hexagon => {
739 let mut map = hexagon::regclass_map();
740 hexagon::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
743 InlineAsmArch::Mips | InlineAsmArch::Mips64 => {
744 let mut map = mips::regclass_map();
745 mips::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
748 InlineAsmArch::S390x => {
749 let mut map = s390x::regclass_map();
750 s390x::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
753 InlineAsmArch::SpirV => {
754 let mut map = spirv::regclass_map();
755 spirv::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
758 InlineAsmArch::Wasm32 | InlineAsmArch::Wasm64 => {
759 let mut map = wasm::regclass_map();
760 wasm::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
763 InlineAsmArch::Bpf => {
764 let mut map = bpf::regclass_map();
765 bpf::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
768 InlineAsmArch::Avr => {
769 let mut map = avr::regclass_map();
770 avr::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
773 InlineAsmArch::Msp430 => {
774 let mut map = msp430::regclass_map();
775 msp430::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
781 #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Hash)]
782 #[derive(HashStable_Generic, Encodable, Decodable)]
783 pub enum InlineAsmClobberAbi {
793 impl InlineAsmClobberAbi {
794 /// Parses a clobber ABI for the given target, or returns a list of supported
795 /// clobber ABIs for the target.
800 ) -> Result<Self, &'static [&'static str]> {
801 let name = name.as_str();
803 InlineAsmArch::X86 => match name {
804 "C" | "system" | "efiapi" | "cdecl" | "stdcall" | "fastcall" => {
805 Ok(InlineAsmClobberAbi::X86)
807 _ => Err(&["C", "system", "efiapi", "cdecl", "stdcall", "fastcall"]),
809 InlineAsmArch::X86_64 => match name {
810 "C" | "system" if !target.is_like_windows => Ok(InlineAsmClobberAbi::X86_64SysV),
811 "C" | "system" if target.is_like_windows => Ok(InlineAsmClobberAbi::X86_64Win),
812 "win64" | "efiapi" => Ok(InlineAsmClobberAbi::X86_64Win),
813 "sysv64" => Ok(InlineAsmClobberAbi::X86_64SysV),
814 _ => Err(&["C", "system", "efiapi", "win64", "sysv64"]),
816 InlineAsmArch::Arm => match name {
817 "C" | "system" | "efiapi" | "aapcs" => Ok(InlineAsmClobberAbi::Arm),
818 _ => Err(&["C", "system", "efiapi", "aapcs"]),
820 InlineAsmArch::AArch64 => match name {
821 "C" | "system" | "efiapi" => Ok(if aarch64::target_reserves_x18(target) {
822 InlineAsmClobberAbi::AArch64NoX18
824 InlineAsmClobberAbi::AArch64
826 _ => Err(&["C", "system", "efiapi"]),
828 InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => match name {
829 "C" | "system" | "efiapi" => Ok(InlineAsmClobberAbi::RiscV),
830 _ => Err(&["C", "system", "efiapi"]),
836 /// Returns the set of registers which are clobbered by this ABI.
837 pub fn clobbered_regs(self) -> &'static [InlineAsmReg] {
838 macro_rules! clobbered_regs {
839 ($arch:ident $arch_reg:ident {
845 $(InlineAsmReg::$arch($arch_reg::$reg),)*
850 InlineAsmClobberAbi::X86 => clobbered_regs! {
851 X86 X86InlineAsmReg {
854 xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7,
856 k0, k1, k2, k3, k4, k5, k6, k7,
858 mm0, mm1, mm2, mm3, mm4, mm5, mm6, mm7,
859 st0, st1, st2, st3, st4, st5, st6, st7,
862 InlineAsmClobberAbi::X86_64SysV => clobbered_regs! {
863 X86 X86InlineAsmReg {
864 ax, cx, dx, si, di, r8, r9, r10, r11,
866 xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7,
867 xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15,
868 zmm16, zmm17, zmm18, zmm19, zmm20, zmm21, zmm22, zmm23,
869 zmm24, zmm25, zmm26, zmm27, zmm28, zmm29, zmm30, zmm31,
871 k0, k1, k2, k3, k4, k5, k6, k7,
873 mm0, mm1, mm2, mm3, mm4, mm5, mm6, mm7,
874 st0, st1, st2, st3, st4, st5, st6, st7,
875 tmm0, tmm1, tmm2, tmm3, tmm4, tmm5, tmm6, tmm7,
878 InlineAsmClobberAbi::X86_64Win => clobbered_regs! {
879 X86 X86InlineAsmReg {
880 // rdi and rsi are callee-saved on windows
881 ax, cx, dx, r8, r9, r10, r11,
883 // xmm6-xmm15 are callee-saved on windows, but we need to
884 // mark them as clobbered anyways because the upper portions
885 // of ymm6-ymm15 are volatile.
886 xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7,
887 xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15,
888 zmm16, zmm17, zmm18, zmm19, zmm20, zmm21, zmm22, zmm23,
889 zmm24, zmm25, zmm26, zmm27, zmm28, zmm29, zmm30, zmm31,
891 k0, k1, k2, k3, k4, k5, k6, k7,
893 mm0, mm1, mm2, mm3, mm4, mm5, mm6, mm7,
894 st0, st1, st2, st3, st4, st5, st6, st7,
895 tmm0, tmm1, tmm2, tmm3, tmm4, tmm5, tmm6, tmm7,
898 InlineAsmClobberAbi::AArch64 => clobbered_regs! {
899 AArch64 AArch64InlineAsmReg {
900 x0, x1, x2, x3, x4, x5, x6, x7,
901 x8, x9, x10, x11, x12, x13, x14, x15,
904 // Technically the low 64 bits of v8-v15 are preserved, but
905 // we have no way of expressing this using clobbers.
906 v0, v1, v2, v3, v4, v5, v6, v7,
907 v8, v9, v10, v11, v12, v13, v14, v15,
908 v16, v17, v18, v19, v20, v21, v22, v23,
909 v24, v25, v26, v27, v28, v29, v30, v31,
911 p0, p1, p2, p3, p4, p5, p6, p7,
912 p8, p9, p10, p11, p12, p13, p14, p15,
917 InlineAsmClobberAbi::AArch64NoX18 => clobbered_regs! {
918 AArch64 AArch64InlineAsmReg {
919 x0, x1, x2, x3, x4, x5, x6, x7,
920 x8, x9, x10, x11, x12, x13, x14, x15,
923 // Technically the low 64 bits of v8-v15 are preserved, but
924 // we have no way of expressing this using clobbers.
925 v0, v1, v2, v3, v4, v5, v6, v7,
926 v8, v9, v10, v11, v12, v13, v14, v15,
927 v16, v17, v18, v19, v20, v21, v22, v23,
928 v24, v25, v26, v27, v28, v29, v30, v31,
930 p0, p1, p2, p3, p4, p5, p6, p7,
931 p8, p9, p10, p11, p12, p13, p14, p15,
936 InlineAsmClobberAbi::Arm => clobbered_regs! {
937 Arm ArmInlineAsmReg {
938 // r9 is either platform-reserved or callee-saved. Either
939 // way we don't need to clobber it.
940 r0, r1, r2, r3, r12, r14,
942 // The finest-grained register variant is used here so that
943 // partial uses of larger registers are properly handled.
944 s0, s1, s2, s3, s4, s5, s6, s7,
945 s8, s9, s10, s11, s12, s13, s14, s15,
946 // s16-s31 are callee-saved
947 d16, d17, d18, d19, d20, d21, d22, d23,
948 d24, d25, d26, d27, d28, d29, d30, d31,
951 InlineAsmClobberAbi::RiscV => clobbered_regs! {
952 RiscV RiscVInlineAsmReg {
958 x10, x11, x12, x13, x14, x15, x16, x17,
962 f0, f1, f2, f3, f4, f5, f6, f7,
964 f10, f11, f12, f13, f14, f15, f16, f17,
968 v0, v1, v2, v3, v4, v5, v6, v7,
969 v8, v9, v10, v11, v12, v13, v14, v15,
970 v16, v17, v18, v19, v20, v21, v22, v23,
971 v24, v25, v26, v27, v28, v29, v30, v31,