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

标签 fortran compiler-optimization gfortran do-loops

我对 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

即程序似乎在为 jpuff 赋值之前尝试初始化 noheight(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

编辑:隐式无包含并相应删除 ierr

最佳答案

程序可以大大简化,这是我想出的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 禁用前端优化。

关于fortran - 带有优化标志的 gfortran 如何解释嵌套的隐含 do 循环?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/77300746/

相关文章:

parallel-processing - 在FORTRAN中实现OpenMP任务?

C++ : In how many ways compiler optimizes away our code?

c++ - 编译器可以生成自修改代码吗?

c++ - 使用 Fortran 编译和链接 C++

Fortran 'parameter' 类型未包含在编译对象中

optimization - 使用-fast编译时,波特兰组FORTRAN pgf90程序失败,-fast -Mnounroll成功时,

csv - 从 fortran 中的 .csv 文件读取数据

java - 用Java编写的编译器: Peephole optimizer implementation

fortran - 直接链接 fortran 代码中的库,无需编译器标志

line-breaks - gfortran 行长度限制