Skip to content

Commit 14b0cdc

Browse files
compiler: use arch-dependent AbiMap construction
Use module privacy to make it harder to construct incorrect AbiMaps.
1 parent 4101ec7 commit 14b0cdc

14 files changed

+166
-170
lines changed

compiler/rustc_abi/src/map.rs

Lines changed: 69 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use std::collections::{BTreeMap, BTreeSet};
22

33
use serde_json::Value as JsonValue;
44

5-
use crate::{AbiFromJsonErr, ArmCall, CanonAbi, ExternAbi, InterruptKind};
5+
use crate::{AbiFromJsonErr, ArmCall, CanonAbi, ExternAbi, InterruptKind, X86Call};
66

77
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
88
pub struct AbiMap {
@@ -15,14 +15,16 @@ pub struct AbiMap {
1515
/// ABI used for `extern "rust-cold"`
1616
pub rust_cold: CanonAbi,
1717

18-
// optional abstract ABIs
19-
pub efiapi: Option<CanonAbi>,
18+
// optional architecture-specific ABIs, should always answer a certain way per-arch
19+
efiapi: Option<CanonAbi>,
20+
win64: Option<CanonAbi>,
21+
sysv64: Option<CanonAbi>,
22+
23+
// optional abstract ABIs, these can be very weird
2024
pub stdcall: Option<CanonAbi>,
2125
pub fastcall: Option<CanonAbi>,
2226
pub thiscall: Option<CanonAbi>,
2327
pub vectorcall: Option<CanonAbi>,
24-
pub win64: Option<CanonAbi>,
25-
pub sysv64: Option<CanonAbi>,
2628

2729
// optional concrete ABIs
2830
// arm
@@ -206,6 +208,39 @@ impl AbiMap {
206208
}
207209
}
208210

211+
// construction
212+
213+
impl AbiMap {
214+
pub fn base_for_arch(arch: &str) -> AbiMap {
215+
match arch {
216+
"aarch64" => AbiMap { efiapi: Some(CanonAbi::C), ..Default::default() },
217+
"amdgpu" => AbiMap { gpu_kernel: true, ..Default::default() },
218+
"arm" => AbiMap {
219+
aapcs: true,
220+
efiapi: Some(CanonAbi::Arm(ArmCall::Aapcs)),
221+
..Default::default()
222+
},
223+
"avr" => AbiMap { avr_interrupt: true, ..Default::default() },
224+
"msp430" => AbiMap { msp430_interrupt: true, ..Default::default() },
225+
"nvptx64" => AbiMap { ptx_kernel: true, gpu_kernel: true, ..Default::default() },
226+
"riscv32" | "riscv64" => {
227+
AbiMap { efiapi: Some(CanonAbi::C), riscv_interrupt: true, ..Default::default() }
228+
}
229+
"x86" => {
230+
AbiMap { efiapi: Some(CanonAbi::C), x86_interrupt: true, ..Default::default() }
231+
}
232+
"x86_64" => AbiMap {
233+
efiapi: Some(CanonAbi::X86(X86Call::Win64)),
234+
sysv64: Some(CanonAbi::X86(X86Call::SysV64)),
235+
win64: Some(CanonAbi::X86(X86Call::Win64)),
236+
x86_interrupt: true,
237+
..Default::default()
238+
},
239+
_ => Default::default(),
240+
}
241+
}
242+
}
243+
209244
// deserialization
210245

211246
type JsonObject = serde_json::Map<String, JsonValue>;
@@ -243,31 +278,19 @@ fn extract_bool_abi(
243278
}
244279

245280
impl AbiMap {
246-
pub fn from_json_object(
281+
pub fn from_arch_and_json(
282+
arch: &str,
247283
mut json: JsonObject,
248-
) -> Result<Self, BTreeMap<String, AbiFromJsonErr>> {
284+
) -> (Self, BTreeMap<String, AbiFromJsonErr>) {
249285
// extract all keys we are interested in
250286
let required_c_abis =
251287
["C", "system", "system-varargs"].map(|abi_str| extract_abi_str(&mut json, abi_str));
252288
let rust_cold = extract_abi_str(&mut json, "rust-cold");
253-
let bool_abis = [
254-
// arm...
255-
"aapcs",
256-
"cmse-nonsecure-entry",
257-
// ...gpu...
258-
"gpu-kernel",
259-
"ptx-kernel",
260-
// ...interrupt
261-
"avr-interrupt",
262-
"msp430-interrupt",
263-
"riscv-interrupt",
264-
"x86-interrupt",
265-
]
266-
.map(|abi_str| extract_bool_abi(&mut json, abi_str));
267-
// x86ish
268-
let optional_abis =
269-
["efiapi", "stdcall", "fastcall", "thiscall", "vectorcall", "win64", "sysv64"]
270-
.map(|abi_str| extract_abi_str(&mut json, abi_str));
289+
let bool_abis =
290+
["aapcs", "cmse-nonsecure-entry"].map(|abi_str| extract_bool_abi(&mut json, abi_str));
291+
// x86ish optional ABIs
292+
let optional_abis = ["stdcall", "fastcall", "thiscall", "vectorcall"]
293+
.map(|abi_str| extract_abi_str(&mut json, abi_str));
271294

272295
// accumulate errors
273296
// create an iterator of invalid types and bad parses
@@ -285,28 +308,22 @@ impl AbiMap {
285308
.chain(errs.cloned())
286309
.collect::<BTreeMap<_, _>>();
287310

288-
if error_map.len() > 0 {
289-
Err(error_map)
290-
} else {
291-
// oh? success? merry giftmas! time to unwrap your presents
292-
// these have default ABIs to select
293-
let [c_proper, system, system_varargs] =
294-
required_c_abis.map(|result| result.unwrap().unwrap_or(CanonAbi::C));
295-
let rust_cold = rust_cold.unwrap().unwrap_or(CanonAbi::RustCold);
296-
297-
// these stay options, but shell the Result
298-
let [efiapi, stdcall, fastcall, thiscall, vectorcall, win64, sysv64] =
299-
optional_abis.map(|result| result.unwrap());
300-
301-
// these simplify to booleans
302-
let bool_abis = bool_abis.map(|result| result.unwrap().unwrap_or(false));
303-
// repeat the mantra: arm...
304-
let [aapcs, cmse_nonsecure_entry, bool_abis @ ..] = bool_abis;
305-
// ...gpu...
306-
let [gpu_kernel, ptx_kernel, bool_abis @ ..] = bool_abis;
307-
// ...interrupt
308-
let [avr_interrupt, msp430_interrupt, riscv_interrupt, x86_interrupt] = bool_abis;
309-
Ok(AbiMap {
311+
// oh? success? merry giftmas! time to unwrap your presents
312+
// start with the architectural defaults
313+
let arch_map = AbiMap::base_for_arch(arch);
314+
// these have default ABIs to select
315+
let [c_proper, system, system_varargs] =
316+
required_c_abis.map(|result| result.unwrap().unwrap_or(CanonAbi::C));
317+
let rust_cold = rust_cold.unwrap().unwrap_or(CanonAbi::RustCold);
318+
319+
// these stay options, but shell the Result
320+
let [stdcall, fastcall, thiscall, vectorcall] = optional_abis.map(|result| result.unwrap());
321+
322+
// these simplify to booleans
323+
let bool_abis = bool_abis.map(|result| result.unwrap().unwrap_or(false));
324+
let [aapcs, cmse_nonsecure_entry] = bool_abis;
325+
(
326+
AbiMap {
310327
c_proper,
311328
system,
312329
system_varargs,
@@ -316,26 +333,16 @@ impl AbiMap {
316333
aapcs,
317334
cmse_nonsecure_entry,
318335

319-
// ...gpu...
320-
gpu_kernel,
321-
ptx_kernel,
322-
323-
// ...interrupt
324-
avr_interrupt,
325-
msp430_interrupt,
326-
riscv_interrupt,
327-
x86_interrupt,
328-
329336
// x86-ish
330-
efiapi,
331337
stdcall,
332338
fastcall,
333339
thiscall,
334340
vectorcall,
335-
win64,
336-
sysv64,
337-
})
338-
}
341+
342+
..arch_map
343+
},
344+
error_map,
345+
)
339346
}
340347

341348
// serialization

compiler/rustc_target/src/spec/base/mod.rs

Lines changed: 41 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -40,107 +40,78 @@ pub(crate) mod windows_uwp_gnu;
4040
pub(crate) mod windows_uwp_msvc;
4141
pub(crate) mod xtensa;
4242

43-
use rustc_abi::{AbiMap, ArmCall, CanonAbi, X86Call};
43+
use rustc_abi::{AbiMap, CanonAbi, X86Call};
4444

4545
pub(crate) fn x86_32_abi_map() -> AbiMap {
46-
AbiMap {
47-
system: CanonAbi::C,
48-
system_varargs: CanonAbi::C,
49-
efiapi: Some(CanonAbi::C),
50-
stdcall: Some(CanonAbi::X86(X86Call::Stdcall)),
51-
fastcall: Some(CanonAbi::X86(X86Call::Fastcall)),
52-
thiscall: Some(CanonAbi::X86(X86Call::Thiscall)),
53-
vectorcall: Some(CanonAbi::X86(X86Call::Vectorcall)),
54-
55-
x86_interrupt: true,
56-
57-
..Default::default()
58-
}
46+
let mut map = AbiMap::base_for_arch("x86");
47+
48+
map.stdcall = Some(CanonAbi::X86(X86Call::Stdcall));
49+
map.fastcall = Some(CanonAbi::X86(X86Call::Fastcall));
50+
map.thiscall = Some(CanonAbi::X86(X86Call::Thiscall));
51+
map.vectorcall = Some(CanonAbi::X86(X86Call::Vectorcall));
52+
53+
map
5954
}
6055

6156
pub(crate) fn x86_32_windows_abi_map() -> AbiMap {
62-
AbiMap {
63-
system: CanonAbi::X86(X86Call::Stdcall),
64-
system_varargs: CanonAbi::C,
65-
efiapi: Some(CanonAbi::C),
66-
stdcall: Some(CanonAbi::X86(X86Call::Stdcall)),
67-
fastcall: Some(CanonAbi::X86(X86Call::Fastcall)),
68-
thiscall: Some(CanonAbi::X86(X86Call::Thiscall)),
69-
vectorcall: Some(CanonAbi::X86(X86Call::Vectorcall)),
70-
71-
x86_interrupt: true,
72-
73-
..Default::default()
74-
}
57+
let mut map = AbiMap::base_for_arch("x86");
58+
map.system = CanonAbi::X86(X86Call::Stdcall);
59+
map.system_varargs = CanonAbi::C;
60+
61+
map.stdcall = Some(CanonAbi::X86(X86Call::Stdcall));
62+
map.fastcall = Some(CanonAbi::X86(X86Call::Fastcall));
63+
map.thiscall = Some(CanonAbi::X86(X86Call::Thiscall));
64+
map.vectorcall = Some(CanonAbi::X86(X86Call::Vectorcall));
65+
66+
map
7567
}
7668

7769
// // See commentary in `is_abi_supported`.
7870
// Stdcall { unwind } | Thiscall { unwind } | Fastcall { unwind } => {
7971
// if self.arch == "x86" { abi } else { C { unwind } }
8072
// }
8173
pub(crate) fn x86_64_abi_map() -> AbiMap {
82-
AbiMap {
83-
efiapi: Some(CanonAbi::X86(X86Call::Win64)),
84-
85-
win64: Some(CanonAbi::X86(X86Call::Win64)),
86-
sysv64: Some(CanonAbi::X86(X86Call::SysV64)),
87-
vectorcall: Some(CanonAbi::X86(X86Call::Vectorcall)),
88-
89-
x86_interrupt: true,
90-
91-
..Default::default()
92-
}
74+
let mut map = AbiMap::base_for_arch("x86_64");
75+
map.vectorcall = Some(CanonAbi::X86(X86Call::Vectorcall));
76+
map
9377
}
9478

9579
pub(crate) fn x86_64_windows_abi_map() -> AbiMap {
96-
AbiMap {
97-
rust_cold: CanonAbi::Rust,
80+
let mut map = AbiMap::base_for_arch("x86_64");
81+
map.rust_cold = CanonAbi::Rust;
9882

99-
stdcall: Some(CanonAbi::C),
100-
thiscall: Some(CanonAbi::C),
101-
fastcall: Some(CanonAbi::C),
83+
map.stdcall = Some(CanonAbi::C);
84+
map.fastcall = Some(CanonAbi::C);
85+
map.vectorcall = Some(CanonAbi::X86(X86Call::Vectorcall));
10286

103-
..x86_64_abi_map()
104-
}
87+
map
10588
}
10689

10790
pub(crate) fn aarch64_abi_map() -> AbiMap {
108-
AbiMap { efiapi: Some(CanonAbi::C), ..Default::default() }
91+
AbiMap::base_for_arch("aarch64")
10992
}
11093

11194
pub(crate) fn aarch64_windows_abi_map() -> AbiMap {
112-
AbiMap {
113-
win64: Some(CanonAbi::C),
114-
sysv64: Some(CanonAbi::C),
115-
stdcall: Some(CanonAbi::C),
116-
thiscall: Some(CanonAbi::C),
117-
fastcall: Some(CanonAbi::C),
118-
119-
vectorcall: Some(CanonAbi::C),
120-
121-
..aarch64_abi_map()
122-
}
95+
let mut map = AbiMap::base_for_arch("aarch64");
96+
map.stdcall = Some(CanonAbi::C);
97+
map.fastcall = Some(CanonAbi::C);
98+
map.vectorcall = Some(CanonAbi::C);
99+
map
123100
}
124101

125102
pub(crate) fn arm_abi_map() -> AbiMap {
126-
AbiMap { aapcs: true, efiapi: Some(CanonAbi::Arm(ArmCall::Aapcs)), ..Default::default() }
103+
AbiMap::base_for_arch("arm")
127104
}
128105

129106
pub(crate) fn arm_windows_abi_map() -> AbiMap {
130-
AbiMap {
131-
aapcs: true,
132-
efiapi: Some(CanonAbi::Arm(ArmCall::Aapcs)),
133-
stdcall: Some(CanonAbi::C),
134-
thiscall: Some(CanonAbi::C),
135-
fastcall: Some(CanonAbi::C),
136-
137-
vectorcall: Some(CanonAbi::C),
138-
139-
..Default::default()
140-
}
107+
let mut map = AbiMap::base_for_arch("arm");
108+
map.stdcall = Some(CanonAbi::C);
109+
map.fastcall = Some(CanonAbi::C);
110+
map.vectorcall = Some(CanonAbi::C);
111+
map
141112
}
142113

143114
// bitness-invariant, for now
144115
pub(crate) fn riscv_abi_map() -> AbiMap {
145-
AbiMap { efiapi: Some(CanonAbi::C), riscv_interrupt: true, ..Default::default() }
116+
AbiMap::base_for_arch("riscv32")
146117
}

0 commit comments

Comments
 (0)