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

How does gfortran with optimization flags interpret nested implied do loops?

提问人:Kristian HM 提问时间:10/16/2023 最后编辑:Ian BushKristian HM 更新时间:10/17/2023 访问量:104

问:

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

作为我正在修改的更大程序的一部分,我正在尝试读取一些数据并将它们存储在一个矩阵中,在我的特定情况下,这是一个给定分配时使用的变量维度的向量。下面给出了显示该问题的最小工作示例。sttheight

问题与从输入文件读取变量时使用的嵌套隐含 do 循环构造有关。当使用 编译程序并运行它时,它会生成所需的输出,即打印 8 个浮点变量:gfortran Read_fct.f90 -o ReadInput.txt

   0.00000000       14370.0117       14370.0117       14370.0117       14370.0117       14370.0117       14370.0117       14370.0117  

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

但是,如果我用 编译它,输出是“0.00000000”打印 8 次。使用或更高优化标志(-O3 到 -O5)可以获得相同的结果。该程序不会引发任何错误或警告,这意味着该问题很容易被忽略。通过揭示错误的来源进行进一步调试:gfortran -O2 Read_fct.f90 -o Read-O1gfortran -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:版本 16.0.1”和“ifort (IFORT) 2021.7.1 20221019”会导致打印正确浮点值的预期行为。

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

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

MWE:

Read_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 编译器优化 gfortran do-loops

评论

0赞 Vladimir F Героям слава 10/16/2023
请使用 .implicit none
1赞 Vladimir F Героям слава 10/16/2023
GCC 7 不会出现此错误,仅会出现在 GCC 8 及更高版本中。嵌套的隐含行为发生了一些奇怪的事情。编译器错误实际上是最可能的原因。数组被越界访问,也由 valgrind 确认noheight

答:

3赞 Vladimir F Героям слава 10/16/2023 #1

程序可以大大简化,这是我想出的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

评论

0赞 Kristian HM 10/17/2023
哇,这太棒了!非常感谢您这样做。看来他们已经开发了对该错误的修复!