我正在查看由GCC-4.8为x86_64生成的代码,想知道是否有更好(更快)的方法来计算三个值中的最小值。

这是Python的collections模块的摘录,该模块计算mrightindex+1leftindex的最小值:

    ssize_t m = n;
    if (m > rightindex + 1)
        m = rightindex + 1;
    if (m > leftindex)
        m = leftindex;

GCC使用CMOV生成与序列相关的代码:
leaq    1(%rbp), %rdx
cmpq    %rsi, %rdx
cmovg   %rsi, %rdx
cmpq    %rbx, %rdx
cmovg   %rbx, %rdx

是否有更快的代码可以通过消除数据依赖项来利用处理器无序并行执行的优势?我想知道是否有已知的技巧可以在不使用条件或谓词指令的情况下计算多个值的最小值。我还想知道是否存在一些饱和算术内在函数在这种情况下会有所帮助。

编辑:
  • 如图所示,代码使用有符号算术,但是无符号算术答案也将有所帮助。
  • 我问了三个最小值,但也对n最小值(n很小)感兴趣。
  • Linus关于CMOV的警告:http://ondioline.org/mail/cmov-a-bad-idea-on-out-of-order-cpus
  • 最佳答案

    至少两个无符号数具有经典的解决方案:

    ; eax = min(eax, ebx), ecx - scratch register.
    .min2:
        sub     ebx, eax
        sbb     ecx, ecx
        and     ecx, ebx
        add     eax, ecx
    

    这种方法可能比使用cmov的解决方案要快,但是为了获得更高的速度,指令必须与其他指令分开才能并行执行。

    可以为三个数字实现此方法:
    ; eax = min(eax, ebx, edx), ecx - scratch register.
    .min3:
        sub     ebx, eax
        sbb     ecx, ecx
        and     ecx, ebx
        add     eax, ecx
    
        sub     edx, eax
        sbb     ecx, ecx
        and     ecx, edx
        add     eax, ecx
    

    另一种尝试是使用条件跳转来测试变体。对于现代处理器,它可能甚至更快,尤其是在高度可预测的情况下:
    .min3:
        cmp     eax, ebx
        jle     @f
        mov     eax, ebx
    @@:
        cmp     eax, edx
        jle     @f
        mov     eax, edx
    @@:
    

    10-08 09:44