]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_target/src/spec/abi.rs
Rollup merge of #82497 - jyn514:json, r=CraftSpider
[rust.git] / compiler / rustc_target / src / spec / abi.rs
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
38     // Multiplatform / generic ABIs
39     System { unwind: bool },
40     RustIntrinsic,
41     RustCall,
42     PlatformIntrinsic,
43     Unadjusted,
44 }
45
46 #[derive(Copy, Clone)]
47 pub struct AbiData {
48     abi: Abi,
49
50     /// Name of this ABI as we like it called.
51     name: &'static str,
52
53     /// A generic ABI is supported on all platforms.
54     generic: bool,
55 }
56
57 #[allow(non_upper_case_globals)]
58 const AbiDatas: &[AbiData] = &[
59     // Cross-platform ABIs
60     AbiData { abi: Abi::Rust, name: "Rust", generic: true },
61     AbiData { abi: Abi::C { unwind: false }, name: "C", generic: true },
62     AbiData { abi: Abi::C { unwind: true }, name: "C-unwind", generic: true },
63     // Platform-specific ABIs
64     AbiData { abi: Abi::Cdecl, name: "cdecl", generic: false },
65     AbiData { abi: Abi::Stdcall { unwind: false }, name: "stdcall", generic: false },
66     AbiData { abi: Abi::Stdcall { unwind: true }, name: "stdcall-unwind", generic: false },
67     AbiData { abi: Abi::Fastcall, name: "fastcall", generic: false },
68     AbiData { abi: Abi::Vectorcall, name: "vectorcall", generic: false },
69     AbiData { abi: Abi::Thiscall { unwind: false }, name: "thiscall", generic: false },
70     AbiData { abi: Abi::Thiscall { unwind: true }, name: "thiscall-unwind", generic: false },
71     AbiData { abi: Abi::Aapcs, name: "aapcs", generic: false },
72     AbiData { abi: Abi::Win64, name: "win64", generic: false },
73     AbiData { abi: Abi::SysV64, name: "sysv64", generic: false },
74     AbiData { abi: Abi::PtxKernel, name: "ptx-kernel", generic: false },
75     AbiData { abi: Abi::Msp430Interrupt, name: "msp430-interrupt", generic: false },
76     AbiData { abi: Abi::X86Interrupt, name: "x86-interrupt", generic: false },
77     AbiData { abi: Abi::AmdGpuKernel, name: "amdgpu-kernel", generic: false },
78     AbiData { abi: Abi::EfiApi, name: "efiapi", generic: false },
79     AbiData { abi: Abi::AvrInterrupt, name: "avr-interrupt", generic: false },
80     AbiData {
81         abi: Abi::AvrNonBlockingInterrupt,
82         name: "avr-non-blocking-interrupt",
83         generic: false,
84     },
85     AbiData { abi: Abi::CCmseNonSecureCall, name: "C-cmse-nonsecure-call", generic: false },
86     // Cross-platform ABIs
87     AbiData { abi: Abi::System { unwind: false }, name: "system", generic: true },
88     AbiData { abi: Abi::System { unwind: true }, name: "system-unwind", generic: true },
89     AbiData { abi: Abi::RustIntrinsic, name: "rust-intrinsic", generic: true },
90     AbiData { abi: Abi::RustCall, name: "rust-call", generic: true },
91     AbiData { abi: Abi::PlatformIntrinsic, name: "platform-intrinsic", generic: true },
92     AbiData { abi: Abi::Unadjusted, name: "unadjusted", generic: true },
93 ];
94
95 /// Returns the ABI with the given name (if any).
96 pub fn lookup(name: &str) -> Option<Abi> {
97     AbiDatas.iter().find(|abi_data| name == abi_data.name).map(|&x| x.abi)
98 }
99
100 pub fn all_names() -> Vec<&'static str> {
101     AbiDatas.iter().map(|d| d.name).collect()
102 }
103
104 impl Abi {
105     #[inline]
106     pub fn index(self) -> usize {
107         // N.B., this ordering MUST match the AbiDatas array above.
108         // (This is ensured by the test indices_are_correct().)
109         use Abi::*;
110         let i = match self {
111             // Cross-platform ABIs
112             Rust => 0,
113             C { unwind: false } => 1,
114             C { unwind: true } => 2,
115             // Platform-specific ABIs
116             Cdecl => 3,
117             Stdcall { unwind: false } => 4,
118             Stdcall { unwind: true } => 5,
119             Fastcall => 6,
120             Vectorcall => 7,
121             Thiscall { unwind: false } => 8,
122             Thiscall { unwind: true } => 9,
123             Aapcs => 10,
124             Win64 => 11,
125             SysV64 => 12,
126             PtxKernel => 13,
127             Msp430Interrupt => 14,
128             X86Interrupt => 15,
129             AmdGpuKernel => 16,
130             EfiApi => 17,
131             AvrInterrupt => 18,
132             AvrNonBlockingInterrupt => 19,
133             CCmseNonSecureCall => 20,
134             // Cross-platform ABIs
135             System { unwind: false } => 21,
136             System { unwind: true } => 22,
137             RustIntrinsic => 23,
138             RustCall => 24,
139             PlatformIntrinsic => 25,
140             Unadjusted => 26,
141         };
142         debug_assert!(
143             AbiDatas
144                 .iter()
145                 .enumerate()
146                 .find(|(_, AbiData { abi, .. })| *abi == self)
147                 .map(|(index, _)| index)
148                 .expect("abi variant has associated data")
149                 == i,
150             "Abi index did not match `AbiDatas` ordering"
151         );
152         i
153     }
154
155     #[inline]
156     pub fn data(self) -> &'static AbiData {
157         &AbiDatas[self.index()]
158     }
159
160     pub fn name(self) -> &'static str {
161         self.data().name
162     }
163
164     pub fn generic(self) -> bool {
165         self.data().generic
166     }
167 }
168
169 impl fmt::Display for Abi {
170     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
171         match self {
172             abi => write!(f, "\"{}\"", abi.name()),
173         }
174     }
175 }