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

Determining if a variable was passed as a literal or a variable in a subroutine?

mford78
Beginner
1,460 Views
Is there a way to determine if, in a subroutine, a local variable was passed in as a literal or as a variable from the calling scope.

[fortran]program main_program

    implicit none

    integer :: a

    a = 2

    call foo( a)

    call foo( 3)

end program

subroutine foo( x)

    integer :: x

    ! Is there a way to do the following
    if( x passed as a literal) then
        print*, "Passed literal value", x
    elseif( x passed as a variable) then
        print*, "Passed through a variable", x
        x = x + 1
    endif

    return
end subroutine foo[/fortran]

The result of the (if it could work) program would be as follows then:
"Passed through a variable 2"
a = 3 after this call
"Passed literal value 3"

Is this at all possible? Thanks.
0 Kudos
8 Replies
mecej4
Honored Contributor III
1,460 Views
No, unless you put in such checks yourself and follow your conventions meticulously.

If there were a difference at subroutine entry between literals and variables, practically every large Fortran code in existence would stop working. With most Fortran compilers, a literal argument is handled by creating a temporary variable, assigning the literal value to that variable, and passing the temporary variable as the actual argument.

There are ways of protecting literal actual arguments from being modified by the callee, but it is best to fix the code such that this never happens.
0 Kudos
mford78
Beginner
1,460 Views
Bummer. That's pretty much what I thought, but I didn't know if there was new wizardry added to F95 or F2003 that allowed for such things. I'll try adding in an optional argument to these routines and make sure I follow my convention for now.... This is a big legacy code base and updating it to modern standards will have to occur slowly over time.

Thanks for the quick reply!
0 Kudos
anthonyrichards
New Contributor III
1,460 Views
For the simple case you give as an example, you could define
subroutine FOO(var, lit)
OPTIONAL var, lit

and call it using

Call Foo(var=A) or
Call Foo(lit=3)
and use

IF(Present(var))

or

If (Present(lit))

It all quickly gets out of hand if you have lots of arguments that can be either or.
0 Kudos
jimdempseyatthecove
Honored Contributor III
1,460 Views
This suggestion is non-portable.

The object code (I should rather say output data)produced by most compilers are multi-stream with each stream going into an entity called a segment ("segment" useddue to legacy reasons). There is typically the following segment classifications under various name: code, variable data, literal data, stack, other...

The trick (hack) is to invent some way to figure out which segment the subroutine argument resides in.

Most linkers build up the the contents of the various differentsegments in link order.

Therefore, if you have a link order of

link objhack1,prog, obja, objb, liba, libc, objhack2

and objhack1 is compiled from

integer(C_PTR) function hack1
hack1 LOC("hack1")
end function hack1

and hack2 is similar

Then if the LOC of the variable in question resides between hack1() and hack2() it resides within the static data segment.

** however

CALL FOO(1,2,3,4,5)

Will likelypass the numeric variables on stack as opposed to using an address to a numeric literal in the static data segment. Floating point constants would likely be passed by reference to a numeric literal in the static data segment.

Determination of "constantness" of integer numeric dummy variables would be problematic.

Note,

If you define and use the function/subroutine interface and USE the interface the /warn:checkinterfaces should warn if you pass a literal into an argument that is declared with INTENT(OUT) or INTENT(INOUT).

Jim Dempsey
0 Kudos
anthonyrichards
New Contributor III
1,460 Views
This program works fine. Why is it non-portable?

Module varlit
contains
subroutine foo(var,lit)
optional var, lit
integer :: var , lit

if( Present(lit)) then
print*, "Passed literal value", lit
elseif( Present(var)) then
print*, "Passed through a variable", var
var=var + 1
endif

return
end subroutine foo

end module

program main_program
use varlit
implicit none
integer :: a
a = 2
call foo( var=a)
call foo( lit=3)

end program

0 Kudos
mecej4
Honored Contributor III
1,460 Views
Supposing it could be done, what use would you have for the information? Can you cite situations where this knowledge would be very beneficial to have?
0 Kudos
jimdempseyatthecove
Honored Contributor III
1,460 Views
Anthony,

While your program is portable it does not solve the original poster's dilemma. I assume:

mford78 is the author of a subroutine that sits in a library and he is in no control of the source code of users (calls) of (to) his subroutine and therefore cannot enforce a literal flag upon the call statements. The intent of mford78 is to place defensive code into the subroutine to assert that the modifiable variables are indeed variables (not literals).

The likely best way to handle this is through an interface declaration (and required use of the interface).
In situations where an interface cannot be use then the hack presented earlier might be the only option available to at least catch calls with variables contained within the static data segment. Those literalspushed on the stack become variables and mutability of these variables would do no harm excepting where these are returning values to be used elsewhere (and are not use).

Jim Dempsey
0 Kudos
anthonyrichards
New Contributor III
1,460 Views
OK I hadn't appreciated that.
0 Kudos
Reply