我一直在阅读 bit twiddling hacks并思考,编译器是否能够避免以下代码中的分支:
constexpr int min(const int lhs, const int rhs) noexcept {
if (lhs < rhs) {
return lhs;
}
return rhs
}
将其替换为 ( explanation ):
constexpr int min(const int lhs, const int rhs) noexcept {
return rhs ^ ((lhs ^ rhs) & -(lhs < rhs));
}
最佳答案
- Are compilers able to...:肯定是的!
- 我可以依赖那些优化吗?:不,你不能依赖任何优化。可能总会有一些奇怪的情况,在这种情况下,编译器会出于某些不明显的原因选择不实现某种优化,或者只是看不到这种可能性。另外,总的来说,我观察到编译器有时比人们想象的要笨得多(或者人们(包括我)比他们想象的要笨)。(1)
- 没有问,但有一个非常重要的方面:我可以相信这实际上是一种优化吗?不!一方面,(尤其是在 x86 上)性能总是取决于周围的代码,并且有很多不同的优化相互作用。此外,一些架构甚至可能提供更高效地执行操作的命令。
- 我应该使用位旋转优化吗?:一般来说:不 - 尤其是在没有验证它们确实给您带来任何好处的情况下!即使它们确实提高了性能,它也会使您的代码更难阅读和审查,并且它会做出一些特定于体系结构和编译器的假设(整数的表示、指令的执行时间、分支预测错误的惩罚……),这可能会导致当您将代码移植到另一个体系结构时性能会更差,或者在最坏的情况下甚至会导致错误的结果。
我的建议:
如果您需要获得特定系统 的最后一点性能,那么只需尝试两种变体并进行测量(并在每次更新您的 CPU 和/或编译器时验证结果)。对于任何其他情况,假设编译器至少在进行低级优化方面与您一样好。我还建议您首先了解所有与优化相关的编译器标志,并在任何情况下开始使用低级优化之前设置适当的基准。
我认为手动优化有时仍然有益的唯一领域是,如果您想最佳地使用 vector 单元。现代编译器可以自动矢量化很多东西,但这仍然是一个相对较新的领域,并且编译器不允许做某些事情,因为它违反了标准的某些保证(尤其是在涉及浮点运算的情况下)。
(1) 有些人似乎认为,不管他们的代码是什么样子,编译器总是会产生提供相同语义的最佳代码。首先,编译器在有限的时间内可以做什么是有限制的(有很多启发式方法在大多数情况下都有效,但并非总是如此)。其次,在很多情况下,c++ 标准要求编译器提供某些保证,您目前实际上并不感兴趣,但仍然会阻止优化。
关于c++ - 编译器是否能够避免分支指令?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32295315/