Most users of g77
can be divided into two camps:
g77
.
g77
to compile existing, "legacy" code.
Users writing new code generally understand most of the necessary aspects of Fortran to write "mainstream" code, but often need help deciding how to handle problems, such as the construction of libraries containing `BLOCK DATA'.
Users dealing with "legacy" code sometimes don't have much
experience with Fortran, but believe that the code they're compiling
already works when compiled by other compilers (and might
not understand why, as is sometimes the case, it doesn't work
when compiled by g77
).
The following information is designed to help users do a better job coping with existing, "legacy" Fortran code, and with writing new code as well.
g77
solves a common problem.
f2c
is so great, why g77
?
These options should be used only as a quick-and-dirty way to determine how well your program will run under different compilation models without having to change the source. Some are more problematic than others, depending on how portable and maintainable you want the program to be (and, of course, whether you are allowed to change it at all is crucial).
You should not continue to use these command-line options to compile a given program, but rather should make changes to the source code:
-finit-local-zero
-fno-automatic
g77
to try
and put variables and arrays on the stack (or in fast registers)
where possible and reasonable.
This tends to make programs faster.
Note: Automatic variables and arrays are not affected
by this option.
These are variables and arrays that are necessarily automatic,
either due to explicit statements, or due to the way they are
declared.
Examples include local variables and arrays not given the
`SAVE' attribute in procedures declared `RECURSIVE',
and local arrays declared with non-constant bounds (automatic
arrays).
Currently, g77
supports only automatic arrays, not
`RECURSIVE' procedures or other means of explicitly
specifying that variables or arrays are automatic.
-fugly
-fgroup-intrinsics-hide
To ensure that block data program units are linked, especially a concern
when they are put into libraries, give each one a name (as in
`BLOCK DATA FOO') and make sure there is an `EXTERNAL FOO'
statement in every program unit that uses any common block
initialized by the corresponding `BLOCK DATA'.
g77
currently compiles a `BLOCK DATA' as if it were a
`SUBROUTINE',
that is, it generates an actual procedure having the appropriate name.
The procedure does nothing but return immediately if it happens to be
called.
For `EXTERNAL FOO', where `FOO' is not otherwise referenced in the
same program unit, g77
assumes there exists a `BLOCK DATA FOO'
in the program and ensures that by generating a
reference to it so the linker will make sure it is present.
(Specifically, g77
outputs in the data section a static pointer to the
external name `FOO'.)
The implementation g77
currently uses to make this work is
one of the few things not compatible with f2c
as currently
shipped.
f2c
currently does nothing with `EXTERNAL FOO' except
issue a warning that `FOO' is not otherwise referenced, and for
`BLOCK DATA FOO', f2c doesn't generate a dummy procedure with the
name `FOO'.
The upshot is that you shouldn't mix `f2c' and g77
in
this particular case.
If you use f2c to compile `BLOCK DATA FOO',
then any g77
-compiled program unit that says `EXTERNAL FOO'
will result in an unresolved reference when linked.
If you do the
opposite, then `FOO' might not be linked in under various
circumstances (such as when `FOO' is in a library, or you're
using a "clever" linker--so clever, it produces a broken program
with little or no warning by omitting initializations of global data
because they are contained in unreferenced procedures).
The changes you make to your code to make g77
handle this situation,
however, appear to be a widely portable way to handle it.
That is, many systems permit it (as they should, since the
FORTRAN 77 standard permits `EXTERNAL FOO' when `FOO'
is a block data program unit), and of the ones
that might not link `BLOCK DATA FOO' under some circumstances, most of
them appear to do so once `EXTERNAL FOO' is present in the appropriate
program units.
Aside from the usual `gcc' options, such as `-O', `-ffast-math', and so on, consider trying:
-fno-f2c
f2c
.
(Note that libf2c
is not an example of code
that is compiled using f2c
---it is compiled by a C
compiler, usually gcc
.)
If you're using `-fno-automatic' already, you probably should change your code to allow compilation with `-fautomatic' (the default), to allow the program to run faster.
Similarly, you should be able to use `-fno-init-local-zero' (the default) instead of `-finit-local-zero'. This is because it is rare that every variable affected by these options in a given program actually needs to be so affected.
For example, `-fno-automatic', which effectively `SAVE's every local non-automatic variable and array, affects even things like `DO' iteration variables, which rarely need to be `SAVE'd, and this often reduces run-time performances. Similarly, `-fno-init-local-zero' forces such variables to be initialized to zero--when `SAVE'd (such as when `-fno-automatic'), this by itself generally affects only startup time for a program, but when not `SAVE'd, it can slow down the procedure every time it is called.
See section Overly Convenient Command-line Options, for information on the `-fno-automatic' and `-finit-local-zero' options and how to convert their use into selective changes in your own code.
Getting Fortran programs to work in the first place can be quite a challenge--even when the programs already work on other systems, or when using other compilers.
g77
offers some options that might be useful for
tracking down bugs in such programs.
See section Option Summary, for a summary of these and other
options, and cross-references for each such option to
the pertinent material in this manual.
-finit-local-zero
-fno-automatic
-Wimplicit
-Wunused
-Wuninitialized
-Wsurprising
g77
.
Such a difference might produce actual bugs.
In any case, changing the code to explicitly do what the
programmer might have expected it to do, so g77
and
other compilers are more likely to follow the programmer's
expectations, might be worthwhile, especially if such changes
make the program work better.
-W
The meaning of a `DO' loop in Fortran is precisely specified in the Fortran standard...and is quite different from what many programmers might expect.
In particular, Fortran `DO' loops are implemented as if the number of trips through the loop is calculated before the loop is entered.
The number of trips for a loop is calculated from the start, end, and increment values specified in a statement such as:
DO iter = start, end, increment
The trip count is evaluated using a fairly simple formula based on the three values following the `=' in the statement, and it is that trip count that is effectively decremented during each iteration of the loop. If, at the beginning of an iteration of the loop, the trip count is zero or negative, the loop terminates. The per-loop-iteration modifications to iter are not related to determining whether to terminate the loop.
There are two important things to remember about the trip count:
These two items mean that there are loops that cannot be written in straightforward fashion using the Fortran `DO'.
For example, on a system with the canonical 32-bit two's-complement implementation of `INTEGER', the following loop will not work:
DO I = -2000000000, 2000000000
Although the start and end values are well within the range of `INTEGER', the trip count is not. The expected trip count is 40000000001, which is outside the range of `INTEGER' on many systems.
Instead, the above loop should be constructed this way:
I = -2000000000 DO IF (I .GT. 2000000000) EXIT ... I = I + 1 END DO
The simple `DO' construct and the `EXIT' statement
(used to leave the innermost loop)
are F90 features that g77
supports.
Some Fortran compilers have buggy implementations of `DO', in that they don't follow the standard. They implement `DO' as a straightforward translation to what, in C, would be a `for' statement. Instead of creating a temporary variable to hold the trip count as calculated at run time, these compilers use the iteration variable iter to control whether the loop continues at each iteration.
The bug in such an implementation shows up when the trip count is within the range of the type of iter, but the magnitude of `ABS(end) + ABS(incr)' exceeds that range. For example:
DO I = 2147483600, 2147483647
A loop started by the above statement will work as implemented
by g77
, but the use, by some compilers, of a
more C-like implementation akin to
for (i = 2147483600; i <= 2147483647; ++i)
produces a loop that does not terminate, because `i' can never be greater than 2147483647, since incrementing it beyond that value overflows `i', setting it to -2147483648. This is a large, negative number that still is less than 2147483647.
Another example of unexpected behavior of `DO' involves using a nonintegral iteration variable iter, such as a `REAL' or `DOUBLE PRECISION' variable. Consider the following program:
DATA BEGIN, END, STEP /.1, .31, .007/ DO 10 R = BEGIN, END, STEP IF (R .GT. END) PRINT *, R, ' .GT. ', END, '!!' PRINT *,R 10 CONTINUE PRINT *,'LAST = ',R IF (R .LE. END) PRINT *, R, ' .LE. ', END, '!!' END
A C-like view of `DO' would hold that the two "exclamatory"
`PRINT' are never executed.
However, this is the output of running the above program
as compiled by g77
on a GNU/Linux ix86 system:
.100000001 .107000001 .114 .120999999 ... .289000005 .296000004 .303000003 LAST = .310000002 .310000002 .LE. .310000002!!
Note that one of the two checks in the program turned up
an apparent violation of the programmer's expectation--yet,
the loop is correctly implemented by g77
, in that
it has 30 iterations.
This trip count of 30 is correct when evaluated using
the floating-point representations for the begin,
end, and incr values (.1, .31, .007) on GNU/Linux
ix86 are used.
On other systems, an apparently more accurate trip count
of 31 might result, but, nevertheless, g77
is
faithfully following the Fortran standard, and the result
is not what the author of the sample program above
apparently expected.
(Such other systems might, for different values in the `DATA'
statement, violate the other programmer's expectation,
for example.)
Due to this combination of imprecise representation
of floating-point values and the often-misunderstood
interpretation of `DO' by standard-conforming
compilers such as g77
, use of `DO' loops
with `REAL' or `DOUBLE PRECISION' iteration
variables is not recommended.
Such use can be caught by specifying `-Wsurprising'.
See section Options to Request or Suppress Warnings, for more information on this
option.
Without f2c
, g77
would have taken much longer to
do and probably not been as good for quite a while.
Sometimes people who notice how much g77
depends on, and
documents encouragement to use, f2c
ask why g77
was created if f2c
already existed.
This section gives some basic answers to these questions, though it is not intended to be comprehensive.
g77
offers several extensions to the Fortran language that f2c
doesn't.
However, f2c
offers a few that g77
doesn't, like
fairly complete support for `INTEGER*2'.
It is expected that g77
will offer some or all of these missing
features at some time in the future.
(Version 0.5.18 of g77
offers some rudimentary support for some
of these features.)
g77
offers a whole bunch of compiler options that f2c
doesn't.
However, f2c
offers a few that g77
doesn't, like an
option to generate code to check array subscripts at run time.
It is expected that g77
will offer some or all of these
missing options at some time in the future.
Saving the steps of writing and then rereading C code is a big reason
why g77
should be able to compile code much faster than using
f2c
in conjunction with the equivalent invocation of gcc
.
However, due to g77
's youth, lots of self-checking is still being
performed.
As a result, this improvement is as yet unrealized
(though the potential seems to be there for quite a big speedup
in the future).
It is possible that, as of version 0.5.18, g77
is noticably faster compiling many Fortran source files than using
f2c
in conjunction with gcc
.
g77
has the potential to better optimize code than f2c
,
even when gcc
is used to compile the output of f2c
,
because f2c
must necessarily
translate Fortran into a somewhat lower-level language (C) that cannot
preserve all the information that is potentially useful for optimization,
while g77
can gather, preserve, and transmit that information directly
to the GBE.
For example, g77
implements `ASSIGN' and assigned
`GOTO' using direct assignment of pointers to labels and direct
jumps to labels, whereas f2c
maps the assigned labels to
integer values and then uses a C `switch' statement to encode
the assigned `GOTO' statements.
However, as is typical, theory and reality don't quite match, at least
not in all cases, so it is still the case that f2c
plus gcc
can generate code that is faster than g77
.
It is hoped that version 0.5.18 of g77
will offer default
settings and options that allow for better program speed, though
it is not yet known whether these same options, when applied to
a gcc
compilation of f2c
output, will improve the
speed of programs compiled using that method as well.
Because g77
compiles directly to assembler code like gcc
,
instead of translating to an intermediate language (C) as does f2c
,
support for debugging can be better for g77
than f2c
.
However, although g77
might be somewhat more "native" in terms of
debugging support than f2c
plus gcc
, there still are a lot
of things "not quite right".
Many of the important ones should be resolved in the near future.
For example, g77
doesn't have to worry about reserved names
like f2c
does.
Given `FOR = WHILE', f2c
must necessarily
translate this to something other than
`for = while;', because C reserves those words.
However, g77
does still uses things like an extra level of indirection
for `ENTRY'-laden procedures--in this case, because the back end doesn't
yet support multiple entry points.
Another example is that, given
COMMON A, B EQUIVALENCE (B, C)
the g77
user should be able to access the variables directly, by name,
without having to traverse C-like structures and unions, while f2c
is unlikely to ever offer this ability (due to limitations in the
C language).
However, due to apparent bugs in the back end, g77
currently doesn't
take advantage of this facility at all--it doesn't emit any debugging
information for `COMMON' and `EQUIVALENCE' areas,
other than information
on the array of `char' it creates (and, in the case
of local `EQUIVALENCE', names) for each such area.
Yet another example is arrays.
g77
represents them to the debugger
using the same "dimensionality" as in the source code, while f2c
must necessarily convert them all to one-dimensional arrays to fit
into the confines of the C language.
However, the level of support
offered by debuggers for interactive Fortran-style access to arrays
as compiled by g77
can vary widely.
In some cases, it can actually
be an advantage that f2c
converts everything to widely supported
C semantics.
In fairness, g77
could do many of the things f2c
does
to get things working at least as well as f2c
---for now,
the maintainers have tended to prefer making g77
work the
way they think it is supposed to, and find help improving the
other products (the GBE of gcc
; gdb
; and so on)
to get things working properly.
To avoid the extensive hassle that would be needed to avoid this,
f2c
uses C character constants to encode character and Hollerith
constants.
That means a constant like `'HELLO'' is translated to
`"hello"' in C, which further means that an extra null byte is
present at the end of the constant.
This null byte is superfluous.
g77
does not generate such null bytes.
This represents significant
savings of resources, such as on systems where `/dev/null' or
`/dev/zero' represent bottlenecks in the systems' performance,
because g77
simply asks for fewer zeros from the operating
system than f2c
.
Go to the first, previous, next, last section, table of contents.