Fortran 中的内联函数

Inlining functions in Fortran

在 Fortran 项目中,我们使用二进制搜索来查找所需的值:

integer function binsearch(tab, el)
  implicit none

  real, intent(in) :: tab(:), el
  integer :: a, b, mid

  a = 1
  b = size(tab)

  do while (b - a > 1)
    mid = (a + b)/2
    if (el >= tab(mid)) then
      a = mid
    else
      b = mid
    endif
    ! if (el < tab(mid + 1)) exit ! BAD OPTIMIZATION !
  enddo

  binsearch = a
end function binsearch

后面我们就直接用

foo = binsearch(tab, el)

不幸的是,周围例程的使用如此频繁,以至于 BAD OPTIMIZATION 将总执行时间增加了一半。所以我考虑内联函数以减少调用成本。

是否可以将此函数标记为内联?在 C 中有关键字 inline 这是对编译器的建议 - Fortran 2008 中是否有类似的内容?

为了代码清晰,我不想复制粘贴。

在 Fortran 中,没有与 C 中 inline 的直接模拟;内联哪些函数总是由编译器决定。然后最重要的是编译具有高优化级别的代码以打开积极的内联(例如 gfortran 中的 -Ofast,ifort 中的 -fast)。此外,您可能想要打开 "link-time optimization"(gfortran 中的 -flto,ifort 中的 -ipo),以便编译器可以在 link 时间内联来自不同源文件的函数如有必要。

但是,有一些方法可以重写增加内联机会的代码。一种这样的方法是将函数显式标记为 pure(即没有副作用的函数),因为这意味着编译器更容易优化对它的调用。换句话说:

pure function binsearch(tab, el) result(r)
  real, intent(in) :: tab(:), el
  integer          :: r, a, b, mid

  ...
end function

如果您可以将 binsearch 重写为您正在使用它的任何函数中的嵌套函数,编译很可能会替换函数对 tab 的函数调用正文或快速 goto 语句,即使您不更改编译选项。在那种情况下:

subroutine some_other_thing()
  ...

  ! Do the search
  i = binsearch(tab, el)

  ...

contains
  pure function binsearch(tab, el) result(r)
    real, intent(in) :: tab(:), el
    integer          :: r, a, b, mid

    ...
  end function
end subroutine

这取决于编译器。我可以验证这适用于 Cray 和 Intel Fortran 编译器,但语句略有不同。

Cray 编译器:

!dir$ forceinline :: frob

这将强制编译器内联函数 frob。你会把它放在函数定义的正上方。

英特尔编译器:

!dir$ attributes forceinline :: frob

我没有看到 gcc/gfortran 目前有这些选项。

两种编译器的手册都涵盖了这一点。