带有优化标志的gfortran如何解释嵌套隐含的do循环?

问题描述 投票:0回答:1

我对 gfortran 有一个问题,我试图在一般层面上理解它,以避免将来再次遇到它。具体来说,我试图了解读取数据时嵌套隐含 do 循环的行为以及 gfortran 优化标志如何影响它。

作为我正在修改的较大程序的一部分,我试图读取一些数据并将它们存储在矩阵中,

sttheight
,在我的特定情况下,它是一个向量,给出分配它时使用的变量的维度。下面给出了显示该问题的最小工作示例。

问题与从输入文件读取变量时使用的嵌套隐含 do 循环结构有关。当使用

gfortran Read_fct.f90 -o Read
编译程序并运行它时,它会产生所需的输出,即打印
Input.txt
中的 8 个浮点变量:

   0.00000000       14370.0117       14370.0117       14370.0117       14370.0117       14370.0117       14370.0117       14370.0117  

我正在使用:“GNU Fortran (GCC) 12.2.0 20220819 (HPE)”

但是,如果我用

gfortran -O2 Read_fct.f90 -o Read
编译它,输出是“0.00000000”,打印8次。使用
-O1
或更高的优化标志(-O3 到 -O5)可以获得相同的结果。该程序不会抛出任何错误或警告,这意味着该问题很容易被忽视。通过
gfortran -O2 -g -fcheck=bounds Read_fct.f90 -o Read
进一步调试揭示了错误的根源:

At line 18 of file Read_fct.f90
Fortran runtime error: Index '0' of dimension 1 of array 'noheight' below lower bound of 1

即程序似乎在为

noheight(jpuff)
赋值之前尝试初始化
jpuff
。因此,对于这种特定情况,我可以轻松解决该问题,但这会使我的代码不那么通用,可能会引入其他问题。另外,在花了几个小时尝试定位问题后,我想了解根本问题,以减少再次遇到此问题的机会。

使用 -O3 和“Cray Fortran : Version 16.0.1”和“ifort (IFORT) 2021.7.1 20221019”进行编译会导致打印正确浮点值的预期行为。

简而言之:1)我的代码有问题吗?2)这是 gfortran 优化标志的预期行为吗?3)这是 gfortran 中的错误吗?后者对我来说似乎不太可能,但我想没有什么是不可能的。

我希望有人能够在这里为我指出正确的方向。

MWE:

读取_fct.f90:

program Read_fct
implicit none
integer ::  ntraj, mpuff
integer :: jheight, jt, jpuff
real,allocatable :: sttheight(:,:,:)

integer, dimension(:), allocatable :: noheight

open(1, file='Input.txt')
ntraj = 8
mpuff = 1

allocate(noheight(mpuff))
noheight(1) = 1

allocate(sttheight(noheight(1), ntraj, mpuff))

read (1,*) (((sttheight(jheight,jt,jpuff),jheight=1,noheight(jpuff)),jt=1,ntraj),jpuff=1,mpuff)
write(*,*) sttheight
close(1)
end program

文件“Input.txt”只有一行包含我要读取的数据:

0.00000000,14370.01149861,14370.01149861,14370.01149861,14370.01149861,14370.01149861,14370.01149861,14370.01149861     ! sttheight

编辑:

implicit none
包含并相应删除

fortran compiler-optimization gfortran do-loops
1个回答
2
投票

程序可以大大简化,这是我想出的MRE

program implied_do_bug
implicit none
integer :: i,j,k
real :: arr(1,1,1)
integer :: ni(1)

ni(1) = 1
arr = 1

write(*,*) (((arr(i,j,k), i=1,ni(k)), j=1,1), k=1,1)
end program

我已将其作为一个可能的编译器错误提交到 GCC Bugzilla 中,该错误是一个回归错误 111837

根据回复,解决方法是通过

-fno-frontend-optimize
禁用前端优化。

© www.soinside.com 2019 - 2024. All rights reserved.