当数组是函数参数时,矩阵乘法中的 Gcc 自动向量化奇怪行为
Gcc autovectorization weird behaviour in matrix multiply when arrays are function parameters
我正在对具有不同优化级别的不同矩阵乘法形式进行基准测试(出于教学目的),我在 gcc 自动矢量化中检测到一个奇怪的行为。当数组是参数时它无法向量化(参见 mxmp)但当数组是全局变量时能够向量化(参见 mxmg)
gcc 版本 7.4.0 (Ubuntu 7.4.0-1ubuntu1~18.04.1)
但行为与旧版 gcc 相同
编译选项:
gcc -O3 -mavx2 -mfma
#define N 1024
float A[N][N], B[N][N], C[N][N];
void mxmp(float A[N][N], float B[N][N], float C[N][N]) {
int i,j,k;
for (i=0; i<N; i++)
for (j=0; j<N; j++)
for (k=0; k<N; k++)
C[i][j] = C[i][j] + A[i][k] * B[k][j];
}
void mxmg() {
int i,j,k;
for (i=0; i<N; i++)
for (j=0; j<N; j++)
for (k=0; k<N; k++)
C[i][j] = C[i][j] + A[i][k] * B[k][j];
}
main(){
mxmg();
mxmp(A, B, C);
}
我希望编译器在这两个函数中执行相同的操作,但是 mxmp 需要大约 10 倍于 mxmg 的执行时间。探索汇编代码,恰好 gcc 能够自动矢量化 mxmg(当数组是全局变量时)但无法矢量化 mxmp(其中数组是参数)。
对 kij 形式进行了同样的尝试,它能够向量化这两个函数。
我需要帮助来发现为什么 gcc 有这种行为。以及如何帮助 gcc(编译指示、编译选项、属性等)正确矢量化 mxmp 函数。
谢谢
当数组是全局数组时,编译器可以很容易地看出它们是不相交的内存区域。当它们是函数参数时,您可以调用 mxmp(A,A,A)
,因此它必须假设写入 C 可能会修改 A 或 B,这可能会影响以后的迭代并使向量化复杂化。当然,在您的特定情况下,编译器可以内联或做其他事情来了解它...
您可以使用 restrict
:
明确指定不使用别名
void mxmp(float A[restrict N][N], float B[restrict N][N], float C[restrict N][N]) {
我正在对具有不同优化级别的不同矩阵乘法形式进行基准测试(出于教学目的),我在 gcc 自动矢量化中检测到一个奇怪的行为。当数组是参数时它无法向量化(参见 mxmp)但当数组是全局变量时能够向量化(参见 mxmg)
gcc 版本 7.4.0 (Ubuntu 7.4.0-1ubuntu1~18.04.1) 但行为与旧版 gcc 相同
编译选项: gcc -O3 -mavx2 -mfma
#define N 1024
float A[N][N], B[N][N], C[N][N];
void mxmp(float A[N][N], float B[N][N], float C[N][N]) {
int i,j,k;
for (i=0; i<N; i++)
for (j=0; j<N; j++)
for (k=0; k<N; k++)
C[i][j] = C[i][j] + A[i][k] * B[k][j];
}
void mxmg() {
int i,j,k;
for (i=0; i<N; i++)
for (j=0; j<N; j++)
for (k=0; k<N; k++)
C[i][j] = C[i][j] + A[i][k] * B[k][j];
}
main(){
mxmg();
mxmp(A, B, C);
}
我希望编译器在这两个函数中执行相同的操作,但是 mxmp 需要大约 10 倍于 mxmg 的执行时间。探索汇编代码,恰好 gcc 能够自动矢量化 mxmg(当数组是全局变量时)但无法矢量化 mxmp(其中数组是参数)。
对 kij 形式进行了同样的尝试,它能够向量化这两个函数。
我需要帮助来发现为什么 gcc 有这种行为。以及如何帮助 gcc(编译指示、编译选项、属性等)正确矢量化 mxmp 函数。 谢谢
当数组是全局数组时,编译器可以很容易地看出它们是不相交的内存区域。当它们是函数参数时,您可以调用 mxmp(A,A,A)
,因此它必须假设写入 C 可能会修改 A 或 B,这可能会影响以后的迭代并使向量化复杂化。当然,在您的特定情况下,编译器可以内联或做其他事情来了解它...
您可以使用 restrict
:
void mxmp(float A[restrict N][N], float B[restrict N][N], float C[restrict N][N]) {