1use rustc_abi::{ArmCall, CanonAbi, ExternAbi, InterruptKind, X86Call};
2
3use crate::spec::{Arch, Target};
4
5#[derive(Clone, Debug)]
10pub struct AbiMap {
11 arch: ArchKind,
12 os: OsKind,
13}
14
15#[derive(Copy, Clone, Debug)]
17pub enum AbiMapping {
18 Direct(CanonAbi),
20 Deprecated(CanonAbi),
22 Invalid,
24}
25
26impl AbiMapping {
27 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 #[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 pub fn from_target(target: &Target) -> Self {
49 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 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 (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 CanonAbi::Arm(ArmCall::Aapcs)
102 }
103 (ExternAbi::System { .. }, _) => CanonAbi::C,
104
105 (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 (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 (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 (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 (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 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}