Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
28815 Discussions

Threadprivate variables in equivalence statements

Bastian_B_
New Contributor I
1,314 Views

Hello,

I just upgraded to Intel Fortran Compiler which comes with Parallel Studio XE 2018 (Initial Release). This version of ifort no longer compiles this piece of code:

      SUBROUTINE MOO
      COMMON /BLOCK/ FOO 
!$OMP THREADPRIVATE (/BLOCK/)
      REAL BAR
      EQUIVALENCE ( FOO, BAR )
      RETURN
      END

$ ifort --version

ifort (IFORT) 18.0.0 20170811
Copyright (C) 1985-2017 Intel Corporation.  All rights reserved.

 

$ ifort -qopenmp -o foo -c foo.f

foo.f(2): error #7903: A variable in a THREADPRIVATE directive must not be an element of a common block or be declared in an equivalence statement.   [FOO]
     COMMON /BLOCK/ FOO  
---------------------^
compilation aborted for foo.f (code 1)

 

Now I realize that use of threadprivate variables in equivalence statements is forbidden by the OpenMP standard. It is also true that gfortran also does not compile this piece of code. However, ifort versions 17.0.4 and before did compile the above fine so it appears that ifort has gotten more strict when it comes to enforcing the standard. So apparently the only way forward is to fix the code.

But given that the real code which shows this problem in our application was written by a third party and is enormous, where the interleaving of threadprivate and equivalenced variables runs very deep this option is not really feasible, so here comes my question:

Is there a flag for ifort which makes the compiler accept the above piece of code, or is there really no way around fixing the code?

Cheers, Bastian

0 Kudos
11 Replies
Steve_Lionel
Honored Contributor III
1,314 Views

Typically in the situation where a coding error had previously gone undetected, and now is detected, there is no "flag" to back off the check. I tried to see if -diag-disable would allow disabling this error, but it would not. It is quite common for new versions to add checks for errors that previous versions missed.

0 Kudos
jimdempseyatthecove
Honored Contributor III
1,314 Views

Would using fpp and -DFOO=BAR be sufficient for a work around? (it may have too large of scope)

Jim Dempsey

0 Kudos
Bastian_B_
New Contributor I
1,314 Views

Maybe Jim, what do you have in mind?

Bastian

0 Kudos
FortranFan
Honored Contributor III
1,314 Views

Bastian B. wrote:

 .. or is there really no way around fixing the code?

How about this?

      SUBROUTINE MOO
      COMMON /BLOCK/ FOO
!$OMP THREADPRIVATE (/BLOCK/)
      CALL BOO()
      RETURN
      END
   
      SUBROUTINE BOO
      COMMON /BLOCK/ FOO
      REAL BAR
      EQUIVALENCE ( FOO, BAR )
      RETURN
      END

 

0 Kudos
jimdempseyatthecove
Honored Contributor III
1,314 Views

FF that is interesting. Not sure what will happen. My guess is you will have BLOCK declared as residing in two different segments, and thus result in a Linker error/warning about duplicate symbol.

I think the "correct" route would be:

      SUBROUTINE MOO
      COMMON /BLOCK/ FOO
!$OMP THREADPRIVATE (/BLOCK/)
      CALL BOO()
      RETURN
      END
   
      SUBROUTINE BOO
      COMMON /BLOCK/ BAR
!$OMP THREADPRIVATE (/BLOCK/)
      REAL BAR
      ...
      RETURN
      END

Though that will (may) require some edits. If the COMMON's are brought into the Fortran source via Fortran INCLUDE this might not require too much editing for Bastien.

Jim Dempsey

0 Kudos
FortranFan
Honored Contributor III
1,314 Views

jimdempseyatthecove wrote:

.. Not sure what will happen. .. I think the "correct" route would be:..

It seems like OP will then be back to square one given the need to EQUIVALENCE BAR with FOO. 

Another option for OP to try is doing away with EQUIVALENCE and use the TRANSFER intrinsic:

      SUBROUTINE MOO
      COMMON /BLOCK/ FOO
!$OMP THREADPRIVATE (/BLOCK/)
      REAL BAR
      BAR = TRANSFER( SOURCE=FOO, MOLD=BAR )
      RETURN
      END

 

0 Kudos
Lorri_M_Intel
Employee
1,314 Views

I'm not sure if the original poster is the one that contacted Intel Support, but we've been having a long discussion about this internally, and we'll have a reply shortly.

                          --Lorri

0 Kudos
jimdempseyatthecove
Honored Contributor III
1,314 Views

FortranFan,

Bastien will have to decide what works for his code.

IMHO a typical Fortran procedure uses EQUIVALENCE to repurpose locations in a COMMON block, once EQUIVALENCE'd the programmer should be obliged to follow Fortran's "Thow shalt not alias variables" rules and use the equivilance'd name throughout the procedure and NOT use the former name (in that procedure). Of potential aliases, pick one.

The #7 post will not work in most cases because BAR becomes a local variable to MOO and thus should the procedure write to BAR (or called procedure modifies /BLOCK/ FOO) the local BAR and global addresses where FOO resides have contents that are out of sync.

Jim Dempsey

0 Kudos
FortranFan
Honored Contributor III
1,314 Views

jimdempseyatthecove wrote:

.. Bastien will have to decide what works for his code. ..

The #7 post will not work in most cases because BAR becomes a local variable to MOO and thus should the procedure write to BAR (or called procedure modifies /BLOCK/ FOO) the local BAR and global addresses where FOO resides have contents that are out of sync.  ..

Indeed OP has to ultimiately figure out how to proceed, possibly have to TRANSFER back from BAR to FOO:

      SUBROUTINE MOO
      COMMON /BLOCK/ FOO
!$OMP THREADPRIVATE (/BLOCK/)
      REAL BAR
      BAR = TRANSFER( SOURCE=FOO, MOLD=BAR )
! Do work with BAR
       ..
! Transfer byte contents back to FOO
      FOO = TRANSFER( SOURCE=BAR, MOLD=FOO )
      RETURN
      END

 

 

0 Kudos
Bastian_B_
New Contributor I
1,314 Views

Thanks everyone for the suggestions, We'll see what we can do.

Lorri - No, I did not contact Intel Support before, but I am looking forward to your reply.

0 Kudos
jimdempseyatthecove
Honored Contributor III
1,314 Views

FortranFan,

That will work ... provided that subroutine MOO does not call anything before it exits that:

a) the called procedure modifies FOO (and expects the caller to observe the modification)
b) MOO modifies BAR, then calls a procedure that uses FOO

Jim Dempsey

0 Kudos
Reply