当我编译这个片段(使用-Ofast -floop-nest-optimize)时,gcc生成按源顺序遍历数组的程序集。
但是,如果我取消对// n = 32767行的注释,并将any编号分配给n,则会将索引顺序更改为x[i * n + j]。以连续行-主要顺序遍历内存比跨列遍历要友好得多。
float matrix_sum_column_major(float* x, int n) {
// n = 32767;
float sum = 0;
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
sum += x[j * n + i];
return sum;
}为什么GCC或clang不能使用运行时变量int 的 回路交换 呢?实际代码通常不会显式地声明大小。
PD:我用gcc和clang-9的不同版本试过了,这两者似乎都发生了。
PD2:即使我使x成为函数内部的局部变量malloc,它仍然会发生。
发布于 2020-04-12 17:46:26
编译器通常将他们的工作(并且应该集中精力)集中在对效率感兴趣的程序员可能使用的构造可以被其他结构所取代的地方,这些构造在任何情况下都很容易被证明是等价的,而这些构造应该是重要的。如果n是常量,编译器可以确定将在循环中使用的数组索引的确切集合,然后确定如何处理所有这些索引。如果n不是常数,编译器可能能够确定当n为正数时,代码将使用从0到n*n-1的所有索引,但这可能需要付出更多的努力。“clang”的作者可能会在这种情况下做出这样的决定,如果他们足够努力的话,但是他们可能认为这种努力是不值得的。
请注意,如果代码将比任何其他代码更多地使用n的一些特定值,让代码显式地检查这些值并使用为它们量身定制的循环,那么编译器可能能够为这些循环生成比可以使用任意n的循环更高效的代码。由于许多现实世界中的问题可能有一些比其他问题更多使用的n值,所以编译器编写人员假设对性能感兴趣的程序员可能会使用这种特殊的循环,并且花费一定的精力来改进任意的-n循环可能比在其他地方花费同样的精力带来的好处更少。
https://stackoverflow.com/questions/61016358
复制相似问题