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

Reply via email to