]>
Commit | Line | Data |
---|---|---|
f9f354fc | 1 | use crate::abi::Size; |
f035d41b | 2 | use crate::spec::Target; |
f9f354fc XL |
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 | ||
f9f354fc XL |
9 | macro_rules! def_reg_class { |
10 | ($arch:ident $arch_regclass:ident { | |
11 | $( | |
12 | $class:ident, | |
13 | )* | |
14 | }) => { | |
6a06907d | 15 | #[derive(Copy, Clone, Encodable, Decodable, Debug, Eq, PartialEq, PartialOrd, Hash, HashStable_Generic)] |
f9f354fc XL |
16 | #[allow(non_camel_case_types)] |
17 | pub enum $arch_regclass { | |
18 | $($class,)* | |
19 | } | |
20 | ||
21 | impl $arch_regclass { | |
fc512014 | 22 | pub fn name(self) -> rustc_span::Symbol { |
f9f354fc | 23 | match self { |
fc512014 | 24 | $(Self::$class => rustc_span::symbol::sym::$class,)* |
f9f354fc XL |
25 | } |
26 | } | |
27 | ||
fc512014 | 28 | pub fn parse(_arch: super::InlineAsmArch, name: rustc_span::Symbol) -> Result<Self, &'static str> { |
f9f354fc XL |
29 | match name { |
30 | $( | |
fc512014 | 31 | rustc_span::sym::$class => Ok(Self::$class), |
f9f354fc XL |
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 | ||
f9f354fc XL |
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)] | |
6a06907d | 63 | #[derive(Copy, Clone, Encodable, Decodable, Debug, Eq, PartialEq, PartialOrd, Hash, HashStable_Generic)] |
f9f354fc XL |
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, | |
f035d41b | 85 | _target: &crate::spec::Target, |
f9f354fc XL |
86 | name: &str, |
87 | ) -> Result<Self, &'static str> { | |
88 | match name { | |
89 | $( | |
90 | $($alias)|* | $reg_name => { | |
cdc7bbd5 | 91 | $($filter(_arch, &mut _has_feature, _target)?;)? |
f9f354fc XL |
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, | |
f035d41b | 106 | _target: &crate::spec::Target, |
f9f354fc XL |
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 | $( | |
cdc7bbd5 | 115 | if $($filter(_arch, &mut _has_feature, _target).is_ok() &&)? true { |
f9f354fc XL |
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 | ||
f9f354fc XL |
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; | |
17df50a5 | 151 | mod bpf; |
f035d41b | 152 | mod hexagon; |
1b1a35ee | 153 | mod mips; |
f9f354fc | 154 | mod nvptx; |
17df50a5 | 155 | mod powerpc; |
f9f354fc | 156 | mod riscv; |
29967ef6 | 157 | mod spirv; |
fc512014 | 158 | mod wasm; |
f9f354fc XL |
159 | mod x86; |
160 | ||
161 | pub use aarch64::{AArch64InlineAsmReg, AArch64InlineAsmRegClass}; | |
162 | pub use arm::{ArmInlineAsmReg, ArmInlineAsmRegClass}; | |
17df50a5 | 163 | pub use bpf::{BpfInlineAsmReg, BpfInlineAsmRegClass}; |
f035d41b | 164 | pub use hexagon::{HexagonInlineAsmReg, HexagonInlineAsmRegClass}; |
1b1a35ee | 165 | pub use mips::{MipsInlineAsmReg, MipsInlineAsmRegClass}; |
f9f354fc | 166 | pub use nvptx::{NvptxInlineAsmReg, NvptxInlineAsmRegClass}; |
17df50a5 | 167 | pub use powerpc::{PowerPCInlineAsmReg, PowerPCInlineAsmRegClass}; |
f9f354fc | 168 | pub use riscv::{RiscVInlineAsmReg, RiscVInlineAsmRegClass}; |
29967ef6 | 169 | pub use spirv::{SpirVInlineAsmReg, SpirVInlineAsmRegClass}; |
fc512014 | 170 | pub use wasm::{WasmInlineAsmReg, WasmInlineAsmRegClass}; |
f9f354fc XL |
171 | pub use x86::{X86InlineAsmReg, X86InlineAsmRegClass}; |
172 | ||
3dfed10e | 173 | #[derive(Copy, Clone, Encodable, Decodable, Debug, Eq, PartialEq, Hash)] |
f9f354fc XL |
174 | pub enum InlineAsmArch { |
175 | X86, | |
176 | X86_64, | |
177 | Arm, | |
178 | AArch64, | |
179 | RiscV32, | |
180 | RiscV64, | |
181 | Nvptx64, | |
f035d41b | 182 | Hexagon, |
1b1a35ee | 183 | Mips, |
29967ef6 | 184 | Mips64, |
17df50a5 XL |
185 | PowerPC, |
186 | PowerPC64, | |
29967ef6 | 187 | SpirV, |
fc512014 | 188 | Wasm32, |
17df50a5 | 189 | Bpf, |
f9f354fc XL |
190 | } |
191 | ||
192 | impl FromStr for InlineAsmArch { | |
193 | type Err = (); | |
194 | ||
195 | fn from_str(s: &str) -> Result<InlineAsmArch, ()> { | |
196 | match s { | |
197 | "x86" => Ok(Self::X86), | |
198 | "x86_64" => Ok(Self::X86_64), | |
199 | "arm" => Ok(Self::Arm), | |
200 | "aarch64" => Ok(Self::AArch64), | |
201 | "riscv32" => Ok(Self::RiscV32), | |
202 | "riscv64" => Ok(Self::RiscV64), | |
203 | "nvptx64" => Ok(Self::Nvptx64), | |
17df50a5 XL |
204 | "powerpc" => Ok(Self::PowerPC), |
205 | "powerpc64" => Ok(Self::PowerPC64), | |
f035d41b | 206 | "hexagon" => Ok(Self::Hexagon), |
1b1a35ee | 207 | "mips" => Ok(Self::Mips), |
29967ef6 XL |
208 | "mips64" => Ok(Self::Mips64), |
209 | "spirv" => Ok(Self::SpirV), | |
fc512014 | 210 | "wasm32" => Ok(Self::Wasm32), |
17df50a5 | 211 | "bpf" => Ok(Self::Bpf), |
f9f354fc XL |
212 | _ => Err(()), |
213 | } | |
214 | } | |
215 | } | |
216 | ||
6a06907d XL |
217 | #[derive( |
218 | Copy, | |
219 | Clone, | |
220 | Encodable, | |
221 | Decodable, | |
222 | Debug, | |
223 | Eq, | |
224 | PartialEq, | |
225 | PartialOrd, | |
226 | Hash, | |
227 | HashStable_Generic | |
228 | )] | |
f9f354fc XL |
229 | pub enum InlineAsmReg { |
230 | X86(X86InlineAsmReg), | |
231 | Arm(ArmInlineAsmReg), | |
232 | AArch64(AArch64InlineAsmReg), | |
233 | RiscV(RiscVInlineAsmReg), | |
234 | Nvptx(NvptxInlineAsmReg), | |
17df50a5 | 235 | PowerPC(PowerPCInlineAsmReg), |
f035d41b | 236 | Hexagon(HexagonInlineAsmReg), |
1b1a35ee | 237 | Mips(MipsInlineAsmReg), |
29967ef6 | 238 | SpirV(SpirVInlineAsmReg), |
fc512014 | 239 | Wasm(WasmInlineAsmReg), |
17df50a5 | 240 | Bpf(BpfInlineAsmReg), |
6a06907d XL |
241 | // Placeholder for invalid register constraints for the current target |
242 | Err, | |
f9f354fc XL |
243 | } |
244 | ||
245 | impl InlineAsmReg { | |
246 | pub fn name(self) -> &'static str { | |
247 | match self { | |
248 | Self::X86(r) => r.name(), | |
249 | Self::Arm(r) => r.name(), | |
250 | Self::AArch64(r) => r.name(), | |
251 | Self::RiscV(r) => r.name(), | |
17df50a5 | 252 | Self::PowerPC(r) => r.name(), |
f035d41b | 253 | Self::Hexagon(r) => r.name(), |
1b1a35ee | 254 | Self::Mips(r) => r.name(), |
17df50a5 | 255 | Self::Bpf(r) => r.name(), |
6a06907d | 256 | Self::Err => "<reg>", |
f9f354fc XL |
257 | } |
258 | } | |
259 | ||
260 | pub fn reg_class(self) -> InlineAsmRegClass { | |
261 | match self { | |
262 | Self::X86(r) => InlineAsmRegClass::X86(r.reg_class()), | |
263 | Self::Arm(r) => InlineAsmRegClass::Arm(r.reg_class()), | |
264 | Self::AArch64(r) => InlineAsmRegClass::AArch64(r.reg_class()), | |
265 | Self::RiscV(r) => InlineAsmRegClass::RiscV(r.reg_class()), | |
17df50a5 | 266 | Self::PowerPC(r) => InlineAsmRegClass::PowerPC(r.reg_class()), |
f035d41b | 267 | Self::Hexagon(r) => InlineAsmRegClass::Hexagon(r.reg_class()), |
1b1a35ee | 268 | Self::Mips(r) => InlineAsmRegClass::Mips(r.reg_class()), |
17df50a5 | 269 | Self::Bpf(r) => InlineAsmRegClass::Bpf(r.reg_class()), |
6a06907d | 270 | Self::Err => InlineAsmRegClass::Err, |
f9f354fc XL |
271 | } |
272 | } | |
273 | ||
274 | pub fn parse( | |
275 | arch: InlineAsmArch, | |
276 | has_feature: impl FnMut(&str) -> bool, | |
f035d41b | 277 | target: &Target, |
f9f354fc XL |
278 | name: Symbol, |
279 | ) -> Result<Self, &'static str> { | |
280 | // FIXME: use direct symbol comparison for register names | |
281 | // Use `Symbol::as_str` instead of `Symbol::with` here because `has_feature` may access `Symbol`. | |
282 | let name = name.as_str(); | |
283 | Ok(match arch { | |
284 | InlineAsmArch::X86 | InlineAsmArch::X86_64 => { | |
f035d41b XL |
285 | Self::X86(X86InlineAsmReg::parse(arch, has_feature, target, &name)?) |
286 | } | |
287 | InlineAsmArch::Arm => { | |
288 | Self::Arm(ArmInlineAsmReg::parse(arch, has_feature, target, &name)?) | |
f9f354fc | 289 | } |
f9f354fc | 290 | InlineAsmArch::AArch64 => { |
f035d41b | 291 | Self::AArch64(AArch64InlineAsmReg::parse(arch, has_feature, target, &name)?) |
f9f354fc XL |
292 | } |
293 | InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => { | |
f035d41b | 294 | Self::RiscV(RiscVInlineAsmReg::parse(arch, has_feature, target, &name)?) |
f9f354fc XL |
295 | } |
296 | InlineAsmArch::Nvptx64 => { | |
f035d41b XL |
297 | Self::Nvptx(NvptxInlineAsmReg::parse(arch, has_feature, target, &name)?) |
298 | } | |
17df50a5 XL |
299 | InlineAsmArch::PowerPC | InlineAsmArch::PowerPC64 => { |
300 | Self::PowerPC(PowerPCInlineAsmReg::parse(arch, has_feature, target, &name)?) | |
301 | } | |
f035d41b XL |
302 | InlineAsmArch::Hexagon => { |
303 | Self::Hexagon(HexagonInlineAsmReg::parse(arch, has_feature, target, &name)?) | |
f9f354fc | 304 | } |
29967ef6 | 305 | InlineAsmArch::Mips | InlineAsmArch::Mips64 => { |
1b1a35ee XL |
306 | Self::Mips(MipsInlineAsmReg::parse(arch, has_feature, target, &name)?) |
307 | } | |
29967ef6 XL |
308 | InlineAsmArch::SpirV => { |
309 | Self::SpirV(SpirVInlineAsmReg::parse(arch, has_feature, target, &name)?) | |
310 | } | |
fc512014 XL |
311 | InlineAsmArch::Wasm32 => { |
312 | Self::Wasm(WasmInlineAsmReg::parse(arch, has_feature, target, &name)?) | |
313 | } | |
17df50a5 XL |
314 | InlineAsmArch::Bpf => { |
315 | Self::Bpf(BpfInlineAsmReg::parse(arch, has_feature, target, &name)?) | |
316 | } | |
f9f354fc XL |
317 | }) |
318 | } | |
319 | ||
320 | // NOTE: This function isn't used at the moment, but is needed to support | |
321 | // falling back to an external assembler. | |
322 | pub fn emit( | |
323 | self, | |
324 | out: &mut dyn fmt::Write, | |
325 | arch: InlineAsmArch, | |
326 | modifier: Option<char>, | |
327 | ) -> fmt::Result { | |
328 | match self { | |
329 | Self::X86(r) => r.emit(out, arch, modifier), | |
330 | Self::Arm(r) => r.emit(out, arch, modifier), | |
331 | Self::AArch64(r) => r.emit(out, arch, modifier), | |
332 | Self::RiscV(r) => r.emit(out, arch, modifier), | |
17df50a5 | 333 | Self::PowerPC(r) => r.emit(out, arch, modifier), |
f035d41b | 334 | Self::Hexagon(r) => r.emit(out, arch, modifier), |
1b1a35ee | 335 | Self::Mips(r) => r.emit(out, arch, modifier), |
17df50a5 | 336 | Self::Bpf(r) => r.emit(out, arch, modifier), |
6a06907d | 337 | Self::Err => unreachable!("Use of InlineAsmReg::Err"), |
f9f354fc XL |
338 | } |
339 | } | |
340 | ||
341 | pub fn overlapping_regs(self, mut cb: impl FnMut(InlineAsmReg)) { | |
342 | match self { | |
343 | Self::X86(r) => r.overlapping_regs(|r| cb(Self::X86(r))), | |
344 | Self::Arm(r) => r.overlapping_regs(|r| cb(Self::Arm(r))), | |
345 | Self::AArch64(_) => cb(self), | |
346 | Self::RiscV(_) => cb(self), | |
17df50a5 | 347 | Self::PowerPC(_) => cb(self), |
f035d41b | 348 | Self::Hexagon(r) => r.overlapping_regs(|r| cb(Self::Hexagon(r))), |
1b1a35ee | 349 | Self::Mips(_) => cb(self), |
17df50a5 | 350 | Self::Bpf(r) => r.overlapping_regs(|r| cb(Self::Bpf(r))), |
6a06907d | 351 | Self::Err => unreachable!("Use of InlineAsmReg::Err"), |
f9f354fc XL |
352 | } |
353 | } | |
354 | } | |
355 | ||
6a06907d XL |
356 | #[derive( |
357 | Copy, | |
358 | Clone, | |
359 | Encodable, | |
360 | Decodable, | |
361 | Debug, | |
362 | Eq, | |
363 | PartialEq, | |
364 | PartialOrd, | |
365 | Hash, | |
366 | HashStable_Generic | |
367 | )] | |
f9f354fc XL |
368 | pub enum InlineAsmRegClass { |
369 | X86(X86InlineAsmRegClass), | |
370 | Arm(ArmInlineAsmRegClass), | |
371 | AArch64(AArch64InlineAsmRegClass), | |
372 | RiscV(RiscVInlineAsmRegClass), | |
373 | Nvptx(NvptxInlineAsmRegClass), | |
17df50a5 | 374 | PowerPC(PowerPCInlineAsmRegClass), |
f035d41b | 375 | Hexagon(HexagonInlineAsmRegClass), |
1b1a35ee | 376 | Mips(MipsInlineAsmRegClass), |
29967ef6 | 377 | SpirV(SpirVInlineAsmRegClass), |
fc512014 | 378 | Wasm(WasmInlineAsmRegClass), |
17df50a5 | 379 | Bpf(BpfInlineAsmRegClass), |
6a06907d XL |
380 | // Placeholder for invalid register constraints for the current target |
381 | Err, | |
f9f354fc XL |
382 | } |
383 | ||
384 | impl InlineAsmRegClass { | |
fc512014 | 385 | pub fn name(self) -> Symbol { |
f9f354fc XL |
386 | match self { |
387 | Self::X86(r) => r.name(), | |
388 | Self::Arm(r) => r.name(), | |
389 | Self::AArch64(r) => r.name(), | |
390 | Self::RiscV(r) => r.name(), | |
391 | Self::Nvptx(r) => r.name(), | |
17df50a5 | 392 | Self::PowerPC(r) => r.name(), |
f035d41b | 393 | Self::Hexagon(r) => r.name(), |
1b1a35ee | 394 | Self::Mips(r) => r.name(), |
29967ef6 | 395 | Self::SpirV(r) => r.name(), |
fc512014 | 396 | Self::Wasm(r) => r.name(), |
17df50a5 | 397 | Self::Bpf(r) => r.name(), |
6a06907d | 398 | Self::Err => rustc_span::symbol::sym::reg, |
f9f354fc XL |
399 | } |
400 | } | |
401 | ||
402 | /// Returns a suggested register class to use for this type. This is called | |
403 | /// after type checking via `supported_types` fails to give a better error | |
404 | /// message to the user. | |
405 | pub fn suggest_class(self, arch: InlineAsmArch, ty: InlineAsmType) -> Option<Self> { | |
406 | match self { | |
407 | Self::X86(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::X86), | |
408 | Self::Arm(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Arm), | |
409 | Self::AArch64(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::AArch64), | |
410 | Self::RiscV(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::RiscV), | |
411 | Self::Nvptx(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Nvptx), | |
17df50a5 | 412 | Self::PowerPC(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::PowerPC), |
f035d41b | 413 | Self::Hexagon(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Hexagon), |
1b1a35ee | 414 | Self::Mips(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Mips), |
29967ef6 | 415 | Self::SpirV(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::SpirV), |
fc512014 | 416 | Self::Wasm(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Wasm), |
17df50a5 | 417 | Self::Bpf(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Bpf), |
6a06907d | 418 | Self::Err => unreachable!("Use of InlineAsmRegClass::Err"), |
f9f354fc XL |
419 | } |
420 | } | |
421 | ||
422 | /// Returns a suggested template modifier to use for this type and an | |
423 | /// example of a register named formatted with it. | |
424 | /// | |
425 | /// Such suggestions are useful if a type smaller than the full register | |
426 | /// size is used and a modifier can be used to point to the subregister of | |
427 | /// the correct size. | |
428 | pub fn suggest_modifier( | |
429 | self, | |
430 | arch: InlineAsmArch, | |
431 | ty: InlineAsmType, | |
432 | ) -> Option<(char, &'static str)> { | |
433 | match self { | |
434 | Self::X86(r) => r.suggest_modifier(arch, ty), | |
435 | Self::Arm(r) => r.suggest_modifier(arch, ty), | |
436 | Self::AArch64(r) => r.suggest_modifier(arch, ty), | |
437 | Self::RiscV(r) => r.suggest_modifier(arch, ty), | |
438 | Self::Nvptx(r) => r.suggest_modifier(arch, ty), | |
17df50a5 | 439 | Self::PowerPC(r) => r.suggest_modifier(arch, ty), |
f035d41b | 440 | Self::Hexagon(r) => r.suggest_modifier(arch, ty), |
1b1a35ee | 441 | Self::Mips(r) => r.suggest_modifier(arch, ty), |
29967ef6 | 442 | Self::SpirV(r) => r.suggest_modifier(arch, ty), |
fc512014 | 443 | Self::Wasm(r) => r.suggest_modifier(arch, ty), |
17df50a5 | 444 | Self::Bpf(r) => r.suggest_modifier(arch, ty), |
6a06907d | 445 | Self::Err => unreachable!("Use of InlineAsmRegClass::Err"), |
f9f354fc XL |
446 | } |
447 | } | |
448 | ||
449 | /// Returns the default modifier for this register and an example of a | |
450 | /// register named formatted with it. | |
451 | /// | |
452 | /// This is only needed when the register class can suggest a modifier, so | |
453 | /// that the user can be shown how to get the default behavior without a | |
454 | /// warning. | |
455 | pub fn default_modifier(self, arch: InlineAsmArch) -> Option<(char, &'static str)> { | |
456 | match self { | |
457 | Self::X86(r) => r.default_modifier(arch), | |
458 | Self::Arm(r) => r.default_modifier(arch), | |
459 | Self::AArch64(r) => r.default_modifier(arch), | |
460 | Self::RiscV(r) => r.default_modifier(arch), | |
461 | Self::Nvptx(r) => r.default_modifier(arch), | |
17df50a5 | 462 | Self::PowerPC(r) => r.default_modifier(arch), |
f035d41b | 463 | Self::Hexagon(r) => r.default_modifier(arch), |
1b1a35ee | 464 | Self::Mips(r) => r.default_modifier(arch), |
29967ef6 | 465 | Self::SpirV(r) => r.default_modifier(arch), |
fc512014 | 466 | Self::Wasm(r) => r.default_modifier(arch), |
17df50a5 | 467 | Self::Bpf(r) => r.default_modifier(arch), |
6a06907d | 468 | Self::Err => unreachable!("Use of InlineAsmRegClass::Err"), |
f9f354fc XL |
469 | } |
470 | } | |
471 | ||
472 | /// Returns a list of supported types for this register class, each with a | |
473 | /// options target feature required to use this type. | |
474 | pub fn supported_types( | |
475 | self, | |
476 | arch: InlineAsmArch, | |
477 | ) -> &'static [(InlineAsmType, Option<&'static str>)] { | |
478 | match self { | |
479 | Self::X86(r) => r.supported_types(arch), | |
480 | Self::Arm(r) => r.supported_types(arch), | |
481 | Self::AArch64(r) => r.supported_types(arch), | |
482 | Self::RiscV(r) => r.supported_types(arch), | |
483 | Self::Nvptx(r) => r.supported_types(arch), | |
17df50a5 | 484 | Self::PowerPC(r) => r.supported_types(arch), |
f035d41b | 485 | Self::Hexagon(r) => r.supported_types(arch), |
1b1a35ee | 486 | Self::Mips(r) => r.supported_types(arch), |
29967ef6 | 487 | Self::SpirV(r) => r.supported_types(arch), |
fc512014 | 488 | Self::Wasm(r) => r.supported_types(arch), |
17df50a5 | 489 | Self::Bpf(r) => r.supported_types(arch), |
6a06907d | 490 | Self::Err => unreachable!("Use of InlineAsmRegClass::Err"), |
f9f354fc XL |
491 | } |
492 | } | |
493 | ||
494 | pub fn parse(arch: InlineAsmArch, name: Symbol) -> Result<Self, &'static str> { | |
fc512014 XL |
495 | Ok(match arch { |
496 | InlineAsmArch::X86 | InlineAsmArch::X86_64 => { | |
497 | Self::X86(X86InlineAsmRegClass::parse(arch, name)?) | |
498 | } | |
499 | InlineAsmArch::Arm => Self::Arm(ArmInlineAsmRegClass::parse(arch, name)?), | |
500 | InlineAsmArch::AArch64 => Self::AArch64(AArch64InlineAsmRegClass::parse(arch, name)?), | |
501 | InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => { | |
502 | Self::RiscV(RiscVInlineAsmRegClass::parse(arch, name)?) | |
503 | } | |
504 | InlineAsmArch::Nvptx64 => Self::Nvptx(NvptxInlineAsmRegClass::parse(arch, name)?), | |
17df50a5 XL |
505 | InlineAsmArch::PowerPC | InlineAsmArch::PowerPC64 => { |
506 | Self::PowerPC(PowerPCInlineAsmRegClass::parse(arch, name)?) | |
507 | } | |
fc512014 XL |
508 | InlineAsmArch::Hexagon => Self::Hexagon(HexagonInlineAsmRegClass::parse(arch, name)?), |
509 | InlineAsmArch::Mips | InlineAsmArch::Mips64 => { | |
510 | Self::Mips(MipsInlineAsmRegClass::parse(arch, name)?) | |
511 | } | |
512 | InlineAsmArch::SpirV => Self::SpirV(SpirVInlineAsmRegClass::parse(arch, name)?), | |
513 | InlineAsmArch::Wasm32 => Self::Wasm(WasmInlineAsmRegClass::parse(arch, name)?), | |
17df50a5 | 514 | InlineAsmArch::Bpf => Self::Bpf(BpfInlineAsmRegClass::parse(arch, name)?), |
f9f354fc XL |
515 | }) |
516 | } | |
517 | ||
518 | /// Returns the list of template modifiers that can be used with this | |
519 | /// register class. | |
520 | pub fn valid_modifiers(self, arch: InlineAsmArch) -> &'static [char] { | |
521 | match self { | |
522 | Self::X86(r) => r.valid_modifiers(arch), | |
523 | Self::Arm(r) => r.valid_modifiers(arch), | |
524 | Self::AArch64(r) => r.valid_modifiers(arch), | |
525 | Self::RiscV(r) => r.valid_modifiers(arch), | |
526 | Self::Nvptx(r) => r.valid_modifiers(arch), | |
17df50a5 | 527 | Self::PowerPC(r) => r.valid_modifiers(arch), |
f035d41b | 528 | Self::Hexagon(r) => r.valid_modifiers(arch), |
1b1a35ee | 529 | Self::Mips(r) => r.valid_modifiers(arch), |
29967ef6 | 530 | Self::SpirV(r) => r.valid_modifiers(arch), |
fc512014 | 531 | Self::Wasm(r) => r.valid_modifiers(arch), |
17df50a5 | 532 | Self::Bpf(r) => r.valid_modifiers(arch), |
6a06907d | 533 | Self::Err => unreachable!("Use of InlineAsmRegClass::Err"), |
f9f354fc XL |
534 | } |
535 | } | |
136023e0 XL |
536 | |
537 | /// Returns whether registers in this class can only be used as clobbers | |
538 | /// and not as inputs/outputs. | |
539 | pub fn is_clobber_only(self, arch: InlineAsmArch) -> bool { | |
540 | self.supported_types(arch).is_empty() | |
541 | } | |
f9f354fc XL |
542 | } |
543 | ||
6a06907d XL |
544 | #[derive( |
545 | Copy, | |
546 | Clone, | |
547 | Encodable, | |
548 | Decodable, | |
549 | Debug, | |
550 | Eq, | |
551 | PartialEq, | |
552 | PartialOrd, | |
553 | Hash, | |
554 | HashStable_Generic | |
555 | )] | |
f9f354fc XL |
556 | pub enum InlineAsmRegOrRegClass { |
557 | Reg(InlineAsmReg), | |
558 | RegClass(InlineAsmRegClass), | |
559 | } | |
560 | ||
561 | impl InlineAsmRegOrRegClass { | |
562 | pub fn reg_class(self) -> InlineAsmRegClass { | |
563 | match self { | |
564 | Self::Reg(r) => r.reg_class(), | |
565 | Self::RegClass(r) => r, | |
566 | } | |
567 | } | |
568 | } | |
569 | ||
570 | impl fmt::Display for InlineAsmRegOrRegClass { | |
571 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
572 | match self { | |
573 | Self::Reg(r) => write!(f, "\"{}\"", r.name()), | |
fc512014 | 574 | Self::RegClass(r) => write!(f, "{}", r.name()), |
f9f354fc XL |
575 | } |
576 | } | |
577 | } | |
578 | ||
579 | /// Set of types which can be used with a particular register class. | |
580 | #[derive(Copy, Clone, Debug, Eq, PartialEq)] | |
581 | pub enum InlineAsmType { | |
582 | I8, | |
583 | I16, | |
584 | I32, | |
585 | I64, | |
586 | I128, | |
587 | F32, | |
588 | F64, | |
589 | VecI8(u64), | |
590 | VecI16(u64), | |
591 | VecI32(u64), | |
592 | VecI64(u64), | |
593 | VecI128(u64), | |
594 | VecF32(u64), | |
595 | VecF64(u64), | |
596 | } | |
597 | ||
598 | impl InlineAsmType { | |
599 | pub fn is_integer(self) -> bool { | |
29967ef6 | 600 | matches!(self, Self::I8 | Self::I16 | Self::I32 | Self::I64 | Self::I128) |
f9f354fc XL |
601 | } |
602 | ||
603 | pub fn size(self) -> Size { | |
604 | Size::from_bytes(match self { | |
605 | Self::I8 => 1, | |
606 | Self::I16 => 2, | |
607 | Self::I32 => 4, | |
608 | Self::I64 => 8, | |
609 | Self::I128 => 16, | |
610 | Self::F32 => 4, | |
611 | Self::F64 => 8, | |
612 | Self::VecI8(n) => n * 1, | |
613 | Self::VecI16(n) => n * 2, | |
614 | Self::VecI32(n) => n * 4, | |
615 | Self::VecI64(n) => n * 8, | |
616 | Self::VecI128(n) => n * 16, | |
617 | Self::VecF32(n) => n * 4, | |
618 | Self::VecF64(n) => n * 8, | |
619 | }) | |
620 | } | |
621 | } | |
622 | ||
623 | impl fmt::Display for InlineAsmType { | |
624 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
625 | match *self { | |
626 | Self::I8 => f.write_str("i8"), | |
627 | Self::I16 => f.write_str("i16"), | |
628 | Self::I32 => f.write_str("i32"), | |
629 | Self::I64 => f.write_str("i64"), | |
630 | Self::I128 => f.write_str("i128"), | |
631 | Self::F32 => f.write_str("f32"), | |
632 | Self::F64 => f.write_str("f64"), | |
633 | Self::VecI8(n) => write!(f, "i8x{}", n), | |
634 | Self::VecI16(n) => write!(f, "i16x{}", n), | |
635 | Self::VecI32(n) => write!(f, "i32x{}", n), | |
636 | Self::VecI64(n) => write!(f, "i64x{}", n), | |
637 | Self::VecI128(n) => write!(f, "i128x{}", n), | |
638 | Self::VecF32(n) => write!(f, "f32x{}", n), | |
639 | Self::VecF64(n) => write!(f, "f64x{}", n), | |
640 | } | |
641 | } | |
642 | } | |
643 | ||
644 | /// Returns the full set of allocatable registers for a given architecture. | |
645 | /// | |
646 | /// The registers are structured as a map containing the set of allocatable | |
647 | /// registers in each register class. A particular register may be allocatable | |
648 | /// from multiple register classes, in which case it will appear multiple times | |
649 | /// in the map. | |
650 | // NOTE: This function isn't used at the moment, but is needed to support | |
651 | // falling back to an external assembler. | |
652 | pub fn allocatable_registers( | |
653 | arch: InlineAsmArch, | |
654 | has_feature: impl FnMut(&str) -> bool, | |
f035d41b | 655 | target: &crate::spec::Target, |
f9f354fc XL |
656 | ) -> FxHashMap<InlineAsmRegClass, FxHashSet<InlineAsmReg>> { |
657 | match arch { | |
658 | InlineAsmArch::X86 | InlineAsmArch::X86_64 => { | |
659 | let mut map = x86::regclass_map(); | |
f035d41b | 660 | x86::fill_reg_map(arch, has_feature, target, &mut map); |
f9f354fc XL |
661 | map |
662 | } | |
663 | InlineAsmArch::Arm => { | |
664 | let mut map = arm::regclass_map(); | |
f035d41b | 665 | arm::fill_reg_map(arch, has_feature, target, &mut map); |
f9f354fc XL |
666 | map |
667 | } | |
668 | InlineAsmArch::AArch64 => { | |
669 | let mut map = aarch64::regclass_map(); | |
f035d41b | 670 | aarch64::fill_reg_map(arch, has_feature, target, &mut map); |
f9f354fc XL |
671 | map |
672 | } | |
673 | InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => { | |
674 | let mut map = riscv::regclass_map(); | |
f035d41b | 675 | riscv::fill_reg_map(arch, has_feature, target, &mut map); |
f9f354fc XL |
676 | map |
677 | } | |
678 | InlineAsmArch::Nvptx64 => { | |
679 | let mut map = nvptx::regclass_map(); | |
f035d41b XL |
680 | nvptx::fill_reg_map(arch, has_feature, target, &mut map); |
681 | map | |
682 | } | |
17df50a5 XL |
683 | InlineAsmArch::PowerPC | InlineAsmArch::PowerPC64 => { |
684 | let mut map = powerpc::regclass_map(); | |
685 | powerpc::fill_reg_map(arch, has_feature, target, &mut map); | |
686 | map | |
687 | } | |
f035d41b XL |
688 | InlineAsmArch::Hexagon => { |
689 | let mut map = hexagon::regclass_map(); | |
690 | hexagon::fill_reg_map(arch, has_feature, target, &mut map); | |
f9f354fc XL |
691 | map |
692 | } | |
29967ef6 | 693 | InlineAsmArch::Mips | InlineAsmArch::Mips64 => { |
1b1a35ee XL |
694 | let mut map = mips::regclass_map(); |
695 | mips::fill_reg_map(arch, has_feature, target, &mut map); | |
696 | map | |
697 | } | |
29967ef6 XL |
698 | InlineAsmArch::SpirV => { |
699 | let mut map = spirv::regclass_map(); | |
700 | spirv::fill_reg_map(arch, has_feature, target, &mut map); | |
701 | map | |
702 | } | |
fc512014 XL |
703 | InlineAsmArch::Wasm32 => { |
704 | let mut map = wasm::regclass_map(); | |
705 | wasm::fill_reg_map(arch, has_feature, target, &mut map); | |
706 | map | |
707 | } | |
17df50a5 XL |
708 | InlineAsmArch::Bpf => { |
709 | let mut map = bpf::regclass_map(); | |
710 | bpf::fill_reg_map(arch, has_feature, target, &mut map); | |
711 | map | |
712 | } | |
f9f354fc XL |
713 | } |
714 | } |