On 5/2/2026 11:34 PM, [email protected] wrote:
> From: MITSUNARI Shigeo <[email protected]>
>
> For 32-bit unsigned integer division by constants that require 33-bit
> magic multipliers (mh != 0, IsAdd case), use a pre-shifted 64-bit magic
> constant and a single 64-bit high-part multiply instead of the traditional
> sub/shift/add sequence.
>
> The 33-bit magic constant (2^32 + ml) is pre-shifted by (32 - post_shift)
> bits, allowing the quotient to be obtained directly from the upper 64 bits
> of a 64x64 multiplication, then truncated to 32 bits.
>
> This reduces the instruction count for divisions like x/7 from 7
> instructions to 4 on x86_64.
>
> Before (x / 7):
>      movl    %edi, %eax
>      imulq   $613566757, %rax, %rax
>      shrq    $32, %rax
>      subl    %eax, %edi
>      shrl    %edi
>      addl    %edi, %eax
>      shrl    $2, %eax
>
> After:
>      movabsq $2635249153617166336, %rcx
>      movl    %edi, %eax
>      mulq    %rcx
>      movl    %edx, %eax
>
> gcc/ChangeLog:
>
> * expmed.cc (expand_divmod): For 32-bit unsigned division with
> 33-bit magic on 64-bit targets, use pre-shifted 64-bit multiply.
> ---
>   gcc/expmed.cc | 86 ++++++++++++++++++++++++++++++++++++---------------
>   1 file changed, 61 insertions(+), 25 deletions(-)
>
> diff --git a/gcc/expmed.cc b/gcc/expmed.cc
> index d57ea78d6b1..443ac09caeb 100644
> --- a/gcc/expmed.cc
> +++ b/gcc/expmed.cc
> @@ -4523,31 +4523,67 @@ expand_divmod (int rem_flag, enum tree_code code, 
> machine_mode mode,
>   
> +                         bool did_64bit_opt = false;
> +
> +                         /* For 32-bit unsigned division on 64-bit targets,
> +                            pre-shift the 33-bit magic constant (2^32 + ml)
> +                            into a 64-bit value and use a single 64-bit
> +                            high-part multiply instead of the sub/shift/add
> +                            sequence.
> +                            Pre-shift by (32 - post_shift) so that the high
> +                            64 bits of (x64 * magic) give the quotient
> +                            directly.
> +                            Note: mh!=0 implies pre_shift==0.  */
> +                         if (size == 32 && post_shift >= 1)
So rather than a magic "32" constant is there something better we can 
test?  If I understand everything correctly, this would work any time we 
have a high part multiply irrespective of the underlying types.  One 
could imagine an 8 bit target with a mulh insn that gives the upper 8 
bits of the 16 bit multiply result.

Rather than calling this "did_64bit_opt", perhaps "did_mulh_opt" or 
something else that is agnostic of the actual sizes.

> +                           {
> +                             scalar_int_mode wide_mode
> +                               = GET_MODE_WIDER_MODE (int_mode).require ();
> +                             unsigned HOST_WIDE_INT magic
> +                               = (ml + (HOST_WIDE_INT_1U << 32))
> +                                 << (32 - post_shift);
Isn't this going to fail on a host where HOST_WIDE_INT is just 32 bits?  
I believe that's the case for windows.  You can't shift a 32 bit object 
by 32 bit positions.

What would happen if we didn't find a wider mode?  Isn't that going to 
fail poorly (internal error)?  What happens on targets that do not have 
a high part multiply?



I'd really like to see a testcase included as well.  I don't mind if 
it's specific to a particular target like x86_64, I just want to have 
some degree of coverage on a commonly tested target.

I think much of this is sound, it's really more a matter of getting 
details nailed down.

On a non-technical note, you need to explicitly contribute this under 
the DCO terms or get a copyright assignment on file with the FSF before 
we can include anything.

jeff

Reply via email to