Skip to main content

rucc_codegen/
combine.rs

1//! Putting a run of machine instructions together into the shorter run the machine has for it.
2//!
3//! Design: `spec/10-backend.md` section 10.9, and `spec/optimizer/37-machine-level-optimization.md`
4//! sections 37.3 and 37.4.
5//!
6//! Section 37.4 names this pass first of the ten it says are genuinely machine level, and says what
7//! shape it should be: a match over machine instructions in SSA form, inside one block, over a
8//! window of a few instructions, which is `gcc/late-combine.cc` rather than `gcc/combine.cc`. The
9//! reason for the smaller of the two is in the same section. Combine is fifteen thousand lines
10//! because it was written without def-use chains and had to find them again each time, and every
11//! RTL pass GCC has written since is on the SSA form it added later for exactly that.
12//!
13//! Section 37.3 says what the pass does once it has found a run: substitute the earlier instruction
14//! into the later one, and ask the machine description whether what came out is an instruction this
15//! target has. That is [`crate::changes`] and this pass does not repeat any of it.
16//!
17//! # The runs it puts together
18//!
19//! Two of them. A value read out of memory and then used once, by arithmetic that this machine
20//! could have read it out of memory itself, which is [`loads`]:
21//!
22//! ```text
23//!   movq 16(%rax), %rcx
24//!   addq %rcx, %rdx        ->    addq 16(%rax), %rdx
25//! ```
26//!
27//! Two instructions become one. The register the load wrote is not written at all, which is one
28//! fewer value for the allocator to find a place for, and the bytes come down because an addressing
29//! mode costs what it costs whichever instruction carries it and the load's own opcode byte goes.
30//!
31//! It is the commonest pair in the machine IR this compiler writes. Counting adjacent instructions
32//! over the corpus at `-O2`, where the first writes what the second reads, the largest family by a
33//! long way is a move into arithmetic, and an addition at eight bytes is the largest single entry
34//! in it. What the pass gets over that corpus is 865 of these at `-O2` and 845 fewer instructions
35//! once the allocator has had its say, with the difference between the two explained below.
36//!
37//! And the same value written back where it came from, which is [`stores`]:
38//!
39//! ```text
40//!   movq 16(%rax), %rcx
41//!   addq %rdx, %rcx        ->    addq %rdx, 16(%rax)
42//!   movq %rcx, 16(%rax)
43//! ```
44//!
45//! Three instructions become one, and this is what a C program writes as `*p += x`. The register in
46//! the middle goes the way the load's register goes above, and so does the second addressing mode,
47//! which was the same address written down twice.
48//!
49//! [`stores`] takes the same run with a constant in it, which is what a C program writes as
50//! `*p += 1` and is the commoner of the two:
51//!
52//! ```text
53//!   movq 16(%rax), %rcx
54//!   addq $1, %rcx          ->    addq $1, 16(%rax)
55//!   movq %rcx, 16(%rax)
56//! ```
57//!
58//! Nothing is left holding a register here at all. The instruction that comes out reads the place,
59//! adds the constant the instruction carries and writes the place, so the whole run costs the
60//! addressing mode and the constant and no operand the allocator has to answer for.
61//!
62//! [`stores`] runs first. Its run is three instructions as the selector wrote them, and folding the
63//! load into the middle one first would leave the same run written a second way that the walk would
64//! then have to know about. Whatever it does not take is still a pair for [`loads`].
65//!
66//! # Why no rule does it
67//!
68//! The selector matches a term, and a term is one value. A load is a term and an addition is a
69//! term, and the pattern that would cover both is an addition with a load under it, which the
70//! selector does offer: it shows a rule the operands of its operands. What it cannot offer is the
71//! rest of the condition. Whether the load may move down to where the addition is depends on what
72//! is written between the two, and whether the load's value is wanted anywhere else depends on the
73//! whole function. Neither is a fact about the term, so neither can be in a pattern.
74//!
75//! # When the load may move
76//!
77//! The load stops being where it was and starts being part of an instruction further down the
78//! block, so everything between the two has to be something the load can pass. Two things are not.
79//!
80//! Anything that touches memory, whether it reads or writes. A write is the obvious half: whether
81//! it writes the bytes this load reads is a question about two addresses, and telling two addresses
82//! apart is an analysis nothing below selection has, so the walk below stops at a store rather than
83//! guessing. [`MachineInsts::touches_mem`] is the target's answer and [`MachineInsts::calls`] is the
84//! rest of it, since what a call does to memory is not in the instruction at all.
85//!
86//! A read is the half that is easy to argue away and is the one that matters. Moving a read past a
87//! read changes the order two accesses happen in, and the program may have said what that order is.
88//! `volatile int a, b; return b - a;` is two loads and a subtract, and folding the first of them
89//! into the subtract would read `b` before `a` when the program said otherwise. The flag that says
90//! so reaches here now, so the walk could ask about each access one at a time, and it does not:
91//! stopping at every access rules the same thing out and costs almost nothing, since the load the
92//! arithmetic reads is nearly always the last access before it and so is still the one that folds.
93//!
94//! What follows from that is the shape of the walk. There is one load in hand rather than a list of
95//! them, and it is always the last memory access there was.
96//!
97//! Anything that writes a register the address reads. Machine IR is in SSA form until the
98//! allocator has run, so a virtual register cannot be written twice, but the stack pointer and the
99//! frame pointer are physical here and an address into the frame reads one of them.
100//!
101//! # When the load is wanted elsewhere
102//!
103//! Exactly one instruction may read what the load wrote, and it has to be the one taking the load
104//! in. [`Reads`] is that count, kept across the commits of the pass the way [`crate::fold`] keeps
105//! it, and a count of one is the whole of the test because a virtual register is written once. Two
106//! readers and the load has to stay where it is, so putting it into one of them buys nothing and
107//! costs a second read of memory.
108//!
109//! An argument an edge carries is a read like any other and is in no operand vector, which is the
110//! one place a count of this shape is easy to get wrong. [`Reads::of`] counts those, which is what
111//! keeps a load whose value leaves the block out of this.
112//!
113//! # Which arithmetic
114//!
115//! [`FOLDS`] is the list, and it is a list rather than a rule about names because the two ends of
116//! each entry are instructions the target describes separately and the widths have to agree. A
117//! sixty four bit addition takes a sixty four bit load and nothing else: reading four bytes where
118//! the program asked for eight is a different instruction, and reading eight where it asked for
119//! four is three bytes nobody said were there.
120//!
121//! The eight bit multiply is the one member of the family with no entry. This machine has no
122//! two-operand multiply narrower than sixteen bits, so an eight bit one is written as a thirty two
123//! bit `imul` and reads a register whose upper bits nothing looks at. A memory operand has no
124//! upper bits to not look at, so there is nothing to read there and the entry is left out.
125//!
126//! # Either source, when the operation does not care
127//!
128//! An addition reads two registers and it is the second of them the memory operand replaces,
129//! because the first is the one the destination is tied to. Where the load feeds the first instead,
130//! the two sources are swapped first, which is a change to the instruction and not to what it
131//! computes as long as the operation commutes. Five of the six here do and subtraction does not,
132//! which is what [`Fold::swapped`] says.
133//!
134//! # Which comparisons
135//!
136//! The comparisons are in [`FOLDS`] too, and they are the reason that field is a name rather than
137//! a flag. A comparison writes a byte neither source has a claim on, so both of its sources are
138//! free the way an addition's second one is, and it still does not commute: the machine reads the
139//! right hand side out of memory and subtracts it from the left. What saves the other arrangement
140//! is that reading the two sides backwards asks the same question backwards, so a load feeding the
141//! left hand side becomes the same instruction with the condition turned over, and `*p < x` is
142//! `x > *p`. Equality and inequality turn over into themselves and the other eight go in pairs.
143//!
144//! A comparison against a constant has one register rather than two and folds too, which is what
145//! a C program writes as `if (*p == 7)`:
146//!
147//! ```text
148//!   movl 16(%rax), %ecx
149//!   cmpl $7, %ecx          ->    cmpl $7, 16(%rax)
150//! ```
151//!
152//! Nothing is arranged either way round here. The constant is on the instruction and has nowhere
153//! else to be, so the side the load filled is the left hand side and stays the left hand side, and
154//! the condition is the one the comparison already had. What is left holding a register is the byte
155//! the comparison sets, and the block layout usually takes that too.
156//!
157//! # A widening
158//!
159//! A load that is read only to be widened is the same pair with one source, and this machine reads
160//! memory and widens it in one instruction. It is what a C program gets for `long x = a[i];` on an
161//! array of `int`, and for every `char` or `short` read into an `int`:
162//!
163//! ```text
164//!   movl (%rcx,%rax,4), %eax
165//!   movslq %eax, %rax      ->    movslq (%rcx,%rax,4), %rax
166//! ```
167//!
168//! [`WIDENINGS`] is the list: a sign and a zero widening from each width that has one, and the zero
169//! widening from thirty two bits to sixty four. That last one is a plain `movl` between registers,
170//! because writing the low half of a register clears the high half, and a `movl` from memory does
171//! the same, so what comes out of it is the load on its own writing the wider register.
172//!
173//! The rules are the ones above. The widening has to be the only reader of the load, and nothing
174//! between the two may touch memory. It is a table of its own rather than more rows of [`FOLDS`]
175//! because a widening reads one width and writes another, which is the one thing every row of that
176//! table is checked not to do.
177//!
178//! # What a `volatile` access gets
179//!
180//! Nothing. Both walks stop at one, so `volatile int *p; *p += x;` comes out as the load, the
181//! arithmetic and the store, and `volatile int *p; return *p + x;` keeps its load.
182//!
183//! What the flag says is that the access happens exactly once and is never moved or merged with
184//! another, and the first two of those were already true here: the walk in [`loads`] stops at any
185//! instruction that touches memory, so nothing ever passes an access, and no fold in this module
186//! turns one access into two or none. Merging is the one that was not. Reading a place, adding to
187//! it and putting it back is one read and one write of the address whether it is three
188//! instructions or one, so the counts the standard talks about are the same either way, and what
189//! the two differ on is whether the reading and the writing are one instruction. A device register
190//! whose memory does something when it is touched is where that difference is the whole point.
191//!
192//! This is a place where the answer is the spec's rather than the reference compiler's.
193//! `spec/optimizer/09-memory-ssa.md` section 9.5 says a `volatile` access is never moved, never
194//! eliminated, never duplicated and never merged, and that last word is this. GCC 16 writes
195//! `addl %esi, (%rdi)` for the read modify write and `cmpl $7, (%rdi)` for a `volatile` compare,
196//! and GCC 13 writes three instructions and two for the same programs, so the merge is something
197//! GCC started doing rather than something it has always done. Both are conforming and neither
198//! changes how many times the address is touched. Taking the spec's side costs an instruction on
199//! code that asked to be watched, which is the trade that document says to make.
200//!
201//! The flag is on the machine instruction because [`rucc_mir::Flags`] carries it now and selection
202//! sets it from the load or the store it matched. Before that it could not be read here at all:
203//! a `volatile` access and an ordinary one were the same opcode over the same address, so there
204//! was nothing to stop at. That was tamnd/rucc#1302.
205//!
206//! # What makes the three one
207//!
208//! The same three questions as the pair, and one more. The word the load read is read by the
209//! arithmetic and by nothing else, the answer the arithmetic wrote is read by the store and by
210//! nothing else, and nothing between the load and the store touches memory or writes a register the
211//! instruction that is left still reads. The run collapses onto the store, so the read of memory
212//! moves down the block to where the write already was, which is the move the memory rule is about.
213//!
214//! The one more is that the two addressing modes have to name the same place. The same registers,
215//! the same scale, the same displacement and the same symbol is most of it, and the frame is the
216//! rest: the displacement of a local is a number [`crate::finish`] has still to add the frame's own
217//! offset to, so two locals can be the same three registers and the same zero here and be two
218//! different places. The list itself is what tells those apart, and the entry the load was
219//! waiting on comes off the list when the run is joined, since the store is already waiting on the
220//! same one.
221//!
222//! # The condition state, which the three has and the pair does not
223//!
224//! The arithmetic in the middle of the run is not where it was afterwards. The run collapses onto
225//! the store, so the load moves down and so does the arithmetic, and the arithmetic writes the
226//! condition state where the load writes nothing. That makes the state a question here and not in
227//! [`loads`], where the arithmetic stays exactly where it is and only a load passes anything.
228//!
229//! Two ways it goes wrong, and both are about the instructions between the arithmetic and the
230//! store. An instruction there that reads the state read what the arithmetic left, and after the
231//! move it reads whatever was there before the arithmetic instead. An instruction there that writes
232//! the state was the last writer before the store, and after the move the arithmetic is, so
233//! anything further down that reads the state reads a different answer. So neither is allowed, and
234//! `quiet` is the question. It is asked from the arithmetic rather than from the load, because
235//! between the load and the arithmetic nothing has moved and the state is nobody's business.
236//!
237//! This is what tamnd/rucc#1424 was. libgmp's `mpn_mulmod_bnm1` adds a limb into a place and then
238//! reads the carry out of that addition with `adcq %rdx, %rdx`, which is how this back end gets a
239//! carry into a register, and the addition and the store it fed were a run with the carry reader
240//! sitting between them. Folding them moved the addition below the reader, so the carry that went
241//! into the next limb was the one a `subq` three instructions earlier had left, and the library
242//! computed a product that was wrong in one limb. It came back as a division that never finished,
243//! a long way from here.
244//!
245//! [`rucc_target::FlagInsts`] is where the answer comes from, the same description
246//! [`crate::compare`] and [`crate::shorten`] ask, and a name it does not cover counts as both a
247//! read and a write, which is the answer that finds fewer runs rather than the one that is wrong.
248//!
249//! # The window
250//!
251//! A load is carried forward at most [`WINDOW`] instructions and then dropped. The bound is what
252//! makes the pass cost a fixed amount per instruction rather than an amount that grows with the
253//! block, which section 37.3 records as GCC's own answer: `max-combine-insns` is four and has been
254//! for decades.
255//!
256//! It is also nearly all of it already at one. The measurement in [`WINDOW`] is that a bound of one
257//! finds 852 folds over the corpus and a bound of thirty two finds 865, which follows from the rule
258//! above about memory rather than from anything about how the selector writes code: the load that
259//! folds is the last access to memory before the arithmetic, and the last access before it is
260//! usually the instruction in front of it. The window is there to bound the walk and it earns
261//! thirteen folds along the way.
262//!
263//! # Where it costs something
264//!
265//! A fold takes out exactly one instruction, so the number of folds and the number of instructions
266//! saved should be the same number, and they are not: 865 folds against 845 instructions over the
267//! corpus at `-O2`, and 1609 against 1444 over the SQLite amalgamation. The gap is the allocator.
268//!
269//! Taking the load out changes which values are live where, so the allocator makes different
270//! choices, and a few of them are worse. Two programs in the corpus come out two instructions
271//! longer at every level above `-O0`, both for the same reason: the folded addition is given a
272//! callee saved register while a caller saved one was free, which buys a push, a pop and a copy for
273//! a value that dies before the next call. That is the allocator preferring the wrong end of its
274//! own list rather than anything this pass did, and it is worth fixing where it is rather than
275//! worth not folding over.
276//!
277//! The trade is the other thing the gap is, and it is a real one rather than an accounting error.
278//! Two instructions become one and the one that is left both reads memory and computes, so it is
279//! two operations in one slot rather than one, which a machine that issues several instructions at
280//! once may not want. The measurement that settles it is run time rather than instruction count,
281//! and section 38.6's scheduler is where that argument belongs, since a scheduler is the pass that
282//! can see whether the slot was going to be used.
283//!
284//! # What it does not do yet
285//!
286//! A comparison. This machine compares against memory as readily as it adds to it, and the reason
287//! there is no entry for one is that a comparison here is one opcode holding a compare and the byte
288//! behind it, so the memory form is a third instruction rather than a second and the target has to
289//! describe it before this can write it.
290//!
291//! Arithmetic against a constant, in either run. `addq $1, 16(%rcx)` is `*p += 1`, which is at
292//! least as common as `*p += x`, and the target has no form that carries an addressing mode and an
293//! immediate together. That is a third instruction description rather than a rule, the way the
294//! comparison above is.
295//!
296//! Anything longer than the two runs above. Section 37.3 says GCC goes to four instructions, and
297//! the longer of the two here is three. What makes a fourth worth having is a rule set that has
298//! something to say about four, and the rule set here grows one measured entry at a time.
299
300use std::collections::HashMap;
301
302use rucc_base::Interner;
303use rucc_mir::{Amode, Flags, Func, Inst, Opcode, Operand, Reg};
304use rucc_target::{FlagInsts, MachineInsts};
305
306use crate::changes::{Changes, Plan, Reads};
307use crate::fold::Pending;
308
309/// How far a load is carried looking for the instruction that takes it in.
310///
311/// Measured over the corpus at `-O2`, which folds this many loads at each bound:
312///
313/// ```text
314///   1     2     4     8    16    32
315/// 852   858   863   864   865   865
316/// ```
317///
318/// Sixteen, because that is where the curve stops. Doubling it again finds nothing, and the pass
319/// still costs a fixed amount per instruction, which is what the bound is for.
320///
321/// The curve is that flat because of the rule about memory rather than because of anything the
322/// selector does. The load that folds is the last access to memory before the arithmetic, and
323/// almost always that is the instruction immediately in front of it. What the room past one buys is
324/// the thirteen where a register was written or a constant made in between.
325pub const WINDOW: usize = 16;
326
327/// One arithmetic instruction that could read its second source out of memory, and the load that
328/// would fill it.
329///
330/// A table rather than a rule about spellings, because the three names in each row are three things
331/// the target describes on their own and nothing about `add_rr_64` says that `mov_rm_64` is the
332/// load of the same width. Writing the three together is what makes a mismatched width a line
333/// somebody can see rather than a string that was built at run time.
334#[derive(Debug, Clone, Copy, PartialEq, Eq)]
335pub struct Fold {
336    /// The arithmetic as the selector wrote it, reading both its sources from registers.
337    pub from: &'static str,
338    /// The same arithmetic reading its second source out of memory.
339    pub into: &'static str,
340    /// The load that would have filled that register, which has to be of the same width.
341    pub load: &'static str,
342    /// The same arithmetic reading its first source out of memory, where there is one.
343    ///
344    /// [`None`] where the two sources may not be swapped at all, which is subtraction: the
345    /// instruction that reads memory reads it as the right hand side and there is no encoding
346    /// that puts it on the left, so a load feeding the left hand side stays where it is. Also
347    /// [`None`] for a comparison against a constant, which has one source rather than two and so
348    /// nothing to swap it with.
349    ///
350    /// The same name as `into` for an operation that commutes, since writing the two sources in
351    /// either order computes the same answer and one instruction covers both.
352    ///
353    /// A different name for a comparison, which is the reason this is a name rather than a flag.
354    /// A comparison does not commute and is still foldable on either side: reading the two sides
355    /// the other way round asks the same question backwards, so the condition turns over with
356    /// them and `a < b` with the load on the left is `b > a`.
357    pub swapped: Option<&'static str>,
358}
359
360/// The arithmetic a load can move into on this machine.
361///
362/// Every two-address integer operation the target has, at every width it has one, except the eight
363/// bit multiply the module documentation gives the reason for. Subtraction is the one that does not
364/// commute.
365///
366/// And then the comparisons, which are not arithmetic and fold the same way. What one writes is a
367/// byte rather than one of its sources, so the row reads the same and the instruction it names has
368/// a destination neither side has a claim on. The forty rows are ten conditions at four widths and
369/// each names two instructions, because which side the memory is is a condition of its own.
370///
371/// And then the same forty against a constant, which name one instruction each. The constant is on
372/// the instruction and cannot be anywhere else, so the register the load filled is the left hand
373/// side and there is no other arrangement to offer.
374pub static FOLDS: &[Fold] = &[
375    Fold { from: "add_rr_8", into: "add_rm_8", load: "mov_rm_8", swapped: Some("add_rm_8") },
376    Fold { from: "add_rr_16", into: "add_rm_16", load: "mov_rm_16", swapped: Some("add_rm_16") },
377    Fold { from: "add_rr_32", into: "add_rm_32", load: "mov_rm_32", swapped: Some("add_rm_32") },
378    Fold { from: "add_rr_64", into: "add_rm_64", load: "mov_rm_64", swapped: Some("add_rm_64") },
379    Fold { from: "sub_rr_8", into: "sub_rm_8", load: "mov_rm_8", swapped: None },
380    Fold { from: "sub_rr_16", into: "sub_rm_16", load: "mov_rm_16", swapped: None },
381    Fold { from: "sub_rr_32", into: "sub_rm_32", load: "mov_rm_32", swapped: None },
382    Fold { from: "sub_rr_64", into: "sub_rm_64", load: "mov_rm_64", swapped: None },
383    Fold { from: "and_rr_8", into: "and_rm_8", load: "mov_rm_8", swapped: Some("and_rm_8") },
384    Fold { from: "and_rr_16", into: "and_rm_16", load: "mov_rm_16", swapped: Some("and_rm_16") },
385    Fold { from: "and_rr_32", into: "and_rm_32", load: "mov_rm_32", swapped: Some("and_rm_32") },
386    Fold { from: "and_rr_64", into: "and_rm_64", load: "mov_rm_64", swapped: Some("and_rm_64") },
387    Fold { from: "or_rr_8", into: "or_rm_8", load: "mov_rm_8", swapped: Some("or_rm_8") },
388    Fold { from: "or_rr_16", into: "or_rm_16", load: "mov_rm_16", swapped: Some("or_rm_16") },
389    Fold { from: "or_rr_32", into: "or_rm_32", load: "mov_rm_32", swapped: Some("or_rm_32") },
390    Fold { from: "or_rr_64", into: "or_rm_64", load: "mov_rm_64", swapped: Some("or_rm_64") },
391    Fold { from: "xor_rr_8", into: "xor_rm_8", load: "mov_rm_8", swapped: Some("xor_rm_8") },
392    Fold { from: "xor_rr_16", into: "xor_rm_16", load: "mov_rm_16", swapped: Some("xor_rm_16") },
393    Fold { from: "xor_rr_32", into: "xor_rm_32", load: "mov_rm_32", swapped: Some("xor_rm_32") },
394    Fold { from: "xor_rr_64", into: "xor_rm_64", load: "mov_rm_64", swapped: Some("xor_rm_64") },
395    Fold { from: "imul_rr_16", into: "imul_rm_16", load: "mov_rm_16", swapped: Some("imul_rm_16") },
396    Fold { from: "imul_rr_32", into: "imul_rm_32", load: "mov_rm_32", swapped: Some("imul_rm_32") },
397    Fold { from: "imul_rr_64", into: "imul_rm_64", load: "mov_rm_64", swapped: Some("imul_rm_64") },
398    Fold {
399        from: "cmp_set_e_8",
400        into: "cmp_set_e_rm_8",
401        load: "mov_rm_8",
402        swapped: Some("cmp_set_e_rm_8"),
403    },
404    Fold {
405        from: "cmp_set_e_16",
406        into: "cmp_set_e_rm_16",
407        load: "mov_rm_16",
408        swapped: Some("cmp_set_e_rm_16"),
409    },
410    Fold {
411        from: "cmp_set_e_32",
412        into: "cmp_set_e_rm_32",
413        load: "mov_rm_32",
414        swapped: Some("cmp_set_e_rm_32"),
415    },
416    Fold {
417        from: "cmp_set_e_64",
418        into: "cmp_set_e_rm_64",
419        load: "mov_rm_64",
420        swapped: Some("cmp_set_e_rm_64"),
421    },
422    Fold {
423        from: "cmp_set_ne_8",
424        into: "cmp_set_ne_rm_8",
425        load: "mov_rm_8",
426        swapped: Some("cmp_set_ne_rm_8"),
427    },
428    Fold {
429        from: "cmp_set_ne_16",
430        into: "cmp_set_ne_rm_16",
431        load: "mov_rm_16",
432        swapped: Some("cmp_set_ne_rm_16"),
433    },
434    Fold {
435        from: "cmp_set_ne_32",
436        into: "cmp_set_ne_rm_32",
437        load: "mov_rm_32",
438        swapped: Some("cmp_set_ne_rm_32"),
439    },
440    Fold {
441        from: "cmp_set_ne_64",
442        into: "cmp_set_ne_rm_64",
443        load: "mov_rm_64",
444        swapped: Some("cmp_set_ne_rm_64"),
445    },
446    Fold {
447        from: "cmp_set_l_8",
448        into: "cmp_set_l_rm_8",
449        load: "mov_rm_8",
450        swapped: Some("cmp_set_g_rm_8"),
451    },
452    Fold {
453        from: "cmp_set_l_16",
454        into: "cmp_set_l_rm_16",
455        load: "mov_rm_16",
456        swapped: Some("cmp_set_g_rm_16"),
457    },
458    Fold {
459        from: "cmp_set_l_32",
460        into: "cmp_set_l_rm_32",
461        load: "mov_rm_32",
462        swapped: Some("cmp_set_g_rm_32"),
463    },
464    Fold {
465        from: "cmp_set_l_64",
466        into: "cmp_set_l_rm_64",
467        load: "mov_rm_64",
468        swapped: Some("cmp_set_g_rm_64"),
469    },
470    Fold {
471        from: "cmp_set_le_8",
472        into: "cmp_set_le_rm_8",
473        load: "mov_rm_8",
474        swapped: Some("cmp_set_ge_rm_8"),
475    },
476    Fold {
477        from: "cmp_set_le_16",
478        into: "cmp_set_le_rm_16",
479        load: "mov_rm_16",
480        swapped: Some("cmp_set_ge_rm_16"),
481    },
482    Fold {
483        from: "cmp_set_le_32",
484        into: "cmp_set_le_rm_32",
485        load: "mov_rm_32",
486        swapped: Some("cmp_set_ge_rm_32"),
487    },
488    Fold {
489        from: "cmp_set_le_64",
490        into: "cmp_set_le_rm_64",
491        load: "mov_rm_64",
492        swapped: Some("cmp_set_ge_rm_64"),
493    },
494    Fold {
495        from: "cmp_set_g_8",
496        into: "cmp_set_g_rm_8",
497        load: "mov_rm_8",
498        swapped: Some("cmp_set_l_rm_8"),
499    },
500    Fold {
501        from: "cmp_set_g_16",
502        into: "cmp_set_g_rm_16",
503        load: "mov_rm_16",
504        swapped: Some("cmp_set_l_rm_16"),
505    },
506    Fold {
507        from: "cmp_set_g_32",
508        into: "cmp_set_g_rm_32",
509        load: "mov_rm_32",
510        swapped: Some("cmp_set_l_rm_32"),
511    },
512    Fold {
513        from: "cmp_set_g_64",
514        into: "cmp_set_g_rm_64",
515        load: "mov_rm_64",
516        swapped: Some("cmp_set_l_rm_64"),
517    },
518    Fold {
519        from: "cmp_set_ge_8",
520        into: "cmp_set_ge_rm_8",
521        load: "mov_rm_8",
522        swapped: Some("cmp_set_le_rm_8"),
523    },
524    Fold {
525        from: "cmp_set_ge_16",
526        into: "cmp_set_ge_rm_16",
527        load: "mov_rm_16",
528        swapped: Some("cmp_set_le_rm_16"),
529    },
530    Fold {
531        from: "cmp_set_ge_32",
532        into: "cmp_set_ge_rm_32",
533        load: "mov_rm_32",
534        swapped: Some("cmp_set_le_rm_32"),
535    },
536    Fold {
537        from: "cmp_set_ge_64",
538        into: "cmp_set_ge_rm_64",
539        load: "mov_rm_64",
540        swapped: Some("cmp_set_le_rm_64"),
541    },
542    Fold {
543        from: "cmp_set_b_8",
544        into: "cmp_set_b_rm_8",
545        load: "mov_rm_8",
546        swapped: Some("cmp_set_a_rm_8"),
547    },
548    Fold {
549        from: "cmp_set_b_16",
550        into: "cmp_set_b_rm_16",
551        load: "mov_rm_16",
552        swapped: Some("cmp_set_a_rm_16"),
553    },
554    Fold {
555        from: "cmp_set_b_32",
556        into: "cmp_set_b_rm_32",
557        load: "mov_rm_32",
558        swapped: Some("cmp_set_a_rm_32"),
559    },
560    Fold {
561        from: "cmp_set_b_64",
562        into: "cmp_set_b_rm_64",
563        load: "mov_rm_64",
564        swapped: Some("cmp_set_a_rm_64"),
565    },
566    Fold {
567        from: "cmp_set_be_8",
568        into: "cmp_set_be_rm_8",
569        load: "mov_rm_8",
570        swapped: Some("cmp_set_ae_rm_8"),
571    },
572    Fold {
573        from: "cmp_set_be_16",
574        into: "cmp_set_be_rm_16",
575        load: "mov_rm_16",
576        swapped: Some("cmp_set_ae_rm_16"),
577    },
578    Fold {
579        from: "cmp_set_be_32",
580        into: "cmp_set_be_rm_32",
581        load: "mov_rm_32",
582        swapped: Some("cmp_set_ae_rm_32"),
583    },
584    Fold {
585        from: "cmp_set_be_64",
586        into: "cmp_set_be_rm_64",
587        load: "mov_rm_64",
588        swapped: Some("cmp_set_ae_rm_64"),
589    },
590    Fold {
591        from: "cmp_set_a_8",
592        into: "cmp_set_a_rm_8",
593        load: "mov_rm_8",
594        swapped: Some("cmp_set_b_rm_8"),
595    },
596    Fold {
597        from: "cmp_set_a_16",
598        into: "cmp_set_a_rm_16",
599        load: "mov_rm_16",
600        swapped: Some("cmp_set_b_rm_16"),
601    },
602    Fold {
603        from: "cmp_set_a_32",
604        into: "cmp_set_a_rm_32",
605        load: "mov_rm_32",
606        swapped: Some("cmp_set_b_rm_32"),
607    },
608    Fold {
609        from: "cmp_set_a_64",
610        into: "cmp_set_a_rm_64",
611        load: "mov_rm_64",
612        swapped: Some("cmp_set_b_rm_64"),
613    },
614    Fold {
615        from: "cmp_set_ae_8",
616        into: "cmp_set_ae_rm_8",
617        load: "mov_rm_8",
618        swapped: Some("cmp_set_be_rm_8"),
619    },
620    Fold {
621        from: "cmp_set_ae_16",
622        into: "cmp_set_ae_rm_16",
623        load: "mov_rm_16",
624        swapped: Some("cmp_set_be_rm_16"),
625    },
626    Fold {
627        from: "cmp_set_ae_32",
628        into: "cmp_set_ae_rm_32",
629        load: "mov_rm_32",
630        swapped: Some("cmp_set_be_rm_32"),
631    },
632    Fold {
633        from: "cmp_set_ae_64",
634        into: "cmp_set_ae_rm_64",
635        load: "mov_rm_64",
636        swapped: Some("cmp_set_be_rm_64"),
637    },
638    Fold { from: "cmp_set_e_ri_8", into: "cmp_set_e_mi_8", load: "mov_rm_8", swapped: None },
639    Fold { from: "cmp_set_e_ri_16", into: "cmp_set_e_mi_16", load: "mov_rm_16", swapped: None },
640    Fold { from: "cmp_set_e_ri_32", into: "cmp_set_e_mi_32", load: "mov_rm_32", swapped: None },
641    Fold { from: "cmp_set_e_ri_64", into: "cmp_set_e_mi_64", load: "mov_rm_64", swapped: None },
642    Fold { from: "cmp_set_ne_ri_8", into: "cmp_set_ne_mi_8", load: "mov_rm_8", swapped: None },
643    Fold { from: "cmp_set_ne_ri_16", into: "cmp_set_ne_mi_16", load: "mov_rm_16", swapped: None },
644    Fold { from: "cmp_set_ne_ri_32", into: "cmp_set_ne_mi_32", load: "mov_rm_32", swapped: None },
645    Fold { from: "cmp_set_ne_ri_64", into: "cmp_set_ne_mi_64", load: "mov_rm_64", swapped: None },
646    Fold { from: "cmp_set_l_ri_8", into: "cmp_set_l_mi_8", load: "mov_rm_8", swapped: None },
647    Fold { from: "cmp_set_l_ri_16", into: "cmp_set_l_mi_16", load: "mov_rm_16", swapped: None },
648    Fold { from: "cmp_set_l_ri_32", into: "cmp_set_l_mi_32", load: "mov_rm_32", swapped: None },
649    Fold { from: "cmp_set_l_ri_64", into: "cmp_set_l_mi_64", load: "mov_rm_64", swapped: None },
650    Fold { from: "cmp_set_le_ri_8", into: "cmp_set_le_mi_8", load: "mov_rm_8", swapped: None },
651    Fold { from: "cmp_set_le_ri_16", into: "cmp_set_le_mi_16", load: "mov_rm_16", swapped: None },
652    Fold { from: "cmp_set_le_ri_32", into: "cmp_set_le_mi_32", load: "mov_rm_32", swapped: None },
653    Fold { from: "cmp_set_le_ri_64", into: "cmp_set_le_mi_64", load: "mov_rm_64", swapped: None },
654    Fold { from: "cmp_set_g_ri_8", into: "cmp_set_g_mi_8", load: "mov_rm_8", swapped: None },
655    Fold { from: "cmp_set_g_ri_16", into: "cmp_set_g_mi_16", load: "mov_rm_16", swapped: None },
656    Fold { from: "cmp_set_g_ri_32", into: "cmp_set_g_mi_32", load: "mov_rm_32", swapped: None },
657    Fold { from: "cmp_set_g_ri_64", into: "cmp_set_g_mi_64", load: "mov_rm_64", swapped: None },
658    Fold { from: "cmp_set_ge_ri_8", into: "cmp_set_ge_mi_8", load: "mov_rm_8", swapped: None },
659    Fold { from: "cmp_set_ge_ri_16", into: "cmp_set_ge_mi_16", load: "mov_rm_16", swapped: None },
660    Fold { from: "cmp_set_ge_ri_32", into: "cmp_set_ge_mi_32", load: "mov_rm_32", swapped: None },
661    Fold { from: "cmp_set_ge_ri_64", into: "cmp_set_ge_mi_64", load: "mov_rm_64", swapped: None },
662    Fold { from: "cmp_set_b_ri_8", into: "cmp_set_b_mi_8", load: "mov_rm_8", swapped: None },
663    Fold { from: "cmp_set_b_ri_16", into: "cmp_set_b_mi_16", load: "mov_rm_16", swapped: None },
664    Fold { from: "cmp_set_b_ri_32", into: "cmp_set_b_mi_32", load: "mov_rm_32", swapped: None },
665    Fold { from: "cmp_set_b_ri_64", into: "cmp_set_b_mi_64", load: "mov_rm_64", swapped: None },
666    Fold { from: "cmp_set_be_ri_8", into: "cmp_set_be_mi_8", load: "mov_rm_8", swapped: None },
667    Fold { from: "cmp_set_be_ri_16", into: "cmp_set_be_mi_16", load: "mov_rm_16", swapped: None },
668    Fold { from: "cmp_set_be_ri_32", into: "cmp_set_be_mi_32", load: "mov_rm_32", swapped: None },
669    Fold { from: "cmp_set_be_ri_64", into: "cmp_set_be_mi_64", load: "mov_rm_64", swapped: None },
670    Fold { from: "cmp_set_a_ri_8", into: "cmp_set_a_mi_8", load: "mov_rm_8", swapped: None },
671    Fold { from: "cmp_set_a_ri_16", into: "cmp_set_a_mi_16", load: "mov_rm_16", swapped: None },
672    Fold { from: "cmp_set_a_ri_32", into: "cmp_set_a_mi_32", load: "mov_rm_32", swapped: None },
673    Fold { from: "cmp_set_a_ri_64", into: "cmp_set_a_mi_64", load: "mov_rm_64", swapped: None },
674    Fold { from: "cmp_set_ae_ri_8", into: "cmp_set_ae_mi_8", load: "mov_rm_8", swapped: None },
675    Fold { from: "cmp_set_ae_ri_16", into: "cmp_set_ae_mi_16", load: "mov_rm_16", swapped: None },
676    Fold { from: "cmp_set_ae_ri_32", into: "cmp_set_ae_mi_32", load: "mov_rm_32", swapped: None },
677    Fold { from: "cmp_set_ae_ri_64", into: "cmp_set_ae_mi_64", load: "mov_rm_64", swapped: None },
678];
679
680/// The widenings a load can move into on this machine, which is tamnd/rucc#1894.
681///
682/// Every sign and zero widening the target has, each with the load of the width it reads and the
683/// instruction that reads that width out of memory and widens it. None of them has a second source
684/// to swap with. The zero widening from thirty two bits comes out as the load itself, since a
685/// thirty two bit load already clears the upper half of the register it writes.
686pub static WIDENINGS: &[Fold] = &[
687    Fold { from: "movzx_8_16", into: "movzx_rm_8_16", load: "mov_rm_8", swapped: None },
688    Fold { from: "movzx_8_32", into: "movzx_rm_8_32", load: "mov_rm_8", swapped: None },
689    Fold { from: "movzx_8_64", into: "movzx_rm_8_64", load: "mov_rm_8", swapped: None },
690    Fold { from: "movzx_16_32", into: "movzx_rm_16_32", load: "mov_rm_16", swapped: None },
691    Fold { from: "movzx_16_64", into: "movzx_rm_16_64", load: "mov_rm_16", swapped: None },
692    Fold { from: "movsx_8_16", into: "movsx_rm_8_16", load: "mov_rm_8", swapped: None },
693    Fold { from: "movsx_8_32", into: "movsx_rm_8_32", load: "mov_rm_8", swapped: None },
694    Fold { from: "movsx_8_64", into: "movsx_rm_8_64", load: "mov_rm_8", swapped: None },
695    Fold { from: "movsx_16_32", into: "movsx_rm_16_32", load: "mov_rm_16", swapped: None },
696    Fold { from: "movsx_16_64", into: "movsx_rm_16_64", load: "mov_rm_16", swapped: None },
697    Fold { from: "movsxd_32_64", into: "movsxd_rm_32_64", load: "mov_rm_32", swapped: None },
698    Fold { from: "mov_32_to_64", into: "mov_rm_32", load: "mov_rm_32", swapped: None },
699];
700
701/// One arithmetic instruction that could work on memory rather than on a register, and the load
702/// and the store that would be the rest of the run.
703///
704/// A table for the reason [`Fold`] is one, and four names in a row rather than three because the
705/// run is three instructions rather than two. The widths of all four have to agree, and writing
706/// them out is what makes a row that got one wrong something a reader can see.
707#[derive(Debug, Clone, Copy, PartialEq, Eq)]
708pub struct Update {
709    /// The arithmetic as the selector wrote it, on two registers.
710    pub from: &'static str,
711    /// The same arithmetic reading one source out of memory and leaving its answer there.
712    pub into: &'static str,
713    /// The load that put the memory's word in a register.
714    pub load: &'static str,
715    /// The store that put the answer back.
716    pub store: &'static str,
717    /// Whether the two sources may be swapped, which is what lets the load feed either of them.
718    pub commutes: bool,
719}
720
721/// The arithmetic that can work on memory in place on this machine.
722///
723/// The five operations that share an opcode column, at every width. The multiply is not one of
724/// them: `imul` writes a register and there is no encoding of it that leaves the product where it
725/// read one of its sources, so there is no instruction for a row to name.
726///
727/// Subtraction is here and does not commute, and the two facts are related. `subq %rax, (%rcx)`
728/// takes the register away from the memory, so the run it matches is the one where the load feeds
729/// the left source, which is the one arrangement [`FOLDS`] cannot use. The other four take either
730/// source, because the answer does not depend on which of the two came out of memory.
731pub static UPDATES: &[Update] = &[
732    Update {
733        from: "add_rr_8",
734        into: "add_mr_8",
735        load: "mov_rm_8",
736        store: "mov_mr_8",
737        commutes: true,
738    },
739    Update {
740        from: "add_rr_16",
741        into: "add_mr_16",
742        load: "mov_rm_16",
743        store: "mov_mr_16",
744        commutes: true,
745    },
746    Update {
747        from: "add_rr_32",
748        into: "add_mr_32",
749        load: "mov_rm_32",
750        store: "mov_mr_32",
751        commutes: true,
752    },
753    Update {
754        from: "add_rr_64",
755        into: "add_mr_64",
756        load: "mov_rm_64",
757        store: "mov_mr_64",
758        commutes: true,
759    },
760    Update {
761        from: "sub_rr_8",
762        into: "sub_mr_8",
763        load: "mov_rm_8",
764        store: "mov_mr_8",
765        commutes: false,
766    },
767    Update {
768        from: "sub_rr_16",
769        into: "sub_mr_16",
770        load: "mov_rm_16",
771        store: "mov_mr_16",
772        commutes: false,
773    },
774    Update {
775        from: "sub_rr_32",
776        into: "sub_mr_32",
777        load: "mov_rm_32",
778        store: "mov_mr_32",
779        commutes: false,
780    },
781    Update {
782        from: "sub_rr_64",
783        into: "sub_mr_64",
784        load: "mov_rm_64",
785        store: "mov_mr_64",
786        commutes: false,
787    },
788    Update {
789        from: "and_rr_8",
790        into: "and_mr_8",
791        load: "mov_rm_8",
792        store: "mov_mr_8",
793        commutes: true,
794    },
795    Update {
796        from: "and_rr_16",
797        into: "and_mr_16",
798        load: "mov_rm_16",
799        store: "mov_mr_16",
800        commutes: true,
801    },
802    Update {
803        from: "and_rr_32",
804        into: "and_mr_32",
805        load: "mov_rm_32",
806        store: "mov_mr_32",
807        commutes: true,
808    },
809    Update {
810        from: "and_rr_64",
811        into: "and_mr_64",
812        load: "mov_rm_64",
813        store: "mov_mr_64",
814        commutes: true,
815    },
816    Update {
817        from: "or_rr_8",
818        into: "or_mr_8",
819        load: "mov_rm_8",
820        store: "mov_mr_8",
821        commutes: true,
822    },
823    Update {
824        from: "or_rr_16",
825        into: "or_mr_16",
826        load: "mov_rm_16",
827        store: "mov_mr_16",
828        commutes: true,
829    },
830    Update {
831        from: "or_rr_32",
832        into: "or_mr_32",
833        load: "mov_rm_32",
834        store: "mov_mr_32",
835        commutes: true,
836    },
837    Update {
838        from: "or_rr_64",
839        into: "or_mr_64",
840        load: "mov_rm_64",
841        store: "mov_mr_64",
842        commutes: true,
843    },
844    Update {
845        from: "xor_rr_8",
846        into: "xor_mr_8",
847        load: "mov_rm_8",
848        store: "mov_mr_8",
849        commutes: true,
850    },
851    Update {
852        from: "xor_rr_16",
853        into: "xor_mr_16",
854        load: "mov_rm_16",
855        store: "mov_mr_16",
856        commutes: true,
857    },
858    Update {
859        from: "xor_rr_32",
860        into: "xor_mr_32",
861        load: "mov_rm_32",
862        store: "mov_mr_32",
863        commutes: true,
864    },
865    Update {
866        from: "xor_rr_64",
867        into: "xor_mr_64",
868        load: "mov_rm_64",
869        store: "mov_mr_64",
870        commutes: true,
871    },
872];
873
874/// One arithmetic instruction against a constant that could work on memory, and the load and the
875/// store that would be the rest of the run.
876///
877/// [`Update`] with the register source replaced by an immediate, and a field shorter for it. There
878/// is no `commutes`, because there is nothing to swap: the constant is on the instruction and
879/// cannot be anywhere else, so the memory is always the left source and every row reads the same
880/// way. Subtraction is in the table without a note attached for the same reason. `subl $1, (%rax)`
881/// takes one away from the place, which is the run this matches and the only one it could be.
882#[derive(Debug, Clone, Copy, PartialEq, Eq)]
883pub struct Bump {
884    /// The arithmetic as the selector wrote it, on a register and a constant.
885    pub from: &'static str,
886    /// The same arithmetic reading memory and leaving its answer there.
887    pub into: &'static str,
888    /// The load that put the memory's word in a register.
889    pub load: &'static str,
890    /// The store that put the answer back.
891    pub store: &'static str,
892}
893
894/// The arithmetic against a constant that can work on memory in place on this machine.
895///
896/// The same five operations [`UPDATES`] has, at the same four widths, and the multiply is missing
897/// for the same reason. The eight bit inclusive or is also the instruction a probing prologue
898/// writes, which is one instruction described once rather than two things that happen to encode
899/// alike.
900///
901/// The narrow inclusive or and exclusive or against a constant went out under tamnd/rucc#368 and
902/// came back with the width narrowing in tamnd/rucc#375, so a program that writes `*p |= 4`
903/// through a `char` is a byte `or` straight to memory.
904pub static BUMPS: &[Bump] = &[
905    Bump { from: "add_ri_8", into: "add_mi_8", load: "mov_rm_8", store: "mov_mr_8" },
906    Bump { from: "add_ri_16", into: "add_mi_16", load: "mov_rm_16", store: "mov_mr_16" },
907    Bump { from: "add_ri_32", into: "add_mi_32", load: "mov_rm_32", store: "mov_mr_32" },
908    Bump { from: "add_ri_64", into: "add_mi_64", load: "mov_rm_64", store: "mov_mr_64" },
909    Bump { from: "sub_ri_8", into: "sub_mi_8", load: "mov_rm_8", store: "mov_mr_8" },
910    Bump { from: "sub_ri_16", into: "sub_mi_16", load: "mov_rm_16", store: "mov_mr_16" },
911    Bump { from: "sub_ri_32", into: "sub_mi_32", load: "mov_rm_32", store: "mov_mr_32" },
912    Bump { from: "sub_ri_64", into: "sub_mi_64", load: "mov_rm_64", store: "mov_mr_64" },
913    Bump { from: "and_ri_8", into: "and_mi_8", load: "mov_rm_8", store: "mov_mr_8" },
914    Bump { from: "and_ri_16", into: "and_mi_16", load: "mov_rm_16", store: "mov_mr_16" },
915    Bump { from: "and_ri_32", into: "and_mi_32", load: "mov_rm_32", store: "mov_mr_32" },
916    Bump { from: "and_ri_64", into: "and_mi_64", load: "mov_rm_64", store: "mov_mr_64" },
917    Bump { from: "or_ri_8", into: "or_mi_8", load: "mov_rm_8", store: "mov_mr_8" },
918    Bump { from: "or_ri_16", into: "or_mi_16", load: "mov_rm_16", store: "mov_mr_16" },
919    Bump { from: "or_ri_32", into: "or_mi_32", load: "mov_rm_32", store: "mov_mr_32" },
920    Bump { from: "or_ri_64", into: "or_mi_64", load: "mov_rm_64", store: "mov_mr_64" },
921    Bump { from: "xor_ri_8", into: "xor_mi_8", load: "mov_rm_8", store: "mov_mr_8" },
922    Bump { from: "xor_ri_16", into: "xor_mi_16", load: "mov_rm_16", store: "mov_mr_16" },
923    Bump { from: "xor_ri_32", into: "xor_mi_32", load: "mov_rm_32", store: "mov_mr_32" },
924    Bump { from: "xor_ri_64", into: "xor_mi_64", load: "mov_rm_64", store: "mov_mr_64" },
925];
926
927/// The load this block has passed that could still end up inside something.
928///
929/// One rather than a list of them, because anything that touches memory ends the one being carried,
930/// so the one being carried is always the last memory access there was.
931#[derive(Debug, Clone, Copy)]
932struct Waiting {
933    /// The load.
934    inst: Inst,
935    /// The register it wrote, which is what the arithmetic has to be reading.
936    reg: Reg,
937    /// Which load it is, so that the width can be held against the arithmetic's.
938    load: &'static str,
939    /// How far along the block it is, which is what [`WINDOW`] is counted in.
940    at: usize,
941}
942
943/// Puts every load that can move into the arithmetic that reads it, and gives back how many.
944///
945/// `pending` is the addresses [`crate::finish`] has still to write a displacement into, and a load
946/// that moves takes its entry with it, the same way one folded into a reader does. An address into
947/// the frame arrives here already inside the load, because [`crate::fold`] has run.
948///
949/// Run after selection and after the addresses are folded, and before allocation. Before the
950/// allocator because what makes the pair safe to put together is that a virtual register is written
951/// once, and after the addresses because a load whose address is still a `lea` in front of it has
952/// nothing in its own memory operand worth carrying.
953pub fn loads(
954    func: &mut Func,
955    machine: &MachineInsts,
956    names: &mut Interner,
957    pending: &mut Pending<'_>,
958) -> usize {
959    let mut reads = Reads::of(func);
960    let mut done = 0;
961    let mut seen = HashMap::new();
962    for block in func.blocks().collect::<Vec<_>>() {
963        let mut waiting: Option<Waiting> = None;
964        for (at, inst) in func.insts(block).collect::<Vec<_>>().into_iter().enumerate() {
965            // Asked before the rewrite below rather than after it, because the rewrite turns an
966            // instruction that touched no memory into one that does, and asking afterwards would
967            // throw away the load that had just gone into it over the load that had just gone into
968            // it. Nothing else about the answer moves: the other end of a row of the fold table is
969            // arithmetic this target describes and is not a call.
970            let opcode = func[inst].opcode;
971            let Loads { barrier, load } =
972                *seen.entry(opcode).or_insert_with(|| Loads::of(machine, names, opcode));
973            if let Some(carried) = waiting {
974                let bare = machine.bare(names.resolve(opcode.name())).to_owned();
975                if let Some(plan) = joined(func, &reads, carried, machine, names, inst, &bare) {
976                    let mut set = Changes::new();
977                    set.rewrite(inst, plan);
978                    set.remove(carried.inst);
979                    if set.commit(func, &mut reads, names, machine).is_ok() {
980                        pending.moved(carried.inst, &[inst]);
981                        waiting = None;
982                        done += 1;
983                    }
984                }
985            }
986            if barrier {
987                waiting = None;
988            }
989            if let Some(carried) = waiting {
990                if at - carried.at >= WINDOW || writes_what_it_reads(func, inst, &carried) {
991                    waiting = None;
992                }
993            }
994            // A load the program insisted on is never carried forward, so there is never one in
995            // hand for the fold below to take. Refused where the load is picked up rather than
996            // where it is joined, because what is wrong with it is what it is and not what it
997            // meets: a load nothing may fold has no business being waited on for sixteen
998            // instructions either.
999            if insisted(func, inst) {
1000                continue;
1001            }
1002            if let Some(load) = load {
1003                let operands = &func[func[inst].operands];
1004                if let Some(first) = operands.first().filter(|operand| operand.role.is_def()) {
1005                    waiting = Some(Waiting { inst, reg: first.reg, load, at });
1006                }
1007            }
1008        }
1009    }
1010    done
1011}
1012
1013/// What [`loads`] asks of an opcode, asked once for each opcode a function has rather than once for
1014/// each instruction.
1015///
1016/// The fold tables are over a hundred rows and the question of which row a load is on was a walk down all
1017/// of them comparing names, asked of every instruction, when most instructions are not loads at
1018/// all. On jtckdint's `test.c` at `-O2` that was about one percent of the build.
1019#[derive(Debug, Clone, Copy)]
1020struct Loads {
1021    /// Whether nothing may be carried past it: a call, a name the target does not have, or
1022    /// something that reads or writes memory.
1023    barrier: bool,
1024    /// The name of the load, when it is one a row of the fold table folds.
1025    load: Option<&'static str>,
1026}
1027
1028impl Loads {
1029    fn of(machine: &MachineInsts, names: &Interner, opcode: Opcode) -> Self {
1030        let name = names.resolve(opcode.name());
1031        let bare = machine.bare(name);
1032        let mut rows = FOLDS.iter().chain(WIDENINGS);
1033        Self {
1034            barrier: machine.calls(name) || !machine.has(name) || machine.touches_mem(name),
1035            load: rows.find(|fold| fold.load == bare).map(|fold| fold.load),
1036        }
1037    }
1038}
1039
1040/// The three instructions that read a place, compute on what was there and write it back.
1041#[derive(Debug, Clone, Copy)]
1042struct Run {
1043    /// The load that read the place.
1044    load: Inst,
1045    /// The arithmetic that read what the load put in a register.
1046    alu: Inst,
1047    /// The store that put the answer back where the load got it.
1048    store: Inst,
1049    /// Which row of [`UPDATES`] the run is.
1050    update: &'static Update,
1051    /// The source the arithmetic is left reading, which is the one the memory is not.
1052    kept: Operand,
1053}
1054
1055/// The same three instructions with a constant where the other source was.
1056///
1057/// A separate shape from [`Run`] rather than the same one with an option in it, because the two
1058/// differ in what they carry and in nothing else. This one holds the constant the instruction that
1059/// comes out will carry, and has no `kept`, since the arithmetic is left reading nothing at all.
1060#[derive(Debug, Clone, Copy)]
1061struct Bumped {
1062    /// The load that read the place.
1063    load: Inst,
1064    /// The arithmetic that read what the load put in a register.
1065    alu: Inst,
1066    /// The store that put the answer back where the load got it.
1067    store: Inst,
1068    /// Which row of [`BUMPS`] the run is.
1069    bump: &'static Bump,
1070    /// The constant the arithmetic was against.
1071    imm: i64,
1072}
1073
1074/// Puts every run that reads a place, computes on it and writes it back into the one instruction
1075/// this machine has for all three, and gives back how many.
1076///
1077/// `pending` is the addresses [`crate::finish`] has still to write a displacement into. The store
1078/// is the instruction that survives and it is already waiting on the entry the load was waiting on,
1079/// since the two name the same place, so the load's entry is taken off rather than moved.
1080///
1081/// Run before [`loads`] rather than after it. The run this looks for is three instructions the
1082/// selector wrote, and folding the load into the arithmetic first would leave two instructions that
1083/// are the same thing written differently, so the walk would have to know both spellings. Whatever
1084/// this does not take is still there for [`loads`] to take the load out of.
1085///
1086/// The run whose arithmetic is against a constant is looked for after the one whose arithmetic is
1087/// against a register, and the order between those two does not matter: the middle instruction
1088/// decides which of them a run is, and no instruction is both an [`UPDATES`] row and a [`BUMPS`]
1089/// row.
1090pub fn stores(
1091    func: &mut Func,
1092    machine: &MachineInsts,
1093    flags: &FlagInsts,
1094    names: &mut Interner,
1095    pending: &mut Pending<'_>,
1096) -> usize {
1097    let mut reads = Reads::of(func);
1098    let mut done = 0;
1099    for block in func.blocks().collect::<Vec<_>>() {
1100        let insts: Vec<Inst> = func.insts(block).collect();
1101        for at in 0..insts.len() {
1102            let found = match run(func, &reads, machine, flags, names, &insts, at) {
1103                Some(found) => Some((
1104                    found.load,
1105                    found.alu,
1106                    found.store,
1107                    updated(func, machine, names, &found),
1108                )),
1109                None => constant(func, &reads, machine, flags, names, &insts, at).map(|found| {
1110                    (found.load, found.alu, found.store, bumped(func, machine, names, &found))
1111                }),
1112            };
1113            let Some((load, alu, store, plan)) = found else { continue };
1114            if !pending.alike(load, store) {
1115                continue;
1116            }
1117            let mut set = Changes::new();
1118            set.rewrite(store, plan);
1119            set.remove(alu);
1120            set.remove(load);
1121            if set.commit(func, &mut reads, names, machine).is_ok() {
1122                pending.moved(load, &[]);
1123                done += 1;
1124            }
1125        }
1126    }
1127    done
1128}
1129
1130/// The run ending in the instruction at that position, or `None`.
1131///
1132/// Walked backwards from the store, because the store is the end of the run and is the instruction
1133/// that is left when the run is joined. Everything the walk needs is behind it: which register it
1134/// is storing says which arithmetic to look for, and which source that arithmetic reads says which
1135/// load.
1136///
1137/// An instruction an earlier fold took out is still in `insts` and is read here as though it were
1138/// where it was. That costs a fold and never takes one: a removed instruction is one more thing in
1139/// the way, and it cannot be the arithmetic or the load this is looking for, because each of those
1140/// is the one writer of a register something still reads.
1141fn run(
1142    func: &Func,
1143    reads: &Reads,
1144    machine: &MachineInsts,
1145    flags: &FlagInsts,
1146    names: &Interner,
1147    insts: &[Inst],
1148    at: usize,
1149) -> Option<Run> {
1150    let store = insts[at];
1151    if insisted(func, store) {
1152        return None;
1153    }
1154    let stored = machine.bare(names.resolve(func[store].opcode.name())).to_owned();
1155    let value = *func[func[store].operands].first()?;
1156    if value.role.is_def() || reads.count(value.reg) != 1 {
1157        return None;
1158    }
1159    // One bound over the whole run rather than one per pair, so that what the window means is how
1160    // far apart the first and the last of the three may be.
1161    let earliest = at.saturating_sub(WINDOW);
1162    let alu = (earliest..at).rev().find(|&k| writes(func, insts[k], value.reg))?;
1163    let bare = machine.bare(names.resolve(func[insts[alu]].opcode.name())).to_owned();
1164    let update = UPDATES.iter().find(|row| row.from == bare && row.store == stored)?;
1165    if !quiet(func, flags, names, insts, (alu, at)) {
1166        return None;
1167    }
1168    let operands = func[func[insts[alu]].operands].to_vec();
1169    let [_, first, second] = operands[..] else { return None };
1170    // The left source is the one the memory takes the place of, because the answer is left where
1171    // the memory operand points and the answer is tied to the left source. Where the load feeds the
1172    // right one instead and the operation commutes, the two swap, which leaves the instruction
1173    // computing what it computed.
1174    let both = [(first, second), (second, first)];
1175    let tried = if update.commutes { &both[..] } else { &both[..1] };
1176    for &(source, kept) in tried {
1177        if reads.count(source.reg) != 1 {
1178            continue;
1179        }
1180        let Some(from) = (earliest..alu).rev().find(|&k| writes(func, insts[k], source.reg)) else {
1181            continue;
1182        };
1183        let load = insts[from];
1184        if insisted(func, load) {
1185            continue;
1186        }
1187        if machine.bare(names.resolve(func[load].opcode.name())) != update.load {
1188            continue;
1189        }
1190        if !same_place(func, load, store) {
1191            continue;
1192        }
1193        // The registers the one instruction left is reading, which are the ones nothing between the
1194        // load and the store may write. The arithmetic itself passes this without being left out of
1195        // it: what it writes is the value the store is storing, and that register is not one of
1196        // these.
1197        let mut wanted: Vec<Reg> =
1198            func[func[store].operands][1..].iter().map(|operand| operand.reg).collect();
1199        wanted.push(kept.reg);
1200        if !clear(func, machine, names, insts, (from, at), &wanted) {
1201            continue;
1202        }
1203        return Some(Run { load, alu: insts[alu], store, update, kept });
1204    }
1205    None
1206}
1207
1208/// The run against a constant ending in the instruction at that position, or `None`.
1209///
1210/// [`run`] with the arithmetic's second source gone. Walked backwards from the store for the same
1211/// reason, and asking the same four questions: the stored register is read once, the source the
1212/// arithmetic reads is written once by a load of the right width, that load names the same place as
1213/// the store, and nothing between the two is in the way. There is no arrangement to choose between,
1214/// because the constant is on the instruction and only the left source can be the memory.
1215///
1216/// One question [`run`] does not ask is here: where the addressing mode's registers are. The
1217/// instruction that comes out has no operand in front of them, so each of them moves one place
1218/// towards the front of the vector, and a mode that already pointed at the front would have to move
1219/// to nowhere. That cannot happen, since the front is the value the store is storing, and refusing
1220/// the run is what it costs to say so rather than to assume it.
1221fn constant(
1222    func: &Func,
1223    reads: &Reads,
1224    machine: &MachineInsts,
1225    flags: &FlagInsts,
1226    names: &Interner,
1227    insts: &[Inst],
1228    at: usize,
1229) -> Option<Bumped> {
1230    let store = insts[at];
1231    if insisted(func, store) {
1232        return None;
1233    }
1234    let stored = machine.bare(names.resolve(func[store].opcode.name())).to_owned();
1235    let value = *func[func[store].operands].first()?;
1236    if value.role.is_def() || reads.count(value.reg) != 1 {
1237        return None;
1238    }
1239    let mem = func[func[store].mem?];
1240    if mem.base == Some(0) || mem.index == Some(0) {
1241        return None;
1242    }
1243    let earliest = at.saturating_sub(WINDOW);
1244    let alu = (earliest..at).rev().find(|&k| writes(func, insts[k], value.reg))?;
1245    let bare = machine.bare(names.resolve(func[insts[alu]].opcode.name())).to_owned();
1246    let bump = BUMPS.iter().find(|row| row.from == bare && row.store == stored)?;
1247    if !quiet(func, flags, names, insts, (alu, at)) {
1248        return None;
1249    }
1250    let operands = func[func[insts[alu]].operands].to_vec();
1251    let [_, source] = operands[..] else { return None };
1252    let imm = func[func[insts[alu]].imm?].0;
1253    if reads.count(source.reg) != 1 {
1254        return None;
1255    }
1256    let from = (earliest..alu).rev().find(|&k| writes(func, insts[k], source.reg))?;
1257    let load = insts[from];
1258    if insisted(func, load) {
1259        return None;
1260    }
1261    if machine.bare(names.resolve(func[load].opcode.name())) != bump.load {
1262        return None;
1263    }
1264    if !same_place(func, load, store) {
1265        return None;
1266    }
1267    // The registers the one instruction left is reading, which are the ones in its address and no
1268    // others, since the constant is not in a register and the arithmetic is left reading nothing.
1269    let wanted: Vec<Reg> =
1270        func[func[store].operands][1..].iter().map(|operand| operand.reg).collect();
1271    if !clear(func, machine, names, insts, (from, at), &wanted) {
1272        return None;
1273    }
1274    Some(Bumped { load, alu: insts[alu], store, bump, imm })
1275}
1276
1277/// Whether the program insisted on this access happening exactly as it is written.
1278///
1279/// Which is `volatile`, and is the one question in this module that is not about what the
1280/// instructions do to each other. See the section above on what such an access gets.
1281fn insisted(func: &Func, inst: Inst) -> bool {
1282    func[inst].flags.contains(Flags::VOLATILE)
1283}
1284
1285/// Whether this instruction writes that register.
1286fn writes(func: &Func, inst: Inst, reg: Reg) -> bool {
1287    func[func[inst].operands].iter().any(|operand| operand.role.is_def() && operand.reg == reg)
1288}
1289
1290/// Whether the two instructions name the same place in memory.
1291///
1292/// The same addressing mode, the same symbol, and the same registers where the mode holds operand
1293/// positions. Both instructions here write their value down first and their address behind it, so
1294/// the positions line up, and the registers are compared anyway rather than the positions, because
1295/// what makes two addresses one place is which registers they read.
1296fn same_place(func: &Func, one: Inst, other: Inst) -> bool {
1297    let (Some(here), Some(there)) = (func[one].mem, func[other].mem) else { return false };
1298    let (here, there) = (func[here], func[there]);
1299    if func[one].symbol != func[other].symbol {
1300        return false;
1301    }
1302    let bare = |amode: Amode| Amode { base: None, index: None, ..amode };
1303    if bare(here) != bare(there) {
1304        return false;
1305    }
1306    let same = |left: Option<u8>, right: Option<u8>| match (left, right) {
1307        (None, None) => true,
1308        (Some(left), Some(right)) => {
1309            func[func[one].operands][usize::from(left)].reg
1310                == func[func[other].operands][usize::from(right)].reg
1311        }
1312        _ => false,
1313    };
1314    same(here.base, there.base) && same(here.index, there.index)
1315}
1316
1317/// Whether everything between the two positions may be passed.
1318///
1319/// The run becomes one instruction where the store is, so the read of memory the load was doing
1320/// moves down the block to there. Nothing that touches memory may be passed, for the reason the
1321/// module documentation gives about [`loads`], and nothing may write a register the instruction
1322/// that is left still reads.
1323fn clear(
1324    func: &Func,
1325    machine: &MachineInsts,
1326    names: &Interner,
1327    insts: &[Inst],
1328    span: (usize, usize),
1329    wanted: &[Reg],
1330) -> bool {
1331    let (from, to) = span;
1332    insts[from + 1..to].iter().all(|&inst| {
1333        let name = names.resolve(func[inst].opcode.name());
1334        if machine.calls(name) || !machine.has(name) || machine.touches_mem(name) {
1335            return false;
1336        }
1337        !func[func[inst].operands]
1338            .iter()
1339            .any(|operand| operand.role.is_def() && wanted.contains(&operand.reg))
1340    })
1341}
1342
1343/// Whether the condition state between the arithmetic and the store belongs to nobody.
1344///
1345/// The arithmetic moves down the block to where the store is and it writes the condition state, so
1346/// everything it passes has to have no opinion about that state. An instruction that reads it was
1347/// reading what the arithmetic left and would be reading what was there before the arithmetic
1348/// instead. An instruction that writes it was the last writer before the store and would stop being
1349/// it, which changes what anything further down reads. Neither is allowed and there is nothing to
1350/// weigh: this is the shape tamnd/rucc#1424 was, where the reader in the middle was the `adc` that
1351/// takes the carry out of the addition above it into a register.
1352///
1353/// Asked from the arithmetic rather than from the load, which is what [`clear`] is asked from.
1354/// Between the load and the arithmetic nothing moves except the load, and a load has nothing to say
1355/// about the condition state.
1356///
1357/// A name the description does not cover counts as both, for the reason [`FlagInsts::writes`] gives
1358/// about a name this target does not have.
1359fn quiet(
1360    func: &Func,
1361    flags: &FlagInsts,
1362    names: &Interner,
1363    insts: &[Inst],
1364    span: (usize, usize),
1365) -> bool {
1366    let (alu, to) = span;
1367    insts[alu + 1..to].iter().all(|&inst| {
1368        let Some(name) = names.resolve(func[inst].opcode.name()).strip_prefix(flags.prefix) else {
1369            return false;
1370        };
1371        flags.reads(name).is_none() && !(flags.writes)(name)
1372    })
1373}
1374
1375/// What the store becomes with the rest of the run inside it.
1376///
1377/// The store's own addressing mode and the source the arithmetic kept, which is the whole of it.
1378/// The mode is left exactly as it was, because the operand it was written against is the value the
1379/// store was storing and what takes that operand's place is one operand as well.
1380fn updated(func: &Func, machine: &MachineInsts, names: &mut Interner, run: &Run) -> Plan {
1381    let operands = func[func[run.store].operands].to_vec();
1382    let into = names.intern(&format!("{}{}", machine.prefix, run.update.into));
1383    Plan {
1384        opcode: Opcode::new(into),
1385        operands: [run.kept].into_iter().chain(operands[1..].iter().copied()).collect(),
1386        imm: None,
1387        amode: func[run.store].mem.map(|mem| func[mem]),
1388        symbol: func[run.store].symbol,
1389    }
1390}
1391
1392/// What the store becomes with the rest of a constant run inside it.
1393///
1394/// The store's own addressing mode again, and the constant the arithmetic carried. The mode does
1395/// not come through untouched this time. The value the store was storing has nothing taking its
1396/// place, so the registers behind it each move one place towards the front of the operand vector,
1397/// and the positions the mode holds are positions in that vector and move with them. [`constant`]
1398/// is what makes sure there is a place for each of them to move to.
1399fn bumped(func: &Func, machine: &MachineInsts, names: &mut Interner, run: &Bumped) -> Plan {
1400    let operands = func[func[run.store].operands][1..].to_vec();
1401    let into = names.intern(&format!("{}{}", machine.prefix, run.bump.into));
1402    let back = |at: Option<u8>| at.map(|at| at - 1);
1403    Plan {
1404        opcode: Opcode::new(into),
1405        operands,
1406        imm: Some(run.imm),
1407        amode: func[run.store].mem.map(|mem| {
1408            let mem = func[mem];
1409            Amode { base: back(mem.base), index: back(mem.index), ..mem }
1410        }),
1411        symbol: func[run.store].symbol,
1412    }
1413}
1414
1415/// Whether this instruction writes a register the carried load needs left alone.
1416///
1417/// The registers its address reads, and the register it wrote. The second is there for the same
1418/// reason the first is: a virtual register cannot be written twice while the IR is in SSA form, and
1419/// these are the physical ones a function has before the allocator runs.
1420fn writes_what_it_reads(func: &Func, inst: Inst, carried: &Waiting) -> bool {
1421    let written: Vec<Reg> = func[func[inst].operands]
1422        .iter()
1423        .filter(|operand| operand.role.is_def())
1424        .map(|operand| operand.reg)
1425        .collect();
1426    func[func[carried.inst].operands].iter().any(|operand| written.contains(&operand.reg))
1427}
1428
1429/// What this instruction becomes with the carried load inside it, or `None`.
1430///
1431/// Nothing here changes anything. What comes back is a proposal, and whether the target has the
1432/// instruction it describes is [`Changes`]'s answer rather than this one.
1433fn joined(
1434    func: &Func,
1435    reads: &Reads,
1436    carried: Waiting,
1437    machine: &MachineInsts,
1438    names: &mut Interner,
1439    inst: Inst,
1440    bare: &str,
1441) -> Option<Plan> {
1442    let fold = FOLDS.iter().chain(WIDENINGS).find(|fold| fold.from == bare)?;
1443    if carried.load != fold.load || reads.count(carried.reg) != 1 {
1444        return None;
1445    }
1446    let operands = func[func[inst].operands].to_vec();
1447    // The second source is the one the memory operand replaces, which for arithmetic is because
1448    // the answer is tied to the first and for a comparison is because that is the side the
1449    // instruction subtracts. Where the load feeds the first source instead, the row says which
1450    // instruction reads the two the other way round, and that one is written instead: for
1451    // arithmetic that commutes it is the same instruction, and for a comparison it is the same
1452    // question with the condition turned over.
1453    //
1454    // A comparison against a constant has one source and no arrangement to choose between, since
1455    // the constant is on the instruction and cannot be anywhere else. What is left in front of the
1456    // address is the byte on its own.
1457    let (front, into) = match operands[..] {
1458        [answer, first, second] => {
1459            let (kept, into) = if second.reg == carried.reg {
1460                (first, fold.into)
1461            } else if first.reg == carried.reg {
1462                (second, fold.swapped?)
1463            } else {
1464                return None;
1465            };
1466            (vec![answer, kept], into)
1467        }
1468        [answer, only] if only.reg == carried.reg => (vec![answer], fold.into),
1469        _ => return None,
1470    };
1471    let load = carried.inst;
1472    let address = func[func[load].operands][1..].to_vec();
1473    let mut amode = func[func[load].mem?];
1474    // The registers an address names are operands behind the ones the instruction writes down. The
1475    // load wrote one of those and the instruction that comes out writes however many are in front
1476    // of the address here, so every position the mode holds moves along by the difference.
1477    let along = u8::try_from(front.len() - 1).expect("a handful of operands");
1478    amode.base = amode.base.map(|at| at + along);
1479    amode.index = amode.index.map(|at| at + along);
1480    let into = names.intern(&format!("{}{}", machine.prefix, into));
1481    Some(Plan {
1482        opcode: Opcode::new(into),
1483        operands: front.into_iter().chain(address).collect(),
1484        imm: func[inst].imm.map(|at| func[at].0),
1485        amode: Some(amode),
1486        symbol: func[load].symbol,
1487    })
1488}
1489
1490#[cfg(test)]
1491mod tests {
1492    use rucc_mir::{self as mir, Constraint, Mem, Operand};
1493    use rucc_target::x86_64::{FLAGS, GPR, MACHINE};
1494
1495    use super::*;
1496
1497    /// A function with one block, and the names it was built with.
1498    fn empty() -> (Interner, Func, mir::Block) {
1499        let mut names = Interner::new();
1500        let mut func = Func::new(names.intern("f"));
1501        let block = func.create_block();
1502        (names, func, block)
1503    }
1504
1505    /// The opcode of that name on this target.
1506    fn op(names: &mut Interner, name: &str) -> Opcode {
1507        Opcode::new(names.intern(&format!("{}{name}", MACHINE.prefix)))
1508    }
1509
1510    /// A load of eight bytes off that register.
1511    fn load(func: &mut Func, names: &mut Interner, block: mir::Block, base: Reg) -> Reg {
1512        let into = func.new_vreg(GPR);
1513        let mov = op(names, "mov_rm_64");
1514        func.build(block, mov)
1515            .def(into, GPR)
1516            .mem(Mem { disp: 16, ..Mem::at(Operand::read(base, GPR)) })
1517            .finish();
1518        into
1519    }
1520
1521    /// The same load, of a place the program said to read exactly where it is written.
1522    fn insisted_load(func: &mut Func, names: &mut Interner, block: mir::Block, base: Reg) -> Reg {
1523        let into = func.new_vreg(GPR);
1524        let mov = op(names, "mov_rm_64");
1525        func.build(block, mov)
1526            .def(into, GPR)
1527            .mem(Mem { disp: 16, ..Mem::at(Operand::read(base, GPR)) })
1528            .flags(Flags::VOLATILE)
1529            .finish();
1530        into
1531    }
1532
1533    /// Two-address arithmetic of that name on those two registers, in that order.
1534    fn alu(
1535        func: &mut Func,
1536        names: &mut Interner,
1537        block: mir::Block,
1538        name: &str,
1539        first: Reg,
1540        second: Reg,
1541    ) -> Reg {
1542        let answer = func.new_vreg(GPR);
1543        let opcode = op(names, name);
1544        func.build(block, opcode)
1545            .operand(Operand::write(answer, GPR).with(Constraint::Reuse(1)))
1546            .uses(first, GPR)
1547            .uses(second, GPR)
1548            .finish();
1549        answer
1550    }
1551
1552    /// A comparison of those two registers in that order, which keeps its answer in a byte the
1553    /// two sources have no claim on and is what makes it not two-address.
1554    fn compare(
1555        func: &mut Func,
1556        names: &mut Interner,
1557        block: mir::Block,
1558        name: &str,
1559        first: Reg,
1560        second: Reg,
1561    ) -> Reg {
1562        let byte = func.new_vreg(GPR);
1563        let opcode = op(names, name);
1564        func.build(block, opcode).def(byte, GPR).uses(first, GPR).uses(second, GPR).finish();
1565        byte
1566    }
1567
1568    /// What every instruction in a block came to, as opcodes.
1569    fn shape(func: &Func, names: &Interner, block: mir::Block) -> Vec<String> {
1570        func.insts(block).map(|inst| names.resolve(func[inst].opcode.name()).to_owned()).collect()
1571    }
1572
1573    /// The pass, with lists nothing is on.
1574    fn combine(func: &mut Func, names: &mut Interner) -> usize {
1575        let mut addresses = Vec::new();
1576        let mut arguments = Vec::new();
1577        let mut dynamic = Vec::new();
1578        let mut pending =
1579            Pending { addresses: &mut addresses, arguments: &mut arguments, dynamic: &mut dynamic };
1580        loads(func, &MACHINE, names, &mut pending)
1581    }
1582
1583    /// A store of that register to sixteen off that base, which is the address `load` reads.
1584    fn store(func: &mut Func, names: &mut Interner, block: mir::Block, base: Reg, value: Reg) {
1585        let mov = op(names, "mov_mr_64");
1586        func.build(block, mov)
1587            .uses(value, GPR)
1588            .mem(Mem { disp: 16, ..Mem::at(Operand::read(base, GPR)) })
1589            .finish();
1590    }
1591
1592    /// The same store, of a place the program said to write exactly where it is written.
1593    fn insisted_store(
1594        func: &mut Func,
1595        names: &mut Interner,
1596        block: mir::Block,
1597        base: Reg,
1598        value: Reg,
1599    ) {
1600        let mov = op(names, "mov_mr_64");
1601        func.build(block, mov)
1602            .uses(value, GPR)
1603            .mem(Mem { disp: 16, ..Mem::at(Operand::read(base, GPR)) })
1604            .flags(Flags::VOLATILE)
1605            .finish();
1606    }
1607
1608    /// The other walk, with lists nothing is on.
1609    fn update(func: &mut Func, names: &mut Interner) -> usize {
1610        let mut addresses = Vec::new();
1611        let mut arguments = Vec::new();
1612        let mut dynamic = Vec::new();
1613        let mut pending =
1614            Pending { addresses: &mut addresses, arguments: &mut arguments, dynamic: &mut dynamic };
1615        stores(func, &MACHINE, &FLAGS, names, &mut pending)
1616    }
1617
1618    /// The shape the second walk is for, which is what `*p += x` is.
1619    #[test]
1620    fn a_word_read_changed_and_written_back_becomes_one_instruction() {
1621        let (mut names, mut func, block) = empty();
1622        let base = func.new_vreg(GPR);
1623        let other = func.new_vreg(GPR);
1624        let word = load(&mut func, &mut names, block, base);
1625        let sum = alu(&mut func, &mut names, block, "add_rr_64", word, other);
1626        store(&mut func, &mut names, block, base, sum);
1627
1628        assert_eq!(update(&mut func, &mut names), 1);
1629        assert_eq!(shape(&func, &names, block), ["x64.add_mr_64"]);
1630        let inst = func.insts(block).next().expect("the addition");
1631        let mem = func[inst].mem.expect("it writes memory");
1632        assert_eq!(func[mem].disp, 16, "the address came from the store");
1633        assert_eq!(func[mem].base, Some(1), "and names the operand behind the source");
1634        assert_eq!(func[func[inst].operands].len(), 2, "one source and the base of the address");
1635        assert_eq!(func[func[inst].operands][0].reg, other, "the source it kept");
1636        assert_eq!(func[func[inst].operands][1].reg, base, "the address");
1637    }
1638
1639    /// The same run with the load feeding the right source instead, which an addition does not
1640    /// mind. What `subq %rax, (%rcx)` computes is memory minus register, so the subtraction below
1641    /// is the one that has to care.
1642    #[test]
1643    fn a_word_read_into_the_right_source_of_an_addition_is_still_one_instruction() {
1644        let (mut names, mut func, block) = empty();
1645        let base = func.new_vreg(GPR);
1646        let other = func.new_vreg(GPR);
1647        let word = load(&mut func, &mut names, block, base);
1648        let sum = alu(&mut func, &mut names, block, "add_rr_64", other, word);
1649        store(&mut func, &mut names, block, base, sum);
1650
1651        assert_eq!(update(&mut func, &mut names), 1);
1652        assert_eq!(shape(&func, &names, block), ["x64.add_mr_64"]);
1653        assert_eq!(func[func[func.insts(block).next().expect("it")].operands][0].reg, other);
1654    }
1655
1656    /// A subtraction with the memory on the left, which is `*p -= x` and is what the machine
1657    /// instruction computes.
1658    #[test]
1659    fn a_subtraction_taking_a_register_away_from_memory_becomes_one_instruction() {
1660        let (mut names, mut func, block) = empty();
1661        let base = func.new_vreg(GPR);
1662        let other = func.new_vreg(GPR);
1663        let word = load(&mut func, &mut names, block, base);
1664        let left = alu(&mut func, &mut names, block, "sub_rr_64", word, other);
1665        store(&mut func, &mut names, block, base, left);
1666
1667        assert_eq!(update(&mut func, &mut names), 1);
1668        assert_eq!(shape(&func, &names, block), ["x64.sub_mr_64"]);
1669    }
1670
1671    /// And the same subtraction the other way round, which is `*p = x - *p`. The machine
1672    /// instruction would compute the other answer, so the run stays three instructions.
1673    #[test]
1674    fn a_subtraction_taking_memory_away_from_a_register_stays_three_instructions() {
1675        let (mut names, mut func, block) = empty();
1676        let base = func.new_vreg(GPR);
1677        let other = func.new_vreg(GPR);
1678        let word = load(&mut func, &mut names, block, base);
1679        let left = alu(&mut func, &mut names, block, "sub_rr_64", other, word);
1680        store(&mut func, &mut names, block, base, left);
1681
1682        assert_eq!(update(&mut func, &mut names), 0);
1683        assert_eq!(
1684            shape(&func, &names, block),
1685            ["x64.mov_rm_64", "x64.sub_rr_64", "x64.mov_mr_64"]
1686        );
1687    }
1688
1689    /// A store to somewhere else. The answer is not going back where it came from, so what is left
1690    /// is a load and an arithmetic and a store of three different addresses.
1691    #[test]
1692    fn a_store_to_another_address_stays_three_instructions() {
1693        let (mut names, mut func, block) = empty();
1694        let base = func.new_vreg(GPR);
1695        let elsewhere = func.new_vreg(GPR);
1696        let other = func.new_vreg(GPR);
1697        let word = load(&mut func, &mut names, block, base);
1698        let sum = alu(&mut func, &mut names, block, "add_rr_64", word, other);
1699        store(&mut func, &mut names, block, elsewhere, sum);
1700
1701        assert_eq!(update(&mut func, &mut names), 0);
1702    }
1703
1704    /// The same address at a different displacement, which is the near miss the comparison has to
1705    /// catch rather than the obvious one above.
1706    #[test]
1707    fn a_store_at_another_displacement_stays_three_instructions() {
1708        let (mut names, mut func, block) = empty();
1709        let base = func.new_vreg(GPR);
1710        let other = func.new_vreg(GPR);
1711        let word = load(&mut func, &mut names, block, base);
1712        let sum = alu(&mut func, &mut names, block, "add_rr_64", word, other);
1713        let mov = op(&mut names, "mov_mr_64");
1714        func.build(block, mov)
1715            .uses(sum, GPR)
1716            .mem(Mem { disp: 24, ..Mem::at(Operand::read(base, GPR)) })
1717            .finish();
1718
1719        assert_eq!(update(&mut func, &mut names), 0);
1720    }
1721
1722    /// The word read again by something else. The load has to stay for the second reader, so the
1723    /// run is not a run.
1724    #[test]
1725    fn a_word_two_instructions_read_stays_three_instructions() {
1726        let (mut names, mut func, block) = empty();
1727        let base = func.new_vreg(GPR);
1728        let other = func.new_vreg(GPR);
1729        let word = load(&mut func, &mut names, block, base);
1730        let sum = alu(&mut func, &mut names, block, "add_rr_64", word, other);
1731        alu(&mut func, &mut names, block, "xor_rr_64", word, other);
1732        store(&mut func, &mut names, block, base, sum);
1733
1734        assert_eq!(update(&mut func, &mut names), 0);
1735    }
1736
1737    /// The answer read by something else as well as by the store, which is `x = *p += 1` and
1738    /// leaves the answer wanted in a register the joined instruction never writes.
1739    #[test]
1740    fn an_answer_something_else_reads_stays_three_instructions() {
1741        let (mut names, mut func, block) = empty();
1742        let base = func.new_vreg(GPR);
1743        let other = func.new_vreg(GPR);
1744        let word = load(&mut func, &mut names, block, base);
1745        let sum = alu(&mut func, &mut names, block, "add_rr_64", word, other);
1746        store(&mut func, &mut names, block, base, sum);
1747        alu(&mut func, &mut names, block, "xor_rr_64", sum, other);
1748
1749        assert_eq!(update(&mut func, &mut names), 0);
1750    }
1751
1752    /// Another access to memory in the middle. The read the run does moves down the block to where
1753    /// the write was, so it would be moving past this one.
1754    #[test]
1755    fn a_run_with_another_access_in_the_middle_stays_three_instructions() {
1756        let (mut names, mut func, block) = empty();
1757        let base = func.new_vreg(GPR);
1758        let other = func.new_vreg(GPR);
1759        let word = load(&mut func, &mut names, block, base);
1760        load(&mut func, &mut names, block, other);
1761        let sum = alu(&mut func, &mut names, block, "add_rr_64", word, other);
1762        store(&mut func, &mut names, block, base, sum);
1763
1764        assert_eq!(update(&mut func, &mut names), 0);
1765    }
1766
1767    /// Something writing the address register in the middle. A physical register is the only one
1768    /// this can happen to before the allocator runs, and the frame is addressed through two.
1769    #[test]
1770    fn a_run_whose_address_register_is_written_in_the_middle_stays_three_instructions() {
1771        let (mut names, mut func, block) = empty();
1772        let base = Reg::physical(rucc_target::x86_64::RSP);
1773        let other = func.new_vreg(GPR);
1774        let word = load(&mut func, &mut names, block, base);
1775        let sub = op(&mut names, "sub_ri_64");
1776        func.build(block, sub)
1777            .operand(Operand::write(base, GPR).with(Constraint::Reuse(1)))
1778            .uses(base, GPR)
1779            .imm(32)
1780            .finish();
1781        let sum = alu(&mut func, &mut names, block, "add_rr_64", word, other);
1782        store(&mut func, &mut names, block, base, sum);
1783
1784        assert_eq!(update(&mut func, &mut names), 0);
1785    }
1786
1787    /// Two locals whose displacements are both nothing so far. They are the same registers and the
1788    /// same number here and are two different places, and what says so is the list the frame layout
1789    /// has still to write an offset into.
1790    #[test]
1791    fn two_locals_the_layout_has_not_placed_yet_are_not_the_same_place() {
1792        let (mut names, mut func, block) = empty();
1793        let base = Reg::physical(rucc_target::x86_64::RSP);
1794        let other = func.new_vreg(GPR);
1795        let mov = op(&mut names, "mov_rm_64");
1796        let word = func.new_vreg(GPR);
1797        func.build(block, mov).def(word, GPR).mem(Mem::at(Operand::read(base, GPR))).finish();
1798        let read = func.insts(block).next().expect("the load");
1799        let sum = alu(&mut func, &mut names, block, "add_rr_64", word, other);
1800        let put = op(&mut names, "mov_mr_64");
1801        func.build(block, put).uses(sum, GPR).mem(Mem::at(Operand::read(base, GPR))).finish();
1802        let written = func.insts(block).nth(2).expect("the store");
1803
1804        let mut addresses = vec![(read, 3usize), (written, 4usize)];
1805        let mut arguments = Vec::new();
1806        let mut dynamic = Vec::new();
1807        let mut pending =
1808            Pending { addresses: &mut addresses, arguments: &mut arguments, dynamic: &mut dynamic };
1809        assert_eq!(stores(&mut func, &MACHINE, &FLAGS, &mut names, &mut pending), 0);
1810    }
1811
1812    /// The one local, which is the same place twice and folds. The entry the load was waiting on
1813    /// comes off the list, because the store is already waiting on the same one and adding the
1814    /// frame's offset twice would put the local at twice its distance.
1815    #[test]
1816    fn the_frame_entry_of_a_load_that_goes_comes_off_the_list() {
1817        let (mut names, mut func, block) = empty();
1818        let base = Reg::physical(rucc_target::x86_64::RSP);
1819        let other = func.new_vreg(GPR);
1820        let mov = op(&mut names, "mov_rm_64");
1821        let word = func.new_vreg(GPR);
1822        func.build(block, mov).def(word, GPR).mem(Mem::at(Operand::read(base, GPR))).finish();
1823        let read = func.insts(block).next().expect("the load");
1824        let sum = alu(&mut func, &mut names, block, "add_rr_64", word, other);
1825        let put = op(&mut names, "mov_mr_64");
1826        func.build(block, put).uses(sum, GPR).mem(Mem::at(Operand::read(base, GPR))).finish();
1827        let written = func.insts(block).nth(2).expect("the store");
1828
1829        let mut addresses = vec![(read, 3usize), (written, 3usize)];
1830        let mut arguments = Vec::new();
1831        let mut dynamic = Vec::new();
1832        let mut pending =
1833            Pending { addresses: &mut addresses, arguments: &mut arguments, dynamic: &mut dynamic };
1834        assert_eq!(stores(&mut func, &MACHINE, &FLAGS, &mut names, &mut pending), 1);
1835
1836        let inst = func.insts(block).next().expect("the addition");
1837        assert_eq!(addresses, [(inst, 3usize)], "one entry, on the instruction that is left");
1838    }
1839
1840    /// A run of the wrong width, which is a load of four bytes under an addition of eight.
1841    #[test]
1842    fn a_run_whose_widths_disagree_stays_three_instructions() {
1843        let (mut names, mut func, block) = empty();
1844        let base = func.new_vreg(GPR);
1845        let other = func.new_vreg(GPR);
1846        let into = func.new_vreg(GPR);
1847        let narrow = op(&mut names, "mov_rm_32");
1848        func.build(block, narrow)
1849            .def(into, GPR)
1850            .mem(Mem { disp: 16, ..Mem::at(Operand::read(base, GPR)) })
1851            .finish();
1852        let sum = alu(&mut func, &mut names, block, "add_rr_64", into, other);
1853        store(&mut func, &mut names, block, base, sum);
1854
1855        assert_eq!(update(&mut func, &mut names), 0);
1856    }
1857
1858    /// The shape tamnd/rucc#1424 was, which is a run with the carry reader in the middle of it.
1859    /// Joining it would put the addition below the `adc` and the carry the `adc` takes would be
1860    /// whatever was there before the addition ran.
1861    #[test]
1862    fn a_run_with_something_reading_the_condition_state_in_the_middle_stays_three_instructions() {
1863        let (mut names, mut func, block) = empty();
1864        let base = func.new_vreg(GPR);
1865        let other = func.new_vreg(GPR);
1866        let carry = func.new_vreg(GPR);
1867        let word = load(&mut func, &mut names, block, base);
1868        let sum = alu(&mut func, &mut names, block, "add_rr_64", word, other);
1869        alu(&mut func, &mut names, block, "adc_rr_64", carry, carry);
1870        store(&mut func, &mut names, block, base, sum);
1871
1872        assert_eq!(update(&mut func, &mut names), 0);
1873    }
1874
1875    /// The other half of the same question, which is something in the middle that writes the state
1876    /// rather than reads it. Joining the run would make the addition the last writer before the
1877    /// store instead of the subtraction, so whatever reads the state further down would read a
1878    /// different answer.
1879    #[test]
1880    fn a_run_with_something_writing_the_condition_state_in_the_middle_stays_three_instructions() {
1881        let (mut names, mut func, block) = empty();
1882        let base = func.new_vreg(GPR);
1883        let other = func.new_vreg(GPR);
1884        let left = func.new_vreg(GPR);
1885        let right = func.new_vreg(GPR);
1886        let word = load(&mut func, &mut names, block, base);
1887        let sum = alu(&mut func, &mut names, block, "add_rr_64", word, other);
1888        alu(&mut func, &mut names, block, "sub_rr_64", left, right);
1889        store(&mut func, &mut names, block, base, sum);
1890
1891        assert_eq!(update(&mut func, &mut names), 0);
1892    }
1893
1894    /// And the same run with an instruction in the middle that has no opinion about the state,
1895    /// which is what keeps the two above from being a rule against anything in the middle at all.
1896    #[test]
1897    fn a_run_with_a_move_in_the_middle_is_still_one_instruction() {
1898        let (mut names, mut func, block) = empty();
1899        let base = func.new_vreg(GPR);
1900        let other = func.new_vreg(GPR);
1901        let from = func.new_vreg(GPR);
1902        let into = func.new_vreg(GPR);
1903        let word = load(&mut func, &mut names, block, base);
1904        let sum = alu(&mut func, &mut names, block, "add_rr_64", word, other);
1905        let copy = op(&mut names, "mov_rr_64");
1906        func.build(block, copy).def(into, GPR).uses(from, GPR).finish();
1907        store(&mut func, &mut names, block, base, sum);
1908
1909        assert_eq!(update(&mut func, &mut names), 1);
1910        assert_eq!(shape(&func, &names, block), ["x64.mov_rr_64", "x64.add_mr_64"]);
1911    }
1912
1913    /// Every row of the table names four instructions this target has, all of one width.
1914    #[test]
1915    fn every_row_of_the_update_table_is_four_instructions_this_target_has() {
1916        for update in UPDATES {
1917            for name in [update.from, update.into, update.load, update.store] {
1918                assert!(MACHINE.has(name), "{name} is not an instruction");
1919            }
1920            let width = |name: &str| name.rsplit_once('_').map(|(_, width)| width.to_owned());
1921            assert_eq!(width(update.from), width(update.into), "{} changes width", update.from);
1922            assert_eq!(
1923                width(update.from),
1924                width(update.load),
1925                "{} loads another width",
1926                update.from
1927            );
1928            assert_eq!(
1929                width(update.from),
1930                width(update.store),
1931                "{} stores another width",
1932                update.from
1933            );
1934            assert!((MACHINE.takes_mem)(update.into), "{} reaches no memory", update.into);
1935            assert!(!(MACHINE.takes_mem)(update.from), "{} already reaches memory", update.from);
1936        }
1937    }
1938
1939    /// One row per arithmetic instruction this machine can do in place, for the reason the count
1940    /// over the fold table is there.
1941    #[test]
1942    fn the_update_table_covers_the_arithmetic_this_target_can_do_in_place() {
1943        assert_eq!(UPDATES.len(), 20, "five operations at four widths, and no multiply");
1944        let commuting = UPDATES.iter().filter(|update| update.commutes).count();
1945        assert_eq!(commuting, 16, "everything but the four subtractions");
1946    }
1947
1948    /// Two-address arithmetic of that name against a constant.
1949    fn alu_imm(
1950        func: &mut Func,
1951        names: &mut Interner,
1952        block: mir::Block,
1953        name: &str,
1954        source: Reg,
1955        value: i64,
1956    ) -> Reg {
1957        let answer = func.new_vreg(GPR);
1958        let opcode = op(names, name);
1959        func.build(block, opcode)
1960            .operand(Operand::write(answer, GPR).with(Constraint::Reuse(1)))
1961            .uses(source, GPR)
1962            .imm(value)
1963            .finish();
1964        answer
1965    }
1966
1967    /// The shape the constant run is for, which is what `*p += 1` is.
1968    #[test]
1969    fn a_word_read_changed_by_a_constant_and_written_back_becomes_one_instruction() {
1970        let (mut names, mut func, block) = empty();
1971        let base = func.new_vreg(GPR);
1972        let word = load(&mut func, &mut names, block, base);
1973        let sum = alu_imm(&mut func, &mut names, block, "add_ri_64", word, 1);
1974        store(&mut func, &mut names, block, base, sum);
1975
1976        assert_eq!(update(&mut func, &mut names), 1);
1977        assert_eq!(shape(&func, &names, block), ["x64.add_mi_64"]);
1978        let inst = func.insts(block).next().expect("the addition");
1979        let mem = func[inst].mem.expect("it writes memory");
1980        assert_eq!(func[mem].disp, 16, "the address came from the store");
1981        assert_eq!(func[mem].base, Some(0), "which is now the first operand and not the second");
1982        assert_eq!(func[func[inst].operands].len(), 1, "the base of the address and nothing else");
1983        assert_eq!(func[func[inst].operands][0].reg, base, "the address");
1984        assert_eq!(func[func[inst].imm.expect("the constant")].0, 1);
1985    }
1986
1987    /// The subtraction, which needs no arrangement chosen for it. A constant cannot be the left
1988    /// source, so the run that exists is the one the instruction computes.
1989    #[test]
1990    fn a_constant_taken_away_from_a_place_becomes_one_instruction() {
1991        let (mut names, mut func, block) = empty();
1992        let base = func.new_vreg(GPR);
1993        let word = load(&mut func, &mut names, block, base);
1994        let left = alu_imm(&mut func, &mut names, block, "sub_ri_64", word, 7);
1995        store(&mut func, &mut names, block, base, left);
1996
1997        assert_eq!(update(&mut func, &mut names), 1);
1998        assert_eq!(shape(&func, &names, block), ["x64.sub_mi_64"]);
1999        assert_eq!(func[func[func.insts(block).next().expect("it")].imm.expect("it")].0, 7);
2000    }
2001
2002    /// The narrow one, so that a width that is carried through wrong is a test that fails rather
2003    /// than a program that is wrong.
2004    #[test]
2005    fn a_byte_read_changed_by_a_constant_and_written_back_becomes_one_instruction() {
2006        let (mut names, mut func, block) = empty();
2007        let base = func.new_vreg(GPR);
2008        let word = func.new_vreg(GPR);
2009        let mov = op(&mut names, "mov_rm_8");
2010        func.build(block, mov)
2011            .def(word, GPR)
2012            .mem(Mem { disp: 16, ..Mem::at(Operand::read(base, GPR)) })
2013            .finish();
2014        let sum = alu_imm(&mut func, &mut names, block, "or_ri_8", word, 4);
2015        let put = op(&mut names, "mov_mr_8");
2016        func.build(block, put)
2017            .uses(sum, GPR)
2018            .mem(Mem { disp: 16, ..Mem::at(Operand::read(base, GPR)) })
2019            .finish();
2020
2021        assert_eq!(update(&mut func, &mut names), 1);
2022        assert_eq!(shape(&func, &names, block), ["x64.or_mi_8"]);
2023    }
2024
2025    /// The word read again by something else, which is the first of the four conditions and is
2026    /// asked here the way it is asked of the register run.
2027    #[test]
2028    fn a_word_a_constant_changes_and_something_else_reads_stays_three_instructions() {
2029        let (mut names, mut func, block) = empty();
2030        let base = func.new_vreg(GPR);
2031        let other = func.new_vreg(GPR);
2032        let word = load(&mut func, &mut names, block, base);
2033        let sum = alu_imm(&mut func, &mut names, block, "add_ri_64", word, 1);
2034        alu(&mut func, &mut names, block, "xor_rr_64", word, other);
2035        store(&mut func, &mut names, block, base, sum);
2036
2037        assert_eq!(update(&mut func, &mut names), 0);
2038    }
2039
2040    /// Something else in the middle that touches memory, which the one instruction left would be
2041    /// passing if the run were joined.
2042    #[test]
2043    fn a_constant_run_with_another_access_in_the_middle_stays_three_instructions() {
2044        let (mut names, mut func, block) = empty();
2045        let base = func.new_vreg(GPR);
2046        let elsewhere = func.new_vreg(GPR);
2047        let word = load(&mut func, &mut names, block, base);
2048        let sum = alu_imm(&mut func, &mut names, block, "add_ri_64", word, 1);
2049        load(&mut func, &mut names, block, elsewhere);
2050        store(&mut func, &mut names, block, base, sum);
2051
2052        assert_eq!(update(&mut func, &mut names), 0);
2053    }
2054
2055    /// The address register written between the load and the store, which would leave the one
2056    /// instruction naming a different place from the one the run read.
2057    #[test]
2058    fn a_constant_run_whose_address_register_is_written_in_the_middle_stays_three_instructions() {
2059        let (mut names, mut func, block) = empty();
2060        let base = Reg::physical(rucc_target::x86_64::RAX);
2061        let word = load(&mut func, &mut names, block, base);
2062        let sum = alu_imm(&mut func, &mut names, block, "add_ri_64", word, 1);
2063        let mov = op(&mut names, "mov_ri_64");
2064        func.build(block, mov).def(base, GPR).imm(0).finish();
2065        store(&mut func, &mut names, block, base, sum);
2066
2067        assert_eq!(update(&mut func, &mut names), 0);
2068    }
2069
2070    /// A store somewhere else, which is the run that is not a run.
2071    #[test]
2072    fn a_constant_written_to_another_address_stays_three_instructions() {
2073        let (mut names, mut func, block) = empty();
2074        let base = func.new_vreg(GPR);
2075        let elsewhere = func.new_vreg(GPR);
2076        let word = load(&mut func, &mut names, block, base);
2077        let sum = alu_imm(&mut func, &mut names, block, "add_ri_64", word, 1);
2078        store(&mut func, &mut names, block, elsewhere, sum);
2079
2080        assert_eq!(update(&mut func, &mut names), 0);
2081    }
2082
2083    /// A run of the wrong width, which is a load of four bytes under an addition of eight.
2084    #[test]
2085    fn a_constant_run_whose_widths_disagree_stays_three_instructions() {
2086        let (mut names, mut func, block) = empty();
2087        let base = func.new_vreg(GPR);
2088        let into = func.new_vreg(GPR);
2089        let narrow = op(&mut names, "mov_rm_32");
2090        func.build(block, narrow)
2091            .def(into, GPR)
2092            .mem(Mem { disp: 16, ..Mem::at(Operand::read(base, GPR)) })
2093            .finish();
2094        let sum = alu_imm(&mut func, &mut names, block, "add_ri_64", into, 1);
2095        store(&mut func, &mut names, block, base, sum);
2096
2097        assert_eq!(update(&mut func, &mut names), 0);
2098    }
2099
2100    /// The multiply, which has a two-address form against a constant and no form that leaves the
2101    /// product in memory, so the run stays three instructions.
2102    #[test]
2103    fn a_place_multiplied_by_a_constant_stays_three_instructions() {
2104        let (mut names, mut func, block) = empty();
2105        let base = func.new_vreg(GPR);
2106        let word = load(&mut func, &mut names, block, base);
2107        let product = alu_imm(&mut func, &mut names, block, "imul_ri_64", word, 3);
2108        store(&mut func, &mut names, block, base, product);
2109
2110        assert_eq!(update(&mut func, &mut names), 0);
2111    }
2112
2113    /// The constant run passes the condition state the same way the register run does, because the
2114    /// arithmetic moves down to the store here too.
2115    #[test]
2116    fn a_constant_run_with_a_carry_reader_in_the_middle_stays_three_instructions() {
2117        let (mut names, mut func, block) = empty();
2118        let base = func.new_vreg(GPR);
2119        let carry = func.new_vreg(GPR);
2120        let word = load(&mut func, &mut names, block, base);
2121        let sum = alu_imm(&mut func, &mut names, block, "add_ri_64", word, 1);
2122        alu(&mut func, &mut names, block, "adc_rr_64", carry, carry);
2123        store(&mut func, &mut names, block, base, sum);
2124
2125        assert_eq!(update(&mut func, &mut names), 0);
2126    }
2127
2128    /// The local, which is the same place twice and folds, and whose frame entry comes off the
2129    /// list for the reason the register run's does.
2130    #[test]
2131    fn the_frame_entry_of_a_load_a_constant_run_takes_comes_off_the_list() {
2132        let (mut names, mut func, block) = empty();
2133        let base = Reg::physical(rucc_target::x86_64::RSP);
2134        let mov = op(&mut names, "mov_rm_64");
2135        let word = func.new_vreg(GPR);
2136        func.build(block, mov).def(word, GPR).mem(Mem::at(Operand::read(base, GPR))).finish();
2137        let read = func.insts(block).next().expect("the load");
2138        let sum = alu_imm(&mut func, &mut names, block, "add_ri_64", word, 1);
2139        let put = op(&mut names, "mov_mr_64");
2140        func.build(block, put).uses(sum, GPR).mem(Mem::at(Operand::read(base, GPR))).finish();
2141        let written = func.insts(block).nth(2).expect("the store");
2142
2143        let mut addresses = vec![(read, 3usize), (written, 3usize)];
2144        let mut arguments = Vec::new();
2145        let mut dynamic = Vec::new();
2146        let mut pending =
2147            Pending { addresses: &mut addresses, arguments: &mut arguments, dynamic: &mut dynamic };
2148        assert_eq!(stores(&mut func, &MACHINE, &FLAGS, &mut names, &mut pending), 1);
2149
2150        let inst = func.insts(block).next().expect("the addition");
2151        assert_eq!(addresses, [(inst, 3usize)], "one entry, on the instruction that is left");
2152    }
2153
2154    /// Two locals the layout has not placed yet, which are the same addressing mode and not the
2155    /// same place, the way they are for the register run.
2156    #[test]
2157    fn two_locals_a_constant_run_would_join_are_not_the_same_place() {
2158        let (mut names, mut func, block) = empty();
2159        let base = Reg::physical(rucc_target::x86_64::RSP);
2160        let mov = op(&mut names, "mov_rm_64");
2161        let word = func.new_vreg(GPR);
2162        func.build(block, mov).def(word, GPR).mem(Mem::at(Operand::read(base, GPR))).finish();
2163        let read = func.insts(block).next().expect("the load");
2164        let sum = alu_imm(&mut func, &mut names, block, "add_ri_64", word, 1);
2165        let put = op(&mut names, "mov_mr_64");
2166        func.build(block, put).uses(sum, GPR).mem(Mem::at(Operand::read(base, GPR))).finish();
2167        let written = func.insts(block).nth(2).expect("the store");
2168
2169        let mut addresses = vec![(read, 3usize), (written, 4usize)];
2170        let mut arguments = Vec::new();
2171        let mut dynamic = Vec::new();
2172        let mut pending =
2173            Pending { addresses: &mut addresses, arguments: &mut arguments, dynamic: &mut dynamic };
2174        assert_eq!(stores(&mut func, &MACHINE, &FLAGS, &mut names, &mut pending), 0);
2175    }
2176
2177    /// Every row of the constant table names four instructions this target has, all of one width.
2178    #[test]
2179    fn every_row_of_the_bump_table_is_four_instructions_this_target_has() {
2180        for bump in BUMPS {
2181            for name in [bump.from, bump.into, bump.load, bump.store] {
2182                assert!(MACHINE.has(name), "{name} is not an instruction");
2183            }
2184            let width = |name: &str| name.rsplit_once('_').map(|(_, width)| width.to_owned());
2185            assert_eq!(width(bump.from), width(bump.into), "{} changes width", bump.from);
2186            assert_eq!(width(bump.from), width(bump.load), "{} loads another width", bump.from);
2187            assert_eq!(width(bump.from), width(bump.store), "{} stores another width", bump.from);
2188            assert!((MACHINE.takes_mem)(bump.into), "{} reaches no memory", bump.into);
2189            assert!(!(MACHINE.takes_mem)(bump.from), "{} already reaches memory", bump.from);
2190            assert!((MACHINE.takes_imm)(bump.into), "{} carries no constant", bump.into);
2191        }
2192    }
2193
2194    /// One row per arithmetic instruction this machine can do in place against a constant, which is
2195    /// the same five operations at the same four widths the register table has.
2196    #[test]
2197    fn the_bump_table_covers_the_arithmetic_this_target_can_do_in_place_against_a_constant() {
2198        assert_eq!(BUMPS.len(), 20, "five operations at four widths, and no multiply");
2199        let register: Vec<&str> = UPDATES.iter().map(|update| update.from).collect();
2200        for bump in BUMPS {
2201            let same = bump.from.replace("_ri_", "_rr_");
2202            assert!(register.contains(&same.as_str()), "{} has no register row", bump.from);
2203        }
2204    }
2205
2206    /// No instruction is in both tables, which is what lets the two walks be tried one after the
2207    /// other without either having to know what the other took.
2208    #[test]
2209    fn nothing_is_both_a_register_run_and_a_constant_run() {
2210        for bump in BUMPS {
2211            assert!(
2212                !UPDATES.iter().any(|update| update.from == bump.from),
2213                "{} starts both kinds of run",
2214                bump.from
2215            );
2216        }
2217    }
2218
2219    /// The shape the whole pass is for.
2220    #[test]
2221    fn a_load_read_once_by_an_addition_becomes_its_memory_operand() {
2222        let (mut names, mut func, block) = empty();
2223        let base = func.new_vreg(GPR);
2224        let other = func.new_vreg(GPR);
2225        let word = load(&mut func, &mut names, block, base);
2226        alu(&mut func, &mut names, block, "add_rr_64", other, word);
2227
2228        assert_eq!(combine(&mut func, &mut names), 1);
2229        assert_eq!(shape(&func, &names, block), ["x64.add_rm_64"]);
2230        let inst = func.insts(block).next().expect("the addition");
2231        let mem = func[inst].mem.expect("the addition reads memory now");
2232        assert_eq!(func[mem].disp, 16, "the load's displacement came with it");
2233        assert_eq!(func[mem].base, Some(2), "and names the operand behind the source it kept");
2234        assert_eq!(func[func[inst].operands][1].reg, other, "the source it kept");
2235        assert_eq!(func[func[inst].operands][2].reg, base, "the address it took on");
2236    }
2237
2238    /// The same load feeding the source the answer is tied to. The two sources are swapped, which
2239    /// an addition does not mind and is what lets this fold at all.
2240    #[test]
2241    fn a_load_feeding_the_first_source_of_an_addition_is_swapped_and_folded() {
2242        let (mut names, mut func, block) = empty();
2243        let base = func.new_vreg(GPR);
2244        let other = func.new_vreg(GPR);
2245        let word = load(&mut func, &mut names, block, base);
2246        alu(&mut func, &mut names, block, "add_rr_64", word, other);
2247
2248        assert_eq!(combine(&mut func, &mut names), 1);
2249        assert_eq!(shape(&func, &names, block), ["x64.add_rm_64"]);
2250        let inst = func.insts(block).next().expect("the addition");
2251        assert_eq!(func[func[inst].operands][1].reg, other);
2252    }
2253
2254    /// A subtraction with the load on the left, which is the one place the swap above would change
2255    /// the answer.
2256    #[test]
2257    fn a_load_feeding_the_left_of_a_subtraction_stays_a_load() {
2258        let (mut names, mut func, block) = empty();
2259        let base = func.new_vreg(GPR);
2260        let other = func.new_vreg(GPR);
2261        let word = load(&mut func, &mut names, block, base);
2262        alu(&mut func, &mut names, block, "sub_rr_64", word, other);
2263
2264        assert_eq!(combine(&mut func, &mut names), 0);
2265        assert_eq!(shape(&func, &names, block), ["x64.mov_rm_64", "x64.sub_rr_64"]);
2266    }
2267
2268    /// And the same subtraction the other way round, which is the one that folds.
2269    #[test]
2270    fn a_load_feeding_the_right_of_a_subtraction_folds() {
2271        let (mut names, mut func, block) = empty();
2272        let base = func.new_vreg(GPR);
2273        let other = func.new_vreg(GPR);
2274        let word = load(&mut func, &mut names, block, base);
2275        alu(&mut func, &mut names, block, "sub_rr_64", other, word);
2276
2277        assert_eq!(combine(&mut func, &mut names), 1);
2278        assert_eq!(shape(&func, &names, block), ["x64.sub_rm_64"]);
2279    }
2280
2281    /// Two readers. The load has to stay where it is for the second of them, so putting it into the
2282    /// first buys nothing and reads the memory twice.
2283    #[test]
2284    fn a_load_two_instructions_read_stays_a_load() {
2285        let (mut names, mut func, block) = empty();
2286        let base = func.new_vreg(GPR);
2287        let other = func.new_vreg(GPR);
2288        let word = load(&mut func, &mut names, block, base);
2289        alu(&mut func, &mut names, block, "add_rr_64", other, word);
2290        alu(&mut func, &mut names, block, "xor_rr_64", other, word);
2291
2292        assert_eq!(combine(&mut func, &mut names), 0);
2293        assert_eq!(
2294            shape(&func, &names, block),
2295            ["x64.mov_rm_64", "x64.add_rr_64", "x64.xor_rr_64"]
2296        );
2297    }
2298
2299    /// A store between the two. Whether it writes what the load reads is a question about two
2300    /// addresses, and the answer to not being able to tell is to leave the load where it is.
2301    #[test]
2302    fn a_load_with_a_store_between_it_and_its_reader_stays_a_load() {
2303        let (mut names, mut func, block) = empty();
2304        let base = func.new_vreg(GPR);
2305        let other = func.new_vreg(GPR);
2306        let word = load(&mut func, &mut names, block, base);
2307        let store = op(&mut names, "mov_mr_64");
2308        func.build(block, store).uses(other, GPR).mem(Mem::at(Operand::read(base, GPR))).finish();
2309        alu(&mut func, &mut names, block, "add_rr_64", other, word);
2310
2311        assert_eq!(combine(&mut func, &mut names), 0);
2312        assert_eq!(
2313            shape(&func, &names, block),
2314            ["x64.mov_rm_64", "x64.mov_mr_64", "x64.add_rr_64"]
2315        );
2316    }
2317
2318    /// Another load between the two, which writes nothing and is still not passed.
2319    ///
2320    /// This is the one that would be wrong if the walk asked only about writes. Where both reads
2321    /// are `volatile` the program said which of them happens first, and nothing here can tell that
2322    /// program from the one that did not say it, so neither may be reordered.
2323    #[test]
2324    fn a_load_with_another_load_between_it_and_its_reader_stays_a_load() {
2325        let (mut names, mut func, block) = empty();
2326        let base = func.new_vreg(GPR);
2327        let other = func.new_vreg(GPR);
2328        let word = load(&mut func, &mut names, block, base);
2329        load(&mut func, &mut names, block, other);
2330        alu(&mut func, &mut names, block, "add_rr_64", other, word);
2331
2332        assert_eq!(combine(&mut func, &mut names), 0);
2333        assert_eq!(
2334            shape(&func, &names, block),
2335            ["x64.mov_rm_64", "x64.mov_rm_64", "x64.add_rr_64"]
2336        );
2337    }
2338
2339    /// The second of two loads, read by arithmetic that reads the first as well. Nothing moves past
2340    /// anything, which is what makes this one the shape the pass is allowed to take.
2341    #[test]
2342    fn the_later_of_two_loads_is_the_one_that_folds() {
2343        let (mut names, mut func, block) = empty();
2344        let base = func.new_vreg(GPR);
2345        let other = func.new_vreg(GPR);
2346        let first = load(&mut func, &mut names, block, base);
2347        let second = load(&mut func, &mut names, block, other);
2348        alu(&mut func, &mut names, block, "add_rr_64", first, second);
2349
2350        assert_eq!(combine(&mut func, &mut names), 1);
2351        assert_eq!(shape(&func, &names, block), ["x64.mov_rm_64", "x64.add_rm_64"]);
2352        let addition = func.insts(block).nth(1).expect("the addition");
2353        assert_eq!(func[func[addition].operands][1].reg, first, "the earlier load is still read");
2354        assert_eq!(func[func[addition].operands][2].reg, other, "and the later one is the address");
2355    }
2356
2357    /// A call between the two. What a call does to memory is not in the instruction, so it is the
2358    /// same answer as the store and reached without asking about the address.
2359    #[test]
2360    fn a_load_with_a_call_between_it_and_its_reader_stays_a_load() {
2361        let (mut names, mut func, block) = empty();
2362        let base = func.new_vreg(GPR);
2363        let other = func.new_vreg(GPR);
2364        let word = load(&mut func, &mut names, block, base);
2365        let call = op(&mut names, "call");
2366        func.build(block, call).finish();
2367        alu(&mut func, &mut names, block, "add_rr_64", other, word);
2368
2369        assert_eq!(combine(&mut func, &mut names), 0);
2370        assert_eq!(shape(&func, &names, block), ["x64.mov_rm_64", "x64.call", "x64.add_rr_64"]);
2371    }
2372
2373    /// Something writing the register the address reads. A physical register is the only one this
2374    /// can happen to while the IR is in SSA form, and the frame is addressed through two of them.
2375    #[test]
2376    fn a_load_whose_address_register_is_written_between_the_two_stays_a_load() {
2377        let (mut names, mut func, block) = empty();
2378        let base = Reg::physical(rucc_target::x86_64::RSP);
2379        let other = func.new_vreg(GPR);
2380        let word = load(&mut func, &mut names, block, base);
2381        let sub = op(&mut names, "sub_ri_64");
2382        func.build(block, sub)
2383            .operand(Operand::write(base, GPR).with(Constraint::Reuse(1)))
2384            .uses(base, GPR)
2385            .imm(32)
2386            .finish();
2387        alu(&mut func, &mut names, block, "add_rr_64", other, word);
2388
2389        assert_eq!(combine(&mut func, &mut names), 0);
2390    }
2391
2392    /// A load of four bytes under an addition of eight. The register held what the load put in it
2393    /// and a memory operand holds what is at the address, which is a different number of bytes.
2394    #[test]
2395    fn a_load_of_the_wrong_width_stays_a_load() {
2396        let (mut names, mut func, block) = empty();
2397        let base = func.new_vreg(GPR);
2398        let other = func.new_vreg(GPR);
2399        let into = func.new_vreg(GPR);
2400        let narrow = op(&mut names, "mov_rm_32");
2401        func.build(block, narrow).def(into, GPR).mem(Mem::at(Operand::read(base, GPR))).finish();
2402        alu(&mut func, &mut names, block, "add_rr_64", other, into);
2403
2404        assert_eq!(combine(&mut func, &mut names), 0);
2405        assert_eq!(shape(&func, &names, block), ["x64.mov_rm_32", "x64.add_rr_64"]);
2406    }
2407
2408    /// A load whose value leaves the block on an edge. It is read by nothing in any operand vector
2409    /// and is read all the same, which is the count that is easy to get wrong.
2410    #[test]
2411    fn a_load_whose_value_an_edge_carries_stays_a_load() {
2412        let (mut names, mut func, block) = empty();
2413        let next = func.create_block();
2414        let base = func.new_vreg(GPR);
2415        let other = func.new_vreg(GPR);
2416        let word = load(&mut func, &mut names, block, base);
2417        alu(&mut func, &mut names, block, "add_rr_64", other, word);
2418        let arrived = func.new_vreg(GPR);
2419        func.params_mut(next).push(mir::Param { reg: arrived, class: GPR });
2420        *func.succs_mut(block) = vec![mir::BlockCall::with(next, vec![word])];
2421
2422        assert_eq!(combine(&mut func, &mut names), 0);
2423        assert_eq!(shape(&func, &names, block), ["x64.mov_rm_64", "x64.add_rr_64"]);
2424    }
2425
2426    /// A reader in another block, which is the whole of what block local means here.
2427    #[test]
2428    fn a_reader_in_another_block_stays_where_it_is() {
2429        let (mut names, mut func, block) = empty();
2430        let next = func.create_block();
2431        let base = func.new_vreg(GPR);
2432        let other = func.new_vreg(GPR);
2433        let word = load(&mut func, &mut names, block, base);
2434        alu(&mut func, &mut names, next, "add_rr_64", other, word);
2435
2436        assert_eq!(combine(&mut func, &mut names), 0);
2437        assert_eq!(shape(&func, &names, block), ["x64.mov_rm_64"]);
2438        assert_eq!(shape(&func, &names, next), ["x64.add_rr_64"]);
2439    }
2440
2441    /// A reader further down the block than the window reaches.
2442    #[test]
2443    fn a_reader_past_the_window_stays_where_it_is() {
2444        let (mut names, mut func, block) = empty();
2445        let base = func.new_vreg(GPR);
2446        let other = func.new_vreg(GPR);
2447        let word = load(&mut func, &mut names, block, base);
2448        let nop = op(&mut names, "nop");
2449        for _ in 0..WINDOW {
2450            func.build(block, nop).finish();
2451        }
2452        alu(&mut func, &mut names, block, "add_rr_64", other, word);
2453
2454        assert_eq!(combine(&mut func, &mut names), 0);
2455    }
2456
2457    /// And one instruction closer, which is the last place it still folds.
2458    #[test]
2459    fn a_reader_at_the_edge_of_the_window_folds() {
2460        let (mut names, mut func, block) = empty();
2461        let base = func.new_vreg(GPR);
2462        let other = func.new_vreg(GPR);
2463        let word = load(&mut func, &mut names, block, base);
2464        let nop = op(&mut names, "nop");
2465        for _ in 0..WINDOW - 1 {
2466            func.build(block, nop).finish();
2467        }
2468        alu(&mut func, &mut names, block, "add_rr_64", other, word);
2469
2470        assert_eq!(combine(&mut func, &mut names), 1);
2471    }
2472
2473    /// The entry a frame layout is waiting on moves with the load. Without this the displacement
2474    /// of a local would be written into an instruction that has gone.
2475    #[test]
2476    fn the_frame_entry_of_a_load_that_moves_goes_with_it() {
2477        let (mut names, mut func, block) = empty();
2478        let base = Reg::physical(rucc_target::x86_64::RSP);
2479        let other = func.new_vreg(GPR);
2480        let word = load(&mut func, &mut names, block, base);
2481        let reader = func.insts(block).nth(1);
2482        assert!(reader.is_none(), "the block holds the load alone so far");
2483        alu(&mut func, &mut names, block, "add_rr_64", other, word);
2484        let held = func.insts(block).next().expect("the load");
2485
2486        let mut addresses = vec![(held, 3usize)];
2487        let mut arguments = Vec::new();
2488        let mut dynamic = Vec::new();
2489        let mut pending =
2490            Pending { addresses: &mut addresses, arguments: &mut arguments, dynamic: &mut dynamic };
2491        assert_eq!(loads(&mut func, &MACHINE, &mut names, &mut pending), 1);
2492
2493        let inst = func.insts(block).next().expect("the addition");
2494        assert_eq!(addresses, [(inst, 3usize)], "the entry names the instruction that took it");
2495    }
2496
2497    /// A comparison whose right hand side came out of a load, which is `if (x < *p)`. The load is
2498    /// the side the instruction reads out of memory already, so the condition is the one that was
2499    /// written and only the opcode's shape changes.
2500    #[test]
2501    fn a_comparison_against_a_word_that_was_just_loaded_becomes_one_instruction() {
2502        let (mut names, mut func, block) = empty();
2503        let base = func.new_vreg(GPR);
2504        let other = func.new_vreg(GPR);
2505        let word = load(&mut func, &mut names, block, base);
2506        compare(&mut func, &mut names, block, "cmp_set_l_64", other, word);
2507
2508        assert_eq!(combine(&mut func, &mut names), 1);
2509        assert_eq!(shape(&func, &names, block), ["x64.cmp_set_l_rm_64"]);
2510        let inst = func.insts(block).next().expect("the comparison");
2511        let mem = func[inst].mem.expect("it reads memory");
2512        assert_eq!(func[mem].disp, 16, "the address came from the load");
2513        assert_eq!(func[mem].base, Some(2), "and names the operand behind the byte and the source");
2514        assert_eq!(func[func[inst].operands][1].reg, other, "the side it kept");
2515        assert_eq!(func[func[inst].operands][2].reg, base, "the address");
2516    }
2517
2518    /// The same comparison the other way round, which is `if (*p < x)`. The machine reads the
2519    /// right hand side out of memory and nothing else, so what comes out is the question asked
2520    /// backwards, and less than on the left is greater than on the right.
2521    #[test]
2522    fn a_comparison_whose_left_hand_side_was_just_loaded_turns_the_condition_over() {
2523        let (mut names, mut func, block) = empty();
2524        let base = func.new_vreg(GPR);
2525        let other = func.new_vreg(GPR);
2526        let word = load(&mut func, &mut names, block, base);
2527        compare(&mut func, &mut names, block, "cmp_set_l_64", word, other);
2528
2529        assert_eq!(combine(&mut func, &mut names), 1);
2530        assert_eq!(shape(&func, &names, block), ["x64.cmp_set_g_rm_64"]);
2531        let inst = func.insts(block).next().expect("the comparison");
2532        assert_eq!(func[func[inst].operands][1].reg, other, "the side it kept");
2533    }
2534
2535    /// Equality on the left, which is the case the turning over has to leave alone. Two values are
2536    /// equal in whichever order they are read, so the row for it names itself on both sides and a
2537    /// table that had reached for the opposite condition would have written inequality here.
2538    #[test]
2539    fn an_equality_folded_on_either_side_is_the_same_comparison() {
2540        for (first, second) in [(true, false), (false, true)] {
2541            let (mut names, mut func, block) = empty();
2542            let base = func.new_vreg(GPR);
2543            let other = func.new_vreg(GPR);
2544            let word = load(&mut func, &mut names, block, base);
2545            let left = if first { word } else { other };
2546            let right = if second { word } else { other };
2547            compare(&mut func, &mut names, block, "cmp_set_e_64", left, right);
2548
2549            assert_eq!(combine(&mut func, &mut names), 1);
2550            assert_eq!(shape(&func, &names, block), ["x64.cmp_set_e_rm_64"]);
2551        }
2552    }
2553
2554    /// A comparison against a constant, which is `if (*p < 7)`. There is one source rather than
2555    /// two, so the side the load filled is the only side there is and the condition stays as it
2556    /// was written. What is left in front of the address is the byte on its own, which puts the
2557    /// base one position earlier than the comparison of two registers leaves it.
2558    #[test]
2559    fn a_comparison_against_a_constant_takes_the_load_on_as_its_memory_operand() {
2560        let (mut names, mut func, block) = empty();
2561        let base = func.new_vreg(GPR);
2562        let byte = func.new_vreg(GPR);
2563        let word = load(&mut func, &mut names, block, base);
2564        let opcode = op(&mut names, "cmp_set_l_ri_64");
2565        func.build(block, opcode).def(byte, GPR).uses(word, GPR).imm(7).finish();
2566
2567        assert_eq!(combine(&mut func, &mut names), 1);
2568        assert_eq!(shape(&func, &names, block), ["x64.cmp_set_l_mi_64"]);
2569        let inst = func.insts(block).next().expect("the comparison");
2570        let mem = func[inst].mem.expect("it reads memory now");
2571        assert_eq!(func[mem].disp, 16, "the load's displacement came with it");
2572        assert_eq!(func[mem].base, Some(1), "and names the operand behind the byte");
2573        assert_eq!(func[func[inst].operands][0].reg, byte, "the byte it sets");
2574        assert_eq!(func[func[inst].operands][1].reg, base, "the address it took on");
2575        let imm = func[inst].imm.expect("the constant is still on it");
2576        assert_eq!(func[imm].0, 7, "and is the one that was written");
2577    }
2578
2579    /// A load that nothing but a widening reads becomes the load that widens, at every width the
2580    /// machine has one for, and the address and the register written come with it.
2581    #[test]
2582    fn a_load_only_a_widening_reads_becomes_a_load_that_widens() {
2583        for row in WIDENINGS {
2584            let (mut names, mut func, block) = empty();
2585            let base = func.new_vreg(GPR);
2586            let narrow = func.new_vreg(GPR);
2587            let wide = func.new_vreg(GPR);
2588            let read = op(&mut names, row.load);
2589            func.build(block, read)
2590                .def(narrow, GPR)
2591                .mem(Mem { disp: 16, ..Mem::at(Operand::read(base, GPR)) })
2592                .finish();
2593            let widen = op(&mut names, row.from);
2594            func.build(block, widen).def(wide, GPR).uses(narrow, GPR).finish();
2595
2596            assert_eq!(combine(&mut func, &mut names), 1, "{} took no load", row.from);
2597            assert_eq!(shape(&func, &names, block), [format!("x64.{}", row.into)]);
2598            let inst = func.insts(block).next().expect("the widening");
2599            assert_eq!(func[func[inst].operands][0].reg, wide, "{} writes elsewhere", row.from);
2600            assert_eq!(func[func[inst].operands][1].reg, base, "{} lost the address", row.from);
2601            let mem = func[inst].mem.expect("it reads memory now");
2602            assert_eq!(func[mem].disp, 16, "the load's displacement came with it");
2603            assert_eq!(func[mem].base, Some(1), "and names the operand behind the answer");
2604        }
2605    }
2606
2607    /// A load that something besides the widening reads stays a load, since the value has to be
2608    /// in a register for the other reader anyway.
2609    #[test]
2610    fn a_load_read_by_a_widening_and_something_else_stays_where_it_is() {
2611        let (mut names, mut func, block) = empty();
2612        let base = func.new_vreg(GPR);
2613        let other = func.new_vreg(GPR);
2614        let narrow = func.new_vreg(GPR);
2615        let wide = func.new_vreg(GPR);
2616        let read = op(&mut names, "mov_rm_32");
2617        func.build(block, read)
2618            .def(narrow, GPR)
2619            .mem(Mem { disp: 16, ..Mem::at(Operand::read(base, GPR)) })
2620            .finish();
2621        let widen = op(&mut names, "movsxd_32_64");
2622        func.build(block, widen).def(wide, GPR).uses(narrow, GPR).finish();
2623        alu(&mut func, &mut names, block, "add_rr_32", other, narrow);
2624
2625        assert_eq!(combine(&mut func, &mut names), 0);
2626        assert_eq!(
2627            shape(&func, &names, block),
2628            ["x64.mov_rm_32", "x64.movsxd_32_64", "x64.add_rr_32"]
2629        );
2630    }
2631
2632    /// A load the program insisted on keeps its own instruction, the same as it does in front of
2633    /// arithmetic.
2634    #[test]
2635    fn a_volatile_load_is_not_widened_on_the_way_in() {
2636        let (mut names, mut func, block) = empty();
2637        let base = func.new_vreg(GPR);
2638        let narrow = func.new_vreg(GPR);
2639        let wide = func.new_vreg(GPR);
2640        let read = op(&mut names, "mov_rm_16");
2641        func.build(block, read)
2642            .def(narrow, GPR)
2643            .mem(Mem { disp: 16, ..Mem::at(Operand::read(base, GPR)) })
2644            .flags(Flags::VOLATILE)
2645            .finish();
2646        let widen = op(&mut names, "movsx_16_32");
2647        func.build(block, widen).def(wide, GPR).uses(narrow, GPR).finish();
2648
2649        assert_eq!(combine(&mut func, &mut names), 0);
2650        assert_eq!(shape(&func, &names, block), ["x64.mov_rm_16", "x64.movsx_16_32"]);
2651    }
2652
2653    /// Every widening names instructions this target has, reads memory only once folded, and
2654    /// takes a load of the width it widens from.
2655    #[test]
2656    fn every_widening_takes_a_load_of_the_width_it_widens_from() {
2657        let from = |name: &str| {
2658            name.split('_').find(|part| part.parse::<u32>().is_ok()).map(str::to_owned)
2659        };
2660        let width = |name: &str| name.rsplit_once('_').map(|(_, width)| width.to_owned());
2661        for row in WIDENINGS {
2662            assert!(MACHINE.has(row.from), "{} is not an instruction", row.from);
2663            assert!(MACHINE.has(row.into), "{} is not an instruction", row.into);
2664            assert!(MACHINE.has(row.load), "{} is not an instruction", row.load);
2665            assert_eq!(from(row.from), width(row.load), "{} loads another width", row.from);
2666            assert!((MACHINE.takes_mem)(row.into), "{} reads no memory", row.into);
2667            assert!(!(MACHINE.takes_mem)(row.from), "{} already reads memory", row.from);
2668            assert_eq!(row.swapped, None, "{} has nothing to swap", row.from);
2669        }
2670    }
2671
2672    /// Every row of the table names instructions this target has, and names a load and an
2673    /// arithmetic whose widths agree. A row that got one of the three wrong would propose an
2674    /// instruction the change framework turns down, which is a fold that silently never happens.
2675    #[test]
2676    fn every_row_of_the_table_is_three_instructions_this_target_has() {
2677        for fold in FOLDS {
2678            assert!(MACHINE.has(fold.from), "{} is not an instruction", fold.from);
2679            assert!(MACHINE.has(fold.into), "{} is not an instruction", fold.into);
2680            assert!(MACHINE.has(fold.load), "{} is not an instruction", fold.load);
2681            let width = |name: &str| name.rsplit_once('_').map(|(_, width)| width.to_owned());
2682            assert_eq!(width(fold.from), width(fold.into), "{} changes width", fold.from);
2683            assert_eq!(width(fold.from), width(fold.load), "{} loads another width", fold.from);
2684            assert!((MACHINE.takes_mem)(fold.into), "{} reads no memory", fold.into);
2685            assert!(!(MACHINE.takes_mem)(fold.from), "{} already reads memory", fold.from);
2686            let Some(swapped) = fold.swapped else { continue };
2687            assert!(MACHINE.has(swapped), "{swapped} is not an instruction");
2688            assert_eq!(width(fold.from), width(swapped), "{} changes width", fold.from);
2689            assert!((MACHINE.takes_mem)(swapped), "{swapped} reads no memory");
2690        }
2691    }
2692
2693    /// One row per arithmetic instruction the target has that could take one, and one per
2694    /// comparison. The counts are here so that an instruction added to the target without a row
2695    /// shows up as a number rather than as a fold nobody noticed was missing.
2696    #[test]
2697    fn the_table_covers_the_arithmetic_and_the_comparisons_this_target_has() {
2698        let compares = FOLDS.iter().filter(|fold| fold.from.starts_with("cmp_set_")).count();
2699        assert_eq!(
2700            compares, 80,
2701            "ten conditions at four widths, against a register and a constant"
2702        );
2703        let arithmetic = FOLDS.len() - compares;
2704        assert_eq!(arithmetic, 23, "six operations at four widths, less the eight bit multiply");
2705        let swapped = FOLDS.iter().filter(|fold| fold.swapped.is_some()).count();
2706        assert_eq!(swapped, 59, "everything but the four subtractions and the constant compares");
2707    }
2708
2709    /// What a comparison folded on its left hand side comes out as.
2710    ///
2711    /// Reading the two sides the other way round turns the question over, so the row has to name
2712    /// the opposite ordering rather than the opposite answer. Less than and greater than are the
2713    /// pair, and equality and inequality are the two that come back to themselves, which is what
2714    /// makes this worth a test of its own: a row that had turned equality into inequality would be
2715    /// wrong in a way no width check and no name check would catch.
2716    #[test]
2717    fn a_comparison_folded_on_its_left_hand_side_asks_the_same_question_backwards() {
2718        let turned = |condition: &str| match condition {
2719            "e" => "e",
2720            "ne" => "ne",
2721            "l" => "g",
2722            "g" => "l",
2723            "le" => "ge",
2724            "ge" => "le",
2725            "b" => "a",
2726            "a" => "b",
2727            "be" => "ae",
2728            "ae" => "be",
2729            other => panic!("{other} is not a condition this machine has"),
2730        };
2731        let compares = FOLDS
2732            .iter()
2733            .filter(|fold| fold.from.starts_with("cmp_set_") && !fold.from.contains("_ri_"));
2734        for fold in compares {
2735            let (front, width) = fold.from.rsplit_once('_').expect("a name ending in a width");
2736            let condition = front.strip_prefix("cmp_set_").expect("a name with a condition");
2737            assert_eq!(fold.into, format!("cmp_set_{condition}_rm_{width}"));
2738            let wanted = format!("cmp_set_{}_rm_{width}", turned(condition));
2739            assert_eq!(fold.swapped, Some(wanted.as_str()), "{} turns over wrongly", fold.from);
2740        }
2741    }
2742
2743    /// What a comparison against a constant comes out as. There is one source rather than two, so
2744    /// the condition is the one that was written and there is no other arrangement to offer. A row
2745    /// that had filled in a `swapped` would be asking the pass to read the constant out of a
2746    /// register, which is not an instruction this machine has.
2747    #[test]
2748    fn a_comparison_against_a_constant_keeps_its_condition_and_has_nothing_to_swap() {
2749        let compares = FOLDS
2750            .iter()
2751            .filter(|fold| fold.from.starts_with("cmp_set_") && fold.from.contains("_ri_"));
2752        let mut rows = 0;
2753        for fold in compares {
2754            let (front, width) = fold.from.rsplit_once('_').expect("a name ending in a width");
2755            let front = front.strip_suffix("_ri").expect("a name against a constant");
2756            let condition = front.strip_prefix("cmp_set_").expect("a name with a condition");
2757            assert_eq!(fold.into, format!("cmp_set_{condition}_mi_{width}"));
2758            assert_eq!(fold.swapped, None, "{} has a side to swap", fold.from);
2759            assert_eq!(fold.load, format!("mov_rm_{width}"), "{} loads wrongly", fold.from);
2760            rows += 1;
2761        }
2762        assert_eq!(rows, 40, "ten conditions at four widths");
2763    }
2764
2765    /// A load the program insisted on, which is `volatile int *p; return *p + x;`.
2766    ///
2767    /// The fold would leave one instruction that reads the place, which is still one read of it,
2768    /// and the program would still do what it says. What it would not be is the load the program
2769    /// wrote, and a machine whose memory does something when it is read is a machine where the
2770    /// difference between one instruction and two is the reason the word was written.
2771    #[test]
2772    fn a_load_the_program_insisted_on_is_left_where_it_stands() {
2773        let (mut names, mut func, block) = empty();
2774        let base = func.new_vreg(GPR);
2775        let other = func.new_vreg(GPR);
2776        let word = insisted_load(&mut func, &mut names, block, base);
2777        alu(&mut func, &mut names, block, "add_rr_64", word, other);
2778
2779        assert_eq!(combine(&mut func, &mut names), 0);
2780        assert_eq!(shape(&func, &names, block), ["x64.mov_rm_64", "x64.add_rr_64"]);
2781    }
2782
2783    /// The same load with the arithmetic that reads it and the store that puts it back, which is
2784    /// `volatile int *p; *p += x;`. Three instructions in and three out, which is what GCC 13
2785    /// writes for it and what the spec asks for.
2786    #[test]
2787    fn a_run_whose_load_the_program_insisted_on_stays_three_instructions() {
2788        let (mut names, mut func, block) = empty();
2789        let base = func.new_vreg(GPR);
2790        let other = func.new_vreg(GPR);
2791        let word = insisted_load(&mut func, &mut names, block, base);
2792        let sum = alu(&mut func, &mut names, block, "add_rr_64", word, other);
2793        store(&mut func, &mut names, block, base, sum);
2794
2795        assert_eq!(update(&mut func, &mut names), 0);
2796    }
2797
2798    /// The other end of the run, which is the half the load's own flag does not cover. A place
2799    /// read plainly and written back to a volatile address is a program that asked for the write
2800    /// to be its own instruction, and both ends are asked about because either one of them says
2801    /// so on its own.
2802    #[test]
2803    fn a_run_whose_store_the_program_insisted_on_stays_three_instructions() {
2804        let (mut names, mut func, block) = empty();
2805        let base = func.new_vreg(GPR);
2806        let other = func.new_vreg(GPR);
2807        let word = load(&mut func, &mut names, block, base);
2808        let sum = alu(&mut func, &mut names, block, "add_rr_64", word, other);
2809        insisted_store(&mut func, &mut names, block, base, sum);
2810
2811        assert_eq!(update(&mut func, &mut names), 0);
2812    }
2813
2814    /// The run against a constant, which is `volatile int *p; *p += 1;` and is the commoner of
2815    /// the two. It is a separate walk over a separate table, so it is asked separately.
2816    #[test]
2817    fn a_constant_run_the_program_insisted_on_stays_three_instructions() {
2818        let (mut names, mut func, block) = empty();
2819        let base = func.new_vreg(GPR);
2820        let word = insisted_load(&mut func, &mut names, block, base);
2821        let sum = alu_imm(&mut func, &mut names, block, "add_ri_64", word, 1);
2822        store(&mut func, &mut names, block, base, sum);
2823
2824        assert_eq!(update(&mut func, &mut names), 0);
2825    }
2826
2827    /// The same run with the flag on the store instead of on the load.
2828    #[test]
2829    fn a_constant_run_whose_store_the_program_insisted_on_stays_three_instructions() {
2830        let (mut names, mut func, block) = empty();
2831        let base = func.new_vreg(GPR);
2832        let word = load(&mut func, &mut names, block, base);
2833        let sum = alu_imm(&mut func, &mut names, block, "add_ri_64", word, 1);
2834        insisted_store(&mut func, &mut names, block, base, sum);
2835
2836        assert_eq!(update(&mut func, &mut names), 0);
2837    }
2838
2839    /// A plain load of the same shape, so that the five above are read as the flag doing the
2840    /// work rather than as the runs being built wrongly.
2841    #[test]
2842    fn the_same_runs_without_the_flag_are_the_ones_the_pass_takes() {
2843        let (mut names, mut func, block) = empty();
2844        let base = func.new_vreg(GPR);
2845        let other = func.new_vreg(GPR);
2846        let word = load(&mut func, &mut names, block, base);
2847        let sum = alu(&mut func, &mut names, block, "add_rr_64", word, other);
2848        store(&mut func, &mut names, block, base, sum);
2849
2850        assert_eq!(update(&mut func, &mut names), 1);
2851        assert_eq!(shape(&func, &names, block), ["x64.add_mr_64"]);
2852    }
2853}