On 6/29/2026 12:14 AM, liuhongt wrote:
When op1's range is [N, N + 1] and one of N or N + 1 is a power of
two, split a TRUNC_DIV_EXPR into two divisions by constants selected
by a compare:
op0 / op1 -> op1 == N ? op0 / N : op0 / (N + 1)
Each arm divides by a constant, so expansion strength-reduces it (a
shift on the power-of-two arm) and the divide instruction is avoided.
This grows code, so gate it on optimize_bb_for_speed_p.
Bootstrapped and regtested on x86_64-pc-linux-gnu{-m32,}.
Ok for trunk?
PR middle-end/125708
gcc/ChangeLog:
* vr-values.cc
(simplify_using_ranges::simplify_div_or_mod_using_ranges):
Compute op1's upper bound for all codes and add the
near-power-of-two TRUNC_DIV_EXPR split, guarded on
optimize_bb_for_speed_p.
gcc/testsuite/ChangeLog:
* gcc.dg/tree-ssa/pr125708-1.c: New test.
* gcc.target/i386/pr125708-2.c: New test.
Note that you're introducing a conditional branch into the mix as well.
If it's a poorly predicted branch, then you could end up burning more
cycles on the branch mispredict than the division would have taken.
I'd kind of want to get a better sense of whether or not we're actually
making an improvement here.
If we're selecting across 1/2 for the divisor and the dividend is a
suitable type, then this really becomes a conditional right shift by 1,
right? That seems likely to have a generally profitable synthesis. But
an arbitary n, n+1 where one of them is a power of two isn't as obvious
to me.
jeff