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