首页 > 解决方案 > CMOVcc 是否被视为分支指令?

问题描述

我有这段memchr代码,我试图使其不分支:

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

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

标签: assemblyx86-64cpu-architecturemicro-optimizationbranch-prediction

解决方案


不,这不是一个分支,这就是cmovcc.

这是一个 ALU 选择,它对两个输入都有数据依赖,而不是控制依赖。(对于内存源,它无条件加载内存源,这与真正 NOPed 的 ARM 谓词加载指令不同。因此,您不能将它与可能错误的指针一起用于无分支边界或 NULL 检查。这可能是最清楚的说明,它绝对是不是一个分支。)

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

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


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

repne scasb在现代 CPU 上每个时钟周期运行大约 1 个计数,即通常比简单的 SSE2 // 循环差大约pcmpeqb16倍pmovmskbtest+jnz通过巧妙的优化,您可以走得更快,每个时钟最多 2 个向量使负载端口饱和。

(例如,请参阅 glibc 的memchrORingpcmpeqb结果,将整个缓存行放在一起以提供一个pmovmskbIIRC。然后返回并找出实际命中的位置。)

repne scasb也有启动开销,但微码分支与常规分支不同:它不是 Intel CPU 上的分支预测。所以这不能错误预测,但是对于除了非常小的缓冲区之外的任何东西的性能来说都是垃圾。

SSE2 是 x86-64 和高效未对齐负载的基线 +pmovmskb使其成为memchr您可以检查长度 >= 16 以避免进入未映射页面的明智之举。

快速 strlen


推荐阅读