当 gfortran 对方程(例如 x = y*z )进行向量化时,编译器将仅使用向量寄存器(例如 YMM)和向量操作码,当且仅当编译器知道所有数据 (x,y,z) 都可以是加载到所述向量寄存器上。然而,如果编译器不知道是否所有数据都可以加载到寄存器中,它将生成冗余代码,以便可以操作剩余的数据。
此冗余代码通常不会使用最高可用的 SIMD 向量寄存器,并且会使可执行文件膨胀。我还没有进行广泛的测试,但常见的推理使我相信它可能会导致 ICACHE 缺失或阻止函数/子例程内联优化。
我想删除这个冗余代码,因为我知道我的所有数据 (x,y,z) 将完美地适合 YMM 向量寄存器。
我之前曾在这里更详细地描述过我的观察结果:https: //www.cfd-online.com/Forums/main/231759-fortran- assembly-how-remove-redundant-non-vectorized-code.html
不过,我想在这里举一些简单的例子来展示我的观点。
对于以下操作:x(:) = y*z其中x,y,z都是可分配数组,编译器不知道该操作是否可以完全矢量化,因为它不知道数组的长度是多少。如果 x,y,z 是整数数组并且长度是 8 的倍数,我们可以推断整个操作可以简单地使用 AVX2 向量化操作来完成。然而,由于数组长度在编译时未知,编译器必须生成可用于任意长度数组的冗余代码。
上帝螺栓链接:https://gcc.godbolt.org/z/1fdzK8
这是为该x(:) = y*z部分生成的程序集:
.L7:
vmovdqu ymm1, YMMWORD PTR [r13+0+rax]
vpmulld ymm0, ymm1, YMMWORD PTR [r12+rax]
vmovdqu YMMWORD PTR [r14+rax], ymm0
add rax, 32
cmp rdx, rax
jne .L7
mov rdx, r15
and rdx, -8
lea rax, [rdx+1]
cmp rdx, …Run Code Online (Sandbox Code Playgroud)