鉴于以下 C 代码,为什么 GCC(版本 10.1、x86-64、-O3)在循环内部写入内存,而不是在求和期间仅使用两个寄存器并仅在最后将结果写入内存?
void sum(unsigned int l, int *as, int *r) {
r[0] = 0;
r[1] = 0;
for (int i = 0; i < l; i++) {
r[0] += as[2 * i];
r[1] += as[2 * i + 1];
}
}
Run Code Online (Sandbox Code Playgroud)
此处生成说明。
我的猜测是这种行为与 GCC 具有“考虑”并发性有关。您可以有另一个线程,例如在执行求和时从同一地址的内存读取。
这是真正的(也是唯一的)原因吗?它甚至可能由 C 标准定义吗?
编译器不知道是否as和r点到同一阵列中,所以它不知道r[0] += as[2 * i];不改变的值as[2 * i + 1],这是需要在r[1] += as[2 * i + 1];,并且类似地针对其它之间的相互作用r[0],r[1]以及各种元件as。
你可以告诉编译器的元素称为通过as和r通过改变函数声明不重叠void sum(unsigned int l, int * restrict as, int * restrict r)。