GCC优化器发出奇怪的条件跳转,为什么?

我正在研究代码中的关键功能的反汇编。 它大约需要90%的表现。 这并不令人惊讶,因为内联后它是一个非常大的功能,所以它最终会做很多事情。

但是,我注意到有一些程序集我不明白这样做的理由:

test rsi, rsi
je setecx0
cmp rsi, 0x1
je setecx1
cmp rsi, 0x2
je setecx2
cmp rsi, 0x3
je setecx3
cmp rsi, 0x4
je setecx4
mov ecx, 0x5
; Code that doesn't use ECX yet
ecxnotzero:
cmp r9, rsi
je epilog
ecxzero:
; Logical code below

epilog:
; Standard cleanup stuff
ret;
; 5kB more code
; 36 code fragments at the end of the function:
NOP WORD PTR[rax+rax*1+0x0] ; 16 byte alignment of the next label
setecx0:
xor ECX,ECX
jmp ecxzero
; similar functions, but with other labels
NOP WORD PTR[rax+rax*1+0x0] ; 16 byte alignment of the next label
setecx4:
mov ecx, 0x4
JMP ecxnotzero
; Similar code with other "return" addresses 
NOP WORD PTR[rax+rax*1+0x0]
setecx1:
mov ecx, 0x1
JMP ecxnotzero
; Similar code with other "return" addresses 
setecx3:
mov ecx, 0x3
JMP ecxnotzero
setecx3:
mov ecx, 0x2
JMP ecxnotzero

我很惊讶的原因是,这似乎是一个非常复杂的将ECX设置为max(RSI,5) 。 另外,我不明白为什么海湾合作委员会将这些片段中的大约三十个放在函数的末尾 - 这些跳跃不能自由,而且它们当然不是本地的。 CMOV不会更有意义吗?

这只是一个更为理智的案例。 我还有以下代码:

cmp rsi, QWORD PTR[rbp-0x70]
je fragment
vzeroupper
; Code to be skipped
skipped:
; cleanup
jmp epilog
; amongst the other fragments
nop WORD PTR[]
fragment:
vzeroupper
jmp skipped

现在我无法理解这里的重点。 根据条件,我们执行vzerouppervzeroupper (!),但在第二种情况下,我们使用两个跳转来跳过一些代码。 为什么使用这样一个片段,而不是更合乎逻辑的方式:

cmp rsi, QWORD PTR[rbp-0x70]
vzeroupper ; Unconditionally
je skipped ; vzeroupper doesn't touch ZF
; Code to be skipped
skipped:

(我并不感到惊讶,因为epilog接近这个函数的开头,原始的C ++代码有一个7路开关,每个开关调用不同的方法,并且看起来epilog放置在第一个和第二个内联之间方法,函数末尾的其他片段似乎来自其他6种方法)

我们用-O3 -march=haswell -funroll-loops -fPIC -mfma进行编译,对于x64使用GCC 4.9.2-10(Debian)。

[编辑]从-fverbose-asm选项,对这些片段的GCC注释是字面上# i,

链接地址: http://www.djcxy.com/p/15233.html

上一篇: GCC optimizer emits strange conditional jumps, why?

下一篇: (VC++) Runtime Check for Uninitialized Variables: How is the test Implemented?