rustc_target/spec/
abi_map.rs

1use rustc_abi::{ArmCall, CanonAbi, ExternAbi, InterruptKind, X86Call};
2
3use crate::spec::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: Arch,
12    os: OsKind,
13}
14
15#[derive(Copy, Clone, Debug)]
16pub enum AbiMapping {
17    /// this ABI is exactly mapped for this platform
18    Direct(CanonAbi),
19    /// we don't yet warn on this, but we will
20    Deprecated(CanonAbi),
21    Invalid,
22}
23
24impl AbiMapping {
25    pub fn into_option(self) -> Option<CanonAbi> {
26        match self {
27            Self::Direct(abi) | Self::Deprecated(abi) => Some(abi),
28            Self::Invalid => None,
29        }
30    }
31
32    pub fn unwrap(self) -> CanonAbi {
33        self.into_option().unwrap()
34    }
35
36    pub fn is_mapped(self) -> bool {
37        self.into_option().is_some()
38    }
39}
40
41impl AbiMap {
42    pub fn from_target(target: &Target) -> Self {
43        // the purpose of this little exercise is to force listing what affects these mappings
44        let arch = match &*target.arch {
45            "aarch64" => Arch::Aarch64,
46            "amdgpu" => Arch::Amdgpu,
47            "arm" if target.llvm_target.starts_with("thumbv8m") => Arch::Arm(ArmVer::ThumbV8M),
48            "arm" => Arch::Arm(ArmVer::Other),
49            "avr" => Arch::Avr,
50            "msp430" => Arch::Msp430,
51            "nvptx64" => Arch::Nvptx,
52            "riscv32" | "riscv64" => Arch::Riscv,
53            "x86" => Arch::X86,
54            "x86_64" => Arch::X86_64,
55            _ => Arch::Other,
56        };
57        let os = if target.is_like_windows { OsKind::Windows } else { OsKind::Other };
58        AbiMap { arch, os }
59    }
60
61    pub fn canonize_abi(&self, extern_abi: ExternAbi, has_c_varargs: bool) -> AbiMapping {
62        let AbiMap { os, arch } = *self;
63
64        let canon_abi = match (extern_abi, arch) {
65            // infallible lowerings
66            (ExternAbi::C { .. }, _) => CanonAbi::C,
67            (ExternAbi::Rust | ExternAbi::RustCall, _) => CanonAbi::Rust,
68            (ExternAbi::Unadjusted, _) => CanonAbi::C,
69
70            (ExternAbi::RustCold, _) if self.os == OsKind::Windows => CanonAbi::Rust,
71            (ExternAbi::RustCold, _) => CanonAbi::RustCold,
72
73            (ExternAbi::System { .. }, Arch::X86) if os == OsKind::Windows && !has_c_varargs => {
74                CanonAbi::X86(X86Call::Stdcall)
75            }
76            (ExternAbi::System { .. }, _) => CanonAbi::C,
77
78            // fallible lowerings
79            (ExternAbi::EfiApi, Arch::Arm(..)) => CanonAbi::Arm(ArmCall::Aapcs),
80            (ExternAbi::EfiApi, Arch::X86_64) => CanonAbi::X86(X86Call::Win64),
81            (ExternAbi::EfiApi, Arch::Aarch64 | Arch::Riscv | Arch::X86) => CanonAbi::C,
82            (ExternAbi::EfiApi, _) => return AbiMapping::Invalid,
83
84            (ExternAbi::Aapcs { .. }, Arch::Arm(..)) => CanonAbi::Arm(ArmCall::Aapcs),
85            (ExternAbi::Aapcs { .. }, _) => return AbiMapping::Invalid,
86
87            (ExternAbi::CCmseNonSecureCall, Arch::Arm(ArmVer::ThumbV8M)) => {
88                CanonAbi::Arm(ArmCall::CCmseNonSecureCall)
89            }
90            (ExternAbi::CCmseNonSecureEntry, Arch::Arm(ArmVer::ThumbV8M)) => {
91                CanonAbi::Arm(ArmCall::CCmseNonSecureEntry)
92            }
93            (ExternAbi::CCmseNonSecureCall | ExternAbi::CCmseNonSecureEntry, ..) => {
94                return AbiMapping::Invalid;
95            }
96
97            (ExternAbi::Cdecl { .. }, Arch::X86) => CanonAbi::C,
98            (ExternAbi::Cdecl { .. }, _) => return AbiMapping::Deprecated(CanonAbi::C),
99
100            (ExternAbi::Fastcall { .. }, Arch::X86) => CanonAbi::X86(X86Call::Fastcall),
101            (ExternAbi::Fastcall { .. }, _) if os == OsKind::Windows => {
102                return AbiMapping::Deprecated(CanonAbi::C);
103            }
104            (ExternAbi::Fastcall { .. }, _) => return AbiMapping::Invalid,
105
106            (ExternAbi::Stdcall { .. }, Arch::X86) => CanonAbi::X86(X86Call::Stdcall),
107            (ExternAbi::Stdcall { .. }, _) if os == OsKind::Windows => {
108                return AbiMapping::Deprecated(CanonAbi::C);
109            }
110            (ExternAbi::Stdcall { .. }, _) => return AbiMapping::Invalid,
111
112            (ExternAbi::Thiscall { .. }, Arch::X86) => CanonAbi::X86(X86Call::Thiscall),
113            (ExternAbi::Thiscall { .. }, _) => return AbiMapping::Invalid,
114
115            (ExternAbi::Vectorcall { .. }, Arch::X86 | Arch::X86_64) => {
116                CanonAbi::X86(X86Call::Vectorcall)
117            }
118            (ExternAbi::Vectorcall { .. }, _) if os == OsKind::Windows => {
119                return AbiMapping::Deprecated(CanonAbi::C);
120            }
121            (ExternAbi::Vectorcall { .. }, _) => return AbiMapping::Invalid,
122
123            (ExternAbi::SysV64 { .. }, Arch::X86_64) => CanonAbi::X86(X86Call::SysV64),
124            (ExternAbi::Win64 { .. }, Arch::X86_64) => CanonAbi::X86(X86Call::Win64),
125            (ExternAbi::SysV64 { .. } | ExternAbi::Win64 { .. }, _) => return AbiMapping::Invalid,
126
127            (ExternAbi::PtxKernel, Arch::Nvptx) => CanonAbi::GpuKernel,
128            (ExternAbi::GpuKernel, Arch::Amdgpu | Arch::Nvptx) => CanonAbi::GpuKernel,
129            (ExternAbi::PtxKernel | ExternAbi::GpuKernel, _) => return AbiMapping::Invalid,
130
131            (ExternAbi::AvrInterrupt, Arch::Avr) => CanonAbi::Interrupt(InterruptKind::Avr),
132            (ExternAbi::AvrNonBlockingInterrupt, Arch::Avr) => {
133                CanonAbi::Interrupt(InterruptKind::AvrNonBlocking)
134            }
135            (ExternAbi::Msp430Interrupt, Arch::Msp430) => {
136                CanonAbi::Interrupt(InterruptKind::Msp430)
137            }
138            (ExternAbi::RiscvInterruptM, Arch::Riscv) => {
139                CanonAbi::Interrupt(InterruptKind::RiscvMachine)
140            }
141            (ExternAbi::RiscvInterruptS, Arch::Riscv) => {
142                CanonAbi::Interrupt(InterruptKind::RiscvSupervisor)
143            }
144            (ExternAbi::X86Interrupt, Arch::X86 | Arch::X86_64) => {
145                CanonAbi::Interrupt(InterruptKind::X86)
146            }
147            (
148                ExternAbi::AvrInterrupt
149                | ExternAbi::AvrNonBlockingInterrupt
150                | ExternAbi::Msp430Interrupt
151                | ExternAbi::RiscvInterruptM
152                | ExternAbi::RiscvInterruptS
153                | ExternAbi::X86Interrupt,
154                _,
155            ) => return AbiMapping::Invalid,
156        };
157
158        AbiMapping::Direct(canon_abi)
159    }
160}
161
162#[derive(Debug, PartialEq, Copy, Clone)]
163enum Arch {
164    Aarch64,
165    Amdgpu,
166    Arm(ArmVer),
167    Avr,
168    Msp430,
169    Nvptx,
170    Riscv,
171    X86,
172    X86_64,
173    /// Architectures which don't need other considerations for ABI lowering
174    Other,
175}
176
177#[derive(Debug, PartialEq, Copy, Clone)]
178enum OsKind {
179    Windows,
180    Other,
181}
182
183#[derive(Debug, PartialEq, Copy, Clone)]
184enum ArmVer {
185    ThumbV8M,
186    Other,
187}