1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
//! The psABIs, as descriptions read by one classifier rather than as one function per ABI.
//!
//! Design: `spec/cross-compile/06-abis.md`, and section 6.7 for the argument this crate exists to settle.
//!
//! # The problem
//!
//! An ABI is the only part of a target where being subtly wrong produces a program that works
//! for months and then does not. Everything else fails loudly: a bad encoding traps, a missing
//! relocation is a link error. A classification that is right for the first eight arguments and
//! wrong for the ninth produces garbage, on one target, in a function nobody changed.
//!
//! `spec/cross-compile/06-abis.md` section 6.1 lists fifteen of them. The compiler implements four by hand at
//! about a thousand lines, and fifteen at that rate is six to ten thousand lines of exactly that
//! kind of code, which is what `spec/cross-compile/02-the-goal.md` claim 3 is written against.
//!
//! # The shape of the answer
//!
//! An ABI is a [`AbiDescription`]: register banks, how a scalar spends them, and two ordered
//! lists of [`Rule`]s saying what an aggregate has to look like and how it travels if it does.
//! [`Call`] reads a description and answers, once per return value and once per argument in
//! order.
//!
//! The rules are not an interpreter for the psABI. The parts that are real algorithms stay as
//! code in [`classify`], and there are four of them across the five ABIs described here. What is
//! data is which of those an ABI uses, in what order, with what limits, and what happens when the
//! registers run out. [`describe`] argues for the split at length, including the case against it.
//!
//! # What is in here and what is not
//!
//! Argument classification and type layout. Not prologue emission, not register allocation
//! constraints, not unwind information, because section 6.7 keeps those as per architecture code
//! with per ABI parameters and says why: an abstraction over them costs more than the
//! duplication it removes.
//!
//! ```
//! use rucc_abi::{Arg, Pass, Scalar, Shape, Slot, abis};
//! use rucc_tuple::TargetTuple;
//!
//! let linux: TargetTuple = "x86_64-linux-gnu".parse().unwrap();
//! let windows: TargetTuple = "x86_64-pc-windows-msvc".parse().unwrap();
//!
//! // Two eight byte integers: two registers on SysV, a hidden pointer on Windows. Same C, same
//! // architecture, different answer, which is the whole reason this is a property of the target
//! // rather than a rule about C.
//! let pieces = rucc_abi::pieces(&[Scalar::integer(8), Scalar::integer(8)]);
//! let shape = Arg::Aggregate(Shape { size: 16, align: 8, pieces: &pieces, complex: false });
//!
//! let mut call = abis::for_target(linux).unwrap().call();
//! assert_eq!(
//! call.argument(&shape),
//! Pass::Pieces(vec![
//! Slot::Integer { offset: 0, size: 8 },
//! Slot::Integer { offset: 8, size: 8 },
//! ])
//! );
//!
//! let mut call = abis::for_target(windows).unwrap().call();
//! assert_eq!(call.argument(&shape), Pass::Reference);
//! ```
// Every public item here is read by somebody bringing up a target who has the psABI document
// open beside it, so an undocumented one is a question they have to answer by reading the body.
pub use Call;
pub use ;
pub use ;
pub use ;
/// The pieces of a record whose members are these, each at the next offset it fits.
///
/// A convenience for building a shape in a test or a tool, and it is here rather than in a test
/// module because the command line tool needs the same thing and two copies of a layout rule is
/// two chances to write one of them differently.
/// The shape of a record whose members are these, sized and aligned the way C would.