Skip to main content

rucc_codegen/
expand.rs

1//! The IR rewrites the machine needs before a rule can be asked anything.
2//!
3//! Design: `spec/10-backend.md` section 10.2, which is where the ordering comes from.
4//!
5//! Everything else in this crate turns an instruction into instructions. There are two things a
6//! rule cannot do, and what is done about each of them instead is here.
7//!
8//! The first is a new shape of control flow. A rule replaces a term with a term and the
9//! replacement has nowhere to put a block, so a construct that becomes blocks has to be rewritten
10//! before selection rather than during it. There is one such construct today and it is `switch`.
11//! Every other terminator leaves a block with one successor or two, which is what the block layout
12//! writes jumps for, and a `switch` leaves it with as many as the program had cases.
13//!
14//! The second is arithmetic on what a rule matched. A rule may name a constant and pass it along,
15//! and it may not add to one or read it as something else, because the pattern language is a
16//! pattern language and giving it a way to compute would make a rule set a program the solver has
17//! to reason about rather than a table it can check a line of at a time. So an instruction whose
18//! lowering needs a value worked out from another one is rewritten here into instructions whose
19//! lowerings do not. Four of them are floats: a float constant, a negation, and the two conversions
20//! between a float and an unsigned integer. The other two move a block of memory, where the
21//! arithmetic is the offset of each word from the front of it.
22//!
23//! # Why a copy is a run of moves and not a call
24//!
25//! A `memcpy` in the IR is not a call to `memcpy`. It is what the front end writes for a structure
26//! assigned, passed or returned by value, and a `memset` is what it writes for the part of an
27//! object an initialiser left unnamed, so a program with a `struct` in it reaches one almost at
28//! once and the size is a constant every time.
29//!
30//! A constant size is what makes the moves the right answer. A four byte copy written as a call
31//! costs the call and the two arguments and gives back four bytes moved, which is more instructions
32//! than the move it replaced and slower than all of them. Every real compiler writes the moves
33//! under some threshold for that reason, and above the threshold writes the call, which is where
34//! this stops: the call needs a `memcpy` to exist, and a statically linked program has nowhere to
35//! get one from until the compiler runtime in tamnd/rucc#277 exists. So a copy larger than the
36//! threshold is refused by name rather than written wrong.
37//!
38//! # Why the chain a `switch` becomes is the backend's and not the front end's
39//!
40//! What a `switch` should become is a target decision and not a language one. A chain of compares
41//! is right for three cases and wrong for two hundred, where the answer is a jump table, and wrong
42//! again for twenty spread over a million, where it is a binary search on the value. A front end
43//! that picked one would be picking for every target at once, and the IR would no longer hold what
44//! the program said. So the `switch` survives as far as here, and here is where it is given up.
45//!
46//! What is written today is the chain, which `spec/10-backend.md` calls the version every compiler
47//! starts with. It is correct for any number of cases and it is slow for a large one. A jump table
48//! wants a read only section to put the table in and a relocation to reach it, and neither exists
49//! yet, so the chain is also the only one that could be written today.
50
51use std::cmp::Ordering;
52use std::collections::HashMap;
53
54use rucc_base::Interner;
55use rucc_ir::{
56    BlockCall, Builder, CallInfo, Def, Extra, Flags, FloatPred, Func, Imm, Inst, InstData, IntPred,
57    MemInfo, MemOrder, Opcode, Signature, Type, Value,
58};
59
60/// Rewrites every `switch` in the function into branches, and leaves everything else alone.
61///
62/// The function is changed in place, which is what makes this the last thing that reads the IR as
63/// the front end built it. `--emit=ir` prints before this runs, and nothing after this asks what
64/// the program said, only what the machine has to do.
65pub fn switches(func: &mut Func) {
66    let found: Vec<Inst> = func
67        .blocks()
68        .filter_map(|block| func.terminator(block))
69        .filter(|&inst| func[inst].opcode == Opcode::Switch)
70        .collect();
71    for inst in found {
72        chain(func, inst);
73    }
74}
75
76/// One `switch`, as a compare and a branch for each case in the order they were written.
77///
78/// The block the `switch` was in gets the first compare, and each case after the first gets a
79/// block of its own that the one before it falls to when its compare failed. The last of them
80/// falls to the default, so the default is not a block anything is created for and the chain costs
81/// one block per case less one.
82///
83/// The order is the order the cases are in, which is the order the program wrote them and not a
84/// sorted one. Sorting would be the first half of a binary search and the second half is not here,
85/// so it would cost a reader the ability to look at the assembly and see their own `switch`, and
86/// buy nothing.
87fn chain(func: &mut Func, inst: Inst) {
88    let block = func.block_of(inst).expect("a terminator is in a block");
89    let span = func.span(inst);
90    let Extra::Switch(info) = func[inst].extra else { return };
91    let info = func[info];
92    let value = func[func[inst].args][0];
93    // The lane, because a `switch` on a vector is not a thing C can write and the immediates are
94    // an integer's either way.
95    let ty = func[value].ty.lane();
96    let calls: Vec<BlockCall> = func[info.targets].to_vec();
97    let cases: Vec<Imm> = func[info.cases].to_vec();
98    let Some((default, arms)) = calls.split_first() else { return };
99
100    // Before anything is written, because the builder appends and the `switch` is where the
101    // appending has to happen.
102    func.remove_inst(inst);
103
104    // A `switch` with nothing but a default is a jump, which is worth writing down rather than
105    // refusing: it is what a `switch` whose only label is `default` is, and it is also what one
106    // whose cases were all folded away by a later pass would be.
107    let Some((first, rest)) = arms.split_first() else {
108        let args: Vec<Value> = func[default.args].to_vec();
109        Builder::new(func, block).at(span).jump(default.block, &args);
110        return;
111    };
112
113    let mut at = block;
114    for (index, arm) in std::iter::once(first).chain(rest).enumerate() {
115        let last = index + 1 == arms.len();
116        let next = if last { default.block } else { func.create_block() };
117        let onward: Vec<Value> = if last { func[default.args].to_vec() } else { Vec::new() };
118        let taken: Vec<Value> = func[arm.args].to_vec();
119        let case = cases[index].signed(ty);
120
121        let mut build = Builder::new(func, at).at(span);
122        let want = build.iconst(ty, case);
123        let same = build.icmp(IntPred::Eq, value, want);
124        build.br_if(same, arm.block, &taken, next, &onward);
125        at = next;
126    }
127}
128
129/// Rewrites every ordered access into the plain access this machine already makes ordered, and
130/// leaves a barrier where the machine needs one.
131///
132/// This is the one pass here whose reason is a memory model rather than a missing instruction, so
133/// it is worth writing down what the model says. x86-64 is total store order. Every load is an
134/// acquire, every store is a release, and an aligned access no wider than a word is indivisible
135/// whether or not anybody asked for one. So an `atomic_load` at any ordering is the same `mov` a
136/// `load` is, and so is an `atomic_store` at every ordering except the strongest, and rewriting
137/// them into the plain access is not an approximation: it is the whole of what the machine does.
138///
139/// The one thing total store order does not give is a store followed by a load of a different
140/// address staying in that order, and that is exactly what sequential consistency is missing. So a
141/// sequentially consistent store is the same `mov` with an `mfence` behind it, which is the pair
142/// gcc 16.2.0 writes. The fence is left in the IR as a `fence` rather than written here, because
143/// what a barrier costs is a target question and [`crate::lower`] is where the target answers are.
144///
145/// A `fence` the program wrote is left alone for the same reason. Every ordering below the
146/// strongest is nothing at all on this machine and the strongest is one instruction, and both of
147/// those are decided by name in [`crate::lower`] where the instruction lives.
148///
149/// # Why the width is checked
150///
151/// An access is only indivisible if the machine can do it in one go, which here means one, two,
152/// four or eight bytes at an address aligned to its own width. Anything else is a run of accesses
153/// and a run of accesses is not atomic at all, so it is left as the opcode it was and no rule
154/// covers it, which is a compile error naming the instruction. That is the right answer: an
155/// atomic access the machine cannot make atomic has no correct lowering, and a wrong one that
156/// looks right is worse than a refusal. C says the same thing through `__atomic_is_lock_free`.
157///
158/// `word` is how many bytes the widest indivisible access carries, which is the same number the
159/// widest move carries and is read from the machine for the reason [`bulk`] reads it.
160///
161/// This runs before every other pass here, so that what it produces is an ordinary load or store
162/// that the width legalisation and everything after it get to see. An ordered access at a width the
163/// machine has no register for would otherwise be a shape nothing later understands, since every
164/// pass after this one is written about `load` and `store` by name.
165pub fn orderings(func: &mut Func, word: u32) {
166    let found: Vec<Inst> =
167        func.blocks().flat_map(|block| func.insts(block).collect::<Vec<_>>()).collect();
168    for inst in found {
169        match func[inst].opcode {
170            Opcode::AtomicLoad => relaxed(func, inst, Opcode::Load, word),
171            Opcode::AtomicStore => relaxed(func, inst, Opcode::Store, word),
172            _ => {}
173        }
174    }
175}
176
177/// One ordered access as the plain one, with a barrier behind it when the ordering asked for more
178/// than the machine gives for free.
179///
180/// The ordering is taken off the access rather than left on it, because the IR verifier refuses an
181/// ordering on a plain access, and it refuses one for a good reason: a plain load may be moved,
182/// duplicated and dropped, and an ordering that survived on one would be a claim nothing downstream
183/// honours. What is true after this pass is that the ordering has been discharged, and the way to
184/// say that is to stop carrying it.
185///
186/// A sequentially consistent store becomes the store and then the fence, and it is built that way
187/// round: the plain store is put in front of the instruction and the instruction itself becomes the
188/// fence. Doing it the other way would need somewhere to insert behind an instruction, and there is
189/// nothing to gain from having two ways to insert.
190fn relaxed(func: &mut Func, inst: Inst, plain: Opcode, word: u32) {
191    let Extra::Mem(mem) = func[inst].extra else { return };
192    let info = func[mem];
193    let ty = match plain {
194        Opcode::Store => match func[func[inst].args].first() {
195            Some(&value) => func[value].ty,
196            None => return,
197        },
198        _ => produced(func, inst),
199    };
200    if !indivisible(ty, info, word) {
201        return;
202    }
203    let unordered = MemInfo { order: MemOrder::NotAtomic, ..info };
204
205    if plain == Opcode::Store && info.order == MemOrder::SeqCst {
206        let [value, addr] = func[func[inst].args] else { return };
207        write(func, inst, value, addr, unordered);
208        let none = func.push_values(&[]);
209        let data = &mut func[inst];
210        data.opcode = Opcode::Fence;
211        data.args = none;
212        data.extra = Extra::Order(MemOrder::SeqCst);
213        data.flags = data.flags.intersection(Flags::legal_on(Opcode::Fence));
214        return;
215    }
216
217    let plainly = func.add_mem(unordered);
218    let data = &mut func[inst];
219    data.opcode = plain;
220    data.extra = Extra::Mem(plainly);
221    data.flags = data.flags.intersection(Flags::legal_on(plain));
222}
223
224/// Whether this machine does an access of this type in one go.
225///
226/// One, two, four or eight bytes, at an address aligned to at least that many. The alignment is the
227/// front end's answer for the type being accessed, which for every type C can spell is its own
228/// width, so what this actually refuses is a `long double` and an access the program underaligned
229/// on purpose.
230///
231/// The width is the storage the value takes and not the bits it holds, because that is what the
232/// access moves. A `bool` is one bit of value in one byte of memory and one byte is indivisible, so
233/// rounding up is what makes an ordered access of one work rather than a refusal nobody wanted. An
234/// address is the exception the other way: the IR gives a pointer no width at all, since how wide
235/// one is belongs to the target, so the target's number is used for it.
236fn indivisible(ty: Type, info: MemInfo, word: u32) -> bool {
237    let bytes = if ty.is_ptr() { word } else { ty.bits().div_ceil(8) };
238    ty.is_scalar() && bytes.is_power_of_two() && bytes <= word && info.align >= bytes
239}
240
241/// Rewrites the float instructions no rule can be written for, and leaves the rest alone.
242///
243/// Each of them needs a value worked out from one the pattern matched, which is the one thing the
244/// rule language deliberately cannot do. A float constant is an integer constant read as a float,
245/// and reading it is arithmetic on the immediate. A negation is an exclusive or with a mask that
246/// depends on the format. A conversion between a float and an integer is that conversion at a
247/// width the machine has, which is a width neither the pattern nor the replacement can work out.
248///
249/// What is left after this is a function whose float instructions are each one machine
250/// instruction, so what a rule is asked stays a table. The conversions between a float and an
251/// unsigned sixty four bit integer are the two that are not a widening or a narrowing away from a
252/// signed one, because there is no signed width that holds those values, and each gets a rewrite
253/// of its own below.
254pub fn floats(func: &mut Func) {
255    let found: Vec<Inst> =
256        func.blocks().flat_map(|block| func.insts(block).collect::<Vec<_>>()).collect();
257    for inst in found {
258        match func[inst].opcode {
259            Opcode::FConst => constant(func, inst),
260            Opcode::FNeg => negate(func, inst),
261            Opcode::SIToFP | Opcode::UIToFP => widen_then_convert(func, inst),
262            Opcode::FPToSI | Opcode::FPToUI => convert_then_narrow(func, inst),
263            _ => {}
264        }
265    }
266}
267
268/// A float constant, as the integer that spells it and a reading of those bits as the float.
269///
270/// This is the whole of what a `movsd` from a literal would be if there were a section to put the
271/// literal in, and there is not one yet. Two instructions in a register beats a constant pool that
272/// nothing else needs, and it is exactly what the bits of the immediate already say, since the IR
273/// holds a float constant as its bit pattern rather than as a number.
274fn constant(func: &mut Func, inst: Inst) {
275    let ty = produced(func, inst);
276    let Extra::Imm(imm) = func[inst].extra else { return };
277    if !ty.is_float() || !ty.is_scalar() {
278        return;
279    }
280    let int = Type::int(ty.bits());
281    let bits = func[imm].bits();
282    // The cast is the bits as they are stored, and `Imm::int` keeps the width, so a constant whose
283    // top bit is set stays the negative integer that spells it rather than becoming a wider one.
284    let spelled = ahead_const(func, inst, Imm::int(bits as i128, int), int);
285    becomes(func, inst, Opcode::Bitcast, &[spelled]);
286}
287
288/// A negation, as an exclusive or with the sign bit.
289///
290/// C says negation flips the sign and says nothing else about it, which is not what subtracting
291/// from zero does to a zero or to a not a number, so this is the operation the IR already calls
292/// out as not being `0 - x`. Flipping the bit is the whole of it, and it is right for every value
293/// a float can hold, the payload of a not a number included, because no other bit is touched.
294///
295/// The bit is flipped in a general purpose register rather than in the one the float is in. The
296/// other way is one instruction rather than three and it wants the mask in memory aligned to the
297/// register, which is the same section a constant pool would need.
298fn negate(func: &mut Func, inst: Inst) {
299    let ty = produced(func, inst);
300    let Some(&arg) = func[func[inst].args].first() else { return };
301    if !ty.is_float() || !ty.is_scalar() {
302        return;
303    }
304    let int = Type::int(ty.bits());
305    let bits = ahead(func, inst, Opcode::Bitcast, &[arg], int);
306    let mask = ahead_const(func, inst, Imm::int(1i128 << (ty.bits() - 1), int), int);
307    let flipped = ahead(func, inst, Opcode::Xor, &[bits, mask], int);
308    becomes(func, inst, Opcode::Bitcast, &[flipped]);
309}
310
311/// An integer becoming a float, as a widening and the signed conversion at a width there is one at.
312///
313/// The widening is with the sign for a signed integer and with zeroes for an unsigned one, and
314/// after it the value is the same number in a signed integer the machine converts from, so the
315/// conversion is the same value and the same rounding. That is the whole of why the machine needs
316/// no unsigned conversion and none at a width narrower than an `int`.
317fn widen_then_convert(func: &mut Func, inst: Inst) {
318    let signed = func[inst].opcode == Opcode::SIToFP;
319    let Some(&arg) = func[func[inst].args].first() else { return };
320    let from = func[arg].ty;
321    if !from.is_int() || !from.is_scalar() {
322        return;
323    }
324    let Some(width) = holder(from.bits(), signed) else {
325        from_unsigned_word(func, inst, arg, from);
326        return;
327    };
328    if width == from.bits() {
329        return;
330    }
331    let widen = if signed { Opcode::SExt } else { Opcode::ZExt };
332    let wide = ahead(func, inst, widen, &[arg], Type::int(width));
333    becomes(func, inst, Opcode::SIToFP, &[wide]);
334}
335
336/// A float becoming an integer, as the signed conversion at such a width and a narrowing.
337///
338/// The same argument the other way round. A float the program says fits in the integer it asked
339/// for fits in the signed one that holds every value of it, so converting there and keeping the
340/// low bits is that value however it is read, and a float that does not fit is undefined in C and
341/// unspecified in the model at either width.
342fn convert_then_narrow(func: &mut Func, inst: Inst) {
343    let signed = func[inst].opcode == Opcode::FPToSI;
344    let ty = produced(func, inst);
345    let Some(&arg) = func[func[inst].args].first() else { return };
346    if !ty.is_int() || !ty.is_scalar() {
347        return;
348    }
349    let Some(width) = holder(ty.bits(), signed) else {
350        to_unsigned_word(func, inst, arg, ty);
351        return;
352    };
353    if width == ty.bits() {
354        return;
355    }
356    let wide = ahead(func, inst, Opcode::FPToSI, &[arg], Type::int(width));
357    becomes(func, inst, Opcode::Trunc, &[wide]);
358}
359
360/// An unsigned sixty four bit integer becoming a float, without a branch.
361///
362/// This is the one conversion into a float that is not the signed one at some width, because there
363/// is no signed width that holds every value of it. What the machine can do is the signed
364/// conversion, so the value has to be brought under half of its range first and put back after.
365///
366/// Halving it is a shift, and a shift throws away the bit it shifts out, which is the difference
367/// between a number that rounds up and one that rounds down. So the bit is put back as the lowest
368/// bit of the half: a half that was exact stays exact, and one that was not comes out odd, which is
369/// never a value the conversion rounds to and so never a value it rounds the wrong way from. That
370/// is round to odd, and rounding to odd and then to nearest is the same answer as rounding to
371/// nearest once, at every width a float here has. Doubling afterwards is exact, since a float
372/// multiplied by two is the same digits with one more on the exponent and nothing here is near the
373/// top of the range.
374///
375/// A value whose top bit is clear needs none of that and is the signed conversion as it stands, so
376/// there are two answers and the machine has to pick one. gcc writes a branch. This writes the
377/// choice as arithmetic, because a branch here would mean splitting the block this instruction is
378/// in, and every rewrite in this pass stays inside one block. A mask that is every bit or no bit
379/// picks the source, and the same mask over the bits of the result picks between doubling it and
380/// adding a zero to it. That is more instructions than gcc's and no branch to predict wrong.
381fn from_unsigned_word(func: &mut Func, inst: Inst, arg: Value, from: Type) {
382    let ty = produced(func, inst);
383    if !ty.is_float() || !ty.is_scalar() {
384        return;
385    }
386    let spread = spread_top_bit(func, inst, arg, from);
387
388    // The value halved, with the bit the halving lost put back as the lowest bit of it.
389    let one = ahead_const(func, inst, Imm::int(1, from), from);
390    let lost = ahead(func, inst, Opcode::And, &[arg, one], from);
391    let half = ahead(func, inst, Opcode::LShr, &[arg, one], from);
392    let odd = ahead(func, inst, Opcode::Or, &[half, lost], from);
393
394    // The source, as the value with the difference between the two conditionally taken out of it.
395    let differ = ahead(func, inst, Opcode::Xor, &[arg, odd], from);
396    let taken = ahead(func, inst, Opcode::And, &[differ, spread], from);
397    let source = ahead(func, inst, Opcode::Xor, &[arg, taken], from);
398    let converted = ahead(func, inst, Opcode::SIToFP, &[source], ty);
399
400    // The doubling, as the result added to itself or to a zero. The mask is the same one narrowed
401    // to the width of the float, since the top bit it came from is a fact about the integer.
402    let bits = Type::int(ty.bits());
403    let narrow = same_width(func, inst, spread, from, bits);
404    let raw = ahead(func, inst, Opcode::Bitcast, &[converted], bits);
405    let again = ahead(func, inst, Opcode::And, &[raw, narrow], bits);
406    let addend = ahead(func, inst, Opcode::Bitcast, &[again], ty);
407    becomes(func, inst, Opcode::FAdd, &[converted, addend]);
408}
409
410/// A float becoming an unsigned sixty four bit integer, without a branch.
411///
412/// The same argument the other way round, and the same reason there is no branch. A float below
413/// half the range converts as the signed one and is already the answer. One at or above it has half
414/// the range subtracted first, which is exact because the two have the same exponent or a smaller
415/// one, converts into the signed integer that now holds it, and gets the top bit put back on.
416///
417/// The subtraction is of a constant that is either half the range or a positive zero, which is the
418/// same mask trick as above written over the bits of the float, and subtracting a positive zero
419/// leaves every value alone including a negative zero. A float too big for the answer, or a not a
420/// number, is undefined in C and unspecified in the model, so the comparison being false for a not
421/// a number costs nothing: it takes the path whose answer was never promised either way.
422fn to_unsigned_word(func: &mut Func, inst: Inst, arg: Value, ty: Type) {
423    let from = func[arg].ty;
424    if !from.is_float() || !from.is_scalar() {
425        return;
426    }
427    // Half the range, as the float that spells it and the bits that spell the float.
428    let bits = Type::int(from.bits());
429    let pattern = Imm::int(half_the_range(from.bits()), bits);
430    let spelled = ahead_const(func, inst, pattern, bits);
431    let half = ahead(func, inst, Opcode::Bitcast, &[spelled], from);
432
433    let over = ahead_cmp(func, inst, Opcode::FCmp, Extra::FloatPred(FloatPred::Oge), &[arg, half]);
434    let wide = ahead(func, inst, Opcode::ZExt, &[over], bits);
435    let zero = ahead_const(func, inst, Imm::int(0, bits), bits);
436    let spread = ahead(func, inst, Opcode::Sub, &[zero, wide], bits);
437
438    let amount = ahead(func, inst, Opcode::And, &[spread, spelled], bits);
439    let taken = ahead(func, inst, Opcode::Bitcast, &[amount], from);
440    let under = ahead(func, inst, Opcode::FSub, &[arg, taken], from);
441    let low = ahead(func, inst, Opcode::FPToSI, &[under], ty);
442
443    // The top bit back on, from the same comparison at the width of the answer.
444    let again = ahead(func, inst, Opcode::ZExt, &[over], ty);
445    let up = ahead_const(func, inst, Imm::int(i128::from(ty.bits() - 1), ty), ty);
446    let top = ahead(func, inst, Opcode::Shl, &[again, up], ty);
447    becomes(func, inst, Opcode::Xor, &[low, top]);
448}
449
450/// The top bit of an integer spread over every bit of one, which is every bit or no bit.
451///
452/// A comparison against zero rather than a shift, because the answer wanted is a mask and the
453/// machine writes a mask out of a condition the same way either way, and the comparison says what
454/// the question was.
455fn spread_top_bit(func: &mut Func, inst: Inst, arg: Value, ty: Type) -> Value {
456    let zero = ahead_const(func, inst, Imm::int(0, ty), ty);
457    let set = ahead_cmp(func, inst, Opcode::ICmp, Extra::IntPred(IntPred::Slt), &[arg, zero]);
458    let wide = ahead(func, inst, Opcode::ZExt, &[set], ty);
459    ahead(func, inst, Opcode::Sub, &[zero, wide], ty)
460}
461
462/// A value brought to another integer width, and itself when the two are already the same.
463fn same_width(func: &mut Func, inst: Inst, value: Value, from: Type, to: Type) -> Value {
464    match to.bits().cmp(&from.bits()) {
465        Ordering::Equal => value,
466        Ordering::Less => ahead(func, inst, Opcode::Trunc, &[value], to),
467        Ordering::Greater => ahead(func, inst, Opcode::SExt, &[value], to),
468    }
469}
470
471/// The bits of the float of this width that is two to the sixty third.
472///
473/// Half of what an unsigned sixty four bit integer holds, which is the one number both conversions
474/// above are written around. The exponent is biased and the significand is zero in both formats,
475/// so it is the bias plus sixty three shifted up past the significand.
476fn half_the_range(width: u32) -> i128 {
477    match width {
478        32 => 0x5F00_0000,
479        _ => 0x43E0_0000_0000_0000,
480    }
481}
482
483/// Rewrites every byte swap into the shifts and masks that are one, and leaves the rest alone.
484///
485/// A byte swap is a rule on a machine that has the instruction and this everywhere else, and until
486/// `x64.bswap` is a term the model knows about, this is what x86-64 gets too. That is tamnd/rucc#307
487/// and the whole of what is left of it: what is written below is correct at every width and slower
488/// than the one instruction, which is the trade `spec/10-backend.md` section 10.3 says the fast path
489/// makes everywhere.
490///
491/// It is here rather than in the front end because the masks are worked out from the width, and
492/// arithmetic on a value a pattern matched is the one thing the rule language deliberately cannot
493/// do. It is here rather than in the walk to the IR because a byte swap is one instruction in the
494/// IR and should stay one for as long as anything is reading the IR, so that the day the rule
495/// exists nothing above the backend has to change.
496pub fn bytes(func: &mut Func) {
497    let found: Vec<Inst> =
498        func.blocks().flat_map(|block| func.insts(block).collect::<Vec<_>>()).collect();
499    for inst in found {
500        if func[inst].opcode == Opcode::Bswap {
501            swap(func, inst);
502        }
503    }
504}
505
506/// One byte swap, as a halving run of swaps of adjacent groups of bits.
507///
508/// Reversing eight bytes is swapping the two halves, then the two halves of each half, then the two
509/// bytes of each of those, and the three steps commute because each is a permutation of positions
510/// the others do not touch. So the run goes from the widest group down to a byte, and every step is
511/// the same five instructions: keep the even numbered groups, move them up, move the odd numbered
512/// ones down, keep those, and put the two together.
513///
514/// Nine instructions for two bytes, seventeen for four, twenty five for eight, before the constants.
515/// Writing it as a shift and a mask per byte instead is fewer steps to read and more instructions at
516/// every width above two, since the cost there grows with the number of bytes rather than with the
517/// logarithm of it.
518///
519/// A width that is not a whole number of bytes is left alone. The verifier does not allow one, and
520/// silently reversing something else would be worse than the instruction surviving to a selector
521/// that has no rule for it and says so.
522fn swap(func: &mut Func, inst: Inst) {
523    let ty = produced(func, inst);
524    let Some(&arg) = func[func[inst].args].first() else { return };
525    if !ty.is_int() || !ty.is_scalar() || ty.bits() < 16 || ty.bits() % 8 != 0 {
526        return;
527    }
528
529    let mut value = arg;
530    let mut group = ty.bits() / 2;
531    while group >= 8 {
532        // The pattern that keeps every other run of `group` bits, counting the run at the bottom as
533        // the first one kept. It is what says which half of each pair moves up and which moves down.
534        let mask = alternating(ty.bits(), group);
535        let keep = ahead_const(func, inst, Imm::int(mask, ty), ty);
536        let count = ahead_const(func, inst, Imm::int(i128::from(group), ty), ty);
537        let low = ahead(func, inst, Opcode::And, &[value, keep], ty);
538        let up = ahead(func, inst, Opcode::Shl, &[low, count], ty);
539        let down = ahead(func, inst, Opcode::LShr, &[value, count], ty);
540        let high = ahead(func, inst, Opcode::And, &[down, keep], ty);
541        // The last step of the last round is the instruction itself, so the value everything
542        // downstream already reads is the answer and nothing has to be substituted.
543        if group == 8 {
544            becomes(func, inst, Opcode::Or, &[up, high]);
545            return;
546        }
547        value = ahead(func, inst, Opcode::Or, &[up, high], ty);
548        group /= 2;
549    }
550}
551
552/// The mask that keeps every other run of `group` bits out of `width` of them, starting with the
553/// run at the bottom.
554///
555/// Sixteen bits in groups of eight is `0x00ff`, thirty two in groups of eight is `0x00ff00ff`, and
556/// thirty two in groups of sixteen is `0x0000ffff`. Built rather than written down because there is
557/// one of these per width per group and a table of them is a table to get wrong.
558///
559/// The top group is always one of the dropped ones, since the run at the bottom is kept and the
560/// width is an even number of groups, so the answer never has its sign bit set and reads the same
561/// as a number as it does as a pattern.
562fn alternating(width: u32, group: u32) -> i128 {
563    every(width, group * 2, group)
564}
565
566/// The pattern with the low `run` bits of every `step` bit group set, out of `width` of them.
567///
568/// `every(32, 2, 1)` is `0x55555555` and `every(64, 8, 1)` is `0x0101010101010101`. Built rather
569/// than written down for the reason the byte swap masks are: there is one of these per width per
570/// group and a table of them is a table to get wrong.
571///
572/// The top group is never a full one when `run` is less than `step`, so the answer never has its
573/// sign bit set and reads the same as a number as it does as a pattern.
574fn every(width: u32, step: u32, run: u32) -> i128 {
575    let ones = (1i128 << run) - 1;
576    let mut mask = 0i128;
577    let mut at = 0;
578    while at < width {
579        mask |= ones << at;
580        at += step;
581    }
582    mask
583}
584
585/// Rewrites every bit count into the arithmetic that is one, and leaves the rest alone.
586///
587/// Three instructions and no rules, which is tamnd/rucc#310. `popcnt` is one instruction on a
588/// machine that has it and `bsr` and `bsf` are the two searches, and none of the three is a term the
589/// model knows about yet, so what runs today is what runs everywhere. The trade is the one
590/// `spec/10-backend.md` section 10.3 describes and `expand::bytes` above makes for the same reason:
591/// slower than the instruction, right on every target, and built only out of rules the verifier has
592/// already discharged.
593///
594/// The two searches are rewritten first, into a set bit count and a little arithmetic, and then
595/// every set bit count is rewritten. That is one pass rather than two because the second sweep picks
596/// up what the first one wrote, and it means there is one place that knows how to count bits rather
597/// than three.
598pub fn counts(func: &mut Func) {
599    let found: Vec<Inst> =
600        func.blocks().flat_map(|block| func.insts(block).collect::<Vec<_>>()).collect();
601    for inst in found {
602        match func[inst].opcode {
603            Opcode::Ctlz => searched(func, inst, true),
604            Opcode::Cttz => searched(func, inst, false),
605            _ => {}
606        }
607    }
608    let found: Vec<Inst> =
609        func.blocks().flat_map(|block| func.insts(block).collect::<Vec<_>>()).collect();
610    for inst in found {
611        if func[inst].opcode == Opcode::Ctpop {
612            counted(func, inst);
613        }
614    }
615}
616
617/// A leading or trailing zero count, as the set bit count of a value with those zeroes turned into
618/// the only bits that are set.
619///
620/// For trailing zeroes that is `~x & (x - 1)`, which is exactly the run of zeroes below the lowest
621/// set bit and nothing else, because `x - 1` sets that run and clears the bit above it while `~x`
622/// keeps only positions `x` did not have.
623///
624/// For leading zeroes it is the same idea upside down. Smearing every set bit downwards, by folding
625/// the value into itself shifted right by one, two, four and so on, leaves ones everywhere at or
626/// below the highest set bit, so the complement is exactly the leading zeroes. That is five extra
627/// steps at thirty two bits and six at sixty four, which is why the search instruction is worth
628/// having and why #310 stays open for it.
629///
630/// Both answer the width for a zero argument, which is what they have to answer for `ffs` to be
631/// masked correctly and is more than C asks for: `__builtin_clz(0)` and `__builtin_ctz(0)` are
632/// undefined, so nothing may rely on this, and the point of writing it down is that it is defined
633/// here rather than being whatever a register happened to hold.
634fn searched(func: &mut Func, inst: Inst, leading: bool) {
635    let ty = produced(func, inst);
636    let Some(&arg) = func[func[inst].args].first() else { return };
637    if !countable(ty) {
638        return;
639    }
640    let ones = ahead_const(func, inst, Imm::int(-1, ty), ty);
641    if leading {
642        let mut value = arg;
643        let mut by = 1;
644        while by < ty.bits() {
645            let count = ahead_const(func, inst, Imm::int(i128::from(by), ty), ty);
646            let down = ahead(func, inst, Opcode::LShr, &[value, count], ty);
647            value = ahead(func, inst, Opcode::Or, &[value, down], ty);
648            by *= 2;
649        }
650        let above = ahead(func, inst, Opcode::Xor, &[value, ones], ty);
651        becomes(func, inst, Opcode::Ctpop, &[above]);
652        return;
653    }
654    let missing = ahead(func, inst, Opcode::Xor, &[arg, ones], ty);
655    let less = ahead(func, inst, Opcode::Add, &[arg, ones], ty);
656    let below = ahead(func, inst, Opcode::And, &[missing, less], ty);
657    becomes(func, inst, Opcode::Ctpop, &[below]);
658}
659
660/// One set bit count, as the halving sum every bit counting routine is written as.
661///
662/// Adjacent bits are added into pairs, pairs into nibbles, nibbles into bytes, and then the bytes
663/// are added together at once by a multiply whose top byte is their sum. The first step is written
664/// as a subtraction rather than as two masks and an add, which is the usual form and is one
665/// instruction shorter: a two bit field minus its own high bit is the number of bits set in it.
666///
667/// Twelve instructions and four constants at sixty four bits, against one `popcnt`, which is the
668/// size of what #310 is worth.
669///
670/// The multiply is the last step only because the byte sums are each at most eight and there are at
671/// most eight of them, so the running total in the top byte cannot carry out of it. At eight bits
672/// there are no bytes to add and the third step is already the answer.
673fn counted(func: &mut Func, inst: Inst) {
674    let ty = produced(func, inst);
675    let Some(&arg) = func[func[inst].args].first() else { return };
676    if !countable(ty) {
677        return;
678    }
679    let width = ty.bits();
680    let pairs = ahead_const(func, inst, Imm::int(alternating(width, 1), ty), ty);
681    let two = ahead_const(func, inst, Imm::int(2, ty), ty);
682    let one = ahead_const(func, inst, Imm::int(1, ty), ty);
683    let high = ahead(func, inst, Opcode::LShr, &[arg, one], ty);
684    let odd = ahead(func, inst, Opcode::And, &[high, pairs], ty);
685    let bits = ahead(func, inst, Opcode::Sub, &[arg, odd], ty);
686
687    let quads = ahead_const(func, inst, Imm::int(alternating(width, 2), ty), ty);
688    let low = ahead(func, inst, Opcode::And, &[bits, quads], ty);
689    let up = ahead(func, inst, Opcode::LShr, &[bits, two], ty);
690    let rest = ahead(func, inst, Opcode::And, &[up, quads], ty);
691    let nibbles = ahead(func, inst, Opcode::Add, &[low, rest], ty);
692
693    let four = ahead_const(func, inst, Imm::int(4, ty), ty);
694    let bytes = ahead_const(func, inst, Imm::int(alternating(width, 4), ty), ty);
695    let folded = ahead(func, inst, Opcode::LShr, &[nibbles, four], ty);
696    let summed = ahead(func, inst, Opcode::Add, &[nibbles, folded], ty);
697    if width == 8 {
698        becomes(func, inst, Opcode::And, &[summed, bytes]);
699        return;
700    }
701    let held = ahead(func, inst, Opcode::And, &[summed, bytes], ty);
702
703    let spread = ahead_const(func, inst, Imm::int(every(width, 8, 1), ty), ty);
704    let top = ahead_const(func, inst, Imm::int(i128::from(width - 8), ty), ty);
705    let total = ahead(func, inst, Opcode::Mul, &[held, spread], ty);
706    becomes(func, inst, Opcode::LShr, &[total, top]);
707}
708
709/// Rewrites every overflow checked instruction into the arithmetic and the test that is one.
710///
711/// Six instructions and no rules, which is tamnd/rucc#309. The trade is the one `expand::bytes` and
712/// `expand::counts` above make, with one thing on top of it: these are the only instructions in the
713/// IR whose result is two things, a value and a bit, and the rule language has no way to write a
714/// term that produces two. So even on a machine whose add sets a carry flag, a rule for one of
715/// these could not name both halves of what it answers, and the rewrite would have to happen
716/// somewhere. Here is that somewhere.
717///
718/// Because the instruction goes away rather than becoming another one, the values the rest of the
719/// function read have to be pointed at what replaced them. That is what `substitute` below does,
720/// once, after every instruction has been rewritten.
721pub fn overflows(func: &mut Func) {
722    let found: Vec<Inst> =
723        func.blocks().flat_map(|block| func.insts(block).collect::<Vec<_>>()).collect();
724    let mut forward = HashMap::new();
725    for inst in found {
726        let checked = match func[inst].opcode {
727            Opcode::UAddOverflow => Checked::Add(false),
728            Opcode::SAddOverflow => Checked::Add(true),
729            Opcode::USubOverflow => Checked::Sub(false),
730            Opcode::SSubOverflow => Checked::Sub(true),
731            Opcode::UMulOverflow => Checked::Mul(false),
732            Opcode::SMulOverflow => Checked::Mul(true),
733            _ => continue,
734        };
735        overflowed(func, inst, checked, &mut forward);
736    }
737    if !forward.is_empty() {
738        substitute(func, &forward);
739    }
740}
741
742/// Which of the six an instruction is, as the arithmetic and whether the operands are signed.
743#[derive(Debug, Clone, Copy)]
744enum Checked {
745    /// An add, whose answer wraps when the exact sum needed one more bit at the top.
746    Add(bool),
747    /// A subtract.
748    Sub(bool),
749    /// A multiply, which is the expensive one because the test needs the high half of the product.
750    Mul(bool),
751}
752
753/// One overflow checked instruction, as the ordinary arithmetic and a test on the operands.
754///
755/// The value is always the ordinary instruction, because that is what the wrapped answer is. What
756/// differs between the six is how the bit is worked out.
757///
758/// The two adds and the two subtracts are one comparison each. An unsigned sum wraps exactly when
759/// it came out below either operand, and an unsigned difference wraps exactly when the left operand
760/// was below the right. A signed sum wraps exactly when both operands had the same sign and the
761/// answer had the other one, which `(a ^ v) & (b ^ v)` has the sign bit of, and a signed difference
762/// wraps exactly when the operands had different signs and the answer took the right one's, which
763/// `(a ^ b) & (a ^ v)` has the sign bit of.
764///
765/// The multiplies are the high half of the product against what the low half implies it should be.
766/// For an unsigned multiply the product fits exactly when the high half is zero, and for a signed
767/// one it fits exactly when the high half is the sign extension of the low half, which is the low
768/// half shifted right arithmetically by every bit but one.
769fn overflowed(func: &mut Func, inst: Inst, checked: Checked, forward: &mut HashMap<Value, Value>) {
770    let ty = produced(func, inst);
771    let [a, b] = func[func[inst].args] else { return };
772    if !countable(ty) {
773        return;
774    }
775    let (value, bit) = match checked {
776        Checked::Add(signed) => {
777            let value = ahead(func, inst, Opcode::Add, &[a, b], ty);
778            let bit = if signed {
779                let left = ahead(func, inst, Opcode::Xor, &[a, value], ty);
780                let right = ahead(func, inst, Opcode::Xor, &[b, value], ty);
781                let both = ahead(func, inst, Opcode::And, &[left, right], ty);
782                negative(func, inst, both, ty)
783            } else {
784                compared(func, inst, IntPred::Ult, value, a)
785            };
786            (value, bit)
787        }
788        Checked::Sub(signed) => {
789            let value = ahead(func, inst, Opcode::Sub, &[a, b], ty);
790            let bit = if signed {
791                let apart = ahead(func, inst, Opcode::Xor, &[a, b], ty);
792                let moved = ahead(func, inst, Opcode::Xor, &[a, value], ty);
793                let both = ahead(func, inst, Opcode::And, &[apart, moved], ty);
794                negative(func, inst, both, ty)
795            } else {
796                compared(func, inst, IntPred::Ult, a, b)
797            };
798            (value, bit)
799        }
800        Checked::Mul(signed) => {
801            let value = ahead(func, inst, Opcode::Mul, &[a, b], ty);
802            let high = high_half(func, inst, a, b, signed, ty);
803            let bit = if signed {
804                let sign = ahead_const(func, inst, Imm::int(i128::from(ty.bits() - 1), ty), ty);
805                let wanted = ahead(func, inst, Opcode::AShr, &[value, sign], ty);
806                compared(func, inst, IntPred::Ne, high, wanted)
807            } else {
808                let zero = ahead_const(func, inst, Imm::int(0, ty), ty);
809                compared(func, inst, IntPred::Ne, high, zero)
810            };
811            (value, bit)
812        }
813    };
814    let mut answers = func[inst].results();
815    if let (Some(wrapped), Some(flag)) = (answers.next(), answers.next()) {
816        forward.insert(wrapped, value);
817        forward.insert(flag, bit);
818    }
819    func.remove_inst(inst);
820}
821
822/// The high half of the product of two values, at the width they are.
823///
824/// Both operands are split into halves of half the width and multiplied four ways, which is long
825/// multiplication in base two to the half width. The three partial products that reach the top are
826/// added with the carry out of the bottom ones, and every step of that fits in the width because
827/// the total is the high half of the product and that is what a high half is.
828///
829/// The whole of it is unsigned, and a signed high half is the unsigned one with a correction: a
830/// negative operand contributed the width's worth of sign bits to the unsigned product that it
831/// should not have, so the other operand is subtracted off once for each negative operand. Spreading
832/// the sign bit of each with an arithmetic shift is what turns that into a mask rather than a
833/// branch.
834///
835/// This is the expensive one. Six multiplies and a dozen other instructions at sixty four bits,
836/// against one `mul` on a machine whose multiply writes the high half into a second register. That
837/// is most of what #309 is worth and it is what makes the multiply the one to give a rule to first.
838fn high_half(func: &mut Func, inst: Inst, a: Value, b: Value, signed: bool, ty: Type) -> Value {
839    let width = ty.bits();
840    let half = width / 2;
841    let shift = ahead_const(func, inst, Imm::int(i128::from(half), ty), ty);
842    let mask = ahead_const(func, inst, Imm::int((1i128 << half) - 1, ty), ty);
843
844    let al = ahead(func, inst, Opcode::And, &[a, mask], ty);
845    let ah = ahead(func, inst, Opcode::LShr, &[a, shift], ty);
846    let bl = ahead(func, inst, Opcode::And, &[b, mask], ty);
847    let bh = ahead(func, inst, Opcode::LShr, &[b, shift], ty);
848
849    let ll = ahead(func, inst, Opcode::Mul, &[al, bl], ty);
850    let lh = ahead(func, inst, Opcode::Mul, &[al, bh], ty);
851    let hl = ahead(func, inst, Opcode::Mul, &[ah, bl], ty);
852    let hh = ahead(func, inst, Opcode::Mul, &[ah, bh], ty);
853
854    // The carry out of the low half, which is the top of the smallest partial product plus the
855    // bottoms of the two middle ones.
856    let over = ahead(func, inst, Opcode::LShr, &[ll, shift], ty);
857    let lh_low = ahead(func, inst, Opcode::And, &[lh, mask], ty);
858    let hl_low = ahead(func, inst, Opcode::And, &[hl, mask], ty);
859    let some = ahead(func, inst, Opcode::Add, &[over, lh_low], ty);
860    let carry = ahead(func, inst, Opcode::Add, &[some, hl_low], ty);
861
862    let lh_high = ahead(func, inst, Opcode::LShr, &[lh, shift], ty);
863    let hl_high = ahead(func, inst, Opcode::LShr, &[hl, shift], ty);
864    let up = ahead(func, inst, Opcode::LShr, &[carry, shift], ty);
865    let first = ahead(func, inst, Opcode::Add, &[hh, lh_high], ty);
866    let second = ahead(func, inst, Opcode::Add, &[first, hl_high], ty);
867    let high = ahead(func, inst, Opcode::Add, &[second, up], ty);
868    if !signed {
869        return high;
870    }
871    let top = ahead_const(func, inst, Imm::int(i128::from(width - 1), ty), ty);
872    let a_sign = ahead(func, inst, Opcode::AShr, &[a, top], ty);
873    let b_sign = ahead(func, inst, Opcode::AShr, &[b, top], ty);
874    let a_owes = ahead(func, inst, Opcode::And, &[a_sign, b], ty);
875    let b_owes = ahead(func, inst, Opcode::And, &[b_sign, a], ty);
876    let once = ahead(func, inst, Opcode::Sub, &[high, a_owes], ty);
877    ahead(func, inst, Opcode::Sub, &[once, b_owes], ty)
878}
879
880/// Whether a value's sign bit is set, as a comparison against zero.
881fn negative(func: &mut Func, inst: Inst, value: Value, ty: Type) -> Value {
882    let zero = ahead_const(func, inst, Imm::int(0, ty), ty);
883    compared(func, inst, IntPred::Slt, value, zero)
884}
885
886/// A comparison written in front of an instruction, which [`ahead`] cannot write because a
887/// comparison carries its predicate where everything else carries nothing.
888fn compared(func: &mut Func, inst: Inst, pred: IntPred, lhs: Value, rhs: Value) -> Value {
889    let ty = func[lhs].ty.with_lane(Type::I1);
890    let args = func.push_values(&[lhs, rhs]);
891    let extra = Extra::IntPred(pred);
892    written(func, inst, InstData { args, extra, ..InstData::new(Opcode::ICmp) }, ty)
893}
894
895/// Points every reader of a removed instruction's results at what replaced them.
896///
897/// The arguments of each instruction and the arguments of the blocks it branches to, which between
898/// them are everything an instruction can read. Nothing chases here, the way the same walk in
899/// `rucc_opt::simplify` does, because every value this map answers with is one written above and so
900/// is never itself a key.
901fn substitute(func: &mut Func, forward: &HashMap<Value, Value>) {
902    let with = |value: Value| forward.get(&value).copied().unwrap_or(value);
903    for block in func.blocks().collect::<Vec<_>>() {
904        for inst in func.insts(block).collect::<Vec<Inst>>() {
905            let args = func[inst].args;
906            func.rewrite(args, with);
907            for call in func.successors(inst).collect::<Vec<_>>() {
908                func.rewrite(call.args, with);
909            }
910        }
911    }
912}
913
914/// Whether the arithmetic in this file works correctly at this type.
915///
916/// A whole number of bytes and a power of two of them, which every width the front end can ask about
917/// is. Anything else is left as the instruction it was, so a selector with no rule for it says so
918/// rather than the program getting a number that was counted, or checked, in the wrong shape.
919///
920/// The bit counts need it because a halving sum halves, and the overflow checks need it because
921/// splitting a value into two halves of equal width needs the width to be even and the halves to be
922/// what a shift by half of it separates.
923fn countable(ty: Type) -> bool {
924    ty.is_int()
925        && ty.is_scalar()
926        && ty.bits() >= 8
927        && ty.bits() <= 64
928        && ty.bits().is_power_of_two()
929}
930
931/// The most moves a copy or a fill becomes before it is left alone for a call instead.
932///
933/// Thirty two, which is two hundred and fifty six bytes at a word a time and is a structure larger
934/// than almost every one a program writes. What the number is trading is code size against a call,
935/// and the exchange rate is a machine's rather than a language's, so the number lives here next to
936/// the code it bounds and not in a target description that would have to be right about it for
937/// every target at once.
938///
939/// It is a count of moves and not a count of bytes because that is what the cost is. A copy of
940/// sixty four bytes between two addresses aligned to eight is eight moves and a copy of the same
941/// sixty four bytes between two addresses aligned to one is sixty four, and the second is the
942/// expensive one whatever the size says.
943pub const UNROLL: usize = 32;
944
945/// Rewrites every bulk copy and bulk fill, into moves when that is worth it and into a call to the
946/// runtime when it is not.
947///
948/// A copy of more than [`UNROLL`] moves becomes a call, and so does a fill whose byte is not a
949/// constant, which the front end does not write today and which would need the byte spread across
950/// a word at runtime. A `memmove` is always a call, because the two sides may overlap and a run of
951/// moves in one direction is only right for one of the two ways they can.
952///
953/// `word` is how many bytes the widest move on this machine carries. Nothing here reads a target
954/// otherwise, and a copy is the same run of loads and stores everywhere.
955pub fn bulk(func: &mut Func, names: &mut Interner, word: u32) {
956    let found: Vec<Inst> =
957        func.blocks().flat_map(|block| func.insts(block).collect::<Vec<_>>()).collect();
958    for inst in found {
959        match func[inst].opcode {
960            Opcode::Memcpy => copy(func, names, inst, word),
961            Opcode::Memset => fill(func, names, inst, word),
962            Opcode::Memmove => library(func, names, inst, "memmove", word),
963            _ => {}
964        }
965    }
966}
967
968/// One `memcpy`, as a load and a store for each word of it.
969///
970/// Each word is read and then written before the next is read, rather than every read being built
971/// before any write the way [`crate::varargs`] copies a list. A `memcpy` is the copy whose two
972/// sides the front end promises do not overlap, so what is at the source when the last word is read
973/// is what was there when the first was, and reading a word at a time costs one register where
974/// reading all of them first would cost as many registers as the copy has words.
975fn copy(func: &mut Func, names: &mut Interner, inst: Inst, word: u32) {
976    let [into, from] = func[func[inst].args] else { return };
977    let Extra::Mem(mem) = func[inst].extra else { return };
978    let info = func[mem];
979    let Some(plan) = chunks(info, word) else { return library(func, names, inst, "memcpy", word) };
980    for (at, width) in plan {
981        let ty = Type::int(width * 8);
982        let access = MemInfo { size: u64::from(width), align: width.min(info.align), ..info };
983        let there = stepped(func, inst, from, at);
984        let word = read(func, inst, there, access, ty);
985        let here = stepped(func, inst, into, at);
986        write(func, inst, word, here, access);
987    }
988    func.remove_inst(inst);
989}
990
991/// One `memset`, as a store of the byte spread across each word of it.
992///
993/// The byte is a constant, so the word it spreads into is a constant too and the spreading is done
994/// here rather than by the program. The front end writes a `memset` for the part of an object an
995/// initialiser did not name, where the byte is always zero, and the general case is written anyway
996/// because the arithmetic is the same and being right about `0xff` costs nothing.
997fn fill(func: &mut Func, names: &mut Interner, inst: Inst, word: u32) {
998    let [into, byte] = func[func[inst].args] else { return };
999    let Extra::Mem(mem) = func[inst].extra else { return };
1000    let info = func[mem];
1001    let Some(spelled) = literal(func, byte) else {
1002        return library(func, names, inst, "memset", word);
1003    };
1004    let Some(plan) = chunks(info, word) else { return library(func, names, inst, "memset", word) };
1005    for (at, width) in plan {
1006        let ty = Type::int(width * 8);
1007        let access = MemInfo { size: u64::from(width), align: width.min(info.align), ..info };
1008        let value = ahead_const(func, inst, Imm::int(spread(spelled, width) as i128, ty), ty);
1009        let here = stepped(func, inst, into, at);
1010        write(func, inst, value, here, access);
1011    }
1012    func.remove_inst(inst);
1013}
1014
1015/// One bulk operation as a call to the routine of that name in the runtime.
1016///
1017/// This is what a copy too large to unroll becomes, and what a `memmove` and a fill with a
1018/// computed byte become whatever their size. The routine is `rucc-builtins`' on a freestanding
1019/// target and the C library's on a hosted one, and the call is the same either way because the two
1020/// have the same names and the same signatures on purpose.
1021///
1022/// The arguments are the C ones and not the IR ones. The IR holds the size beside the instruction
1023/// where C passes it, and holds a fill byte as a byte where C passes an `int`, so the size becomes
1024/// a constant in a register and the byte is widened. The value each returns is its first argument,
1025/// which nothing reads, so the call is built as returning nothing rather than as returning a
1026/// pointer nobody looks at.
1027fn library(func: &mut Func, names: &mut Interner, inst: Inst, routine: &str, word: u32) {
1028    let [into, second] = func[func[inst].args] else { return };
1029    let Extra::Mem(mem) = func[inst].extra else { return };
1030    let size = func[mem].size;
1031
1032    // `size_t`, which is as wide as a general purpose register on every target here. Taken from
1033    // the machine rather than written as sixty four so that a thirty two bit target gets the
1034    // argument its own C library declares.
1035    let words = Type::int(word * 8);
1036    let count = ahead_const(func, inst, Imm::int(i128::from(size), words), words);
1037    // A fill passes an `int` where the IR passes the byte itself, and the widening is a zero
1038    // extension because the routine looks at the low eight bits and nothing else.
1039    let second = match routine {
1040        "memset" => widened(func, inst, second),
1041        _ => second,
1042    };
1043
1044    let sig = func.add_signature(Signature::new().with_params(&[
1045        Type::PTR,
1046        if routine == "memset" { Type::int(32) } else { Type::PTR },
1047        words,
1048    ]));
1049    let callee = names.intern(routine);
1050    let varargs = func.push_abis(&[]);
1051    let info = func.add_call(CallInfo { callee: Some(callee), signature: sig, varargs });
1052    let args = func.push_values(&[into, second, count]);
1053    let data = &mut func[inst];
1054    data.opcode = Opcode::Call;
1055    data.args = args;
1056    data.extra = Extra::Call(info);
1057    data.flags = data.flags.intersection(Flags::legal_on(Opcode::Call));
1058}
1059
1060/// A value widened to an `int`, or the value itself when it is one already.
1061fn widened(func: &mut Func, inst: Inst, value: Value) -> Value {
1062    let int = Type::int(32);
1063    let ty = func[value].ty;
1064    if ty == int {
1065        return value;
1066    }
1067    ahead(func, inst, Opcode::ZExt, &[value], int)
1068}
1069
1070/// Where each word of a block of memory starts and how wide it is, or nothing for a block that is
1071/// more words than [`UNROLL`].
1072///
1073/// The widest word is the smaller of what the machine moves at once and what the block is known to
1074/// be aligned to, because a load wider than the alignment is a fault on a machine that checks and
1075/// this pass does not know whether the one it is compiling for does. That costs a copy of a
1076/// character array a move per byte, which is exactly the copy the threshold sends to a call.
1077///
1078/// The width halves whenever what is left is narrower than it, so a block of thirteen bytes aligned
1079/// to eight is eight, four and one rather than thirteen ones. Every offset is a multiple of the
1080/// width at it, since each width divides the sum of the wider ones in front of it, which is what
1081/// lets the alignment of each access be written down as the width.
1082fn chunks(info: MemInfo, word: u32) -> Option<Vec<(u64, u32)>> {
1083    plan(info.size, info.align, word)
1084}
1085
1086/// The same, as the two numbers rather than as an access, for the one caller that has no access to
1087/// ask about.
1088///
1089/// [`crate::abi`] copies a structure passed by value into the argument area, and that copy is not a
1090/// `memcpy` in the IR: it is written straight into the machine IR, because where it goes is an
1091/// offset the placement walk gives and nothing before this pass knows it. The plan has to be the
1092/// same plan either way, so it is one function.
1093pub(crate) fn plan(size: u64, align: u32, word: u32) -> Option<Vec<(u64, u32)>> {
1094    let widest = word.min(align).max(1);
1095    if !widest.is_power_of_two() {
1096        return None;
1097    }
1098    let mut plan = Vec::new();
1099    let mut at = 0;
1100    let mut width = u64::from(widest);
1101    while at < size {
1102        while width > size - at {
1103            width /= 2;
1104        }
1105        plan.push((at, u32::try_from(width).ok()?));
1106        at += width;
1107        if plan.len() > UNROLL {
1108            return None;
1109        }
1110    }
1111    Some(plan)
1112}
1113
1114/// The byte a fill writes, when the program said which one rather than working it out.
1115fn literal(func: &Func, value: Value) -> Option<u8> {
1116    let Def::Result { inst, .. } = func[value].def else { return None };
1117    if func[inst].opcode != Opcode::IConst {
1118        return None;
1119    }
1120    let Extra::Imm(imm) = func[inst].extra else { return None };
1121    u8::try_from(func[imm].bits() & 0xff).ok()
1122}
1123
1124/// One byte repeated across a word of that many bytes, which is what a fill stores.
1125fn spread(byte: u8, width: u32) -> u64 {
1126    (0..width).fold(0, |word, at| word | u64::from(byte) << (at * 8))
1127}
1128
1129/// The address that far into a block, written in front of an instruction, or the block itself for
1130/// the word at the front of it.
1131fn stepped(func: &mut Func, inst: Inst, block: Value, at: u64) -> Value {
1132    if at == 0 {
1133        return block;
1134    }
1135    let step = ahead_const(func, inst, Imm::int(i128::from(at), Type::int(64)), Type::int(64));
1136    ahead(func, inst, Opcode::PtrAdd, &[block, step], Type::PTR)
1137}
1138
1139/// A load put in front of an instruction, and the value it reads.
1140fn read(func: &mut Func, inst: Inst, from: Value, info: MemInfo, ty: Type) -> Value {
1141    let extra = Extra::Mem(func.add_mem(info));
1142    let args = func.push_values(&[from]);
1143    written(func, inst, InstData { args, extra, ..InstData::new(Opcode::Load) }, ty)
1144}
1145
1146/// A store put in front of an instruction, which produces nothing and is only its effect.
1147fn write(func: &mut Func, inst: Inst, value: Value, into: Value, info: MemInfo) {
1148    let span = func.span(inst);
1149    let extra = Extra::Mem(func.add_mem(info));
1150    let args = func.push_values(&[value, into]);
1151    let data = InstData { args, extra, ..InstData::new(Opcode::Store) };
1152    let made = func.create_inst(data, &[], span);
1153    func.insert_before(made, inst);
1154}
1155
1156/// The width the machine converts at that holds every value of an integer of this one.
1157///
1158/// The machine converts between a float and a signed integer at thirty two bits and at sixty four
1159/// and at no other width, so a conversion anywhere else is one of those two with a widening in
1160/// front of it or a narrowing behind it. Which of the two it is, is the narrower one the values
1161/// fit in, and an unsigned integer of `bits` bits needs one more bit than that to be signed in.
1162///
1163/// `None` is a width no signed integer here holds, which is only an unsigned sixty four bit one.
1164fn holder(bits: u32, signed: bool) -> Option<u32> {
1165    match if signed { bits } else { bits + 1 } {
1166        ..=32 => Some(32),
1167        33..=64 => Some(64),
1168        _ => None,
1169    }
1170}
1171
1172/// The type of the one value an instruction produces.
1173///
1174/// Every opcode this pass touches produces exactly one, so an instruction that produces none is
1175/// one the caller has already gone wrong about and the void type says so without panicking.
1176fn produced(func: &Func, inst: Inst) -> Type {
1177    func[inst].first_result.map_or(Type::VOID, |value| func[value].ty)
1178}
1179
1180/// Puts an instruction over these operands in front of another one, and gives back its value.
1181fn ahead(func: &mut Func, inst: Inst, opcode: Opcode, args: &[Value], ty: Type) -> Value {
1182    let args = func.push_values(args);
1183    written(func, inst, InstData { args, ..InstData::new(opcode) }, ty)
1184}
1185
1186/// The same for a comparison, which carries the predicate and produces one bit.
1187fn ahead_cmp(func: &mut Func, inst: Inst, opcode: Opcode, extra: Extra, args: &[Value]) -> Value {
1188    let args = func.push_values(args);
1189    written(func, inst, InstData { args, extra, ..InstData::new(opcode) }, Type::I1)
1190}
1191
1192/// The same for a constant, which carries an immediate rather than operands.
1193fn ahead_const(func: &mut Func, inst: Inst, imm: Imm, ty: Type) -> Value {
1194    let extra = Extra::Imm(func.add_imm(imm));
1195    written(func, inst, InstData { extra, ..InstData::new(Opcode::IConst) }, ty)
1196}
1197
1198/// Creates the instruction, puts it where those two asked, and reads its value back out.
1199fn written(func: &mut Func, inst: Inst, data: InstData, ty: Type) -> Value {
1200    let span = func.span(inst);
1201    let made = func.create_inst(data, &[ty], span);
1202    func.insert_before(made, inst);
1203    func[made].first_result.expect("an instruction created with one result has one")
1204}
1205
1206/// Turns an instruction into a different one over different operands, in place.
1207///
1208/// The last instruction of a rewrite is the original rather than a new one, so the value the rest
1209/// of the function reads is the value it already read and nothing has to be substituted anywhere.
1210/// The type of that value does not change either, because every rewrite here ends at the type it
1211/// started at.
1212fn becomes(func: &mut Func, inst: Inst, opcode: Opcode, args: &[Value]) {
1213    let args = func.push_values(args);
1214    let data = &mut func[inst];
1215    data.opcode = opcode;
1216    data.args = args;
1217    data.extra = Extra::None;
1218    // What the program said about rounding and about not a numbers is still true of the
1219    // instructions it became, and what is no longer meaningful is dropped rather than carried.
1220    data.flags = data.flags.intersection(Flags::legal_on(opcode));
1221}
1222
1223/// The blocks a chain of `n` cases needs beyond the ones the program already had.
1224///
1225/// Here so that a test can say the number rather than count it, and so that whoever writes the
1226/// jump table has one place to compare against.
1227#[must_use]
1228pub fn blocks_for(cases: usize) -> usize {
1229    cases.saturating_sub(1)
1230}
1231
1232#[cfg(test)]
1233mod tests {
1234    use rucc_base::Interner;
1235    use rucc_ir::{Builder, Flags, Float, Func, Module, Opcode, Signature, Type};
1236    use rucc_target::{Arch, Env, Os, TargetInfo, Triple};
1237
1238    use rucc_ir::{Extra, InstData, MemInfo, MemOrder, Restrict};
1239
1240    use super::{
1241        UNROLL, alternating, blocks_for, bulk, bytes, chunks, counts, every, floats, orderings,
1242        overflows, spread, switches,
1243    };
1244
1245    fn target() -> TargetInfo {
1246        TargetInfo::new(Triple::new(Arch::X86_64, Os::Linux, Env::Gnu))
1247    }
1248
1249    /// `int sw(int x) { switch (x) { case 1: return 10; case 2: return 20; default: return 30; } }`
1250    /// as the walk builds it, which is the program in issue 275.
1251    fn built(cases: &[i128]) -> (Interner, Func) {
1252        let mut names = Interner::new();
1253        let int = Type::int(32);
1254        let mut func = Func::new(
1255            names.intern("sw"),
1256            Signature::new().with_params(&[int]).with_returns(&[int]),
1257        );
1258        let entry = func.create_block();
1259        let x = func.append_param(entry, int);
1260
1261        let default = func.create_block();
1262        let arms: Vec<_> = cases.iter().map(|_| func.create_block()).collect();
1263        let table: Vec<(i128, rucc_ir::Block)> =
1264            cases.iter().copied().zip(arms.iter().copied()).collect();
1265        Builder::new(&mut func, entry).switch(x, default, &table);
1266
1267        for (index, &arm) in arms.iter().enumerate() {
1268            let mut build = Builder::new(&mut func, arm);
1269            let what = i128::try_from(index).expect("a small number of cases");
1270            let v = build.iconst(int, (what + 1) * 10);
1271            build.ret(&[v]);
1272        }
1273        let mut build = Builder::new(&mut func, default);
1274        let v = build.iconst(int, 30);
1275        build.ret(&[v]);
1276        (names, func)
1277    }
1278
1279    fn count(func: &Func) -> usize {
1280        func.blocks().count()
1281    }
1282
1283    fn printed(func: &Func, names: &mut Interner) -> String {
1284        let module = Module::new(names.intern("sw.c"), &target());
1285        rucc_ir::print_func(&module, func, names)
1286    }
1287
1288    #[test]
1289    fn a_switch_becomes_a_compare_and_a_branch_for_each_case() {
1290        let (mut names, mut func) = built(&[1, 2]);
1291        let before = count(&func);
1292        switches(&mut func);
1293        assert_eq!(count(&func), before + blocks_for(2));
1294
1295        let text = printed(&func, &mut names);
1296        assert!(!text.contains("switch"), "the switch is gone: {text}");
1297        assert_eq!(text.matches("icmp eq").count(), 2, "one compare per case: {text}");
1298        assert_eq!(text.matches("br_if").count(), 2, "one branch per case: {text}");
1299    }
1300
1301    #[test]
1302    fn the_last_case_falls_to_the_default_rather_than_to_a_block_of_its_own() {
1303        let (_, mut func) = built(&[7]);
1304        let before = count(&func);
1305        switches(&mut func);
1306        // One case needs no chain block at all: the one compare goes to the arm or to the default.
1307        assert_eq!(count(&func), before);
1308        assert_eq!(blocks_for(1), 0);
1309    }
1310
1311    #[test]
1312    fn a_switch_with_only_a_default_is_a_jump() {
1313        let (_, mut func) = built(&[]);
1314        switches(&mut func);
1315        let entry = func.entry().expect("an entry block");
1316        let term = func.terminator(entry).expect("a terminator");
1317        assert_eq!(func[term].opcode, Opcode::Jump);
1318    }
1319
1320    /// The rewrite has to leave a function the verifier still accepts, since every check it makes
1321    /// is one the rest of the back end assumes and none of them is rechecked after this runs.
1322    #[test]
1323    fn what_comes_out_is_valid_ir() {
1324        let (mut names, mut func) = built(&[1, 2, 3, 4]);
1325        switches(&mut func);
1326        let module = Module::new(names.intern("sw.c"), &target());
1327        rucc_ir::verify_func(&module, &func, &names).expect("the rewrite builds valid IR");
1328    }
1329
1330    /// Nothing else is touched, which matters because this runs over every function whether or not
1331    /// one has a `switch` in it.
1332    #[test]
1333    fn a_function_with_no_switch_is_left_exactly_as_it_was() {
1334        let mut names = Interner::new();
1335        let int = Type::int(32);
1336        let mut func =
1337            Func::new(names.intern("f"), Signature::new().with_params(&[int]).with_returns(&[int]));
1338        let entry = func.create_block();
1339        let x = func.append_param(entry, int);
1340        Builder::new(&mut func, entry).ret(&[x]);
1341
1342        let before = printed(&func, &mut names);
1343        switches(&mut func);
1344        assert_eq!(printed(&func, &mut names), before);
1345    }
1346
1347    /// A function of one parameter and one result, with a body somebody else writes.
1348    ///
1349    /// The float rewrites are each one instruction becoming several in the middle of a block, so
1350    /// what a test needs is a block with something around the instruction rather than a shape.
1351    fn one(
1352        params: &[Type],
1353        returns: &[Type],
1354        body: impl FnOnce(&mut Builder<'_>, &[rucc_ir::Value]),
1355    ) -> (Interner, Func) {
1356        let mut names = Interner::new();
1357        let mut func = Func::new(
1358            names.intern("f"),
1359            Signature::new().with_params(params).with_returns(returns),
1360        );
1361        let entry = func.create_block();
1362        let args: Vec<_> = params.iter().map(|&ty| func.append_param(entry, ty)).collect();
1363        let mut build = Builder::new(&mut func, entry);
1364        body(&mut build, &args);
1365        (names, func)
1366    }
1367
1368    fn f64() -> Type {
1369        Type::float(Float::F64)
1370    }
1371
1372    fn f32() -> Type {
1373        Type::float(Float::F32)
1374    }
1375
1376    /// The obligation every rewrite here has: nothing after this checks the IR again.
1377    fn valid(func: &Func, names: &mut Interner) {
1378        let module = Module::new(names.intern("f.c"), &target());
1379        rucc_ir::verify_func(&module, func, names).expect("the rewrite builds valid IR");
1380    }
1381
1382    /// `double c(void) { return 1.5; }`, which is the constant nothing in the rule set can name.
1383    #[test]
1384    fn a_float_constant_becomes_the_integer_that_spells_it_and_a_reading_of_those_bits() {
1385        let (mut names, mut func) = one(&[], &[f64()], |build, _| {
1386            let k = build.fconst(f64(), 0x3ff8_0000_0000_0000);
1387            build.ret(&[k]);
1388        });
1389        floats(&mut func);
1390
1391        let text = printed(&func, &mut names);
1392        assert!(!text.contains("fconst"), "the float constant is gone: {text}");
1393        assert!(text.contains("iconst.i64 4609434218613702656"), "the bits, as an integer: {text}");
1394        assert!(text.contains("bitcast"), "read back as the float: {text}");
1395    }
1396
1397    /// The width follows the format rather than being the widest one, so a `float` constant is an
1398    /// `i32` and reaches `movd` rather than `movq`.
1399    #[test]
1400    fn a_constant_at_the_narrow_format_is_an_integer_of_the_narrow_width() {
1401        let (mut names, mut func) = one(&[], &[f32()], |build, _| {
1402            let k = build.fconst(f32(), 0x4020_0000);
1403            build.ret(&[k]);
1404        });
1405        floats(&mut func);
1406        assert!(printed(&func, &mut names).contains("iconst.i32"), "an i32, not an i64");
1407    }
1408
1409    /// `double n(double x) { return -x; }`. Flipping the sign bit is what C means and subtracting
1410    /// from zero is not, so what this asserts is the exclusive or and the mask it is given.
1411    #[test]
1412    fn a_negation_flips_the_sign_bit_and_touches_no_other() {
1413        let (mut names, mut func) = one(&[f64()], &[f64()], |build, args| {
1414            let n = build.unary(Opcode::FNeg, args[0], f64());
1415            build.ret(&[n]);
1416        });
1417        floats(&mut func);
1418
1419        let text = printed(&func, &mut names);
1420        assert!(!text.contains("fneg"), "the negation is gone: {text}");
1421        assert!(!text.contains("fsub"), "and it did not become a subtraction: {text}");
1422        assert!(text.contains("iconst.i64 -9223372036854775808"), "the sign bit alone: {text}");
1423        assert_eq!(text.matches("xor").count(), 1, "one exclusive or: {text}");
1424        assert_eq!(text.matches("bitcast").count(), 2, "there and back: {text}");
1425    }
1426
1427    /// `double u(unsigned x) { return x; }`, which is a widening and the signed conversion.
1428    #[test]
1429    fn an_unsigned_integer_becoming_a_float_widens_first_and_then_converts_as_signed() {
1430        let (mut names, mut func) = one(&[Type::int(32)], &[f64()], |build, args| {
1431            let d = build.unary(Opcode::UIToFP, args[0], f64());
1432            build.ret(&[d]);
1433        });
1434        floats(&mut func);
1435
1436        let text = printed(&func, &mut names);
1437        assert!(!text.contains("uitofp"), "the unsigned conversion is gone: {text}");
1438        assert!(text.contains("zext.i64"), "widened with zeroes: {text}");
1439        assert!(text.contains("sitofp.f64"), "converted as signed: {text}");
1440    }
1441
1442    /// `unsigned t(double x) { return x; }`, which is the same argument the other way round.
1443    #[test]
1444    fn a_float_becoming_an_unsigned_integer_converts_as_signed_first_and_then_narrows() {
1445        let (mut names, mut func) = one(&[f64()], &[Type::int(32)], |build, args| {
1446            let n = build.unary(Opcode::FPToUI, args[0], Type::int(32));
1447            build.ret(&[n]);
1448        });
1449        floats(&mut func);
1450
1451        let text = printed(&func, &mut names);
1452        assert!(!text.contains("fptoui"), "the unsigned conversion is gone: {text}");
1453        assert!(text.contains("fptosi.i64"), "converted as signed: {text}");
1454        assert!(text.contains("trunc.i32"), "and narrowed to what was asked: {text}");
1455    }
1456
1457    /// `signed char a(double x) { return (signed char)x; }`, which the front end writes as a
1458    /// conversion straight to eight bits and the machine has no instruction for at that width.
1459    #[test]
1460    fn a_conversion_narrower_than_the_machine_has_is_one_it_has_and_a_narrowing() {
1461        let (mut names, mut func) = one(&[f64()], &[Type::int(8)], |build, args| {
1462            let n = build.unary(Opcode::FPToSI, args[0], Type::int(8));
1463            build.ret(&[n]);
1464        });
1465        floats(&mut func);
1466
1467        let text = printed(&func, &mut names);
1468        assert!(text.contains("fptosi.i32"), "converted at a width there is one at: {text}");
1469        assert!(text.contains("trunc.i8"), "and narrowed to what was asked: {text}");
1470    }
1471
1472    /// The same the other way, where the widening carries the sign because the value has one.
1473    #[test]
1474    fn a_signed_integer_narrower_than_the_machine_converts_from_is_widened_with_its_sign() {
1475        let (mut names, mut func) = one(&[Type::int(8)], &[f64()], |build, args| {
1476            let d = build.unary(Opcode::SIToFP, args[0], f64());
1477            build.ret(&[d]);
1478        });
1479        floats(&mut func);
1480
1481        let text = printed(&func, &mut names);
1482        assert!(text.contains("sext.i32"), "widened with the sign and not with zeroes: {text}");
1483        assert!(!text.contains("zext"), "widened with the sign and not with zeroes: {text}");
1484        assert!(text.contains("sitofp.f64"), "converted at a width there is one at: {text}");
1485    }
1486
1487    /// The table the two of them share, which is where the whole argument about widths lives.
1488    #[test]
1489    fn the_width_a_conversion_happens_at_is_the_narrowest_one_that_holds_the_values() {
1490        use super::holder;
1491        for bits in [1, 8, 16, 32] {
1492            assert_eq!(holder(bits, true), Some(32), "a signed {bits} bit value fits in an int");
1493        }
1494        assert_eq!(holder(64, true), Some(64));
1495        for bits in [1, 8, 16, 31] {
1496            assert_eq!(holder(bits, false), Some(32), "an unsigned {bits} bit value does too");
1497        }
1498        // The one more bit an unsigned value needs is what makes these two the wider width.
1499        assert_eq!(holder(32, false), Some(64));
1500        assert_eq!(holder(64, false), None);
1501    }
1502
1503    /// Sixty four bits is where the widening argument runs out, because an unsigned value of that
1504    /// width is not a signed value of any width the IR has. Each of the two gets a rewrite of its
1505    /// own, and what both leave is the signed conversion the machine has with arithmetic around it.
1506    #[test]
1507    fn the_unsigned_conversions_at_the_widest_width_become_the_signed_one_and_a_correction() {
1508        for float in [f32(), f64()] {
1509            let (mut names, mut func) = one(&[Type::int(64)], &[float], |build, args| {
1510                let d = build.unary(Opcode::UIToFP, args[0], float);
1511                build.ret(&[d]);
1512            });
1513            floats(&mut func);
1514            let text = printed(&func, &mut names);
1515            assert!(!text.contains("uitofp"), "the unsigned conversion is gone: {text}");
1516            assert!(text.contains("sitofp"), "the signed one is what is left: {text}");
1517            // The halving that brings the value under the range the signed conversion has, and the
1518            // bit it would have thrown away put back so that the rounding is still the right one.
1519            assert!(text.contains("lshr"), "the value is halved: {text}");
1520            assert!(text.contains("fadd"), "and doubled again afterwards: {text}");
1521            valid(&func, &mut names);
1522        }
1523
1524        for float in [f32(), f64()] {
1525            let (mut names, mut func) = one(&[float], &[Type::int(64)], |build, args| {
1526                let n = build.unary(Opcode::FPToUI, args[0], Type::int(64));
1527                build.ret(&[n]);
1528            });
1529            floats(&mut func);
1530            let text = printed(&func, &mut names);
1531            assert!(!text.contains("fptoui"), "the unsigned conversion is gone: {text}");
1532            assert!(text.contains("fptosi"), "the signed one is what is left: {text}");
1533            // Half the range taken off before the conversion and put back on after it.
1534            assert!(text.contains("fsub"), "the value is brought down: {text}");
1535            assert!(text.contains("shl"), "and the top bit goes back on: {text}");
1536            valid(&func, &mut names);
1537        }
1538    }
1539
1540    /// Neither of those two has a branch in it, which is the thing about them worth a test of its
1541    /// own. Every rewrite in this pass stays inside the block it started in, so a pass that grew a
1542    /// second block would be one whose callers all have to be looked at again.
1543    #[test]
1544    fn the_widest_unsigned_conversions_are_written_without_a_branch() {
1545        let (_, mut func) = one(&[Type::int(64)], &[f64()], |build, args| {
1546            let d = build.unary(Opcode::UIToFP, args[0], f64());
1547            build.ret(&[d]);
1548        });
1549        floats(&mut func);
1550        assert_eq!(func.blocks().count(), 1, "the conversion did not split the block");
1551
1552        let (_, mut func) = one(&[f64()], &[Type::int(64)], |build, args| {
1553            let n = build.unary(Opcode::FPToUI, args[0], Type::int(64));
1554            build.ret(&[n]);
1555        });
1556        floats(&mut func);
1557        assert_eq!(func.blocks().count(), 1, "nor did the other one");
1558    }
1559
1560    /// The arithmetic of those two rewrites, done here in the same order the instructions do it.
1561    ///
1562    /// This is not the compiler running, it is the sequence written out again in a language that
1563    /// can be asked what the answer should have been. What it checks is the part that is easy to
1564    /// get wrong and impossible to see in the assembly, which is whether the halving rounds the way
1565    /// the conversion would have and whether the subtraction is exact. Every boundary is in the
1566    /// list, and so are the values either side of the ones where the two paths meet.
1567    #[test]
1568    fn the_arithmetic_the_widest_unsigned_conversions_do_is_the_conversion() {
1569        const CASES: &[u64] = &[
1570            0,
1571            1,
1572            2,
1573            0x7FFF_FFFF,
1574            0x8000_0000,
1575            0xFFFF_FFFF,
1576            0x0020_0000_0000_0000,
1577            0x0020_0000_0000_0001,
1578            0x7FFF_FFFF_FFFF_FFFF,
1579            0x8000_0000_0000_0000,
1580            0x8000_0000_0000_0001,
1581            0x8000_0000_0000_0400,
1582            0xFFFF_FFFF_FFFF_F800,
1583            0xFFFF_FFFF_FFFF_FFFF,
1584        ];
1585        for &x in CASES {
1586            // What `from_unsigned_word` writes, at `f64`.
1587            let mask = if (x as i64) < 0 { u64::MAX } else { 0 };
1588            let odd = (x >> 1) | (x & 1);
1589            let source = x ^ ((x ^ odd) & mask);
1590            let converted = source as i64 as f64;
1591            let addend = f64::from_bits(converted.to_bits() & mask);
1592            assert_eq!(converted + addend, x as f64, "converting {x:#x} into a double");
1593        }
1594
1595        for &x in CASES {
1596            // And what `to_unsigned_word` writes, at `f64`, over the same values read back.
1597            let d = x as f64;
1598            if d >= 18_446_744_073_709_551_616.0 {
1599                continue;
1600            }
1601            let half = f64::from_bits(0x43E0_0000_0000_0000);
1602            let mask = if d >= half { u64::MAX } else { 0 };
1603            let taken = f64::from_bits(half.to_bits() & mask);
1604            let low = (d - taken) as i64;
1605            let top = u64::from(d >= half) << 63;
1606            assert_eq!(low as u64 ^ top, d as u64, "converting {d} into an unsigned word");
1607        }
1608    }
1609
1610    /// The same obligation the `switch` rewrite has, for the same reason: nothing after this
1611    /// checks the IR again and everything after it assumes what the verifier would have said.
1612    #[test]
1613    fn what_the_float_rewrites_leave_is_valid_ir() {
1614        let (mut names, mut func) = one(&[Type::int(32)], &[f64()], |build, args| {
1615            let k = build.fconst(f64(), 0x3ff8_0000_0000_0000);
1616            let d = build.unary(Opcode::UIToFP, args[0], f64());
1617            let n = build.unary(Opcode::FNeg, d, f64());
1618            let s = build.binary(Opcode::FAdd, n, k, Flags::NONE);
1619            build.ret(&[s]);
1620        });
1621        floats(&mut func);
1622        let module = Module::new(names.intern("f.c"), &target());
1623        rucc_ir::verify_func(&module, &func, &names).expect("the rewrite builds valid IR");
1624    }
1625
1626    /// Nothing else is touched, for the same reason the `switch` pass has that test: this runs
1627    /// over every function whether or not one has a float in it.
1628    #[test]
1629    fn a_function_with_no_floats_in_it_is_left_exactly_as_it_was() {
1630        let (mut names, mut func) = one(&[Type::int(32)], &[Type::int(32)], |build, args| {
1631            build.ret(&[args[0]]);
1632        });
1633        let before = printed(&func, &mut names);
1634        floats(&mut func);
1635        assert_eq!(printed(&func, &mut names), before);
1636    }
1637    fn access(size: u64, align: u32) -> MemInfo {
1638        MemInfo { size, align, order: MemOrder::NotAtomic, tbaa: None, restrict: Restrict::NONE }
1639    }
1640
1641    /// `void c(void *to, const void *from) { *(T *)to = *(const T *)from; }` for a `T` of that
1642    /// size and alignment, which is what the front end writes for a structure assignment.
1643    fn moving(opcode: Opcode, size: u64, align: u32, byte: Option<i128>) -> (Interner, Func) {
1644        one(&[Type::PTR, Type::PTR], &[], |build, args| {
1645            let second = match byte {
1646                Some(value) => build.iconst(Type::int(8), value),
1647                None => args[1],
1648            };
1649            let mem = build.func().add_mem(access(size, align));
1650            let operands = build.func().push_values(&[args[0], second]);
1651            let data = InstData { args: operands, extra: Extra::Mem(mem), ..InstData::new(opcode) };
1652            build.inst(data, &[]);
1653            build.ret(&[]);
1654        })
1655    }
1656
1657    fn copying(size: u64, align: u32) -> (Interner, Func) {
1658        moving(Opcode::Memcpy, size, align, None)
1659    }
1660
1661    fn filling(size: u64, align: u32, byte: i128) -> (Interner, Func) {
1662        moving(Opcode::Memset, size, align, Some(byte))
1663    }
1664
1665    /// The plan a copy of that size and alignment becomes, as widths, which is what the offsets
1666    /// follow from.
1667    fn widths(size: u64, align: u32) -> Option<Vec<u32>> {
1668        Some(chunks(access(size, align), 8)?.into_iter().map(|(_, width)| width).collect())
1669    }
1670
1671    /// `struct point { int x, y; } a, b; a = b;`, which is sixteen bytes aligned to eight.
1672    #[test]
1673    fn a_copy_becomes_a_load_and_a_store_for_each_word_of_it() {
1674        let (mut names, mut func) = copying(16, 8);
1675        bulk(&mut func, &mut names, 8);
1676
1677        let text = printed(&func, &mut names);
1678        assert!(!text.contains("memcpy"), "the copy is gone: {text}");
1679        assert_eq!(text.matches("load.i64").count(), 2, "a load per word: {text}");
1680        assert_eq!(text.matches("store").count(), 2, "a store per word: {text}");
1681        assert_eq!(
1682            text.matches("ptr_add").count(),
1683            2,
1684            "no offset for the word at the front: {text}"
1685        );
1686    }
1687
1688    /// A word is as wide as the block is known to be aligned to and no wider, because a load
1689    /// wider than that faults on a machine that checks and this does not know whether the one it
1690    /// is compiling for does.
1691    #[test]
1692    fn a_word_is_as_wide_as_the_block_is_aligned_to() {
1693        assert_eq!(widths(16, 8), Some(vec![8, 8]));
1694        assert_eq!(widths(16, 4), Some(vec![4, 4, 4, 4]));
1695        assert_eq!(widths(4, 1), Some(vec![1, 1, 1, 1]));
1696    }
1697
1698    /// What is left over is narrower words rather than a run of bytes, so thirteen bytes aligned
1699    /// to eight is three moves and not six.
1700    #[test]
1701    fn what_is_left_over_is_narrower_words_and_not_a_run_of_bytes() {
1702        assert_eq!(widths(13, 8), Some(vec![8, 4, 1]));
1703        assert_eq!(widths(3, 8), Some(vec![2, 1]));
1704        assert_eq!(widths(1, 8), Some(vec![1]));
1705    }
1706
1707    /// Every offset is a multiple of the width at it, which is what lets the alignment of each
1708    /// access be written down as its width.
1709    #[test]
1710    fn every_word_starts_somewhere_it_is_aligned_for() {
1711        for (at, width) in chunks(access(13, 8), 8).expect("a plan for thirteen bytes") {
1712            assert_eq!(at % u64::from(width), 0, "{at} is a multiple of {width}");
1713        }
1714    }
1715
1716    /// `struct big b = { 0 };`, where the part the initialiser did not name is zeroed.
1717    #[test]
1718    fn a_fill_is_the_byte_spread_across_each_word() {
1719        let (mut names, mut func) = filling(16, 8, 0);
1720        bulk(&mut func, &mut names, 8);
1721
1722        let text = printed(&func, &mut names);
1723        assert!(!text.contains("memset"), "the fill is gone: {text}");
1724        assert_eq!(text.matches("store").count(), 2, "a store per word: {text}");
1725        assert!(!text.contains("load"), "a fill reads nothing: {text}");
1726    }
1727
1728    /// The spreading is arithmetic on the byte, which is the thing a rule cannot do and the
1729    /// reason this pass exists at all.
1730    #[test]
1731    fn the_byte_is_repeated_across_the_word_it_is_stored_as() {
1732        assert_eq!(spread(0, 8), 0);
1733        assert_eq!(spread(0xff, 1), 0xff);
1734        assert_eq!(spread(0xff, 4), 0xffff_ffff);
1735        assert_eq!(spread(0xab, 2), 0xabab);
1736        assert_eq!(spread(0xab, 8), 0xabab_abab_abab_abab);
1737    }
1738
1739    /// A copy larger than the threshold is a call to the runtime rather than a run of moves.
1740    #[test]
1741    fn a_copy_too_large_to_unroll_becomes_a_call_to_the_runtime() {
1742        let size = u64::try_from(UNROLL).expect("a small threshold") + 1;
1743        let (mut names, mut func) = copying(size, 1);
1744        bulk(&mut func, &mut names, 8);
1745        let text = printed(&func, &mut names);
1746        assert!(text.contains("call @memcpy"), "a call and not a bulk move: {text}");
1747
1748        // And the one word under it is moves, because the threshold counts moves rather than
1749        // bytes and the whole point of the threshold is that a small copy does not pay for a call.
1750        let (mut names, mut func) = copying(size - 1, 1);
1751        bulk(&mut func, &mut names, 8);
1752        assert!(!printed(&func, &mut names).contains("memcpy"), "one word under it is unrolled");
1753    }
1754
1755    /// The call passes what C passes, which is not what the IR holds. The size lives beside the
1756    /// instruction in the IR and travels in a register in the call.
1757    #[test]
1758    fn the_call_passes_the_size_that_the_instruction_carried_beside_it() {
1759        let size = u64::try_from(UNROLL).expect("a small threshold") + 1;
1760        let (mut names, mut func) = copying(size, 1);
1761        bulk(&mut func, &mut names, 8);
1762        let text = printed(&func, &mut names);
1763        assert!(text.contains(&format!("{size}")), "the size is an argument now: {text}");
1764    }
1765
1766    /// A `memmove` is a call whatever its size, because the two sides may overlap and a run of
1767    /// moves in one direction is right for only one of the two ways they can.
1768    #[test]
1769    fn a_move_is_a_call_however_small_it_is() {
1770        let (mut names, mut func) = moving(Opcode::Memmove, 8, 8, None);
1771        bulk(&mut func, &mut names, 8);
1772        let text = printed(&func, &mut names);
1773        assert!(text.contains("call @memmove"), "a call and not a run of moves: {text}");
1774    }
1775
1776    /// A fill whose byte the program works out rather than names. Spreading a value across a
1777    /// word at runtime is a multiply, so this is a call rather than moves however small it is.
1778    #[test]
1779    fn a_fill_whose_byte_is_not_a_constant_becomes_a_call() {
1780        let (mut names, mut func) = one(&[Type::PTR, Type::int(8)], &[], |build, args| {
1781            let mem = build.func().add_mem(access(8, 8));
1782            let operands = build.func().push_values(&[args[0], args[1]]);
1783            let data = InstData {
1784                args: operands,
1785                extra: Extra::Mem(mem),
1786                ..InstData::new(Opcode::Memset)
1787            };
1788            build.inst(data, &[]);
1789            build.ret(&[]);
1790        });
1791        bulk(&mut func, &mut names, 8);
1792        let text = printed(&func, &mut names);
1793        assert!(text.contains("call @memset"), "a call and not a run of stores: {text}");
1794        // Widened, because C passes the byte as an `int` and the IR holds it as a byte.
1795        assert!(text.contains("zext.i32"), "the byte is widened to what C passes: {text}");
1796    }
1797
1798    /// A machine whose widest move is four bytes gets four byte words out of an eight byte block,
1799    /// however well aligned the block is.
1800    #[test]
1801    fn no_word_is_wider_than_the_machine_moves_at_once() {
1802        assert_eq!(chunks(access(8, 8), 4).map(|plan| plan.len()), Some(2));
1803        assert_eq!(chunks(access(8, 8), 8).map(|plan| plan.len()), Some(1));
1804    }
1805
1806    #[test]
1807    fn what_a_copy_becomes_is_ir_that_verifies() {
1808        let (mut names, mut func) = copying(13, 8);
1809        bulk(&mut func, &mut names, 8);
1810        let module = Module::new(names.intern("c.c"), &target());
1811        rucc_ir::verify_func(&module, &func, &names).expect("the rewrite builds valid IR");
1812    }
1813
1814    #[test]
1815    fn what_a_fill_becomes_is_ir_that_verifies() {
1816        let (mut names, mut func) = filling(13, 8, 0xff);
1817        bulk(&mut func, &mut names, 8);
1818        let module = Module::new(names.intern("f.c"), &target());
1819        rucc_ir::verify_func(&module, &func, &names).expect("the rewrite builds valid IR");
1820    }
1821
1822    #[test]
1823    fn what_a_copy_too_large_to_unroll_becomes_is_ir_that_verifies() {
1824        let size = u64::try_from(UNROLL).expect("a small threshold") + 1;
1825        let (mut names, mut func) = copying(size, 1);
1826        bulk(&mut func, &mut names, 8);
1827        let module = Module::new(names.intern("c.c"), &target());
1828        rucc_ir::verify_func(&module, &func, &names).expect("the call is valid IR");
1829    }
1830
1831    /// Nothing else is touched, for the same reason the other two passes have that test.
1832    #[test]
1833    fn a_function_with_no_bulk_move_in_it_is_left_exactly_as_it_was() {
1834        let (mut names, mut func) = one(&[Type::int(32)], &[Type::int(32)], |build, args| {
1835            build.ret(&[args[0]]);
1836        });
1837        let before = printed(&func, &mut names);
1838        bulk(&mut func, &mut names, 8);
1839        assert_eq!(printed(&func, &mut names), before);
1840    }
1841
1842    /// A function whose body is one byte swap of the given width, which is what a call to
1843    /// `__builtin_bswap16` and its neighbours has become by the time this pass runs.
1844    fn swapping(width: u32) -> (Interner, Func) {
1845        let ty = Type::int(width);
1846        one(&[ty], &[ty], |build, args| {
1847            let s = build.unary(Opcode::Bswap, args[0], ty);
1848            build.ret(&[s]);
1849        })
1850    }
1851
1852    /// The masks are the alternating runs the halving needs, and they are the constants a reader
1853    /// checking this against a byte swap written by hand would expect to see.
1854    ///
1855    /// At thirty two bits the first step swaps sixteen bit halves and so keeps the low half of each
1856    /// pair, which is `0x0000ffff`, and the second swaps bytes within those halves and keeps
1857    /// `0x00ff00ff`. Written as signed because that is what the IR holds an immediate as.
1858    #[test]
1859    fn the_masks_are_the_alternating_runs_of_the_group_being_swapped() {
1860        assert_eq!(alternating(32, 16), 0x0000_ffff);
1861        assert_eq!(alternating(32, 8), 0x00ff_00ff);
1862        assert_eq!(alternating(16, 8), 0x00ff);
1863        assert_eq!(alternating(64, 32), 0x0000_0000_ffff_ffff);
1864        assert_eq!(alternating(64, 16), 0x0000_ffff_0000_ffff);
1865        assert_eq!(alternating(64, 8), 0x00ff_00ff_00ff_00ff);
1866    }
1867
1868    /// The two byte swap is the one step there is, so it is one mask and one pair of shifts.
1869    #[test]
1870    fn a_two_byte_swap_is_one_exchange_of_neighbouring_bytes() {
1871        let (mut names, mut func) = swapping(16);
1872        bytes(&mut func);
1873
1874        let text = printed(&func, &mut names);
1875        assert!(!text.contains("bswap"), "the instruction is gone: {text}");
1876        assert!(text.contains("iconst.i16 255"), "the low byte of the pair: {text}");
1877        assert_eq!(text.matches("shl").count(), 1, "one shift up: {text}");
1878        assert_eq!(text.matches("lshr").count(), 1, "one shift down: {text}");
1879        assert_eq!(text.matches(" or ").count(), 1, "and the two put together: {text}");
1880    }
1881
1882    /// The wider two are the same step done again at half the group, which is what makes the count
1883    /// grow by a fixed amount per doubling rather than per byte.
1884    #[test]
1885    fn a_wider_swap_is_the_same_exchange_once_per_halving() {
1886        for (width, steps) in [(16u32, 1usize), (32, 2), (64, 3)] {
1887            let (mut names, mut func) = swapping(width);
1888            bytes(&mut func);
1889            let text = printed(&func, &mut names);
1890            assert_eq!(text.matches("shl").count(), steps, "at {width}: {text}");
1891            assert_eq!(text.matches("lshr").count(), steps, "at {width}: {text}");
1892            assert_eq!(text.matches(" and ").count(), steps * 2, "at {width}: {text}");
1893            assert_eq!(text.matches(" or ").count(), steps, "at {width}: {text}");
1894        }
1895    }
1896
1897    /// The shift counts are the group being exchanged and nothing else, so a reader can read the
1898    /// halving straight off the constants.
1899    #[test]
1900    fn the_shift_counts_are_the_group_width_halving_as_it_goes() {
1901        let (mut names, mut func) = swapping(64);
1902        bytes(&mut func);
1903        let text = printed(&func, &mut names);
1904        for count in ["iconst.i64 32", "iconst.i64 16", "iconst.i64 8"] {
1905            assert!(text.contains(count), "{count} is a step: {text}");
1906        }
1907    }
1908
1909    /// The rewrite has to leave a function the verifier still accepts, for the reason the switch
1910    /// rewrite has the same test: nothing rechecks it.
1911    #[test]
1912    fn what_a_byte_swap_becomes_is_ir_that_verifies() {
1913        let (mut names, mut func) = swapping(32);
1914        bytes(&mut func);
1915        let module = Module::new(names.intern("b.c"), &target());
1916        rucc_ir::verify_func(&module, &func, &names).expect("the rewrite builds valid IR");
1917    }
1918
1919    /// Nothing else is touched, which matters because this runs over every function in the program
1920    /// and nearly none of them reverses any bytes.
1921    #[test]
1922    fn a_function_with_no_byte_swap_in_it_is_left_exactly_as_it_was() {
1923        let (mut names, mut func) = one(&[Type::int(32)], &[Type::int(32)], |build, args| {
1924            build.ret(&[args[0]]);
1925        });
1926        let before = printed(&func, &mut names);
1927        bytes(&mut func);
1928        assert_eq!(printed(&func, &mut names), before);
1929    }
1930
1931    /// A function whose body is one bit count of the given opcode and width.
1932    fn counting(op: Opcode, width: u32) -> (Interner, Func) {
1933        let ty = Type::int(width);
1934        one(&[ty], &[ty], |build, args| {
1935            let c = build.unary(op, args[0], ty);
1936            build.ret(&[c]);
1937        })
1938    }
1939
1940    /// The masks the halving sum needs, which are the ones any bit counting routine is written with
1941    /// and are worth being able to read off against one.
1942    #[test]
1943    fn the_counting_masks_are_the_ones_the_halving_sum_is_written_with() {
1944        assert_eq!(alternating(32, 1), 0x5555_5555);
1945        assert_eq!(alternating(32, 2), 0x3333_3333);
1946        assert_eq!(alternating(32, 4), 0x0f0f_0f0f);
1947        assert_eq!(every(32, 8, 1), 0x0101_0101);
1948        assert_eq!(every(64, 8, 1), 0x0101_0101_0101_0101);
1949    }
1950
1951    /// The set bit count is arithmetic and the multiply is what adds the bytes together, which is
1952    /// the step a reader is most likely to want to check.
1953    #[test]
1954    fn a_set_bit_count_is_the_halving_sum_and_a_multiply_that_adds_the_bytes() {
1955        let (mut names, mut func) = counting(Opcode::Ctpop, 32);
1956        counts(&mut func);
1957
1958        let text = printed(&func, &mut names);
1959        assert!(!text.contains("ctpop"), "the instruction is gone: {text}");
1960        assert!(text.contains("iconst.i32 1431655765"), "the pairs mask: {text}");
1961        assert!(text.contains("iconst.i32 858993459"), "the nibbles mask: {text}");
1962        assert!(text.contains("iconst.i32 252645135"), "the bytes mask: {text}");
1963        assert_eq!(text.matches(" mul ").count(), 1, "one multiply: {text}");
1964        assert!(text.contains("iconst.i32 24"), "and the top byte is the answer: {text}");
1965    }
1966
1967    /// At eight bits there are no bytes left to add, so the multiply is not written at all.
1968    #[test]
1969    fn a_count_of_one_byte_stops_before_the_multiply() {
1970        let (mut names, mut func) = counting(Opcode::Ctpop, 8);
1971        counts(&mut func);
1972        let text = printed(&func, &mut names);
1973        assert!(!text.contains("ctpop"), "{text}");
1974        assert!(!text.contains(" mul "), "nothing to add together: {text}");
1975    }
1976
1977    /// A leading zero count smears every set bit downwards and counts what is left unset above it,
1978    /// which is one shift and one or per doubling and then the count.
1979    #[test]
1980    fn a_leading_zero_count_smears_the_value_down_and_counts_the_complement() {
1981        let (mut names, mut func) = counting(Opcode::Ctlz, 32);
1982        counts(&mut func);
1983
1984        let text = printed(&func, &mut names);
1985        assert!(!text.contains("ctlz"), "the instruction is gone: {text}");
1986        assert!(!text.contains("ctpop"), "and so is the count it became: {text}");
1987        for by in ["iconst.i32 1", "iconst.i32 2", "iconst.i32 4", "iconst.i32 8", "iconst.i32 16"]
1988        {
1989            assert!(text.contains(by), "{by} is a smearing step: {text}");
1990        }
1991        assert_eq!(text.matches(" xor ").count(), 1, "one complement: {text}");
1992    }
1993
1994    /// A trailing zero count is the bits below the lowest set one, which is a mask and no smearing.
1995    #[test]
1996    fn a_trailing_zero_count_masks_the_bits_below_the_lowest_set_one() {
1997        let (mut names, mut func) = counting(Opcode::Cttz, 32);
1998        counts(&mut func);
1999
2000        let text = printed(&func, &mut names);
2001        assert!(!text.contains("cttz"), "the instruction is gone: {text}");
2002        assert!(!text.contains("ctpop"), "and so is the count it became: {text}");
2003        assert!(text.contains("iconst.i32 -1"), "the complement and the decrement: {text}");
2004        assert_eq!(text.matches(" xor ").count(), 1, "one complement: {text}");
2005        // Far fewer instructions than the leading count, because there is no smearing to do.
2006        assert!(text.matches(" or ").count() <= 1, "no smearing run: {text}");
2007    }
2008
2009    /// The rewrites have to leave a function the verifier still accepts, at every width and for all
2010    /// three, because nothing rechecks what comes out of here.
2011    #[test]
2012    fn what_a_bit_count_becomes_is_ir_that_verifies() {
2013        for op in [Opcode::Ctpop, Opcode::Ctlz, Opcode::Cttz] {
2014            for width in [8u32, 16, 32, 64] {
2015                let (mut names, mut func) = counting(op, width);
2016                counts(&mut func);
2017                let module = Module::new(names.intern("c.c"), &target());
2018                rucc_ir::verify_func(&module, &func, &names)
2019                    .unwrap_or_else(|e| panic!("{op:?} at {width}: {e:?}"));
2020            }
2021        }
2022    }
2023
2024    /// A width the arithmetic is not written for is left as the instruction it was, so a selector
2025    /// with no rule for it says so rather than the program getting a number counted in the wrong
2026    /// shape.
2027    #[test]
2028    fn a_width_the_halving_sum_is_not_written_for_is_left_alone() {
2029        let (mut names, mut func) = counting(Opcode::Ctpop, 24);
2030        counts(&mut func);
2031        assert!(printed(&func, &mut names).contains("ctpop"), "left as it was");
2032    }
2033
2034    /// Nothing else is touched, for the same reason the other passes have that test.
2035    #[test]
2036    fn a_function_with_no_bit_count_in_it_is_left_exactly_as_it_was() {
2037        let (mut names, mut func) = one(&[Type::int(32)], &[Type::int(32)], |build, args| {
2038            build.ret(&[args[0]]);
2039        });
2040        let before = printed(&func, &mut names);
2041        counts(&mut func);
2042        assert_eq!(printed(&func, &mut names), before);
2043    }
2044
2045    /// One overflow checked instruction whose value and whose flag are both returned, so that the
2046    /// substitution has two readers to find rather than none.
2047    fn checking(op: Opcode, width: u32) -> (Interner, Func) {
2048        let ty = Type::int(width);
2049        let bit = ty.with_lane(Type::I1);
2050        one(&[ty, ty], &[ty, bit], |build, args| {
2051            let (value, flag) = build.checked(op, args[0], args[1]);
2052            build.ret(&[value, flag]);
2053        })
2054    }
2055
2056    /// An unsigned add wraps exactly when the sum came out below an operand, which is one
2057    /// comparison and no arithmetic on the sign bits.
2058    #[test]
2059    fn a_checked_unsigned_add_becomes_an_add_and_one_comparison() {
2060        let (mut names, mut func) = checking(Opcode::UAddOverflow, 32);
2061        overflows(&mut func);
2062
2063        let text = printed(&func, &mut names);
2064        assert!(!text.contains("uadd_overflow"), "the instruction is gone: {text}");
2065        assert_eq!(text.matches(" add ").count(), 1, "one add: {text}");
2066        assert_eq!(text.matches("icmp ult").count(), 1, "and one comparison: {text}");
2067        assert!(!text.contains(" xor "), "nothing about sign bits: {text}");
2068    }
2069
2070    /// A signed add wraps exactly when the operands agreed in sign and the answer did not, which is
2071    /// the sign bit of `(a ^ v) & (b ^ v)`.
2072    #[test]
2073    fn a_checked_signed_add_becomes_an_add_and_the_sign_bit_of_two_exclusive_ors() {
2074        let (mut names, mut func) = checking(Opcode::SAddOverflow, 32);
2075        overflows(&mut func);
2076
2077        let text = printed(&func, &mut names);
2078        assert!(!text.contains("sadd_overflow"), "the instruction is gone: {text}");
2079        assert_eq!(text.matches(" add ").count(), 1, "one add: {text}");
2080        assert_eq!(text.matches(" xor ").count(), 2, "the answer against each operand: {text}");
2081        assert_eq!(text.matches(" and ").count(), 1, "both at once: {text}");
2082        assert!(text.contains("icmp slt"), "and its sign bit: {text}");
2083    }
2084
2085    /// An unsigned subtract wraps exactly when the left operand was below the right, which does not
2086    /// need the answer at all.
2087    #[test]
2088    fn a_checked_unsigned_subtract_compares_the_operands_and_not_the_answer() {
2089        let (mut names, mut func) = checking(Opcode::USubOverflow, 64);
2090        overflows(&mut func);
2091
2092        let text = printed(&func, &mut names);
2093        assert!(!text.contains("usub_overflow"), "the instruction is gone: {text}");
2094        assert_eq!(text.matches(" sub ").count(), 1, "one subtract: {text}");
2095        assert!(text.contains("icmp ult %0, %1"), "the operands, in order: {text}");
2096    }
2097
2098    /// A checked multiply is the ordinary multiply and the high half of the product, which is four
2099    /// multiplies of the halves and the carry between them.
2100    ///
2101    /// This is the expensive one and it is what tamnd/rucc#309 is mostly worth: a machine whose
2102    /// multiply writes the high half into a second register does the whole of it in one
2103    /// instruction.
2104    #[test]
2105    fn a_checked_multiply_becomes_a_multiply_and_the_high_half_of_the_product() {
2106        let (mut names, mut func) = checking(Opcode::UMulOverflow, 64);
2107        overflows(&mut func);
2108
2109        let text = printed(&func, &mut names);
2110        assert!(!text.contains("umul_overflow"), "the instruction is gone: {text}");
2111        assert_eq!(text.matches(" mul ").count(), 5, "the answer and the four halves: {text}");
2112        assert!(text.contains("iconst.i64 32"), "split at half the width: {text}");
2113        assert!(text.contains("iconst.i64 4294967295"), "and masked to it: {text}");
2114        assert!(text.contains("icmp ne"), "the high half against zero: {text}");
2115        assert!(!text.contains("ashr"), "and nothing corrected for sign: {text}");
2116    }
2117
2118    /// The signed multiply is the unsigned one with the sign correction on top, and the test is
2119    /// against the sign extension of the low half rather than against zero.
2120    #[test]
2121    fn a_checked_signed_multiply_corrects_the_high_half_for_each_negative_operand() {
2122        let (mut names, mut func) = checking(Opcode::SMulOverflow, 64);
2123        overflows(&mut func);
2124
2125        let text = printed(&func, &mut names);
2126        assert!(!text.contains("smul_overflow"), "the instruction is gone: {text}");
2127        assert_eq!(
2128            text.matches(" ashr ").count(),
2129            3,
2130            "each operand's sign, and the answer: {text}"
2131        );
2132        assert!(text.contains("iconst.i64 63"), "spread from the top bit: {text}");
2133        assert_eq!(text.matches(" sub ").count(), 2, "one correction per operand: {text}");
2134    }
2135
2136    /// Both results have to reach their readers, which is the one thing this pass has to do that
2137    /// the others do not: the instruction goes away rather than becoming another one, so nothing is
2138    /// left holding the values the rest of the function was reading.
2139    #[test]
2140    fn both_results_are_substituted_into_whoever_was_reading_them() {
2141        let (mut names, mut func) = checking(Opcode::SAddOverflow, 32);
2142        overflows(&mut func);
2143
2144        // The whole of it, because what this is checking is that nothing is left pointing at the
2145        // two values the removed instruction used to define. The return names the add and the
2146        // comparison, which are what replaced them.
2147        let text = printed(&func, &mut names);
2148        assert_eq!(
2149            text,
2150            concat!(
2151                "func @f(i32, i32) -> (i32, i1), linkage(external) {\n",
2152                "block0(%0: i32, %1: i32):\n",
2153                "    %2 = add %0, %1\n",
2154                "    %3 = xor %0, %2\n",
2155                "    %4 = xor %1, %2\n",
2156                "    %5 = and %3, %4\n",
2157                "    %6 = iconst.i32 0\n",
2158                "    %7 = icmp slt %5, %6\n",
2159                "    return %2, %7\n",
2160                "}\n",
2161            ),
2162        );
2163    }
2164
2165    /// The rewrites have to leave a function the verifier still accepts, for all six and at every
2166    /// width, because nothing rechecks what comes out of here.
2167    #[test]
2168    fn what_an_overflow_check_becomes_is_ir_that_verifies() {
2169        let all = [
2170            Opcode::UAddOverflow,
2171            Opcode::SAddOverflow,
2172            Opcode::USubOverflow,
2173            Opcode::SSubOverflow,
2174            Opcode::UMulOverflow,
2175            Opcode::SMulOverflow,
2176        ];
2177        for op in all {
2178            for width in [8u32, 16, 32, 64] {
2179                let (mut names, mut func) = checking(op, width);
2180                overflows(&mut func);
2181                let module = Module::new(names.intern("c.c"), &target());
2182                rucc_ir::verify_func(&module, &func, &names)
2183                    .unwrap_or_else(|e| panic!("{op:?} at {width}: {e:?}"));
2184            }
2185        }
2186    }
2187
2188    /// A width the arithmetic is not written for is left as the instruction it was, for the same
2189    /// reason the bit counts leave one: a selector with no rule for it says so, which is better
2190    /// than an answer checked in the wrong shape.
2191    #[test]
2192    fn a_width_the_split_is_not_written_for_is_left_alone() {
2193        let (mut names, mut func) = checking(Opcode::UMulOverflow, 24);
2194        overflows(&mut func);
2195        assert!(printed(&func, &mut names).contains("umul_overflow"), "left as it was");
2196    }
2197
2198    /// Nothing else is touched, for the same reason the other passes have that test.
2199    #[test]
2200    fn a_function_with_no_overflow_check_in_it_is_left_exactly_as_it_was() {
2201        let (mut names, mut func) = one(&[Type::int(32)], &[Type::int(32)], |build, args| {
2202            build.ret(&[args[0]]);
2203        });
2204        let before = printed(&func, &mut names);
2205        overflows(&mut func);
2206        assert_eq!(printed(&func, &mut names), before);
2207    }
2208
2209    /// `T x = *p;` with an ordering on it, which is what `__atomic_load_n` becomes.
2210    fn reading(ty: Type, align: u32, order: MemOrder) -> (Interner, Func) {
2211        one(&[Type::PTR], &[ty], |build, args| {
2212            let info = MemInfo { order, ..access(0, align) };
2213            let value = build.atomic_load(ty, args[0], info, Flags::NONE);
2214            build.ret(&[value]);
2215        })
2216    }
2217
2218    /// `*p = x;` with an ordering on it, which is what `__atomic_store_n` becomes.
2219    fn writing(ty: Type, align: u32, order: MemOrder) -> (Interner, Func) {
2220        one(&[Type::PTR, ty], &[], |build, args| {
2221            let info = MemInfo { order, ..access(0, align) };
2222            build.atomic_store(args[1], args[0], info, Flags::NONE);
2223            build.ret(&[]);
2224        })
2225    }
2226
2227    /// Every ordered access below the strongest store is the plain instruction on this machine,
2228    /// and the ordering comes off it when it is.
2229    ///
2230    /// The ordering coming off is not cosmetic: the verifier refuses an ordering on a plain access,
2231    /// because a plain load may be moved, duplicated and dropped and an ordering left on one would
2232    /// be a claim nothing downstream honours.
2233    #[test]
2234    fn an_ordered_access_becomes_the_plain_one_this_machine_already_orders() {
2235        for order in [MemOrder::Relaxed, MemOrder::Acquire, MemOrder::SeqCst] {
2236            let (mut names, mut func) = reading(Type::int(32), 4, order);
2237            orderings(&mut func, 8);
2238            let text = printed(&func, &mut names);
2239            assert!(text.contains("load.i32"), "{order:?}: {text}");
2240            assert!(!text.contains("atomic_load"), "{order:?}: {text}");
2241            assert!(!text.contains(order.name()), "the ordering came off: {text}");
2242        }
2243
2244        for order in [MemOrder::Relaxed, MemOrder::Release] {
2245            let (mut names, mut func) = writing(Type::int(32), 4, order);
2246            orderings(&mut func, 8);
2247            let text = printed(&func, &mut names);
2248            assert!(text.contains("store %1 -> %0"), "{order:?}: {text}");
2249            assert!(!text.contains("atomic_store"), "{order:?}: {text}");
2250            assert!(!text.contains("fence"), "{order:?} costs nothing here: {text}");
2251        }
2252    }
2253
2254    /// The strongest store is the plain store and a barrier behind it, in that order.
2255    ///
2256    /// It is the one thing total store order does not give away: a store followed by a load of
2257    /// another address may be seen the other way round, and sequential consistency is exactly the
2258    /// ordering that forbids it.
2259    #[test]
2260    fn the_strongest_store_keeps_a_barrier_behind_it() {
2261        let (mut names, mut func) = writing(Type::int(32), 4, MemOrder::SeqCst);
2262        orderings(&mut func, 8);
2263        let text = printed(&func, &mut names);
2264        let (before, after) = text.split_once("fence seq_cst").expect("a barrier");
2265        assert!(before.contains("store %1 -> %0"), "the store comes first: {text}");
2266        assert!(!after.contains("store"), "and nothing is between them: {text}");
2267        assert!(!text.contains("atomic_store"), "{text}");
2268    }
2269
2270    /// A barrier the program wrote is left for `crate::lower`, which is where a target says what
2271    /// an ordering costs.
2272    #[test]
2273    fn a_barrier_is_left_for_the_place_that_knows_what_one_costs() {
2274        for order in MemOrder::all().filter(|&order| order != MemOrder::NotAtomic) {
2275            let (mut names, mut func) = one(&[], &[], |build, _| {
2276                build.fence(order);
2277                build.ret(&[]);
2278            });
2279            let before = printed(&func, &mut names);
2280            orderings(&mut func, 8);
2281            assert_eq!(printed(&func, &mut names), before, "{order:?}");
2282        }
2283    }
2284
2285    /// An access the machine cannot do in one go is left as the opcode it was, which is a refusal
2286    /// naming the instruction rather than an answer that is not atomic at all.
2287    ///
2288    /// Two ways it happens: wider than a word, and narrower than a word but at an address the
2289    /// program said less about than the width. Both are `__atomic_is_lock_free` answering no.
2290    #[test]
2291    fn an_access_this_machine_cannot_do_in_one_go_is_left_alone() {
2292        for (ty, align) in [(Type::int(128), 16), (Type::int(64), 4)] {
2293            let (mut names, mut func) = reading(ty, align, MemOrder::SeqCst);
2294            orderings(&mut func, 8);
2295            assert!(printed(&func, &mut names).contains("atomic_load"), "left as it was");
2296        }
2297    }
2298
2299    /// What comes out is IR the verifier takes, which is the check that matters most here: the
2300    /// ordering has to be gone from a plain access or this pass has built something illegal.
2301    #[test]
2302    fn what_the_ordered_accesses_become_verifies() {
2303        for order in MemOrder::all().filter(|&order| order != MemOrder::NotAtomic) {
2304            for (mut names, mut func) in
2305                [reading(Type::int(32), 4, order), writing(Type::int(32), 4, order)]
2306            {
2307                if !order.is_valid_for_load() && !order.is_valid_for_store() {
2308                    continue;
2309                }
2310                orderings(&mut func, 8);
2311                let module = Module::new(names.intern("a.c"), &target());
2312                rucc_ir::verify_func(&module, &func, &names)
2313                    .unwrap_or_else(|e| panic!("{order:?}: {e:?}"));
2314            }
2315        }
2316    }
2317
2318    /// Nothing else is touched, for the same reason the other passes have that test.
2319    #[test]
2320    fn a_function_with_no_ordered_access_in_it_is_left_exactly_as_it_was() {
2321        let (mut names, mut func) = one(&[Type::int(32)], &[Type::int(32)], |build, args| {
2322            build.ret(&[args[0]]);
2323        });
2324        let before = printed(&func, &mut names);
2325        orderings(&mut func, 8);
2326        assert_eq!(printed(&func, &mut names), before);
2327    }
2328}