1 use std::fmt;
2 
3 use rustc_macros::HashStable_Generic;
4 
5 #[cfg(test)]
6 mod tests;
7 
8 #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Debug)]
9 #[derive(HashStable_Generic, Encodable, Decodable)]
10 pub enum Abi {
11     // Multiplatform / generic ABIs
12     //
13     // These ABIs come first because every time we add a new ABI, we
14     // have to re-bless all the hashing tests. These are used in many
15     // places, so giving them stable values reduces test churn. The
16     // specific values are meaningless.
17     Rust,
18     C { unwind: bool },
19 
20     // Single platform ABIs
21     Cdecl,
22     Stdcall { unwind: bool },
23     Fastcall,
24     Vectorcall,
25     Thiscall { unwind: bool },
26     Aapcs,
27     Win64,
28     SysV64,
29     PtxKernel,
30     Msp430Interrupt,
31     X86Interrupt,
32     AmdGpuKernel,
33     EfiApi,
34     AvrInterrupt,
35     AvrNonBlockingInterrupt,
36     CCmseNonSecureCall,
37     Wasm,
38 
39     // Multiplatform / generic ABIs
40     System { unwind: bool },
41     RustIntrinsic,
42     RustCall,
43     PlatformIntrinsic,
44     Unadjusted,
45 }
46 
47 #[derive(Copy, Clone)]
48 pub struct AbiData {
49     abi: Abi,
50 
51     /// Name of this ABI as we like it called.
52     name: &'static str,
53 
54     /// A generic ABI is supported on all platforms.
55     generic: bool,
56 }
57 
58 #[allow(non_upper_case_globals)]
59 const AbiDatas: &[AbiData] = &[
60     // Cross-platform ABIs
61     AbiData { abi: Abi::Rust, name: "Rust", generic: true },
62     AbiData { abi: Abi::C { unwind: false }, name: "C", generic: true },
63     AbiData { abi: Abi::C { unwind: true }, name: "C-unwind", generic: true },
64     // Platform-specific ABIs
65     AbiData { abi: Abi::Cdecl, name: "cdecl", generic: false },
66     AbiData { abi: Abi::Stdcall { unwind: false }, name: "stdcall", generic: false },
67     AbiData { abi: Abi::Stdcall { unwind: true }, name: "stdcall-unwind", generic: false },
68     AbiData { abi: Abi::Fastcall, name: "fastcall", generic: false },
69     AbiData { abi: Abi::Vectorcall, name: "vectorcall", generic: false },
70     AbiData { abi: Abi::Thiscall { unwind: false }, name: "thiscall", generic: false },
71     AbiData { abi: Abi::Thiscall { unwind: true }, name: "thiscall-unwind", generic: false },
72     AbiData { abi: Abi::Aapcs, name: "aapcs", generic: false },
73     AbiData { abi: Abi::Win64, name: "win64", generic: false },
74     AbiData { abi: Abi::SysV64, name: "sysv64", generic: false },
75     AbiData { abi: Abi::PtxKernel, name: "ptx-kernel", generic: false },
76     AbiData { abi: Abi::Msp430Interrupt, name: "msp430-interrupt", generic: false },
77     AbiData { abi: Abi::X86Interrupt, name: "x86-interrupt", generic: false },
78     AbiData { abi: Abi::AmdGpuKernel, name: "amdgpu-kernel", generic: false },
79     AbiData { abi: Abi::EfiApi, name: "efiapi", generic: false },
80     AbiData { abi: Abi::AvrInterrupt, name: "avr-interrupt", generic: false },
81     AbiData {
82         abi: Abi::AvrNonBlockingInterrupt,
83         name: "avr-non-blocking-interrupt",
84         generic: false,
85     },
86     AbiData { abi: Abi::CCmseNonSecureCall, name: "C-cmse-nonsecure-call", generic: false },
87     AbiData { abi: Abi::Wasm, name: "wasm", generic: false },
88     // Cross-platform ABIs
89     AbiData { abi: Abi::System { unwind: false }, name: "system", generic: true },
90     AbiData { abi: Abi::System { unwind: true }, name: "system-unwind", generic: true },
91     AbiData { abi: Abi::RustIntrinsic, name: "rust-intrinsic", generic: true },
92     AbiData { abi: Abi::RustCall, name: "rust-call", generic: true },
93     AbiData { abi: Abi::PlatformIntrinsic, name: "platform-intrinsic", generic: true },
94     AbiData { abi: Abi::Unadjusted, name: "unadjusted", generic: true },
95 ];
96 
97 /// Returns the ABI with the given name (if any).
lookup(name: &str) -> Option<Abi>98 pub fn lookup(name: &str) -> Option<Abi> {
99     AbiDatas.iter().find(|abi_data| name == abi_data.name).map(|&x| x.abi)
100 }
101 
all_names() -> Vec<&'static str>102 pub fn all_names() -> Vec<&'static str> {
103     AbiDatas.iter().map(|d| d.name).collect()
104 }
105 
106 impl Abi {
107     #[inline]
index(self) -> usize108     pub fn index(self) -> usize {
109         // N.B., this ordering MUST match the AbiDatas array above.
110         // (This is ensured by the test indices_are_correct().)
111         use Abi::*;
112         let i = match self {
113             // Cross-platform ABIs
114             Rust => 0,
115             C { unwind: false } => 1,
116             C { unwind: true } => 2,
117             // Platform-specific ABIs
118             Cdecl => 3,
119             Stdcall { unwind: false } => 4,
120             Stdcall { unwind: true } => 5,
121             Fastcall => 6,
122             Vectorcall => 7,
123             Thiscall { unwind: false } => 8,
124             Thiscall { unwind: true } => 9,
125             Aapcs => 10,
126             Win64 => 11,
127             SysV64 => 12,
128             PtxKernel => 13,
129             Msp430Interrupt => 14,
130             X86Interrupt => 15,
131             AmdGpuKernel => 16,
132             EfiApi => 17,
133             AvrInterrupt => 18,
134             AvrNonBlockingInterrupt => 19,
135             CCmseNonSecureCall => 20,
136             Wasm => 21,
137             // Cross-platform ABIs
138             System { unwind: false } => 22,
139             System { unwind: true } => 23,
140             RustIntrinsic => 24,
141             RustCall => 25,
142             PlatformIntrinsic => 26,
143             Unadjusted => 27,
144         };
145         debug_assert!(
146             AbiDatas
147                 .iter()
148                 .enumerate()
149                 .find(|(_, AbiData { abi, .. })| *abi == self)
150                 .map(|(index, _)| index)
151                 .expect("abi variant has associated data")
152                 == i,
153             "Abi index did not match `AbiDatas` ordering"
154         );
155         i
156     }
157 
158     #[inline]
data(self) -> &'static AbiData159     pub fn data(self) -> &'static AbiData {
160         &AbiDatas[self.index()]
161     }
162 
name(self) -> &'static str163     pub fn name(self) -> &'static str {
164         self.data().name
165     }
166 
generic(self) -> bool167     pub fn generic(self) -> bool {
168         self.data().generic
169     }
170 }
171 
172 impl fmt::Display for Abi {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result173     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
174         match self {
175             abi => write!(f, "\"{}\"", abi.name()),
176         }
177     }
178 }
179