用GCC和GFORTRAN实现矢量化
我有一个简单的循环,我希望在程序集中看到YMM寄存器,但我只看到XMM用GCC和GFORTRAN实现矢量化,gcc,compiler-optimization,avx,intel-fortran,avx2,Gcc,Compiler Optimization,Avx,Intel Fortran,Avx2,我有一个简单的循环,我希望在程序集中看到YMM寄存器,但我只看到XMM program loopunroll integer i double precision x(8) do i=1,8 x(i) = dble(i) + 5.0d0 enddo end program loopunroll 然后我编译它(gcc或gfortran不重要,我使用的是gcc 8.1.0) 但如果我这样做,英特尔并行工作室2018将更新3: [user@machine avx]$ ifort -S -mav
program loopunroll
integer i
double precision x(8)
do i=1,8
x(i) = dble(i) + 5.0d0
enddo
end program loopunroll
然后我编译它(gcc或gfortran不重要,我使用的是gcc 8.1.0)
但如果我这样做,英特尔并行工作室2018将更新3:
[user@machine avx]$ ifort -S -mavx loopunroll.f90
[user@machine avx]$ cat loopunroll.s|grep mm vmovdqu .L_2il0floatpacket.0(%rip), %xmm2 #11.8
vpaddd .L_2il0floatpacket.2(%rip), %xmm2, %xmm3 #11.15
vmovupd .L_2il0floatpacket.1(%rip), %ymm4 #11.23
vcvtdq2pd %xmm2, %ymm0 #11.15
vcvtdq2pd %xmm3, %ymm5 #11.15
vaddpd %ymm0, %ymm4, %ymm1 #11.8
vaddpd %ymm5, %ymm4, %ymm6 #11.8
vmovupd %ymm1, loopunroll_$X.0.1(%rip) #11.8
vmovupd %ymm6, 32+loopunroll_$X.0.1(%rip) #11.8
我也试过旗子
-三月=core-avx2-mtune=core-avx2
对于gnu和intel,我在gnu生成的程序集中仍然得到了相同的XMM结果,但在intel生成的程序集中得到了YMM结果
我应该做些什么来取悦大家
非常感谢,,
M您忘记使用
gfortran
启用优化。使用gfortran-O3-march=native
为了不完全优化,请编写一个函数(子例程),该函数生成的结果在该子例程之外的代码可以看到。e、 g.将x
作为参数并存储它。编译器必须发出适用于任何调用方的asm,包括调用子例程后关心数组内容的调用方
对于gcc,
-ftree vectorize
仅在-O3
处启用,而不是在-O2
处启用
gcc默认值为-O0
,即编译速度快,生成速度慢得惊人的代码,从而提供一致的调试
gcc永远不会在-O0
自动矢量化。必须使用-O3
或-O2-ftree矢量化
与gcc不同,ifort
默认值显然包括优化。如果不对gcc使用-O3
,则不应期望ifort-S
和gcc-S
的输出在远程相似
当我使用-O3时,它会在程序集中丢弃对XMM和YMM的任何引用 编译器优化无用的工作是件好事 编写一个函数,该函数接受数组输入arg并写入输出arg,然后查看asm中的该函数。或在两个全局数组上运行的函数。不是一个完整的程序,因为编译器有完整的程序优化 无论如何,请参阅以获取有关编写有用函数以查看编译器asm输出的提示。这是一个C问答,但所有的建议也适用于Fortran:编写接受参数并返回结果的函数,或者产生无法优化的副作用 没有Fortran,而且看起来
-xfortran
无法使g++
编译为Fortran。(<代码> -XC< /COD>工作在C中代替C++编译为GOOBET)。否则,我建议使用该工具来查看编译器输出。< /P>
我制作了一个C版本的循环,以查看gcc对其优化器的类似输入做了什么。(我没有安装gfortran 8.1,也不太了解Fortran。我来这里是为了AVX和优化标签,但gfortran使用的后端与我非常熟悉的gcc相同。) 我们可以通过使用偏移量来阻止小数组的常量传播,因此要存储的值不再是编译时常量:
void store_i5_var(double *x, int offset) {
for(int i=0 ; i<8; i++) {
x[i] = 5.0 + (i + offset);
}
}
void store_i5_var(双*x,整数偏移){
对于(int i=0;i您忘记使用gfortran
启用优化。请使用gfortran-O3-march=native
为了不完全优化,编写一个函数(子例程)这将产生子例程外部的代码可以看到的结果。例如,将x
作为参数并存储它。编译器必须发出适用于任何调用方的asm,包括在调用子例程后关心数组内容的调用方
对于gcc,-ftree vectorize
仅在-O3
处启用,而不是在-O2
处启用
gcc默认值为-O0
,即编译速度快,生成速度慢得惊人的代码,从而提供一致的调试
gcc永远不会在-O0
处自动矢量化。必须使用-O3
或-O2-ftree矢量化
与gcc不同,ifort
默认值显然包括优化。如果不对gcc使用-O3
,则不应期望ifort-S
和gcc-S
的输出非常相似
当我使用-O3时,它会在程序集中丢弃对XMM和YMM的任何引用
编译器优化无用的工作是件好事
编写一个函数,该函数接受数组输入arg并写入输出arg,然后查看asm中的该函数。或者是一个在两个全局数组上运行的函数。不是一个完整的程序,因为编译器具有完整的程序优化
无论如何,请参阅以获取编写有用函数以查看编译器asm输出的提示。这是一个C问答,但所有建议也适用于Fortran:编写接受参数并返回结果或具有无法优化的副作用的函数
不存在FORTRAN,它看起来像<代码> -Xfortran < /C> >不能使<代码> G++< /COD>编译为FORTRAN。(<代码> -XC< /COD>工作在C上编译为C++而不是GOOBD上的C++)。否则,我建议使用查看编译器输出的工具。< /P>
我制作了一个C版本的循环,看看gcc对其优化器的输入做了什么(我没有安装gfortran 8.1,也几乎不知道Fortran。我在这里是为了AVX和优化标签,但gfortran使用与gcc相同的后端,我非常熟悉)
我们可以通过使用偏移量来阻止小数组的常量传播,因此要存储的值不再是编译时常量:
void store_i5_var(double *x, int offset) {
for(int i=0 ; i<8; i++) {
x[i] = 5.0 + (i + offset);
}
}
void store_i5_var(双*x,整数偏移){
对于(int i=0;i来说,为了整理这一点,Peters的建议是正确的。我的代码现在如下所示:
program loopunroll
double precision x(512)
call looptest(x)
end program loopunroll
subroutine looptest(x)
integer i
double precision x(512)
do i=1,512
x(i) = dble(i) + 5.0d0
enddo
return
end subroutine looptest
生产YMM的方法是
gfortran -S -march=haswell -O3 loopunroll.f90
为了整理一下,Peters的建议是正确的。我的代码现在看起来像:
program loopunroll
double precision x(512)
call looptest(x)
end program loopunroll
subroutine looptest(x)
integer i
double precision x(512)
do i=1,512
x(i) = dble(i) + 5.0d0
enddo
return
end subroutine looptest
生产YMM的方法是
gfortran -S -march=haswell -O3 loopunroll.f90
您忘记使用gfortran
启用优化。请使用gfortran-O3-march=native
。