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