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