]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_target/src/asm/arm.rs
Rollup merge of #98301 - ortem:pretty-printers-nonzero, r=wesleywiser
[rust.git] / compiler / rustc_target / src / asm / arm.rs
1 use super::{InlineAsmArch, InlineAsmType};
2 use crate::spec::{RelocModel, Target};
3 use rustc_data_structures::fx::FxHashSet;
4 use rustc_macros::HashStable_Generic;
5 use rustc_span::{sym, Symbol};
6 use std::fmt;
7
8 def_reg_class! {
9     Arm ArmInlineAsmRegClass {
10         reg,
11         sreg,
12         sreg_low16,
13         dreg,
14         dreg_low16,
15         dreg_low8,
16         qreg,
17         qreg_low8,
18         qreg_low4,
19     }
20 }
21
22 impl ArmInlineAsmRegClass {
23     pub fn valid_modifiers(self, _arch: super::InlineAsmArch) -> &'static [char] {
24         match self {
25             Self::qreg | Self::qreg_low8 | Self::qreg_low4 => &['e', 'f'],
26             _ => &[],
27         }
28     }
29
30     pub fn suggest_class(self, _arch: InlineAsmArch, _ty: InlineAsmType) -> Option<Self> {
31         None
32     }
33
34     pub fn suggest_modifier(
35         self,
36         _arch: InlineAsmArch,
37         _ty: InlineAsmType,
38     ) -> Option<(char, &'static str)> {
39         None
40     }
41
42     pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> {
43         None
44     }
45
46     pub fn supported_types(
47         self,
48         _arch: InlineAsmArch,
49     ) -> &'static [(InlineAsmType, Option<Symbol>)] {
50         match self {
51             Self::reg => types! { _: I8, I16, I32, F32; },
52             Self::sreg | Self::sreg_low16 => types! { vfp2: I32, F32; },
53             Self::dreg_low16 | Self::dreg_low8 => types! {
54                 vfp2: I64, F64, VecI8(8), VecI16(4), VecI32(2), VecI64(1), VecF32(2);
55             },
56             Self::dreg => types! {
57                 d32: I64, F64, VecI8(8), VecI16(4), VecI32(2), VecI64(1), VecF32(2);
58             },
59             Self::qreg | Self::qreg_low8 | Self::qreg_low4 => types! {
60                 neon: VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF32(4);
61             },
62         }
63     }
64 }
65
66 // This uses the same logic as useR7AsFramePointer in LLVM
67 fn frame_pointer_is_r7(target_features: &FxHashSet<Symbol>, target: &Target) -> bool {
68     target.is_like_osx || (!target.is_like_windows && target_features.contains(&sym::thumb_mode))
69 }
70
71 fn frame_pointer_r11(
72     arch: InlineAsmArch,
73     reloc_model: RelocModel,
74     target_features: &FxHashSet<Symbol>,
75     target: &Target,
76     is_clobber: bool,
77 ) -> Result<(), &'static str> {
78     not_thumb1(arch, reloc_model, target_features, target, is_clobber)?;
79
80     if !frame_pointer_is_r7(target_features, target) {
81         Err("the frame pointer (r11) cannot be used as an operand for inline asm")
82     } else {
83         Ok(())
84     }
85 }
86
87 fn frame_pointer_r7(
88     _arch: InlineAsmArch,
89     _reloc_model: RelocModel,
90     target_features: &FxHashSet<Symbol>,
91     target: &Target,
92     _is_clobber: bool,
93 ) -> Result<(), &'static str> {
94     if frame_pointer_is_r7(target_features, target) {
95         Err("the frame pointer (r7) cannot be used as an operand for inline asm")
96     } else {
97         Ok(())
98     }
99 }
100
101 fn not_thumb1(
102     _arch: InlineAsmArch,
103     _reloc_model: RelocModel,
104     target_features: &FxHashSet<Symbol>,
105     _target: &Target,
106     is_clobber: bool,
107 ) -> Result<(), &'static str> {
108     if !is_clobber
109         && target_features.contains(&sym::thumb_mode)
110         && !target_features.contains(&sym::thumb2)
111     {
112         Err("high registers (r8+) can only be used as clobbers in Thumb-1 code")
113     } else {
114         Ok(())
115     }
116 }
117
118 fn reserved_r9(
119     arch: InlineAsmArch,
120     reloc_model: RelocModel,
121     target_features: &FxHashSet<Symbol>,
122     target: &Target,
123     is_clobber: bool,
124 ) -> Result<(), &'static str> {
125     not_thumb1(arch, reloc_model, target_features, target, is_clobber)?;
126
127     match reloc_model {
128         RelocModel::Rwpi | RelocModel::RopiRwpi => {
129             Err("the RWPI static base register (r9) cannot be used as an operand for inline asm")
130         }
131         _ => Ok(()),
132     }
133 }
134
135 def_regs! {
136     Arm ArmInlineAsmReg ArmInlineAsmRegClass {
137         r0: reg = ["r0", "a1"],
138         r1: reg = ["r1", "a2"],
139         r2: reg = ["r2", "a3"],
140         r3: reg = ["r3", "a4"],
141         r4: reg = ["r4", "v1"],
142         r5: reg = ["r5", "v2"],
143         r7: reg = ["r7", "v4"] % frame_pointer_r7,
144         r8: reg = ["r8", "v5"] % not_thumb1,
145         r9: reg = ["r9", "v6", "rfp"] % reserved_r9,
146         r10: reg = ["r10", "sl"] % not_thumb1,
147         r11: reg = ["r11", "fp"] % frame_pointer_r11,
148         r12: reg = ["r12", "ip"] % not_thumb1,
149         r14: reg = ["r14", "lr"] % not_thumb1,
150         s0: sreg, sreg_low16 = ["s0"],
151         s1: sreg, sreg_low16 = ["s1"],
152         s2: sreg, sreg_low16 = ["s2"],
153         s3: sreg, sreg_low16 = ["s3"],
154         s4: sreg, sreg_low16 = ["s4"],
155         s5: sreg, sreg_low16 = ["s5"],
156         s6: sreg, sreg_low16 = ["s6"],
157         s7: sreg, sreg_low16 = ["s7"],
158         s8: sreg, sreg_low16 = ["s8"],
159         s9: sreg, sreg_low16 = ["s9"],
160         s10: sreg, sreg_low16 = ["s10"],
161         s11: sreg, sreg_low16 = ["s11"],
162         s12: sreg, sreg_low16 = ["s12"],
163         s13: sreg, sreg_low16 = ["s13"],
164         s14: sreg, sreg_low16 = ["s14"],
165         s15: sreg, sreg_low16 = ["s15"],
166         s16: sreg = ["s16"],
167         s17: sreg = ["s17"],
168         s18: sreg = ["s18"],
169         s19: sreg = ["s19"],
170         s20: sreg = ["s20"],
171         s21: sreg = ["s21"],
172         s22: sreg = ["s22"],
173         s23: sreg = ["s23"],
174         s24: sreg = ["s24"],
175         s25: sreg = ["s25"],
176         s26: sreg = ["s26"],
177         s27: sreg = ["s27"],
178         s28: sreg = ["s28"],
179         s29: sreg = ["s29"],
180         s30: sreg = ["s30"],
181         s31: sreg = ["s31"],
182         d0: dreg, dreg_low16, dreg_low8 = ["d0"],
183         d1: dreg, dreg_low16, dreg_low8 = ["d1"],
184         d2: dreg, dreg_low16, dreg_low8 = ["d2"],
185         d3: dreg, dreg_low16, dreg_low8 = ["d3"],
186         d4: dreg, dreg_low16, dreg_low8 = ["d4"],
187         d5: dreg, dreg_low16, dreg_low8 = ["d5"],
188         d6: dreg, dreg_low16, dreg_low8 = ["d6"],
189         d7: dreg, dreg_low16, dreg_low8 = ["d7"],
190         d8: dreg, dreg_low16 = ["d8"],
191         d9: dreg, dreg_low16 = ["d9"],
192         d10: dreg, dreg_low16 = ["d10"],
193         d11: dreg, dreg_low16 = ["d11"],
194         d12: dreg, dreg_low16 = ["d12"],
195         d13: dreg, dreg_low16 = ["d13"],
196         d14: dreg, dreg_low16 = ["d14"],
197         d15: dreg, dreg_low16 = ["d15"],
198         d16: dreg = ["d16"],
199         d17: dreg = ["d17"],
200         d18: dreg = ["d18"],
201         d19: dreg = ["d19"],
202         d20: dreg = ["d20"],
203         d21: dreg = ["d21"],
204         d22: dreg = ["d22"],
205         d23: dreg = ["d23"],
206         d24: dreg = ["d24"],
207         d25: dreg = ["d25"],
208         d26: dreg = ["d26"],
209         d27: dreg = ["d27"],
210         d28: dreg = ["d28"],
211         d29: dreg = ["d29"],
212         d30: dreg = ["d30"],
213         d31: dreg = ["d31"],
214         q0: qreg, qreg_low8, qreg_low4 = ["q0"],
215         q1: qreg, qreg_low8, qreg_low4 = ["q1"],
216         q2: qreg, qreg_low8, qreg_low4 = ["q2"],
217         q3: qreg, qreg_low8, qreg_low4 = ["q3"],
218         q4: qreg, qreg_low8 = ["q4"],
219         q5: qreg, qreg_low8 = ["q5"],
220         q6: qreg, qreg_low8 = ["q6"],
221         q7: qreg, qreg_low8 = ["q7"],
222         q8: qreg = ["q8"],
223         q9: qreg = ["q9"],
224         q10: qreg = ["q10"],
225         q11: qreg = ["q11"],
226         q12: qreg = ["q12"],
227         q13: qreg = ["q13"],
228         q14: qreg = ["q14"],
229         q15: qreg = ["q15"],
230         #error = ["r6", "v3"] =>
231             "r6 is used internally by LLVM and cannot be used as an operand for inline asm",
232         #error = ["r13", "sp"] =>
233             "the stack pointer cannot be used as an operand for inline asm",
234         #error = ["r15", "pc"] =>
235             "the program pointer cannot be used as an operand for inline asm",
236     }
237 }
238
239 impl ArmInlineAsmReg {
240     pub fn emit(
241         self,
242         out: &mut dyn fmt::Write,
243         _arch: InlineAsmArch,
244         modifier: Option<char>,
245     ) -> fmt::Result {
246         // Only qreg is allowed to have modifiers. This should have been
247         // validated already by now.
248         if let Some(modifier) = modifier {
249             let index = self as u32 - Self::q0 as u32;
250             assert!(index < 16);
251             let index = index * 2 + (modifier == 'f') as u32;
252             write!(out, "d{}", index)
253         } else {
254             out.write_str(self.name())
255         }
256     }
257
258     pub fn overlapping_regs(self, mut cb: impl FnMut(ArmInlineAsmReg)) {
259         cb(self);
260
261         macro_rules! reg_conflicts {
262             (
263                 $(
264                     $q:ident : $d0:ident $d1:ident : $s0:ident $s1:ident $s2:ident $s3:ident
265                 ),*;
266                 $(
267                     $q_high:ident : $d0_high:ident $d1_high:ident
268                 ),*;
269             ) => {
270                 match self {
271                     $(
272                         Self::$q => {
273                             cb(Self::$d0);
274                             cb(Self::$d1);
275                             cb(Self::$s0);
276                             cb(Self::$s1);
277                             cb(Self::$s2);
278                             cb(Self::$s3);
279                         }
280                         Self::$d0 => {
281                             cb(Self::$q);
282                             cb(Self::$s0);
283                             cb(Self::$s1);
284                         }
285                         Self::$d1 => {
286                             cb(Self::$q);
287                             cb(Self::$s2);
288                             cb(Self::$s3);
289                         }
290                         Self::$s0 | Self::$s1 => {
291                             cb(Self::$q);
292                             cb(Self::$d0);
293                         }
294                         Self::$s2 | Self::$s3 => {
295                             cb(Self::$q);
296                             cb(Self::$d1);
297                         }
298                     )*
299                     $(
300                         Self::$q_high => {
301                             cb(Self::$d0_high);
302                             cb(Self::$d1_high);
303                         }
304                         Self::$d0_high | Self::$d1_high => {
305                             cb(Self::$q_high);
306                         }
307                     )*
308                     _ => {},
309                 }
310             };
311         }
312
313         // ARM's floating-point register file is interesting in that it can be
314         // viewed as 16 128-bit registers, 32 64-bit registers or 32 32-bit
315         // registers. Because these views overlap, the registers of different
316         // widths will conflict (e.g. d0 overlaps with s0 and s1, and q1
317         // overlaps with d2 and d3).
318         //
319         // See section E1.3.1 of the ARM Architecture Reference Manual for
320         // ARMv8-A for more details.
321         reg_conflicts! {
322             q0 : d0 d1 : s0 s1 s2 s3,
323             q1 : d2 d3 : s4 s5 s6 s7,
324             q2 : d4 d5 : s8 s9 s10 s11,
325             q3 : d6 d7 : s12 s13 s14 s15,
326             q4 : d8 d9 : s16 s17 s18 s19,
327             q5 : d10 d11 : s20 s21 s22 s23,
328             q6 : d12 d13 : s24 s25 s26 s27,
329             q7 : d14 d15 : s28 s29 s30 s31;
330             q8 : d16 d17,
331             q9 : d18 d19,
332             q10 : d20 d21,
333             q11 : d22 d23,
334             q12 : d24 d25,
335             q13 : d26 d27,
336             q14 : d28 d29,
337             q15 : d30 d31;
338         }
339     }
340 }