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::Msp430 => ArchKind::Msp430,
60            Arch::Nvptx64 => ArchKind::Nvptx,
61            Arch::RiscV32 | Arch::RiscV64 => ArchKind::Riscv,
62            Arch::X86 => ArchKind::X86,
63            Arch::X86_64 => ArchKind::X86_64,
64            _ => ArchKind::Other,
65        };
66
67        let os = if target.is_like_windows {
68            OsKind::Windows
69        } else if target.is_like_vexos {
70            OsKind::VEXos
71        } else {
72            OsKind::Other
73        };
74
75        AbiMap { arch, os }
76    }
77
78    /// lower an [ExternAbi] to a [CanonAbi] if this AbiMap allows
79    pub fn canonize_abi(&self, extern_abi: ExternAbi, has_c_varargs: bool) -> AbiMapping {
80        let AbiMap { os, arch } = *self;
81
82        let canon_abi = match (extern_abi, arch) {
83            // infallible lowerings
84            (ExternAbi::C { .. }, _) => CanonAbi::C,
85            (ExternAbi::Rust | ExternAbi::RustCall, _) => CanonAbi::Rust,
86            (ExternAbi::Unadjusted, _) => CanonAbi::C,
87
88            (ExternAbi::RustCold, _) if self.os == OsKind::Windows => CanonAbi::Rust,
89            (ExternAbi::RustCold, _) => CanonAbi::RustCold,
90
91            (ExternAbi::Custom, _) => CanonAbi::Custom,
92
93            (ExternAbi::System { .. }, ArchKind::X86)
94                if os == OsKind::Windows && !has_c_varargs =>
95            {
96                CanonAbi::X86(X86Call::Stdcall)
97            }
98            (ExternAbi::System { .. }, ArchKind::Arm(..)) if self.os == OsKind::VEXos => {
99                // Calls to VEXos APIs do not use VFP registers.
100                CanonAbi::Arm(ArmCall::Aapcs)
101            }
102            (ExternAbi::System { .. }, _) => CanonAbi::C,
103
104            // fallible lowerings
105            /* multi-platform */
106            // always and forever
107            (ExternAbi::RustInvalid, _) => return AbiMapping::Invalid,
108
109            (ExternAbi::EfiApi, ArchKind::Arm(..)) => CanonAbi::Arm(ArmCall::Aapcs),
110            (ExternAbi::EfiApi, ArchKind::X86_64) => CanonAbi::X86(X86Call::Win64),
111            (ExternAbi::EfiApi, ArchKind::Aarch64 | ArchKind::Riscv | ArchKind::X86) => CanonAbi::C,
112            (ExternAbi::EfiApi, _) => return AbiMapping::Invalid,
113
114            /* arm */
115            (ExternAbi::Aapcs { .. }, ArchKind::Arm(..)) => CanonAbi::Arm(ArmCall::Aapcs),
116            (ExternAbi::Aapcs { .. }, _) => return AbiMapping::Invalid,
117
118            (ExternAbi::CmseNonSecureCall, ArchKind::Arm(ArmVer::ThumbV8M)) => {
119                CanonAbi::Arm(ArmCall::CCmseNonSecureCall)
120            }
121            (ExternAbi::CmseNonSecureEntry, ArchKind::Arm(ArmVer::ThumbV8M)) => {
122                CanonAbi::Arm(ArmCall::CCmseNonSecureEntry)
123            }
124            (ExternAbi::CmseNonSecureCall | ExternAbi::CmseNonSecureEntry, ..) => {
125                return AbiMapping::Invalid;
126            }
127
128            /* gpu */
129            (ExternAbi::PtxKernel, ArchKind::Nvptx) => CanonAbi::GpuKernel,
130            (ExternAbi::GpuKernel, ArchKind::Amdgpu | ArchKind::Nvptx) => CanonAbi::GpuKernel,
131            (ExternAbi::PtxKernel | ExternAbi::GpuKernel, _) => return AbiMapping::Invalid,
132
133            /* x86 */
134            (ExternAbi::Cdecl { .. }, ArchKind::X86) => CanonAbi::C,
135            (ExternAbi::Cdecl { .. }, _) => return AbiMapping::Deprecated(CanonAbi::C),
136
137            (ExternAbi::Fastcall { .. }, ArchKind::X86) => CanonAbi::X86(X86Call::Fastcall),
138            (ExternAbi::Fastcall { .. }, _) if os == OsKind::Windows => {
139                return AbiMapping::Deprecated(CanonAbi::C);
140            }
141            (ExternAbi::Fastcall { .. }, _) => return AbiMapping::Invalid,
142
143            (ExternAbi::Stdcall { .. }, ArchKind::X86) => CanonAbi::X86(X86Call::Stdcall),
144            (ExternAbi::Stdcall { .. }, _) if os == OsKind::Windows => {
145                return AbiMapping::Deprecated(CanonAbi::C);
146            }
147            (ExternAbi::Stdcall { .. }, _) => return AbiMapping::Invalid,
148
149            (ExternAbi::Thiscall { .. }, ArchKind::X86) => CanonAbi::X86(X86Call::Thiscall),
150            (ExternAbi::Thiscall { .. }, _) => return AbiMapping::Invalid,
151
152            (ExternAbi::Vectorcall { .. }, ArchKind::X86 | ArchKind::X86_64) => {
153                CanonAbi::X86(X86Call::Vectorcall)
154            }
155            (ExternAbi::Vectorcall { .. }, _) => return AbiMapping::Invalid,
156
157            (ExternAbi::SysV64 { .. }, ArchKind::X86_64) => CanonAbi::X86(X86Call::SysV64),
158            (ExternAbi::Win64 { .. }, ArchKind::X86_64) => CanonAbi::X86(X86Call::Win64),
159            (ExternAbi::SysV64 { .. } | ExternAbi::Win64 { .. }, _) => return AbiMapping::Invalid,
160
161            /* interrupts */
162            (ExternAbi::AvrInterrupt, ArchKind::Avr) => CanonAbi::Interrupt(InterruptKind::Avr),
163            (ExternAbi::AvrNonBlockingInterrupt, ArchKind::Avr) => {
164                CanonAbi::Interrupt(InterruptKind::AvrNonBlocking)
165            }
166            (ExternAbi::Msp430Interrupt, ArchKind::Msp430) => {
167                CanonAbi::Interrupt(InterruptKind::Msp430)
168            }
169            (ExternAbi::RiscvInterruptM, ArchKind::Riscv) => {
170                CanonAbi::Interrupt(InterruptKind::RiscvMachine)
171            }
172            (ExternAbi::RiscvInterruptS, ArchKind::Riscv) => {
173                CanonAbi::Interrupt(InterruptKind::RiscvSupervisor)
174            }
175            (ExternAbi::X86Interrupt, ArchKind::X86 | ArchKind::X86_64) => {
176                CanonAbi::Interrupt(InterruptKind::X86)
177            }
178            (
179                ExternAbi::AvrInterrupt
180                | ExternAbi::AvrNonBlockingInterrupt
181                | ExternAbi::Msp430Interrupt
182                | ExternAbi::RiscvInterruptM
183                | ExternAbi::RiscvInterruptS
184                | ExternAbi::X86Interrupt,
185                _,
186            ) => return AbiMapping::Invalid,
187        };
188
189        AbiMapping::Direct(canon_abi)
190    }
191}
192
193#[derive(Debug, PartialEq, Copy, Clone)]
194enum ArchKind {
195    Aarch64,
196    Amdgpu,
197    Arm(ArmVer),
198    Avr,
199    Msp430,
200    Nvptx,
201    Riscv,
202    X86,
203    X86_64,
204    /// Architectures which don't need other considerations for ABI lowering
205    Other,
206}
207
208#[derive(Debug, PartialEq, Copy, Clone)]
209enum OsKind {
210    Windows,
211    VEXos,
212    Other,
213}
214
215#[derive(Debug, PartialEq, Copy, Clone)]
216enum ArmVer {
217    ThumbV8M,
218    Other,
219}