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

ifx change of behavior, calls to procedure defined in EXTERNAL statement; QUESTION

Churchill
Novice
416 Views

FIRST

Here is some code which is OK

module mod1
    EXTERNAL bessel1
contains
    subroutine bigfun(i1,i2)
        integer    :: i1
        integer,value :: i2
        print *,"bigfun"
        call bessel1(16)   ! literal
        call bessel1(i1)   ! dummy
        call bessel1(i1+1) ! temporary
        call bessel1(i2)   ! dummy
end
end module mod1

!

!example external; (usually in another .f file, as is)

!Placed in this file to keep self-contained. 

subroutine bessel1( i1 )
integer i1
print *,i1
end

 

When 'bigfun' is called, eg via: 

subroutine example_main
    use mod1
    call bigfun( 17, 19 )
    print *,"hellow"
end subroutine example_main

 

we get the expected output: 

bigfun
16
17
18
19
hellow

 

SECOND

Here is some code which SEGFAULTS:

(everything else the same as the first example)

module mod1
    EXTERNAL bessel1
contains
    subroutine bigfun(i1,i2) bind(C)
        integer :: i1
        integer,value :: i2
        print *,"bigfun"
        call bessel1(16)   ! literal
        call bessel1(i1)   ! dummy
        call bessel1(i1+1) ! temporary
        call bessel1(i2)   ! dummy
end
end module mod1

 

Now, the output:

 bigfun
16
17
18
Segmentation fault

 

My understanding of ISO Fortran

1. Use of 'EXTERNAL' statement to 'import' procedures is still supported

2. In which case: the interface of such an external procedure is 'implicit' , consisting of: a list of actual argument addresses is passed to the called procedure. 

3. This implicit interface convention, the 'passing actual argument addresses', may require the complier to create temporaries, as we observe in the first (and second) example above, where the external procedure is CALLed using an integer literal, and an expression 'R-value',  I1+1

4. Again, my reading is that the nature of the thing-being-passed the EXTERNAL procedure does not change the rule that implicit interface of an EXTERNAL-statement defined procedure is  always a list of addresses (possibly via creation of temporaries if needed) .

 

Anyway, that is my take, which consistent with 'example1.f90', and with 'example2.f0' if example2.py is built using ifort.

 

The on difference between example1 and example2 is the addition of an (unused/irrelevant -- this is a pure Fortran program) attribute to the function (bigfun) within which the calls the the EXTERNAL-statement defined external procedure is made.

 

 

Two methods 'make the problem go away':

 

1. Both examples compile and run as expected via 'ifort'

2. Instead of using the EXTERNAL statement with it's implicit interface consisting of a list of addresses of its argument/dummies, an explicit interface definition is used to 'bring in' 'bessel' procedure into scope:

module mod1

    !EXTERNAL bessel1

    interface bessel1

         subroutine bessel1(i1)

         integer i1

         end

     interface i1

...

(as pointed out by jimdempseyatthecove)

 

Neither 1 nor 2 are _immediately_ available for me to follow (contact to the library provider would be necessary, or, to tear off a branch and make changes to thier source, but...)

 

Hence my question: 

 

Is Intel sure that ifx is standard-conforming with respect to the behavior 'example2'?

 

I would expect to see a text in the standard going something like: 

 

"The implicit interface to external procedures defined by an EXTERNAL statement consists of passing the addresses of the call arguments (via creation of implicit temporaries if necessary), UNLESS the call to the external procedure is being made from within a function:

1. for which the 'BIND(C)' attribute has been specified

2. AND for which one of its formal(dummy) arguments is given VALUE attribute

in which case, if such a containing-function argument appears in call to the external procedure defined by an EXTERNAL statement, then everything should be passed  by address (via creation of temporaries if necessary) except for that one argument, which should have its value passed instead into the external procedure. 

"

something like that? less wordy tho. 

I couldn't locate words to this effect in WD 1539-1, J3/23-007r1 -- but i'm still reading. 

 

Also curious if there are any explanatory code samples associated with the standard?

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

0 Kudos
5 Replies
jimdempseyatthecove
Honored Contributor III
403 Views

On one of the other threads, they had a similar problem with external (reference verses value).

While I cannot confirm this, my assumption of the behavior is:

Procedures declared without BIND(C), external has Fortran argument passing (reference)

Procedures declared with BIND(C), external has C argument passing (value)

 

Somone can experiment with this to confirm the behavior.

 

Note, as with the other thread, replacing external with a proper interface resolves the issue.

 

Jim Dempsey

0 Kudos
Churchill
Novice
335 Views

thank you for taking the time to respond

 

Ive paired the example down a bit, to exhibit: 

 

1. why HOUSE1/2 calls to 'dog(16)' both succeed, with both ifort/ifx?

2. Obviously, both know how to box a 'value', and send this to 'dog'

3. However, for the Fortran function HOUSE2 which include BIND(C), ifx (but not ifort) fails to make the necessary adjustment to the incoming argument 'i2' when calling 'dog'.

 

Note this example has nothing to do with 'C'. 

 

Thanks again

 

module mod1
    external dog
contains

subroutine HOUSE1(i1,i2)
    integer :: i1
    integer,value :: i2
    print *,"HOUSE1",i1,i2
    call dog(16)
    call dog(i1)
    call dog(i1+1)
    call dog(i2)
end

subroutine HOUSE2(i1,i2) BIND(C)
    integer :: i1
    integer,value :: i2
    print *,"HOUSE2",i1,i2
    call dog(16)
    call dog(i1)
    call dog(i1+1)
    call dog(i2)
end

end module mod1

 

!!!!!!!!!!!!!!!
!EXTERNAL, veryold, f77 .so
!placed here to be self-contained
subroutine dog( i )
    integer i
    print *,"dog",i
end

 

!!!!!!!!!!!!!!!
program main
    use mod1
    call HOUSE1( 17, 19 )
    call HOUSE2( 17, 19 )
    print *,"hellow"
end program main

!
!ifx ifxBINDC.f90; a.out
!
! HOUSE1 17 19
! dog 16
! dog 17
! dog 18
! dog 19
!
! HOUSE2 17 19
! dog 16
! dog 17
! dog 18
! forrtl: severe (174): SIGSEGV, segmentation fault occurred
! Image PC Routine Line Source
! libpthread-2.17.s 00007F0B5B1E25D0 Unknown Unknown Unknown
! a.out 0000000000404F06 Unknown Unknown Unknown
! a.out 0000000000404F7E Unknown Unknown Unknown
! a.out 0000000000404A8D Unknown Unknown Unknown
! libc-2.17.so 00007F0B5AE283D5 __libc_start_main Unknown Unknown
! a.out 00000000004049B6 Unknown Unknown Unknown
!
!

0 Kudos
jimdempseyatthecove
Honored Contributor III
304 Views

In HOUSE2, the first three calls are properly passing by reference, whereas the forth call, using an attributed value dummy i2, is apparently passing by value. This is definitely a bug.

 

Will replacing the "external dog" with a proper interface correct the problem

!dir$ if(.false.)
  external dog
!dir$ else
  interface
    subroutine dog(i)
      integer i
    end subroutine dog
  end interface
!dir$ endif

(untested code)

 

Jim Dempsey

 

0 Kudos
Churchill
Novice
297 Views

It certainly does. 

 

However, this requires me to modify (someone else's) original source, in the following: 

 

1. go through the old f90's, remove the 'external dog' lines

2. add a 'use f77prototypes' to those files

3. Now, the hard part, look through the old old .f files, fixed width fortran files. 

    a) extract only the 'argument' type definitions from the function bodies

    b) there is extensive use of '*' line continuation -- fix that, change  to & for f90

    c) dump these parts into a 'f77prototypes.f90'

 

I kinda hate doing that kinda thing tho (doesnt everyone?)

  

The original author(s) of the code had, i think, a not bad solution to grafting a C-interface onto the oldold .f files.

They made a handful of higher level 'HOUSE2' functions, which each call 1 (or more: some business logic slipped into the f90 layer) of the oldold.f functions 

 

I don't really mind doing 1,2,3 outlined above;  but it does kindof rile me that I'm only doing it because of a bug in 'ifx'. which might be temporary. 

 

The author is Elizabeth Wong, and you can see this middle layer, there: 

https://github.com/snopt/snopt-interface/blob/master/src/sqopt_wrapper.f90

 

In general, the underlying, oldold.f code is  not available (this is the UcSD/Stanford optimization library SNOPT. 

 

We have paid for that source -- so that i do know what the 'correct' interface definition should be (the 1-2-3 method above). 

 

But that's cheating! 

 

And without that source, i would have to infer the 'interface' from the usage in the 'sqopt_wrapper.f90' shim -- ugh!

 

Elizabeth Wong's method, using EXTERNAL, was sufficient to graft a subset of oldold.f Fortran source. 

 

Now we have to break that division, because ... ifx has a bug?

 

c'mon. 

 

Thank's for interest so far... 

 

 

 

 

 

What I've done is collect

 

0 Kudos
jimdempseyatthecove
Honored Contributor III
265 Views

If you remove (comment out) the external

then add the options gen-interfaces and warn-interfaces, this may do the work for you.

Also, if you add the option of fpp .AND. define macros for external and EXTERNAL to substitute "!" this might comment out the external statement without editing the source.

 

Note, the gen/warn-interface may generate errors relating to misuse in calling conventions.

 

Jim Dempsey

0 Kudos
Reply