【发布时间】:2024-01-30 00:50:01
【问题描述】:
我正在运行 x86 处理器,但我相信我的问题很笼统。我很好奇 CMP + JE 序列与单个 MUL 操作所消耗的时钟周期的理论差异。
在 C 伪代码中:
unsigned foo = 1; /* must be 0 or 1 */
unsigned num = 0;
/* Method 1: CMP + JE*/
if(foo == 1){
num = 5;
}
/* Method 2: MUL */
num = foo*5; /* num = 0 if foo = 0 */
不要对伪代码看得太深,它纯粹是为了阐明这两种方法背后的数学逻辑。
我实际比较的是以下两个指令序列:
方法一:CMP + JE
MOV EAX, 1 ; FOO = 1 here, but can be set to 0
MOV EBX, 0 ; NUM = 0
CMP EAX, 1 ; if(foo == 1)
JE SUCCESS ; enter branch
JMP FINISH ; end program
SUCCESS:
MOV EBX, 5 ; num = 5
FINISH:
方法2:MUL
MOV EAX, 1 ; FOO = 1 here, but can be set to 0
MOV ECX, EAX ; save copy of FOO to ECX
MUL ECX, 5 ; result = foo*5
MOV EBX, ECX ; num = result = foo*5
似乎单个 MUL(总共 4 条指令)比 CMP + JE(总共 6 条指令)更有效,但是指令消耗的时钟周期平均 - 即完成与任何其他指令相同的指令所需的时钟周期数?
如果实际消耗的时钟周期取决于机器,单个MUL 是否通常比大多数处理器上的分支方法更快,因为它需要更少的总指令?
【问题讨论】:
-
在这种情况下,
CMOV可能比CMP + JE或MUL更有效。 -
这大概是机器码优化的第一条规则。如果可以,总是避免分支。错误预测的分支非常昂贵。第 0 条规则是始终先测量。
-
请记住,这有点像“苹果对橙子”的比较——如果
foo不在{0, 1}中,这两种方法是不等价的。 -
@twalberg 糟糕,我忘了说明
foo必须是0或1才能进行数学运算。 -
“分支”版本不太可能使用
JE后跟JMP- 而是单个JNE FINISH。
标签: c performance optimization assembly x86