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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
//! What a classifier is asked about, and what it answers.
//!
//! Design: `spec/cross-compile/06-abis.md` sections 6.2 and 6.7.
//!
//! Everything in this module is deliberately not C. A psABI does not read a C type, it reads a
//! size, an alignment, and where the scalars inside are and whether each one is an integer or a
//! floating point value. Flattening a C type down to that is the compiler's job, because that
//! is where the C type system lives, and every rule after it is the target's.
//!
//! Keeping the boundary there is what lets the descriptions in [`crate::abis`] be data. A rule
//! written over "the members of the struct" would have to know about unions, arrays, bit-fields
//! and anonymous members. A rule written over a flat list of scalars at offsets does not, and
//! every psABI on `spec/cross-compile/06-abis.md` section 6.1's list turns out to be expressible over the flat
//! list.
/// A floating point format.
///
/// The compiler's own [`rucc_base::float::Format`], rather than a copy of it. A format is one
/// fact and it has to be the same fact in a data layout, in a psABI rule and in a constant the
/// front end folded, because those three meet: the layout says a target's `long double` is x87,
/// the ABI rule says an x87 value goes on the stack, and the constant evaluator has to produce
/// eighty bits for it. Two enums with the same variants let those drift apart one variant at a
/// time and the drift shows up as a wrong number rather than as a build error.
///
/// The width and the format are separate facts, which is the trap in `spec/cross-compile/06-abis.md` section
/// 6.2 item 1. An x87 `long double` is eighty bits of value stored in twelve bytes on i386 and
/// sixteen on x86-64, and a `long double` on AArch64 Linux is a different format entirely at the
/// same sixteen bytes. A rule written over the width alone gets both wrong.
pub use Format;
/// What a scalar is, once the ABI is the one asking.
///
/// Signedness is not here. Every ABI in `spec/cross-compile/06-abis.md` section 6.1 passes a value of a given
/// width the same way whichever end of the range it sits at, and the widening a narrow argument
/// gets on the way into a register is a property of the call rather than of the type.
/// One scalar, with the three facts a psABI reads about it.
/// One scalar inside an aggregate, at the offset the layout gave it.
/// An aggregate, as much of it as an ABI cares about.
///
/// The pieces are every scalar in it with arrays and nested records flattened out, in offset
/// order. Padding is not a piece: a hole is described by the offsets on either side of it, which
/// is the form every classification rule is written in.
/// One argument, or one return value, as much of it as an ABI cares about.
/// One register's worth of an aggregate that travels in registers, and which of the object's
/// bytes go in it.
///
/// A slot says what the object's bytes are read as rather than what the program wrote into them.
/// An eightbyte holding two `float`s is a [`Slot::Float`] of [`Format::Double`], because eight
/// bytes of floating point data arrive in one vector register whichever way the program divided
/// them up and the bits are the same either way.
///
/// The offset is carried rather than derived because it cannot be worked out from the run of
/// slots. Two eightbytes are at zero and eight, four `float`s of a homogeneous aggregate are
/// four bytes apart, and `struct { double value; int tag; }` on RISC-V travels in one floating
/// point and one integer register whose bytes are at zero and eight, where the second is not
/// where the first one ended.
/// How one value travels.