为什么没有优化检查

时间:2017-01-06 15:12:31

标签: c++ gcc assembly optimization x86

今天我开始玩分支检查两个布尔值。我非常确定在某些优化级别它们只会被添加然后检查,但gcc和clang的情况并非如此。为什么不通过添加和检查来替换它们来优化两个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)不应该比加法和分支(加+ jne)慢吗?

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

3 个答案:

答案 0 :(得分:6)

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

如果您 希望短片,&可以提供帮助(带评论)。

答案 1 :(得分:2)

  

为什么不通过替换它们来优化两个bool检查   另外还有一张支票?

建议的优化不正确。 添加不是&&运算符的正确替代品,因为当至少(不是两者)时,前者将评估为true条件是true

问题仍然存在,如何进行优化?

C ++标准保证bool值转换为具有定义值的intfalse转换为0true转换为1 }。因此,以下构造是完全合法的(假设ab只是bool个变量):

if (a & b) // OK, integral promotions take place (bool ---> int)

假设编译器始终存储具有bool(例如true)和0x1false)的相同内部表示的0x0值,则条件可能为直接翻译成x86 test指令:

test    sil, dil

这是棘手的部分。显然,GCC编译器改变了主线4.6和4.7之间的行为。即使对int进行显式转换,它也会保持两次单独的跳转。条件:

if (static_cast<int>(a) & static_cast<int>(b))

生成代码(GCC 6.2.0,-O3优化级别):

test    dil, dil
je      .L1
test    sil, sil
je      .L1

另一方面,ICC和MSVC 2015编译器都执行&#34; true&#34;按位和:

movzx   eax, BYTE PTR b$[rsp]
test    al, BYTE PTR a$[rsp]
je  SHORT $LN6@main

版本4.7之前的GCC也是如此(带-O3的GCC 4.6.3):

movzx   edi, dil
test    esi, edi

答案 2 :(得分:-2)

您忘记了逻辑运算符short-circuit evaluation

对于逻辑,如果左侧为假,则不评估右侧。