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