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