有两种众所周知的方法可以在 x86 上将整数寄存器设置为零值。
任何一个
mov reg, 0
或者
xor reg, reg
有一种观点认为第二种变体更好,因为值 0 没有存储在代码中,并且节省了生成的机器代码的几个字节。这绝对是好的——使用更少的指令缓存,这有时可以加快代码执行速度。许多编译器产生这样的代码。
然而,在 xor 指令和任何更改同一寄存器的早期指令之间存在正式的指令间依赖关系。由于存在依赖性,后一条指令需要等到前一条指令完成,这可能会减少处理器单元的负载并损害性能。
add reg, 17
;do something else with reg here
xor reg, reg
很明显,无论初始寄存器值如何,异或的结果都将完全相同。但它的处理器能够识别这一点吗?
我在 VC++7 中尝试了以下测试:
const int Count = 10 * 1000 * 1000 * 1000;
int _tmain(int argc, _TCHAR* argv[])
{
int i;
DWORD start = GetTickCount();
for( i = 0; i < Count ; i++ ) {
__asm {
mov eax, 10
xor eax, eax
};
}
DWORD diff = GetTickCount() - start;
start = GetTickCount();
for( i = 0; i < Count ; i++ ) {
__asm {
mov eax, 10
mov eax, 0
};
}
diff = GetTickCount() - start;
return 0;
}
关闭优化后,两个循环的时间完全相同。这是否合理地证明处理器认识到指令不依赖xor reg, reg
于先前的mov eax, 0
指令?有什么更好的测试来检查这一点?