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
//! The language an ABI is described in.
//!
//! Design: `spec/cross-compile/06-abis.md` section 6.7.
//!
//! # The argument, restated
//!
//! `spec/cross-compile/06-abis.md` section 6.1 lists fifteen psABIs and the compiler has four of them today,
//! hand written, at about a thousand lines. Fifteen at that rate is six to ten thousand lines of
//! the most bug prone code in a compiler, and `spec/cross-compile/02-the-goal.md` claim 3 says the per target
//! line count outside the target crate and the rule set has to be zero.
//!
//! # Where the line is drawn, and why here
//!
//! The tempting version of this idea is to make everything data, and it does not work. The SysV
//! eightbyte merge is a real algorithm with a real fixed point, the homogeneous aggregate scan
//! walks a list and compares members, and writing either as a table produces an interpreter that
//! is longer than the four functions it replaced and slower than all of them.
//!
//! So the split is between mechanism and policy. The mechanisms are code, in [`crate::classify`],
//! and there are four of them across the five ABIs described here: cut into eightbytes and merge,
//! look for a homogeneous run of floating point members, look for a one or two member aggregate
//! with a floating point member in it, and check the size against a list. The policies are data,
//! and a policy is which mechanisms an ABI applies, in what order, with what limits, and what
//! happens when the registers a mechanism wanted are not there.
//!
//! That split is what makes the count work. The fifth ABI reuses a mechanism and costs a
//! description. The eleventh probably does too. A new mechanism is a real cost and it is paid
//! once per idea rather than once per target, and there are far fewer ideas than targets.
//!
//! # The performance objection
//!
//! Section 6.7 raises it against itself: a compile time decision becoming a run time table walk,
//! on the hot path. Two answers. The classifier runs once per call site and once per function
//! signature rather than once per instruction, so the exposure is bounded, and the descriptions
//! are `const` data reached through a `&'static`, so the branch predictor sees the same rule list
//! for every call in a translation unit.
//!
//! Bounded is a prediction rather than a measurement, and the measurement is `spec/cross-compile/02-the-goal.md`
//! claim 2's benchmark at the migration point. The fallback if it fails is written down in
//! section 6.7: the descriptions stay as the source of truth for the tests and the documentation
//! and the classifiers go back to being hand written, which loses claim 3 and keeps claim 2.
//! Claim 2 outranks claim 3.
use crateFormat;
/// One psABI, completely.
///
/// Everything an ABI decides about how a value travels is in here. What is deliberately not in
/// here is in [`AbiDescription::stack_args`]'s note: prologue emission, register allocation
/// constraints and unwind emission are per architecture code with per ABI parameters, and
/// section 6.7 is explicit that turning those into tables costs more than the duplication.
/// The registers a call starts with.
/// How a scalar spends registers.
/// Where the address of a return value that comes back in memory travels.
/// What a variadic argument does differently.
/// How arguments that did not get a register sit in the argument area.
/// One rule: what an aggregate has to look like, how it travels if it does, and what happens
/// when the registers it wanted are not there.
///
/// The rules are tried in order and the first one whose test matches wins, so a rule list reads
/// the way the psABI document it came from is written: the special cases first, the general size
/// rule after them, and the catch-all last.
/// What an aggregate has to look like for a rule to apply.
///
/// Four of these look inside the aggregate and the rest read its size. The four are the
/// mechanisms of this crate, and the claim in section 6.7 is that the number of them grows much
/// more slowly than the number of ABIs.
/// How a value travels when a rule's test matched.
/// What happens when the registers a rule wanted are not there.
///
/// This is the part of a psABI that is easiest to get wrong and hardest to notice, because every
/// test anybody writes by hand passes few enough arguments that it never comes up. The ninth
/// argument of a call is not classified the way the first one is on three of the five ABIs here.