rustc_target/spec/
abi_map.rs

1use rustc_abi::{ArmCall, CanonAbi, ExternAbi, InterruptKind, X86Call};
2
3use crate::spec::{Arch, Target};
4
5/// Mapping for ExternAbi to CanonAbi according to a Target
6///
7/// A maybe-transitional structure circa 2025 for hosting future experiments in
8/// encapsulating arch-specific ABI lowering details to make them more testable.
9#[derive(Clone, Debug)]
10pub struct AbiMap {
11    arch: ArchKind,
12    os: OsKind,
13}
14
15/// result from trying to map an ABI
16#[derive(Copy, Clone, Debug)]
17pub enum AbiMapping {
18    /// this ABI is exactly mapped for this platform
19    Direct(CanonAbi),
20    /// we don't yet warn on this, but we will
21    Deprecated(CanonAbi),
22    /// ABI we do not map for this platform: it must not reach codegen
23    Invalid,
24}
25
26impl AbiMapping {
27    /// optionally get a [CanonAbi], even if Deprecated
28    pub fn into_option(self) -> Option<CanonAbi> {
29        match self {
30            Self::Direct(abi) | Self::Deprecated(abi) => Some(abi),
31            Self::Invalid => None,
32        }
33    }
34
35    /// get a [CanonAbi] even if Deprecated, panicking if Invalid
36    #[track_caller]
37    pub fn unwrap(self) -> CanonAbi {
38        self.into_option().unwrap()
39    }
40
41    pub fn is_mapped(self) -> bool {
42        self.into_option().is_some()
43    }
44}
45
46impl AbiMap {
47    /// create an AbiMap according to arbitrary fields on the [Target]
48    pub fn from_target(target: &Target) -> Self {
49        // the purpose of this little exercise is to force listing what affects these mappings
50        let arch = match target.arch {
51            Arch::AArch64 => ArchKind::Aarch64,
52            Arch::AmdGpu => ArchKind::Amdgpu,
53            Arch::Arm => ArchKind::Arm(if target.llvm_target.starts_with("thumbv8m") {
54                ArmVer::ThumbV8M
55            } else {
56                ArmVer::Other
57            }),
58            Arch::Avr => ArchKind::Avr,
59            Arch::LoongArch32 | Arch::LoongArch64 => ArchKind::LoongArch,
60            Arch::Msp430 => ArchKind::Msp430,
61            Arch::Nvptx64 => ArchKind::Nvptx,
62            Arch::RiscV32 | Arch::RiscV64 => ArchKind::Riscv,
63            Arch::X86 => ArchKind::X86,
64            Arch::X86_64 => ArchKind::X86_64,
65            _ => ArchKind::Other,
66        };
67
68        let os = if target.is_like_windows {
69            OsKind::Windows
70        } else if target.is_like_vexos {
71            OsKind::VEXos
72        } else {
73            OsKind::Other
74        };
75
76        AbiMap { arch, os }
77    }
78
79    /// lower an [ExternAbi] to a [CanonAbi] if this AbiMap allows
80    pub fn canonize_abi(&self, extern_abi: ExternAbi, has_c_varargs: bool) -> AbiMapping {
81        let AbiMap { os, arch } = *self;
82
83        let canon_abi = match (extern_abi, arch) {
84            // infallible lowerings
85            (ExternAbi::C { .. }, _) => CanonAbi::C,
86            (ExternAbi::Rust | ExternAbi::RustCall, _) => CanonAbi::Rust,
87            (ExternAbi::Unadjusted, _) => CanonAbi::C,
88
89            (ExternAbi::RustCold, _) if self.os == OsKind::Windows => CanonAbi::Rust,
90            (ExternAbi::RustCold, _) => CanonAbi::RustCold,
91
92            (ExternAbi::Custom, _) => CanonAbi::Custom,
93
94            (ExternAbi::System { .. }, ArchKind::X86)
95                if os == OsKind::Windows && !has_c_varargs =>
96            {
97                CanonAbi::X86(X86Call::Stdcall)
98            }
99            (ExternAbi::System { .. }, ArchKind::Arm(..)) if self.os == OsKind::VEXos => {
100                // Calls to VEXos APIs do not use VFP registers.
101                CanonAbi::Arm(ArmCall::Aapcs)
102            }
103            (ExternAbi::System { .. }, _) => CanonAbi::C,
104
105            // fallible lowerings
106            /* multi-platform */
107            // always and forever
108            (ExternAbi::RustInvalid, _) => return AbiMapping::Invalid,
109
110            (ExternAbi::EfiApi, ArchKind::Arm(..)) => CanonAbi::Arm(ArmCall::Aapcs),
111            (ExternAbi::EfiApi, ArchKind::X86_64) => CanonAbi::X86(X86Call::Win64),
112            (
113                ExternAbi::EfiApi,
114                ArchKind::Aarch64 | ArchKind::LoongArch | ArchKind::Riscv | ArchKind::X86,
115            ) => CanonAbi::C,
116            (ExternAbi::EfiApi, _) => return AbiMapping::Invalid,
117
118            /* arm */
119            (ExternAbi::Aapcs { .. }, ArchKind::Arm(..)) => CanonAbi::Arm(ArmCall::Aapcs),
120            (ExternAbi::Aapcs { .. }, _) => return AbiMapping::Invalid,
121
122            (ExternAbi::CmseNonSecureCall, ArchKind::Arm(ArmVer::ThumbV8M)) => {
123                CanonAbi::Arm(ArmCall::CCmseNonSecureCall)
124            }
125            (ExternAbi::CmseNonSecureEntry, ArchKind::Arm(ArmVer::ThumbV8M)) => {
126                CanonAbi::Arm(ArmCall::CCmseNonSecureEntry)
127            }
128            (ExternAbi::CmseNonSecureCall | ExternAbi::CmseNonSecureEntry, ..) => {
129                return AbiMapping::Invalid;
130            }
131
132            /* gpu */
133            (ExternAbi::PtxKernel, ArchKind::Nvptx) => CanonAbi::GpuKernel,
134            (ExternAbi::GpuKernel, ArchKind::Amdgpu | ArchKind::Nvptx) => CanonAbi::GpuKernel,
135            (ExternAbi::PtxKernel | ExternAbi::GpuKernel, _) => return AbiMapping::Invalid,
136
137            /* x86 */
138            (ExternAbi::Cdecl { .. }, ArchKind::X86) => CanonAbi::C,
139            (ExternAbi::Cdecl { .. }, _) => return AbiMapping::Deprecated(CanonAbi::C),
140
141            (ExternAbi::Fastcall { .. }, ArchKind::X86) => CanonAbi::X86(X86Call::Fastcall),
142            (ExternAbi::Fastcall { .. }, _) if os == OsKind::Windows => {
143                return AbiMapping::Deprecated(CanonAbi::C);
144            }
145            (ExternAbi::Fastcall { .. }, _) => return AbiMapping::Invalid,
146
147            (ExternAbi::Stdcall { .. }, ArchKind::X86) => CanonAbi::X86(X86Call::Stdcall),
148            (ExternAbi::Stdcall { .. }, _) if os == OsKind::Windows => {
149                return AbiMapping::Deprecated(CanonAbi::C);
150            }
151            (ExternAbi::Stdcall { .. }, _) => return AbiMapping::Invalid,
152
153            (ExternAbi::Thiscall { .. }, ArchKind::X86) => CanonAbi::X86(X86Call::Thiscall),
154            (ExternAbi::Thiscall { .. }, _) => return AbiMapping::Invalid,
155
156            (ExternAbi::Vectorcall { .. }, ArchKind::X86 | ArchKind::X86_64) => {
157                CanonAbi::X86(X86Call::Vectorcall)
158            }
159            (ExternAbi::Vectorcall { .. }, _) => return AbiMapping::Invalid,
160
161            (ExternAbi::SysV64 { .. }, ArchKind::X86_64) => CanonAbi::X86(X86Call::SysV64),
162            (ExternAbi::Win64 { .. }, ArchKind::X86_64) => CanonAbi::X86(X86Call::Win64),
163            (ExternAbi::SysV64 { .. } | ExternAbi::Win64 { .. }, _) => return AbiMapping::Invalid,
164
165            /* interrupts */
166            (ExternAbi::AvrInterrupt, ArchKind::Avr) => CanonAbi::Interrupt(InterruptKind::Avr),
167            (ExternAbi::AvrNonBlockingInterrupt, ArchKind::Avr) => {
168                CanonAbi::Interrupt(InterruptKind::AvrNonBlocking)
169            }
170            (ExternAbi::Msp430Interrupt, ArchKind::Msp430) => {
171                CanonAbi::Interrupt(InterruptKind::Msp430)
172            }
173            (ExternAbi::RiscvInterruptM, ArchKind::Riscv) => {
174                CanonAbi::Interrupt(InterruptKind::RiscvMachine)
175            }
176            (ExternAbi::RiscvInterruptS, ArchKind::Riscv) => {
177                CanonAbi::Interrupt(InterruptKind::RiscvSupervisor)
178            }
179            (ExternAbi::X86Interrupt, ArchKind::X86 | ArchKind::X86_64) => {
180                CanonAbi::Interrupt(InterruptKind::X86)
181            }
182            (
183                ExternAbi::AvrInterrupt
184                | ExternAbi::AvrNonBlockingInterrupt
185                | ExternAbi::Msp430Interrupt
186                | ExternAbi::RiscvInterruptM
187                | ExternAbi::RiscvInterruptS
188                | ExternAbi::X86Interrupt,
189                _,
190            ) => return AbiMapping::Invalid,
191        };
192
193        AbiMapping::Direct(canon_abi)
194    }
195}
196
197#[derive(Debug, PartialEq, Copy, Clone)]
198enum ArchKind {
199    Aarch64,
200    Amdgpu,
201    Arm(ArmVer),
202    Avr,
203    LoongArch,
204    Msp430,
205    Nvptx,
206    Riscv,
207    X86,
208    X86_64,
209    /// Architectures which don't need other considerations for ABI lowering
210    Other,
211}
212
213#[derive(Debug, PartialEq, Copy, Clone)]
214enum OsKind {
215    Windows,
216    VEXos,
217    Other,
218}
219
220#[derive(Debug, PartialEq, Copy, Clone)]
221enum ArmVer {
222    ThumbV8M,
223    Other,
224}