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::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 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 (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 CanonAbi::Arm(ArmCall::Aapcs)
101 }
102 (ExternAbi::System { .. }, _) => CanonAbi::C,
103
104 (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 (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 (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 (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 (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 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}