我正在读一本书,作者说这if( a < 901 )比书更快if( a <= 900 ).
与此简单示例不完全相同,但循环复杂代码略有性能变化.我想这必须对生成的机器代码做一些事情,以防它甚至是真的.
我想检查boost::variant在我的代码中应用的程序集输出,以便查看哪些中间调用被优化掉了.
当我编译以下示例(使用GCC 5.3 g++ -O3 -std=c++14 -S)时,似乎编译器优化了所有内容并直接返回100:
(...)
main:
.LFB9320:
.cfi_startproc
movl $100, %eax
ret
.cfi_endproc
(...)
Run Code Online (Sandbox Code Playgroud)
#include <boost/variant.hpp>
struct Foo
{
int get() { return 100; }
};
struct Bar
{
int get() { return 999; }
};
using Variant = boost::variant<Foo, Bar>;
int run(Variant v)
{
return boost::apply_visitor([](auto& x){return x.get();}, v);
}
int main()
{
Foo f;
return run(f);
}
Run Code Online (Sandbox Code Playgroud)
但是,完整的程序集输出包含的内容远远超过上面的摘录,对我而言,它看起来永远不会被调用.有没有办法告诉GCC/clang删除所有"噪音"并输出程序运行时实际调用的内容?
完整装配输出:
.file "main1.cpp"
.section .rodata.str1.8,"aMS",@progbits,1
.align 8
.LC0:
.string "/opt/boost/include/boost/variant/detail/forced_return.hpp"
.section .rodata.str1.1,"aMS",@progbits,1
.LC1: …Run Code Online (Sandbox Code Playgroud) 首先是一个微不足道的数学事实:给定整数n和m,我们有n < m当且仅当n <= m - 1。
GCC 似乎更喜欢较小绝对值的即时值。因此,当m已知并且满足其他条件时,编译器在等效比较表达式中选择最小化绝对值的表达式。例如,它喜欢n <= 1000在n < 1001和GCC 9.2将这种
bool f(uint32_t n) {
return n < 1001;
}
Run Code Online (Sandbox Code Playgroud)
进入这个x86汇编代码
f(unsigned int):
cmpl $1000, %edi
setbe %al
ret
Run Code Online (Sandbox Code Playgroud)
这可能有很好的性能原因,但这不是我的问题。我想知道的是:有没有办法强制 GCC 保持原始比较?更具体地说,我不担心可移植性,因此,GCC 细节(选项、编译指示、属性等)对我来说是可以的。但是,我正在寻找一个constexpr友好的解决方案,它似乎排除了 inline asm。最后,我的目标是 C++17,它不包括std::is_constant_evaluated. (话虽如此,请尽管不顾我的限制自由地提供答案,因为它可能对其他人仍然有用。)
你可能会问我为什么要做这样的事情。开始了。据我所知(如果我错了,请纠正我)这种行为可能是x86_64以下示例中的“悲观化” :
bool g(uint64_t n) {
n *= 5000000001;
return n …Run Code Online (Sandbox Code Playgroud)