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