为什么没有优化检查

Elv*_*ins 3 c++ optimization x86 assembly gcc

今天我开始玩分支检查两个布尔值.我非常确定在某些优化级别它们只会被添加然后检查,但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";
    }
}
Run Code Online (Sandbox Code Playgroud)

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

test   dil,dil
je     400794 <test(bool, bool)+0x14>
test   sil,sil
jne    4007b0 <test(bool, bool)+0x30>
Run Code Online (Sandbox Code Playgroud)

而它为分支2生成以下代码:

movzx  ebx,bl
movzx  ebp,bpl
add    ebx,ebp
jne    4007cf <test(bool, bool)+0x4f>
Run Code Online (Sandbox Code Playgroud)

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

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

Mar*_*ica 6

在抽象机器的级别,&&如果第一个表达式为false ,则强制不评估第二个表达式.通过as-if规则,编译器可以选择评估第二个表达式 - 如果它可以证明它已经定义了行为(或者未定义的行为无关紧要)并且没有副作用; 然而编译器编写者已明确决定不值得.

如果你想要短切,&可以(用注释)有帮助.

  • 注意,在内部,在几个平台上,gcc早期用'a&b`替换`a && b`(参见-fdump-tree-gimple).然后后端选择将'(a&b)!= 0`扩展为2跳,因为它认为平均效率更高. (2认同)