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};
9 Arm ArmInlineAsmRegClass {
22 impl ArmInlineAsmRegClass {
23 pub fn valid_modifiers(self, _arch: super::InlineAsmArch) -> &'static [char] {
25 Self::qreg | Self::qreg_low8 | Self::qreg_low4 => &['e', 'f'],
30 pub fn suggest_class(self, _arch: InlineAsmArch, _ty: InlineAsmType) -> Option<Self> {
34 pub fn suggest_modifier(
38 ) -> Option<(char, &'static str)> {
42 pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> {
46 pub fn supported_types(
49 ) -> &'static [(InlineAsmType, Option<Symbol>)] {
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);
56 Self::qreg | Self::qreg_low8 | Self::qreg_low4 => types! {
57 neon: VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF32(4);
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))
70 reloc_model: RelocModel,
71 target_features: &FxHashSet<Symbol>,
74 ) -> Result<(), &'static str> {
75 not_thumb1(arch, reloc_model, target_features, target, is_clobber)?;
77 if !frame_pointer_is_r7(target_features, target) {
78 Err("the frame pointer (r11) cannot be used as an operand for inline asm")
86 _reloc_model: RelocModel,
87 target_features: &FxHashSet<Symbol>,
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")
100 _reloc_model: RelocModel,
101 target_features: &FxHashSet<Symbol>,
104 ) -> Result<(), &'static str> {
106 && target_features.contains(&sym::thumb_mode)
107 && !target_features.contains(&sym::thumb2)
109 Err("high registers (r8+) can only be used as clobbers in Thumb-1 code")
117 reloc_model: RelocModel,
118 target_features: &FxHashSet<Symbol>,
121 ) -> Result<(), &'static str> {
122 not_thumb1(arch, reloc_model, target_features, target, is_clobber)?;
125 RelocModel::Rwpi | RelocModel::RopiRwpi => {
126 Err("the RWPI static base register (r9) cannot be used as an operand for inline asm")
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"],
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"],
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"],
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",
236 impl ArmInlineAsmReg {
239 out: &mut dyn fmt::Write,
240 _arch: InlineAsmArch,
241 modifier: Option<char>,
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;
248 let index = index * 2 + (modifier == 'f') as u32;
249 write!(out, "d{}", index)
251 out.write_str(self.name())
255 pub fn overlapping_regs(self, mut cb: impl FnMut(ArmInlineAsmReg)) {
258 macro_rules! reg_conflicts {
261 $q:ident : $d0:ident $d1:ident : $s0:ident $s1:ident $s2:ident $s3:ident
264 $q_high:ident : $d0_high:ident $d1_high:ident
287 Self::$s0 | Self::$s1 => {
291 Self::$s2 | Self::$s3 => {
301 Self::$d0_high | Self::$d1_high => {
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).
316 // See section E1.3.1 of the ARM Architecture Reference Manual for
317 // ARMv8-A for more details.
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;