帮助编译器优化分支代码序列

han*_*ans 13 c c++ optimization

我在C/C++中有包含许多分支的代码序列,如下所示:

if( condition1 )
    return true;
if( condition2 )
    return true;
...
return false;
Run Code Online (Sandbox Code Playgroud)

(相当于返回condition1 || condition2 || ...;)

评估每个条件需要几次存储器访问(所有只读),但编译器在评估先前条件之前不移动存储器访问而错过了一个重要的优化机会.当condition1为真时,condition2的内存访问的原因可能是段错误.我知道他们不这样做,我希望编译器能够做出明智的事情并将这些代码序列中的一些混合在一起,以适应性能,例如利用指令级并行性.我也不想将条件更改为逻辑或(不是短路),因为其中一个分支可能会跳出来.

关于如何实现这一点的任何想法(最好使用gcc)?

谢谢.

Ton*_*roy 6

评估每个条件需要几次内存访问

为什么不在个别条件下避免短路评估,而是让条件出现?

使用非内置类型的短路操作符

究竟如何实现前者取决于这些条件(即本质condition1,condition2在你的代码) -给你展示他们一无所知,我只能泛泛而谈:他们内部包含短路运营商,而不是布尔值转换为整数表示和使用例如按位OR(如果它读得更好并且在您的特定用法中起作用,则甚至是'+'或'*').按位运算符通常更安全,因为它们的优先级较低 - 只有在条件已经包含按位运算符时才需要小心.

为了显示:

OLD: return (a > 4 && b == 2 && c < a) ||   // condition1
            (a == 3 && b != 2 && c == -a);  // condition2

NEW: return (a > 4 & b == 2 & c < a) ||
            (a == 3 & b != 2 & c == -a);
Run Code Online (Sandbox Code Playgroud)

如果你之前使用数字/指针的隐式转换,也要小心bool......你想将它们标准化为bools,这样它们的最低有效位反映了它们的布尔意义:

OLD: return my_int && my_point && !my_double;
NEW: return bool(my_int) & bool(my_point) & !my_double;  // ! normalises before bitwise-&
Run Code Online (Sandbox Code Playgroud)

你可能还想用...进行基准测试

     bool condition1 = a > 4 & b == 2 & c < a;
     bool condition2 = a == 3 & b != 2 & c == -a;
     return condition1 || condition2;
Run Code Online (Sandbox Code Playgroud)

...可能更快 - 可能仅在整个"返回假"的情况下,并且可能在最后一个条件N或2是"返回真实"的决定因素时.

用户定义的运算符可避免短路评估

单独地,对具有重载逻辑运算符的对象禁用短路评估,这为您使用现有表示法进行检查提供了另一种途径,但您必须更改或增强数据类型.

思考

更一般地说,如果你在每个条件中组合了大量的断言,那么你只会从中受益 - 如果函数倾向于通过返回false则更多.

"AProgrammer"也是一个很好的观点 - 在现代CPU上可以使用推测执行,CPU可能已经领先于短路评估所暗示的排序(在一些特殊模式下,要么避免或抑制任何内存故障,要么取消引用无效指针,除以0等).因此,整个优化尝试可能会毫无意义甚至适得其反.需要对所有替代品进行基准测试.


Goz*_*Goz 5

你能不能自己移动这部分病情?

 const bool bCondition1Result = <condition1>;
 const bool bCondition2Result = <condition2>;
Run Code Online (Sandbox Code Playgroud)

等等

为了更好的优化仍然...重新设置您的条件的顺序,以便最受欢迎的一个是第一个被检查.通过这种方式,它会提前出现(这可能会产生很小的差别).