我正在尝试编写一个(非常)短的汇编例程,它测试两个dwords的相等性并返回一个布尔值(1 = true,0 = false)。到目前为止,我已经提出了三种方法,其中一种方法使用了LAHF,而某些x86_64处理器显然不支持LAHF,所以不幸的是,问题就出现了。
第一版是:
mov eax, [esp + 8]
cmp b, [esp + 4]
mov eax, 1
jnz jpt
mov eax, 0
jpt: ret
和第二版是:
mov eax, [ebp + 8]
cmp b, [ebp + 4]
pushf ; Get lowest word of the flags register
pop ax
and eax, 0x0040 ; Extract the zero flag
shr eax, 6 ; eax is now true(1) if arg1 == arg2
ret
版本1有一个额外的分支指令,但版本2有一个额外的推送和一个额外的pop指令。您希望哪一个最快?为什么?这取决于是否采取/预测分支?
答案 0 :(得分:2)
两者版本都不好。一个随机分支需要很长时间才能执行,因为它无法预测,lahf只是一个no no,因为部分寄存器写入。但是,当然,在汇编程序中编写一个相等的测试完全是胡说八道,因为函数开销将是内联等效指令的倍数,所以我在这里:
mov eax, [ebp + 8]
cmp eax, [ebp + 4]
setz al ;set al to 1 if equal
movzx eax,al ;convert to dword
ret
答案 1 :(得分:0)
在我需要优化的应用程序之前,我发现了这些瓶颈,它们肯定表明你已经碰壁,无法真正进一步优化。
最好的行动方案是选择不同的算法或数据布局,一个适合平台的模式和访问模式比现有模式更好。这可能是你能做的最重要的事情。
然而,由于截止日期或其他限制有时也是不可能的,所以你需要对它有创意,这可能意味着使用SIMD操作一次测试多个元素(例如,使用_mm_cmpeq_epi32内在函数)比较4个元素)。如果你打算对它进行分支,你可以将16个元素,按位或掩码一起比较并在其上进行分支(然后在分支内选择正确的数据)。
这主要是在分支机构非常昂贵的平台上有利,而在IA-32/64上则不是这样(例如分支机构便宜)。
另请注意,由于无序执行(OOE),英特尔平台随后可以使用;你正在使用的分析器很可能是在一个或多或少的随机位置上报告停顿,因为处理器需要等待从缓存或RAM中读取数据。
如果碰巧遇到这种情况,请确保优化算法以使其更适合缓存(例如,确定缓存行中适合的项目数量,减小数据结构的大小等)。 p>