- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我做了这个小程序来测试,如果gfortran做尾调用消除:
program tailrec
implicit none
print *, tailrecsum(5, 0)
contains
recursive function tailrecsum (x, running_total) result (ret_val)
integer, intent(in) :: x
integer, intent(in) :: running_total
integer :: ret_val
if (x == 0) then
ret_val = running_total
return
end if
ret_val = tailrecsum (x-1, running_total + x)
end function tailrecsum
end program
为了检查,我使用 -S 选项编译它,以查看说明。这里是 tailrecsum 函数的行:
tailrecsum.3429:
.LFB1:
.cfi_startproc
movl (%rdi), %eax
testl %eax, %eax
jne .L2
movl (%rsi), %eax
ret
.p2align 4,,10
.p2align 3
.L2:
subq $24, %rsp
.cfi_def_cfa_offset 32
leal -1(%rax), %edx
addl (%rsi), %eax
leaq 8(%rsp), %rdi
leaq 12(%rsp), %rsi
movl %edx, 8(%rsp)
movl %eax, 12(%rsp)
call tailrecsum.3429
addq $24, %rsp
.cfi_def_cfa_offset 8
ret
.cfi_endproc
最后,我看到 call tailrecsum.3429
,因此认为没有尾调用消除。当我使用 -O2
或 -O3
和 -foptimize-sibling-calls
时也是如此。那么,是 gfortran 不支持这个还是我的代码有问题?
最佳答案
它确实支持它。要避免许多非常微妙的陷阱会损害尾调用优化,这是非常棘手的。
如果按值传递参数,编译器优化尾调用会变得更简单。在那种情况下,接收过程不需要指针(地址)指向它。
其实这样修改就足以消除尾调用,实现无限递归了:
recursive function tailrecsum (x, running_total) result (ret_val) bind(C)
integer, value :: x
integer, value :: running_total
integer :: ret_val
if (x == 0) then
ret_val = running_total
return
end if
ret_val = tailrecsum (x-1, running_total + x)
end function tailrecsum
Gfortran 不需要bind(C)
,因为它将所有value
实现为类似C 的按值传递。英特尔确实需要它,因为它会创建一个临时地址并传递其地址。
不同架构的细节可能不同,这取决于谁负责清理什么。
考虑这个版本:
program tailrec
use iso_fortran_env
implicit none
integer(int64) :: acc, x
acc = 0
x = 500000000
call tailrecsum(x, acc)
print *, acc
contains
recursive subroutine tailrecsum (x, running_total)
integer(int64), intent(inout) :: x
integer(int64), intent(inout) :: running_total
integer(int64) :: ret_val
if (x == 0) return
running_total = running_total + x
x = x - 1
call tailrecsum (x, running_total)
end subroutine tailrecsum
end program
有了 500000000 次迭代,它显然会在没有 TCO 的情况下破坏堆栈,但它不会:
> gfortran -O2 -frecursive tailrec.f90
> ./a.out
125000000250000000
您可以使用 -fdump-tree-optimized
更轻松地检查编译器的功能。老实说,我什至懒得去理解你的汇编输出。 X86 汇编对我来说太深奥了,我简单的大脑只能处理某些 RISC。
你可以看到在你的原始版本中调用下一个迭代之后还有很多事情要做:
<bb 6>:
_25 = _5 + -3;
D.1931 = _25;
_27 = _18 + _20;
D.1930 = _27;
ret_val_28 = tailrecsum (&D.1931, &D.1930);
D.1930 ={v} {CLOBBER};
D.1931 ={v} {CLOBBER};
<bb 7>:
# _29 = PHI <_20(5), ret_val_28(6)>
<bb 8>:
# _22 = PHI <_11(4), _29(7)>
<bb 9>:
# _1 = PHI <ret_val_7(3), _22(8)>
return _1;
}
我不是 GIMPLE 的专家,但 D.193x
操作肯定链接到为调用而放在堆栈上的临时表达式。
PHI
操作然后根据 if 语句 (https://gcc.gnu.org/onlinedocs/gccint/SSA.html) 中实际采用的分支查找实际返回的返回值版本。
正如我所说,有时很难将代码简化为 gfortran 可以接受的正确形式来执行尾调用优化。
关于fortran - gfortran 是否支持尾调用消除?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39330498/
我正在为一个私有(private)项目编译库,这取决于许多库。具体来说,其中一个依赖项是用 Fortran 编译的。在某些情况下,我看到使用 g77 编译的依赖项,在其他人身上,我看到它是用 gfor
根据 this , gfortran 可以进行整数逻辑转换,但我收到此错误: if (.not.bDropped.and.(zz_unif01() .lt. (1
我听说 g95 不再有效。现在使用哪种编译器是合适的(我将不胜感激提供最新的概述) 最佳答案 截至 2010 年 12 月 29 日,该项目似乎已死。自 2010 年 8 月中旬以来,该项目的博客没有
我有一个针对 ifort 进行了优化的程序,但是我想改用 gfortran 编译它。以下是提供的标志: FCFLAGS= -Vaxlib -CB -mcmodel=large -O -openmp
我正在尝试使用 gfortran 编译器在 Ubuntu 14.04 上使用旧的 CPMD-3.11.1 版本。 在运行 Makefile 时我遇到了这个错误: Error: Unclassifiab
我目前有 Xcode(以及命令行工具)和 gfrotran from HPC安装在我的 Yosemite 系统上,并希望将 HPC 的 gfortran 替换为 Homebrew 的(因为我在使用 H
自升级到优胜美地后,我无法使用 gfortran 进行编译。最初我收到“段错误 11”,然后我: 从 http://hpc.sourceforge.net/ 更新到 gcc v.5.0 重新安装了 X
我做了这个小程序来测试,如果gfortran做尾调用消除: program tailrec implicit none print *, tailrecsum(5, 0) contains recur
我使用的是 ubuntu 12.04,gcc/g++ 4.8,gfortran 是 4.6,我重新安装了 gfortran-4.8 和 gfortran-4.8.dev,仍然没有链接。 当我尝试编译一
有没有办法格式化输出的实数,以便宽度和小数部分都未指定?只需执行以下操作,ifort 就可以做到这一点: write (*, '(F)') num ...但我知道这种用法是特定于编译器的扩展。 Gfo
我需要调试一些 pure用 gfortran 编译的程序中的函数。有什么办法可以忽略 pure声明以便我可以使用 write , print等在这些pure功能不费力? 不幸的是,要删除 pure
是否存在与 C“inline”关键字等效的 Fortran 关键字? 如果存在一些特定于编译器的关键字,gfortran 是否有? 最佳答案 一般来说,Fortran 规范为编译器编写者提供了如何实现
请参阅下面的示例 program test character(10),dimension(5):: models = (/"feddes.swp", "jarvis89.swp", "jarvi
有没有办法强制 gfortran 中的下溢清零? 我不敢相信这是第一次有人问这个问题,但我在任何地方都找不到任何相关内容。如果这是重复的,我很抱歉。 最佳答案 您可以使用支持 Fortran 2003
我在将程序链接到库时遇到问题。我以前从未这样做过,所以我可能做了一些愚蠢的事情,但据我所知,我正在做正确的事情。我需要将程序 foo.f90 链接到库 libbar.a,该库位于我的主目录下其他位置的
使用 gfortran 编译时是否可以使用实数作为迭代器和数组索引?这是一些示例代码: program test real i real testarray(5) testar
我需要一点帮助:根据this site ,最大连续行数有限制。 所以我决定对此进行测试。我编写了一个巨大的 FUNCTION ,它计算在分成 17,146 个连续行的语句中表达的巨大代数公式。 !te
考虑以下代码: subroutine tao_show_this () implicit none type b_struct integer, pointer :: good_user => n
我正在尝试使用 mac-ports (OS-X) 中的 Gfortran 4.7 编译以下简单代码: program main implicit none integer :: n = 1, cloc
我用 Fortran90 编写了一个简单的程序来计算三角形的面积。用户输入三角形的三边,然后程序输出面积。足够简单。 MODULE Triangle_Operations IMPLICIT N
我是一名优秀的程序员,十分优秀!