4e6a144034
From-SVN: r26519
888 lines
27 KiB
Plaintext
888 lines
27 KiB
Plaintext
@c Copyright (C) 1999 Free Software Foundation, Inc.
|
|
@c This is part of the G77 manual.
|
|
@c For copying conditions, see the file g77.texi.
|
|
|
|
@node Front End
|
|
@chapter Front End
|
|
@cindex GNU Fortran Front End (FFE)
|
|
@cindex FFE
|
|
@cindex @code{g77}, front end
|
|
@cindex front end, @code{g77}
|
|
|
|
This chapter describes some aspects of the design and implementation
|
|
of the @code{g77} front end.
|
|
|
|
@menu
|
|
* Philosophy of Code Generation::
|
|
* Two-pass Design::
|
|
* Challenges Posed::
|
|
* Transforming Statements::
|
|
* Transforming Expressions::
|
|
@end menu
|
|
|
|
@node Philosophy of Code Generation
|
|
@section Philosophy of Code Generation
|
|
|
|
Don't poke the bear.
|
|
|
|
The @code{g77} front end generates code
|
|
via the @code{gcc} back end.
|
|
|
|
@cindex GNU Back End (GBE)
|
|
@cindex GBE
|
|
@cindex @code{gcc}, back end
|
|
@cindex back end, gcc
|
|
@cindex code generator
|
|
The @code{gcc} back end (GBE) is a large, complex
|
|
labyrinth of intricate code
|
|
written in a combination of the C language
|
|
and specialized languages internal to @code{gcc}.
|
|
|
|
While the @emph{code} that implements the GBE
|
|
is written in a combination of languages,
|
|
the GBE itself is,
|
|
to the front end for a language like Fortran,
|
|
best viewed as a @emph{compiler}
|
|
that compiles its own, unique, language.
|
|
|
|
The GBE's ``source'', then, is written in this language,
|
|
which consists primarily of
|
|
a combination of calls to GBE functions
|
|
and @dfn{tree} nodes
|
|
(which are, themselves, created
|
|
by calling GBE functions).
|
|
|
|
So, the @code{g77} generates code by, in effect,
|
|
translating the Fortran code it reads
|
|
into a form ``written'' in the ``language''
|
|
of the @code{gcc} back end.
|
|
|
|
@cindex GBEL
|
|
@cindex GNU Back End Language (GBEL)
|
|
This language will heretofore be referred to as @dfn{GBEL},
|
|
for GNU Back End Language.
|
|
|
|
GBEL is an evolving language,
|
|
not fully specified in any published form
|
|
as of this writing.
|
|
It offers many facilities,
|
|
but its ``core'' facilities
|
|
are those that corresponding most directly
|
|
to those needed to support @code{gcc}
|
|
(compiling code written in GNU C).
|
|
|
|
The @code{g77} Fortran Front End (FFE)
|
|
is designed and implemented
|
|
to navigate the currents and eddies
|
|
of ongoing GBEL and @code{gcc} development
|
|
while also delivering on the potential
|
|
of an integrated FFE
|
|
(as compared to using a converter like @code{f2c}
|
|
and feeding the output into @code{gcc}).
|
|
|
|
Goals of the FFE's code-generation strategy include:
|
|
|
|
@itemize @bullet
|
|
@item
|
|
High likelihood of generation of correct code,
|
|
or, failing that, producing a fatal diagnostic or crashing.
|
|
|
|
@item
|
|
Generation of highly optimized code,
|
|
as directed by the user
|
|
via GBE-specific (versus @code{g77}-specific) constructs,
|
|
such as command-line options.
|
|
|
|
@item
|
|
Fast overall (FFE plus GBE) compilation.
|
|
|
|
@item
|
|
Preservation of source-level debugging information.
|
|
@end itemize
|
|
|
|
The strategies historically, and currently, used by the FFE
|
|
to achieve these goals include:
|
|
|
|
@itemize @bullet
|
|
@item
|
|
Use of GBEL constructs that most faithfully encapsulate
|
|
the semantics of Fortran.
|
|
|
|
@item
|
|
Avoidance of GBEL constructs that are so rarely used,
|
|
or limited to use in specialized situations not related to Fortran,
|
|
that their reliability and performance has not yet been established
|
|
as sufficient for use by the FFE.
|
|
|
|
@item
|
|
Flexible design, to readily accommodate changes to specific
|
|
code-generation strategies, perhaps governed by command-line options.
|
|
@end itemize
|
|
|
|
@cindex Bear-poking
|
|
@cindex Poking the bear
|
|
``Don't poke the bear'' somewhat summarizes the above strategies.
|
|
The GBE is the bear.
|
|
The FFE is designed and implemented to avoid poking it
|
|
in ways that are likely to just annoy it.
|
|
The FFE usually either tackles it head-on,
|
|
or avoids treating it in ways dissimilar to how
|
|
the @code{gcc} front end treats it.
|
|
|
|
For example, the FFE uses the native array facility in the back end
|
|
instead of the lower-level pointer-arithmetic facility
|
|
used by @code{gcc} when compiling @code{f2c} output).
|
|
Theoretically, this presents more opportunities for optimization,
|
|
faster compile times,
|
|
and the production of more faithful debugging information.
|
|
These benefits were not, however, immediately realized,
|
|
mainly because @code{gcc} itself makes little or no use
|
|
of the native array facility.
|
|
|
|
Complex arithmetic is a case study of the evolution of this strategy.
|
|
When originally implemented,
|
|
the GBEL had just evolved its own native complex-arithmetic facility,
|
|
so the FFE took advantage of that.
|
|
|
|
When porting @code{g77} to 64-bit systems,
|
|
it was discovered that the GBE didn't really
|
|
implement its native complex-arithmetic facility properly.
|
|
|
|
The short-term solution was to rewrite the FFE
|
|
to instead use the lower-level facilities
|
|
that'd be used by @code{gcc}-compiled code
|
|
(assuming that code, itself, didn't use the native complex type
|
|
provided, as an extension, by @code{gcc}),
|
|
since these were known to work,
|
|
and, in any case, if shown to not work,
|
|
would likely be rapidly fixed
|
|
(since they'd likely not work for vanilla C code in similar circumstances).
|
|
|
|
However, the rewrite accommodated the original, native approach as well
|
|
by offering a command-line option to select it over the emulated approach.
|
|
This allowed users, and especially GBE maintainers, to try out
|
|
fixes to complex-arithmetic support in the GBE
|
|
while @code{g77} continued to default to compiling more code correctly,
|
|
albeit producing (typically) slower executables.
|
|
|
|
As of April 1999, it appeared that the last few bugs
|
|
in the GBE's support of its native complex-arithmetic facility
|
|
were worked out.
|
|
The FFE was changed back to default to using that native facility,
|
|
leaving emulation as an option.
|
|
|
|
Other Fortran constructs---arrays, character strings,
|
|
complex division, @code{COMMON} and @code{EQUIVALENCE} aggregates,
|
|
and so on---involve issues similar to those pertaining to complex arithmetic.
|
|
|
|
So, it is possible that the history
|
|
of how the FFE handled complex arithmetic
|
|
will be repeated, probably in modified form
|
|
(and hopefully over shorter timeframes),
|
|
for some of these other facilities.
|
|
|
|
@node Two-pass Design
|
|
@section Two-pass Design
|
|
|
|
The FFE does not tell the GBE anything about a program unit
|
|
until after the last statement in that unit has been parsed.
|
|
(A program unit is a Fortran concept that corresponds, in the C world,
|
|
mostly closely to functions definitions in ISO C.
|
|
That is, a program unit in Fortran is like a top-level function in C.
|
|
Nested functions, found among the extensions offered by GNU C,
|
|
correspond roughly to Fortran's statement functions.)
|
|
|
|
So, while parsing the code in a program unit,
|
|
the FFE saves up all the information
|
|
on statements, expressions, names, and so on,
|
|
until it has seen the last statement.
|
|
|
|
At that point, the FFE revisits the saved information
|
|
(in what amounts to a second @dfn{pass} over the program unit)
|
|
to perform the actual translation of the program unit into GBEL,
|
|
ultimating in the generation of assembly code for it.
|
|
|
|
Some lookahead is performed during this second pass,
|
|
so the FFE could be viewed as a ``two-plus-pass'' design.
|
|
|
|
@menu
|
|
* Two-pass Code::
|
|
* Why Two Passes::
|
|
@end menu
|
|
|
|
@node Two-pass Code
|
|
@subsection Two-pass Code
|
|
|
|
Most of the code that turns the first pass (parsing)
|
|
into a second pass for code generation
|
|
is in @file{@value{path-g77}/std.c}.
|
|
|
|
It has external functions,
|
|
called mainly by siblings in @file{@value{path-g77}/stc.c},
|
|
that record the information on statements and expressions
|
|
in the order they are seen in the source code.
|
|
These functions save that information.
|
|
|
|
It also has an external function that revisits that information,
|
|
calling the siblings in @file{@value{path-g77}/ste.c},
|
|
which handles the actual code generation
|
|
(by generating GBEL code,
|
|
that is, by calling GBE routines
|
|
to represent and specify expressions, statements, and so on).
|
|
|
|
@node Why Two Passes
|
|
@subsection Why Two Passes
|
|
|
|
The need for two passes was not immediately evident
|
|
during the design and implementation of the code in the FFE
|
|
that was to produce GBEL.
|
|
Only after a few kludges,
|
|
to handle things like incorrectly-guessed @code{ASSIGN} label nature,
|
|
had been implemented,
|
|
did enough evidence pile up to make it clear
|
|
that @file{std.c} had to be introduced to intercept,
|
|
save, then revisit as part of a second pass,
|
|
the digested contents of a program unit.
|
|
|
|
Other such missteps have occurred during the evolution of the FFE,
|
|
because of the different goals of the FFE and the GBE.
|
|
|
|
Because the GBE's original, and still primary, goal
|
|
was to directly support the GNU C language,
|
|
the GBEL, and the GBE itself,
|
|
requires more complexity
|
|
on the part of most front ends
|
|
than it requires of @code{gcc}'s.
|
|
|
|
For example,
|
|
the GBEL offers an interface that permits the @code{gcc} front end
|
|
to implement most, or all, of the language features it supports,
|
|
without the front end having to
|
|
make use of non-user-defined variables.
|
|
(It's almost certainly the case that all of K&R C,
|
|
and probably ANSI C as well,
|
|
is handled by the @code{gcc} front end
|
|
without declaring such variables.)
|
|
|
|
The FFE, on the other hand, must resort to a variety of ``tricks''
|
|
to achieve its goals.
|
|
|
|
Consider the following C code:
|
|
|
|
@smallexample
|
|
int
|
|
foo (int a, int b)
|
|
@{
|
|
int c = 0;
|
|
|
|
if ((c = bar (c)) == 0)
|
|
goto done;
|
|
|
|
quux (c << 1);
|
|
|
|
done:
|
|
return c;
|
|
@}
|
|
@end smallexample
|
|
|
|
Note what kinds of objects are declared, or defined, before their use,
|
|
and before any actual code generation involving them
|
|
would normally take place:
|
|
|
|
@itemize @bullet
|
|
@item
|
|
Return type of function
|
|
|
|
@item
|
|
Entry point(s) of function
|
|
|
|
@item
|
|
Dummy arguments
|
|
|
|
@item
|
|
Variables
|
|
|
|
@item
|
|
Initial values for variables
|
|
@end itemize
|
|
|
|
Whereas, the following items can, and do,
|
|
suddenly appear ``out of the blue'' in C:
|
|
|
|
@itemize @bullet
|
|
@item
|
|
Label references
|
|
|
|
@item
|
|
Function references
|
|
@end itemize
|
|
|
|
Not surprisingly, the GBE faithfully permits the latter set of items
|
|
to be ``discovered'' partway through GBEL ``programs'',
|
|
just as they are permitted to in C.
|
|
|
|
Yet, the GBE has tended, at least in the past,
|
|
to be reticent to fully support similar ``late'' discovery
|
|
of items in the former set.
|
|
|
|
This makes Fortran a poor fit for the ``safe'' subset of GBEL.
|
|
Consider:
|
|
|
|
@smallexample
|
|
FUNCTION X (A, ARRAY, ID1)
|
|
CHARACTER*(*) A
|
|
DOUBLE PRECISION X, Y, Z, TMP, EE, PI
|
|
REAL ARRAY(ID1*ID2)
|
|
COMMON ID2
|
|
EXTERNAL FRED
|
|
|
|
ASSIGN 100 TO J
|
|
CALL FOO (I)
|
|
IF (I .EQ. 0) PRINT *, A(0)
|
|
GOTO 200
|
|
|
|
ENTRY Y (Z)
|
|
ASSIGN 101 TO J
|
|
200 PRINT *, A(1)
|
|
READ *, TMP
|
|
GOTO J
|
|
100 X = TMP * EE
|
|
RETURN
|
|
101 Y = TMP * PI
|
|
CALL FRED
|
|
DATA EE, PI /2.71D0, 3.14D0/
|
|
END
|
|
@end smallexample
|
|
|
|
Here are some observations about the above code,
|
|
which, while somewhat contrived,
|
|
conforms to the FORTRAN 77 and Fortran 90 standards:
|
|
|
|
@itemize @bullet
|
|
@item
|
|
The return type of function @samp{X} is not known
|
|
until the @samp{DOUBLE PRECISION} line has been parsed.
|
|
|
|
@item
|
|
Whether @samp{A} is a function or a variable
|
|
is not known until the @samp{PRINT *, A(0)} statement
|
|
has been parsed.
|
|
|
|
@item
|
|
The bounds of the array of argument @samp{ARRAY}
|
|
depend on a computation involving
|
|
the subsequent argument @samp{ID1}
|
|
and the blank-common member @samp{ID2}.
|
|
|
|
@item
|
|
Whether @samp{Y} and @samp{Z} are local variables,
|
|
additional function entry points,
|
|
or dummy arguments to additional entry points
|
|
is not known
|
|
until the @code{ENTRY} statement is parsed.
|
|
|
|
@item
|
|
Similarly, whether @samp{TMP} is a local variable is not known
|
|
until the @samp{READ *, TMP} statement is parsed.
|
|
|
|
@item
|
|
The initial values for @samp{EE} and @samp{PI}
|
|
are not known until after the @code{DATA} statement is parsed.
|
|
|
|
@item
|
|
Whether @samp{FRED} is a function returning type @code{REAL}
|
|
or a subroutine
|
|
(which can be thought of as returning type @code{void}
|
|
@emph{or}, to support alternate returns in a simple way,
|
|
type @code{int})
|
|
is not known
|
|
until the @samp{CALL FRED} statement is parsed.
|
|
|
|
@item
|
|
Whether @samp{100} is a @code{FORMAT} label
|
|
or the label of an executable statement
|
|
is not known
|
|
until the @samp{X =} statement is parsed.
|
|
(These two types of labels get @emph{very} different treatment,
|
|
especially when @code{ASSIGN}'ed.)
|
|
|
|
@item
|
|
That @samp{J} is a local variable is not known
|
|
until the first @code{ASSIGN} statement is parsed.
|
|
(This happens @emph{after} executable code has been seen.)
|
|
@end itemize
|
|
|
|
Very few of these ``discoveries''
|
|
can be accommodated by the GBE as it has evolved over the years.
|
|
The GBEL doesn't support several of them,
|
|
and those it might appear to support
|
|
don't always work properly,
|
|
especially in combination with other GBEL and GBE features,
|
|
as implemented in the GBE.
|
|
|
|
(Had the GBE and its GBEL originally evolved to support @code{g77},
|
|
the shoe would be on the other foot, so to speak---most, if not all,
|
|
of the above would be directly supported by the GBEL,
|
|
and a few C constructs would probably not, as they are in reality,
|
|
be supported.
|
|
Both this mythical, and today's real, GBE caters to its GBEL
|
|
by, sometimes, scrambling around, cleaning up after itself---after
|
|
discovering that assumptions it made earlier during code generation
|
|
are incorrect.)
|
|
|
|
So, the FFE handles these discrepancies---between the order in which
|
|
it discovers facts about the code it is compiling,
|
|
and the order in which the GBEL and GBE support such discoveries---by
|
|
performing what amounts to two
|
|
passes over each program unit.
|
|
|
|
(A few ambiguities can remain at that point,
|
|
such as whether, given @samp{EXTERNAL BAZ}
|
|
and no other reference to @samp{BAZ} in the program unit,
|
|
it is a subroutine, a function, or a block-data---which, in C-speak,
|
|
governs its declared return type.
|
|
Fortunately, these distinctions are easily finessed
|
|
for the procedure, library, and object-file interfaces
|
|
supported by @code{g77}.)
|
|
|
|
@node Challenges Posed
|
|
@section Challenges Posed
|
|
|
|
Consider the following Fortran code, which uses various extensions
|
|
(including some to Fortran 90):
|
|
|
|
@smallexample
|
|
SUBROUTINE X(A)
|
|
CHARACTER*(*) A
|
|
COMPLEX CFUNC
|
|
INTEGER*2 CLOCKS(200)
|
|
INTEGER IFUNC
|
|
|
|
CALL SYSTEM_CLOCK (CLOCKS (IFUNC (CFUNC ('('//A//')'))))
|
|
@end smallexample
|
|
|
|
The above poses the following challenges to any Fortran compiler
|
|
that uses run-time interfaces, and a run-time library, roughly similar
|
|
to those used by @code{g77}:
|
|
|
|
@itemize @bullet
|
|
@item
|
|
Assuming the library routine that supports @code{SYSTEM_CLOCK}
|
|
expects to set an @code{INTEGER*4} variable via its @code{COUNT} argument,
|
|
the compiler must make available to it a temporary variable of that type.
|
|
|
|
@item
|
|
Further, after the @code{SYSTEM_CLOCK} library routine returns,
|
|
the compiler must ensure that the temporary variable it wrote
|
|
is copied into the appropriate element of the @samp{CLOCKS} array.
|
|
(This assumes the compiler doesn't just reject the code,
|
|
which it should if it is compiling under some kind of a "strict" option.)
|
|
|
|
@item
|
|
To determine the correct index into the @samp{CLOCKS} array,
|
|
(putting aside the fact that the index, in this particular case,
|
|
need not be computed until after
|
|
the @code{SYSTEM_CLOCK} library routine returns),
|
|
the compiler must ensure that the @code{IFUNC} function is called.
|
|
|
|
That requires evaluating its argument,
|
|
which requires, for @code{g77}
|
|
(assuming @code{-ff2c} is in force),
|
|
reserving a temporary variable of type @code{COMPLEX}
|
|
for use as a repository for the return value
|
|
being computed by @samp{CFUNC}.
|
|
|
|
@item
|
|
Before invoking @samp{CFUNC},
|
|
is argument must be evaluated,
|
|
which requires allocating, at run time,
|
|
a temporary large enough to hold the result of the concatenation,
|
|
as well as actually performing the concatenation.
|
|
|
|
@item
|
|
The large temporary needed during invocation of @code{CFUNC}
|
|
should, ideally, be deallocated
|
|
(or, at least, left to the GBE to dispose of, as it sees fit)
|
|
as soon as @code{CFUNC} returns,
|
|
which means before @code{IFUNC} is called
|
|
(as it might need a lot of dynamically allocated memory).
|
|
@end itemize
|
|
|
|
@code{g77} currently doesn't support all of the above,
|
|
but, so that it might someday, it has evolved to handle
|
|
at least some of the above requirements.
|
|
|
|
Meeting the above requirements is made more challenging
|
|
by conforming to the requirements of the GBEL/GBE combination.
|
|
|
|
@node Transforming Statements
|
|
@section Transforming Statements
|
|
|
|
Most Fortran statements are given their own block,
|
|
and, for temporary variables they might need, their own scope.
|
|
(A block is what distinguishes @samp{@{ foo (); @}}
|
|
from just @samp{foo ();} in C.
|
|
A scope is included with every such block,
|
|
providing a distinct name space for local variables.)
|
|
|
|
Label definitions for the statement precede this block,
|
|
so @samp{10 PRINT *, I} is handled more like
|
|
@samp{fl10: @{ @dots{} @}} than @samp{@{ fl10: @dots{} @}}
|
|
(where @samp{fl10} is just a notation meaning ``Fortran Label 10''
|
|
for the purposes of this document).
|
|
|
|
@menu
|
|
* Statements Needing Temporaries::
|
|
* Transforming DO WHILE::
|
|
* Transforming Iterative DO::
|
|
* Transforming Block IF::
|
|
* Transforming SELECT CASE::
|
|
@end menu
|
|
|
|
@node Statements Needing Temporaries
|
|
@subsection Statements Needing Temporaries
|
|
|
|
Any temporaries needed during, but not beyond,
|
|
execution of a Fortran statement,
|
|
are made local to the scope of that statement's block.
|
|
|
|
This allows the GBE to share storage for these temporaries
|
|
among the various statements without the FFE
|
|
having to manage that itself.
|
|
|
|
(The GBE could, of course, decide to optimize
|
|
management of these temporaries.
|
|
For example, it could, theoretically,
|
|
schedule some of the computations involving these temporaries
|
|
to occur in parallel.
|
|
More practically, it might leave the storage for some temporaries
|
|
``live'' beyond their scopes, to reduce the number of
|
|
manipulations of the stack pointer at run time.)
|
|
|
|
Temporaries needed across distinct statement boundaries usually
|
|
are associated with Fortran blocks (such as @code{DO}/@code{END DO}).
|
|
(Also, there might be temporaries not associated with blocks at all---these
|
|
would be in the scope of the entire program unit.)
|
|
|
|
Each Fortran block @emph{should} get its own block/scope in the GBE.
|
|
This is best, because it allows temporaries to be more naturally handled.
|
|
However, it might pose problems when handling labels
|
|
(in particular, when they're the targets of @code{GOTO}s outside the Fortran
|
|
block), and generally just hassling with replicating
|
|
parts of the @code{gcc} front end
|
|
(because the FFE needs to support
|
|
an arbitrary number of nested back-end blocks
|
|
if each Fortran block gets one).
|
|
|
|
So, there might still be a need for top-level temporaries, whose
|
|
``owning'' scope is that of the containing procedure.
|
|
|
|
Also, there seems to be problems declaring new variables after
|
|
generating code (within a block) in the back end, leading to, e.g.,
|
|
@samp{label not defined before binding contour} or similar messages,
|
|
when compiling with @samp{-fstack-check} or
|
|
when compiling for certain targets.
|
|
|
|
Because of that, and because sometimes these temporaries are not
|
|
discovered until in the middle of of generating code for an expression
|
|
statement (as in the case of the optimization for @samp{X**I}),
|
|
it seems best to always
|
|
pre-scan all the expressions that'll be expanded for a block
|
|
before generating any of the code for that block.
|
|
|
|
This pre-scan then handles discovering and declaring, to the back end,
|
|
the temporaries needed for that block.
|
|
|
|
It's also important to treat distinct items in an I/O list as distinct
|
|
statements deserving their own blocks.
|
|
That's because there's a requirement
|
|
that each I/O item be fully processed before the next one,
|
|
which matters in cases like @samp{READ (*,*), I, A(I)}---the
|
|
element of @samp{A} read in the second item
|
|
@emph{must} be determined from the value
|
|
of @samp{I} read in the first item.
|
|
|
|
@node Transforming DO WHILE
|
|
@subsection Transforming DO WHILE
|
|
|
|
@samp{DO WHILE(expr)} @emph{must} be implemented
|
|
so that temporaries needed to evaluate @samp{expr}
|
|
are generated just for the test, each time.
|
|
|
|
Consider how @samp{DO WHILE (A//B .NE. 'END'); @dots{}; END DO} is transformed:
|
|
|
|
@smallexample
|
|
for (;;)
|
|
@{
|
|
int temp0;
|
|
|
|
@{
|
|
char temp1[large];
|
|
|
|
libg77_catenate (temp1, a, b);
|
|
temp0 = libg77_ne (temp1, 'END');
|
|
@}
|
|
|
|
if (! temp0)
|
|
break;
|
|
|
|
@dots{}
|
|
@}
|
|
@end smallexample
|
|
|
|
In this case, it seems like a time/space tradeoff
|
|
between allocating and deallocating @samp{temp1} for each iteration
|
|
and allocating it just once for the entire loop.
|
|
|
|
However, if @samp{temp1} is allocated just once for the entire loop,
|
|
it could be the wrong size for subsequent iterations of that loop
|
|
in cases like @samp{DO WHILE (A(I:J)//B .NE. 'END')},
|
|
because the body of the loop might modify @samp{I} or @samp{J}.
|
|
|
|
So, the above implementation is used,
|
|
though a more optimal one can be used
|
|
in specific circumstances.
|
|
|
|
@node Transforming Iterative DO
|
|
@subsection Transforming Iterative DO
|
|
|
|
An iterative @code{DO} loop
|
|
(one that specifies an iteration variable)
|
|
is required by the Fortran standards
|
|
to be implemented as though an iteration count
|
|
is computed before entering the loop body,
|
|
and that iteration count used to determine
|
|
the number of times the loop body is to be performed
|
|
(assuming the loop isn't cut short via @code{GOTO} or @code{EXIT}).
|
|
|
|
The FFE handles this by allocating a temporary variable
|
|
to contain the computed number of iterations.
|
|
Since this variable must be in a scope that includes the entire loop,
|
|
a GBEL block is created for that loop,
|
|
and the variable declared as belonging to the scope of that block.
|
|
|
|
@node Transforming Block IF
|
|
@subsection Transforming Block IF
|
|
|
|
Consider:
|
|
|
|
@smallexample
|
|
SUBROUTINE X(A,B,C)
|
|
CHARACTER*(*) A, B, C
|
|
LOGICAL LFUNC
|
|
|
|
IF (LFUNC (A//B)) THEN
|
|
CALL SUBR1
|
|
ELSE IF (LFUNC (A//C)) THEN
|
|
CALL SUBR2
|
|
ELSE
|
|
CALL SUBR3
|
|
END
|
|
@end smallexample
|
|
|
|
The arguments to the two calls to @samp{LFUNC}
|
|
require dynamic allocation (at run time),
|
|
but are not required during execution of the @code{CALL} statements.
|
|
|
|
So, the scopes of those temporaries must be within blocks inside
|
|
the block corresponding to the Fortran @code{IF} block.
|
|
|
|
This cannot be represented ``naturally''
|
|
in vanilla C, nor in GBEL.
|
|
The @code{if}, @code{elseif}, @code{else},
|
|
and @code{endif} constructs
|
|
provided by both languages must,
|
|
for a given @code{if} block,
|
|
share the same C/GBE block.
|
|
|
|
Therefore, any temporaries needed during evaluation of @samp{expr}
|
|
while executing @samp{ELSE IF(expr)}
|
|
must either have been predeclared
|
|
at the top of the corresponding @code{IF} block,
|
|
or declared within a new block for that @code{ELSE IF}---a block that,
|
|
since it cannot contain the @code{else} or @code{else if} itself
|
|
(due to the above requirement),
|
|
actually implements the rest of the @code{IF} block's
|
|
@code{ELSE IF} and @code{ELSE} statements
|
|
within an inner block.
|
|
|
|
The FFE takes the latter approach.
|
|
|
|
@node Transforming SELECT CASE
|
|
@subsection Transforming SELECT CASE
|
|
|
|
@code{SELECT CASE} poses a few interesting problems for code generation,
|
|
if efficiency and frugal stack management are important.
|
|
|
|
Consider @samp{SELECT CASE (I('PREFIX'//A))},
|
|
where @samp{A} is @code{CHARACTER*(*)}.
|
|
In a case like this---basically,
|
|
in any case where largish temporaries are needed
|
|
to evaluate the expression---those temporaries should
|
|
not be ``live'' during execution of any of the @code{CASE} blocks.
|
|
|
|
So, evaluation of the expression is best done within its own block,
|
|
which in turn is within the @code{SELECT CASE} block itself
|
|
(which contains the code for the CASE blocks as well,
|
|
though each within their own block).
|
|
|
|
Otherwise, we'd have the rough equivalent of this pseudo-code:
|
|
|
|
@smallexample
|
|
@{
|
|
char temp[large];
|
|
|
|
libg77_catenate (temp, 'prefix', a);
|
|
|
|
switch (i (temp))
|
|
@{
|
|
case 0:
|
|
@dots{}
|
|
@}
|
|
@}
|
|
@end smallexample
|
|
|
|
And that would leave temp[large] in scope during the CASE blocks
|
|
(although a clever back end *could* see that it isn't referenced
|
|
in them, and thus free that temp before executing the blocks).
|
|
|
|
So this approach is used instead:
|
|
|
|
@smallexample
|
|
@{
|
|
int temp0;
|
|
|
|
@{
|
|
char temp1[large];
|
|
|
|
libg77_catenate (temp1, 'prefix', a);
|
|
temp0 = i (temp1);
|
|
@}
|
|
|
|
switch (temp0)
|
|
@{
|
|
case 0:
|
|
@dots{}
|
|
@}
|
|
@}
|
|
@end smallexample
|
|
|
|
Note how @samp{temp1} goes out of scope before starting the switch,
|
|
thus making it easy for a back end to free it.
|
|
|
|
The problem @emph{that} solution has, however,
|
|
is with @samp{SELECT CASE('prefix'//A)}
|
|
(which is currently not supported).
|
|
|
|
Unless the GBEL is extended to support arbitrarily long character strings
|
|
in its @code{case} facility,
|
|
the FFE has to implement @code{SELECT CASE} on @code{CHARACTER}
|
|
(probably excepting @code{CHARACTER*1})
|
|
using a cascade of
|
|
@code{if}, @code{elseif}, @code{else}, and @code{endif} constructs
|
|
in GBEL.
|
|
|
|
To prevent the (potentially large) temporary,
|
|
needed to hold the selected expression itself (@samp{'prefix'//A}),
|
|
from being in scope during execution of the @code{CASE} blocks,
|
|
two approaches are available:
|
|
|
|
@itemize @bullet
|
|
@item
|
|
Pre-evaluate all the @code{CASE} tests,
|
|
producing an integer ordinal that is used,
|
|
a la @samp{temp0} in the earlier example,
|
|
as if @samp{SELECT CASE(temp0)} had been written.
|
|
|
|
Each corresponding @code{CASE} is replaced with @samp{CASE(@var{i})},
|
|
where @var{i} is the ordinal for that case,
|
|
determined while, or before,
|
|
generating the cascade of @code{if}-related constructs
|
|
to cope with @code{CHARACTER} selection.
|
|
|
|
@item
|
|
Make @samp{temp0} above just
|
|
large enough to hold the longest @code{CASE} string
|
|
that'll actually be compared against the expression
|
|
(in this case, @samp{'prefix'//A}).
|
|
|
|
Since that length must be constant
|
|
(because @code{CASE} expressions are all constant),
|
|
it won't be so large,
|
|
and, further, @samp{temp1} need not be dynamically allocated,
|
|
since normal @code{CHARACTER} assignment can be used
|
|
into the fixed-length @samp{temp0}.
|
|
@end itemize
|
|
|
|
Both of these solutions require @code{SELECT CASE} implementation
|
|
to be changed so all the corresponding @code{CASE} statements
|
|
are seen during the actual code generation for @code{SELECT CASE}.
|
|
|
|
@node Transforming Expressions
|
|
@section Transforming Expressions
|
|
|
|
The interactions between statements, expressions, and subexpressions
|
|
at program run time can be viewed as:
|
|
|
|
@smallexample
|
|
@var{action}(@var{expr})
|
|
@end smallexample
|
|
|
|
Here, @var{action} is the series of steps
|
|
performed to effect the statement,
|
|
and @var{expr} is the expression
|
|
whose value is used by @var{action}.
|
|
|
|
Expanding the above shows a typical order of events at run time:
|
|
|
|
@smallexample
|
|
Evaluate @var{expr}
|
|
Perform @var{action}, using result of evaluation of @var{expr}
|
|
Clean up after evaluating @var{expr}
|
|
@end smallexample
|
|
|
|
So, if evaluating @var{expr} requires allocating memory,
|
|
that memory can be freed before performing @var{action}
|
|
only if it is not needed to hold the result of evaluating @var{expr}.
|
|
Otherwise, it must be freed no sooner than
|
|
after @var{action} has been performed.
|
|
|
|
The above are recursive definitions,
|
|
in the sense that they apply to subexpressions of @var{expr}.
|
|
|
|
That is, evaluating @var{expr} involves
|
|
evaluating all of its subexpressions,
|
|
performing the @var{action} that computes the
|
|
result value of @var{expr},
|
|
then cleaning up after evaluating those subexpressions.
|
|
|
|
The recursive nature of this evaluation is implemented
|
|
via recursive-descent transformation of the top-level statements,
|
|
their expressions, @emph{their} subexpressions, and so on.
|
|
|
|
However, that recursive-descent transformation is,
|
|
due to the nature of the GBEL,
|
|
focused primarily on generating a @emph{single} stream of code
|
|
to be executed at run time.
|
|
|
|
Yet, from the above, it's clear that multiple streams of code
|
|
must effectively be simultaneously generated
|
|
during the recursive-descent analysis of statements.
|
|
|
|
The primary stream implements the primary @var{action} items,
|
|
while at least two other streams implement
|
|
the evaluation and clean-up items.
|
|
|
|
Requirements imposed by expressions include:
|
|
|
|
@itemize @bullet
|
|
@item
|
|
Whether the caller needs to have a temporary ready
|
|
to hold the value of the expression.
|
|
|
|
@item
|
|
Other stuff???
|
|
|
|
|
|
@end itemize
|