2 use crate::spec
::Target
;
3 use rustc_data_structures
::fx
::{FxHashMap, FxHashSet}
;
4 use rustc_macros
::HashStable_Generic
;
5 use rustc_span
::Symbol
;
10 macro_rules
! def_reg_class
{
11 ($arch
:ident $arch_regclass
:ident
{
16 #[derive(Copy, Clone, Encodable, Decodable, Debug, Eq, PartialEq, PartialOrd, Hash, HashStable_Generic)]
17 #[allow(non_camel_case_types)]
18 pub enum $arch_regclass
{
23 pub fn name(self) -> rustc_span
::Symbol
{
25 $
(Self::$class
=> rustc_span
::symbol
::sym
::$class
,)*
29 pub fn parse(_arch
: super::InlineAsmArch
, name
: rustc_span
::Symbol
) -> Result
<Self, &'
static str> {
32 rustc_span
::sym
::$class
=> Ok(Self::$class
),
34 _
=> Err("unknown register class"),
39 pub(super) fn regclass_map() -> rustc_data_structures
::fx
::FxHashMap
<
40 super::InlineAsmRegClass
,
41 rustc_data_structures
::fx
::FxHashSet
<super::InlineAsmReg
>,
43 use rustc_data_structures
::fx
::{FxHashMap, FxHashSet}
;
44 use super::InlineAsmRegClass
;
45 let mut map
= FxHashMap
::default();
47 map
.insert(InlineAsmRegClass
::$
arch($arch_regclass
::$class
), FxHashSet
::default());
55 macro_rules
! def_regs
{
56 ($arch
:ident $arch_reg
:ident $arch_regclass
:ident
{
58 $reg
:ident
: $class
:ident $
(, $extra_class
:ident
)* = [$reg_name
:literal $
(, $alias
:literal
)*] $
(% $filter
:ident
)?
,
61 #error = [$($bad_reg:literal),+] => $error:literal,
64 #[allow(unreachable_code)]
65 #[derive(Copy, Clone, Encodable, Decodable, Debug, Eq, PartialEq, PartialOrd, Hash, HashStable_Generic)]
66 #[allow(non_camel_case_types)]
72 pub fn name(self) -> &'
static str {
74 $
(Self::$reg
=> $reg_name
,)*
78 pub fn reg_class(self) -> $arch_regclass
{
80 $
(Self::$reg
=> $arch_regclass
::$class
,)*
85 _arch
: super::InlineAsmArch
,
86 mut _has_feature
: impl FnMut(&str) -> bool
,
87 _target
: &crate::spec
::Target
,
89 ) -> Result
<Self, &'
static str> {
92 $
($alias
)|* | $reg_name
=> {
93 $
($
filter(_arch
, &mut _has_feature
, _target
)?
;)?
98 $
($bad_reg
)|* => Err($error
),
100 _
=> Err("unknown register"),
105 pub(super) fn fill_reg_map(
106 _arch
: super::InlineAsmArch
,
107 mut _has_feature
: impl FnMut(&str) -> bool
,
108 _target
: &crate::spec
::Target
,
109 _map
: &mut rustc_data_structures
::fx
::FxHashMap
<
110 super::InlineAsmRegClass
,
111 rustc_data_structures
::fx
::FxHashSet
<super::InlineAsmReg
>,
114 #[allow(unused_imports)]
115 use super::{InlineAsmReg, InlineAsmRegClass}
;
117 if $
($
filter(_arch
, &mut _has_feature
, _target
).is_ok() &&)?
true {
118 if let Some(set
) = _map
.get_mut(&InlineAsmRegClass
::$
arch($arch_regclass
::$class
)) {
119 set
.insert(InlineAsmReg
::$
arch($arch_reg
::$reg
));
122 if let Some(set
) = _map
.get_mut(&InlineAsmRegClass
::$
arch($arch_regclass
::$extra_class
)) {
123 set
.insert(InlineAsmReg
::$
arch($arch_reg
::$reg
));
135 $
(_
: $
($ty
:expr
),+;)?
136 $
($feature
:literal
: $
($ty2
:expr
),+;)*
139 use super::InlineAsmType
::*;
145 ($ty2
, Some($feature
)),
162 pub use aarch64
::{AArch64InlineAsmReg, AArch64InlineAsmRegClass}
;
163 pub use arm
::{ArmInlineAsmReg, ArmInlineAsmRegClass}
;
164 pub use hexagon
::{HexagonInlineAsmReg, HexagonInlineAsmRegClass}
;
165 pub use mips
::{MipsInlineAsmReg, MipsInlineAsmRegClass}
;
166 pub use nvptx
::{NvptxInlineAsmReg, NvptxInlineAsmRegClass}
;
167 pub use riscv
::{RiscVInlineAsmReg, RiscVInlineAsmRegClass}
;
168 pub use spirv
::{SpirVInlineAsmReg, SpirVInlineAsmRegClass}
;
169 pub use wasm
::{WasmInlineAsmReg, WasmInlineAsmRegClass}
;
170 pub use x86
::{X86InlineAsmReg, X86InlineAsmRegClass}
;
172 #[derive(Copy, Clone, Encodable, Decodable, Debug, Eq, PartialEq, Hash)]
173 pub enum InlineAsmArch
{
188 impl FromStr
for InlineAsmArch
{
191 fn from_str(s
: &str) -> Result
<InlineAsmArch
, ()> {
193 "x86" => Ok(Self::X86
),
194 "x86_64" => Ok(Self::X86_64
),
195 "arm" => Ok(Self::Arm
),
196 "aarch64" => Ok(Self::AArch64
),
197 "riscv32" => Ok(Self::RiscV32
),
198 "riscv64" => Ok(Self::RiscV64
),
199 "nvptx64" => Ok(Self::Nvptx64
),
200 "hexagon" => Ok(Self::Hexagon
),
201 "mips" => Ok(Self::Mips
),
202 "mips64" => Ok(Self::Mips64
),
203 "spirv" => Ok(Self::SpirV
),
204 "wasm32" => Ok(Self::Wasm32
),
222 pub enum InlineAsmReg
{
223 X86(X86InlineAsmReg
),
224 Arm(ArmInlineAsmReg
),
225 AArch64(AArch64InlineAsmReg
),
226 RiscV(RiscVInlineAsmReg
),
227 Nvptx(NvptxInlineAsmReg
),
228 Hexagon(HexagonInlineAsmReg
),
229 Mips(MipsInlineAsmReg
),
230 SpirV(SpirVInlineAsmReg
),
231 Wasm(WasmInlineAsmReg
),
232 // Placeholder for invalid register constraints for the current target
237 pub fn name(self) -> &'
static str {
239 Self::X86(r
) => r
.name(),
240 Self::Arm(r
) => r
.name(),
241 Self::AArch64(r
) => r
.name(),
242 Self::RiscV(r
) => r
.name(),
243 Self::Hexagon(r
) => r
.name(),
244 Self::Mips(r
) => r
.name(),
245 Self::Err
=> "<reg>",
249 pub fn reg_class(self) -> InlineAsmRegClass
{
251 Self::X86(r
) => InlineAsmRegClass
::X86(r
.reg_class()),
252 Self::Arm(r
) => InlineAsmRegClass
::Arm(r
.reg_class()),
253 Self::AArch64(r
) => InlineAsmRegClass
::AArch64(r
.reg_class()),
254 Self::RiscV(r
) => InlineAsmRegClass
::RiscV(r
.reg_class()),
255 Self::Hexagon(r
) => InlineAsmRegClass
::Hexagon(r
.reg_class()),
256 Self::Mips(r
) => InlineAsmRegClass
::Mips(r
.reg_class()),
257 Self::Err
=> InlineAsmRegClass
::Err
,
263 has_feature
: impl FnMut(&str) -> bool
,
266 ) -> Result
<Self, &'
static str> {
267 // FIXME: use direct symbol comparison for register names
268 // Use `Symbol::as_str` instead of `Symbol::with` here because `has_feature` may access `Symbol`.
269 let name
= name
.as_str();
271 InlineAsmArch
::X86
| InlineAsmArch
::X86_64
=> {
272 Self::X86(X86InlineAsmReg
::parse(arch
, has_feature
, target
, &name
)?
)
274 InlineAsmArch
::Arm
=> {
275 Self::Arm(ArmInlineAsmReg
::parse(arch
, has_feature
, target
, &name
)?
)
277 InlineAsmArch
::AArch64
=> {
278 Self::AArch64(AArch64InlineAsmReg
::parse(arch
, has_feature
, target
, &name
)?
)
280 InlineAsmArch
::RiscV32
| InlineAsmArch
::RiscV64
=> {
281 Self::RiscV(RiscVInlineAsmReg
::parse(arch
, has_feature
, target
, &name
)?
)
283 InlineAsmArch
::Nvptx64
=> {
284 Self::Nvptx(NvptxInlineAsmReg
::parse(arch
, has_feature
, target
, &name
)?
)
286 InlineAsmArch
::Hexagon
=> {
287 Self::Hexagon(HexagonInlineAsmReg
::parse(arch
, has_feature
, target
, &name
)?
)
289 InlineAsmArch
::Mips
| InlineAsmArch
::Mips64
=> {
290 Self::Mips(MipsInlineAsmReg
::parse(arch
, has_feature
, target
, &name
)?
)
292 InlineAsmArch
::SpirV
=> {
293 Self::SpirV(SpirVInlineAsmReg
::parse(arch
, has_feature
, target
, &name
)?
)
295 InlineAsmArch
::Wasm32
=> {
296 Self::Wasm(WasmInlineAsmReg
::parse(arch
, has_feature
, target
, &name
)?
)
301 // NOTE: This function isn't used at the moment, but is needed to support
302 // falling back to an external assembler.
305 out
: &mut dyn fmt
::Write
,
307 modifier
: Option
<char>,
310 Self::X86(r
) => r
.emit(out
, arch
, modifier
),
311 Self::Arm(r
) => r
.emit(out
, arch
, modifier
),
312 Self::AArch64(r
) => r
.emit(out
, arch
, modifier
),
313 Self::RiscV(r
) => r
.emit(out
, arch
, modifier
),
314 Self::Hexagon(r
) => r
.emit(out
, arch
, modifier
),
315 Self::Mips(r
) => r
.emit(out
, arch
, modifier
),
316 Self::Err
=> unreachable
!("Use of InlineAsmReg::Err"),
320 pub fn overlapping_regs(self, mut cb
: impl FnMut(InlineAsmReg
)) {
322 Self::X86(r
) => r
.overlapping_regs(|r
| cb(Self::X86(r
))),
323 Self::Arm(r
) => r
.overlapping_regs(|r
| cb(Self::Arm(r
))),
324 Self::AArch64(_
) => cb(self),
325 Self::RiscV(_
) => cb(self),
326 Self::Hexagon(r
) => r
.overlapping_regs(|r
| cb(Self::Hexagon(r
))),
327 Self::Mips(_
) => cb(self),
328 Self::Err
=> unreachable
!("Use of InlineAsmReg::Err"),
345 pub enum InlineAsmRegClass
{
346 X86(X86InlineAsmRegClass
),
347 Arm(ArmInlineAsmRegClass
),
348 AArch64(AArch64InlineAsmRegClass
),
349 RiscV(RiscVInlineAsmRegClass
),
350 Nvptx(NvptxInlineAsmRegClass
),
351 Hexagon(HexagonInlineAsmRegClass
),
352 Mips(MipsInlineAsmRegClass
),
353 SpirV(SpirVInlineAsmRegClass
),
354 Wasm(WasmInlineAsmRegClass
),
355 // Placeholder for invalid register constraints for the current target
359 impl InlineAsmRegClass
{
360 pub fn name(self) -> Symbol
{
362 Self::X86(r
) => r
.name(),
363 Self::Arm(r
) => r
.name(),
364 Self::AArch64(r
) => r
.name(),
365 Self::RiscV(r
) => r
.name(),
366 Self::Nvptx(r
) => r
.name(),
367 Self::Hexagon(r
) => r
.name(),
368 Self::Mips(r
) => r
.name(),
369 Self::SpirV(r
) => r
.name(),
370 Self::Wasm(r
) => r
.name(),
371 Self::Err
=> rustc_span
::symbol
::sym
::reg
,
375 /// Returns a suggested register class to use for this type. This is called
376 /// after type checking via `supported_types` fails to give a better error
377 /// message to the user.
378 pub fn suggest_class(self, arch
: InlineAsmArch
, ty
: InlineAsmType
) -> Option
<Self> {
380 Self::X86(r
) => r
.suggest_class(arch
, ty
).map(InlineAsmRegClass
::X86
),
381 Self::Arm(r
) => r
.suggest_class(arch
, ty
).map(InlineAsmRegClass
::Arm
),
382 Self::AArch64(r
) => r
.suggest_class(arch
, ty
).map(InlineAsmRegClass
::AArch64
),
383 Self::RiscV(r
) => r
.suggest_class(arch
, ty
).map(InlineAsmRegClass
::RiscV
),
384 Self::Nvptx(r
) => r
.suggest_class(arch
, ty
).map(InlineAsmRegClass
::Nvptx
),
385 Self::Hexagon(r
) => r
.suggest_class(arch
, ty
).map(InlineAsmRegClass
::Hexagon
),
386 Self::Mips(r
) => r
.suggest_class(arch
, ty
).map(InlineAsmRegClass
::Mips
),
387 Self::SpirV(r
) => r
.suggest_class(arch
, ty
).map(InlineAsmRegClass
::SpirV
),
388 Self::Wasm(r
) => r
.suggest_class(arch
, ty
).map(InlineAsmRegClass
::Wasm
),
389 Self::Err
=> unreachable
!("Use of InlineAsmRegClass::Err"),
393 /// Returns a suggested template modifier to use for this type and an
394 /// example of a register named formatted with it.
396 /// Such suggestions are useful if a type smaller than the full register
397 /// size is used and a modifier can be used to point to the subregister of
398 /// the correct size.
399 pub fn suggest_modifier(
403 ) -> Option
<(char, &'
static str)> {
405 Self::X86(r
) => r
.suggest_modifier(arch
, ty
),
406 Self::Arm(r
) => r
.suggest_modifier(arch
, ty
),
407 Self::AArch64(r
) => r
.suggest_modifier(arch
, ty
),
408 Self::RiscV(r
) => r
.suggest_modifier(arch
, ty
),
409 Self::Nvptx(r
) => r
.suggest_modifier(arch
, ty
),
410 Self::Hexagon(r
) => r
.suggest_modifier(arch
, ty
),
411 Self::Mips(r
) => r
.suggest_modifier(arch
, ty
),
412 Self::SpirV(r
) => r
.suggest_modifier(arch
, ty
),
413 Self::Wasm(r
) => r
.suggest_modifier(arch
, ty
),
414 Self::Err
=> unreachable
!("Use of InlineAsmRegClass::Err"),
418 /// Returns the default modifier for this register and an example of a
419 /// register named formatted with it.
421 /// This is only needed when the register class can suggest a modifier, so
422 /// that the user can be shown how to get the default behavior without a
424 pub fn default_modifier(self, arch
: InlineAsmArch
) -> Option
<(char, &'
static str)> {
426 Self::X86(r
) => r
.default_modifier(arch
),
427 Self::Arm(r
) => r
.default_modifier(arch
),
428 Self::AArch64(r
) => r
.default_modifier(arch
),
429 Self::RiscV(r
) => r
.default_modifier(arch
),
430 Self::Nvptx(r
) => r
.default_modifier(arch
),
431 Self::Hexagon(r
) => r
.default_modifier(arch
),
432 Self::Mips(r
) => r
.default_modifier(arch
),
433 Self::SpirV(r
) => r
.default_modifier(arch
),
434 Self::Wasm(r
) => r
.default_modifier(arch
),
435 Self::Err
=> unreachable
!("Use of InlineAsmRegClass::Err"),
439 /// Returns a list of supported types for this register class, each with a
440 /// options target feature required to use this type.
441 pub fn supported_types(
444 ) -> &'
static [(InlineAsmType
, Option
<&'
static str>)] {
446 Self::X86(r
) => r
.supported_types(arch
),
447 Self::Arm(r
) => r
.supported_types(arch
),
448 Self::AArch64(r
) => r
.supported_types(arch
),
449 Self::RiscV(r
) => r
.supported_types(arch
),
450 Self::Nvptx(r
) => r
.supported_types(arch
),
451 Self::Hexagon(r
) => r
.supported_types(arch
),
452 Self::Mips(r
) => r
.supported_types(arch
),
453 Self::SpirV(r
) => r
.supported_types(arch
),
454 Self::Wasm(r
) => r
.supported_types(arch
),
455 Self::Err
=> unreachable
!("Use of InlineAsmRegClass::Err"),
459 pub fn parse(arch
: InlineAsmArch
, name
: Symbol
) -> Result
<Self, &'
static str> {
461 InlineAsmArch
::X86
| InlineAsmArch
::X86_64
=> {
462 Self::X86(X86InlineAsmRegClass
::parse(arch
, name
)?
)
464 InlineAsmArch
::Arm
=> Self::Arm(ArmInlineAsmRegClass
::parse(arch
, name
)?
),
465 InlineAsmArch
::AArch64
=> Self::AArch64(AArch64InlineAsmRegClass
::parse(arch
, name
)?
),
466 InlineAsmArch
::RiscV32
| InlineAsmArch
::RiscV64
=> {
467 Self::RiscV(RiscVInlineAsmRegClass
::parse(arch
, name
)?
)
469 InlineAsmArch
::Nvptx64
=> Self::Nvptx(NvptxInlineAsmRegClass
::parse(arch
, name
)?
),
470 InlineAsmArch
::Hexagon
=> Self::Hexagon(HexagonInlineAsmRegClass
::parse(arch
, name
)?
),
471 InlineAsmArch
::Mips
| InlineAsmArch
::Mips64
=> {
472 Self::Mips(MipsInlineAsmRegClass
::parse(arch
, name
)?
)
474 InlineAsmArch
::SpirV
=> Self::SpirV(SpirVInlineAsmRegClass
::parse(arch
, name
)?
),
475 InlineAsmArch
::Wasm32
=> Self::Wasm(WasmInlineAsmRegClass
::parse(arch
, name
)?
),
479 /// Returns the list of template modifiers that can be used with this
481 pub fn valid_modifiers(self, arch
: InlineAsmArch
) -> &'
static [char] {
483 Self::X86(r
) => r
.valid_modifiers(arch
),
484 Self::Arm(r
) => r
.valid_modifiers(arch
),
485 Self::AArch64(r
) => r
.valid_modifiers(arch
),
486 Self::RiscV(r
) => r
.valid_modifiers(arch
),
487 Self::Nvptx(r
) => r
.valid_modifiers(arch
),
488 Self::Hexagon(r
) => r
.valid_modifiers(arch
),
489 Self::Mips(r
) => r
.valid_modifiers(arch
),
490 Self::SpirV(r
) => r
.valid_modifiers(arch
),
491 Self::Wasm(r
) => r
.valid_modifiers(arch
),
492 Self::Err
=> unreachable
!("Use of InlineAsmRegClass::Err"),
509 pub enum InlineAsmRegOrRegClass
{
511 RegClass(InlineAsmRegClass
),
514 impl InlineAsmRegOrRegClass
{
515 pub fn reg_class(self) -> InlineAsmRegClass
{
517 Self::Reg(r
) => r
.reg_class(),
518 Self::RegClass(r
) => r
,
523 impl fmt
::Display
for InlineAsmRegOrRegClass
{
524 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
526 Self::Reg(r
) => write
!(f
, "\"{}\"", r
.name()),
527 Self::RegClass(r
) => write
!(f
, "{}", r
.name()),
532 /// Set of types which can be used with a particular register class.
533 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
534 pub enum InlineAsmType
{
552 pub fn is_integer(self) -> bool
{
553 matches
!(self, Self::I8
| Self::I16
| Self::I32
| Self::I64
| Self::I128
)
556 pub fn size(self) -> Size
{
557 Size
::from_bytes(match self {
565 Self::VecI8(n
) => n
* 1,
566 Self::VecI16(n
) => n
* 2,
567 Self::VecI32(n
) => n
* 4,
568 Self::VecI64(n
) => n
* 8,
569 Self::VecI128(n
) => n
* 16,
570 Self::VecF32(n
) => n
* 4,
571 Self::VecF64(n
) => n
* 8,
576 impl fmt
::Display
for InlineAsmType
{
577 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
579 Self::I8
=> f
.write_str("i8"),
580 Self::I16
=> f
.write_str("i16"),
581 Self::I32
=> f
.write_str("i32"),
582 Self::I64
=> f
.write_str("i64"),
583 Self::I128
=> f
.write_str("i128"),
584 Self::F32
=> f
.write_str("f32"),
585 Self::F64
=> f
.write_str("f64"),
586 Self::VecI8(n
) => write
!(f
, "i8x{}", n
),
587 Self::VecI16(n
) => write
!(f
, "i16x{}", n
),
588 Self::VecI32(n
) => write
!(f
, "i32x{}", n
),
589 Self::VecI64(n
) => write
!(f
, "i64x{}", n
),
590 Self::VecI128(n
) => write
!(f
, "i128x{}", n
),
591 Self::VecF32(n
) => write
!(f
, "f32x{}", n
),
592 Self::VecF64(n
) => write
!(f
, "f64x{}", n
),
597 /// Returns the full set of allocatable registers for a given architecture.
599 /// The registers are structured as a map containing the set of allocatable
600 /// registers in each register class. A particular register may be allocatable
601 /// from multiple register classes, in which case it will appear multiple times
603 // NOTE: This function isn't used at the moment, but is needed to support
604 // falling back to an external assembler.
605 pub fn allocatable_registers(
607 has_feature
: impl FnMut(&str) -> bool
,
608 target
: &crate::spec
::Target
,
609 ) -> FxHashMap
<InlineAsmRegClass
, FxHashSet
<InlineAsmReg
>> {
611 InlineAsmArch
::X86
| InlineAsmArch
::X86_64
=> {
612 let mut map
= x86
::regclass_map();
613 x86
::fill_reg_map(arch
, has_feature
, target
, &mut map
);
616 InlineAsmArch
::Arm
=> {
617 let mut map
= arm
::regclass_map();
618 arm
::fill_reg_map(arch
, has_feature
, target
, &mut map
);
621 InlineAsmArch
::AArch64
=> {
622 let mut map
= aarch64
::regclass_map();
623 aarch64
::fill_reg_map(arch
, has_feature
, target
, &mut map
);
626 InlineAsmArch
::RiscV32
| InlineAsmArch
::RiscV64
=> {
627 let mut map
= riscv
::regclass_map();
628 riscv
::fill_reg_map(arch
, has_feature
, target
, &mut map
);
631 InlineAsmArch
::Nvptx64
=> {
632 let mut map
= nvptx
::regclass_map();
633 nvptx
::fill_reg_map(arch
, has_feature
, target
, &mut map
);
636 InlineAsmArch
::Hexagon
=> {
637 let mut map
= hexagon
::regclass_map();
638 hexagon
::fill_reg_map(arch
, has_feature
, target
, &mut map
);
641 InlineAsmArch
::Mips
| InlineAsmArch
::Mips64
=> {
642 let mut map
= mips
::regclass_map();
643 mips
::fill_reg_map(arch
, has_feature
, target
, &mut map
);
646 InlineAsmArch
::SpirV
=> {
647 let mut map
= spirv
::regclass_map();
648 spirv
::fill_reg_map(arch
, has_feature
, target
, &mut map
);
651 InlineAsmArch
::Wasm32
=> {
652 let mut map
= wasm
::regclass_map();
653 wasm
::fill_reg_map(arch
, has_feature
, target
, &mut map
);