Search code examples
fortranthread-safetyopenmpgfortran

Are loop variables in Fortran SAVEd?


I have SAVE statement in subroutine or function. Also I haven't IMPLICIT NONE. In that case are loop variables in Fortran SAVEd? Example:

FUNCTION GLOB7S(P)
      REAL LONG
      LOGICAL mess
      COMMON/iounit/konsol,mess
      COMMON/LPOLY/PLG(9,4),CTLOC,STLOC,C2TLOC,S2TLOC,C3TLOC,S3TLOC,
     $ IYR,DAY,DF,DFA,APD,APDF,APT(4),LONG
      COMMON/CSW/SW(25),ISW,SWC(25)
      DIMENSION P(100),T(14)
      SAVE
      DATA DR/1.72142E-2/,DGTR/1.74533E-2/,PSET/2./
      DATA DAYL/-1./,P32,P18,P14,P39/4*-1000./
!$OMP THREADPRIVATE(/iounit/)
!$OMP THREADPRIVATE(/LPOLY/)
!$OMP THREADPRIVATE(/CSW/)

!$OMP THREADPRIVATE(T,DR,DGTR,PSET,DAYL,P32,P18,P14,P39)
!$OMP THREADPRIVATE(CD32,CD18,CD14,CD39)
!$OMP THREADPRIVATE(T71,T72,T81,T82,TT,GLOB7S)
C       CONFIRM PARAMETER SET
      IF(P(100).EQ.0) P(100)=PSET
      IF(P(100).NE.PSET) THEN
        if(mess) WRITE(konsol,900) PSET,P(100)
  900   FORMAT(1X,'WRONG PARAMETER SET FOR GLOB7S',3F10.1)
        STOP
      ENDIF
      DO 10 J=1,14
        T(J)=0.
   10 CONTINUE
      IF(DAY.NE.DAYL.OR.P32.NE.P(32)) CD32=COS(DR*(DAY-P(32)))
      IF(DAY.NE.DAYL.OR.P18.NE.P(18)) CD18=COS(2.*DR*(DAY-P(18)))
      IF(DAY.NE.DAYL.OR.P14.NE.P(14)) CD14=COS(DR*(DAY-P(14)))
      IF(DAY.NE.DAYL.OR.P39.NE.P(39)) CD39=COS(2.*DR*(DAY-P(39)))
      DAYL=DAY
      P32=P(32)
      P18=P(18)
      P14=P(14)
      P39=P(39)
...

In this example is J SAVEd? I need to know this, because I'm trying to parallelize very old and very big Fortran code with OpenMP and I don't shure that I use THREADPRIVATE directive right.


Solution

  • A DO construct of the form of the question is not a scoping unit. Further, a "loop variable" for such a construct is not a privileged entity: it's just a variable in the scope containing the loop which is used in a particular way.

    j in this case is variable which exists before the DO construct, and it exists after the DO construct.

    That j is of implicitly declared type is not relevant: a variable which is not a construct or statement entity with implicit type exists throughout the scoping unit (and possibly others) in which the reference appears (see later). That is, the implicitly typed j here exists throughout the function, not just from the point where it appears in the DO construct.

    The SAVE statement applies to the whole (non-inclusive) scoping unit. If j is a local variable (in this case, not use- or host-associated) then the SAVE saves it.


    As Steve Lionel points out in a comment, in general, things can be much more complicated. Although not relevant to this question there are exceptions to what may otherwise be seen as blanket statements above.

    Consider the similar concepts (switching to free form code for clarity)

    integer t(10)
    
    data (t(j), integer :: j=1,10)/10*0/
    
    t = [(0, integer :: j=1,10)]
    
    forall (integer :: j=1:10) t(j) = 0
    
    do concurrent (integer :: j=1:10)
      t(j) = 0
    end do
    
    end program
    

    In each of these cases j is of the scope of the statement or DO CONCURRENT construct. The SAVE statement will not apply to these variables, because they are not then local variables of the scoping unit.

    Even without the explicit integer :: j, using implicit typing, these forms do not implicitly declare a variable outside the statement or construct.

    In other constructs, such as an ASSOCIATE construct:

    associate (a => 1+2)
    end associate
    

    the entity has the scope of the construct, but in this case we should note that the type of any construct entity is not implicit: it is exactly that of the selector rather than being based on first letter of its name.

    Finally, note that there is (currently) no such thing as

    do integer :: j=1,10
    end do
    

    which makes the normal DO construct pretty boring in this respect.