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

Runtime issues in legacy multiple entry subroutines

Alan_B_2
Beginner
1,896 Views

Hi, I am in evaluation mode of your product on Windows and OS X. I am trying to get some legacy FORTRAN IV code running and I have issues with existing multiple entry point subroutines. Here is a basic sample that has the problem I am having: 
 

       DIMENSION TEST(10),NTEST(5) 
       N=5 
       CALL TESTENTRY(N,TEST,NTEST) 
       A=2. 
       B=3. 
       C=5. 
       I=2 
       CALL ENTRY1(I,A,B,C) 
       END 

       SUBROUTINE TESTENTRY(NENT,TESTENT,NTESTENT) 
       DIMENSION TESTENT(NENT),NTESTENT(NENT+1) 
       RETURN 
       ENTRY ENTRY1(ICOUNT,A,B,C) 
       DO 10 I=1,ICOUNT 
          TESTENT(I) = A*FLOAT(I) 
          NTESTENT(I) = I 
 10   CONTINUE 
       RETURN 
       END

what happens is the program logic expects the arrays to be available under ENTRY1 but they are not available, as indicated in the debugger with a breakpoint set at the first line of the do loop.  It appears the arrays and variables available in the main entry are not available in the second entry, even the integer NENT.   Is there some flag I can set for the compiler to understand this kind of FORTRAN IV style logic?

Thanks

0 Kudos
15 Replies
mecej4
Honored Contributor III
1,896 Views

This is not a legacy, it is non-conforming code that has been passed on to you.

The Fortran manual has this under ENTRY:

"Dummy arguments can be used in ENTRY statements even if they differ in order, number, type and kind parameters, and name from the dummy arguments used in the FUNCTION, SUBROUTINE, and other ENTRY statements in the same subprogram. However, each reference to a function, subroutine, or entry must use an actual argument list that agrees in order, number, and type with the dummy argument list in the corresponding FUNCTION, SUBROUTINE, or ENTRY statement."

"Dummy arguments can be referred to only in executable statements that follow the first SUBROUTINE, FUNCTION, or ENTRY statement in which the dummy argument is specified. If a dummy argument is not currently associated with an actual argument, the dummy argument is undefined and cannot be referenced. Arguments do not retain their association from one reference of a subprogram to another."

These rules are quite sensible. Your ENTRY contains one integer and three real arguments, whereas the SUBROUTINE takes two integer and one real arguments. When you call ENTRY1, NTESTENT is neither a local variable nor a known ENTRY argument, so the code is not compilable.

Page 34 of http://www.math.utah.edu/~beebe/software/fortran-documentation/ftnsum.pdf has this interesting entry for ENTRY:

10.7.9 ENTRY statement
The ENTRY statement is a rarely used Fortran feature that permits a routine
to have multiple names and argument lists. Its use is strongly discouraged,
and its syntax will not even be shown here.

0 Kudos
Alan_B_2
Beginner
1,896 Views

Thanks, not what I wanted to hear.  I was amazed when I saw this logic in the first place.  This kind of code was supposedly running under FORTRAN IV in 1980.  I suppose the compilers then saved the arguments passed in the main call and made them available below the other entry points.  I will need to separate the routines some how with common blocks and with dimension parameters passed I suppose.  

0 Kudos
Steven_L_Intel1
Employee
1,896 Views

As mecej4 says, this isnt valid FORTRAN IV code. However, this "trick" did work in some compilers of the time as an accident of the implementation used for ENTRY. I once worked on such a compiler, VAX Fortran, but there were others then where this would not have worked.

You could use COMMON or module variables, or just pass all the arguments in the single call and get rid of ENTRY.

0 Kudos
Alan_B_2
Beginner
1,896 Views

Thanks for the reply.  Your fix should work but the call lists will be very long, and the programmer called these other entries from routines that do not have available the variables in the main call list.  It is like the programmer was hacking a pseudo block-dimensioning type thing with this logic.

I thought the VAX f77  I used in the 80's was compliant!  I guess you indicate it to have allowed some stuff not so compliant.   As far as I can tell this code was running on an IBM of the times.  There are other things this code does that makes the new compilers sing as well.    

0 Kudos
mecej4
Honored Contributor III
1,896 Views

If the original code worked properly, sanitizing it should be straightforward.

Make two copies of the old code.  In the first copy, remove the ENTRY statement and all lines of code that could only be executed when the ENTRY was called in the original code.

In the second copy, replace the SUBROUTINE statement with a SUBROUTINE statement with the former ENTRY name used as the subroutine name, and the former ENTRY argument list as the subroutine argument list. Remove all lines of code that could only be executed when the SUBROUTINE was called in the original code.

Remove any orphan declarations in the two new codes and clean up comments, if any.

the programmer called these other entries from routines that do not have available the variables in the main call list

That should not be a problem, since after the changes that I indicated you will have two separate subroutines instead of siamese twins.

0 Kudos
TimP
Honored Contributor III
1,896 Views

This was one of the pre-77 non-standard usages.  It should have worked in single threaded non-reentrant context (no RECURSIVE) if all the shared arguments were copied explicitly to and from SAVEd variables/arrays, or, as previously mentioned, copied to COMMON in compilers where COMMON stays in scope.

It would be a little disappointing if something could have been written so as to work in VAX Fortran extensions but not DEC x86 Fortran.

0 Kudos
Steven_L_Intel1
Employee
1,896 Views

VAX Fortran 77 was indeed compliant with Fortran 77. That is, if presented with a standard-conforming program it would process it as the standard specifies. The behavior being relied on here was not even a documented extension - it was taking advantage of the internal implementation of ENTRY.

0 Kudos
TimP
Honored Contributor III
1,896 Views

One of the implementations of f66 with ENTRY automatically used the same argument list as the main entry point.  These problems with ENTRY may have been reasons why f90 introduced the requirement for an option to flag non-compliant extensions, if they are accepted.  It's difficult for me to know which of those must be caught under a flag such as ifort -stand. 

0 Kudos
JVanB
Valued Contributor II
1,896 Views

You could perhaps try to save the arguments passed to subroutine TESTENTRY:

       SUBROUTINE TESTENTRY(INENT,PTESTENT,PNTESTENT)
        USE ISO_C_BINDING
        TYPE(C_PTR) PTESTENT, PNTESTENT
!DEC$ ATTRIBUTES VALUE :: PTESTENT, PNTESTENT
        SAVE TESTENT, NTESTENT, NENT
        DIMENSION TESTENT(:), NTESTENT(:)
        POINTER TESTENT, NTESTENT
        NENT = INENT
        CALL C_F_POINTER(PTESTENT,TESTENT,(/NENT/))
        CALL C_F_POINTER(PNTESTENT,NTESTENT,(/NENT+1/))
        RETURN 
        ENTRY ENTRY1(ICOUNT,A,B,C) 
        DO 10 I=1,ICOUNT 
           TESTENT(I) = A*FLOAT(I) 
           NTESTENT(I) = I 
  10   CONTINUE 
        RETURN 
        END

 

0 Kudos
Steven_L_Intel1
Employee
1,896 Views

Tim Prince wrote:

One of the implementations of f66 with ENTRY automatically used the same argument list as the main entry point.  These problems with ENTRY may have been reasons why f90 introduced the requirement for an option to flag non-compliant extensions, if they are accepted.  It's difficult for me to know which of those must be caught under a flag such as ifort -stand. 

It's not difficult at all when you see what the standard says. The relevant section of Fortran 2008 is 1.5 Conformance, but the simple rule is that if the code does not violate a numbered syntax rule or constraint, the compiler is not required to be able to report it. The restriction on ENTRY is not in a numbered syntax rule or constraint, and it can't be, because detecting this error means that the compiler has to 100% understand the control flow of the program. The restriction is on the program to not access dummy arguments except through the active entry point.

So, the only aspect of this code that the compiler is required to diagnose is the use of ENTRY itself, which is obsolescent.

0 Kudos
mecej4
Honored Contributor III
1,896 Views

One of the problems highlighted by the present code extract is that its correct functioning depends on calls being made in proper sequence.

The caller has to make a 'priming' call to TESTENTRY before calling ENTRY1. In fact, since the only executable statement of the TESTENTRY part is RETURN, the entire purpose of calling TESTENTRY is to save the argument(s) is preparation for the anticipated call to ENTRY1. RepeatOffender's solution adds executable statements to effect this 'save!' action, but that solution also depends on proper sequencing of calls.

I shudder to think of what compiler optimizations would do to this code,  in particular IPO and code inlining.

0 Kudos
Alan_B_2
Beginner
1,896 Views

Thanks for all the responses.  I have chosen a way to break these multiple entry routines apart.  All I needed was a push, and the fact that this kind of code is not supportable in the future, and all your comments set me free!  It is amazing how much spaghetti can be produced in code!  

Best wishes to all!

 

0 Kudos
jimdempseyatthecove
Honored Contributor III
1,896 Views

Mecej4 is correct, but I think the description requires expansion for better understanding.

The first call places information on the program's stack (the references and/or values).
The return from the first call leaves them there. But be mindful that the stack locations where these argument reside are now in unclaimed territory.
On the call to the ENTRY...
*** provided nothing between the calls disturbed what was formerly on the stack from the first call, such as a diagnostic PRINT ***
... the entry arguments are located on the stack, overwriting those locations on the stack formerly used on the prior call(s). Unless these ENTRY variables are intended to replace former call(s) variables, they will invalidate those other variables. This invalidation is not reported by the runtime system, other than possibly by a program crash or the program using/trashing something unintended.

The earlier compilers had to do these kinds of things because memory was at a premium. Today, it is a different story, some of these legacy characteristics have been phased out in favor of newer (desirable) features.

Mecej4, also points out that this kind of code should not be inlined (via IPO), which is default behavior now, as in doing so essentially eliminates the stack for context carryover.

Jim Dempsey

 

0 Kudos
jimdempseyatthecove
Honored Contributor III
1,896 Views

I do not think the code is relatable to spaghetti, I think it is more liken to Lasagna with carefully crafted layers of stuff you may find confusing (today). If you mess up one layer, you ruin the whole dish.

Jim Dempsey

0 Kudos
Alan_B_2
Beginner
1,896 Views

Yes the layers for the small example I sent, but the programer did things like entering in one section of code then having a goto statement to a label above the entry just executed.  I guess it worked because the return in this case was once again below the entry,  Hardly layered.  It is something I guess worked, in the past but it seems so convoluted today, or even convoluted in f77 days.  I also had to regenerate the code from an impact line printer printout photo copied who knows how many times; digital source lost or never supplied.  Lots of chopped of characters that in context are, I hope, deciphered correctly.

Thanks again for the clarifications.

 

 

0 Kudos
Reply