From: MITSUNARI Shigeo <[email protected]>

Thanks, and no rush.

On the generalization point: the v8 patch is not tied to a single
size.  The helper derives the wide mode with GET_MODE_2XWIDER_MODE and
guards it with BITS_PER_WORD and HOST_BITS_PER_WIDE_INT, so it fires
for any integer mode whose double-width mode fits in a word and whose
magic constant fits in a HOST_WIDE_INT.

Concretely, with a compiler built from v8, x / 7 improves for:

- x86-64: uint32_t, uint16_t and uint8_t.

- i386 (-m32): uint16_t and uint8_t.  uint32_t is unchanged there,
  because its double-width mode is DImode (64 bits) while
  BITS_PER_WORD is 32, so the classic sub/shift/add sequence is kept.

As one example, for

  uint16_t udiv7 (uint16_t x) { return x / 7; }

x86-64 -O2 goes from 7 insns to 3:

  before                             after
    movzwl  %di, %eax                  movzwl  %di, %eax
    imull   $9363, %eax, %eax          imulq   $613572608, %rax, %rax
    shrl    $16, %eax                  shrq    $32, %rax
    subl    %eax, %edi                 ret
    shrw    %di
    addl    %edi, %eax
    shrw    $2, %ax
    ret

and the same function on i386 -O2 (-m32) goes from 8 insns to 4:

  before                             after
    movzwl  4(%esp), %edx              movzwl  4(%esp), %eax
    movl    %edx, %eax                 movl    $613572608, %ecx
    imull   $9363, %edx, %edx          mull    %ecx
    shrl    $16, %edx                  movl    %edx, %eax
    subl    %edx, %eax                 ret
    shrw    %ax
    addl    %edx, %eax
    shrw    $2, %ax
    ret

I verified the new sequences over all inputs, for every 8-bit divisor
and for 16-bit divisors up to 2000.  No divisor regresses.

Thanks,
Shigeo

Reply via email to