rustc_target/asm/
powerpc.rs

1use std::fmt;
2
3use rustc_data_structures::fx::FxIndexSet;
4use rustc_span::Symbol;
5
6use super::{InlineAsmArch, InlineAsmType, ModifierInfo};
7use crate::spec::{Abi, RelocModel, Target};
8
9def_reg_class! {
10    PowerPC PowerPCInlineAsmRegClass {
11        reg,
12        reg_nonzero,
13        freg,
14        vreg,
15        vsreg,
16        cr,
17        ctr,
18        lr,
19        xer,
20    }
21}
22
23impl PowerPCInlineAsmRegClass {
24    pub fn valid_modifiers(self, _arch: super::InlineAsmArch) -> &'static [char] {
25        &[]
26    }
27
28    pub fn suggest_class(self, _arch: InlineAsmArch, _ty: InlineAsmType) -> Option<Self> {
29        None
30    }
31
32    pub fn suggest_modifier(
33        self,
34        _arch: InlineAsmArch,
35        _ty: InlineAsmType,
36    ) -> Option<ModifierInfo> {
37        None
38    }
39
40    pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<ModifierInfo> {
41        None
42    }
43
44    pub fn supported_types(
45        self,
46        arch: InlineAsmArch,
47    ) -> &'static [(InlineAsmType, Option<Symbol>)] {
48        match self {
49            Self::reg | Self::reg_nonzero => {
50                if arch == InlineAsmArch::PowerPC {
51                    types! { _: I8, I16, I32; }
52                } else {
53                    types! { _: I8, I16, I32, I64; }
54                }
55            }
56            Self::freg => types! { _: F32, F64; },
57            // FIXME: vsx also supports integers?: https://github.com/rust-lang/rust/pull/131551#discussion_r1862535963
58            Self::vreg => types! {
59                altivec: VecI8(16), VecI16(8), VecI32(4), VecF32(4);
60                vsx: F32, F64, VecI64(2), VecF64(2);
61            },
62            // VSX is a superset of altivec.
63            Self::vsreg => types! {
64                vsx: F32, F64, VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF32(4), VecF64(2);
65            },
66            Self::cr | Self::ctr | Self::lr | Self::xer => &[],
67        }
68    }
69}
70
71fn reserved_r13(
72    arch: InlineAsmArch,
73    _reloc_model: RelocModel,
74    _target_features: &FxIndexSet<Symbol>,
75    target: &Target,
76    _is_clobber: bool,
77) -> Result<(), &'static str> {
78    if target.is_like_aix && arch == InlineAsmArch::PowerPC {
79        Ok(())
80    } else {
81        Err("r13 is a reserved register on this target")
82    }
83}
84
85fn reserved_r29(
86    arch: InlineAsmArch,
87    _reloc_model: RelocModel,
88    _target_features: &FxIndexSet<Symbol>,
89    _target: &Target,
90    _is_clobber: bool,
91) -> Result<(), &'static str> {
92    if arch != InlineAsmArch::PowerPC {
93        Ok(())
94    } else {
95        Err("r29 is used internally by LLVM and cannot be used as an operand for inline asm")
96    }
97}
98
99fn reserved_v20to31(
100    _arch: InlineAsmArch,
101    _reloc_model: RelocModel,
102    _target_features: &FxIndexSet<Symbol>,
103    target: &Target,
104    _is_clobber: bool,
105) -> Result<(), &'static str> {
106    if target.is_like_aix {
107        match &target.options.abi {
108            Abi::VecDefault => Err("v20-v31 (vs52-vs63) are reserved on vec-default ABI"),
109            Abi::VecExtAbi => Ok(()),
110            abi => unreachable!("unrecognized AIX ABI: {abi}"),
111        }
112    } else {
113        Ok(())
114    }
115}
116
117def_regs! {
118    PowerPC PowerPCInlineAsmReg PowerPCInlineAsmRegClass {
119        r0: reg = ["r0", "0"],
120        r3: reg, reg_nonzero = ["r3", "3"],
121        r4: reg, reg_nonzero = ["r4", "4"],
122        r5: reg, reg_nonzero = ["r5", "5"],
123        r6: reg, reg_nonzero = ["r6", "6"],
124        r7: reg, reg_nonzero = ["r7", "7"],
125        r8: reg, reg_nonzero = ["r8", "8"],
126        r9: reg, reg_nonzero = ["r9", "9"],
127        r10: reg, reg_nonzero = ["r10", "10"],
128        r11: reg, reg_nonzero = ["r11", "11"],
129        r12: reg, reg_nonzero = ["r12", "12"],
130        r13: reg, reg_nonzero = ["r13", "13"] % reserved_r13,
131        r14: reg, reg_nonzero = ["r14", "14"],
132        r15: reg, reg_nonzero = ["r15", "15"],
133        r16: reg, reg_nonzero = ["r16", "16"],
134        r17: reg, reg_nonzero = ["r17", "17"],
135        r18: reg, reg_nonzero = ["r18", "18"],
136        r19: reg, reg_nonzero = ["r19", "19"],
137        r20: reg, reg_nonzero = ["r20", "20"],
138        r21: reg, reg_nonzero = ["r21", "21"],
139        r22: reg, reg_nonzero = ["r22", "22"],
140        r23: reg, reg_nonzero = ["r23", "23"],
141        r24: reg, reg_nonzero = ["r24", "24"],
142        r25: reg, reg_nonzero = ["r25", "25"],
143        r26: reg, reg_nonzero = ["r26", "26"],
144        r27: reg, reg_nonzero = ["r27", "27"],
145        r28: reg, reg_nonzero = ["r28", "28"],
146        r29: reg, reg_nonzero = ["r29", "29"] % reserved_r29,
147        f0: freg = ["f0", "fr0"],
148        f1: freg = ["f1", "fr1"],
149        f2: freg = ["f2", "fr2"],
150        f3: freg = ["f3", "fr3"],
151        f4: freg = ["f4", "fr4"],
152        f5: freg = ["f5", "fr5"],
153        f6: freg = ["f6", "fr6"],
154        f7: freg = ["f7", "fr7"],
155        f8: freg = ["f8", "fr8"],
156        f9: freg = ["f9", "fr9"],
157        f10: freg = ["f10", "fr10"],
158        f11: freg = ["f11", "fr11"],
159        f12: freg = ["f12", "fr12"],
160        f13: freg = ["f13", "fr13"],
161        f14: freg = ["f14", "fr14"],
162        f15: freg = ["f15", "fr15"],
163        f16: freg = ["f16", "fr16"],
164        f17: freg = ["f17", "fr17"],
165        f18: freg = ["f18", "fr18"],
166        f19: freg = ["f19", "fr19"],
167        f20: freg = ["f20", "fr20"],
168        f21: freg = ["f21", "fr21"],
169        f22: freg = ["f22", "fr22"],
170        f23: freg = ["f23", "fr23"],
171        f24: freg = ["f24", "fr24"],
172        f25: freg = ["f25", "fr25"],
173        f26: freg = ["f26", "fr26"],
174        f27: freg = ["f27", "fr27"],
175        f28: freg = ["f28", "fr28"],
176        f29: freg = ["f29", "fr29"],
177        f30: freg = ["f30", "fr30"],
178        f31: freg = ["f31", "fr31"],
179        v0: vreg = ["v0"],
180        v1: vreg = ["v1"],
181        v2: vreg = ["v2"],
182        v3: vreg = ["v3"],
183        v4: vreg = ["v4"],
184        v5: vreg = ["v5"],
185        v6: vreg = ["v6"],
186        v7: vreg = ["v7"],
187        v8: vreg = ["v8"],
188        v9: vreg = ["v9"],
189        v10: vreg = ["v10"],
190        v11: vreg = ["v11"],
191        v12: vreg = ["v12"],
192        v13: vreg = ["v13"],
193        v14: vreg = ["v14"],
194        v15: vreg = ["v15"],
195        v16: vreg = ["v16"],
196        v17: vreg = ["v17"],
197        v18: vreg = ["v18"],
198        v19: vreg = ["v19"],
199        v20: vreg = ["v20"] % reserved_v20to31,
200        v21: vreg = ["v21"] % reserved_v20to31,
201        v22: vreg = ["v22"] % reserved_v20to31,
202        v23: vreg = ["v23"] % reserved_v20to31,
203        v24: vreg = ["v24"] % reserved_v20to31,
204        v25: vreg = ["v25"] % reserved_v20to31,
205        v26: vreg = ["v26"] % reserved_v20to31,
206        v27: vreg = ["v27"] % reserved_v20to31,
207        v28: vreg = ["v28"] % reserved_v20to31,
208        v29: vreg = ["v29"] % reserved_v20to31,
209        v30: vreg = ["v30"] % reserved_v20to31,
210        v31: vreg = ["v31"] % reserved_v20to31,
211        vs0: vsreg = ["vs0"],
212        vs1: vsreg = ["vs1"],
213        vs2: vsreg = ["vs2"],
214        vs3: vsreg = ["vs3"],
215        vs4: vsreg = ["vs4"],
216        vs5: vsreg = ["vs5"],
217        vs6: vsreg = ["vs6"],
218        vs7: vsreg = ["vs7"],
219        vs8: vsreg = ["vs8"],
220        vs9: vsreg = ["vs9"],
221        vs10: vsreg = ["vs10"],
222        vs11: vsreg = ["vs11"],
223        vs12: vsreg = ["vs12"],
224        vs13: vsreg = ["vs13"],
225        vs14: vsreg = ["vs14"],
226        vs15: vsreg = ["vs15"],
227        vs16: vsreg = ["vs16"],
228        vs17: vsreg = ["vs17"],
229        vs18: vsreg = ["vs18"],
230        vs19: vsreg = ["vs19"],
231        vs20: vsreg = ["vs20"],
232        vs21: vsreg = ["vs21"],
233        vs22: vsreg = ["vs22"],
234        vs23: vsreg = ["vs23"],
235        vs24: vsreg = ["vs24"],
236        vs25: vsreg = ["vs25"],
237        vs26: vsreg = ["vs26"],
238        vs27: vsreg = ["vs27"],
239        vs28: vsreg = ["vs28"],
240        vs29: vsreg = ["vs29"],
241        vs30: vsreg = ["vs30"],
242        vs31: vsreg = ["vs31"],
243        vs32: vsreg = ["vs32"],
244        vs33: vsreg = ["vs33"],
245        vs34: vsreg = ["vs34"],
246        vs35: vsreg = ["vs35"],
247        vs36: vsreg = ["vs36"],
248        vs37: vsreg = ["vs37"],
249        vs38: vsreg = ["vs38"],
250        vs39: vsreg = ["vs39"],
251        vs40: vsreg = ["vs40"],
252        vs41: vsreg = ["vs41"],
253        vs42: vsreg = ["vs42"],
254        vs43: vsreg = ["vs43"],
255        vs44: vsreg = ["vs44"],
256        vs45: vsreg = ["vs45"],
257        vs46: vsreg = ["vs46"],
258        vs47: vsreg = ["vs47"],
259        vs48: vsreg = ["vs48"],
260        vs49: vsreg = ["vs49"],
261        vs50: vsreg = ["vs50"],
262        vs51: vsreg = ["vs51"],
263        // vs52 - vs63 are aliases of v20-v31.
264        vs52: vsreg = ["vs52"] % reserved_v20to31,
265        vs53: vsreg = ["vs53"] % reserved_v20to31,
266        vs54: vsreg = ["vs54"] % reserved_v20to31,
267        vs55: vsreg = ["vs55"] % reserved_v20to31,
268        vs56: vsreg = ["vs56"] % reserved_v20to31,
269        vs57: vsreg = ["vs57"] % reserved_v20to31,
270        vs58: vsreg = ["vs58"] % reserved_v20to31,
271        vs59: vsreg = ["vs59"] % reserved_v20to31,
272        vs60: vsreg = ["vs60"] % reserved_v20to31,
273        vs61: vsreg = ["vs61"] % reserved_v20to31,
274        vs62: vsreg = ["vs62"] % reserved_v20to31,
275        vs63: vsreg = ["vs63"] % reserved_v20to31,
276        cr: cr = ["cr"],
277        cr0: cr = ["cr0"],
278        cr1: cr = ["cr1"],
279        cr2: cr = ["cr2"],
280        cr3: cr = ["cr3"],
281        cr4: cr = ["cr4"],
282        cr5: cr = ["cr5"],
283        cr6: cr = ["cr6"],
284        cr7: cr = ["cr7"],
285        ctr: ctr = ["ctr"],
286        lr: lr = ["lr"],
287        xer: xer = ["xer"],
288        #error = ["r1", "1", "sp"] =>
289            "the stack pointer cannot be used as an operand for inline asm",
290        #error = ["r2", "2"] =>
291            "r2 is a system reserved register and cannot be used as an operand for inline asm",
292        #error = ["r30", "30"] =>
293            "r30 is used internally by LLVM and cannot be used as an operand for inline asm",
294        #error = ["r31", "31", "fp"] =>
295            "the frame pointer cannot be used as an operand for inline asm",
296        #error = ["vrsave"] =>
297            "the vrsave register cannot be used as an operand for inline asm",
298    }
299}
300
301impl PowerPCInlineAsmReg {
302    pub fn emit(
303        self,
304        out: &mut dyn fmt::Write,
305        _arch: InlineAsmArch,
306        _modifier: Option<char>,
307    ) -> fmt::Result {
308        macro_rules! do_emit {
309            (
310                $($(($reg:ident, $value:literal)),*;)*
311            ) => {
312                out.write_str(match self {
313                    $($(Self::$reg => $value,)*)*
314                })
315            };
316        }
317        // Strip off the leading prefix.
318        do_emit! {
319            (r0, "0"), (r3, "3"), (r4, "4"), (r5, "5"), (r6, "6"), (r7, "7");
320            (r8, "8"), (r9, "9"), (r10, "10"), (r11, "11"), (r12, "12"), (r13, "13"), (r14, "14"), (r15, "15");
321            (r16, "16"), (r17, "17"), (r18, "18"), (r19, "19"), (r20, "20"), (r21, "21"), (r22, "22"), (r23, "23");
322            (r24, "24"), (r25, "25"), (r26, "26"), (r27, "27"), (r28, "28"), (r29, "29");
323            (f0, "0"), (f1, "1"), (f2, "2"), (f3, "3"), (f4, "4"), (f5, "5"), (f6, "6"), (f7, "7");
324            (f8, "8"), (f9, "9"), (f10, "10"), (f11, "11"), (f12, "12"), (f13, "13"), (f14, "14"), (f15, "15");
325            (f16, "16"), (f17, "17"), (f18, "18"), (f19, "19"), (f20, "20"), (f21, "21"), (f22, "22"), (f23, "23");
326            (f24, "24"), (f25, "25"), (f26, "26"), (f27, "27"), (f28, "28"), (f29, "29"), (f30, "30"), (f31, "31");
327            (v0, "0"), (v1, "1"), (v2, "2"), (v3, "3"), (v4, "4"), (v5, "5"), (v6, "6"), (v7, "7");
328            (v8, "8"), (v9, "9"), (v10, "10"), (v11, "11"), (v12, "12"), (v13, "13"), (v14, "14"), (v15, "15");
329            (v16, "16"), (v17, "17"), (v18, "18"), (v19, "19"), (v20, "20"), (v21, "21"), (v22, "22"), (v23, "23");
330            (v24, "24"), (v25, "25"), (v26, "26"), (v27, "27"), (v28, "28"), (v29, "29"), (v30, "30"), (v31, "31");
331            (vs0, "0"), (vs1, "1"), (vs2, "2"), (vs3, "3"), (vs4, "4"), (vs5, "5"), (vs6, "6"), (vs7, "7"),
332            (vs8, "8"), (vs9, "9"), (vs10, "10"), (vs11, "11"), (vs12, "12"), (vs13, "13"), (vs14, "14"),
333            (vs15, "15"), (vs16, "16"), (vs17, "17"), (vs18, "18"), (vs19, "19"), (vs20, "20"), (vs21, "21"),
334            (vs22, "22"), (vs23, "23"), (vs24, "24"), (vs25, "25"), (vs26, "26"), (vs27, "27"), (vs28, "28"),
335            (vs29, "29"), (vs30, "30"), (vs31, "31"), (vs32, "32"), (vs33, "33"), (vs34, "34"), (vs35, "35"),
336            (vs36, "36"), (vs37, "37"), (vs38, "38"), (vs39, "39"), (vs40, "40"), (vs41, "41"), (vs42, "42"),
337            (vs43, "43"), (vs44, "44"), (vs45, "45"), (vs46, "46"), (vs47, "47"), (vs48, "48"), (vs49, "49"),
338            (vs50, "50"), (vs51, "51"), (vs52, "52"), (vs53, "53"), (vs54, "54"), (vs55, "55"), (vs56, "56"),
339            (vs57, "57"), (vs58, "58"), (vs59, "59"), (vs60, "60"), (vs61, "61"), (vs62, "62"), (vs63, "63"),
340            (cr, "cr");
341            (cr0, "0"), (cr1, "1"), (cr2, "2"), (cr3, "3"), (cr4, "4"), (cr5, "5"), (cr6, "6"), (cr7, "7");
342            (ctr, "ctr");
343            (lr, "lr");
344            (xer, "xer");
345        }
346    }
347
348    pub fn overlapping_regs(self, mut cb: impl FnMut(PowerPCInlineAsmReg)) {
349        macro_rules! reg_conflicts {
350            (
351                $(
352                    $full:ident : $($field:ident)*
353                ),*;
354            ) => {
355                match self {
356                    $(
357                        Self::$full => {
358                            cb(Self::$full);
359                            $(cb(Self::$field);)*
360                        }
361                        $(Self::$field)|* => {
362                            cb(Self::$full);
363                            cb(self);
364                        }
365                    )*
366                    r => cb(r),
367                }
368            };
369        }
370        reg_conflicts! {
371            cr : cr0 cr1 cr2 cr3 cr4 cr5 cr6 cr7,
372            // f0-f31 overlap half of each of vs0-vs32.
373            vs0 : f0,
374            vs1 : f1,
375            vs2 : f2,
376            vs3 : f3,
377            vs4 : f4,
378            vs5 : f5,
379            vs6 : f6,
380            vs7 : f7,
381            vs8 : f8,
382            vs9 : f9,
383            vs10 : f10,
384            vs11 : f11,
385            vs12 : f12,
386            vs13 : f13,
387            vs14 : f14,
388            vs15 : f15,
389            vs16 : f16,
390            vs17 : f17,
391            vs18 : f18,
392            vs19 : f19,
393            vs20 : f20,
394            vs21 : f21,
395            vs22 : f22,
396            vs23 : f23,
397            vs24 : f24,
398            vs25 : f25,
399            vs26 : f26,
400            vs27 : f27,
401            vs28 : f28,
402            vs29 : f29,
403            vs30 : f30,
404            vs31 : f31,
405            // vs32-v63 are aliases of v0-v31
406            vs32 : v0,
407            vs33 : v1,
408            vs34 : v2,
409            vs35 : v3,
410            vs36 : v4,
411            vs37 : v5,
412            vs38 : v6,
413            vs39 : v7,
414            vs40 : v8,
415            vs41 : v9,
416            vs42 : v10,
417            vs43 : v11,
418            vs44 : v12,
419            vs45 : v13,
420            vs46 : v14,
421            vs47 : v15,
422            vs48 : v16,
423            vs49 : v17,
424            vs50 : v18,
425            vs51 : v19,
426            vs52 : v20,
427            vs53 : v21,
428            vs54 : v22,
429            vs55 : v23,
430            vs56 : v24,
431            vs57 : v25,
432            vs58 : v26,
433            vs59 : v27,
434            vs60 : v28,
435            vs61 : v29,
436            vs62 : v30,
437            vs63 : v31;
438        }
439        // For more detail on how vsx, vmx (altivec), fpr, and mma registers overlap
440        // see OpenPOWER ISA 3.1C, Book I, Section 7.2.1.1 through 7.2.1.3.
441        //
442        // https://files.openpower.foundation/s/9izgC5Rogi5Ywmm
443    }
444}