GCC为何未将逻辑或(||)优化为按位或(|)的无跳转代码?
GCC为何不将逻辑或优化为按位或的形式?
原始C代码
#include <stdbool.h> typedef struct { bool a; bool b; } MyStruct2; bool g(MyStruct2 *s) { return s->a || s->b; } bool g2(MyStruct2 *s) { return s->a | s->b; } int main() { return 0; }
编译生成的汇编代码
g: movzx eax, BYTE PTR [rdi] test al, al jne .L1 movzx eax, BYTE PTR [rdi+1] .L1: ret g2: movzx eax, BYTE PTR [rdi] or al, BYTE PTR [rdi+1] ret main: xor eax, eax ret
问题
可见g2的汇编代码更短且无跳转指令,但GCC并未将g函数的逻辑或代码优化为g2的形式。由于MyStruct2的成员均非volatile或特殊类型,即使s->a为真时也可安全访问s->b,请问GCC为何不生成这种无跳转的更短代码?
解答
这本质是编译器在分支预测收益与内存访问开销之间做的权衡:
- 逻辑或的实现(带跳转)在
s->a为真的场景下,只需要读取一次内存,不需要访问s->b。如果实际业务中s->a为真的概率较高,CPU的分支预测会让这个跳转几乎没有额外开销,反而比按位或的两次内存读取更快——毕竟内存访问的延迟远高于分支预测成功的开销。 - 按位或的实现虽然代码长度更短,但无论
s->a是否为真,都要读取两个内存地址。如果s->a和s->b不在同一个CPU缓存行中,第二次内存读取可能触发缓存未命中,反而带来更大的性能损耗。 - GCC的优化器默认会优先考虑通用场景下的平均最优性能,而非单纯追求代码短小。如果需要强制这种优化,可以尝试使用
__builtin_expect引导编译器,或者调整优化级别,但通常编译器的选择是基于通用性能模型做出的合理决策。
内容的提问来源于stack exchange,提问作者Kevin Meier
相关产品推荐
相关产品推荐

