我目前正在尝试提高程序速度。
我想知道是否将有助于替换所有类型的if语句:
bool a=1;
int b=0;
if(a){b++;}
与此:
bool a=1;
int b=0;
b+=a;
我不确定从bool到int的转换在时间上是否会成为问题。
答案 0 :(得分:3)
编程时的一个经验法则是不进行微优化。
另一条规则是编写清晰的代码。
但是在这种情况下,适用另一条规则。如果要编写优化的代码,请避免使用任何可能导致分支的代码,因为由于分支预测失败,可能导致不必要的cpu管道转储。
还请记住,汇编器中没有bool
和int
类型:只是寄存器,因此您可能会发现所有转换都会被优化。因此
b += a;
为我赢;也更清楚。
答案 1 :(得分:2)
允许编译器假定bool
的基础值没有被弄乱,因此优化编译器 可以避免分支。
如果我们在at the generated code上进行人工测试
int with_if_bool(bool a, int b) {
if(a){b++;}
return b;
}
int with_if_char(unsigned char a, int b) {
if(a){b++;}
return b;
}
int without_if(bool a, int b) {
b += a;
return b;
}
clang将利用这一事实并生成与a
版本的b
和bool
相加的完全相同的无分支代码,而在{{1}中使用零进行实际比较} case(尽管它仍然是无分支的代码):
unsigned char
gcc会像对待with_if_bool(bool, int): # @with_if_bool(bool, int)
lea eax, [rdi + rsi]
ret
with_if_char(unsigned char, int): # @with_if_char(unsigned char, int)
cmp dil, 1
sbb esi, -1
mov eax, esi
ret
without_if(bool, int): # @without_if(bool, int)
lea eax, [rdi + rsi]
ret
一样对待bool
,而不利用其属性,生成与clang的unsigned char
情况类似的代码。
unsigned char
最后,Visual C ++会像gcc一样平等对待with_if_bool(bool, int):
mov eax, esi
cmp dil, 1
sbb eax, -1
ret
with_if_char(unsigned char, int):
mov eax, esi
cmp dil, 1
sbb eax, -1
ret
without_if(bool, int):
movzx edi, dil
lea eax, [rdi+rsi]
ret
和bool
版本,尽管具有更幼稚的代码源(它使用条件移动而不是使用标志寄存器执行算术,传统上,IIRC的效率较低(对于当前的机器不知道)。
unsigned char
在所有情况下,都不会生成分支;唯一的不同是,在大多数编译器上,生成了一些更复杂的代码,这些代码依赖于a$ = 8
b$ = 16
int with_if_bool(bool,int) PROC ; with_if_bool, COMDAT
test cl, cl
lea eax, DWORD PTR [rdx+1]
cmove eax, edx
ret 0
int with_if_bool(bool,int) ENDP ; with_if_bool
a$ = 8
b$ = 16
int with_if_char(unsigned char,int) PROC ; with_if_char, COMDAT
test cl, cl
lea eax, DWORD PTR [rdx+1]
cmove eax, edx
ret 0
int with_if_char(unsigned char,int) ENDP ; with_if_char
a$ = 8
b$ = 16
int without_if(bool,int) PROC ; without_if, COMDAT
movzx eax, cl
add eax, edx
ret 0
int without_if(bool,int) ENDP ; without_if
或cmp
,从而创建了更长的依赖链。
话虽如此,只有当您实际在探查器下运行代码,并且结果指向该特定代码(或涉及该代码的紧密循环)时,我才会担心这种微优化。通常,您应该编写明智的,语义正确的代码,并专注于使用正确的算法/数据结构。稍后会进行微优化。
在我的程序中,这是行不通的,因为a实际上是类型为
的操作test
这对于优化器来说应该更好,因为它甚至对b+=(a==c)
的来源没有任何疑问-它可以直接从标志寄存器中进行确定。 As you can see,这里的gcc在两种情况下产生的代码非常相似,叮当声完全相同,而VC ++照例在bool
情况下产生的条件性代码(cmov
)更加类似