> -----Original Message-----
> From: Jeffrey Law <[email protected]>
> Sent: Tuesday, June 30, 2026 4:01 AM
> To: Liu, Hongtao <[email protected]>; [email protected]
> Cc: [email protected]
> Subject: Re: [PATCH] tree-ssa: Split divisions by near power-of-two ranges [PR
> middle-end/125708]
> 
> 
> 
> 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 assume COND_EXPR op1 == N ? op0 / N : op0 / (N + 1) will be expanded into a 
conditional move at rtl w/o branch, maybe I should also add 
can_conditionally_move_p to guard the optimization?

> 
> 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.

Yes, for the original case in the PR(divisor is 2 - bool), it's a conditional 
shift which should be profitable.

For an arbitrary, when divisor is pow2 +- 1, since divisor now is constant, 
division by any nonzero compile-time constant is always strength-reduced with 
magic multiply.
So, it's *shift + magic multiply + compare + conditional move* vs. *original 
division*
.i.e

int
foo (int a, bool b)
{
  return a / ((1 << 20) - b);
}

Before optimization

       mov     eax, edi
        movzx   esi, sil
        mov     ecx, 1048576
        sub     ecx, esi
        cdq
        idiv    ecx

After optimization

        movslq  %edi, %rax
        movl    %edi, %edx
        imulq   $-2147481599, %rax, %rax
        sarl    $31, %edx
        shrq    $32, %rax
        addl    %edi, %eax
        sarl    $19, %eax
        subl    %edx, %eax
        testl   %edi, %edi
        leal    1048575(%rdi), %edx
        cmovns  %edi, %edx
        sarl    $20, %edx
        testb   %sil, %sil
        cmove   %edx, %eax
        ret

Since division is strength-reduced to magic multiply(so the multiplication 
sequence should be cheaper the division), the extra cost here is *shift + 
compare + conditional move*, I think it's profitable(guarded by 
optimize_bb_for_speed_p).

> 
> jeff

Reply via email to