rustc_target/asm/
sparc.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    Sparc SparcInlineAsmRegClass {
11        reg,
12        yreg,
13    }
14}
15
16impl SparcInlineAsmRegClass {
17    pub fn valid_modifiers(self, _arch: super::InlineAsmArch) -> &'static [char] {
18        &[]
19    }
20
21    pub fn suggest_class(self, _arch: InlineAsmArch, _ty: InlineAsmType) -> Option<Self> {
22        None
23    }
24
25    pub fn suggest_modifier(
26        self,
27        _arch: InlineAsmArch,
28        _ty: InlineAsmType,
29    ) -> Option<ModifierInfo> {
30        None
31    }
32
33    pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<ModifierInfo> {
34        None
35    }
36
37    pub fn supported_types(
38        self,
39        arch: InlineAsmArch,
40    ) -> &'static [(InlineAsmType, Option<Symbol>)] {
41        match self {
42            Self::reg => {
43                if arch == InlineAsmArch::Sparc {
44                    types! {
45                        _: I8, I16, I32;
46                        // FIXME: i64 is ok for g*/o* registers on SPARC-V8+ ("h" constraint in GCC),
47                        //        but not yet supported in LLVM.
48                        // v8plus: I64;
49                    }
50                } else {
51                    types! { _: I8, I16, I32, I64; }
52                }
53            }
54            Self::yreg => &[],
55        }
56    }
57}
58
59fn reserved_g5(
60    arch: InlineAsmArch,
61    _reloc_model: RelocModel,
62    _target_features: &FxIndexSet<Symbol>,
63    _target: &Target,
64    _is_clobber: bool,
65) -> Result<(), &'static str> {
66    if arch == InlineAsmArch::Sparc {
67        // FIXME: Section 2.1.5 "Function Registers with Unassigned Roles" of the V8+ Technical
68        // Specification says "%g5; no longer reserved for system software" [1], but LLVM always
69        // reserves it on SPARC32 [2].
70        // [1]: https://temlib.org/pub/SparcStation/Standards/V8plus.pdf
71        // [2]: https://github.com/llvm/llvm-project/blob/llvmorg-19.1.0/llvm/lib/Target/Sparc/SparcRegisterInfo.cpp#L64-L66
72        Err("g5 is reserved for system on SPARC32")
73    } else {
74        Ok(())
75    }
76}
77
78def_regs! {
79    Sparc SparcInlineAsmReg SparcInlineAsmRegClass {
80        // FIXME:
81        // - LLVM has reserve-{g,o,l,i}N feature to reserve each general-purpose registers.
82        // - g2-g4 are reserved for application (optional in both LLVM and GCC, and GCC has -mno-app-regs option to reserve them).
83        // There are currently no builtin targets that use them, but in the future they may need to
84        // be supported via options similar to AArch64's -Z fixed-x18.
85        r2: reg = ["r2", "g2"], // % reserved_g2
86        r3: reg = ["r3", "g3"], // % reserved_g3
87        r4: reg = ["r4", "g4"], // % reserved_g4
88        r5: reg = ["r5", "g5"] % reserved_g5,
89        r8: reg = ["r8", "o0"], // % reserved_o0
90        r9: reg = ["r9", "o1"], // % reserved_o1
91        r10: reg = ["r10", "o2"], // % reserved_o2
92        r11: reg = ["r11", "o3"], // % reserved_o3
93        r12: reg = ["r12", "o4"], // % reserved_o4
94        r13: reg = ["r13", "o5"], // % reserved_o5
95        r15: reg = ["r15", "o7"], // % reserved_o7
96        r16: reg = ["r16", "l0"], // % reserved_l0
97        r17: reg = ["r17", "l1"], // % reserved_l1
98        r18: reg = ["r18", "l2"], // % reserved_l2
99        r19: reg = ["r19", "l3"], // % reserved_l3
100        r20: reg = ["r20", "l4"], // % reserved_l4
101        r21: reg = ["r21", "l5"], // % reserved_l5
102        r22: reg = ["r22", "l6"], // % reserved_l6
103        r23: reg = ["r23", "l7"], // % reserved_l7
104        r24: reg = ["r24", "i0"], // % reserved_i0
105        r25: reg = ["r25", "i1"], // % reserved_i1
106        r26: reg = ["r26", "i2"], // % reserved_i2
107        r27: reg = ["r27", "i3"], // % reserved_i3
108        r28: reg = ["r28", "i4"], // % reserved_i4
109        r29: reg = ["r29", "i5"], // % reserved_i5
110        y: yreg = ["y"],
111        #error = ["r0", "g0"] =>
112            "g0 is always zero and cannot be used as an operand for inline asm",
113        // FIXME: %g1 is volatile in ABI, but used internally by LLVM.
114        // https://github.com/llvm/llvm-project/blob/llvmorg-19.1.0/llvm/lib/Target/Sparc/SparcRegisterInfo.cpp#L55-L56
115        // > FIXME: G1 reserved for now for large imm generation by frame code.
116        #error = ["r1", "g1"] =>
117            "reserved by LLVM and cannot be used as an operand for inline asm",
118        #error = ["r6", "g6", "r7", "g7"] =>
119            "reserved for system and cannot be used as an operand for inline asm",
120        #error = ["sp", "r14", "o6"] =>
121            "the stack pointer cannot be used as an operand for inline asm",
122        #error = ["fp", "r30", "i6"] =>
123            "the frame pointer cannot be used as an operand for inline asm",
124        #error = ["r31", "i7"] =>
125            "the return address register cannot be used as an operand for inline asm",
126    }
127}
128
129impl SparcInlineAsmReg {
130    pub fn emit(
131        self,
132        out: &mut dyn fmt::Write,
133        _arch: InlineAsmArch,
134        _modifier: Option<char>,
135    ) -> fmt::Result {
136        write!(out, "%{}", self.name())
137    }
138}