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

OPTIONAL and VALUE attributes - unexpected behaviour

Alexis_R_
New Contributor I
732 Views

Ifort 13.1.2.183 Build 20130514 gives the following warning:

warning #7937: The OPTIONAL attribute should not be used for arguments with the VALUE attribute.

when compiling this code:

[fortran]module test_mod
contains
subroutine test_routine(iopt)
integer, optional, value :: iopt
if (present(iopt)) then
 print *, 'present'
else
 print *, 'absent'
endif
end subroutine
end module
program test
use test_mod
call test_routine(iopt=1)
call test_routine()
end program[/fortran]

The executable does not give the expected result:

$ ./a.out
 present
 present

(the second time the routine is called, the argument is not present, therefore the present(iopt) should be .FALSE.)

This looks like a bug to me. If the standard says that we can't have OPTIONAL and VALUE together (I haven't checked), then ifort should throw an error, not a warning. If the standard does allow it, then the implementation is buggy. FWIW, NAGfor generates an executable with the expected behaviour.

0 Kudos
10 Replies
Steven_L_Intel1
Employee
732 Views

Interesting. The standard doesn't have a restriction here.  I agree that this is a bug and will escalate it.

0 Kudos
jimdempseyatthecove
Honored Contributor III
732 Views

When passing by reference a pointer to the argument is passed. By convention, data cannot be positioned at location 0. Therefore a pointer to 0 can be used and interpreted as argument not present.

When passing integer by value, 0 is a valid value. Meaning there is no way to disambiguate present or not present. Thus the warning. What is unknown (to me) is when the subrouting has an interface with "integer, optional, value :: iopt" and the caller uses the interface and calls without an argument, then the question is: Is the value of iopt == 0 (regardless of report of test of present). If true, then reserve option value == 0 to indicate none.

Jim Dempsey

0 Kudos
Steven_L_Intel1
Employee
732 Views

I made an error in my earlier reply, since edited. The Fortran standard VALUE attribute does not necessarily mean pass-by-value. It does only if the called routine is declared as BIND(C).

Issue ID is DPD200244863.

0 Kudos
Steven_L_Intel1
Employee
732 Views

I think I need to explain more.

First of all, the Fortran VALUE attribute is not the same as !DEC$ ATTRIBUTES VALUE. For a routine that is not BIND(C), it effectively means that the called routine makes a local copy of the actual argument an any writes to it are discarded on exit. For a routine with BIND(C), it does mean pass-by-value.

In Fortran 2008, a BIND(C) routine is not allowed to have an OPTIONAL argument. There is a specification TS29113 for "Further  Interoperability of Fortran with C" that does allow for OPTIONAL arguments, but it disallows the combination of OPTIONAL and VALUE.

So in the case in question, Intel Fortran should compile this without a warning and with the correct behavior.

0 Kudos
Alexis_R_
New Contributor I
732 Views

Thanks Steve & Jim.

Steve, could you clarify the distinction you/Fortran makes between

the called routine makes a local copy of the actual argument and any writes to it are discarded on exit

and

pass-by-value

The two sound equivalent to me, so I must be missing something.

Thanks!

0 Kudos
Steven_L_Intel1
Employee
732 Views

Pass by value is when the argument list (usually on the stack or a register) contains the actual value, not the address of the value. In C it's the difference between foo(x) and foo(&x). The Fortran standard VALUE attribute, in the absence of BIND(C), doesn't change how the argument is passed, but does make the called routine copy the argument into a local and use the copy. The net effect to the caller is like pass-by-value - the thing you pass can't be changed - but the mechanism is different.

If you DO have BIND(C), then VALUE means doing it like C without the & - the argument list contains the data, not the data's address.

0 Kudos
Alexis_R_
New Contributor I
732 Views

Thanks Steve, that clears it up for me.

0 Kudos
Steven_L_Intel1
Employee
732 Views

We've fixed this for the 14.0 compiler release, due out in September, but the new behavior won't be enabled by default. We found that the change broke some of the modules we supply and we didn't have time to fix them.

For now, you will need to specify the new /assume:std_value option (or /standard-semantics) to get it so that non-BIND(C) routines with VALUE arguments have them passed by reference (and this will make OPTIONAL and PRESENT work). We also cleared up issues with specifying VALUE for arrays (ok for non-BIND(C) routines with the new option, disallowed otherwise.)

We may change the default behavior in a future release.

0 Kudos
mecej4
Honored Contributor III
732 Views

Steve,

Above (http://software.intel.com/en-us/comment/reply/393207/1737938?quote=1#comment-form), you said:

Steve Lionel wrote:
The Fortran standard VALUE attribute, in the absence of BIND(C), doesn't change how the argument is passed, but does make the called routine copy the argument into a local and use the copy. The net effect to the caller is like pass-by-value - the thing you pass can't be changed - but the mechanism is different.

I cannot reconcile this statement with what the compiler actually does. Let us restrict ourselves to scalar arguments of built-in-type, say INTEGER. The x86 as well as the x64 assembly outputs for the test program below show that, in fact, passing an argument with the VALUE attribute is implemented with pass-by-value. The x86 assembly code shows that the caller passes the value on the stack. The x64 code passes the value in the first register specified by the ABI (RDI in Linux, RCX in Windows). In both cases, the called subroutine takes the value off the stack/register. There is no creation of a local copy of the argument either in the caller or callee beyond the normal copying of the value to the stack or register according to the normal ABI conventions.

BIND(C) is not involved, I did not use any -std options in compiling to assembly.

As we know, the Fortran standard requires that an explicit interface be available to the caller for calling a subprogram one or more of whose dummy arguments have the VALUE attribute. This means that the caller as well as the callee know about the VALUE attribute. The standard does not specify the argument-passing mechanism, of course, but one needs to know the mechanism when doing mixed-language programming without recourse to ISO C-interoperability.

Please, therefore, clarify the issue.

[fortran]

program tstvalue
implicit none
integer :: a,b
!
interface
subroutine sub(v,x)
implicit none
integer, value :: v
integer, intent(out) :: x
end subroutine sub
end interface
!
a=3
call sub(a,b)
write(*,*)a,b
end program tstvalue
!
subroutine sub(v,x)
implicit none
integer, value :: v
integer, intent(out) :: x
x=v*v
v=0
return
end subroutine sub[/fortran]

Here are the assembly instructions for the subroutine (Linux IFort 13.1.163 Build 2, x64 version)

[bash]

 imull %edi, %edi 
movl %edi, (%rsi) 
ret [/bash]

Had the first argument not been passed by value, the imull instruction would be doing the meaningless operation of multiplying two addresses.

0 Kudos
Steven_L_Intel1
Employee
732 Views

The compiler currently does not implement VALUE for non-BIND(C) routines correctly. It treates VALUE the same as for BIND(C) - it passes and accepts the argument by value. That's not correct and is fixed in version 14, but only if you use the new switch.

The text of mine you quote is me explaining what the standard says - not what ifort is currently doing.

0 Kudos
Reply