Program Controller

The Program Controller (main routine) controls invocation of the initialization routines, the other major compiler modules, and the finish routine.

Initialization is performed by the routine init at the very beginning of execution.

Program Controller

Each subprogram is completely processed and output before the next subprogram is processed. Conceptually, it is as if each subprogram were in a separate file. For Fortran 90 contained subprograms, some information must be preserved from the host subprogram to the contained subprograms, particularly any stack or BSS addresses assigned to host subprogram variables.

The same source file is used to generate the program controller for both the compiler and the extractor, since they share so much code. The differences in the source code appear as tests of the preprocessor variable EXTRACTOR, which is defined only for the extractor controller.

See figure 2-1 for a pseudo-code description of the Program Controller processing for the compiler. See figure 2-2 for a pseudo-code description of the Program Controller for the extractor.

init();

for (each subprogram) {
   reinit();   /\* init for subprogram \*/
   upper();    /\* import ILMs from F90 front end \*/
   extractor();/\* optionally extract subprograms for future inlining \*/
   expand();   /\* expand ILMs into shared ILI \*/
   upper_save_syminfo();       /\* save host subprogram info \*/
   xref();     /\* optionally generate cross reference \*/
}

finish();

Figure 2-1 Program Controller Operation for Compiler

init();

for (each subprogram) {
    reinit();        /\* init for subprogram \*/
    upper();    /\* import ILMs from F90 front end \*/
    extractor();/\* extract subprograms for future inlining \*/
}

finish();

Figure 2-2 Program Controller Operation for Extractor

Init

The init module performs the following five major tasks:

  1. Processes command line and sets values of internal variables depending on the flags specified by the user.

  2. Opens input and output files.

  3. If a listing file is being generated, writes the Listing Header.

  4. Initializes the Error message module, Symbol table module, Scanner, Directive processing, and other modules by calling the appropriate init routine for each.

Adding Compiler Flags

The command line processor searches the structure swtchtab[] (defined in main.c) to find valid flags or flag prefixes. To add a flag, add the new flag (without the preceeding “(mi”) to swtchtab[]’s initialization, keeping the flags in lexicographic order. Also add a case constant to the initialization. Switch case constants are #define’d constants of the form SW_<flag name in caps>, and appear above the definition of swtchtab. The case constant must be unique but numerical order is not necessary. (i.e., you don’t have to change existing constants, just use the next biggest unused integer.)

Add the case label SW_<flag name in caps>: to init() (also defined in main.c). Also, add code to process flag and any values that follow the flag. See existing code in init() for examples.

Finish

finish is called at the end of compiler execution to close files, write a compilation summary line to the user’s terminal, and exit.

Debugging

The development compiler supports debug output in the compile process; these are mostly disabled when the preprocessor variable DEBUG is zero, as is done for a release. Most debug output is enabled with a -q or -qq switch. Each of these takes two arguments; the -q 45 8 sets bit mask 8 in flg.dbg[45]. This is tested in the compiler source code with

#if DEBUG
   if( DBGBIT(45,8) ) fprintf( gbl.dbgfil, "debug output\\n" );
#endif

The #if DEBUG test disables this code for a release. The DBGBIT(45,8) macro is shorthand for (flg.dbg[45]&8).

Debug output is normally written to gbl.dbgfil, which is normally be opened to the file filename.qdbg by init unless -q 0 1 is specified, which says to open gbl.dbgfil to standard output. Using the compiler driver, debug switches can be set using

-Mq,45,8
-Mq,66,7

where the latter sets bits 1, 2, and 4.

The controller can also generate dumps during compile process. At various points in the controller will appear a line like:

DUMP( "expand" );

This is a preprocessor macro that calls a generic debug dump routine. To enable a dump, you can pass a -qq switch to the compiler like

-qq expand blocks

which will invoke the blocks dump after the expand phase. Multiple phases and multiple dumps can be specified at once, like

-qq expand+optimize blocks
-qq unroll printblocks+sym

which will invoke the blocks dump after both the expand and optimize phases, and will invoke both the printblocks and sym dumps after the unroll phase. Using the driver, these would appear as

-Mqq,expand+optimize,blocks
-Mqq,unroll,printblocks+sym

Specifying all as the phase name will invoke those dump routines after all phases. The list of available phases is available by looking at the source code for the

DUMP( "phase" )

lines, or by looking at the filename.qdbg file for lines something like

{pgf90-linux86-64 after expand
{pgf90-linux86-64 after upper

The dump controller prints out these lines before every active phase, and will generate any dumps after each of these lines. New dump points can be inserted anywhere in the source of the program controller. The list of available dumps is only available by looking at the source code of the program controller; look for the variable dumpnames. New dump names can be added here, and the appropriate dump code added in the switch statement in routine do_debug.