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::{RelocModel, Target};
8
9def_reg_class! {
10    PowerPC PowerPCInlineAsmRegClass {
11        reg,
12        reg_nonzero,
13        freg,
14        vreg,
15        cr,
16        ctr,
17        lr,
18        xer,
19    }
20}
21
22impl PowerPCInlineAsmRegClass {
23    pub fn valid_modifiers(self, _arch: super::InlineAsmArch) -> &'static [char] {
24        &[]
25    }
26
27    pub fn suggest_class(self, _arch: InlineAsmArch, _ty: InlineAsmType) -> Option<Self> {
28        None
29    }
30
31    pub fn suggest_modifier(
32        self,
33        _arch: InlineAsmArch,
34        _ty: InlineAsmType,
35    ) -> Option<ModifierInfo> {
36        None
37    }
38
39    pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<ModifierInfo> {
40        None
41    }
42
43    pub fn supported_types(
44        self,
45        arch: InlineAsmArch,
46    ) -> &'static [(InlineAsmType, Option<Symbol>)] {
47        match self {
48            Self::reg | Self::reg_nonzero => {
49                if arch == InlineAsmArch::PowerPC {
50                    types! { _: I8, I16, I32; }
51                } else {
52                    types! { _: I8, I16, I32, I64; }
53                }
54            }
55            Self::freg => types! { _: F32, F64; },
56            // FIXME: vsx also supports integers?: https://github.com/rust-lang/rust/pull/131551#discussion_r1862535963
57            Self::vreg => types! {
58                altivec: VecI8(16), VecI16(8), VecI32(4), VecF32(4);
59                vsx: F32, F64, VecI64(2), VecF64(2);
60            },
61            Self::cr | Self::ctr | Self::lr | Self::xer => &[],
62        }
63    }
64}
65
66fn reserved_r13(
67    arch: InlineAsmArch,
68    _reloc_model: RelocModel,
69    _target_features: &FxIndexSet<Symbol>,
70    target: &Target,
71    _is_clobber: bool,
72) -> Result<(), &'static str> {
73    if target.is_like_aix && arch == InlineAsmArch::PowerPC {
74        Ok(())
75    } else {
76        Err("r13 is a reserved register on this target")
77    }
78}
79
80fn reserved_v20to31(
81    _arch: InlineAsmArch,
82    _reloc_model: RelocModel,
83    _target_features: &FxIndexSet<Symbol>,
84    target: &Target,
85    _is_clobber: bool,
86) -> Result<(), &'static str> {
87    if target.is_like_aix {
88        match &*target.options.abi {
89            "vec-default" => Err("v20-v31 are reserved on vec-default ABI"),
90            "vec-extabi" => Ok(()),
91            _ => unreachable!("unrecognized AIX ABI"),
92        }
93    } else {
94        Ok(())
95    }
96}
97
98def_regs! {
99    PowerPC PowerPCInlineAsmReg PowerPCInlineAsmRegClass {
100        r0: reg = ["r0", "0"],
101        r3: reg, reg_nonzero = ["r3", "3"],
102        r4: reg, reg_nonzero = ["r4", "4"],
103        r5: reg, reg_nonzero = ["r5", "5"],
104        r6: reg, reg_nonzero = ["r6", "6"],
105        r7: reg, reg_nonzero = ["r7", "7"],
106        r8: reg, reg_nonzero = ["r8", "8"],
107        r9: reg, reg_nonzero = ["r9", "9"],
108        r10: reg, reg_nonzero = ["r10", "10"],
109        r11: reg, reg_nonzero = ["r11", "11"],
110        r12: reg, reg_nonzero = ["r12", "12"],
111        r13: reg, reg_nonzero = ["r13", "13"] % reserved_r13,
112        r14: reg, reg_nonzero = ["r14", "14"],
113        r15: reg, reg_nonzero = ["r15", "15"],
114        r16: reg, reg_nonzero = ["r16", "16"],
115        r17: reg, reg_nonzero = ["r17", "17"],
116        r18: reg, reg_nonzero = ["r18", "18"],
117        r19: reg, reg_nonzero = ["r19", "19"],
118        r20: reg, reg_nonzero = ["r20", "20"],
119        r21: reg, reg_nonzero = ["r21", "21"],
120        r22: reg, reg_nonzero = ["r22", "22"],
121        r23: reg, reg_nonzero = ["r23", "23"],
122        r24: reg, reg_nonzero = ["r24", "24"],
123        r25: reg, reg_nonzero = ["r25", "25"],
124        r26: reg, reg_nonzero = ["r26", "26"],
125        r27: reg, reg_nonzero = ["r27", "27"],
126        r28: reg, reg_nonzero = ["r28", "28"],
127        f0: freg = ["f0", "fr0"],
128        f1: freg = ["f1", "fr1"],
129        f2: freg = ["f2", "fr2"],
130        f3: freg = ["f3", "fr3"],
131        f4: freg = ["f4", "fr4"],
132        f5: freg = ["f5", "fr5"],
133        f6: freg = ["f6", "fr6"],
134        f7: freg = ["f7", "fr7"],
135        f8: freg = ["f8", "fr8"],
136        f9: freg = ["f9", "fr9"],
137        f10: freg = ["f10", "fr10"],
138        f11: freg = ["f11", "fr11"],
139        f12: freg = ["f12", "fr12"],
140        f13: freg = ["f13", "fr13"],
141        f14: freg = ["f14", "fr14"],
142        f15: freg = ["f15", "fr15"],
143        f16: freg = ["f16", "fr16"],
144        f17: freg = ["f17", "fr17"],
145        f18: freg = ["f18", "fr18"],
146        f19: freg = ["f19", "fr19"],
147        f20: freg = ["f20", "fr20"],
148        f21: freg = ["f21", "fr21"],
149        f22: freg = ["f22", "fr22"],
150        f23: freg = ["f23", "fr23"],
151        f24: freg = ["f24", "fr24"],
152        f25: freg = ["f25", "fr25"],
153        f26: freg = ["f26", "fr26"],
154        f27: freg = ["f27", "fr27"],
155        f28: freg = ["f28", "fr28"],
156        f29: freg = ["f29", "fr29"],
157        f30: freg = ["f30", "fr30"],
158        f31: freg = ["f31", "fr31"],
159        v0: vreg = ["v0"],
160        v1: vreg = ["v1"],
161        v2: vreg = ["v2"],
162        v3: vreg = ["v3"],
163        v4: vreg = ["v4"],
164        v5: vreg = ["v5"],
165        v6: vreg = ["v6"],
166        v7: vreg = ["v7"],
167        v8: vreg = ["v8"],
168        v9: vreg = ["v9"],
169        v10: vreg = ["v10"],
170        v11: vreg = ["v11"],
171        v12: vreg = ["v12"],
172        v13: vreg = ["v13"],
173        v14: vreg = ["v14"],
174        v15: vreg = ["v15"],
175        v16: vreg = ["v16"],
176        v17: vreg = ["v17"],
177        v18: vreg = ["v18"],
178        v19: vreg = ["v19"],
179        v20: vreg = ["v20"] % reserved_v20to31,
180        v21: vreg = ["v21"] % reserved_v20to31,
181        v22: vreg = ["v22"] % reserved_v20to31,
182        v23: vreg = ["v23"] % reserved_v20to31,
183        v24: vreg = ["v24"] % reserved_v20to31,
184        v25: vreg = ["v25"] % reserved_v20to31,
185        v26: vreg = ["v26"] % reserved_v20to31,
186        v27: vreg = ["v27"] % reserved_v20to31,
187        v28: vreg = ["v28"] % reserved_v20to31,
188        v29: vreg = ["v29"] % reserved_v20to31,
189        v30: vreg = ["v30"] % reserved_v20to31,
190        v31: vreg = ["v31"] % reserved_v20to31,
191        cr: cr = ["cr"],
192        cr0: cr = ["cr0"],
193        cr1: cr = ["cr1"],
194        cr2: cr = ["cr2"],
195        cr3: cr = ["cr3"],
196        cr4: cr = ["cr4"],
197        cr5: cr = ["cr5"],
198        cr6: cr = ["cr6"],
199        cr7: cr = ["cr7"],
200        ctr: ctr = ["ctr"],
201        lr: lr = ["lr"],
202        xer: xer = ["xer"],
203        #error = ["r1", "1", "sp"] =>
204            "the stack pointer cannot be used as an operand for inline asm",
205        #error = ["r2", "2"] =>
206            "r2 is a system reserved register and cannot be used as an operand for inline asm",
207        #error = ["r29", "29"] =>
208            "r29 is used internally by LLVM and cannot be used as an operand for inline asm",
209        #error = ["r30", "30"] =>
210            "r30 is used internally by LLVM and cannot be used as an operand for inline asm",
211        #error = ["r31", "31", "fp"] =>
212            "the frame pointer cannot be used as an operand for inline asm",
213        #error = ["vrsave"] =>
214            "the vrsave register cannot be used as an operand for inline asm",
215    }
216}
217
218impl PowerPCInlineAsmReg {
219    pub fn emit(
220        self,
221        out: &mut dyn fmt::Write,
222        _arch: InlineAsmArch,
223        _modifier: Option<char>,
224    ) -> fmt::Result {
225        macro_rules! do_emit {
226            (
227                $($(($reg:ident, $value:literal)),*;)*
228            ) => {
229                out.write_str(match self {
230                    $($(Self::$reg => $value,)*)*
231                })
232            };
233        }
234        // Strip off the leading prefix.
235        do_emit! {
236            (r0, "0"), (r3, "3"), (r4, "4"), (r5, "5"), (r6, "6"), (r7, "7");
237            (r8, "8"), (r9, "9"), (r10, "10"), (r11, "11"), (r12, "12"), (r13, "13"), (r14, "14"), (r15, "15");
238            (r16, "16"), (r17, "17"), (r18, "18"), (r19, "19"), (r20, "20"), (r21, "21"), (r22, "22"), (r23, "23");
239            (r24, "24"), (r25, "25"), (r26, "26"), (r27, "27"), (r28, "28");
240            (f0, "0"), (f1, "1"), (f2, "2"), (f3, "3"), (f4, "4"), (f5, "5"), (f6, "6"), (f7, "7");
241            (f8, "8"), (f9, "9"), (f10, "10"), (f11, "11"), (f12, "12"), (f13, "13"), (f14, "14"), (f15, "15");
242            (f16, "16"), (f17, "17"), (f18, "18"), (f19, "19"), (f20, "20"), (f21, "21"), (f22, "22"), (f23, "23");
243            (f24, "24"), (f25, "25"), (f26, "26"), (f27, "27"), (f28, "28"), (f29, "29"), (f30, "30"), (f31, "31");
244            (v0, "0"), (v1, "1"), (v2, "2"), (v3, "3"), (v4, "4"), (v5, "5"), (v6, "6"), (v7, "7");
245            (v8, "8"), (v9, "9"), (v10, "10"), (v11, "11"), (v12, "12"), (v13, "13"), (v14, "14"), (v15, "15");
246            (v16, "16"), (v17, "17"), (v18, "18"), (v19, "19"), (v20, "20"), (v21, "21"), (v22, "22"), (v23, "23");
247            (v24, "24"), (v25, "25"), (v26, "26"), (v27, "27"), (v28, "28"), (v29, "29"), (v30, "30"), (v31, "31");
248            (cr, "cr");
249            (cr0, "0"), (cr1, "1"), (cr2, "2"), (cr3, "3"), (cr4, "4"), (cr5, "5"), (cr6, "6"), (cr7, "7");
250            (ctr, "ctr");
251            (lr, "lr");
252            (xer, "xer");
253        }
254    }
255
256    pub fn overlapping_regs(self, mut cb: impl FnMut(PowerPCInlineAsmReg)) {
257        macro_rules! reg_conflicts {
258            (
259                $(
260                    $full:ident : $($field:ident)*
261                ),*;
262            ) => {
263                match self {
264                    $(
265                        Self::$full => {
266                            cb(Self::$full);
267                            $(cb(Self::$field);)*
268                        }
269                        $(Self::$field)|* => {
270                            cb(Self::$full);
271                            cb(self);
272                        }
273                    )*
274                    r => cb(r),
275                }
276            };
277        }
278        reg_conflicts! {
279            cr : cr0 cr1 cr2 cr3 cr4 cr5 cr6 cr7;
280        }
281        // f0-f31 (vsr0-vsr31) and v0-v31 (vsr32-vsr63) do not conflict.
282    }
283}