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