1use rustc_abi::{ArmCall, CanonAbi, ExternAbi, InterruptKind, X86Call};
2
3use crate::spec::Target;
4
5#[derive(Clone, Debug)]
10pub struct AbiMap {
11 arch: Arch,
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 "aarch64" => Arch::Aarch64,
52 "amdgpu" => Arch::Amdgpu,
53 "arm" if target.llvm_target.starts_with("thumbv8m") => Arch::Arm(ArmVer::ThumbV8M),
54 "arm" => Arch::Arm(ArmVer::Other),
55 "avr" => Arch::Avr,
56 "msp430" => Arch::Msp430,
57 "nvptx64" => Arch::Nvptx,
58 "riscv32" | "riscv64" => Arch::Riscv,
59 "x86" => Arch::X86,
60 "x86_64" => Arch::X86_64,
61 _ => Arch::Other,
62 };
63
64 let os = if target.is_like_windows {
65 OsKind::Windows
66 } else if target.is_like_vexos {
67 OsKind::VEXos
68 } else {
69 OsKind::Other
70 };
71
72 AbiMap { arch, os }
73 }
74
75 pub fn canonize_abi(&self, extern_abi: ExternAbi, has_c_varargs: bool) -> AbiMapping {
77 let AbiMap { os, arch } = *self;
78
79 let canon_abi = match (extern_abi, arch) {
80 (ExternAbi::C { .. }, _) => CanonAbi::C,
82 (ExternAbi::Rust | ExternAbi::RustCall, _) => CanonAbi::Rust,
83 (ExternAbi::Unadjusted, _) => CanonAbi::C,
84
85 (ExternAbi::RustCold, _) if self.os == OsKind::Windows => CanonAbi::Rust,
86 (ExternAbi::RustCold, _) => CanonAbi::RustCold,
87
88 (ExternAbi::Custom, _) => CanonAbi::Custom,
89
90 (ExternAbi::System { .. }, Arch::X86) if os == OsKind::Windows && !has_c_varargs => {
91 CanonAbi::X86(X86Call::Stdcall)
92 }
93 (ExternAbi::System { .. }, Arch::Arm(..)) if self.os == OsKind::VEXos => {
94 CanonAbi::Arm(ArmCall::Aapcs)
96 }
97 (ExternAbi::System { .. }, _) => CanonAbi::C,
98
99 (ExternAbi::RustInvalid, _) => return AbiMapping::Invalid,
103
104 (ExternAbi::EfiApi, Arch::Arm(..)) => CanonAbi::Arm(ArmCall::Aapcs),
105 (ExternAbi::EfiApi, Arch::X86_64) => CanonAbi::X86(X86Call::Win64),
106 (ExternAbi::EfiApi, Arch::Aarch64 | Arch::Riscv | Arch::X86) => CanonAbi::C,
107 (ExternAbi::EfiApi, _) => return AbiMapping::Invalid,
108
109 (ExternAbi::Aapcs { .. }, Arch::Arm(..)) => CanonAbi::Arm(ArmCall::Aapcs),
111 (ExternAbi::Aapcs { .. }, _) => return AbiMapping::Invalid,
112
113 (ExternAbi::CmseNonSecureCall, Arch::Arm(ArmVer::ThumbV8M)) => {
114 CanonAbi::Arm(ArmCall::CCmseNonSecureCall)
115 }
116 (ExternAbi::CmseNonSecureEntry, Arch::Arm(ArmVer::ThumbV8M)) => {
117 CanonAbi::Arm(ArmCall::CCmseNonSecureEntry)
118 }
119 (ExternAbi::CmseNonSecureCall | ExternAbi::CmseNonSecureEntry, ..) => {
120 return AbiMapping::Invalid;
121 }
122
123 (ExternAbi::PtxKernel, Arch::Nvptx) => CanonAbi::GpuKernel,
125 (ExternAbi::GpuKernel, Arch::Amdgpu | Arch::Nvptx) => CanonAbi::GpuKernel,
126 (ExternAbi::PtxKernel | ExternAbi::GpuKernel, _) => return AbiMapping::Invalid,
127
128 (ExternAbi::Cdecl { .. }, Arch::X86) => CanonAbi::C,
130 (ExternAbi::Cdecl { .. }, _) => return AbiMapping::Deprecated(CanonAbi::C),
131
132 (ExternAbi::Fastcall { .. }, Arch::X86) => CanonAbi::X86(X86Call::Fastcall),
133 (ExternAbi::Fastcall { .. }, _) if os == OsKind::Windows => {
134 return AbiMapping::Deprecated(CanonAbi::C);
135 }
136 (ExternAbi::Fastcall { .. }, _) => return AbiMapping::Invalid,
137
138 (ExternAbi::Stdcall { .. }, Arch::X86) => CanonAbi::X86(X86Call::Stdcall),
139 (ExternAbi::Stdcall { .. }, _) if os == OsKind::Windows => {
140 return AbiMapping::Deprecated(CanonAbi::C);
141 }
142 (ExternAbi::Stdcall { .. }, _) => return AbiMapping::Invalid,
143
144 (ExternAbi::Thiscall { .. }, Arch::X86) => CanonAbi::X86(X86Call::Thiscall),
145 (ExternAbi::Thiscall { .. }, _) => return AbiMapping::Invalid,
146
147 (ExternAbi::Vectorcall { .. }, Arch::X86 | Arch::X86_64) => {
148 CanonAbi::X86(X86Call::Vectorcall)
149 }
150 (ExternAbi::Vectorcall { .. }, _) => return AbiMapping::Invalid,
151
152 (ExternAbi::SysV64 { .. }, Arch::X86_64) => CanonAbi::X86(X86Call::SysV64),
153 (ExternAbi::Win64 { .. }, Arch::X86_64) => CanonAbi::X86(X86Call::Win64),
154 (ExternAbi::SysV64 { .. } | ExternAbi::Win64 { .. }, _) => return AbiMapping::Invalid,
155
156 (ExternAbi::AvrInterrupt, Arch::Avr) => CanonAbi::Interrupt(InterruptKind::Avr),
158 (ExternAbi::AvrNonBlockingInterrupt, Arch::Avr) => {
159 CanonAbi::Interrupt(InterruptKind::AvrNonBlocking)
160 }
161 (ExternAbi::Msp430Interrupt, Arch::Msp430) => {
162 CanonAbi::Interrupt(InterruptKind::Msp430)
163 }
164 (ExternAbi::RiscvInterruptM, Arch::Riscv) => {
165 CanonAbi::Interrupt(InterruptKind::RiscvMachine)
166 }
167 (ExternAbi::RiscvInterruptS, Arch::Riscv) => {
168 CanonAbi::Interrupt(InterruptKind::RiscvSupervisor)
169 }
170 (ExternAbi::X86Interrupt, Arch::X86 | Arch::X86_64) => {
171 CanonAbi::Interrupt(InterruptKind::X86)
172 }
173 (
174 ExternAbi::AvrInterrupt
175 | ExternAbi::AvrNonBlockingInterrupt
176 | ExternAbi::Msp430Interrupt
177 | ExternAbi::RiscvInterruptM
178 | ExternAbi::RiscvInterruptS
179 | ExternAbi::X86Interrupt,
180 _,
181 ) => return AbiMapping::Invalid,
182 };
183
184 AbiMapping::Direct(canon_abi)
185 }
186}
187
188#[derive(Debug, PartialEq, Copy, Clone)]
189enum Arch {
190 Aarch64,
191 Amdgpu,
192 Arm(ArmVer),
193 Avr,
194 Msp430,
195 Nvptx,
196 Riscv,
197 X86,
198 X86_64,
199 Other,
201}
202
203#[derive(Debug, PartialEq, Copy, Clone)]
204enum OsKind {
205 Windows,
206 VEXos,
207 Other,
208}
209
210#[derive(Debug, PartialEq, Copy, Clone)]
211enum ArmVer {
212 ThumbV8M,
213 Other,
214}