Expand description
A division by a constant, as a multiply by its reciprocal and a shift.
Design: spec/optimizer/19-reassociation-and-arithmetic.md section 19.5, which hands this to
the back end.
A div takes twenty to forty cycles and a multiply takes three, so every compiler turns a
division by a constant into a multiply by a number close to its reciprocal, scaled up by a power
of two, and a shift that takes the scale back out. The number is what Granlund and Montgomery
call the magic number, and multiplier works it out the way choose_multiplier at
gcc/expmed.cc:3728 does.
§Why the product is sixty four bits wide
gcc writes the multiply as a high multiply at the width of the division, which is an instruction the IR does not have. What it has is an ordinary multiply at sixty four bits, and a dividend of at most thirty two bits times a magic number of at most thirty three fits in one. So the dividend is widened, multiplied, and shifted by the width and the post shift at once, and the answer is the low half of that. It is also one step shorter than gcc’s when the magic number needs thirty three bits: gcc cannot hold the sum of the dividend and the high half in thirty two bits and halves the difference first, and here the sum fits.
A division at sixty four bits needs the high half of a hundred and twenty eight bit product, so
it stays a div until the IR has a high multiply (#309). A power of two and an exact division
need no product and are done at every width.
§What the dividend is known to hold
C divides at int at least, so an unsigned short divided by ten is an int division of a
value widened from sixteen bits. The widening says the value fits in sixteen bits, a magic
number for sixteen bits is smaller and never needs the extra add, and a signed division of a
value that cannot be negative is the unsigned one. Range is that, read off the instruction
the dividend comes from.
§What is left alone
Everything when the goal is size, where the div is shorter, which is what gcc does at -Os.
A divisor of zero, one or minus one, which is undefined or which the optimizer has already
answered. A divisor larger than anything the dividend can hold, where the quotient is zero or
one and a compare is the right code, which is rare enough to wait.
§How it is checked
program writes the rewrite as a short list of Steps before anything goes into the
function, and the tests run that same list on numbers. At eight bits that is every dividend
against every divisor. At sixteen it is every divisor, over the dividends either side of each of
its multiples, which is a proof rather than a sample: the rewrite and the division it replaces
only ever move at those points, so agreeing there is agreeing everywhere. cargo xtask divide
runs what the compiler makes of the same divisions against gcc.
Structs§
- Division
- One division or remainder by a constant, as far as the rewrite needs to know it.
- Program
- A rewrite, in the order it is written.
Enums§
Functions§
- divisions
- Rewrites every division and remainder by a constant that
programhas an answer for. - multiplier
- The magic number for dividing by
divisora value ofbitsbits whose topbits - precisionbits are known to be clear, and the shift that goes after the multiply. - program
- The rewrite for one division, or
Nonewhere thedivis left.