]> git.lizzy.rs Git - rust.git/blob - src/librustc_target/asm/mod.rs
Rework `rustc_serialize`
[rust.git] / src / librustc_target / asm / mod.rs
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_use]
10 macro_rules! def_reg_class {
11     ($arch:ident $arch_regclass:ident {
12         $(
13             $class:ident,
14         )*
15     }) => {
16         #[derive(Copy, Clone, Encodable, Decodable, Debug, Eq, PartialEq, Hash, HashStable_Generic)]
17         #[allow(non_camel_case_types)]
18         pub enum $arch_regclass {
19             $($class,)*
20         }
21
22         impl $arch_regclass {
23             pub fn name(self) -> &'static str {
24                 match self {
25                     $(Self::$class => stringify!($class),)*
26                 }
27             }
28
29             pub fn parse(_arch: super::InlineAsmArch, name: &str) -> Result<Self, &'static str> {
30                 match name {
31                     $(
32                         stringify!($class) => Ok(Self::$class),
33                     )*
34                     _ => Err("unknown register class"),
35                 }
36             }
37         }
38
39         pub(super) fn regclass_map() -> rustc_data_structures::fx::FxHashMap<
40             super::InlineAsmRegClass,
41             rustc_data_structures::fx::FxHashSet<super::InlineAsmReg>,
42         > {
43             use rustc_data_structures::fx::{FxHashMap, FxHashSet};
44             use super::InlineAsmRegClass;
45             let mut map = FxHashMap::default();
46             $(
47                 map.insert(InlineAsmRegClass::$arch($arch_regclass::$class), FxHashSet::default());
48             )*
49             map
50         }
51     }
52 }
53
54 #[macro_use]
55 macro_rules! def_regs {
56     ($arch:ident $arch_reg:ident $arch_regclass:ident {
57         $(
58             $reg:ident: $class:ident $(, $extra_class:ident)* = [$reg_name:literal $(, $alias:literal)*] $(% $filter:ident)?,
59         )*
60         $(
61             #error = [$($bad_reg:literal),+] => $error:literal,
62         )*
63     }) => {
64         #[allow(unreachable_code)]
65         #[derive(Copy, Clone, Encodable, Decodable, Debug, Eq, PartialEq, Hash, HashStable_Generic)]
66         #[allow(non_camel_case_types)]
67         pub enum $arch_reg {
68             $($reg,)*
69         }
70
71         impl $arch_reg {
72             pub fn name(self) -> &'static str {
73                 match self {
74                     $(Self::$reg => $reg_name,)*
75                 }
76             }
77
78             pub fn reg_class(self) -> $arch_regclass {
79                 match self {
80                     $(Self::$reg => $arch_regclass::$class,)*
81                 }
82             }
83
84             pub fn parse(
85                 _arch: super::InlineAsmArch,
86                 mut _has_feature: impl FnMut(&str) -> bool,
87                 _target: &crate::spec::Target,
88                 name: &str,
89             ) -> Result<Self, &'static str> {
90                 match name {
91                     $(
92                         $($alias)|* | $reg_name => {
93                             $($filter(_arch, &mut _has_feature, _target, false)?;)?
94                             Ok(Self::$reg)
95                         }
96                     )*
97                     $(
98                         $($bad_reg)|* => Err($error),
99                     )*
100                     _ => Err("unknown register"),
101                 }
102             }
103         }
104
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>,
112             >,
113         ) {
114             #[allow(unused_imports)]
115             use super::{InlineAsmReg, InlineAsmRegClass};
116             $(
117                 if $($filter(_arch, &mut _has_feature, _target, true).is_ok() &&)? true {
118                     if let Some(set) = _map.get_mut(&InlineAsmRegClass::$arch($arch_regclass::$class)) {
119                         set.insert(InlineAsmReg::$arch($arch_reg::$reg));
120                     }
121                     $(
122                         if let Some(set) = _map.get_mut(&InlineAsmRegClass::$arch($arch_regclass::$extra_class)) {
123                             set.insert(InlineAsmReg::$arch($arch_reg::$reg));
124                         }
125                     )*
126                 }
127             )*
128         }
129     }
130 }
131
132 #[macro_use]
133 macro_rules! types {
134     (
135         $(_ : $($ty:expr),+;)?
136         $($feature:literal: $($ty2:expr),+;)*
137     ) => {
138         {
139             use super::InlineAsmType::*;
140             &[
141                 $($(
142                     ($ty, None),
143                 )*)?
144                 $($(
145                     ($ty2, Some($feature)),
146                 )*)*
147             ]
148         }
149     };
150 }
151
152 mod aarch64;
153 mod arm;
154 mod hexagon;
155 mod nvptx;
156 mod riscv;
157 mod x86;
158
159 pub use aarch64::{AArch64InlineAsmReg, AArch64InlineAsmRegClass};
160 pub use arm::{ArmInlineAsmReg, ArmInlineAsmRegClass};
161 pub use hexagon::{HexagonInlineAsmReg, HexagonInlineAsmRegClass};
162 pub use nvptx::{NvptxInlineAsmReg, NvptxInlineAsmRegClass};
163 pub use riscv::{RiscVInlineAsmReg, RiscVInlineAsmRegClass};
164 pub use x86::{X86InlineAsmReg, X86InlineAsmRegClass};
165
166 #[derive(Copy, Clone, Encodable, Decodable, Debug, Eq, PartialEq, Hash)]
167 pub enum InlineAsmArch {
168     X86,
169     X86_64,
170     Arm,
171     AArch64,
172     RiscV32,
173     RiscV64,
174     Nvptx64,
175     Hexagon,
176 }
177
178 impl FromStr for InlineAsmArch {
179     type Err = ();
180
181     fn from_str(s: &str) -> Result<InlineAsmArch, ()> {
182         match s {
183             "x86" => Ok(Self::X86),
184             "x86_64" => Ok(Self::X86_64),
185             "arm" => Ok(Self::Arm),
186             "aarch64" => Ok(Self::AArch64),
187             "riscv32" => Ok(Self::RiscV32),
188             "riscv64" => Ok(Self::RiscV64),
189             "nvptx64" => Ok(Self::Nvptx64),
190             "hexagon" => Ok(Self::Hexagon),
191             _ => Err(()),
192         }
193     }
194 }
195
196 #[derive(Copy, Clone, Encodable, Decodable, Debug, Eq, PartialEq, Hash, HashStable_Generic)]
197 pub enum InlineAsmReg {
198     X86(X86InlineAsmReg),
199     Arm(ArmInlineAsmReg),
200     AArch64(AArch64InlineAsmReg),
201     RiscV(RiscVInlineAsmReg),
202     Nvptx(NvptxInlineAsmReg),
203     Hexagon(HexagonInlineAsmReg),
204 }
205
206 impl InlineAsmReg {
207     pub fn name(self) -> &'static str {
208         match self {
209             Self::X86(r) => r.name(),
210             Self::Arm(r) => r.name(),
211             Self::AArch64(r) => r.name(),
212             Self::RiscV(r) => r.name(),
213             Self::Hexagon(r) => r.name(),
214         }
215     }
216
217     pub fn reg_class(self) -> InlineAsmRegClass {
218         match self {
219             Self::X86(r) => InlineAsmRegClass::X86(r.reg_class()),
220             Self::Arm(r) => InlineAsmRegClass::Arm(r.reg_class()),
221             Self::AArch64(r) => InlineAsmRegClass::AArch64(r.reg_class()),
222             Self::RiscV(r) => InlineAsmRegClass::RiscV(r.reg_class()),
223             Self::Hexagon(r) => InlineAsmRegClass::Hexagon(r.reg_class()),
224         }
225     }
226
227     pub fn parse(
228         arch: InlineAsmArch,
229         has_feature: impl FnMut(&str) -> bool,
230         target: &Target,
231         name: Symbol,
232     ) -> Result<Self, &'static str> {
233         // FIXME: use direct symbol comparison for register names
234         // Use `Symbol::as_str` instead of `Symbol::with` here because `has_feature` may access `Symbol`.
235         let name = name.as_str();
236         Ok(match arch {
237             InlineAsmArch::X86 | InlineAsmArch::X86_64 => {
238                 Self::X86(X86InlineAsmReg::parse(arch, has_feature, target, &name)?)
239             }
240             InlineAsmArch::Arm => {
241                 Self::Arm(ArmInlineAsmReg::parse(arch, has_feature, target, &name)?)
242             }
243             InlineAsmArch::AArch64 => {
244                 Self::AArch64(AArch64InlineAsmReg::parse(arch, has_feature, target, &name)?)
245             }
246             InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
247                 Self::RiscV(RiscVInlineAsmReg::parse(arch, has_feature, target, &name)?)
248             }
249             InlineAsmArch::Nvptx64 => {
250                 Self::Nvptx(NvptxInlineAsmReg::parse(arch, has_feature, target, &name)?)
251             }
252             InlineAsmArch::Hexagon => {
253                 Self::Hexagon(HexagonInlineAsmReg::parse(arch, has_feature, target, &name)?)
254             }
255         })
256     }
257
258     // NOTE: This function isn't used at the moment, but is needed to support
259     // falling back to an external assembler.
260     pub fn emit(
261         self,
262         out: &mut dyn fmt::Write,
263         arch: InlineAsmArch,
264         modifier: Option<char>,
265     ) -> fmt::Result {
266         match self {
267             Self::X86(r) => r.emit(out, arch, modifier),
268             Self::Arm(r) => r.emit(out, arch, modifier),
269             Self::AArch64(r) => r.emit(out, arch, modifier),
270             Self::RiscV(r) => r.emit(out, arch, modifier),
271             Self::Hexagon(r) => r.emit(out, arch, modifier),
272         }
273     }
274
275     pub fn overlapping_regs(self, mut cb: impl FnMut(InlineAsmReg)) {
276         match self {
277             Self::X86(r) => r.overlapping_regs(|r| cb(Self::X86(r))),
278             Self::Arm(r) => r.overlapping_regs(|r| cb(Self::Arm(r))),
279             Self::AArch64(_) => cb(self),
280             Self::RiscV(_) => cb(self),
281             Self::Hexagon(r) => r.overlapping_regs(|r| cb(Self::Hexagon(r))),
282         }
283     }
284 }
285
286 #[derive(Copy, Clone, Encodable, Decodable, Debug, Eq, PartialEq, Hash, HashStable_Generic)]
287 pub enum InlineAsmRegClass {
288     X86(X86InlineAsmRegClass),
289     Arm(ArmInlineAsmRegClass),
290     AArch64(AArch64InlineAsmRegClass),
291     RiscV(RiscVInlineAsmRegClass),
292     Nvptx(NvptxInlineAsmRegClass),
293     Hexagon(HexagonInlineAsmRegClass),
294 }
295
296 impl InlineAsmRegClass {
297     pub fn name(self) -> &'static str {
298         match self {
299             Self::X86(r) => r.name(),
300             Self::Arm(r) => r.name(),
301             Self::AArch64(r) => r.name(),
302             Self::RiscV(r) => r.name(),
303             Self::Nvptx(r) => r.name(),
304             Self::Hexagon(r) => r.name(),
305         }
306     }
307
308     /// Returns a suggested register class to use for this type. This is called
309     /// after type checking via `supported_types` fails to give a better error
310     /// message to the user.
311     pub fn suggest_class(self, arch: InlineAsmArch, ty: InlineAsmType) -> Option<Self> {
312         match self {
313             Self::X86(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::X86),
314             Self::Arm(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Arm),
315             Self::AArch64(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::AArch64),
316             Self::RiscV(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::RiscV),
317             Self::Nvptx(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Nvptx),
318             Self::Hexagon(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Hexagon),
319         }
320     }
321
322     /// Returns a suggested template modifier to use for this type and an
323     /// example of a  register named formatted with it.
324     ///
325     /// Such suggestions are useful if a type smaller than the full register
326     /// size is used and a modifier can be used to point to the subregister of
327     /// the correct size.
328     pub fn suggest_modifier(
329         self,
330         arch: InlineAsmArch,
331         ty: InlineAsmType,
332     ) -> Option<(char, &'static str)> {
333         match self {
334             Self::X86(r) => r.suggest_modifier(arch, ty),
335             Self::Arm(r) => r.suggest_modifier(arch, ty),
336             Self::AArch64(r) => r.suggest_modifier(arch, ty),
337             Self::RiscV(r) => r.suggest_modifier(arch, ty),
338             Self::Nvptx(r) => r.suggest_modifier(arch, ty),
339             Self::Hexagon(r) => r.suggest_modifier(arch, ty),
340         }
341     }
342
343     /// Returns the default modifier for this register and an example of a
344     /// register named formatted with it.
345     ///
346     /// This is only needed when the register class can suggest a modifier, so
347     /// that the user can be shown how to get the default behavior without a
348     /// warning.
349     pub fn default_modifier(self, arch: InlineAsmArch) -> Option<(char, &'static str)> {
350         match self {
351             Self::X86(r) => r.default_modifier(arch),
352             Self::Arm(r) => r.default_modifier(arch),
353             Self::AArch64(r) => r.default_modifier(arch),
354             Self::RiscV(r) => r.default_modifier(arch),
355             Self::Nvptx(r) => r.default_modifier(arch),
356             Self::Hexagon(r) => r.default_modifier(arch),
357         }
358     }
359
360     /// Returns a list of supported types for this register class, each with a
361     /// options target feature required to use this type.
362     pub fn supported_types(
363         self,
364         arch: InlineAsmArch,
365     ) -> &'static [(InlineAsmType, Option<&'static str>)] {
366         match self {
367             Self::X86(r) => r.supported_types(arch),
368             Self::Arm(r) => r.supported_types(arch),
369             Self::AArch64(r) => r.supported_types(arch),
370             Self::RiscV(r) => r.supported_types(arch),
371             Self::Nvptx(r) => r.supported_types(arch),
372             Self::Hexagon(r) => r.supported_types(arch),
373         }
374     }
375
376     pub fn parse(arch: InlineAsmArch, name: Symbol) -> Result<Self, &'static str> {
377         // FIXME: use direct symbol comparison for register class names
378         name.with(|name| {
379             Ok(match arch {
380                 InlineAsmArch::X86 | InlineAsmArch::X86_64 => {
381                     Self::X86(X86InlineAsmRegClass::parse(arch, name)?)
382                 }
383                 InlineAsmArch::Arm => Self::Arm(ArmInlineAsmRegClass::parse(arch, name)?),
384                 InlineAsmArch::AArch64 => {
385                     Self::AArch64(AArch64InlineAsmRegClass::parse(arch, name)?)
386                 }
387                 InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
388                     Self::RiscV(RiscVInlineAsmRegClass::parse(arch, name)?)
389                 }
390                 InlineAsmArch::Nvptx64 => Self::Nvptx(NvptxInlineAsmRegClass::parse(arch, name)?),
391                 InlineAsmArch::Hexagon => {
392                     Self::Hexagon(HexagonInlineAsmRegClass::parse(arch, name)?)
393                 }
394             })
395         })
396     }
397
398     /// Returns the list of template modifiers that can be used with this
399     /// register class.
400     pub fn valid_modifiers(self, arch: InlineAsmArch) -> &'static [char] {
401         match self {
402             Self::X86(r) => r.valid_modifiers(arch),
403             Self::Arm(r) => r.valid_modifiers(arch),
404             Self::AArch64(r) => r.valid_modifiers(arch),
405             Self::RiscV(r) => r.valid_modifiers(arch),
406             Self::Nvptx(r) => r.valid_modifiers(arch),
407             Self::Hexagon(r) => r.valid_modifiers(arch),
408         }
409     }
410 }
411
412 #[derive(Copy, Clone, Encodable, Decodable, Debug, Eq, PartialEq, Hash, HashStable_Generic)]
413 pub enum InlineAsmRegOrRegClass {
414     Reg(InlineAsmReg),
415     RegClass(InlineAsmRegClass),
416 }
417
418 impl InlineAsmRegOrRegClass {
419     pub fn reg_class(self) -> InlineAsmRegClass {
420         match self {
421             Self::Reg(r) => r.reg_class(),
422             Self::RegClass(r) => r,
423         }
424     }
425 }
426
427 impl fmt::Display for InlineAsmRegOrRegClass {
428     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
429         match self {
430             Self::Reg(r) => write!(f, "\"{}\"", r.name()),
431             Self::RegClass(r) => f.write_str(r.name()),
432         }
433     }
434 }
435
436 /// Set of types which can be used with a particular register class.
437 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
438 pub enum InlineAsmType {
439     I8,
440     I16,
441     I32,
442     I64,
443     I128,
444     F32,
445     F64,
446     VecI8(u64),
447     VecI16(u64),
448     VecI32(u64),
449     VecI64(u64),
450     VecI128(u64),
451     VecF32(u64),
452     VecF64(u64),
453 }
454
455 impl InlineAsmType {
456     pub fn is_integer(self) -> bool {
457         match self {
458             Self::I8 | Self::I16 | Self::I32 | Self::I64 | Self::I128 => true,
459             _ => false,
460         }
461     }
462
463     pub fn size(self) -> Size {
464         Size::from_bytes(match self {
465             Self::I8 => 1,
466             Self::I16 => 2,
467             Self::I32 => 4,
468             Self::I64 => 8,
469             Self::I128 => 16,
470             Self::F32 => 4,
471             Self::F64 => 8,
472             Self::VecI8(n) => n * 1,
473             Self::VecI16(n) => n * 2,
474             Self::VecI32(n) => n * 4,
475             Self::VecI64(n) => n * 8,
476             Self::VecI128(n) => n * 16,
477             Self::VecF32(n) => n * 4,
478             Self::VecF64(n) => n * 8,
479         })
480     }
481 }
482
483 impl fmt::Display for InlineAsmType {
484     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
485         match *self {
486             Self::I8 => f.write_str("i8"),
487             Self::I16 => f.write_str("i16"),
488             Self::I32 => f.write_str("i32"),
489             Self::I64 => f.write_str("i64"),
490             Self::I128 => f.write_str("i128"),
491             Self::F32 => f.write_str("f32"),
492             Self::F64 => f.write_str("f64"),
493             Self::VecI8(n) => write!(f, "i8x{}", n),
494             Self::VecI16(n) => write!(f, "i16x{}", n),
495             Self::VecI32(n) => write!(f, "i32x{}", n),
496             Self::VecI64(n) => write!(f, "i64x{}", n),
497             Self::VecI128(n) => write!(f, "i128x{}", n),
498             Self::VecF32(n) => write!(f, "f32x{}", n),
499             Self::VecF64(n) => write!(f, "f64x{}", n),
500         }
501     }
502 }
503
504 /// Returns the full set of allocatable registers for a given architecture.
505 ///
506 /// The registers are structured as a map containing the set of allocatable
507 /// registers in each register class. A particular register may be allocatable
508 /// from multiple register classes, in which case it will appear multiple times
509 /// in the map.
510 // NOTE: This function isn't used at the moment, but is needed to support
511 // falling back to an external assembler.
512 pub fn allocatable_registers(
513     arch: InlineAsmArch,
514     has_feature: impl FnMut(&str) -> bool,
515     target: &crate::spec::Target,
516 ) -> FxHashMap<InlineAsmRegClass, FxHashSet<InlineAsmReg>> {
517     match arch {
518         InlineAsmArch::X86 | InlineAsmArch::X86_64 => {
519             let mut map = x86::regclass_map();
520             x86::fill_reg_map(arch, has_feature, target, &mut map);
521             map
522         }
523         InlineAsmArch::Arm => {
524             let mut map = arm::regclass_map();
525             arm::fill_reg_map(arch, has_feature, target, &mut map);
526             map
527         }
528         InlineAsmArch::AArch64 => {
529             let mut map = aarch64::regclass_map();
530             aarch64::fill_reg_map(arch, has_feature, target, &mut map);
531             map
532         }
533         InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
534             let mut map = riscv::regclass_map();
535             riscv::fill_reg_map(arch, has_feature, target, &mut map);
536             map
537         }
538         InlineAsmArch::Nvptx64 => {
539             let mut map = nvptx::regclass_map();
540             nvptx::fill_reg_map(arch, has_feature, target, &mut map);
541             map
542         }
543         InlineAsmArch::Hexagon => {
544             let mut map = hexagon::regclass_map();
545             hexagon::fill_reg_map(arch, has_feature, target, &mut map);
546             map
547         }
548     }
549 }