以下所有说明都做同样的事情:设置%eax为零.哪种方式最佳(需要最少的机器周期)?
xorl %eax, %eax
mov $0, %eax
andl $0, %eax
Run Code Online (Sandbox Code Playgroud) 在MSVC 2013中编译以下代码,64位版本构建,/O2优化:
while (*s == ' ' || *s == ',' || *s == '\r' || *s == '\n') {
++s;
}
Run Code Online (Sandbox Code Playgroud)
我得到了以下代码 - 使用64位寄存器作为带有bt(位测试)指令的查找表,它具有非常酷的优化.
mov rcx, 17596481020928 ; 0000100100002400H
npad 5
$LL82@myFunc:
movzx eax, BYTE PTR [rsi]
cmp al, 44 ; 0000002cH
ja SHORT $LN81@myFunc
movsx rax, al
bt rcx, rax
jae SHORT $LN81@myFunc
inc rsi
jmp SHORT $LL82@myFunc
$LN81@myFunc:
; code after loop...
Run Code Online (Sandbox Code Playgroud)
但我的问题是:movsx rax, al第一个分支后的目的是什么?
首先,我们从字符串中加载一个字节rax并对其进行零扩展:
movzx eax, BYTE …Run Code Online (Sandbox Code Playgroud) clang能够将许多小整数的==比较转换为一条大SIMD指令,这让我很感兴趣,但是后来我注意到了一些奇怪的事情。当我进行7次比较时,Clang生成了“更差”的代码(在我的业余评估中),而当我进行8次比较时,Clang生成了该代码。
bool f1(short x){
return (x==-1) | (x == 150) |
(x==5) | (x==64) |
(x==15) | (x==223) |
(x==42) | (x==47);
}
bool f2(short x){
return (x==-1) | (x == 150) |
(x==5) | (x==64) |
(x==15) | (x==223) |
(x==42);
}
Run Code Online (Sandbox Code Playgroud)
我的问题是这是一个很小的性能错误,或者clang有一个很好的理由不想引入虚拟比较(即假装与7个值之一进行额外的比较),并在代码中使用一个更多的常量来实现它。
Godbolt链接在这里:
# clang(trunk) -O2 -march=haswell
f1(short):
vmovd xmm0, edi
vpbroadcastw xmm0, xmm0 # set1(x)
vpcmpeqw xmm0, xmm0, xmmword ptr [rip + .LCPI0_0] # 16 bytes = 8 shorts
vpacksswb xmm0, xmm0, xmm0
vpmovmskb eax, …Run Code Online (Sandbox Code Playgroud)