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)]
16pub enum AbiMapping {
17 Direct(CanonAbi),
19 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 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 (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 (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 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}