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 let os = if target.is_like_windows { OsKind::Windows } else { OsKind::Other };
64 AbiMap { arch, os }
65 }
66
67 pub fn canonize_abi(&self, extern_abi: ExternAbi, has_c_varargs: bool) -> AbiMapping {
69 let AbiMap { os, arch } = *self;
70
71 let canon_abi = match (extern_abi, arch) {
72 (ExternAbi::C { .. }, _) => CanonAbi::C,
74 (ExternAbi::Rust | ExternAbi::RustCall, _) => CanonAbi::Rust,
75 (ExternAbi::Unadjusted, _) => CanonAbi::C,
76
77 (ExternAbi::RustCold, _) if self.os == OsKind::Windows => CanonAbi::Rust,
78 (ExternAbi::RustCold, _) => CanonAbi::RustCold,
79
80 (ExternAbi::Custom, _) => CanonAbi::Custom,
81
82 (ExternAbi::System { .. }, Arch::X86) if os == OsKind::Windows && !has_c_varargs => {
83 CanonAbi::X86(X86Call::Stdcall)
84 }
85 (ExternAbi::System { .. }, _) => CanonAbi::C,
86
87 (ExternAbi::EfiApi, Arch::Arm(..)) => CanonAbi::Arm(ArmCall::Aapcs),
89 (ExternAbi::EfiApi, Arch::X86_64) => CanonAbi::X86(X86Call::Win64),
90 (ExternAbi::EfiApi, Arch::Aarch64 | Arch::Riscv | Arch::X86) => CanonAbi::C,
91 (ExternAbi::EfiApi, _) => return AbiMapping::Invalid,
92
93 (ExternAbi::Aapcs { .. }, Arch::Arm(..)) => CanonAbi::Arm(ArmCall::Aapcs),
94 (ExternAbi::Aapcs { .. }, _) => return AbiMapping::Invalid,
95
96 (ExternAbi::CCmseNonSecureCall, Arch::Arm(ArmVer::ThumbV8M)) => {
97 CanonAbi::Arm(ArmCall::CCmseNonSecureCall)
98 }
99 (ExternAbi::CCmseNonSecureEntry, Arch::Arm(ArmVer::ThumbV8M)) => {
100 CanonAbi::Arm(ArmCall::CCmseNonSecureEntry)
101 }
102 (ExternAbi::CCmseNonSecureCall | ExternAbi::CCmseNonSecureEntry, ..) => {
103 return AbiMapping::Invalid;
104 }
105
106 (ExternAbi::Cdecl { .. }, Arch::X86) => CanonAbi::C,
107 (ExternAbi::Cdecl { .. }, _) => return AbiMapping::Deprecated(CanonAbi::C),
108
109 (ExternAbi::Fastcall { .. }, Arch::X86) => CanonAbi::X86(X86Call::Fastcall),
110 (ExternAbi::Fastcall { .. }, _) if os == OsKind::Windows => {
111 return AbiMapping::Deprecated(CanonAbi::C);
112 }
113 (ExternAbi::Fastcall { .. }, _) => return AbiMapping::Invalid,
114
115 (ExternAbi::Stdcall { .. }, Arch::X86) => CanonAbi::X86(X86Call::Stdcall),
116 (ExternAbi::Stdcall { .. }, _) if os == OsKind::Windows => {
117 return AbiMapping::Deprecated(CanonAbi::C);
118 }
119 (ExternAbi::Stdcall { .. }, _) => return AbiMapping::Invalid,
120
121 (ExternAbi::Thiscall { .. }, Arch::X86) => CanonAbi::X86(X86Call::Thiscall),
122 (ExternAbi::Thiscall { .. }, _) => return AbiMapping::Invalid,
123
124 (ExternAbi::Vectorcall { .. }, Arch::X86 | Arch::X86_64) => {
125 CanonAbi::X86(X86Call::Vectorcall)
126 }
127 (ExternAbi::Vectorcall { .. }, _) => return AbiMapping::Invalid,
128
129 (ExternAbi::SysV64 { .. }, Arch::X86_64) => CanonAbi::X86(X86Call::SysV64),
130 (ExternAbi::Win64 { .. }, Arch::X86_64) => CanonAbi::X86(X86Call::Win64),
131 (ExternAbi::SysV64 { .. } | ExternAbi::Win64 { .. }, _) => return AbiMapping::Invalid,
132
133 (ExternAbi::PtxKernel, Arch::Nvptx) => CanonAbi::GpuKernel,
134 (ExternAbi::GpuKernel, Arch::Amdgpu | Arch::Nvptx) => CanonAbi::GpuKernel,
135 (ExternAbi::PtxKernel | ExternAbi::GpuKernel, _) => return AbiMapping::Invalid,
136
137 (ExternAbi::AvrInterrupt, Arch::Avr) => CanonAbi::Interrupt(InterruptKind::Avr),
138 (ExternAbi::AvrNonBlockingInterrupt, Arch::Avr) => {
139 CanonAbi::Interrupt(InterruptKind::AvrNonBlocking)
140 }
141 (ExternAbi::Msp430Interrupt, Arch::Msp430) => {
142 CanonAbi::Interrupt(InterruptKind::Msp430)
143 }
144 (ExternAbi::RiscvInterruptM, Arch::Riscv) => {
145 CanonAbi::Interrupt(InterruptKind::RiscvMachine)
146 }
147 (ExternAbi::RiscvInterruptS, Arch::Riscv) => {
148 CanonAbi::Interrupt(InterruptKind::RiscvSupervisor)
149 }
150 (ExternAbi::X86Interrupt, Arch::X86 | Arch::X86_64) => {
151 CanonAbi::Interrupt(InterruptKind::X86)
152 }
153 (
154 ExternAbi::AvrInterrupt
155 | ExternAbi::AvrNonBlockingInterrupt
156 | ExternAbi::Msp430Interrupt
157 | ExternAbi::RiscvInterruptM
158 | ExternAbi::RiscvInterruptS
159 | ExternAbi::X86Interrupt
160 | ExternAbi::RustInvalid,
161 _,
162 ) => return AbiMapping::Invalid,
163 };
164
165 AbiMapping::Direct(canon_abi)
166 }
167}
168
169#[derive(Debug, PartialEq, Copy, Clone)]
170enum Arch {
171 Aarch64,
172 Amdgpu,
173 Arm(ArmVer),
174 Avr,
175 Msp430,
176 Nvptx,
177 Riscv,
178 X86,
179 X86_64,
180 Other,
182}
183
184#[derive(Debug, PartialEq, Copy, Clone)]
185enum OsKind {
186 Windows,
187 Other,
188}
189
190#[derive(Debug, PartialEq, Copy, Clone)]
191enum ArmVer {
192 ThumbV8M,
193 Other,
194}