我的 C/C++ 代码序列包含很多 分支,像这样:
if( condition1 )
return true;
if( condition2 )
return true;
...
return false;
(相当于返回条件1 || 条件2 || ...;)
评估每个条件都需要多次内存访问(都是只读的),但编译器在评估前一个条件之前没有移动内存访问,从而错过了一个重要的优化机会。原因是当条件1 为真时,条件2 的内存访问可能会出现段错误。 好吧,我知道他们没有,我希望编译器做一些明智的事情,并在适合性能的地方混合其中一些代码序列,例如利用指令级并行性。 我也不想将条件更改为逻辑或(不是短路),因为其中一个分支可能会跳出来。
关于如何实现这一点的任何想法(最好使用 gcc)?
谢谢。
最佳答案
Evaluating each of the conditions requires several memory accesses
为什么不避免个别条件下的短路求值,而是让它发生在条件的 or-ing 中?
对内置类型使用不短路的运算符
究竟如何实现前者取决于这些条件的性质(即代码中的 condition1
、condition2
) - 鉴于您对它们一无所知,我只能谈谈一般而言:它们内部包含短路运算符,而是将 bool 值转换为整数表示并使用例如按位或(如果读起来更好并且适用于您的特定用途,甚至是“+”或“*”)。位运算符通常更安全,因为它们的优先级较低 - 仅当您的条件已经包含位运算符时才需要小心。
举例说明:
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);
如果您之前使用数字/指针到 bool
的隐式转换也要小心...您希望将它们规范化为 bool
以便它们的最低有效位反射(reflect)它们的 bool 意义:
OLD: return my_int && my_point && !my_double;
NEW: return bool(my_int) & bool(my_point) & !my_double; // ! normalises before bitwise-&
您可能还想使用...进行基准测试
bool condition1 = a > 4 & b == 2 & c < a;
bool condition2 = a == 3 & b != 2 & c == -a;
return condition1 || condition2;
...这可能更快 - 可能仅在整体“返回 false”的情况下,并且可能当最后一个条件 N 或两个是“返回 true”的决定因素时。
用户定义的运算符避免短路评估
另外,对具有重载逻辑运算符的对象禁用短路评估,这为您使用现有符号进行检查提供了另一种途径,但您必须更改或增强您的数据类型。
想法
更一般地说,如果您在每个单独的条件中组合了大量的断言,您只会从中受益 - 如果函数倾向于运行并返回 false,则更是如此。
“AProgrammer”也提出了一个很好的观点——在现代 CPU 上可以使用推测执行,CPU 可能已经领先于短路评估所暗示的顺序(在某些特殊模式下,它可以避免或抑制取消引用导致的任何内存故障无效的指针,除以 0 等)。因此,整个优化尝试可能会被证明毫无意义甚至适得其反。需要对所有备选方案进行基准测试。
关于c++ - 帮助编译器优化分支代码序列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6290184/