为了更好地理解编译器,特别是汇编语言,我一直在实验一段简单的代码,其中计算第一个N
数字的总和,这应该导致N(N1)/2
或N(N-1)/2
.
如代码所示,有两个功能:
#include <cstdint>
// Once compiled with optimization, the generated assembly has a loop
uint64_t sum1( uint64_t n ) {
uint64_t sum = 0;
for ( uint64_t j=0; j<=n; ++j ) {
sum += j;
}
return sum;
}
// Once compiled with optimization, the generated assembly of the following has no loop
uint64_t sum2( uint64_t n ) {
uint64_t sum = 0;
for ( uint64_t j=0; j<n; ++j ) {
sum += j;
}
return sum;
}
在第一个函数中,I从O循环到N,即j
我的理解/观察:
>
对于第一个函数
sum1
,生成的程序集有一个循环,而对于第二个函数sum2
,程序集没有显示循环。然而,一旦我删除了编译器优化,即-O3
,那么您最终可以在程序集中看到第二个函数的循环。
要查看通过编译器优化生成的程序集,请查看此优化。
若要查看生成的程序集而不进行编译器优化,请查看此非优化。
编译器是x86-64 clang
问题:为什么编译器优化没有显示程序集中的另一个循环?
这是因为你的编译器非常非常聪明,它知道从0到n的所有值的总和可以用一个微不足道的数学公式来计算,而不是循环。
但是,您的C编译器也发现这个数学公式不能在中使用。
为了更好地理解编译器,特别是汇编语言,我一直在尝试一段简单的代码,其中计算前个数字的总和,这应该产生或。 如代码所示,有两个功能: 在第一个函数中,我从O循环到N,即
在我的系统上,行-主顺序访问平均花费(试用),而列-主顺序访问在我的系统上花费(试用),这是相当重要的。 从表面上看,这应该是一件非常简单的事情来优化。 为什么现代编译器不优化这些场景?
(这个问题与此密切相关,但它是一个更具体的问题,我希望能就此得到答案)
这是CppCon谈话中的一个例子https://www.youtube.com/watch?v=F6Ipn7gCOsY 目标是首先从A打印Hello,然后允许线程B启动。很明显,应该避免繁忙等待,因为它占用大量CPU。 作者说, 循环可以由编译器进行优化(通过将 的值放入寄存器中),因为编译器看到 从不Hibernate,因此永远不会被更改。但是,即使线程从不Hibernate,另一个线程仍然可以