Skip to main content

rucc_codegen/
divide.rs

1//! A division by a constant, as a multiply by its reciprocal and a shift.
2//!
3//! Design: `spec/optimizer/19-reassociation-and-arithmetic.md` section 19.5, which hands this to
4//! the back end.
5//!
6//! A `div` takes twenty to forty cycles and a multiply takes three, so every compiler turns a
7//! division by a constant into a multiply by a number close to its reciprocal, scaled up by a power
8//! of two, and a shift that takes the scale back out. The number is what Granlund and Montgomery
9//! call the magic number, and [`multiplier`] works it out the way `choose_multiplier` at
10//! `gcc/expmed.cc:3728` does.
11//!
12//! # Why the product is sixty four bits wide
13//!
14//! gcc writes the multiply as a high multiply at the width of the division, which is an instruction
15//! the IR does not have. What it has is an ordinary multiply at sixty four bits, and a dividend of
16//! at most thirty two bits times a magic number of at most thirty three fits in one. So the
17//! dividend is widened, multiplied, and shifted by the width and the post shift at once, and the
18//! answer is the low half of that. It is also one step shorter than gcc's when the magic number
19//! needs thirty three bits: gcc cannot hold the sum of the dividend and the high half in thirty two
20//! bits and halves the difference first, and here the sum fits.
21//!
22//! A division at sixty four bits needs the high half of a hundred and twenty eight bit product, so
23//! it stays a `div` until the IR has a high multiply (#309). A power of two and an exact division
24//! need no product and are done at every width.
25//!
26//! # What the dividend is known to hold
27//!
28//! C divides at `int` at least, so an `unsigned short` divided by ten is an `int` division of a
29//! value widened from sixteen bits. The widening says the value fits in sixteen bits, a magic
30//! number for sixteen bits is smaller and never needs the extra add, and a signed division of a
31//! value that cannot be negative is the unsigned one. [`Range`] is that, read off the instruction
32//! the dividend comes from.
33//!
34//! # What is left alone
35//!
36//! Everything when the goal is size, where the `div` is shorter, which is what gcc does at `-Os`.
37//! A divisor of zero, one or minus one, which is undefined or which the optimizer has already
38//! answered. A divisor larger than anything the dividend can hold, where the quotient is zero or
39//! one and a compare is the right code, which is rare enough to wait.
40//!
41//! # How it is checked
42//!
43//! [`program`] writes the rewrite as a short list of [`Step`]s before anything goes into the
44//! function, and the tests run that same list on numbers. At eight bits that is every dividend
45//! against every divisor. At sixteen it is every divisor, over the dividends either side of each of
46//! its multiples, which is a proof rather than a sample: the rewrite and the division it replaces
47//! only ever move at those points, so agreeing there is agreeing everywhere. `cargo xtask divide`
48//! runs what the compiler makes of the same divisions against gcc.
49
50use rucc_cost::Goal;
51use rucc_ir::{Def, Extra, Flags, Func, Imm, Inst, Opcode, Type, Value};
52
53use crate::expand::{ahead, ahead_const, becomes};
54
55/// Rewrites every division and remainder by a constant that [`program`] has an answer for.
56pub fn divisions(func: &mut Func, goal: Goal) {
57    if matches!(goal, Goal::Size) {
58        return;
59    }
60    let found: Vec<Inst> =
61        func.blocks().flat_map(|block| func.insts(block).collect::<Vec<_>>()).collect();
62    for inst in found {
63        let Some(division) = division(func, inst) else { continue };
64        let Some(program) = program(division) else { continue };
65        write(func, inst, &program);
66    }
67}
68
69/// What the dividend is known to hold.
70#[derive(Debug, Clone, Copy, PartialEq, Eq)]
71pub enum Range {
72    /// Something from zero up to, but not including, two to the power of this.
73    Unsigned(u32),
74    /// Something a signed integer of this many bits holds.
75    Signed(u32),
76}
77
78/// One division or remainder by a constant, as far as the rewrite needs to know it.
79#[derive(Debug, Clone, Copy, PartialEq, Eq)]
80pub struct Division {
81    /// Whether it reads its operands as signed.
82    pub signed: bool,
83    /// Whether the answer is the remainder rather than the quotient.
84    pub remainder: bool,
85    /// Whether the program promised the division leaves nothing over.
86    pub exact: bool,
87    /// The width it is done at.
88    pub width: u32,
89    /// What the dividend holds.
90    pub range: Range,
91    /// The divisor, read the way the division reads it.
92    pub divisor: i128,
93}
94
95/// One instruction of a rewrite.
96///
97/// Value zero is the dividend, and value `i + 1` is what step `i` gives.
98#[derive(Debug, Clone, Copy, PartialEq, Eq)]
99pub enum Step {
100    /// A constant of that many bits.
101    Const(i128, u32),
102    /// An operation over one value or two, giving that many bits. A conversion reads only the
103    /// first.
104    Op(Opcode, [usize; 2], u32),
105}
106
107/// A rewrite, in the order it is written.
108#[derive(Debug, Clone, PartialEq, Eq)]
109pub struct Program {
110    /// The width of the dividend and of the answer.
111    pub width: u32,
112    /// The steps, the last of which is the answer.
113    pub steps: Vec<Step>,
114}
115
116/// The dividend, which every program starts from.
117const DIVIDEND: usize = 0;
118
119impl Program {
120    fn new(width: u32) -> Self {
121        Self { width, steps: Vec::new() }
122    }
123
124    fn push(&mut self, step: Step) -> usize {
125        self.steps.push(step);
126        self.steps.len()
127    }
128
129    fn constant(&mut self, value: i128, bits: u32) -> usize {
130        self.push(Step::Const(value, bits))
131    }
132
133    /// An operation over two values of `bits` bits, with the second a constant.
134    fn by(&mut self, opcode: Opcode, value: usize, constant: i128, bits: u32) -> usize {
135        let constant = self.constant(constant, bits);
136        self.push(Step::Op(opcode, [value, constant], bits))
137    }
138
139    fn op(&mut self, opcode: Opcode, lhs: usize, rhs: usize, bits: u32) -> usize {
140        self.push(Step::Op(opcode, [lhs, rhs], bits))
141    }
142
143    fn convert(&mut self, opcode: Opcode, value: usize, bits: u32) -> usize {
144        self.push(Step::Op(opcode, [value, value], bits))
145    }
146
147    /// The dividend at sixty four bits, where the product is taken.
148    fn widened(&mut self, extend: Opcode) -> usize {
149        if self.width == 64 { DIVIDEND } else { self.convert(extend, DIVIDEND, 64) }
150    }
151
152    /// A value of sixty four bits back at the width of the division.
153    fn narrowed(&mut self, value: usize) -> usize {
154        if self.width == 64 { value } else { self.convert(Opcode::Trunc, value, self.width) }
155    }
156
157    /// Zero minus the value.
158    fn negated(&mut self, value: usize) -> usize {
159        let zero = self.constant(0, self.width);
160        self.op(Opcode::Sub, zero, value, self.width)
161    }
162
163    /// The dividend less the quotient times the divisor, which is the remainder.
164    fn left_over(&mut self, quotient: usize, divisor: i128) -> usize {
165        let back = self.by(Opcode::Mul, quotient, divisor, self.width);
166        self.op(Opcode::Sub, DIVIDEND, back, self.width)
167    }
168}
169
170/// The rewrite for one division, or `None` where the `div` is left.
171#[must_use]
172pub fn program(division: Division) -> Option<Program> {
173    let Division { signed, remainder, exact, width, range, divisor } = division;
174    if !matches!(width, 8 | 16 | 32 | 64) || matches!(divisor, 0 | 1) || (signed && divisor == -1) {
175        return None;
176    }
177    let mut program = Program::new(width);
178    if exact && !remainder {
179        exactly(&mut program, signed, divisor);
180        return Some(program);
181    }
182    let size = divisor.unsigned_abs();
183    match range {
184        Range::Unsigned(bits) => {
185            let quotient = unsigned(&mut program, size, bits)?;
186            if remainder {
187                if size.is_power_of_two() {
188                    let mask = i128::try_from(size - 1).ok()?;
189                    program.by(Opcode::And, DIVIDEND, mask, width);
190                } else {
191                    program.left_over(quotient, i128::try_from(size).ok()?);
192                }
193            } else if divisor < 0 {
194                program.negated(quotient);
195            }
196        }
197        Range::Signed(_) if size.is_power_of_two() => biased(&mut program, divisor, remainder),
198        Range::Signed(bits) => {
199            let quotient = rounded(&mut program, divisor, bits)?;
200            if remainder {
201                program.left_over(quotient, divisor);
202            }
203        }
204    }
205    Some(program)
206}
207
208/// The magic number for dividing by `divisor` a value of `bits` bits whose top `bits - precision`
209/// bits are known to be clear, and the shift that goes after the multiply.
210///
211/// `choose_multiplier` at `gcc/expmed.cc:3728`. The quotient is the product shifted right by `bits`
212/// and then by the shift. The number is the smallest that is still exact over the whole range,
213/// which is found by starting from the largest shift that can work and halving both bounds for as
214/// long as they stay apart.
215///
216/// # Panics
217///
218/// Panics if the divisor is zero or the working does not fit, which is a width over sixty four.
219#[must_use]
220pub fn multiplier(divisor: u128, bits: u32, precision: u32) -> (u128, u32) {
221    assert!(divisor > 0, "a divisor of zero has no reciprocal");
222    let up = 128 - (divisor - 1).leading_zeros();
223    assert!(bits + up < 128, "a divisor and a width this can work with");
224    let mut shift = up;
225    let low = (1u128 << (bits + up)) / divisor;
226    let high = ((1u128 << (bits + up)) + (1u128 << (bits + up - precision))) / divisor;
227    let (mut low, mut high) = (low, high);
228    while shift > 0 && low / 2 < high / 2 {
229        low /= 2;
230        high /= 2;
231        shift -= 1;
232    }
233    (high, shift)
234}
235
236/// The quotient of a dividend that is never negative and fits in `bits` bits, by a positive
237/// divisor.
238///
239/// When the magic number needs one bit more than the dividend has and the dividend has thirty two,
240/// the product would need sixty five, so the number goes in without its top bit and the dividend is
241/// added back to the high half, which is the same product shifted down by thirty two. The sum has
242/// thirty three bits and fits.
243fn unsigned(program: &mut Program, divisor: u128, bits: u32) -> Option<usize> {
244    let width = program.width;
245    if bits >= 128 || divisor >= 1u128 << bits {
246        return None;
247    }
248    if divisor.is_power_of_two() {
249        let shift = i128::from(divisor.trailing_zeros());
250        return Some(program.by(Opcode::LShr, DIVIDEND, shift, width));
251    }
252    if bits > 32 {
253        return None;
254    }
255    let (magic, shift) = multiplier(divisor, bits, bits);
256    let wide = program.widened(Opcode::ZExt);
257    let shifted = if magic < 1u128 << bits || bits < 32 {
258        let product = program.by(Opcode::Mul, wide, i128::try_from(magic).ok()?, 64);
259        program.by(Opcode::LShr, product, i128::from(bits + shift), 64)
260    } else {
261        let magic = i128::try_from(magic - (1u128 << 32)).ok()?;
262        let product = program.by(Opcode::Mul, wide, magic, 64);
263        let high = program.by(Opcode::LShr, product, 32, 64);
264        let sum = program.op(Opcode::Add, high, wide, 64);
265        if shift == 0 { sum } else { program.by(Opcode::LShr, sum, i128::from(shift), 64) }
266    };
267    Some(program.narrowed(shifted))
268}
269
270/// The quotient of a signed dividend of `bits` bits by a divisor that is not a power of two,
271/// rounded towards zero.
272///
273/// The product shifted down is the quotient rounded towards minus infinity, which for a negative
274/// dividend is one less than C's answer, so the dividend's sign, which is minus one or zero, is
275/// taken off it. For a negative divisor it is the other way round, and the same subtraction the
276/// other way round negates the quotient for nothing.
277fn rounded(program: &mut Program, divisor: i128, bits: u32) -> Option<usize> {
278    let width = program.width;
279    let size = divisor.unsigned_abs();
280    if bits > 32 || size > 1u128 << (bits - 1) {
281        return None;
282    }
283    let (magic, shift) = multiplier(size, bits, bits - 1);
284    let wide = program.widened(Opcode::SExt);
285    let product = program.by(Opcode::Mul, wide, i128::try_from(magic).ok()?, 64);
286    let shifted = program.by(Opcode::AShr, product, i128::from(bits + shift), 64);
287    let low = program.narrowed(shifted);
288    let sign = program.by(Opcode::AShr, DIVIDEND, i128::from(width - 1), width);
289    Some(if divisor > 0 {
290        program.op(Opcode::Sub, low, sign, width)
291    } else {
292        program.op(Opcode::Sub, sign, low, width)
293    })
294}
295
296/// A signed division or remainder by a power of two or the negative of one.
297///
298/// A shift rounds towards minus infinity and C rounds towards zero, so a negative dividend has the
299/// divisor less one added first, which is the bias. The sign shifted down is that bias, or the top
300/// bit on its own when the power is one. The remainder is what the mask leaves of the biased
301/// dividend with the bias taken back off.
302fn biased(program: &mut Program, divisor: i128, remainder: bool) {
303    let width = program.width;
304    let size = divisor.unsigned_abs();
305    let power = size.trailing_zeros();
306    let bias = if power == 1 {
307        program.by(Opcode::LShr, DIVIDEND, i128::from(width - 1), width)
308    } else {
309        let sign = program.by(Opcode::AShr, DIVIDEND, i128::from(width - 1), width);
310        program.by(Opcode::LShr, sign, i128::from(width - power), width)
311    };
312    let sum = program.op(Opcode::Add, DIVIDEND, bias, width);
313    if remainder {
314        let mask = (1i128 << power) - 1;
315        let low = program.by(Opcode::And, sum, mask, width);
316        program.op(Opcode::Sub, low, bias, width);
317        return;
318    }
319    let quotient = program.by(Opcode::AShr, sum, i128::from(power), width);
320    if divisor < 0 {
321        program.negated(quotient);
322    }
323}
324
325/// A division the program promised is exact, as a shift and a multiply by the inverse of what is
326/// left of the divisor.
327///
328/// An odd number has an inverse modulo any power of two, so a multiple of it times that inverse is
329/// the other factor, wrapping and all. The power of two in the divisor comes out first as a shift,
330/// which loses nothing because the dividend is a multiple of it. This is what a pointer subtraction
331/// over a structure whose size is not a power of two becomes, and it needs no product wider than
332/// the division, so it is done at sixty four bits too.
333fn exactly(program: &mut Program, signed: bool, divisor: i128) {
334    let width = program.width;
335    let power = divisor.trailing_zeros();
336    let mut value = DIVIDEND;
337    if power > 0 {
338        let shift = if signed { Opcode::AShr } else { Opcode::LShr };
339        value = program.by(shift, DIVIDEND, i128::from(power), width);
340    }
341    let odd = divisor >> power;
342    if odd != 1 {
343        program.by(Opcode::Mul, value, signed_at(inverse(odd, width), width), width);
344    }
345}
346
347/// The inverse of an odd number modulo two to the `width`.
348///
349/// Newton's iteration: an odd number is its own inverse modulo eight, and each step doubles the
350/// bits that are right, so six steps are enough for sixty four.
351fn inverse(odd: i128, width: u32) -> u128 {
352    let odd = odd as u128;
353    let mut inverse = odd;
354    for _ in 0..6 {
355        inverse = inverse.wrapping_mul(2u128.wrapping_sub(odd.wrapping_mul(inverse)));
356    }
357    inverse & mask(width)
358}
359
360/// Those bits read as a signed number of that width.
361fn signed_at(bits: u128, width: u32) -> i128 {
362    let spare = 128 - width;
363    ((bits << spare) as i128) >> spare
364}
365
366/// The low `width` bits set.
367fn mask(width: u32) -> u128 {
368    if width >= 128 { u128::MAX } else { (1u128 << width) - 1 }
369}
370
371/// The division an instruction is, if it is one by a constant at a width this knows.
372fn division(func: &Func, inst: Inst) -> Option<Division> {
373    let data = &func[inst];
374    let (signed, remainder) = match data.opcode {
375        Opcode::SDiv => (true, false),
376        Opcode::UDiv => (false, false),
377        Opcode::SRem => (true, true),
378        Opcode::URem => (false, true),
379        _ => return None,
380    };
381    let &[dividend, by] = &func[data.args] else { return None };
382    let ty = func[dividend].ty;
383    if !ty.is_int() || ty.lanes() != 1 {
384        return None;
385    }
386    let imm = constant(func, by)?;
387    let divisor = if signed { imm.signed(ty) } else { i128::try_from(imm.unsigned()).ok()? };
388    Some(Division {
389        signed,
390        remainder,
391        exact: data.flags.contains(Flags::EXACT),
392        width: ty.bits(),
393        range: range(func, dividend, ty.bits(), signed),
394        divisor,
395    })
396}
397
398/// The immediate a value is, if it is a constant.
399fn constant(func: &Func, value: Value) -> Option<Imm> {
400    let Def::Result { inst, .. } = func[value].def else { return None };
401    if func[inst].opcode != Opcode::IConst {
402        return None;
403    }
404    let Extra::Imm(imm) = func[inst].extra else { return None };
405    Some(func[imm])
406}
407
408/// What the dividend holds, from the widening it came out of if it came out of one.
409///
410/// A value widened with zeroes is never negative, whichever way the division reads it. One widened
411/// with its sign is a narrower signed value to a signed division, and to an unsigned one it is a
412/// value of the whole width, since its top bits are the sign's.
413fn range(func: &Func, value: Value, width: u32, signed: bool) -> Range {
414    let whole = if signed { Range::Signed(width) } else { Range::Unsigned(width) };
415    let Def::Result { inst, .. } = func[value].def else { return whole };
416    let Some(&from) = func[func[inst].args].first() else { return whole };
417    let bits = func[from].ty.bits();
418    if bits == 0 || bits >= width {
419        return whole;
420    }
421    match func[inst].opcode {
422        Opcode::ZExt => Range::Unsigned(bits),
423        Opcode::SExt if signed => Range::Signed(bits),
424        _ => whole,
425    }
426}
427
428/// Puts the program in front of the division and turns the division into its last step.
429fn write(func: &mut Func, inst: Inst, program: &Program) {
430    let Some((&Step::Op(opcode, args, _), before)) = program.steps.split_last() else { return };
431    let mut values = vec![func[func[inst].args][0]];
432    for &step in before {
433        let value = match step {
434            Step::Const(value, bits) => {
435                let ty = Type::int(bits);
436                ahead_const(func, inst, Imm::int(value, ty), ty)
437            }
438            Step::Op(opcode, args, bits) => {
439                let operands: Vec<Value> =
440                    args[..arity(opcode)].iter().map(|&at| values[at]).collect();
441                ahead(func, inst, opcode, &operands, Type::int(bits))
442            }
443        };
444        values.push(value);
445    }
446    let operands: Vec<Value> = args[..arity(opcode)].iter().map(|&at| values[at]).collect();
447    becomes(func, inst, opcode, &operands);
448}
449
450/// How many operands an opcode of a program reads.
451fn arity(opcode: Opcode) -> usize {
452    match opcode {
453        Opcode::Trunc | Opcode::ZExt | Opcode::SExt => 1,
454        _ => 2,
455    }
456}
457
458#[cfg(test)]
459mod tests {
460    use rucc_base::Interner;
461    use rucc_cost::Goal;
462    use rucc_ir::{Builder, Flags, Func, Opcode, Signature, Type, Value};
463
464    use super::{Division, Program, Range, Step, divisions, mask, multiplier, program, signed_at};
465
466    /// What a program gives for one dividend, worked the way the machine works it, with the width
467    /// of every operand checked on the way.
468    fn run(program: &Program, dividend: u128, values: &mut Vec<(u128, u32)>) -> u128 {
469        values.clear();
470        values.push((dividend & mask(program.width), program.width));
471        for &step in &program.steps {
472            let value = match step {
473                Step::Const(value, bits) => (value as u128 & mask(bits), bits),
474                Step::Op(opcode, [lhs, rhs], bits) => {
475                    let (a, from) = values[lhs];
476                    let (b, other) = values[rhs];
477                    let answer = match opcode {
478                        Opcode::ZExt | Opcode::Trunc | Opcode::SExt => {
479                            let right =
480                                if opcode == Opcode::Trunc { from > bits } else { from < bits };
481                            assert!(right, "{opcode:?} from {from} bits to {bits}");
482                            if opcode == Opcode::SExt { signed_at(a, from) as u128 } else { a }
483                        }
484                        _ => {
485                            assert_eq!((from, other), (bits, bits), "{opcode:?} at {bits} bits");
486                            match opcode {
487                                Opcode::Add => a.wrapping_add(b),
488                                Opcode::Sub => a.wrapping_sub(b),
489                                Opcode::Mul => a.wrapping_mul(b),
490                                Opcode::And => a & b,
491                                Opcode::LShr | Opcode::AShr => {
492                                    assert!(b < u128::from(bits), "a shift by {b} at {bits} bits");
493                                    if opcode == Opcode::LShr {
494                                        a >> b
495                                    } else {
496                                        (signed_at(a, bits) >> b) as u128
497                                    }
498                                }
499                                _ => panic!("{opcode:?} is not something a program writes"),
500                            }
501                        }
502                    };
503                    (answer & mask(bits), bits)
504                }
505            };
506            values.push(value);
507        }
508        let (answer, bits) = *values.last().expect("a program has steps");
509        assert_eq!(bits, program.width, "the answer is at the width of the division");
510        answer
511    }
512
513    /// What C says the division gives.
514    fn truth(division: &Division, dividend: u128) -> u128 {
515        let answer = if division.signed {
516            let x = signed_at(dividend, division.width);
517            if division.remainder { x % division.divisor } else { x / division.divisor }
518        } else {
519            let d = division.divisor as u128;
520            (if division.remainder { dividend % d } else { dividend / d }) as i128
521        };
522        answer as u128 & mask(division.width)
523    }
524
525    /// The smallest and the largest value the range holds.
526    fn ends(range: Range) -> (i128, i128) {
527        match range {
528            Range::Unsigned(bits) => (0, (1 << bits) - 1),
529            Range::Signed(bits) => (-(1 << (bits - 1)), (1 << (bits - 1)) - 1),
530        }
531    }
532
533    fn division(
534        signed: bool,
535        remainder: bool,
536        width: u32,
537        range: Range,
538        divisor: i128,
539    ) -> Division {
540        Division { signed, remainder, exact: false, width, range, divisor }
541    }
542
543    /// Whether the rewrite is meant to leave this one as a `div`, which the tests hold it to, so a
544    /// divisor quietly left alone is a failure rather than a pass.
545    fn left(division: &Division) -> bool {
546        let size = division.divisor.unsigned_abs();
547        let (low, high) = ends(division.range);
548        let most = low.unsigned_abs().max(high.unsigned_abs());
549        let bits = match division.range {
550            Range::Unsigned(bits) | Range::Signed(bits) => bits,
551        };
552        let signed_range = matches!(division.range, Range::Signed(_));
553        matches!(division.divisor, 0 | 1)
554            || (division.signed && division.divisor == -1)
555            || (!signed_range && size > most)
556            || (signed_range && !size.is_power_of_two() && (size > most || bits > 32))
557            || (!signed_range && !size.is_power_of_two() && bits > 32)
558    }
559
560    /// Runs the rewrite of one division over these dividends and holds every answer to C's.
561    fn check(
562        division: Division,
563        dividends: impl IntoIterator<Item = i128>,
564        values: &mut Vec<(u128, u32)>,
565    ) {
566        let Some(program) = program(division) else {
567            assert!(left(&division), "{division:?} was left as a div");
568            return;
569        };
570        assert!(!left(&division), "{division:?} was rewritten");
571        for x in dividends {
572            let x = x as u128 & mask(division.width);
573            assert_eq!(run(&program, x, values), truth(&division, x), "{division:?} of {x:#x}");
574        }
575    }
576
577    /// Every multiple of the divisor in the range and the dividend either side of it, and the ends.
578    ///
579    /// The rewrite of a quotient only ever steps up as the dividend does, over the values that are
580    /// not negative and again over the ones that are, and so does C's quotient. Two functions that
581    /// only step up and agree at both ends of every run where one of them is flat agree all the way
582    /// along it, so checking these is checking every dividend.
583    fn edges(range: Range, divisor: i128) -> Vec<i128> {
584        let (low, high) = ends(range);
585        let size = divisor.abs().max(1);
586        let mut all = vec![low, high, -1, 0, 1];
587        let mut at = 0;
588        while at <= high + 1 || -at >= low - 1 {
589            all.extend([at - 1, at, at + 1, -at - 1, -at, -at + 1]);
590            at += size;
591        }
592        all.retain(|&x| (low..=high).contains(&x));
593        all
594    }
595
596    /// xorshift64, so the samples are the same every run.
597    fn random(state: &mut u64) -> u64 {
598        *state ^= *state << 13;
599        *state ^= *state >> 7;
600        *state ^= *state << 17;
601        *state
602    }
603
604    fn both() -> [(bool, bool); 4] {
605        [(false, false), (false, true), (true, false), (true, true)]
606    }
607
608    #[test]
609    fn the_magic_numbers_are_the_ones_gcc_writes() {
610        // `x % 100u` is `imulq $1374389535` and `shrq $37`, thirty two and five.
611        assert_eq!(multiplier(100, 32, 32), (1_374_389_535, 5));
612        // `x / 7u` needs thirty three bits, and gcc writes the low thirty two, `$613566757`.
613        assert_eq!(multiplier(7, 32, 32), ((1 << 32) + 613_566_757, 3));
614        // `x / 7` at `int` is `imulq $-1840700269`, the same bits read as signed, and `sarl $2`.
615        assert_eq!(multiplier(7, 32, 31), (2_454_267_027, 2));
616        // `x / -3` is `imulq $1431655766` and the high half as it is.
617        assert_eq!(multiplier(3, 32, 31), (1_431_655_766, 0));
618        // An `unsigned short` over ten is `imull $52429` and `shrl $19`.
619        assert_eq!(multiplier(10, 16, 16), (52_429, 3));
620    }
621
622    /// Every dividend against every divisor at eight bits, at the width the division is done at
623    /// and from a `char` widened to each wider one.
624    #[test]
625    fn every_eight_bit_division_by_every_divisor_is_right() {
626        let mut values = Vec::new();
627        for (signed, remainder) in both() {
628            for width in [8, 16, 32, 64] {
629                let mut ranges = vec![Range::Unsigned(8)];
630                if signed {
631                    ranges.push(Range::Signed(8));
632                }
633                for range in ranges {
634                    if width == 8
635                        && range != (if signed { Range::Signed(8) } else { Range::Unsigned(8) })
636                    {
637                        continue;
638                    }
639                    let (low, high) = ends(range);
640                    let divisors: Vec<i128> =
641                        if signed { (-300..=300).collect() } else { (0..=300).collect() };
642                    for divisor in divisors {
643                        let divisor = match (width, signed) {
644                            (8, true) => signed_at(divisor as u128 & 0xff, 8),
645                            (8, false) => divisor & 0xff,
646                            _ => divisor,
647                        };
648                        check(
649                            division(signed, remainder, width, range, divisor),
650                            low..=high,
651                            &mut values,
652                        );
653                    }
654                }
655            }
656        }
657    }
658
659    /// Every divisor at sixteen bits, over the dividends that decide the answer, which [`edges`]
660    /// says why is all of them.
661    #[test]
662    fn every_sixteen_bit_quotient_by_every_divisor_is_right() {
663        let mut values = Vec::new();
664        for signed in [false, true] {
665            for width in [16, 32] {
666                let range = if signed { Range::Signed(16) } else { Range::Unsigned(16) };
667                let divisors: Vec<i128> =
668                    if signed { (-32_768..=32_767).collect() } else { (0..=65_535).collect() };
669                for divisor in divisors {
670                    check(
671                        division(signed, false, width, range, divisor),
672                        edges(range, divisor),
673                        &mut values,
674                    );
675                }
676            }
677        }
678        // And a signed division of an `unsigned short`, which is the unsigned one.
679        let range = Range::Unsigned(16);
680        for divisor in -70_000..=70_000 {
681            check(division(true, false, 32, range, divisor), edges(range, divisor), &mut values);
682        }
683    }
684
685    /// The remainder is the quotient multiplied back and taken off, except for a power of two,
686    /// where it is a mask of its own and is checked here over every dividend.
687    #[test]
688    fn every_sixteen_bit_remainder_by_a_power_of_two_is_right() {
689        let mut values = Vec::new();
690        for (signed, remainder) in both() {
691            let range = if signed { Range::Signed(16) } else { Range::Unsigned(16) };
692            let (low, high) = ends(range);
693            for power in 1..16 {
694                for divisor in [1i128 << power, -(1i128 << power)] {
695                    if !signed && divisor < 0 {
696                        continue;
697                    }
698                    check(division(signed, remainder, 16, range, divisor), low..=high, &mut values);
699                }
700            }
701        }
702    }
703
704    /// Thirty two bits, over the ends, the multiples nearest them and a random sample, for every
705    /// small divisor, every power of two and the divisors either side of one, and a random sample
706    /// of the rest. Both at thirty two bits and from a thirty two bit value widened to sixty four.
707    #[test]
708    fn thirty_two_bit_divisions_are_right_at_the_edges_and_on_a_sample() {
709        let mut values = Vec::new();
710        let mut state = 0x9e37_79b9_7f4a_7c15;
711        let mut divisors: Vec<i128> = (-2_000..=2_000).collect();
712        for power in 1..=32 {
713            let at = 1i128 << power;
714            divisors.extend([at - 1, at, at + 1, -at + 1, -at, -at - 1]);
715        }
716        for _ in 0..2_000 {
717            divisors.push(i128::from(random(&mut state) as u32));
718            divisors.push(i128::from(random(&mut state) as i32));
719        }
720        for (signed, remainder) in both() {
721            for (width, range) in [
722                (32, if signed { Range::Signed(32) } else { Range::Unsigned(32) }),
723                (64, Range::Unsigned(32)),
724                (64, if signed { Range::Signed(32) } else { Range::Unsigned(32) }),
725            ] {
726                let (low, high) = ends(range);
727                for &divisor in &divisors {
728                    let divisor = if width == 32 {
729                        let bits = divisor as u128 & mask(32);
730                        if signed { signed_at(bits, 32) } else { bits as i128 }
731                    } else {
732                        divisor
733                    };
734                    if !signed && divisor < 0 {
735                        continue;
736                    }
737                    let size = divisor.abs().max(1);
738                    let mut dividends = vec![low, low + 1, -1, 0, 1, 2, high - 1, high];
739                    for end in [low, high] {
740                        let near = end / size * size;
741                        dividends.extend([near - 1, near, near + 1, near - size, near + size]);
742                    }
743                    for _ in 0..64 {
744                        let x = random(&mut state) as u128 & mask(32);
745                        dividends.push(if matches!(range, Range::Signed(_)) {
746                            signed_at(x, 32)
747                        } else {
748                            x as i128
749                        });
750                    }
751                    dividends.retain(|x| (low..=high).contains(x));
752                    check(
753                        division(signed, remainder, width, range, divisor),
754                        dividends,
755                        &mut values,
756                    );
757                }
758            }
759        }
760    }
761
762    /// A sixty four bit dividend that could be anything needs a product of a hundred and twenty
763    /// eight bits for any divisor that is not a power of two, and is left as a `div`. A power of
764    /// two is not.
765    #[test]
766    fn sixty_four_bits_rewrite_only_a_power_of_two() {
767        let mut values = Vec::new();
768        let mut state = 0x2545_f491_4f6c_dd1d;
769        for (signed, remainder) in both() {
770            let range = if signed { Range::Signed(64) } else { Range::Unsigned(64) };
771            let (low, high) = ends(range);
772            let mut dividends = vec![low, low + 1, -1, 0, 1, high - 1, high];
773            for _ in 0..512 {
774                let x = u128::from(random(&mut state));
775                dividends.push(if signed { signed_at(x, 64) } else { x as i128 });
776            }
777            dividends.retain(|x| (low..=high).contains(x));
778            for power in 1..64 {
779                for divisor in [1i128 << power, -(1i128 << power)] {
780                    if !signed && divisor < 0 {
781                        continue;
782                    }
783                    check(
784                        division(signed, remainder, 64, range, divisor),
785                        dividends.clone(),
786                        &mut values,
787                    );
788                }
789            }
790            for divisor in [3, 7, 10, 1_000_000_007] {
791                check(
792                    division(signed, remainder, 64, range, divisor),
793                    dividends.clone(),
794                    &mut values,
795                );
796            }
797        }
798    }
799
800    /// An exact division is a shift and a multiply by an inverse at any width, checked over
801    /// multiples of the divisor, which are the only dividends it is promised.
802    #[test]
803    fn an_exact_division_is_right_over_every_multiple_it_is_given() {
804        let mut values = Vec::new();
805        let mut state = 0x1234_5678_9abc_def1;
806        for signed in [false, true] {
807            for width in [8, 16, 32, 64] {
808                let range = if signed { Range::Signed(width) } else { Range::Unsigned(width) };
809                let (low, high) = ends(range);
810                for divisor in (-100i128..=100).chain([12, 24, 40, 56, 1 << 20, 3 << 30]) {
811                    if (!signed && divisor < 0) || divisor < low || divisor > high {
812                        continue;
813                    }
814                    let exact =
815                        Division { exact: true, ..division(signed, false, width, range, divisor) };
816                    let Some(program) = program(exact) else {
817                        assert!(
818                            matches!(divisor, 0 | 1) || (signed && divisor == -1),
819                            "{exact:?} was left"
820                        );
821                        continue;
822                    };
823                    let size = divisor.abs();
824                    let mut dividends: Vec<i128> = if width <= 16 {
825                        (low / size..=high / size).map(|times| times * divisor).collect()
826                    } else {
827                        (0..256)
828                            .map(|_| {
829                                let times = signed_at(u128::from(random(&mut state)), 64)
830                                    % (high / size).max(1);
831                                if signed { times * divisor } else { times.abs() * divisor }
832                            })
833                            .collect()
834                    };
835                    dividends.extend([0, divisor, high / size * divisor]);
836                    dividends.retain(|x| (low..=high).contains(x));
837                    for x in dividends {
838                        let x = x as u128 & mask(width);
839                        assert_eq!(
840                            run(&program, x, &mut values),
841                            truth(&exact, x),
842                            "{exact:?} of {x:#x}"
843                        );
844                    }
845                }
846            }
847        }
848    }
849
850    /// A function of one parameter that returns what `body` makes of it.
851    fn one(param: Type, ret: Type, body: impl FnOnce(&mut Builder<'_>, Value) -> Value) -> Func {
852        let mut names = Interner::new();
853        let mut func = Func::new(
854            names.intern("f"),
855            Signature::new().with_params(&[param]).with_returns(&[ret]),
856        );
857        let entry = func.create_block();
858        let x = func.append_param(entry, param);
859        let mut build = Builder::new(&mut func, entry);
860        let answer = body(&mut build, x);
861        build.ret(&[answer]);
862        func
863    }
864
865    /// The opcodes the function is left with, less its constants.
866    fn opcodes(func: &Func) -> Vec<Opcode> {
867        let entry = func.blocks().next().expect("an entry");
868        func.insts(entry).map(|inst| func[inst].opcode).filter(|&op| op != Opcode::IConst).collect()
869    }
870
871    fn divided(
872        opcode: Opcode,
873        divisor: i128,
874        flags: Flags,
875    ) -> impl FnOnce(&mut Builder<'_>, Value) -> Value {
876        move |build, x| {
877            let ty = build.func()[x].ty;
878            let by = build.iconst(ty, divisor);
879            build.binary(opcode, x, by, flags)
880        }
881    }
882
883    #[test]
884    fn an_unsigned_division_by_seven_is_a_multiply_an_add_and_two_shifts() {
885        let i32 = Type::int(32);
886        let mut func = one(i32, i32, divided(Opcode::UDiv, 7, Flags::NONE));
887        divisions(&mut func, Goal::Speed);
888        let want = [
889            Opcode::ZExt,
890            Opcode::Mul,
891            Opcode::LShr,
892            Opcode::Add,
893            Opcode::LShr,
894            Opcode::Trunc,
895            Opcode::Return,
896        ];
897        assert_eq!(opcodes(&func), want);
898    }
899
900    #[test]
901    fn a_signed_remainder_is_the_quotient_multiplied_back() {
902        let i32 = Type::int(32);
903        let mut func = one(i32, i32, divided(Opcode::SRem, 7, Flags::NONE));
904        divisions(&mut func, Goal::Speed);
905        let want = [
906            Opcode::SExt,
907            Opcode::Mul,
908            Opcode::AShr,
909            Opcode::Trunc,
910            Opcode::AShr,
911            Opcode::Sub,
912            Opcode::Mul,
913            Opcode::Sub,
914            Opcode::Return,
915        ];
916        assert_eq!(opcodes(&func), want);
917    }
918
919    /// `(int)x / 10` for an `unsigned short x`, where the widening says the dividend is sixteen
920    /// bits and never negative, so the signed division is the unsigned one with the small number.
921    #[test]
922    fn a_widened_unsigned_short_takes_the_short_number_and_no_correction() {
923        let (i16, i32) = (Type::int(16), Type::int(32));
924        let mut func = one(i16, i32, |build, x| {
925            let wide = build.unary(Opcode::ZExt, x, i32);
926            divided(Opcode::SDiv, 10, Flags::NONE)(build, wide)
927        });
928        divisions(&mut func, Goal::Speed);
929        let want =
930            [Opcode::ZExt, Opcode::ZExt, Opcode::Mul, Opcode::LShr, Opcode::Trunc, Opcode::Return];
931        assert_eq!(opcodes(&func), want);
932    }
933
934    /// `(p - q)` over a twelve byte structure, which the front end marks exact.
935    #[test]
936    fn an_exact_division_is_a_shift_and_a_multiply() {
937        let i64 = Type::int(64);
938        let mut func = one(i64, i64, divided(Opcode::SDiv, 12, Flags::EXACT));
939        divisions(&mut func, Goal::Speed);
940        assert_eq!(opcodes(&func), [Opcode::AShr, Opcode::Mul, Opcode::Return]);
941    }
942
943    #[test]
944    fn size_a_variable_divisor_and_a_wide_dividend_keep_the_div() {
945        let i32 = Type::int(32);
946        let mut func = one(i32, i32, divided(Opcode::UDiv, 7, Flags::NONE));
947        divisions(&mut func, Goal::Size);
948        assert_eq!(opcodes(&func), [Opcode::UDiv, Opcode::Return]);
949
950        let mut func = one(i32, i32, |build, x| build.binary(Opcode::SDiv, x, x, Flags::NONE));
951        divisions(&mut func, Goal::Speed);
952        assert_eq!(opcodes(&func), [Opcode::SDiv, Opcode::Return]);
953
954        let i64 = Type::int(64);
955        let mut func = one(i64, i64, divided(Opcode::UDiv, 10, Flags::NONE));
956        divisions(&mut func, Goal::Speed);
957        assert_eq!(opcodes(&func), [Opcode::UDiv, Opcode::Return]);
958    }
959}