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