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

problem with changed behavior between compiler versions when using /fpscomp:logicals

Karanta__Antti
New Contributor I
733 Views

I am working on updating the ifort compiler we use from 2011 to 2019.3 (the newest). As lots of water has flown in the Nile in the meantime, this is not straight forward. 

One issue I am facing is the different behavior of the option /fpscomp:logicals option. https://software.intel.com/en-us/fortran-compiler-developer-guide-and-reference-fpscomp

In ifort 2011, if one assigned an integer value to a logical, it retained that value. In ifort 2019 it is truncated to the last bit only.

Here's a sample program:

program logicaltest

    logical :: lg
    integer :: i
    
    i = -1
    
    lg = i
    
    if (lg == 1) then
       print *, "got one!"
    elseif (lg == 0) then
       print *, "got none!"
    else    
       print *, "something else entirely!"
    end if 
end program

 
Here's what happens with the 2011 compiler (12.1.7.371 Build 20120928)

C:\work>ifort /nologo logicaltest.f90 && logicaltest.exe
 something else entirely!

C:\work>ifort /nologo /fpscomp:logical logicaltest.f90 && logicaltest.exe
 something else entirely!

I.e. the behavior with regards to assigning an integer value to a logical variable is the same irregardless of whether one uses /fpscomp:logical

With 2019.3 (19.0.3.203 Build 20190206) this is what happens:

C:\work>ifort /nologo /fpscomp:logical logicaltest.f90 && logicaltest.exe
 got one!

C:\work>ifort /nologo logicaltest.f90 && logicaltest.exe
 something else entirely!

 
In my opinion using logical variables to store integer values just should not be done. However, I we have several million lines of source code and having found a few cases where it is done I suspect there are many more.

Not using /fpscomp:logical is not an option due to our C code relying on this notion of truth (!= 0) and false (== 0).

Thus, my question: is there a command line switch for ifort that would make it keep the integer values assigned to logicals, as it previously did?
Or, is there a way to make the compiler issue a warning (or better yet, an error) when an integer is assigned to a logical variable? That would enable me to find all the cases and fix them.

Any other ideas are also highly appreciated.
 
 
Environment: windows, producing 64 bit executable
 

0 Kudos
1 Solution
mecej4
Honored Contributor III
733 Views

For what it is worth, note that the following are not allowed in standard Fortran: (i) assigning a logical variable  an integer value and (ii) comparing a logical variable to an integer expression. In fact, given your code, Fortran Powerstation 4.00 fails to compile your program:

Microsoft (R) Fortran PowerStation  Version 4.00
Copyright (C) Microsoft Corp 1982-1995. All rights reserved.

fpslog0.f90
fpslog0.f90(10): error FOR3041: operands to relational operator .EQ. are of incompatible data type
fpslog0.f90(12): error FOR3041: operands to relational operator .EQ. are of incompatible data type

Ifort 2013SP1 as well as CVF 6.6, with or without /fpscomp:logicals, output "something else entirely!"

Any code, whether in Fortran or C, is non-portable if it relies on a specific non-zero bit pattern for .TRUE.

Instead of if (lg == 1) then, use if (lg) then; instead of if (lg == 0), use if (.not. lg) then.

You can catch instances of such misuse of logical variables by using the compiler option /stand:f95.

The effort involved in fixing your code can be considerable, but I feel that it cannot be avoided. Some day, you may be building your code with a compiler that will refuse to accept such nonstandard usage, with no option to override that refusal. 

View solution in original post

0 Kudos
7 Replies
mecej4
Honored Contributor III
734 Views

For what it is worth, note that the following are not allowed in standard Fortran: (i) assigning a logical variable  an integer value and (ii) comparing a logical variable to an integer expression. In fact, given your code, Fortran Powerstation 4.00 fails to compile your program:

Microsoft (R) Fortran PowerStation  Version 4.00
Copyright (C) Microsoft Corp 1982-1995. All rights reserved.

fpslog0.f90
fpslog0.f90(10): error FOR3041: operands to relational operator .EQ. are of incompatible data type
fpslog0.f90(12): error FOR3041: operands to relational operator .EQ. are of incompatible data type

Ifort 2013SP1 as well as CVF 6.6, with or without /fpscomp:logicals, output "something else entirely!"

Any code, whether in Fortran or C, is non-portable if it relies on a specific non-zero bit pattern for .TRUE.

Instead of if (lg == 1) then, use if (lg) then; instead of if (lg == 0), use if (.not. lg) then.

You can catch instances of such misuse of logical variables by using the compiler option /stand:f95.

The effort involved in fixing your code can be considerable, but I feel that it cannot be avoided. Some day, you may be building your code with a compiler that will refuse to accept such nonstandard usage, with no option to override that refusal. 

0 Kudos
jimdempseyatthecove
Honored Contributor III
733 Views

Additionally, when comparing logicals, say A and B, use the logical operators

IF( A .EQV. B) .... ! when same
IF( A .NEQV. B) ... ! when different

Do not use .EQ. or == or .NE. or /= as these are arithmetic operators.

If you really insist on using arithmetic operators then the "proper" way is

IF( IAND(A, 1) == IAND(B, 1)) ...

This is assuming the compiler (standards) do not complain about a logical in the intrinsic IAND.
If it does, then:

IF( IAND(TRANSFER(A, 1), 1) == IAND(TRANSFER(B,1), 1)) ...

Your choice....

Jim Dempsey
 

0 Kudos
FortranFan
Honored Contributor II
733 Views

Karanta,Antti wrote:

In my opinion using logical variables to store integer values just should not be done. ..

Thus, my question: is there a command line switch for ifort that would make it keep the integer values assigned to logicals, as it previously did?
Or, is there a way to make the compiler issue a warning (or better yet, an error) when an integer is assigned to a logical variable? That would enable me to find all the cases and fix them. ..

Have your tried /warn:stderrors with your code?

https://software.intel.com/en-us/fortran-compiler-developer-guide-and-reference-warn

C:\Temp>type x.f90
program logicaltest

    logical :: lg
    integer :: i

    i = -1

    lg = i

    if (lg == 1) then
       print *, "got one!"
    elseif (lg == 0) then
       print *, "got none!"
    else
       print *, "something else entirely!"
    end if
end program

C:\Temp>ifort /warn:stderrors x.f90
Intel(R) Visual Fortran Intel(R) 64 Compiler for applications running on Intel(R) 64, 
Version 19.0.3.203 Build 20190206
Copyright (C) 1985-2019 Intel Corporation.  All rights reserved.

ifort: command line warning #10249: /warn:stderrors sets /stand
x.f90(8): error #6192: Fortran 2003 does not allow this data type conversion.   
    lg = i
---------^
x.f90(10): error #6192: Fortran 2003 does not allow this data type conversion.   [LG]
    if (lg == 1) then
--------^
x.f90(12): error #6192: Fortran 2003 does not allow this data type conversion.   [LG]
    elseif (lg == 0) then
------------^
compilation aborted for x.f90 (code 1)

C:\Temp>

 

0 Kudos
FortranFan
Honored Contributor II
733 Views

Karanta, Antti wrote:

.. Not using /fpscomp:logical is not an option due to our C code relying on this notion of truth (!= 0) and false (== 0). ..

Any other ideas are also highly appreciated.

Will it be possible to elaborate a bit further on your C code and its relevance to Fortran code?  Is it in connection with invoking functions from one language in the other and passing data as function parameters?  Or with coding styles, etc.?

If it's the first aspect, meaning calling C from Fortran and vice versa with calling Fortran from C and exchanging data and with your last point re: "Any other ideas are also highly appreciated," you may know modern Fortran with 2018 standard revision offers enhanced capabilities for interoperation with C which is fully supported by the Intel Fortran version you've in mind for your compiler upgrade (19.0 Update 3).  Something to consider for your code if this is relevant:

https://software.intel.com/en-us/fortran-compiler-developer-guide-and-reference-standard-fortran-and-c-interoperability

 

0 Kudos
TimP
Honored Contributor III
733 Views

The standards compliance option /standard-semantics includes /fpscomp:logicals because the f2003 iso C interop specifies the interoperability of Fortran LOGICAL with C_INT if() and if(!()).. (also, by inference, C++ bool).  The usage is portable and standard with any combination of C and Fortran compilers complying with f2003.  It's a puzzle as to why ifort would still require the command line option for compliance, and the /stand option to produce a diagnostic about the non-compliant usage, particularly if the limited default equivalence of logical and integer was introduced to support PowerStation.

0 Kudos
Steve_Lionel
Honored Contributor III
733 Views

The switch is required because the DEC heritage compilers, back at least to VAX FORTRAN, used an odd/even test for true/false. Changing the default would break existing code, though I'd guess that by this time there are few programs still dependent on the VAX behavior. PowerStation used the C method (that is, fpscomp:logicals - that's why the switch is named fpscomp!)

0 Kudos
Karanta__Antti
New Contributor I
733 Views

Hi,

Thanks for all the answers and help! I was able to resovel the problem by using the following command line options to locate the offending code:

/fpscomp:logicals /stand:f18 /Qdiag-error:6192 /Qdiag-error:6188

The warnings here promoted to errors being:

"6192: Fortran 95 does not allow this data type conversion"
"6188: Fortran 2018 requires a LOGICAL data type in this context"

It took me a better part of a day to fix everything that came up. :)


To answer the questions posed:

The reason I took up our C code is due to interoperability and there being lots of calls back and forth passing all kinds of data, logicals included. Due to our long history, we have both "old school" C integration, i.e. just knowing what the functions will look like in when written in one language or another and then linking the results together and newer code using the BIND( C ), which does make things cleaner. We just have not gone through the effort of rewriting all the old code that is not using the iso c interoperability.

Thanks for all the tips on good programming practices. I very much agree with each and every one, and I think you are preaching to the choir here. :) The issue was to get a large code base containing all kinds of, well, interesting, code to work with the 2019.3 ifort compiler with minimal or at least reasonable effort.

The sample code I posted was simplified from a case I ran to in the code base, where logical variables were used to store integer values and relied to be able to do just that. A classic case of "if it is possible, someone will write code depending on it". 


And thanks Steve for sharing the history of where the name fpscomp comes from. :D


 

0 Kudos
Reply