c++ - 为什么 if 检查没有被优化

标签 c++ gcc assembly optimization x86

今天我开始研究检查两个 bool 值的分支。我很确定在某些优化级别上,它们只会被添加然后检查,但 gcc 和 clang 不是这种情况。为什么 gcc 不通过​​用加法和一个检查替换它们来优化两个 bool 检查?让我向您展示示例:

void test(bool a, bool b)
{ 
    // Branch 1
    if (a && b)
    {
        std::cout << "Branch 1";
    }

    // Branch 2
    if (static_cast<int>(a) + static_cast<int>(b))
    {
        std::cout << "Branch 2";
    }
}

gcc(即使具有最大优化级别)为分支 1 生成以下代码:

test   dil,dil
je     400794 <test(bool, bool)+0x14>
test   sil,sil
jne    4007b0 <test(bool, bool)+0x30>

同时为分支 2 生成以下代码:

movzx  ebx,bl
movzx  ebp,bpl
add    ebx,ebp
jne    4007cf <test(bool, bool)+0x4f>

两个分支(test + je)不应该比加法和分支(add + jne)慢吗?

编辑:我真正的意思是乘法,因为在真假 (1 + 0) 的情况下,加法给出真 (1),但乘法给出正确的结果 (0)。

最佳答案

在抽象机级别,&& 强制在第一个表达式为假时不对第二个表达式求值。根据 as-if 规则,编译器可以选择评估第二个表达式——如果它可以证明它具有已定义的行为(或者未定义的行为无关紧要)并且没有副作用;然而,编译器作者已经明确地决定这是不值得的。

如果您不想走捷径,& 会有所帮助(带有注释)。

关于c++ - 为什么 if 检查没有被优化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41508563/

相关文章:

c++ - 如何使用 openSSL C++ 以 PEM 格式存储 Diffie HellMan 对象的 key

c - 为什么 gcc 为我展开的循环结语生成的代码看起来过于复杂?

c - 更好地替代 C 中的 exit()、atexit()

c++ - 给定一对 (lat,long) 和偏移纬度找到经度

c++ - 如何遍历 multimap 并打印按键分组的值?

c++11 - 无法摆脱 "warning: command line option ‘-std=c++11’“使用 nvcc/CUDA/cmake

javascript - 获取 JavaScript 编译器生成的汇编代码

assembly - 使用 x86 或 x86_64 程序集反转字符串的最简洁方法是什么?

assembly - 6502 汇编将 2 位数字转换为 4 位数字

c++ - 如何测试注册表项是否存在?