for循环中一个始终为false的布尔条件是否会被优化掉?

ldo*_*dog 5 c++ optimization loops

我有以下情况

bool user_set_flag;

getFlagFromUser(&user_set_flag);

while(1){

    if(user_set_flag){
        //do some computation and output

    }


    //do other computation
}
Run Code Online (Sandbox Code Playgroud)

该变量user_set_flag仅在代码中设置一次且仅一次,在开始时,其本质上是用户选择他想对程序执行的操作.假设用户选择user_set_flag = false然后编译器将以这样的方式编译代码,使得该if(user_set_flag)语句仅被检查一次,或者将始终被检查.我可以给编译器提示如将bool设置为const吗?

我问这个的原因是因为我的应用程序是时间关键的,它尽可能快地处理帧.一个总是错误的分支应该能够在运行时以某种方式确定?

int*_*nt3 14

首先,处理器具有称为分支预测的能力.经过几次循环后,处理器将能够注意到您的if语句始终是单向的.(它甚至可以注意到常规模式,例如true false true false.)然后它会推测性地执行该分支,只要它能够正确预测,if语句的额外成本就会大大消除.如果您认为用户更可能选择true而不是false,您甚至可以告诉gcc编译器(特定于gcc的扩展名).

但是,你在一条评论中提到你有一个"更复杂的bool序列".我认为处理器可能没有内存来模式匹配所有跳转 - 当它返回到第一个if语句时,知道跳转的方式已从其内存中移位.但我们可以帮助它...

编译器能够将循环和if语句转换为它认为更优化的形式.例如,它可能会将您的代码转换为schnaader给出的形式.这称为循环非开关.您可以通过执行配置文件引导优化(PGO)来帮助它,让编译器知道热点的位置.(注意:在gcc中,-funswitch-loops仅在打开时-O3.)

您应该在指令级别(VTune将是一个很好的工具)分析您的代码,以查看if语句是否真的是瓶颈.如果它们确实存在,并且通过查看生成的程序集,您认为尽管PGO编译器已经错了,您可以尝试自己提升if语句.也许模板化的代码会使它更方便:

template<bool B> void innerLoop() {
    for (int i=0; i<10000; i++) {
        if (B) {
            // some stuff..
        } else {
            // some other stuff..
        }
    }
}
if (user_set_flag) innerLoop<true>();
else innerLoop<false>();
Run Code Online (Sandbox Code Playgroud)

  • 关于分支预测的好处,人们总是忘记这一点,但它对这些事情有很大的影响. (2认同)

Igo*_*aka 6

我认为根本不可能进一步优化这一点.编译器足够聪明,知道user_set_flag在执行循环期间值不会改变,并将为此生成最有效的机器代码.

这也是二次猜测编译器的一些方面.除非你真的真的知道自己在做什么,否则最好坚持使用最简单的解决方案.

作为练习尝试使用if (true)和 来分析(时间)执行if(user_set_flag).我的猜测是执行时间差异不大.


sch*_*der 5

另一种选择是:

if(user_set_flag){
    while(1){
      ComputationAndOutput();
      OtherComputation();
    }
} else {
    while(1){
      OtherComputation();
    }
}
Run Code Online (Sandbox Code Playgroud)

但正如Smashery所说,这是微优化,并不会像你可以肯定的其他优化一样加速你的程序.