Optimization 在fortran中访问虚拟变量会阻止优化吗?

Optimization 在fortran中访问虚拟变量会阻止优化吗?,optimization,fortran,Optimization,Fortran,我试图优化一些fortran代码,并注意到一些我试图理解的令人惊讶的行为。progb的运行速度大约是proga的3到4倍。唯一的区别是progb中的赋值“d=2”而不是proga中的“d=b”,所以很简单,它们应该是等价的: program proga implicit none call hist(2) stop end subroutine hist(b) implicit none integer, intent(in):: b integer

我试图优化一些fortran代码,并注意到一些我试图理解的令人惊讶的行为。progb的运行速度大约是proga的3到4倍。唯一的区别是progb中的赋值“d=2”而不是proga中的“d=b”,所以很简单,它们应该是等价的:

  program proga
  implicit  none

  call hist(2)
  stop
  end

  subroutine hist(b)
  implicit  none
  integer, intent(in):: b
  integer   d,i,p(200000000)

  d = b
  do i=1,200000000
     p(i) = i/d
  end do
  write(*,*) p(1)
  end


  program progb
  implicit  none

  call hist(2)
  stop
  end

  subroutine hist(b)
  implicit  none
  integer, intent(in):: b
  integer   d,i,p(200000000)

  d = 2
  do i=1,200000000
     p(i) = i/d
  end do
  write(*,*) p(1)
  end
我用“gfortran proga.f-O3”编译,同样也用progb编译。这发生在Debian上的gcc版本4.9.2以及cygwin上的gcc版本5.4.0上

当我编译时,没有-O3标志,两者都以相同的速度运行,所以听起来编译器也不能优化proga。什么优化不能在proga上完成,为什么


我已经为这篇文章删减了我的代码(我的实际代码做了一些有用的事情!)。常量200000000应该足够大,以提供重要的运行时间。写入操作可防止循环被优化。值2是一个非常特殊的值。如果编译器知道它总是被2除,它可以只移位位,而不是进行算术计算。但是,在
progb
中,编译器必须使用任何可能的整数值进行计数,因此必须实现实除法,而不仅仅是位移位

因此,访问参数不会抑制任何优化。使用固定值可以进行某些特定的优化。特别是当它是2的幂时

检查以下位置的差异:

通用版本使用

idiv    ecx
版本除以2使用

shr     edx, 31
add     eax, edx
sar     eax
idiv
指令比移位和加法慢得多

对于非二次幂,它仍然是可优化的,但它通常还涉及乘法、加法和减法等算术运算,而不仅仅是位移位。然而,这些都比除法更快。除法是一项非常缓慢的工作


正如steve所指出的,使用
-fwhole program
可以使编译器将所有单元编译在一起,并且可以假定它不需要生成不需要的子例程


顺便说一句,对于我在上面的godbolt链接中使用的简化子例程,gfortran优化了对子例程的调用,即使没有
-fwhole程序

,感谢您的快速回复,Vladimir。因此,编译器不够聪明,不知道b在proga中总是取值2?编译器相当聪明。不幸的是,程序员并没有试图帮助编译器。尝试使子例程成为
包含
ed内部子程序,或尝试使用-fwhole程序选项
proga
hist
是独立的作用域单元。神奇的是,Steve,-fwhole程序实现了这一点,两个版本运行速度一样快。我想补充一点,没有-fwhole程序,不仅2的幂在progb中运行得更快,将d设置为大素数仍然比proga快。所以我猜编译器知道d有一个特定的值(2的幂或否),它允许编译器在没有-fwhole程序的情况下进行优化。@fredko即使对于较大的素数,它也可以很好地进行优化。但这不仅仅是一个很容易说明的位移位。它还将进行一些乘法运算,这仍然比除法快,但仍然比移位快。@steve
-fwholeprogram
做什么?你知道ifort的等价物吗?