https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82261

--- Comment #5 from Paweł Bylica <chfast at gmail dot com> ---
The form that is well defined for a shift count of 0 is not turned into
SHLD/SHRD either. SHLD/SHRD with a count of 0 leave the destination unchanged,
which is the s == 0 result here:

unsigned long fshl(unsigned long hi, unsigned long lo, unsigned s)
{
  return s == 0 ? hi : (hi << s) | (lo >> (64 - s));
}

unsigned long fshr(unsigned long hi, unsigned long lo, unsigned s)
{
  return s == 0 ? lo : (lo >> s) | (hi << (64 - s));
}

GCC 16.2 and trunk -O2 (fshr is the same with the shifts swapped):

fshl:
        movl    %edx, %ecx
        movq    %rdi, %rax
        negl    %ecx
        shrq    %cl, %rsi
        movl    %edx, %ecx
        salq    %cl, %rax
        orq     %rax, %rsi
        testl   %edx, %edx
        movq    %rdi, %rax
        cmovne  %rsi, %rax
        ret

GCC 15.2 used SHLD/SHRD, but kept the branch on s == 0:

fshl:
        movq    %rdi, %rax
        testl   %edx, %edx
        je      .L2
        movl    %edx, %ecx
        shldq   %cl, %rsi, %rax
.L2:
        ret

Clang:

fshl:
        movl    %edx, %ecx
        movq    %rdi, %rax
        shldq   %cl, %rsi, %rax
        retq

intx (a multi-precision integer library) writes its funnel shifts this way.

Reply via email to