转到优化重构

时间:2012-10-31 18:14:14

标签: c++ c goto

我有一个“MyFunction”我一直在思考是否应该或不应该使用goto和类似(希望很少见)的情况。所以我正试图为这种情况建立一种快节奏的习惯。待办事宜或不做事。

int MyFunction()
{   if (likely_condition)
    {
    condition_met:
        // ...
        return result;
    }
    else /*unlikely failure*/
    {   // meet condition
        goto condition_met;
    }
}

我打算在可能的情况下为失败的条件跳转指令带来好处。但是我没有看到编译器如何在没有这样的情况下知道哪些可以简化案例概率。

  1. 它运作正常吗?
  2. 是值得混淆的好处吗?
  3. 是否有更好的(更简洁,更有条理,更富表现力)的方式来启用此优化?

4 个答案:

答案 0 :(得分:5)

在我看来,您尝试进行的优化大多已经过时了。大多数现代处理器都内置了分支预测,所以(假设它足够用来注意)它们跟踪分支的采用频率和预测,并根据其过去采用的模式来预测分支是否可能被采用。在这种情况下,速度主要取决于预测的准确程度,而不是预测是采取还是采取。

因此,您可能最好使用相当简单的代码:

int MyFunction() {   
    if (!likely_condition) {
        meet_condition();
    }
    // ...
    return result;
}

答案 1 :(得分:4)

  1. 只要condition_met:没有跳过变量初始化,看起来代码应该按预期工作。

  2. 不,您甚至不知道混淆版本会编译成更优的代码。编译器优化(和处理器分支预测)近来变得非常聪明。

  3. 3

    int MyFunction()
    {
        if (!likely_condition)
        {
            // meet condition
        }
    
        condition_met:
            // ...
        return result;
    }
    

    或者,如果它有助于您的编译器(检查程序集)

    int MyFunction()
    {
        if (likely_condition); else
        {
            // meet condition
        }
    
        condition_met:
            // ...
        return result;
    }
    

答案 2 :(得分:4)

现代CPU如果进行正确的分支预测,将以相同的性能采用该分支。因此,如果它在内循环中,if (unlikely) { meet condition } common code;的性能将与您所写的相匹配。

另外,如果你在两个分支中拼出公共代码,编译器将生成与你所写的相同的代码:将为if子句发出通用案例并且else子句将jmp添加到公共代码中。您可以通过更简单的终端案例*out = whatever; return result;来看到这一点。在调试时,很难分辨出你正在查看哪个return,因为它们已经合并。

答案 3 :(得分:1)

我强烈建议您使用__builtin_expect()宏(GCC)或类似于您的特定C ++编译器(请参阅Portable branch prediction hints),而不是使用goto

int MyFunction()
{   if (__builtin_expect(likely_condition))
    {
        // ...
        return result;
    }
    else /*unlikely failure*/
    {   // meet condition
    }
}

正如其他人所提到的那样goto容易出错,而且骨头也是邪恶的。