https://gcc.gnu.org/bugzilla/show_bug.cgi?id=84759
Bug ID: 84759
Summary: Calculation of quotient and remainder with constant
denominator uses __umoddi3+__udivdi3 instead of
__udivmoddi4
Product: gcc
Version: 7.3.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: target
Assignee: unassigned at gcc dot gnu.org
Reporter: b7.10110111 at gmail dot com
Target Milestone: ---
Starting from GCC 7, code calculating both quotient and remainder of a loong
division calls a single __udivmodti4. But this only happens for general values
of denominator, while for specific constants for some reason GCC still
generates calls to __umodti3 and __udivti3. See the following code (the picture
is the same for x86 and amd64 targets):
#ifdef __SIZEOF_INT128__
typedef __uint128_t Longer;
#else
typedef unsigned long long Longer;
#endif
typedef unsigned long Shorter;
Shorter divmod(Longer numerator, Shorter denominator, Shorter* remainder)
{
*remainder = numerator%denominator;
return numerator/denominator;
}
Shorter divmodConst(Longer numerator, Shorter* remainder)
{
const Shorter denominator = 100;
*remainder = numerator%denominator;
return numerator/denominator;
}
Here divmod is optimized, while divmodConst appears not optimized:
divmod:
sub esp, 28
xor edx, edx
mov eax, DWORD PTR [esp+40]
lea ecx, [esp+8]
sub esp, 12
push ecx
push edx
push eax
push DWORD PTR [esp+60]
push DWORD PTR [esp+60]
call __udivmoddi4
mov edx, DWORD PTR [esp+76]
mov ecx, DWORD PTR [esp+40]
mov DWORD PTR [edx], ecx
add esp, 60
ret
divmodConst:
push edi
push esi
sub esp, 4
mov esi, DWORD PTR [esp+16]
mov edi, DWORD PTR [esp+20]
push 0
push 100
push edi
push esi
call __umoddi3
add esp, 16
mov edx, DWORD PTR [esp+24]
mov DWORD PTR [edx], eax
push 0
push 100
push edi
push esi
call __udivdi3
add esp, 20
pop esi
pop edi
ret