real::r1test vs. real::r1test(1) - same but different in interfaces

real::r1test vs. real::r1test(1) - same but different in interfaces

Dear all,

I've got a huge lib in F77, which contains around 1000 subroutines. My plan was to check the interfaces to avoid unpredictable behaviour. So far so good. After turning on /warn:interfaces I get a lot of errors of the following kind:

The call of the subroutine says:

real :: r1test ! this is a scalar
! ...
call d0dummy(r1test)

The parameter in the subroutine is defined as:

subroutine d0dummy(r1test)
real::r1test(*) ! this is a assumed shape array

error #8284: If the actual argument is scalar, the dummy argument shall be scalar unless the actual argument is of type character or is an element of an array that is not assumed shape, pointer, or polymorphic. 

I know the best way would be to write interfaces or to put the routines into modules to get rid of the implicit interfaces. But this will take a lot of time I will not spend currently (something for dark cold winter days with nothing to do than playing around with old FORTRAN libs). However, if I deactivate the interface warning I get no runtime errors nor the intel inspector delivers memory leaks.

How is the warning/error ment? Can memory errors be caused by this implicit interface?

Best regards,

Johannes

11 Beiträge / 0 neu
Letzter Beitrag
Nähere Informationen zur Compiler-Optimierung finden Sie in unserem Optimierungshinweis.

IF(youDoNotDeclareInterfaces .AND. DoNotUseWarnInterfaces .AND. DoNotHaveTheSubroutineCalledVisibleToTheCaller) then
F77 interface rules apply
endif

*** However, note, the recent compilers have a default to use multi-file iInterprocedural optimizations. You may also need to turn off multi-file interprocedural optimizations (single file should be ok).

Jim Dempsey

www.quickthreadprogramming.com

What is general does "subroutine d0dummy"  do with r1test? Does is use LBOUND and UBOUND to try to determine the array limits? As it stands in the example if the suboutine trries to work with anything other than r1test(1) a world of pain  will ensue.

With this type of code it was usual in my experiance to see integer paramaters on the call containing the size of the array, in your example 1.

If you are using the bounds, then you require to pass the array descriptor, to pass the array descriptor, the interface must be known to the caller.

For your library, consider adding a new file. This file is a module containing the interfaces to your subroutines. You would then USE this module in your library .AND. distribute a copy of this module to you users such that they can USE it too (you may wish to remove internal interfaces).

Jim Dempsey

www.quickthreadprogramming.com

Note that the code is "illegal" Fortran, regardless of whether you are writing FORTRAN 77, Fortran 2008, you've got an interface or warnings or whatever.  Thou must not pass a scalar actual to an array dummy [unless ... things not relevant here, but note that if the actual argument was an array element things are ok]. If this code was under active maintenance I'd be fixing something like that (i.e. passing a scalar to an array...) pretty quick.

(One benefit of having an explicit interface is that this programming error is more likely to be caught, but if the error isn't caught, it is still an error.  Providing explicit interfaces would have reasonable priority for me (assuming I could write to later language standards), but that's a separate issue to fixing the error that the compiler happens to have caught above.)

It happens to work because of the particular [and common] implementation used by the Intel compiler.  But on other compilers (or if the Intel implementation was to change for some reason) you may not be so happy.

(The example code doesn't really look like F77.  Note also that the r1test dummy inside the d0dummy is assumed size, not assumed shape.)

Dear all,

thanks for your quick replies.

The library was written in a time when I was beginning to learn to write (1980s). I'm just happy, that I can benefit from it. :-) It is not used in a commercial code but only for research. The example I gave is not cited directly from the real code but should represent the problem simplified.

I'm glad that there are no one-dimensional arrays in a call which 'transform' to two-dimensional arrays in the called subroutine and vice versa, what I have also seen in older libs. I don't know whether this would be 'legal' FORTRAN 77?

UBOUND or LBOUND are not used and yes, the dimension of most arrays are given as a parameter also many times but not always. What I learn from your posts, that I should bite the bullet...

I recently changed character*(*) to character(len=*) to get array bounds checking into use. Let's see what interfaces will bring (Jims approach will be the one). Hopefully not to much errors but stability. Old libraries are blessing and curse, but what would we do without it...

Kind regards,

Johannes

There's no functional difference between character*(*) and character(len=*). Both will get string bounds checking. The latter is preferred syntax, however.

Steve - Intel Developer Support

@Steve

You're right. The bounds checking works for the character*(*) in the same way as for character(len=*). The reason, why this didn't work in my code, was a simple error in one array bound which was introduced before I worked on the code... It was cleaned while I changed the character definition to character(len=*) .

@all

However, I think I opened Pandora's Box. I took a very deep look into the old library and found things I wonder that the program still works. Here is one example (in parts the library uses DDOT from LINPACK (1978)):

calling subroutine

INTEGER LM,M,K, LDA
DOUBLE PRECISION A
DOUBLE PRECISION ABD(LDA,*),Z(*)
...
A=DDOT(LM,ABD(M+1,K),1,Z(K+1),1)

the called function (LM = 2 in one case):

DOUBLE PRECISION FUNCTION DDOT(N,DX,INCX,DY,INCY)
DOUBLE PRECISION :: DX(*),DY(*)
INTEGER                   :: N,INCX,INCY
...
DDOT = 0.d0
DO 10 I = 1,N
  DDOT= DDOT+ DX(IX)*DY(IY)
10 CONTINUE

If I use /warn:interfaces I got an error, that the size of ABD(M+1,K) and DX(*) are not matching, which is obvious. Was this legal in F77? Nevertheless the loops in DDOT runs from 1 to 2 and DX(2) can be addressed as well as DY(2) although the debugger shows only a scalar. Not that only higher dimensional arrays are flatted to one dimensional arrays (column-major order) but then only the first element of the vector is given through the interface like a pointer? I fear that there are so many places in my library where things like the above example are present, that I surrender. Have anybody an idea, how I can 'repair' it without rewriting the bigger part anyway?

Best regards,

Johannes

Fortran 77 did allow such a calling sequence, with implied sequence association, and it's carried over into current standards,  provided that no F90 syntax is introduced to complicate the situation.

Replacement of DDOT by dot_product would often improve efficiency (provided that you can retain the default /fp:fast option). It would involve making explicit the array sections involved.

Hi Tim,

thanks for your answer.I replaced DDOT partially by dot_product (the equal index version). /fp is set to precise because otherwise I got different result between O0 and O2/O3.

If 'implied sequence association' is still legal, is it also legal to mix integer and double precision? I fear not. I've seen many examples in my old lib where integers 'transformed' to double precision. Nevertheless it seems to work and the results are plausible. What is the compiler doing in these cases? Is the starting address pointer relevant only, so that it doesn' matter whether it is an integer or double?

For me it is a little bit magic. I do like explicit interfaces increasingly more ...

Kind regards,

Johannes

Dear all,

I've investigated 'sequence association' a little bit and found a very interesting article from Steve:

http://software.intel.com/en-us/blogs/2009/03/31/doctor-fortran-in-ive-c...

Especially the last paragraph is interesting in my case:

Let's take a simple example common to older code.

real a(10)
call sub(a(3))
...
subroutine sub (b)
real b(8)

[...]

If in the example above, array a was an assumed-shape array (might be a POINTER or ALLOCATABLE or a dummy argument itself) and you passed a(3), the compiler would give you error #6585 quoting the text from the standard shown in the previous paragraph. The workaround for an assumed-shape array would be to pass an array slice, but you can't then depend on sequence association and the dummy argument has to be no larger than the slice you passed.

Unfortunately, there are many many cases where 'a' is a assumes-shape (or -size) itself and so /warn:interface will produce an error because the Fortran standard is violated. To fix this problem all calls (around 3000 in my case) have to be adjusted. Introducing interfaces alone won't help.

By the way, /gen-interfaces:source delivers all needed interfaces. One could copy them all in one module and add this to all desired subroutines. But this will only work if your interfaces corresponds to the standard. Otherwise you get the same errors as in /warn:interfaces (different order).

IMHO steps to clean up an old lib would be:

1. Use /warn:interfaces.

2. Correct your interfaces.

3. Use /gen-interfaces:source to produce interfaces (release/debug folder), which can be copied to one module.

4. Add this module to all subroutines.

5. Remove 'external' and function definitions because otherwise conflicts with the module/interface will arise. Functions seems to have be declared only once in the module by the interface definition now. (Maybe someone can confirm/correct this?)

6. If not already done add 'implicit none' to all subroutines/functions and add missing declarations.

I finally surrender because step 2 will take weeks for me...Maybe someone find this helpful or can correct me if I'm wrong.

Best regards,

Johannes

Kommentar hinterlassen

Bitte anmelden, um einen Kommentar hinzuzufügen. Sie sind noch nicht Mitglied? Jetzt teilnehmen