CMOVcc是否被视为分支指令?

JL2*_*210 -1 assembly x86-64 cpu-architecture micro-optimization branch-prediction

我有memchr我要使非分支的这段代码:

.globl memchr
memchr:
        mov %rdx, %rcx
        mov %sil, %al
        cld
        repne scasb
        lea -1(%rdi), %rax
        test %rcx, %rcx
        cmove %rcx, %rax
        ret
Run Code Online (Sandbox Code Playgroud)

我不确定是否cmove是分支指令。是吗?如果是这样,如何重新排列我的代码,使其不分支?

Pet*_*des 12

不,这不是分支,这才是重点cmovcc

这是一个ALU选择,它对两个输入都具有数据依赖性,而不是控制依赖性。(使用内存源时,它无条件加载内存源,这与ARM谓词的加载指令真正被NOPed不同。因此,您不能将其与可能不良的指针一起用于无分支范围或NULL检查。这也许是最清楚的说明,它肯定是不是分支。)

但是无论如何,它不是以任何方式预测或推测的。就CPU调度程序而言,它就像一条adc指令:2个整数输入+ FLAGS和1个整数输出。(与adc/的唯一区别sbb是它不编写FLAGS。当然,它在具有不同内部结构的执行单元上运行)。

这是好是坏完全取决于用例。另请参见gcc优化标志-O3使代码比-O2慢,以了解更多有关cmov上升/下降的信息


请注意,这repne scasb并不快。 “快速字符串”仅适用于rep stos / movs。

repne scasb大约每时钟周期1个计数在现代的CPU,即通常大约16倍不是一个简单的SSE2糟糕的运行pcmpeqb/ pmovmskb/ test+jnz循环。通过巧妙的优化,您甚至可以更快地运行,每个时钟最多2个向量,从而使加载端口饱和。

(例如memchrpcmpeqb对于整个缓存行,请参见glibc的ORing 结果,以一起馈送一个pmovmskbIIRC。然后返回并找出实际命中的位置。)

repne scasb也有启动开销,但是微代码分支与常规分支不同:它不是在Intel CPU上分支预测的。因此,这不会造成错误的预测,但是对于除了很小的缓冲区之外的任何东西来说,都是对性能的完全浪费。

SSE2是x86-64和有效未对齐负载的基线,+ pmovmskb使它成为不费吹灰之力的memchr地方,您可以在其中检查长度> = 16,以避免进入未映射的页面。

快速动感

  • *“ **请注意`repne scasb`并不快。**” *-我知道。我打算稍后再用更快的速度替换它,但是现在它很小并且可以使用。 (2认同)