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