porting F77 code to the latest Intel Fortran

479 views
Skip to first unread message

Lynn McGuire

unread,
Dec 10, 2021, 7:08:47 PM12/10/21
to
I am porting our 850,000 lines of F77 code to the latest Intel Fortran.
The hidden verification of all the subroutine arguments is causing me a
lot of work. Plus this little code change got me when I back ported to
our Open Watcom F77 compiler:

double precision factor (1)
...
factor = qaunit / 5.44444d0

The calculation of factor is legal for the Intel Fortran compiler but
not on the Open Watcom F77 compiler. Is this part of the array changes
in the F90 and above compilers ?

Thanks,
Lynn

Robin Vowels

unread,
Dec 11, 2021, 1:03:33 AM12/11/21
to
.
You have not stated what the declaration of qaunit is.

John

unread,
Dec 11, 2021, 3:23:52 AM12/11/21
to
Since dimensioning an array to a size of zero or one was not defined in F77 it is likely that the dimension of 1 was using an old extension for what became the asterisk; so FACTOR is a parameter on a procedure? And since this was before array syntax was supported if FACTOR was an array then the statement FACTOR = ... makes no sense; so probably need to see more than just the QAUNIT declaration;
but what the code looked like originally as well; but it looks like you were using some really old extensions or some other information is missing.

Thomas Koenig

unread,
Dec 11, 2021, 4:13:49 AM12/11/21
to
Lynn McGuire <lynnmc...@gmail.com> schrieb:
> I am porting our 850,000 lines of F77 code to the latest Intel Fortran.
> The hidden verification of all the subroutine arguments is causing me a
> lot of work.

As it should :-)

It is usually advisable to use several compilers, and heed the
warnings from all of them. gfortran would be an obvious choice
(it's free). NAG is excellent with checking and run-time checks.

> Plus this little code change got me when I back ported to
> our Open Watcom F77 compiler:
>
> double precision factor (1)
> ...
> factor = qaunit / 5.44444d0
>
> The calculation of factor is legal for the Intel Fortran compiler but
> not on the Open Watcom F77 compiler. Is this part of the array changes
> in the F90 and above compilers ?

Assuming that quaunit is a scalar, what you write there is an
assignment statement for the whole array factor with a scalar
right-hand-side. All elements (one, in this case) of "factor"
get assigned the same value.

Perfectly legal, and this may or may not be what you intended.

Robin Vowels

unread,
Dec 11, 2021, 4:42:09 AM12/11/21
to
On Saturday, December 11, 2021 at 7:23:52 PM UTC+11, John wrote:
> Since dimensioning an array to a size of zero or one was not defined in F77
.
It's perfectly legal to define an array with one element.
.

Robin Vowels

unread,
Dec 11, 2021, 5:02:18 AM12/11/21
to
On Saturday, December 11, 2021 at 11:08:47 AM UTC+11, Lynn McGuire wrote:
.
You said that you were porting to the latest Intel compiler.
So, why are you trying to port to F77?
That assignment is not a statement that was legal in F77.
So why did you change it from F77?

Steve Lionel

unread,
Dec 11, 2021, 5:11:08 PM12/11/21
to
The question at hand is assignment of a scalar to an array. This is
legal in F90, but I can't find any words in F77 to either allow or
reject it. My guess is that this was not valid in F77. (I am assuming
that qaunit is a scalar.)

You did mention "subroutine arguments", so I think John was on the right
track when he mentioned the use of (1) as a way around bounds violations
in F66. F77 added assumed-size arrays (*), but many compilers allowed
(1) as a substitute.

--
Steve Lionel
ISO/IEC JTC1/SC22/WG5 (Fortran) Convenor
Retired Intel Fortran developer/support
Email: firstname at firstnamelastname dot com
Twitter: @DoctorFortran
LinkedIn: https://www.linkedin.com/in/stevelionel
Blog: https://stevelionel.com/drfortran
WG5: https://wg5-fortran.org

mecej4

unread,
Dec 12, 2021, 7:29:46 AM12/12/21
to
It is not clear what you mean by "porting" and "back ported". To most
people, "F77" is the language "Fortran 77"; to some, it is a compiler
such as the AT&T f77 compiler, Sun's f77 compiler, etc. At the other end
of the panoply, "Intel Fortran" is a compiler, and that compiler will
happily compile source programs that conform to Fortran 66, Fortran IV,
Fortran 77, Fortran 95, ..., Fortran 2018.

Your goal of porting to "the latest Intel Fortran" is probably not a
good choice. By the time that you finish porting a tenth of your 800,000
lines of code, there will be a different "latest Intel Fortran".

Please consider porting your code to a specific modern language
standard, such as Fortran 2008, for which several reliable compilers are
available, and do not rely on, or even tolerate, any language extensions
that the compiler may allow but you do not need.
---

Setting an array variable (i.e., without subscript) equal to a scalar
valued expression was not allowed by most Fortran 77 compilers. As Steve
Lionel pointed out, there is no explicit wording in the Fortran 77
standard that says so, but Watcom 77 (which you use), f2c (Fortran to C
translator from AT&T)and Silverfrost/Salford FTN77 reject the following
program.

program xyz
dimension a(1)
a = 2.5
print *,a
end

On the other hand, Microsoft Fortran 5.10 for MSDOS accept it. I suggest
that you use such assignments only in ported code, and not attempt to
back-port such features.

--
mecej...@nospam.invalid
(Replace four by 4, nospam by gmail, invalid by com,
and remove all underscores)

John Collins

unread,
Dec 12, 2021, 9:44:26 AM12/12/21
to
We have migrated a great deal of legacy Fortran code to modern compilers, usually gfortran or ifort. We always carry out a back-port of any modifications to the original compiler. This is sometimes essential in verifying that changes in the code have not changed the behaviour.

I agree with @mecej4 that it is desirable to migrate to a standard and not to a compiler. But sometimes legacy codes may contain language extensions which affect a large number of statements. The Intel and gfortran authors have taken great care to preserve these features. There is sometimes a strong argument to migrate to a specific compiler, at least as a first step. We recently migrated over a million lines of VMS Fortran to ifort. The VMS code used STRUCTURE, MAP and UNION. A systematic change of the records to derived types would have changed about 50,000 statements, and we would have needed to find an efficient way to implement UNION. ifort handled it very well.

By the way, we have seen standard-conforming FORTRAN 77 which will not compile under Fortran 90 and later, though these are very rare. Before someone asks, for example:

REAL NU, LAMBDA
DIMENSION NU(1000)
LAMBDA(NU) = C(ALT) / NU ! Statement function for wavelength, NU remains scalar.

I don't think this works in Fortran 2018!

John

Gary Klimowicz

unread,
Dec 13, 2021, 12:30:43 PM12/13/21
to
Steve Lionel <st...@seesignature.invalid> writes:

> The question at hand is assignment of a scalar to an array. This is
> legal in F90, but I can't find any words in F77 to either allow or
> reject it. My guess is that this was not valid in F77. (I am assuming
> that qaunit is a scalar.)

My reading of the F77 standard is that the use of "variable name" means a
scalar variable. When referring to the name of an array, they seem to
use "array name".

So in 7.1.1.1 and 7.1.1.2, when F77 refers to assignments of the form
v = e
they are referring only to scalar assignment and array element assignment.

But I wasn't there when they wrote it... :-)

Steve Lionel

unread,
Dec 13, 2021, 2:20:17 PM12/13/21
to
On 12/12/2021 9:44 AM, John Collins wrote:
> By the way, we have seen standard-conforming FORTRAN 77 which will not compile under Fortran 90 and later, though these are very rare. Before someone asks, for example:
>
> REAL NU, LAMBDA
> DIMENSION NU(1000)
> LAMBDA(NU) = C(ALT) / NU ! Statement function for wavelength, NU remains scalar.
>
> I don't think this works in Fortran 2018!

Statement functions are still part of Fortran 2018 (15.6.4), though in
the "obsolescent" category.

gah4

unread,
Dec 13, 2021, 4:01:38 PM12/13/21
to
On Sunday, December 12, 2021 at 6:44:26 AM UTC-8, john.c...@simconglobal.com wrote:

(snip)

> By the way, we have seen standard-conforming FORTRAN 77 which will not compile
> under Fortran 90 and later, though these are very rare. Before someone asks, for example:
>
> REAL NU, LAMBDA
> DIMENSION NU(1000)
> LAMBDA(NU) = C(ALT) / NU ! Statement function for wavelength, NU remains scalar.
>
> I don't think this works in Fortran 2018!

It doesn't work in the gfortran that I have.

I believe it isn't legal in Fortran 77, but reading the standard doesn't make that so obvious.

Dummy arguments in statement functions can also be variables in the program.

I don't see that it specifically allows, or disallows, them to be arrays. It does allow them to
be COMMON block names.

"The statement function dummy argument list serves only to indicate order,
number, and type of arguments for the statement function."

That might mean that rank is ignored (like implied-DO variables).

But then later:

"The name must not be used to identify any other entity in the program
unit except a common block."

OK, so can't be a SUBROUTINE or FUNCTION name. But is an array
another entity that is not allowed?


Lynn McGuire

unread,
Dec 13, 2021, 5:36:41 PM12/13/21
to
double precision qaunit
...
qaunit = some value

Lynn

Lynn McGuire

unread,
Dec 13, 2021, 5:37:46 PM12/13/21
to
Scary and not what I intended.

Lynn

Lynn McGuire

unread,
Dec 13, 2021, 5:40:21 PM12/13/21
to
We use STRUCTURE, MAP, and UNION also.

C type64 is 8 bytes, 64 bites and memory compatible with double
C precision variable and arrays
structure / type64 /
union
map
character c
end map
map
double precision d
end map
map
integer i
integer i_low
end map
map
logical l
integer l_low
end map
map
character*8 s
end map
end union
end structure

Thanks,
Lynn

mecej4

unread,
Dec 13, 2021, 8:51:47 PM12/13/21
to
On 12/13/2021 4:40 PM, Lynn McGuire wrote:
> ...
>             map
>                double precision d
>             end map
>             map
>                integer i
>                integer i_low
>             end map

There is something odd about i_low coming after i. Does your software
run on big-endian hardware? Or are you solving something similar to the
"nUxi problem"?

Lynn McGuire

unread,
Dec 13, 2021, 9:05:56 PM12/13/21
to
On 12/13/2021 7:51 PM, mecej4 wrote:
> On 12/13/2021 4:40 PM, Lynn McGuire wrote:
> > ...
>>              map
>>                 double precision d
>>              end map
>>              map
>>                 integer i
>>                 integer i_low
>>              end map
>
> There is something odd about i_low coming after i. Does your software
> run on big-endian hardware? Or are you solving something similar to the
> "nUxi problem"?

Nope, just a variant data type mapped onto a double precision array in a
Win32 app. The only time that i_low is used is to zero the entire 8 bytes.

Lynn


Lynn McGuire

unread,
Dec 13, 2021, 11:09:37 PM12/13/21
to
On 12/11/2021 3:13 AM, Thomas Koenig wrote:
BTW, thanks for verifying what I suspected !

We have not used an IDE (interactive development environment) with our
Fortran code ever so I want to use an IDE now. I tried the Simply
Fortran first but the debugger support is just too primitive for us (no
breakpoints by name, no breaking at the 5,456th call to a subroutine).
So now I am trying Intel Fortran with Visual Studio 2019.

This the third time in 15 years that I have tried to port to the Intel
Fortran compiler, the other two times were a linker crash (too many
symbols) and a failure to properly initialize all our variables to zero.

Also, we have around 20,000 lines of C and C++ with our calculation
engine so the IDE and compiler must support those.

My first time to port this code was back in 1977 IIRC when I ported us
from the Univac 1108 to the CDC 7600. It was an easy port. Since then
we have ported to 12 ? 14 ? 15 ? compilers and platforms.

Lynn

Lynn McGuire

unread,
Dec 13, 2021, 11:12:53 PM12/13/21
to
Because Watcom does not care if you send a scalar to a subroutine for a
vector of (1) whereas Intel Fortran cares very much.

And I have not finished the port to Intel Fortran and must ship patches
to customers. So the code goes into the repository and must be ported
back. Life is a circle and we move to the next station on it.

Lynn

Lynn McGuire

unread,
Dec 13, 2021, 11:19:30 PM12/13/21
to
On 12/11/2021 4:11 PM, Steve Lionel wrote:
> On 12/10/2021 7:08 PM, Lynn McGuire wrote:
>> I am porting our 850,000 lines of F77 code to the latest Intel
>> Fortran. The hidden verification of all the subroutine arguments is
>> causing me a lot of work.  Plus this little code change got me when I
>> back ported to our Open Watcom F77 compiler:
>>
>> double precision factor (1)
>> ...
>> factor = qaunit / 5.44444d0
>>
>> The calculation of factor is legal for the Intel Fortran compiler but
>> not on the Open Watcom F77 compiler.  Is this part of the array
>> changes in the F90 and above compilers ?
>
> The question at hand is assignment of a scalar to an array. This is
> legal in F90, but I can't find any words in F77 to either allow or
> reject it. My guess is that this was not valid in F77. (I am assuming
> that qaunit is a scalar.)
>
> You did mention "subroutine arguments", so I think John was on the right
> track when he mentioned the use of (1) as a way around bounds violations
> in F66. F77 added assumed-size arrays (*), but many compilers allowed
> (1) as a substitute.

F66 allowed (1) also. At least the IBM CMS and MVS compilers allowed that.

The last time I ported to the IBM mainframes was back in the early
1990s. Our host charged half the rate for the F66 compiler so we used
it whenever we could as each port cost us several thousand dollars. The
output from the F66 and F77 compilers would link perfectly so our script
kept track of that for us.

Lynn

Robin Vowels

unread,
Dec 14, 2021, 2:31:43 AM12/14/21
to
On Saturday, December 11, 2021 at 7:23:52 PM UTC+11, John wrote:
> Since dimensioning an array to a size of zero or one was not defined in F77 it is likely that the dimension of 1 was using an old extension for what became the asterisk; so FACTOR is a parameter on a procedure? And since this was before array syntax was supported if FACTOR was an array then the statement FACTOR = ... makes no sense; so probably need to see more than just the QAUNIT declaration;
.
DOUBLE PRECISION FACTOR (1)
was a way of defining a dummy argument of a subroutine or function.
.
What Lynn (and anyone needing advice) needs to show is the complete context
of the statement, including all declarations (whether implicit or explicit)
and whether used as a dummy argument, COMMON, EQUIVALENCE,
or other restriction.
.
The piece of code in question lacked declaration for QAUNIT
and any statement about dummy arguments, COMMON, etc.

> but what the code looked like originally as well; but it looks like you were
> using some really old extensions or some other information is missing.
.
Too much information was missing.

gah4

unread,
Dec 14, 2021, 3:28:34 AM12/14/21
to
On Monday, December 13, 2021 at 8:19:30 PM UTC-8, Lynn McGuire wrote:

(snip)

> F66 allowed (1) also. At least the IBM CMS and MVS compilers allowed that.

As well as I know, no version of the standard allows for dimension of (1) for
other than length one arrays. It is a side effect of not doing bounds checking.

Years ago, I was trying to run a program using this with WATFIV, where it doesn't
work. The program was doing matrix algebra, with the calling matrix (N,N), and
the dummy argument (1). You can't make it (N*N), as that wasn't (yet) legal.
I had to pass another argument with the value N*N.

Is WATFIV the only compiler that doesn't allow turning off bounds checking?

mecej4

unread,
Dec 14, 2021, 9:24:16 AM12/14/21
to
On 12/13/2021 10:12 PM, Lynn McGuire wrote:
> On 12/11/2021 4:02 AM, Robin Vowels wrote:
>> On Saturday, December 11, 2021 at 11:08:47 AM UTC+11, Lynn McGuire wrote:
>>> I am porting our 850,000 lines of F77 code to the latest Intel Fortran.
>>> The hidden verification of all the subroutine arguments is causing me a
>>> lot of work. Plus this little code change got me when I back ported to
>>> our Open Watcom F77 compiler:
>>>
>>> double precision factor (1)
>>> ...
>>> factor = qaunit / 5.44444d0
>>>
>>> The calculation of factor is legal for the Intel Fortran compiler but
>>> not on the Open Watcom F77 compiler. Is this part of the array changes
>>> in the F90 and above compilers ?
>> .
>> You said that you were porting to the latest Intel compiler.
>> So, why are you trying to port to F77?
>> That assignment is not a statement that was legal in F77.
>> So why did you change it from F77?
>
> Because Watcom does not care if you send a scalar to a subroutine for a
> vector of (1) whereas Intel Fortran cares very much.
>
> Lynn

The statement that "... Watcom does not care whereas Intel does"
requires qualification. Perhaps, you can give an example and state the
compiler options that you used. For the following example, neither
Watcom 1.9 nor Intel 2021 cares; the options I used are -BO -TR for
Watcom and /check:all for Intel.

program LMG
implicit none
integer iv(5),i
do 10 i = 1,5
iv(i) = 2*i-1
10 continue
call sub(iv,5)
print *,iv
end

subroutine sub(kv,n)
implicit none
integer i,n,kv(1) !The '(1)' is taken to be '(*)'
do 10 i=1,n
kv(i) = kv(i)/2+1
10 continue
return
end

Robin Vowels

unread,
Dec 14, 2021, 10:59:57 AM12/14/21
to
.
Try a different compiler.
Silverfrost FTN95 says that there's a subscript error at the
assignment involving array KV in subroutine SUB.
.
But why did you write such obsolete and error-prone code?
Put the subroutine SUB within program LMG, following CONTAINS,
in order than a proper interface can be generated automatically,
and define array KV in the subroutine as KV(:).
Then you don't need to include N as an argument / dummy argument.
.
Also, you don't run the risk of clobbbering the constant 5 used as
an argument (in the event that an assignment to N is made).
.
Next, you are allowed to use UBOUND in the main program
instead of the hardwired '5' in the DO statement.
.
Finally, you could have used DO / END DO in subroutine SUB,
but even better would be an array assignment KV = KV/2 + 1
that does away with the DO loop and eliminates the possibility of
introducing a subscript error for that operation.

Lynn McGuire

unread,
Dec 14, 2021, 3:43:30 PM12/14/21
to
I really have no idea what Intel Fortran compile options that I am using
are. I am just using the defaults at this time. For instance, I am
getting this error concerning this call:

double precision ddummy
...
CALL UNIVOL (DDUMMY,1,DUNIT,VOLKEY(1),VOLKEY(3),2)

Severity Code Description Project File Line Suppression State
Error 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. [VAL] C:\dii\CHM\PURCOM\tabpur.f 176

I load univol.f and find that the first argument is VAL which is defined as:

SUBROUTINE UNIVOL (VAL,N,NAMES,KEY,KSP,IGO)
integer N
double precision VAL (N)

So I will have to convert the definition of DDUMMY in tabpur.f to:

double precision ddummy (1)

Lynn

Thomas Koenig

unread,
Dec 14, 2021, 6:08:28 PM12/14/21
to
Lynn McGuire <lynnmc...@gmail.com> schrieb:

> I really have no idea what Intel Fortran compile options that I am using
> are. I am just using the defaults at this time. For instance, I am
> getting this error concerning this call:
>
> double precision ddummy
> ...
> CALL UNIVOL (DDUMMY,1,DUNIT,VOLKEY(1),VOLKEY(3),2)
>
> Severity Code Description Project File Line Suppression State
> Error 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. [VAL] C:\dii\CHM\PURCOM\tabpur.f 176
>
> I load univol.f and find that the first argument is VAL which is defined as:
>
> SUBROUTINE UNIVOL (VAL,N,NAMES,KEY,KSP,IGO)
> integer N
> double precision VAL (N)

gfortran's error messages are a bit more concise :-)

dd.f:2:20:

2 | CALL UNIVOL (DDUMMY,1,DUNIT,VOLKEY(1),VOLKEY(3),2)
| 1
Error: Rank mismatch in argument 'val' at (1) (rank-1 and scalar)

but they amount to the same thing.

> So I will have to convert the definition of DDUMMY in tabpur.f to:
>
> double precision ddummy (1)

Yes. If an array is expected, you have to pass an array or
(in this case) an array element.

A bit to the side of the issue, but what ifort's message is referring
to is the fact that

real :: a(10)
call foo(a(2),9)

subroutine foo (b,n)
integer :: n
real :: b(n)

is legal, you can then refer to the second element of a as b(1) etc
according to the rules of storage association.

Robin Vowels

unread,
Dec 14, 2021, 7:38:30 PM12/14/21
to
.
Definitely.

gah4

unread,
Dec 15, 2021, 12:10:05 AM12/15/21
to
On Tuesday, December 14, 2021 at 3:08:28 PM UTC-8, Thomas Koenig wrote:
> Lynn McGuire <lynnmc...@gmail.com> schrieb:

(snip)

> 2 | CALL UNIVOL (DDUMMY,1,DUNIT,VOLKEY(1),VOLKEY(3),2)
> | 1
> Error: Rank mismatch in argument 'val' at (1) (rank-1 and scalar)

> but they amount to the same thing.
> > So I will have to convert the definition of DDUMMY in tabpur.f to:

> > double precision ddummy (1)
> Yes. If an array is expected, you have to pass an array or
> (in this case) an array element.

You can pass an array element to a scalar or array (explicit or
assumed size) dummy argument. But a scalar can only be passed
to a scalar argument.

In the usual implementation, an address is passed.

In C, a pointer to a scalar works exactly the same as an array
dimensioned one. Partly that is related to C's call by value, and
passing a pointer when needed.

In any case, the Fortran standard doesn't allow passing a scalar to an array
dummy, dimensioned (1) or any other number. Some systems might figure
this out, others won't.

John

unread,
Dec 15, 2021, 1:04:39 AM12/15/21
to
This is touching on the biggest porting issue going from older code to modern code with interfaces, at least in my experience. Modern fortran really wants the rule to be "array to array and scalar to scalar", but because every compiler I know of pre-fortran90 allowed the same behavior as C every large code I ever modernized had this as an issue, and the exceptions like in the example are more a minimal bow to this history than a feature; so I would recommend passing a(2:) instead of a(2) above. Note that many (all that I know of) F77 compilers
would have allowed

program show
real a(10)
data a /1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0/
a=[(real(i),i=1,size(a))]
call foo(a(2),9)
call foo(10.0,1)
end

subroutine foo (b,n)
integer n
real b(n)
write(*,*)b
return
end

and if compiled in two files I still do not know of one that does not; and the ones that do catch it have a switch to allow it; and virtually everyone that ever used Fortran except for a few people on the Fortran committee would have said that was standard Fortran, but technically it never was; so if you move that subroutine to a module or a contained routine (where it automatically has an interface) or create an interface for foo you will get a mismatch; and the standard did not define an array below a size of two elements so the size of 1
was used for years to denote not checking bounds, which was later formalized as an asterisk dimension. As a result of this and some other history Fortran is now intuitively inconsistent; allowing a(2) where a(2:) would seem to be required, because trying something like
size(a(2)) would say a(2) is a scalar and not allowed; but passing a(2) in this case acts like a(2:) was passed; and it other cases a(2) will actually not work. There are lots of odd issues left over from this history. In fortran 66 array=scalar actually set the FIRST element of the array to the scalar; now it would set all elements of the array to the scalar value; and I found a bug just a few years ago that was caused by this change in Fortran behavior (the code has been in constant use from the early sixties) because the compilers used for years were still compiling it so it ran as originally intended. It sounds like your use of this F77 compiler has allowed you to carry forward some of these old behaviors and will be a real issue to port if you are not very aware of these changes, particulary in the non-standard things like arrays dimensioned to one element. I think you might first want to port to standard F77 using as many switches as possible (if any are left on the compiler you are using) to force strict adherence to F77, and use the rule of "scalar to scalar, array to array", and then port to modern Fortran. It sounds like you have a lot of non-f77-standard (even if once common) extensions to deal with. Where I work at was the first place that used Fortran outside of IBM and a lot of the codes have existed and been modernized since that time so I have done a LOT of this so this is not a casual thought but a very serious recommendation.

I funny thing is that Fortran having pre-dated C people used to talk about C passing arrays like Fortran, not the other way around :>.




Thomas Koenig

unread,
Dec 15, 2021, 1:42:07 AM12/15/21
to
John <urba...@comcast.net> schrieb:
> This is touching on the biggest porting issue going from
> older code to modern code with interfaces, at least in my
> experience. Modern fortran really wants the rule to be "array to
> array and scalar to scalar", but because every compiler I know of
> pre-fortran90 allowed the same behavior as C every large code I
> ever modernized had this as an issue, and the exceptions like in
> the example are more a minimal bow to this history than a feature;
> so I would recommend passing a(2:) instead of a(2) above.

Actually not necessary.

>Note that many (all that I know of) F77 compilers

> would have allowed
>
> program show
> real a(10)
> data a /1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0/
> a=[(real(i),i=1,size(a))]

Side remark: This is not really F77 :-)

> call foo(a(2),9)

The above is fine.

> call foo(10.0,1)

And the second call is not...

> end
>
> subroutine foo (b,n)
> integer n
> real b(n)
> write(*,*)b
> return
> end

...with this subroutine.

John

unread,
Dec 15, 2021, 2:22:47 AM12/15/21
to
Trying to write something in F77 I forgot to delete the a= line, the data statement above it was supposed to replace it. I know the second call is not standard-conforming. That was basically the point is that without an interface that runs with three compilers I tried it with and was a very common syntax I have seen in many codes from many sources that is now considered wrong, but like things like REAL*8 and dimensioning a dummy argument to one was very commonly supported, often appearing in vendor-supplied code and still in a lot of files on netlib and large code in production no matter how much it is pointed out as non-conforming; and it is one of the more tiresome things to port, as equivalence is also out of favor and you have to know the intent to know if something as kludgey as putting the scalar in square braces to pass it as an array will work, etc. it can take a lot of work to eliminate that particular usage. I was making the non-conforming call to illustrate the old common usage that is a common porting problem. I've done at least 8million lines of this, so believe me I know.

gah4

unread,
Dec 15, 2021, 3:23:26 AM12/15/21
to
On Tuesday, December 14, 2021 at 10:04:39 PM UTC-8, John wrote:
> This is touching on the biggest porting issue going from older code to modern
> code with interfaces, at least in my experience. Modern fortran really wants the
> rule to be "array to array and scalar to scalar", but because every compiler
> I know of pre-fortran90 allowed the same behavior as C every large code
> I ever modernized had this as an issue, and the exceptions like in the example
> are more a minimal bow to this history than a feature;

It has been standard since Fortran 66, and still is for assumed size dummy
arrays, that you can pass an array element, and reference element from that
one to the end of the array. (You are not supposed to use negative subscripts
and reference earlier elements.)

It won't work for assumed shape, which is recommended by many
for new code.

Assumed size also allows for passing to a different rank array, commonly
used to process a matrix, with a 1D dummy array. Many matrix routines
from the Fortran 66 days do that.

> so I would recommend passing a(2:) instead of a(2) above.
> Note that many (all that I know of) F77 compilers
> would have allowed

You want a(2:) for assumed shape, which will generate a descriptor
with the appropriate bounds, and pass those bounds.


wolfman jack

unread,
Dec 15, 2021, 4:29:27 AM12/15/21
to
You can also generate beautiful little bugs with using (1) instead of (*). If I remember correctly, I once had to use a rather large library, where a lot of arrays were declared like that. I replaced the ones that were subroutine arguments with (*), but they also used (1) in common blocks (last variable), and gfortran used that information for optimizing loops:

program whatever
! size of x depends on the problem to be solved
common /workarray/ i(100), x(2500)
...
call sub(...some arguments...)
end program

! library code
subroutine sub(....)
common /workarray/ i(100), x(1)
...
do j = 1, n
x(i) = ...
end do
end subroutine

and gfortran optimized away the loop. Compiler option -funconstrained-commons solved the problem, but a proper modernization of the code would have been much nicer. I do not know if the same happens with subroutine arguments.

John

unread,
Dec 15, 2021, 4:43:53 AM12/15/21
to
I am familiar with that, I still recommend using a(2:) unless a compiler is bad enough to make a copy because of the array syntax, as the need for upward compatibility has created a lot of inconsistencies; like requiring kind=real64 on REAL((10.0d,20.0d),kind=real64) and so
on. The risk the compiler will go a gather-scatter is real, but probably means you need a better compiler. Upward compatibility can go to
far. Taking the example back a few years ....

A little more like some old Fortran code.
Works fine with nvfortran and ifort, only
gfortran required splitting it into two
files to run.

* main
1000 0real*8 a(5),b(5),c(10)
2000 0data a /1.0, 2.0, 3.0, 4.0, 5.0/
3000 0data b /6.0, 7.0, 8.0, 9.0, 10.0/
4000 0equivalence
1 (a,c(1)),
2 (b,c(6))
5000 0calls 00 (c(2),9)
6000 0calls 01 (10.0d0,1)
6500 0calls 01 (c(2),9)
7000 0end
* subroutines
8000 0subroutines 00 (b,n)
9000 0integer n
1000 0real*8 b(1)
1 0continue
1100 0do 2i=1,n
2 0write(6,'(2HB=999F8.4,1X)')b(i)
1200 0return
1300 0entrys 01(b,n)
1400 0write(6,'(2HN=I9)')n
0goto 1
1500 0return
1600 0end

#!/bin/bash
set -x
rm -f ./a.out
#gfortran tmp.f -Wargument-mismatch
gfortran tmp1.f tmp2.f && ./a.out

rm -f ./a.out
ifort tmp.f && ./a.out

rm -f ./a.out
nvfortran tmp.f && ./a.out

B= 2.0000
B= 3.0000
B= 4.0000
B= 5.0000
B= 6.0000
B= 7.0000
B= 8.0000
B= 9.0000
B= 10.0000
N= 1
B= 10.0000
N= 9
B= 2.0000
B= 3.0000
B= 4.0000
B= 5.0000
B= 6.0000
B= 7.0000
B= 8.0000
B= 9.0000
B= 10.0000



gah4

unread,
Dec 15, 2021, 5:25:07 AM12/15/21
to
On Wednesday, December 15, 2021 at 1:29:27 AM UTC-8, wolfman jack wrote:

(snip)

> You can also generate beautiful little bugs with using (1) instead of (*).
> If I remember correctly, I once had to use a rather large library, where a lot of
> arrays were declared like that. I replaced the ones that were subroutine
> arguments with (*), but they also used (1) in common blocks (last variable),
> and gfortran used that information for optimizing loops:

> program whatever
> ! size of x depends on the problem to be solved
> common /workarray/ i(100), x(2500)
> ...
> call sub(...some arguments...)
> end program
>
> ! library code
> subroutine sub(....)
> common /workarray/ i(100), x(1)

> do j = 1, n
> x(i) = ...
> end do
> end subroutine

> and gfortran optimized away the loop. Compiler option -funconstrained-commons
> solved the problem, but a proper modernization of the code would have been
> much nicer. I do not know if the same happens with subroutine arguments.

I always forget the rules on COMMON. They are tied to EQUIVALENCE, including
the rules related to subscripts.

The only one I remember running into with (1) dimension was a compiler
doing compile-time bounds checking, even with run-time checks off.

There was a reference to X(2), which the compiler caught.
Dimension with(*) fixed that one.

I don't think (*) works for COMMON, though.


Thomas Koenig

unread,
Dec 15, 2021, 4:22:27 PM12/15/21
to
John <urba...@comcast.net> schrieb:
> I am familiar with that, I still recommend using a(2:)
> unless a compiler is bad enough to make a copy because of the
> array syntax, as the need for upward compatibility has created
> a lot of inconsistencies; like requiring kind=real64 on
> REAL((10.0d,20.0d),kind=real64) and so on.

The old syntax still works. On a modern system, you are
likely to get an IEEE 64-bit real for DOUBLE PRECISION.

> The risk the compiler will go a gather-scatter is real, but probably
> means you need a better compiler.

There is (usually) an overhead associated with assumed-shaped
arrays, for filling out the array descriptor (aka dope vector).

There are some cases where pack/repack is indeed necessary,
but compilers should be quite good at avoiding these by now.

>Upward compatibility can go to
> far. Taking the example back a few years ....
>
> A little more like some old Fortran code.
> Works fine with nvfortran and ifort, only
> gfortran required splitting it into two
> files to run.
>
> * main
> 1000 0real*8 a(5),b(5),c(10)

This code has severe formatting (and syntax) issues.
I could try to reconstruct it, but maybe you could
post a clean version?

> 2000 0data a /1.0, 2.0, 3.0, 4.0, 5.0/
> 3000 0data b /6.0, 7.0, 8.0, 9.0, 10.0/
> 4000 0equivalence
> 1 (a,c(1)),
> 2 (b,c(6))
> 5000 0calls 00 (c(2),9)

This arrives here as

"5000 0calls 00 (c(2),9)"

which makes little sense.

mecej4

unread,
Dec 15, 2021, 10:10:59 PM12/15/21
to
On 12/15/2021 3:22 PM, Thomas Koenig wrote:
> This arrives here as
>
> "5000 0calls 00 (c(2),9)"
>
> which makes little sense.

John's fixed form source code has unnecessary statement numbers, '0's in
column 6, and has non-significant blanks added in some places and
removed in other places. These features may bother humans, but the
compiler should be able to handle them.

The above statement could be written

call s00(c(2),9)

John

unread,
Dec 16, 2021, 12:54:32 AM12/16/21
to

wolfman jack

unread,
Dec 16, 2021, 5:28:18 AM12/16/21
to
I think it works with gfortran too. It does give a *warning*, not an error, and the output is what you sent.
gfortran -s -O2 -std=legacy clf_john.f -o clf_john
clf_john.f:10:16:

10 | call s01 (10.0d0,1)
| 1
Warning: Rank mismatch in argument ‘b’ at (1) (rank-1 and scalar) [-Wargument-mismatch]

./clf_john
B= 2.0000
B= 3.0000
B= 4.0000
B= 5.0000
B= 6.0000
B= 7.0000
B= 8.0000
B= 9.0000
B= 10.0000
N= 1
B= 10.0000
N= 9
B= 2.0000
B= 3.0000
B= 4.0000
B= 5.0000
B= 6.0000
B= 7.0000
B= 8.0000
B= 9.0000
B= 10.0000

I am using gfortran 9.3.0 (Ubuntu 9.3.0-17ubuntu1~20.04).

X Mecej4

unread,
Dec 16, 2021, 6:08:15 AM12/16/21
to
On Thursday, December 16, 2021 at 4:28:18 AM UTC-6, wolfman jack wrote:
>
> I think it works with gfortran too. It does give a *warning*, not an error, and the output is what you sent.
> gfortran -s -O2 -std=legacy clf_john.f -o clf_john
> clf_john.f:10:16:
>
> 10 | call s01 (10.0d0,1)
> | 1
> Warning: Rank mismatch in argument ‘b’ at (1) (rank-1 and scalar) [-Wargument-mismatch]
>

> I am using gfortran 9.3.0 (Ubuntu 9.3.0-17ubuntu1~20.04).

I think that more recent versions of Gfortran treat such argument mismatches as errors rather than as cause for issuing just warnings, so John's program will have to be compiled with the -fallow-argument-mismatch option.

John

unread,
Dec 16, 2021, 1:19:52 PM12/16/21
to
The non-standard example was actually a back-port of the original example highlighting that compilers often not only support previous standards but non-standard usage as well, which is understandable given the long history of Fortran and how in the past it was often highly extended, particularly before C and Unix emerged that makes it even harder to reliably upgrade old code without being aware of what the history of the code is (what platforms did it ever work on); which was meant to highlight why it can be important to port code to standard-conforming F77 code first (which because F77 is a subset of F90+ also means the code becomes much more portable); and lets you develop unit tests in the original environment more reliably before starting a more extensive upgrade. Even gfortran, which has become much more NAG-like in strictly applying standard conformance by default in recent releases, the code will compile without warning if the subroutine and main program are placed in separate files. I often find placing all the source in a single file as a test useful partly for this reason (especially in the past that could also give a big performance guide primarily because it allowed for more inlining and other optimizations when the compiler could "see everything"; but modern compilers are often much better about optimizing multi-file builds than in the past). Several of the features like the asterisk comment and dimensioning and real*8 were never standard as I remember it; but very very common extensions; but dimensioning to one now has a standard-conforming meaning so you really have to be careful with that one; some of the other syntax was not only a bit of a try at humor but shows how tooling you might make to automate some migration can easily run into issues if it looks for certain words like subroutine or procedure names like s00 shows in the example. I do not know if more recent compilers will ever even consider supporting some of that old syntax, but if they do some of the works in progress could give access to automatic migration tools. I think NAG has a tool that will rewrite the code; and I think that the LFortran project plans to be able to read your Fortran code in and rewrite it as standard-conforming (although it is unlikely it would automatically convert a COMMON to a MODULE) which sounds like it could be very useful in a circumstance like this. But the example was just a few mods to the original to illustrate (I thought somewhat humourously, but perhaps not) how even such a horrible little code snippet would compile with three newer-facing compilers; which is create for code longevity but horrible in other respects. At least I did not add computed GOTOs.

When I see things like 800 000, lines needed upgraded (having gone through such a painful process myself) I just wanted to note some painfully learned lessons -- try to break such a large code in libraries or modules that can be maintained and ported seperately; build unit tests for the old code so changes will get detected as early as possible; use at least three new compilers if possible; look for anything dimensioned to one and make sure you know what it was originally doing before just changing it to an asterisk; use every compiler switch you can find to at least identify any non-standard f77 usage first, and do new development with all those switches on; .... "Divide and Conquer" is still good advice, I suppose.

robin

unread,
Dec 16, 2021, 6:23:24 PM12/16/21
to

"John" <urba...@comcast.net> wrote in message
news:be2ca926-b95b-4870...@googlegroups.com...
> The non-standard example was actually a back-port of the original example highlighting that
> compilers often not only support previous standards but non-standard usage as well,
> which is understandable given the long history of Fortran and how in the past
> it was often highly extended, particularly before C and Unix emerged that
> makes it even harder to reliably upgrade old code without being aware of
> what the history of the code is (what platforms did it ever work on);
> which was meant to highlight why it can be important to port code to
> standard-conforming F77 code first
.
It's a waste of time and effort to upgrade to F77.
The first step should be to upgrade to F90 minimum,
with:
* interface blocks, with automatic checking of types of arguments and dummy aruments;
* dummy argument arrays defined in the modern form;
* free source form, which finds miss-spelled identifiers;
* generic intrinsics;
* double-precision constants properly converted;
.
and so on.
.
> (which because F77 is a subset of F90+
.
It isn't.
.
> also means the code becomes much more portable);
.
It doesn't really.
.
---
This email has been checked for viruses by Avast antivirus software.
https://www.avast.com/antivirus

Daniel Feenberg

unread,
Dec 19, 2021, 6:37:59 AM12/19/21
to
On Friday, December 10, 2021 at 7:08:47 PM UTC-5, Lynn McGuire wrote:
> I am porting our 850,000 lines of F77 code to the latest Intel Fortran.
> The hidden verification of all the subroutine arguments is causing me a
> lot of work. Plus this little code change got me when I back ported to
> our Open Watcom F77 compiler:
>
> double precision factor (1)
> ...
> factor = qaunit / 5.44444d0
>
> The calculation of factor is legal for the Intel Fortran compiler but
> not on the Open Watcom F77 compiler. Is this part of the array changes
> in the F90 and above compilers ?
>
> Thanks,
> Lynn
If you still have access to the Watcom compiler, there is a great advantage to doing the conversion on it. You can then test as you do the conversion, step by step. One you think it is compatible with the Intel compiler, you can test that. If it fails, back to Watcom for some revision and testing. Of course this means you can't start using F90+ features until you have standard F77 code and can then move the testing to Intel, but I don't think that is a big disadvantage compared to working from the start on Intel, and having no working executable until the *entire* conversion is done. Most runtime messages are pretty inscrutable. If you are working in Watcom, you will know exactly which change to the code caused the failure, and that will pinpoint the problem in a way that few diagnostics will.

Ron Shepard

unread,
Dec 19, 2021, 1:48:51 PM12/19/21
to
On 12/19/21 5:37 AM, Daniel Feenberg wrote:
> On Friday, December 10, 2021 at 7:08:47 PM UTC-5, Lynn McGuire wrote:
>> I am porting our 850,000 lines of F77 code to the latest Intel Fortran.
>> The hidden verification of all the subroutine arguments is causing me a
>> lot of work. Plus this little code change got me when I back ported to
>> our Open Watcom F77 compiler:
>>
>> double precision factor (1)
>> ...
>> factor = qaunit / 5.44444d0
>>
>> The calculation of factor is legal for the Intel Fortran compiler but
>> not on the Open Watcom F77 compiler. Is this part of the array changes
>> in the F90 and above compilers ?

As others have pointed out, this statement is legal f90+ code because of
array syntax. Assignment of a scalar to an array broadcasts that value
to all elements of the array. In this case, the dummy array has a single
element, regardless of the size of the actual array.

This is not legal f77 code, where such an assignment was undefined. The
simple change

factor(1) = qaunit / 5.44444d0

would make that statement standard conforming with f77 and every
standard thereafter.

There is a separate issue with associating a scalar actual argument with
the dummy array, factor(1). That is not legal anywhere. It works on some
compilers because they happen to pass all arguments by address. But
historically, compilers have used various ways to associate actual and
dummy arguments, and not all of those are consistent with the rank
mismatch. For example, some compilers pass the first few scalar
arguments through registers rather than by address. In that case the
actual scalar argument value would have been loaded into a register,
used directly in the register within the subprogram, and then eventually
copied back from that register into its memory location by the calling
program. The dummy declaration would have looked for an address on the
stack for that argument instead of its value in the register, so the
compiler would not have made the correct association between actual and
dummy argument. If the compiler could not detect such errors, then
syntax tools such as FTNCHEK could detect them. Contrary to some
previous statements in this thead, this was a fairly common error in
fortran codes in the 70s and 80s, and I think most programmers were
aware of the problem, they just did not have or use the tools available
to detect and correct the code. In the above case, as I understand it,
it was a recently introduced error, not a legacy error.

Then there is a further issue with associating a scalar constant or
expression with a dummy argument that is modified within the subprogram.
That is not allowed, at all, even with a scalar dummy argument. In f77,
and with f90+ when the interface is implicit, it is up to the programmer
to ensure that does not happen. Some compilers could catch such an error
at compile time if it could see the dummy argument declarations, and
some compilers could catch such an error at run time by placing the
constant in read-only memory where the subsequent modification attempt
could be detected. Some cases cannot be detected by static analysis
because the illegal modification only occurs on some calls. In f90+ if
the interface is explicit, and if intent(out) or intent(inout) are
specified, then the compiler should catch such an error at compile time.

So it appears that there were several possible errors associated with
that single statement: rank mismatches between actual and dummy
arguments, unintentional rank mismatches within the statement itself,
and mismatches of argument intent due to the lack of an explicit interface.

$.02 -Ron Shepard

gah4

unread,
Dec 20, 2021, 7:00:06 AM12/20/21
to
On Sunday, December 19, 2021 at 10:48:51 AM UTC-8, Ron Shepard wrote:

(snip)

> There is a separate issue with associating a scalar actual argument with
> the dummy array, factor(1). That is not legal anywhere. It works on some
> compilers because they happen to pass all arguments by address. But
> historically, compilers have used various ways to associate actual and
> dummy arguments, and not all of those are consistent with the rank
> mismatch. For example, some compilers pass the first few scalar
> arguments through registers rather than by address. In that case the
> actual scalar argument value would have been loaded into a register,
> used directly in the register within the subprogram, and then eventually
> copied back from that register into its memory location by the calling
> program. The dummy declaration would have looked for an address on the
> stack for that argument instead of its value in the register, so the
> compiler would not have made the correct association between actual and
> dummy argument. If the compiler could not detect such errors, then
> syntax tools such as FTNCHEK could detect them. Contrary to some
> previous statements in this thead, this was a fairly common error in
> fortran codes in the 70s and 80s, and I think most programmers were
> aware of the problem, they just did not have or use the tools available
> to detect and correct the code. In the above case, as I understand it,
> it was a recently introduced error, not a legacy error.

This is true, but do note that the standard, from Fortran 66 through the
current version, allows passing an array element to an array dummy.
(Explicit size or assumed size, but not assumed shape.)

The calling convention has to work in those cases. It also has to work
passing an array element to a scalar dummy argument.

There are some that pass both the address on the stack, and value
(or maybe address) in a register. Various ideas have been used over
the years to speed up function calls.




Lynn McGuire

unread,
Dec 20, 2021, 3:43:21 PM12/20/21
to
I am back porting to the Open Watcom compiler as I go along to pinpoint
problems that occur in the port. Plus, we release patches and numbered
releases all the time of our software which is at version 16.11c using
Open Watcom. I am only maintaining one production sandbox on my
development PC right now. Although, I do have several other sandboxes
of previous releases on my PC going back two decades for comparison
purposes.

You can get the Open Watcom C, C++, and F77 compiler at:
http://www.openwatcom.org/

Lynn

gah4

unread,
Dec 20, 2021, 8:00:34 PM12/20/21
to
On Monday, December 20, 2021 at 12:43:21 PM UTC-8, Lynn McGuire wrote:

(snip)

> You can get the Open Watcom C, C++, and F77 compiler at:
> http://www.openwatcom.org/

In the MSDOS days, Watcom (not yet open) was my favorite compiler.

And even when using the MS compiler, I used the Watcom linker, which I liked
much better. I used to run them on OS/2, for my use, and also to compile programs
for MSDOS users. The linker has an overlay feature much nicer than the MS linker.

And much earlier, WATFIV was my favorite Fortran compiler, which had Fortran 77
features in 1973, I believe testing them before the standard was written.

John Collins

unread,
Jan 28, 2022, 2:14:27 PMJan 28
to
Have you tried using either fpt or PlusFort in the migration? Either should find the problems and may fix them automatically.

We would very much like to know which issues cause the most difficulty.

Best wishes,

John

Ben Barrowes

unread,
Feb 10, 2022, 7:26:29 AMFeb 10
to
I would like to echo John Appleyard's recommendation above. PlusFort does a good job of cleaning up code and modernizing it to more modern standards, gives good diagnostics as well.

If you want to do a source to source conversion of your fortran code into matlab/octave or python, I could help with that kind of project. Refactoring all the goto's potentially littered around the code can be difficult, but I have some tools for that. Execution speed usually suffers without some effort at optimization, but you end up with source code in a language perhaps more programmers are proficient in. Something to consider.

Ben Barrowes

Thomas Koenig

unread,
Feb 10, 2022, 8:48:40 AMFeb 10
to
Ben Barrowes <benba...@gmail.com> schrieb:
> On Friday, January 28, 2022 at 2:14:27 PM UTC-5, john.c...@simconglobal.com wrote:
>> Have you tried using either fpt or PlusFort in the migration? Either should find the problems and may fix them automatically.
>>
>> We would very much like to know which issues cause the most difficulty.
>>
>> Best wishes,
>>
>> John
>
> I would like to echo John Appleyard's recommendation above. PlusFort does a good job of cleaning up code and modernizing it to more modern standards, gives good diagnostics as well.
>
> If you want to do a source to source conversion of your fortran
> code into matlab/octave or python, I could help with that kind of
> project.

Before doing this kind of thing, consider that

- With Matlab, you are committing to the vendor lock from hell

- With Python, you are committing to a highly unstable, moving
target, see
http://blog.khinsen.net/posts/2017/11/16/a-plea-for-stability-in-the-scipy-ecosystem/

All three of these versions have the drawback of abysmally slow
execution (factor of 10000 or so) if you have to specify formulas
yourself instead of using highly-optimized library calls.

Not a good idea, generally :-)

Thomas Koenig

unread,
Feb 10, 2022, 8:49:41 AMFeb 10
to
Thomas Koenig <tko...@netcologne.de> schrieb:
> Ben Barrowes <benba...@gmail.com> schrieb:
>> On Friday, January 28, 2022 at 2:14:27 PM UTC-5, john.c...@simconglobal.com wrote:
>>> Have you tried using either fpt or PlusFort in the migration? Either should find the problems and may fix them automatically.
>>>
>>> We would very much like to know which issues cause the most difficulty.
>>>
>>> Best wishes,
>>>
>>> John
>>
>> I would like to echo John Appleyard's recommendation above. PlusFort does a good job of cleaning up code and modernizing it to more modern standards, gives good diagnostics as well.
>>
>> If you want to do a source to source conversion of your fortran
>> code into matlab/octave or python, I could help with that kind of
>> project.
>
> Before doing this kind of thing, consider that
>
> - With Matlab, you are committing to the vendor lock from hell
>
> - With Python, you are committing to a highly unstable, moving
> target, see
> http://blog.khinsen.net/posts/2017/11/16/a-plea-for-stability-in-the-scipy-ecosystem/
>
> All three of these versions have the drawback of abysmally slow
> execution (factor of 10000 or so)

I have just been corrected that a factor of 100 is still realistic :-)
Reply all
Reply to author
Forward
0 new messages