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
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
//! The psABIs, as descriptions.
//!
//! Design: `spec/cross-compile/06-abis.md` sections 6.1 to 6.5.
//!
//! Six of the fifteen ABIs on section 6.1's list, which is the four the compiler implements by
//! hand today plus Darwin arm64 and i386 SysV. Darwin arm64 is the point of the first five:
//! section 6.3 argues that it is a separate ABI rather than AAPCS64 with notes, and the two
//! descriptions here differ in exactly two fields, which is what "separate ABI" turns out to mean
//! once the ABI is a described thing.
//!
//! i386 SysV is the point of the sixth. It was added as data with no change under `src/` other
//! than the description itself and the two lines of dispatch, which is what section 6.7's proposal
//! predicted and the first time it has been tested on an ABI that ships rather than on the
//! fixture in `tests/descriptions.rs`. It is also the first description with a four byte register
//! width, which nothing in this crate can observe on it, because an ABI with no argument registers
//! never asks how wide one is. [`Banks::integer_width`] earns its place there anyway: with
//! [`StackArgs::RegisterSized`] it is what says an argument slot on i386 is four bytes and not
//! eight, and that is read by the backend rather than by the classifier.
//!
//! # What the next three cost, which is not nothing
//!
//! The nine that are not here are not here because nothing emits for those targets yet, and the
//! claim this file used to make was that each of them is a description of this size and none of
//! them needs a new mechanism. Writing three of them out is how that claim gets checked, and it
//! does not survive in that form. Two of the three need something the language cannot say. Both
//! are about *which* register rather than about how many, and neither is reachable by adding
//! another [`Test`], which is what makes them mechanisms rather than policies.
//!
//! **A floating point scalar that takes two vector registers.** s390x passes a 128-bit `long
//! double` in an even and odd pair of floating point registers, f0 with f2 or f4 with f6. The
//! model here says a floating point value either fits one vector register, decided by
//! [`Banks::float_width`], or moves to the general purpose bank the way a `long double` does on
//! RISC-V LP64D. There is no third answer, so the aggregate half of s390x is describable today and
//! the `long double` half is not. That is why s390x is still the fixture in
//! `tests/descriptions.rs` and is not dispatched to from [`for_target`]: a description that is
//! right about structures and wrong about one scalar is the almost-right answer this file must
//! not give.
//!
//! **An argument that has to start on an even numbered register.** LoongArch LP64D puts a `long
//! double` in a pair of general purpose registers aligned to an even one, and AAPCS32 puts a
//! 64-bit value in r0 and r1 or in r2 and r3 and never in r1 and r2. A bank here is a count, and a
//! count cannot carry a parity constraint, so an odd number of preceding arguments gives the wrong
//! register on both. LoongArch is otherwise identical to RISC-V LP64D, which is the shape section
//! 6.1 predicted, and identical-except-one-mechanism is still not identical.
//!
//! Neither gap is expensive to close and neither is closed here, because closing a mechanism on
//! behalf of a target with no backend is how a mechanism ends up fitted to a guess. They are
//! written down so the next person to reach for LoongArch finds the reason it is absent rather
//! than the absence.
use ;
use crate;
use crateFormat;
/// SysV AMD64: x86-64 everywhere but Windows.
///
/// The intricate one, and the one every other ABI on the list is simpler than. An aggregate is
/// cut into eightbytes and each eightbyte is classified by merging what reaches into it, so
/// `struct { int a; float b; }` travels in one general purpose register and the `float` with it.
///
/// The x87 `long double` is the other half. As an argument it sits in the argument area and
/// spends no register, because there is no register file it could travel in. As a return value
/// it comes back on the x87 stack, and so does a `_Complex long double` in st(0) and st(1),
/// which is the one place the `_Complex` flag on a shape changes an answer.
pub static SYSV_AMD64: AbiDescription = AbiDescription ;
/// The shared part of [`AAPCS64`] and [`DARWIN_ARM64`].
///
/// A constant rather than a second copy of the rules, so that "Darwin arm64 differs in two
/// fields" is a fact the file states rather than a claim the reader has to check by diffing.
const AAPCS64_BASE: AbiDescription = AbiDescription ;
/// AAPCS64: AArch64 everywhere but Darwin and Windows.
///
/// Cleaner than SysV and with one idea SysV does not have. An aggregate of at most sixteen bytes
/// travels in general purpose registers, one per eightbyte, and anything larger travels as the
/// address of a copy the caller made. The exception is the homogeneous floating point aggregate:
/// up to four members, all the same floating point type and nothing else in it, in consecutive
/// vector registers. `struct { float x, y, z; }` is three vector registers, and adding one `int`
/// to it makes it eight bytes in one general purpose register instead.
///
/// The draining is what makes it easy to get wrong. An aggregate that wants more registers than
/// are left does not fall back to fewer of them: it goes in the argument area and takes the rest
/// of that bank with it, so the ninth argument of a call is not classified the way the first one
/// is.
pub static AAPCS64: AbiDescription = AAPCS64_BASE;
/// Darwin arm64: macOS and iOS on AArch64.
///
/// Two fields different from [`AAPCS64`], and `spec/cross-compile/06-abis.md` section 6.3 explains why those
/// two are enough to make it a separate ABI rather than a footnote on that one.
///
/// A variadic argument is always in the argument area, whatever registers are left. That is why
/// a variadic call here is ABI-incompatible with a non-variadic one, which means calling an
/// unprototyped function works right up until the day it does not, and it is why `printf("%d",
/// x)` prints garbage on a compiler that got this wrong and nothing else does.
///
/// Stack arguments are packed at their natural size rather than taking a register's worth each,
/// so a function with more than eight arguments returns garbage from the ninth onward if the
/// backend assumed otherwise. Nothing in this crate reads that field; it is here because the
/// backend that does read it should be reading it from the same description the tests are
/// generated from.
///
/// The third divergence, `long double` being a `double`, is in the data layout rather than here,
/// because it is a fact about the type and not about how a value of the type travels. The
/// fourth, x18 being reserved, is a register allocation constraint and `spec/cross-compile/06-abis.md` section
/// 6.7 keeps those as code.
pub static DARWIN_ARM64: AbiDescription = AbiDescription ;
/// Windows x64.
///
/// The simplest of the five and the one with the sharpest rule: anything not exactly one, two,
/// four or eight bytes travels as the address of a copy the caller made, so a three byte
/// structure and a three hundred byte structure are passed identically. There is no
/// classification to do and no pair of registers to fill.
///
/// An aggregate that does fit travels as an integer of its size whatever is in it, so a
/// `struct { float x, y; }` arrives in rcx. That is the other half of the shared bank: rcx, rdx,
/// r8 and r9 are the four positions an integer can use, xmm0 to xmm3 are the four a floating
/// point value can use, and they are the same four positions, so a call taking an `int` and then
/// a `double` uses rcx and xmm1 and never xmm0.
///
/// The 32 bytes of shadow space the caller allocates for those four registers, whether or not
/// the callee uses them, is a frame fact and lives with the frame code. Forgetting it corrupts
/// the caller's frame, which is `spec/cross-compile/06-abis.md` section 6.4's first bullet and a good reason
/// for the description to say so somewhere the frame code can find it.
pub static WIN64: AbiDescription = AbiDescription ;
/// The RISC-V LP64D psABI.
///
/// Two eightbytes for an aggregate that fits, an address for one that does not, and one rule
/// with no analogue in the other four: an aggregate of one or two floating point members travels
/// in floating point registers, and one of a floating point member and an integer member travels
/// in one of each. `struct { double re, im; }` is fa0 and fa1, and `struct { double value; int
/// tag; }` is fa0 and a0.
///
/// The rule stops where the registers do. A `long double` on this ABI is sixteen bytes and a
/// floating point register is eight, so a `long double` is not a floating point member for this
/// purpose and the aggregate holding it is an integer pair like anything else. That single fact
/// is the whole difference between this description and one for LoongArch LP64D, which is why
/// section 6.1 calls that one close to this one.
pub static RISCV_LP64D: AbiDescription = AbiDescription ;
/// The i386 System V psABI: 32-bit x86 on Linux and the other ELF systems.
///
/// The one with no argument registers at all. Every argument is in the argument area, in source
/// order, each rounded up to four bytes, and every aggregate return value comes back in memory
/// through a hidden first argument. There is no classification left to do once that is said,
/// which is why this description is the shortest one in the file and why it is the one worth
/// having: an ABI whose answer is always the same is still an ABI, and a target with no
/// description gets no answer rather than the easy one.
///
/// Both bank sizes are zero and both register widths are set anyway. The widths are not read by
/// the classifier here, because an ABI with no argument registers never asks how wide one is, and
/// they are not zero because [`Banks::integer_width`] is what tells the backend that an argument
/// slot on i386 is four bytes rather than eight, and because a vector register holding nothing is
/// a statement the property test in `tests/descriptions.rs` refuses on every description rather
/// than carrying an exception for this one.
///
/// The `long double` here is the eighty bit x87 one, twelve bytes and four byte aligned, and it
/// travels in the argument area like everything else. That makes [`Scalars::in_memory`]
/// unnecessary rather than wrong: the field exists to move a scalar off a register bank, and
/// there is no bank to move it off.
///
/// Returning a small structure in edx:eax is a real convention and it is not this one. GCC calls
/// it `-freg-struct-return`, Darwin and some BSDs default to it, and Linux does not, so the
/// return list below says memory for every size. Getting that backwards is the failure this crate
/// exists to avoid, and it is why the dispatch below answers for the ELF systems and declines
/// i686 Windows, whose stdcall and fastcall decoration is a different ABI wearing the same
/// architecture.
pub static I386_SYSV: AbiDescription = AbiDescription ;
/// Every ABI described here, which is what the report and the tests iterate.
pub static DESCRIBED: & =
&;
/// The ABI this target follows, and [`None`] for one whose ABI is not described yet.
///
/// [`None`] is a real answer rather than a gap to be filled in with a guess. `spec/cross-compile/04-target-matrix.md`
/// section 4.2 has a tier for a target the compiler knows about and cannot emit for, and
/// answering with the wrong ABI is the one failure mode `spec/cross-compile/06-abis.md` opens by naming: a
/// program that works for months and then does not.