]> git.proxmox.com Git - rustc.git/blob - compiler/rustc_target/src/asm/mod.rs
New upstream version 1.63.0+dfsg1
[rustc.git] / compiler / rustc_target / src / asm / mod.rs
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;
6 use std::fmt;
7 use std::str::FromStr;
8
9 macro_rules! def_reg_class {
10 ($arch:ident $arch_regclass:ident {
11 $(
12 $class:ident,
13 )*
14 }) => {
15 #[derive(Copy, Clone, Encodable, Decodable, Debug, Eq, PartialEq, PartialOrd, Hash, HashStable_Generic)]
16 #[allow(non_camel_case_types)]
17 pub enum $arch_regclass {
18 $($class,)*
19 }
20
21 impl $arch_regclass {
22 pub fn name(self) -> rustc_span::Symbol {
23 match self {
24 $(Self::$class => rustc_span::symbol::sym::$class,)*
25 }
26 }
27
28 pub fn parse(name: rustc_span::Symbol) -> Result<Self, &'static str> {
29 match name {
30 $(
31 rustc_span::sym::$class => Ok(Self::$class),
32 )*
33 _ => Err("unknown register class"),
34 }
35 }
36 }
37
38 pub(super) fn regclass_map() -> rustc_data_structures::fx::FxHashMap<
39 super::InlineAsmRegClass,
40 rustc_data_structures::fx::FxHashSet<super::InlineAsmReg>,
41 > {
42 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
43 use super::InlineAsmRegClass;
44 let mut map = FxHashMap::default();
45 $(
46 map.insert(InlineAsmRegClass::$arch($arch_regclass::$class), FxHashSet::default());
47 )*
48 map
49 }
50 }
51 }
52
53 macro_rules! def_regs {
54 ($arch:ident $arch_reg:ident $arch_regclass:ident {
55 $(
56 $reg:ident: $class:ident $(, $extra_class:ident)* = [$reg_name:literal $(, $alias:literal)*] $(% $filter:ident)?,
57 )*
58 $(
59 #error = [$($bad_reg:literal),+] => $error:literal,
60 )*
61 }) => {
62 #[allow(unreachable_code)]
63 #[derive(Copy, Clone, Encodable, Decodable, Debug, Eq, PartialEq, PartialOrd, Hash, HashStable_Generic)]
64 #[allow(non_camel_case_types)]
65 pub enum $arch_reg {
66 $($reg,)*
67 }
68
69 impl $arch_reg {
70 pub fn name(self) -> &'static str {
71 match self {
72 $(Self::$reg => $reg_name,)*
73 }
74 }
75
76 pub fn reg_class(self) -> $arch_regclass {
77 match self {
78 $(Self::$reg => $arch_regclass::$class,)*
79 }
80 }
81
82 pub fn parse(name: &str) -> Result<Self, &'static str> {
83 match name {
84 $(
85 $($alias)|* | $reg_name => Ok(Self::$reg),
86 )*
87 $(
88 $($bad_reg)|* => Err($error),
89 )*
90 _ => Err("unknown register"),
91 }
92 }
93
94 pub fn validate(self,
95 _arch: super::InlineAsmArch,
96 _reloc_model: crate::spec::RelocModel,
97 _target_features: &rustc_data_structures::fx::FxHashSet<Symbol>,
98 _target: &crate::spec::Target,
99 _is_clobber: bool,
100 ) -> Result<(), &'static str> {
101 match self {
102 $(
103 Self::$reg => {
104 $($filter(
105 _arch,
106 _reloc_model,
107 _target_features,
108 _target,
109 _is_clobber
110 )?;)?
111 Ok(())
112 }
113 )*
114 }
115 }
116 }
117
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>,
126 >,
127 ) {
128 #[allow(unused_imports)]
129 use super::{InlineAsmReg, InlineAsmRegClass};
130 $(
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));
134 }
135 $(
136 if let Some(set) = _map.get_mut(&InlineAsmRegClass::$arch($arch_regclass::$extra_class)) {
137 set.insert(InlineAsmReg::$arch($arch_reg::$reg));
138 }
139 )*
140 }
141 )*
142 }
143 }
144 }
145
146 macro_rules! types {
147 (
148 $(_ : $($ty:expr),+;)?
149 $($feature:ident: $($ty2:expr),+;)*
150 ) => {
151 {
152 use super::InlineAsmType::*;
153 &[
154 $($(
155 ($ty, None),
156 )*)?
157 $($(
158 ($ty2, Some(rustc_span::sym::$feature)),
159 )*)*
160 ]
161 }
162 };
163 }
164
165 mod aarch64;
166 mod arm;
167 mod avr;
168 mod bpf;
169 mod hexagon;
170 mod mips;
171 mod msp430;
172 mod nvptx;
173 mod powerpc;
174 mod riscv;
175 mod s390x;
176 mod spirv;
177 mod wasm;
178 mod x86;
179
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};
194
195 #[derive(Copy, Clone, Encodable, Decodable, Debug, Eq, PartialEq, Hash)]
196 pub enum InlineAsmArch {
197 X86,
198 X86_64,
199 Arm,
200 AArch64,
201 RiscV32,
202 RiscV64,
203 Nvptx64,
204 Hexagon,
205 Mips,
206 Mips64,
207 PowerPC,
208 PowerPC64,
209 S390x,
210 SpirV,
211 Wasm32,
212 Wasm64,
213 Bpf,
214 Avr,
215 Msp430,
216 }
217
218 impl FromStr for InlineAsmArch {
219 type Err = ();
220
221 fn from_str(s: &str) -> Result<InlineAsmArch, ()> {
222 match s {
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),
242 _ => Err(()),
243 }
244 }
245 }
246
247 #[derive(
248 Copy,
249 Clone,
250 Encodable,
251 Decodable,
252 Debug,
253 Eq,
254 PartialEq,
255 PartialOrd,
256 Hash,
257 HashStable_Generic
258 )]
259 pub enum InlineAsmReg {
260 X86(X86InlineAsmReg),
261 Arm(ArmInlineAsmReg),
262 AArch64(AArch64InlineAsmReg),
263 RiscV(RiscVInlineAsmReg),
264 Nvptx(NvptxInlineAsmReg),
265 PowerPC(PowerPCInlineAsmReg),
266 Hexagon(HexagonInlineAsmReg),
267 Mips(MipsInlineAsmReg),
268 S390x(S390xInlineAsmReg),
269 SpirV(SpirVInlineAsmReg),
270 Wasm(WasmInlineAsmReg),
271 Bpf(BpfInlineAsmReg),
272 Avr(AvrInlineAsmReg),
273 Msp430(Msp430InlineAsmReg),
274 // Placeholder for invalid register constraints for the current target
275 Err,
276 }
277
278 impl InlineAsmReg {
279 pub fn name(self) -> &'static str {
280 match self {
281 Self::X86(r) => r.name(),
282 Self::Arm(r) => r.name(),
283 Self::AArch64(r) => r.name(),
284 Self::RiscV(r) => r.name(),
285 Self::PowerPC(r) => r.name(),
286 Self::Hexagon(r) => r.name(),
287 Self::Mips(r) => r.name(),
288 Self::S390x(r) => r.name(),
289 Self::Bpf(r) => r.name(),
290 Self::Avr(r) => r.name(),
291 Self::Msp430(r) => r.name(),
292 Self::Err => "<reg>",
293 }
294 }
295
296 pub fn reg_class(self) -> InlineAsmRegClass {
297 match self {
298 Self::X86(r) => InlineAsmRegClass::X86(r.reg_class()),
299 Self::Arm(r) => InlineAsmRegClass::Arm(r.reg_class()),
300 Self::AArch64(r) => InlineAsmRegClass::AArch64(r.reg_class()),
301 Self::RiscV(r) => InlineAsmRegClass::RiscV(r.reg_class()),
302 Self::PowerPC(r) => InlineAsmRegClass::PowerPC(r.reg_class()),
303 Self::Hexagon(r) => InlineAsmRegClass::Hexagon(r.reg_class()),
304 Self::Mips(r) => InlineAsmRegClass::Mips(r.reg_class()),
305 Self::S390x(r) => InlineAsmRegClass::S390x(r.reg_class()),
306 Self::Bpf(r) => InlineAsmRegClass::Bpf(r.reg_class()),
307 Self::Avr(r) => InlineAsmRegClass::Avr(r.reg_class()),
308 Self::Msp430(r) => InlineAsmRegClass::Msp430(r.reg_class()),
309 Self::Err => InlineAsmRegClass::Err,
310 }
311 }
312
313 pub fn parse(arch: InlineAsmArch, name: Symbol) -> Result<Self, &'static str> {
314 // FIXME: use direct symbol comparison for register names
315 // Use `Symbol::as_str` instead of `Symbol::with` here because `has_feature` may access `Symbol`.
316 let name = name.as_str();
317 Ok(match arch {
318 InlineAsmArch::X86 | InlineAsmArch::X86_64 => Self::X86(X86InlineAsmReg::parse(name)?),
319 InlineAsmArch::Arm => Self::Arm(ArmInlineAsmReg::parse(name)?),
320 InlineAsmArch::AArch64 => Self::AArch64(AArch64InlineAsmReg::parse(name)?),
321 InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
322 Self::RiscV(RiscVInlineAsmReg::parse(name)?)
323 }
324 InlineAsmArch::Nvptx64 => Self::Nvptx(NvptxInlineAsmReg::parse(name)?),
325 InlineAsmArch::PowerPC | InlineAsmArch::PowerPC64 => {
326 Self::PowerPC(PowerPCInlineAsmReg::parse(name)?)
327 }
328 InlineAsmArch::Hexagon => Self::Hexagon(HexagonInlineAsmReg::parse(name)?),
329 InlineAsmArch::Mips | InlineAsmArch::Mips64 => {
330 Self::Mips(MipsInlineAsmReg::parse(name)?)
331 }
332 InlineAsmArch::S390x => Self::S390x(S390xInlineAsmReg::parse(name)?),
333 InlineAsmArch::SpirV => Self::SpirV(SpirVInlineAsmReg::parse(name)?),
334 InlineAsmArch::Wasm32 | InlineAsmArch::Wasm64 => {
335 Self::Wasm(WasmInlineAsmReg::parse(name)?)
336 }
337 InlineAsmArch::Bpf => Self::Bpf(BpfInlineAsmReg::parse(name)?),
338 InlineAsmArch::Avr => Self::Avr(AvrInlineAsmReg::parse(name)?),
339 InlineAsmArch::Msp430 => Self::Msp430(Msp430InlineAsmReg::parse(name)?),
340 })
341 }
342
343 pub fn validate(
344 self,
345 arch: InlineAsmArch,
346 reloc_model: RelocModel,
347 target_features: &FxHashSet<Symbol>,
348 target: &Target,
349 is_clobber: bool,
350 ) -> Result<(), &'static str> {
351 match self {
352 Self::X86(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
353 Self::Arm(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
354 Self::AArch64(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
355 Self::RiscV(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
356 Self::PowerPC(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
357 Self::Hexagon(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
358 Self::Mips(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
359 Self::S390x(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
360 Self::Bpf(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
361 Self::Avr(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
362 Self::Msp430(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
363 Self::Err => unreachable!(),
364 }
365 }
366
367 // NOTE: This function isn't used at the moment, but is needed to support
368 // falling back to an external assembler.
369 pub fn emit(
370 self,
371 out: &mut dyn fmt::Write,
372 arch: InlineAsmArch,
373 modifier: Option<char>,
374 ) -> fmt::Result {
375 match self {
376 Self::X86(r) => r.emit(out, arch, modifier),
377 Self::Arm(r) => r.emit(out, arch, modifier),
378 Self::AArch64(r) => r.emit(out, arch, modifier),
379 Self::RiscV(r) => r.emit(out, arch, modifier),
380 Self::PowerPC(r) => r.emit(out, arch, modifier),
381 Self::Hexagon(r) => r.emit(out, arch, modifier),
382 Self::Mips(r) => r.emit(out, arch, modifier),
383 Self::S390x(r) => r.emit(out, arch, modifier),
384 Self::Bpf(r) => r.emit(out, arch, modifier),
385 Self::Avr(r) => r.emit(out, arch, modifier),
386 Self::Msp430(r) => r.emit(out, arch, modifier),
387 Self::Err => unreachable!("Use of InlineAsmReg::Err"),
388 }
389 }
390
391 pub fn overlapping_regs(self, mut cb: impl FnMut(InlineAsmReg)) {
392 match self {
393 Self::X86(r) => r.overlapping_regs(|r| cb(Self::X86(r))),
394 Self::Arm(r) => r.overlapping_regs(|r| cb(Self::Arm(r))),
395 Self::AArch64(_) => cb(self),
396 Self::RiscV(_) => cb(self),
397 Self::PowerPC(r) => r.overlapping_regs(|r| cb(Self::PowerPC(r))),
398 Self::Hexagon(r) => r.overlapping_regs(|r| cb(Self::Hexagon(r))),
399 Self::Mips(_) => cb(self),
400 Self::S390x(_) => cb(self),
401 Self::Bpf(r) => r.overlapping_regs(|r| cb(Self::Bpf(r))),
402 Self::Avr(r) => r.overlapping_regs(|r| cb(Self::Avr(r))),
403 Self::Msp430(_) => cb(self),
404 Self::Err => unreachable!("Use of InlineAsmReg::Err"),
405 }
406 }
407 }
408
409 #[derive(
410 Copy,
411 Clone,
412 Encodable,
413 Decodable,
414 Debug,
415 Eq,
416 PartialEq,
417 PartialOrd,
418 Hash,
419 HashStable_Generic
420 )]
421 pub enum InlineAsmRegClass {
422 X86(X86InlineAsmRegClass),
423 Arm(ArmInlineAsmRegClass),
424 AArch64(AArch64InlineAsmRegClass),
425 RiscV(RiscVInlineAsmRegClass),
426 Nvptx(NvptxInlineAsmRegClass),
427 PowerPC(PowerPCInlineAsmRegClass),
428 Hexagon(HexagonInlineAsmRegClass),
429 Mips(MipsInlineAsmRegClass),
430 S390x(S390xInlineAsmRegClass),
431 SpirV(SpirVInlineAsmRegClass),
432 Wasm(WasmInlineAsmRegClass),
433 Bpf(BpfInlineAsmRegClass),
434 Avr(AvrInlineAsmRegClass),
435 Msp430(Msp430InlineAsmRegClass),
436 // Placeholder for invalid register constraints for the current target
437 Err,
438 }
439
440 impl InlineAsmRegClass {
441 pub fn name(self) -> Symbol {
442 match self {
443 Self::X86(r) => r.name(),
444 Self::Arm(r) => r.name(),
445 Self::AArch64(r) => r.name(),
446 Self::RiscV(r) => r.name(),
447 Self::Nvptx(r) => r.name(),
448 Self::PowerPC(r) => r.name(),
449 Self::Hexagon(r) => r.name(),
450 Self::Mips(r) => r.name(),
451 Self::S390x(r) => r.name(),
452 Self::SpirV(r) => r.name(),
453 Self::Wasm(r) => r.name(),
454 Self::Bpf(r) => r.name(),
455 Self::Avr(r) => r.name(),
456 Self::Msp430(r) => r.name(),
457 Self::Err => rustc_span::symbol::sym::reg,
458 }
459 }
460
461 /// Returns a suggested register class to use for this type. This is called
462 /// when `supported_types` fails to give a better error
463 /// message to the user.
464 pub fn suggest_class(self, arch: InlineAsmArch, ty: InlineAsmType) -> Option<Self> {
465 match self {
466 Self::X86(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::X86),
467 Self::Arm(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Arm),
468 Self::AArch64(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::AArch64),
469 Self::RiscV(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::RiscV),
470 Self::Nvptx(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Nvptx),
471 Self::PowerPC(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::PowerPC),
472 Self::Hexagon(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Hexagon),
473 Self::Mips(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Mips),
474 Self::S390x(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::S390x),
475 Self::SpirV(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::SpirV),
476 Self::Wasm(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Wasm),
477 Self::Bpf(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Bpf),
478 Self::Avr(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Avr),
479 Self::Msp430(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Msp430),
480 Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
481 }
482 }
483
484 /// Returns a suggested template modifier to use for this type and an
485 /// example of a register named formatted with it.
486 ///
487 /// Such suggestions are useful if a type smaller than the full register
488 /// size is used and a modifier can be used to point to the subregister of
489 /// the correct size.
490 pub fn suggest_modifier(
491 self,
492 arch: InlineAsmArch,
493 ty: InlineAsmType,
494 ) -> Option<(char, &'static str)> {
495 match self {
496 Self::X86(r) => r.suggest_modifier(arch, ty),
497 Self::Arm(r) => r.suggest_modifier(arch, ty),
498 Self::AArch64(r) => r.suggest_modifier(arch, ty),
499 Self::RiscV(r) => r.suggest_modifier(arch, ty),
500 Self::Nvptx(r) => r.suggest_modifier(arch, ty),
501 Self::PowerPC(r) => r.suggest_modifier(arch, ty),
502 Self::Hexagon(r) => r.suggest_modifier(arch, ty),
503 Self::Mips(r) => r.suggest_modifier(arch, ty),
504 Self::S390x(r) => r.suggest_modifier(arch, ty),
505 Self::SpirV(r) => r.suggest_modifier(arch, ty),
506 Self::Wasm(r) => r.suggest_modifier(arch, ty),
507 Self::Bpf(r) => r.suggest_modifier(arch, ty),
508 Self::Avr(r) => r.suggest_modifier(arch, ty),
509 Self::Msp430(r) => r.suggest_modifier(arch, ty),
510 Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
511 }
512 }
513
514 /// Returns the default modifier for this register and an example of a
515 /// register named formatted with it.
516 ///
517 /// This is only needed when the register class can suggest a modifier, so
518 /// that the user can be shown how to get the default behavior without a
519 /// warning.
520 pub fn default_modifier(self, arch: InlineAsmArch) -> Option<(char, &'static str)> {
521 match self {
522 Self::X86(r) => r.default_modifier(arch),
523 Self::Arm(r) => r.default_modifier(arch),
524 Self::AArch64(r) => r.default_modifier(arch),
525 Self::RiscV(r) => r.default_modifier(arch),
526 Self::Nvptx(r) => r.default_modifier(arch),
527 Self::PowerPC(r) => r.default_modifier(arch),
528 Self::Hexagon(r) => r.default_modifier(arch),
529 Self::Mips(r) => r.default_modifier(arch),
530 Self::S390x(r) => r.default_modifier(arch),
531 Self::SpirV(r) => r.default_modifier(arch),
532 Self::Wasm(r) => r.default_modifier(arch),
533 Self::Bpf(r) => r.default_modifier(arch),
534 Self::Avr(r) => r.default_modifier(arch),
535 Self::Msp430(r) => r.default_modifier(arch),
536 Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
537 }
538 }
539
540 /// Returns a list of supported types for this register class, each with an
541 /// options target feature required to use this type.
542 pub fn supported_types(
543 self,
544 arch: InlineAsmArch,
545 ) -> &'static [(InlineAsmType, Option<Symbol>)] {
546 match self {
547 Self::X86(r) => r.supported_types(arch),
548 Self::Arm(r) => r.supported_types(arch),
549 Self::AArch64(r) => r.supported_types(arch),
550 Self::RiscV(r) => r.supported_types(arch),
551 Self::Nvptx(r) => r.supported_types(arch),
552 Self::PowerPC(r) => r.supported_types(arch),
553 Self::Hexagon(r) => r.supported_types(arch),
554 Self::Mips(r) => r.supported_types(arch),
555 Self::S390x(r) => r.supported_types(arch),
556 Self::SpirV(r) => r.supported_types(arch),
557 Self::Wasm(r) => r.supported_types(arch),
558 Self::Bpf(r) => r.supported_types(arch),
559 Self::Avr(r) => r.supported_types(arch),
560 Self::Msp430(r) => r.supported_types(arch),
561 Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
562 }
563 }
564
565 pub fn parse(arch: InlineAsmArch, name: Symbol) -> Result<Self, &'static str> {
566 Ok(match arch {
567 InlineAsmArch::X86 | InlineAsmArch::X86_64 => {
568 Self::X86(X86InlineAsmRegClass::parse(name)?)
569 }
570 InlineAsmArch::Arm => Self::Arm(ArmInlineAsmRegClass::parse(name)?),
571 InlineAsmArch::AArch64 => Self::AArch64(AArch64InlineAsmRegClass::parse(name)?),
572 InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
573 Self::RiscV(RiscVInlineAsmRegClass::parse(name)?)
574 }
575 InlineAsmArch::Nvptx64 => Self::Nvptx(NvptxInlineAsmRegClass::parse(name)?),
576 InlineAsmArch::PowerPC | InlineAsmArch::PowerPC64 => {
577 Self::PowerPC(PowerPCInlineAsmRegClass::parse(name)?)
578 }
579 InlineAsmArch::Hexagon => Self::Hexagon(HexagonInlineAsmRegClass::parse(name)?),
580 InlineAsmArch::Mips | InlineAsmArch::Mips64 => {
581 Self::Mips(MipsInlineAsmRegClass::parse(name)?)
582 }
583 InlineAsmArch::S390x => Self::S390x(S390xInlineAsmRegClass::parse(name)?),
584 InlineAsmArch::SpirV => Self::SpirV(SpirVInlineAsmRegClass::parse(name)?),
585 InlineAsmArch::Wasm32 | InlineAsmArch::Wasm64 => {
586 Self::Wasm(WasmInlineAsmRegClass::parse(name)?)
587 }
588 InlineAsmArch::Bpf => Self::Bpf(BpfInlineAsmRegClass::parse(name)?),
589 InlineAsmArch::Avr => Self::Avr(AvrInlineAsmRegClass::parse(name)?),
590 InlineAsmArch::Msp430 => Self::Msp430(Msp430InlineAsmRegClass::parse(name)?),
591 })
592 }
593
594 /// Returns the list of template modifiers that can be used with this
595 /// register class.
596 pub fn valid_modifiers(self, arch: InlineAsmArch) -> &'static [char] {
597 match self {
598 Self::X86(r) => r.valid_modifiers(arch),
599 Self::Arm(r) => r.valid_modifiers(arch),
600 Self::AArch64(r) => r.valid_modifiers(arch),
601 Self::RiscV(r) => r.valid_modifiers(arch),
602 Self::Nvptx(r) => r.valid_modifiers(arch),
603 Self::PowerPC(r) => r.valid_modifiers(arch),
604 Self::Hexagon(r) => r.valid_modifiers(arch),
605 Self::Mips(r) => r.valid_modifiers(arch),
606 Self::S390x(r) => r.valid_modifiers(arch),
607 Self::SpirV(r) => r.valid_modifiers(arch),
608 Self::Wasm(r) => r.valid_modifiers(arch),
609 Self::Bpf(r) => r.valid_modifiers(arch),
610 Self::Avr(r) => r.valid_modifiers(arch),
611 Self::Msp430(r) => r.valid_modifiers(arch),
612 Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
613 }
614 }
615
616 /// Returns whether registers in this class can only be used as clobbers
617 /// and not as inputs/outputs.
618 pub fn is_clobber_only(self, arch: InlineAsmArch) -> bool {
619 self.supported_types(arch).is_empty()
620 }
621 }
622
623 #[derive(
624 Copy,
625 Clone,
626 Encodable,
627 Decodable,
628 Debug,
629 Eq,
630 PartialEq,
631 PartialOrd,
632 Hash,
633 HashStable_Generic
634 )]
635 pub enum InlineAsmRegOrRegClass {
636 Reg(InlineAsmReg),
637 RegClass(InlineAsmRegClass),
638 }
639
640 impl InlineAsmRegOrRegClass {
641 pub fn reg_class(self) -> InlineAsmRegClass {
642 match self {
643 Self::Reg(r) => r.reg_class(),
644 Self::RegClass(r) => r,
645 }
646 }
647 }
648
649 impl fmt::Display for InlineAsmRegOrRegClass {
650 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
651 match self {
652 Self::Reg(r) => write!(f, "\"{}\"", r.name()),
653 Self::RegClass(r) => write!(f, "{}", r.name()),
654 }
655 }
656 }
657
658 /// Set of types which can be used with a particular register class.
659 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
660 pub enum InlineAsmType {
661 I8,
662 I16,
663 I32,
664 I64,
665 I128,
666 F32,
667 F64,
668 VecI8(u64),
669 VecI16(u64),
670 VecI32(u64),
671 VecI64(u64),
672 VecI128(u64),
673 VecF32(u64),
674 VecF64(u64),
675 }
676
677 impl InlineAsmType {
678 pub fn is_integer(self) -> bool {
679 matches!(self, Self::I8 | Self::I16 | Self::I32 | Self::I64 | Self::I128)
680 }
681
682 pub fn size(self) -> Size {
683 Size::from_bytes(match self {
684 Self::I8 => 1,
685 Self::I16 => 2,
686 Self::I32 => 4,
687 Self::I64 => 8,
688 Self::I128 => 16,
689 Self::F32 => 4,
690 Self::F64 => 8,
691 Self::VecI8(n) => n * 1,
692 Self::VecI16(n) => n * 2,
693 Self::VecI32(n) => n * 4,
694 Self::VecI64(n) => n * 8,
695 Self::VecI128(n) => n * 16,
696 Self::VecF32(n) => n * 4,
697 Self::VecF64(n) => n * 8,
698 })
699 }
700 }
701
702 impl fmt::Display for InlineAsmType {
703 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
704 match *self {
705 Self::I8 => f.write_str("i8"),
706 Self::I16 => f.write_str("i16"),
707 Self::I32 => f.write_str("i32"),
708 Self::I64 => f.write_str("i64"),
709 Self::I128 => f.write_str("i128"),
710 Self::F32 => f.write_str("f32"),
711 Self::F64 => f.write_str("f64"),
712 Self::VecI8(n) => write!(f, "i8x{}", n),
713 Self::VecI16(n) => write!(f, "i16x{}", n),
714 Self::VecI32(n) => write!(f, "i32x{}", n),
715 Self::VecI64(n) => write!(f, "i64x{}", n),
716 Self::VecI128(n) => write!(f, "i128x{}", n),
717 Self::VecF32(n) => write!(f, "f32x{}", n),
718 Self::VecF64(n) => write!(f, "f64x{}", n),
719 }
720 }
721 }
722
723 /// Returns the full set of allocatable registers for a given architecture.
724 ///
725 /// The registers are structured as a map containing the set of allocatable
726 /// registers in each register class. A particular register may be allocatable
727 /// from multiple register classes, in which case it will appear multiple times
728 /// in the map.
729 // NOTE: This function isn't used at the moment, but is needed to support
730 // falling back to an external assembler.
731 pub fn allocatable_registers(
732 arch: InlineAsmArch,
733 reloc_model: RelocModel,
734 target_features: &FxHashSet<Symbol>,
735 target: &crate::spec::Target,
736 ) -> FxHashMap<InlineAsmRegClass, FxHashSet<InlineAsmReg>> {
737 match arch {
738 InlineAsmArch::X86 | InlineAsmArch::X86_64 => {
739 let mut map = x86::regclass_map();
740 x86::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
741 map
742 }
743 InlineAsmArch::Arm => {
744 let mut map = arm::regclass_map();
745 arm::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
746 map
747 }
748 InlineAsmArch::AArch64 => {
749 let mut map = aarch64::regclass_map();
750 aarch64::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
751 map
752 }
753 InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
754 let mut map = riscv::regclass_map();
755 riscv::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
756 map
757 }
758 InlineAsmArch::Nvptx64 => {
759 let mut map = nvptx::regclass_map();
760 nvptx::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
761 map
762 }
763 InlineAsmArch::PowerPC | InlineAsmArch::PowerPC64 => {
764 let mut map = powerpc::regclass_map();
765 powerpc::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
766 map
767 }
768 InlineAsmArch::Hexagon => {
769 let mut map = hexagon::regclass_map();
770 hexagon::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
771 map
772 }
773 InlineAsmArch::Mips | InlineAsmArch::Mips64 => {
774 let mut map = mips::regclass_map();
775 mips::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
776 map
777 }
778 InlineAsmArch::S390x => {
779 let mut map = s390x::regclass_map();
780 s390x::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
781 map
782 }
783 InlineAsmArch::SpirV => {
784 let mut map = spirv::regclass_map();
785 spirv::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
786 map
787 }
788 InlineAsmArch::Wasm32 | InlineAsmArch::Wasm64 => {
789 let mut map = wasm::regclass_map();
790 wasm::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
791 map
792 }
793 InlineAsmArch::Bpf => {
794 let mut map = bpf::regclass_map();
795 bpf::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
796 map
797 }
798 InlineAsmArch::Avr => {
799 let mut map = avr::regclass_map();
800 avr::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
801 map
802 }
803 InlineAsmArch::Msp430 => {
804 let mut map = msp430::regclass_map();
805 msp430::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
806 map
807 }
808 }
809 }
810
811 #[derive(
812 Copy,
813 Clone,
814 Encodable,
815 Decodable,
816 Debug,
817 Eq,
818 PartialEq,
819 PartialOrd,
820 Hash,
821 HashStable_Generic
822 )]
823 pub enum InlineAsmClobberAbi {
824 X86,
825 X86_64Win,
826 X86_64SysV,
827 Arm,
828 AArch64,
829 AArch64NoX18,
830 RiscV,
831 }
832
833 impl InlineAsmClobberAbi {
834 /// Parses a clobber ABI for the given target, or returns a list of supported
835 /// clobber ABIs for the target.
836 pub fn parse(
837 arch: InlineAsmArch,
838 target: &Target,
839 name: Symbol,
840 ) -> Result<Self, &'static [&'static str]> {
841 let name = name.as_str();
842 match arch {
843 InlineAsmArch::X86 => match name {
844 "C" | "system" | "efiapi" | "cdecl" | "stdcall" | "fastcall" => {
845 Ok(InlineAsmClobberAbi::X86)
846 }
847 _ => Err(&["C", "system", "efiapi", "cdecl", "stdcall", "fastcall"]),
848 },
849 InlineAsmArch::X86_64 => match name {
850 "C" | "system" if !target.is_like_windows => Ok(InlineAsmClobberAbi::X86_64SysV),
851 "C" | "system" if target.is_like_windows => Ok(InlineAsmClobberAbi::X86_64Win),
852 "win64" | "efiapi" => Ok(InlineAsmClobberAbi::X86_64Win),
853 "sysv64" => Ok(InlineAsmClobberAbi::X86_64SysV),
854 _ => Err(&["C", "system", "efiapi", "win64", "sysv64"]),
855 },
856 InlineAsmArch::Arm => match name {
857 "C" | "system" | "efiapi" | "aapcs" => Ok(InlineAsmClobberAbi::Arm),
858 _ => Err(&["C", "system", "efiapi", "aapcs"]),
859 },
860 InlineAsmArch::AArch64 => match name {
861 "C" | "system" | "efiapi" => Ok(if aarch64::target_reserves_x18(target) {
862 InlineAsmClobberAbi::AArch64NoX18
863 } else {
864 InlineAsmClobberAbi::AArch64
865 }),
866 _ => Err(&["C", "system", "efiapi"]),
867 },
868 InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => match name {
869 "C" | "system" | "efiapi" => Ok(InlineAsmClobberAbi::RiscV),
870 _ => Err(&["C", "system", "efiapi"]),
871 },
872 _ => Err(&[]),
873 }
874 }
875
876 /// Returns the set of registers which are clobbered by this ABI.
877 pub fn clobbered_regs(self) -> &'static [InlineAsmReg] {
878 macro_rules! clobbered_regs {
879 ($arch:ident $arch_reg:ident {
880 $(
881 $reg:ident,
882 )*
883 }) => {
884 &[
885 $(InlineAsmReg::$arch($arch_reg::$reg),)*
886 ]
887 };
888 }
889 match self {
890 InlineAsmClobberAbi::X86 => clobbered_regs! {
891 X86 X86InlineAsmReg {
892 ax, cx, dx,
893
894 xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7,
895
896 k0, k1, k2, k3, k4, k5, k6, k7,
897
898 mm0, mm1, mm2, mm3, mm4, mm5, mm6, mm7,
899 st0, st1, st2, st3, st4, st5, st6, st7,
900 }
901 },
902 InlineAsmClobberAbi::X86_64SysV => clobbered_regs! {
903 X86 X86InlineAsmReg {
904 ax, cx, dx, si, di, r8, r9, r10, r11,
905
906 xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7,
907 xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15,
908 zmm16, zmm17, zmm18, zmm19, zmm20, zmm21, zmm22, zmm23,
909 zmm24, zmm25, zmm26, zmm27, zmm28, zmm29, zmm30, zmm31,
910
911 k0, k1, k2, k3, k4, k5, k6, k7,
912
913 mm0, mm1, mm2, mm3, mm4, mm5, mm6, mm7,
914 st0, st1, st2, st3, st4, st5, st6, st7,
915 tmm0, tmm1, tmm2, tmm3, tmm4, tmm5, tmm6, tmm7,
916 }
917 },
918 InlineAsmClobberAbi::X86_64Win => clobbered_regs! {
919 X86 X86InlineAsmReg {
920 // rdi and rsi are callee-saved on windows
921 ax, cx, dx, r8, r9, r10, r11,
922
923 // xmm6-xmm15 are callee-saved on windows, but we need to
924 // mark them as clobbered anyways because the upper portions
925 // of ymm6-ymm15 are volatile.
926 xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7,
927 xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15,
928 zmm16, zmm17, zmm18, zmm19, zmm20, zmm21, zmm22, zmm23,
929 zmm24, zmm25, zmm26, zmm27, zmm28, zmm29, zmm30, zmm31,
930
931 k0, k1, k2, k3, k4, k5, k6, k7,
932
933 mm0, mm1, mm2, mm3, mm4, mm5, mm6, mm7,
934 st0, st1, st2, st3, st4, st5, st6, st7,
935 tmm0, tmm1, tmm2, tmm3, tmm4, tmm5, tmm6, tmm7,
936 }
937 },
938 InlineAsmClobberAbi::AArch64 => clobbered_regs! {
939 AArch64 AArch64InlineAsmReg {
940 x0, x1, x2, x3, x4, x5, x6, x7,
941 x8, x9, x10, x11, x12, x13, x14, x15,
942 x16, x17, x18, x30,
943
944 // Technically the low 64 bits of v8-v15 are preserved, but
945 // we have no way of expressing this using clobbers.
946 v0, v1, v2, v3, v4, v5, v6, v7,
947 v8, v9, v10, v11, v12, v13, v14, v15,
948 v16, v17, v18, v19, v20, v21, v22, v23,
949 v24, v25, v26, v27, v28, v29, v30, v31,
950
951 p0, p1, p2, p3, p4, p5, p6, p7,
952 p8, p9, p10, p11, p12, p13, p14, p15,
953 ffr,
954
955 }
956 },
957 InlineAsmClobberAbi::AArch64NoX18 => clobbered_regs! {
958 AArch64 AArch64InlineAsmReg {
959 x0, x1, x2, x3, x4, x5, x6, x7,
960 x8, x9, x10, x11, x12, x13, x14, x15,
961 x16, x17, x30,
962
963 // Technically the low 64 bits of v8-v15 are preserved, but
964 // we have no way of expressing this using clobbers.
965 v0, v1, v2, v3, v4, v5, v6, v7,
966 v8, v9, v10, v11, v12, v13, v14, v15,
967 v16, v17, v18, v19, v20, v21, v22, v23,
968 v24, v25, v26, v27, v28, v29, v30, v31,
969
970 p0, p1, p2, p3, p4, p5, p6, p7,
971 p8, p9, p10, p11, p12, p13, p14, p15,
972 ffr,
973
974 }
975 },
976 InlineAsmClobberAbi::Arm => clobbered_regs! {
977 Arm ArmInlineAsmReg {
978 // r9 is either platform-reserved or callee-saved. Either
979 // way we don't need to clobber it.
980 r0, r1, r2, r3, r12, r14,
981
982 // The finest-grained register variant is used here so that
983 // partial uses of larger registers are properly handled.
984 s0, s1, s2, s3, s4, s5, s6, s7,
985 s8, s9, s10, s11, s12, s13, s14, s15,
986 // s16-s31 are callee-saved
987 d16, d17, d18, d19, d20, d21, d22, d23,
988 d24, d25, d26, d27, d28, d29, d30, d31,
989 }
990 },
991 InlineAsmClobberAbi::RiscV => clobbered_regs! {
992 RiscV RiscVInlineAsmReg {
993 // ra
994 x1,
995 // t0-t2
996 x5, x6, x7,
997 // a0-a7
998 x10, x11, x12, x13, x14, x15, x16, x17,
999 // t3-t6
1000 x28, x29, x30, x31,
1001 // ft0-ft7
1002 f0, f1, f2, f3, f4, f5, f6, f7,
1003 // fa0-fa7
1004 f10, f11, f12, f13, f14, f15, f16, f17,
1005 // ft8-ft11
1006 f28, f29, f30, f31,
1007
1008 v0, v1, v2, v3, v4, v5, v6, v7,
1009 v8, v9, v10, v11, v12, v13, v14, v15,
1010 v16, v17, v18, v19, v20, v21, v22, v23,
1011 v24, v25, v26, v27, v28, v29, v30, v31,
1012 }
1013 },
1014 }
1015 }
1016 }