9999
The SUIF compiler provides an excellent set of flexible libraries for parallel and machine-independent optimizations. This document and its associated documents describe a set of modifications and extensions to the base SUIF library that provide the abstractions necessary for machine-specific optimizations, such as global instruction scheduling. We have designed these modifications and extensions so that existing SUIF code compiles without change. Furthermore, we have designed this code base so that it is easy to add support for new instructions or instruction set architectures, to include new analysis or machine-specific optimization passes, and to experiment with new hardware structures or organizations. We hope that you find this system useful. Enjoy!
As with base SUIF, Machine SUIF is built around a core library, the
machine library consisting of the files in the machine
subdirectory of the machsuif distribution package. Currently,
the machine library relies on the suif and useful libraries
distributed with basesuif. On top of the machine library,
we have constructed several other libraries and many machine-specific
optimization passes.
This document serves as an overview of the Machine SUIF system. It presents the philosophy behind the design of Machine SUIF, directions for using and extending the system, and pointers to the other documentation available. Throughout our documents, it is assumed that the reader is familiar with the SUIF system and has read the SUIF overview document [cite bibsuif].
We use the noweb system [cite bibnoweb] by Norman Ramsey for the
majority of our documentation. This literate programming tool lets
you combine documentation and code in the same source file. It is our
convention to use noweb to document only the most important header
files in the Machine SUIF libraries, i.e. the files that describe a
library's interface. We use man pages and simple C comments to
document the interesting portions of Machine SUIF passes and library
implementation files. The machsuif/doc directory contains
several other documents that a user of Machine SUIF might find
helpful. A ``roadmap'' to these documents can be found in
Section [->].
The following section discusses the inter-operability and research goals that drove the design of our machine library. Section [->] describes how you need to setup your computing environment in order to compile and use Machine SUIF. Section [->] introduces the flow of passes in Machine SUIF. Further information on the ordering of passes and the contracts governing individual passes can be found in the Machine-SUIF Interfaces document. Section [->] briefly describes how one would go about extending our system. Among other things, this section explains how you would extend the machine library to support a new architecture. Section [->] will get you started into the rest of our documentation. Finally, Section [->] lists those places that are less than perfect in the current system, while Section [->] summarizes the status, availability, and future plans for Machine SUIF.
When we began this project in the spring of 1994, we had two distinct goals in mind. The first goal was to maintain inter-operability with the existing SUIF infrastructure. Our system should dovetail seamlessly into SUIF, and the key philosophical tenets of SUIF should be maintained. The second goal was to develop an infrastructure that would meet the needs of a research program in computer architecture and machine-specific code optimization. Sections [->] and [->] discuss the design decisions that resulted from these goals, and they briefly describe the implications for users of our system.
There are both practical and philosophical reasons behind the desire to maintain inter-operability with the SUIF system. To be precise, we define inter-operability to mean that the machine library extends the SUIF system without the need to duplicate functionality unnecessarily. The current SUIF infrastructure provides many tools that are useful for machine-specific compiler research, and we want to exploit this existing infrastructure as much as possible.
The machine library re-uses the basesuif infrastructure whenever
possible. Other than a few extensions to the existing SUIF
instruction and operand classes, our library simply derives a
set of new instruction classes, the machine instruction classes, from
the existing SUIF in_gen instruction class (as described in
detail in machine library documentation). By carefully crafting our
machine instruction classes and implementing key helper routines, we
are able to re-use many existing utilities. For example, we use a
straightforward wrapper around the SUIF methods that read and write
procedures. We are thus independent of the implementation details
of the input/output stream routines. In addition, we carefully
maintain the symbol table and other high-level information passed down
from the front end. Architecture-specific assembly-language data
statements are generated only when outputting ASCII assembly-language
text, i.e. when leaving the SUIF system. As a testament to the clean
interface between the base SUIF system and our machine library, it
typically takes us less than one day to port our machine library to
the latest distribution of SUIF. [This is also a
testament to the stability of SUIF.]
We also strived to maintain the philosophical underpinnings of SUIF. Whenever possible, we chose design decisions that allow for easy modification and expansion of our base system. At the same time, we attempted to create abstractions that were general. For example, our single instruction class abstraction is powerful enough to support both RISC and CISC instruction set semantics, and yet, it follows the structure of the base SUIF instruction class. Mapping functions for the base SUIF instruction class work without change on the machine instruction classes. Finally, our machine extensions support the development of machine-specific passes implemented as separate programs that link with the core SUIF libraries. As with the original SUIF system, this is inefficient in terms of compile time, but extremely flexible and an ideal platform for evaluating new architectural ideas.
Research on machine-specific compile-time optimizations is closely tied to research in computer architecture. To support this area of research, a compilation system must possess an intermediate form (IF) that is both extensible and expressive. We require extensibility so that we can experiment with new compiler-visible instructions, architectural features, and hardware mechanisms. Since SUIF was built with extensibility as a primary design goal, it was simple for us to meet this requirement. We desire expressiveness in our IF so that every single machine instruction is representable by a single IF instruction. A one-to-one correspondence between IF instructions and actual machine instructions is required for optimizations such as global instruction scheduling.
The development of an extensible and expressive IF could be a lifelong project within itself. Since we were primarily interested in the compiler as a tool, we focused on the development of an IF that met our needs without greatly disrupting the structure of the IF already present in the SUIF system. We considered two basic approaches to satisfy the goal of a one-to-one correspondence between IF instructions and machine instructions. The approaches differ in where they perform the actual mapping from an IF opcode to a machine opcode.
The first approach postpones this mapping until the last possible moment in the compilation process (see Figure 1a). To ensure that there is a one-to-one correspondence between IF and machine instructions, there is an earlier pass in the compilation process that restricts the IF form so that each IF instruction can be mapped directly to a single machine instruction. The machine-specific optimization passes maintain this one-to-one correspondence. The IMPACT compiler [cite bibimpact] employs this type of an approach.
| .c --> front-end --> IF-restriction --> optimizations --> code-gen --> .s |
| (a) |
| .c --> front-end --> code-gen --> optimizations --> .s |
| (b) |
The second approach performs the mapping from IF instructions to machine instructions early in the compilation process (see Figure 1b). Machine SUIF employs this approach. To keep from having to re-implement each machine-specific optimization for each target instruction set architecture, the specifics of an instruction are hidden by abstraction techniques when those specifics are not needed for optimization. As a result, we use the same register allocation pass, for example, for several different machine architectures.
Alternatively, one could use retargetable compiler technology, as done in the vpcc/vpo compiler [cite bibvpo], to achieve the same result. The designers of a compiler pass write their passes without reference to any specific machine instruction set. They then use a compiler compiler to generate the actual compiler for a specific instruction set.
Given complete freedom over the design process, it is unclear to us that
one approach is significantly better than the others. Of
course, we did not have complete freedom in the design process. We
chose our approach for several practical reasons. First, the IMPACT
approach requires us to be able to extend the SUIF instruction
class arbitrarily. The existing SUIF system has defined a specific
way to extend its instruction class, i.e. through io_gen's,
and hence it is simpler for us to ``restrict'' the IF by performing
the mapping all at once. Furthermore, existing SUIF passes handle
io_gen's generically, and thus this approach gives us some
semblance of inter-operability with the existing SUIF code base.
Since SUIF is implemented in C++, the existing class structure
provides us with the ability to abstract away details as required by
the second approach. Thus, we do not need to build a compiler
compiler to obtain the benefits of abstraction.
Before leaving this section on goals, we would like to mention that the ability to produce runnable code has and always will be a foremost goal of our compiler. Not only will our system produce code for experimental architectures, but it will be capable of producing good code for a range of existing instruction set architectures. This ability will help our compiler system to evolve as technology advances.
The following discussion assumes that you are using a UNIX-based
operating system as your development platform. It also assumes that
you know how to unpack the distribution and set-up the SUIF source
directory. If not, please first review the README files contained
in the distributions.
In addition to the environment variables required by base SUIF
(i.e. MACHINE, SUIFHOME, COMPILER_NAME and possibly
NEED_RANLIB, USER_CFLAGS, and USER_CXXFLAGS), we have
created several other environment variables used by Machine SUIF.
Some of these environment variables are used when you compile the
Machine SUIF compiler. We discuss these variables in
Section [->]. Section [->] overviews
other environment variables that you may find useful during SUIF
compilation of a target application. Before we get into these details
however, Section [->] introduces the four different
types of source modules in the Machine SUIF world.
There are two distinguishers that together separate every piece of
Machine SUIF source code into one of four categories. The first
distinguisher differentiates code that is organized as a compiler pass
from code that acts as a common library of routines. For example, the
code in src/machsuif/machine is the source for the machine
library while code in src/machsuif/agen uses this machine
library to perform Digital Alpha code generation. The second
distinguisher differentiates source code that requires
target-machine-dependent information during its compilation from code
that is target-machine-independent. Please remember that all of our
optimizations use machine-specific information during compilation.
The issue here is whether the compiler code is specific to a
particular target machine or whether it can be used generically for
any (properly abstracted) target machine. For example, the code in
src/machsuif/agen is target-machine-dependent code because it
produces only Alpha intermediate-form instructions. The code in
src/machsuif/raga, on the other hand, is target-machine-independent
because it performs register allocation for any of our target
machine architectures.
To summarize, we have four kinds of source directories in the
machsuif distribution:
raga.
agen.
cfg library.
machine library.
The compilation of the source files in the machsuif distribution
depend upon a set of environment variables of the form
MACHSUIF_TARGET_*, where * is replaced by a machine
architecture name (e.g., ALPHA). If an environment variable
like MACHSUIF_TARGET_ALPHA is defined, this tells the make
process that you would like your SUIF compiler to be able to
produce code for Digital Alpha targets. By setting more than
one of these variables, you create a SUIF compiler capable of
producing code for multiple targets.
Each of these environment variables has a corresponding makefile
variable of the form M_*. Again, we replace the * with a
machine architecture name. So, M_ALPHA is the makefile variable
associated with MACHSUIF_TARGET_ALPHA. The M_* makefile
variables are passed as preprocessor define variables during a make
process. These variables are checked in the source code to
include/exclude machine-specific portions of code.
Referring to the four kinds of source directories described in the
previous subsection, we can now explain how the makefile structure of
Machine SUIF works. The makefile for a machine-independent pass
(e.g. raga) will not contain any references to M_* define
variables. (Why? Because it is machine-independent, of course.)
Furthermore, the M_* define variables do not appear anywhere in
the source code of a machine-independent pass.
The makefile for a machine-dependent pass (e.g. agen), on the
other hand, will contain uses of a single M_* variable
(M_ALPHA for this example pass). In particular, the
EXTRA_CFLAGS and EXTRA_CXXFLAGS lines of this pass's Makefile
will contain
-DM_*. Notice that you know exactly what define flag is required
since a machine-dependent pass is specific to only one architecture.
The makefile for a machine-independent library (e.g. cfg), like
a machine-independent pass's makefile, does not contain any references
to M_* define variables. If compilation of a library of this kind
fails, then you did not build a machine-independent library. The same
type of error checking applies for machine-independent passes.
The makefile for a library containing machine-dependent code
(e.g. machine) is slightly more complex than anything mentioned
earlier. See the Makefile in src/machsuif/machine as an
example. Among other things, it includes the file
src/machsuif/Makefile.defs. This file is the central location for
checking the environment variables MACHSUIF_TARGET_* and then
setting the appropriate M_* variables. The library itself should
use M_* to set off machine-specific code from machine-independent
code. Please try to place all of the machine-specific code in a
single module. If you create source files that are specific to only
one architecture, then you can use the *_{HDRS,SRCS,OBJS} makefile
variables to enable/disable their compilation based on the
MACHSUIF_TARGET_* environment variables. Please see the machine
library as an example.
To perform machine-specific optimizations, we must have access to
information about the organization and microarchitecture of the target
machine. Except for the definition of the machine instructions and
assembler directives [This information is maintained in the
src/machsuif/machine directory.] , we place the rest of the
target-machine-specific organizational and microarchitectural
information in data files in the directory src/machsuif/impl.
When you compile Machine SUIF, these data files are installed in
$(SUIFHOME)/include/impl for use during target
machine-code generation. If you want something other than
$(SUIFHOME)/include/impl as the directory where
machine-specific information lives, you can override this default
location for the impl directory with the MACHSUIF_IMPL_DIR
environment variable.
In the impl directory, data files have names of the form
<family>-<version>-<implementation>.<extension>
where each of <family>, <version>, <implementation>, and
<extension> are string values. <family> is the architectural
family name for the target machine; <version> is the reversion
number of the architectural specification; <implementation>
indicates a particular hardware realization of it; and a file's
<extension> indicates what kind of information it contains.
As we will see in a moment, the <family>, <version>, and
<implementation> values provide us with a rational namespace to
describe machine-specific features.
First however, we will briefly mention how these values are recorded
and used.
For more information on this topic, we encourage you to read the
document describing our machine library. As mentioned later in
Section [->] on the basic ordering of our compiler passes, it
is the task of a *gen pass to translate a low-SUIF representation
of a code module into a machine-SUIF representation of this same code
module. During this translation, the *gen pass will mark each
file_set_entry with four target configuration identifiers:
<family>, <version>, <implementation>, and <vendor-os>.
We have already mentioned three of these four identifiers. The
last, <vendor-os>, records the vendor and target operating system
information.
We obtain the values used for <family>, <version>,
<implementation>, and <vendor-os> in several ways. The value
for <family> is
determined solely by the code generator invoked. For example, if you
set the -Target flag for scc to be
alpha-dec-osf [Typically, the value of this string is
retrieved from your MACHINE environment variable. You use a
different value if you are cross-compiling.] , the SUIF compiler would
invoke a Digital Alpha code generation pass that would define the
architectural family of the target to be alpha. We specify the
values for the <version>, implementation>, and <vendor-os>
strings in one of two ways. One way to specify this information is to
use the -ver, -impl, and -os command line options
of the *gen passes. An example of this method is shown in
Section [->]. Alternatively, if you define the environment
variables, MACHSUIF_TARGET_VERSION, MACHSUIF_TARGET_IMPL, and
MACHSUIF_TARGET_OS,
our *gen passes will use them. The command line arguments will
override the environment variables, and if neither command line
arguments nor environment variables are defined, the *gen pass
will throw an assertion.
The machine library uses the values of <family>, <version>,
and <implementation> to search the impl directory for
machine-specific information. The library performs this search every
time you read a Machine-SUIF intermediate form file from disk. In
addition, the library performs this search from MOST-specific to
LEAST-specific name. So for example, alpha-1-21064A-4M.reg
would override any settings in alpha-1.reg or alpha.reg. This
allows us to collect common
descriptions in a single file that is appropriate for any hardware
organization of an architectural version or any implementation of a
particular architecture family (i.e., alpha.reg is equivalent to
alpha-*-*.reg) .
The <extension> on the impl directory files indicates the
kind of machine-specific information contained in that file. For
example, the .reg extension indicates that this file contains a
description of register file organizations and software conventions.
The README.* files in the impl source directory discuss
the kinds of machine-specific information files supported and the
syntax of these files. The partitioning corresponds to the interfaces
that we have built in the machine and associated libraries for
accessing machine-specific information. We do not claim that this
partitioning is ideal in any sense; the current one just makes
intuitive sense to us. Eventually, the crufty nature of these files
will be hidden by the use of the University of Virginia's Computer
Systems Description Language (CSDL).
In theory, we could extend the naming structure in the impl
directory to include the <vendor-os> string since, for instance,
different OSs could use the same processor but different register
conventions. We do not use the <vendor-os> string in the
impl directory names because different operating systems may change
the ways in which the hardware is used by the software, but it does
not change the hardware directly. To support different software
conventions and interfaces, we allow specific impl files,
e.g. the *.reg files, to include multiple convention
definitions, each marked by the associated <vendor-os> strings.
This is a relatively minor choice in the grand scheme of things, but
it keeps our impl directory namespace manageable.
In summary, we define and use the following environment variables in Machine SUIF:
MACHSUIF_TARGET_*. This set of variables are used during the
compilation of the Machine SUIF system to indicate what target architectures
should be supported by the resulting SUIF compiler. (The binding of each
such variable is ignored. Its existence in the environment is what
matters.)
MACHSUIF_IMPL_DIR. This variable is used during
compilation with the SUIF compiler to override the default location
for the target-machine-specific implementation files.
MACHSUIF_TARGET_VERSION. This variable defines the
version string for the target architecture.
MACHSUIF_TARGET_IMPL. This variable defines the implementation
string for the target machine.
MACHSUIF_TARGET_OS. This variable defines the vendor and
operating system string name for the target machine. Typically, this
matches the last two items in the MACHINE environment variable.
Like the rest of SUIF, we attempt to minimize the requirements on the ordering of Machine SUIF passes. There are however certain assumptions that must be met. This section talks about the general structure of a back-end implemented in Machine SUIF. The specific requirements of each Machine SUIF pass are fully documented in its man page. Further information on the ordering of passes and the contracts between individual passes can be found in the Machine-SUIF Interfaces document.
The back-end starts with a code generator pass that converts the ``low-suif'' representation of a program into a Machine SUIF representation of that program for a particular machine architecture. The simplest way to describe the interface between Machine SUIF and the rest of the SUIF system is to say that a Machine-SUIF code generator expects an input file containing only low-suif constructs---all high-suif constructs have been decomposed into low-suif constructs.
So, what is low-suif? Good question. There is no formal definition of low-suif, and there probably should not be, given the one-to-many mapping between the SUIF intermediate form and target machine instruction sets. Since this is a research compiler infrastructure, it is conceivable that someone would create a new ``high-suif'' construct that was passed directly to a particular Machine-SUIF code generator (and decomposed for other Machine-SUIF code generators).
Today, we run (at least) the following SUIF passes to translate a C
program into a low-suif representation acceptable to our Digital Alpha
code generator. The machine target specified in the scc command
should be changed to match your target machine environment. Note that
the options to swighnflew may be different for each target
architecture. You would change the initial scc command
appropriately to compile a FORTRAN program.
<Generate machsuif-palatable low-suif code>= scc -Target alpha-dec-osf -.spd $f.c porky -Darrays -Dfors -Dloops -Difs -Dblocks -no-call-expr \ -Ddivfloors -Ddivceils -Dmins -Dmaxs -Dmods \ $f.spd $f.spx swighnflew -no-struct-return -mark-struct-alignment \ -mark-varargs __builtin_va_start $f.spx $f.sfl
To this point, we have described information flowing in only one direction: from the front-end to the back-end. It is conceivable and desirable to have information flow in the opposite direction too. There does not currently exist a formal convention for representing this flow of information.
The purpose of the back-end is to translate a low-suif representation of a program into an equivalent assembly-language representation of that program. This translation typically requires the following two basic steps: translate low-suif instructions into a specific machine's assembly instructions (code generation); and translate SUIF symbol and instruction-pointer operands into machine registers and memory locations (register allocation). A minimal Machine-SUIF back-end consists of four steps related to these two basic steps: perform most of the code generation; perform register allocation; finish machine-specific translation; and print the ASCII representation of the Machine-SUIF binary file. The following commands perform these steps to generate a Digital Alpha assembly file:
<A minimal Alpha back-end>= agen -ver 1 -impl 21064A-4M -os dec-osf3.2 $f.sfl $f.acg raga $f.acg $f.ara afin $f.ara $f.af printmachine $f.af $f.s
The agen pass performs most of the machine-specific code
generation. It does not perform any register allocation (beyond what
is necessary, for example, because a certain instruction uses a
specific, implicit register). It does however translate instruction
pointer operands representing compiler virtual registers into
virtual register operands.
As mentioned earlier in Section [<-], *gen passes
like agen define the machine-specific target information
associated with an intermediate file. By default, when you invoke
agen (as opposed to say mgen), you implicitly pick an Alpha
target running Digital UNIX. If you wanted another target operating
system, you would select a different version of agen. (Currently,
we ship a version of agen that supports Digital UNIX, a.k.a.
OSF1, versions 3.2 and 4.0.)
Additionally, we have specified via command line options that the
target machine implements version 1 of the Alpha instruction set
architecture, its hardware organization contains an Alpha 21064A
microprocessor with a 4MB second-level cache, and the target operating
system is Digital UNIX version 3.2. The operating system string is
used by agen; agen simply embeds the values of the other two
parameters into the output file for use by later machine-specific
optimization passes.
The raga pass performs register allocation, translating all
register-allocated symbols and virtual registers into hard registers.
This register allocator is based on the technique described by
George and Appel [cite bibraga].
The afin pass completes the translation process by laying out
the stack frame for each procedure, replacing
stack-allocated symbols by their stack-based effective-address
calculation, and inserting the procedure entry and exit code
sequences. These entry/exit sequences are not created before this
point so that other Machine SUIF passes can easily reallocate
registers in a procedure, for example, and not have to change the
register save/restore code at that procedure's entry/exit points.
The printmachine pass translates the Machine SUIF
representation for a program into an architecture-specific ASCII
assembly-language file (a .s file). This pass also creates the
data pseudo-ops by translating the file's symbol table. Before this
point, it is expected that all Machine SUIF passes will maintain the
symbol table (and not create machine-specific data pseudo-ops in the
instruction lists). The resulting .s file can then be assembled
by the target machine's assembler to create a .o file.
Of these essential passes, only agen and afin are written in a
machine-specific manner. The raga and printmachine passes are
written in a machine-independent manner, even though they perform
machine-specific actions and optimizations. Thus, if we wanted to
create a MIPS assembly language file, we would replace agen and
afin by mgen and mfin respectively. You will gain a
better understanding of how we create machine-independent passes
that perform machine-specific optimizations after you read the
machine library documentation.
An equally important purpose of the back-end is to perform
machine-specific optimizations. We place machine-specific
optimization passes between the code generator and printmachine.
For example, if we had a global instruction scheduling pass called
twine and a target architecture like the Alpha 21064A that required
instruction scheduling to achieve maximum performance, we might run
the following passes:
<A scheduling back-end for the Alpha 21064A>= agen -ver 1 -impl 21064A-4M -os dec-osf3.2 $f.sfl $f.acg aexp -use_vregs $f.acg $f.ae1 twine -preschedule $f.ae1 $f.aps raga $f.aps $f.ara aexp $f.ara $f.ae2 twine -postschedule $f.ae2 $f.ags afin $f.ags $f.af aexp $f.ara $f.ae3 twine -bbschedule $f.ae3 $f.afs fix-alpha-gp $f.afs $f.afx printmachine $f.afx $f.s
The filename extensions are unimportant. This back-end includes two
other machine-specific passes, aexp and fix-alpha-gp. The
aexp pass expands all pseudo-ops into real machine
instructions so that we can schedule all of the machine instructions.
When run after code generation, this pass uses compiler virtual
registers during pseudo-op expansion; it is not limited to the use of
the Alpha assembler temporary register. Since the register-allocation
and the finishing passes may also use pseudo-ops, aexp is run after
each--these times using assembler-temporary hard registers however.
The fix-alpha-gp pass cleans up the world with respect to the
calculation of the global data pointer. These calculations are sensitive
to their location in the code and thus must be finalized after all
scheduling is complete.
Scheduling takes place three times in this example. Once before
register allocation (pre-scheduling), once after register allocation
(post-scheduling), and once after the finishing pass. We schedule the
code each time for an Alpha 21064A machine model. This directive
came from the impl command line parameter specified during agen.
The use of pre- and post-schedulers is typical approach when the
compiler separates register allocation and instruction scheduling.
The final scheduling pass simply schedules the procedure entry and
exit code sequences added during the finishing pass. The assumption
here is that afin marks the code sequences that it inserts as ones
that need to be scheduled. The basic block scheduler does not touch
any of the previously scheduled sequences.
As discussed earlier, aexp and fix-alpha-gp are a
machine-specific passes like
agen and afin. All of these passes could be generated
automatically by a compiler compiler from very simple machine
description files. The instruction scheduling (twine) and
register allocation (raga) passes are machine-independent
passes that perform machine-specific optimizations. These passes
are also constructed so that you may rerun them multiple times.
Code sequences are marked so that the optimization in question
is enabled/disabled.
This section assumes that you are familiar with Machine SUIF in general, and Section [<-] and the machine library in particular. The information in this section should help you get started toward the goal of extending Machine SUIF to support a new machine architecture.
Begin by picking a name for the new architecture, analogous to ALPHA
in MACHSUIF_TARGET_ALPHA. For clarity of
discussion, let us assume that your new target architecture is called
MYMACH. Then modify the makefiles in any machine-specific
library and in the top-level directory src/machsuif to include
your architecture's information during the build of each
machine-dependent library and each MYMACH-specific pass.
Obviously, the makefile in a MYMACH-specific pass should be
configured as described in Section [<-].
Next, extend each
machine-specific library to know about your new architecture. For the
rest of this section, I will assume that the machine-specific library
in question is machsuif/machine. A similar set of steps
would be needed for any other machine-specific library.
In the directory src/machsuif/machine,
machineUtil.cc. These lines should be predicated
on a preprocessor variable (defined in the machine/Makefile)
that controls whether this architecture is included in the
machine library or not.
*Instr.{h,cc} that contain all of
the architecture-specific helper routines referenced in
the previous bullet.
*Ops.h.
*Ops.{h,cc}, *.data, and
*Arch.data.
*Ops.h and *Instr.h
in machine.h. Like the code lines in the
architecture-specific dispatch routines mentioned above,
these lines should be predicated on this architecture's
preprocessor variable.
Finally, create the essential
machine-specific passes. In particular, you must at least create an
initial code generator pass *gen and a final code generation pass
*fin. See Section [<-] for a brief description of
the functionality of these passes. You can find more detailed
information concerning the interface between key Machine SUIF
passes in the Machine-SUIF Interfaces document.
You may also create an expander pass *exp that expands all of the
assembly pseudo/macro ops into real machine instructions. This pass
is necessary only if you wish to use instruction
scheduling passes in Machine SUIF.
As long as your architecture is similar to those already supported under Machine SUIF, you should not need to change any other Machine SUIF pass.
In addition to this document, we provide several other postscript documents for your reading pleasure. As mentioned earlier, our convention is to use noweb to document the header files of our Machine SUIF libraries and man pages to document the purpose and restrictions on Machine SUIF passes. Below, we summarize the list of documents available describing the Machine-SUIF compilation system:
machine.ps); a library for
constructing and manipulating a procedure's control-flow graph
(cfg.ps); and a library for building iterative, bit-vector-based
data-flow analyzers (dfa.ps).
basesuif-changes.ps outlines our
changes to the basesuif distribution in support of Machine SUIF.
interfaces.ps collects all of the
interesting information concerning interfaces and assumed contracts
between important Machine SUIF passes. We often refer to this
document as the Machine-SUIF Interfaces document.
It's pretty clear to us that Machine SUIF is far from perfect. The following is a list of action items that we're working on:
gpr bank while a single-precision
floating-point number goes in the fpr bank. We'd like to
remove this hard-coded information from the register allocator
pass.
We have developed a machine-specific library that adheres to the philosophy of the existing SUIF infrastructure and yet also supports research in computer architecture and machine-specific code optimization. At Harvard, we are using or have used this machine library to support the construction of several code generators (including RISC-based and CISC-based architectures), register allocators, global instruction schedulers, and several code transformations to support our work in branch prediction and code layout. Though we continue to identify new annotations and helper routines, the core of the machine library appears stable.
A version of the machine library is available by anonymous ftp from
ftp.eecs.harvard.edu in pub/hube (the same code is available
from our web site, http://www.eecs.harvard.edu/~hube/). The
current release works with version 1.1.2 of the base SUIF system, and
it is organized as a ``super-package'' (machsuif) that requires
only basesuif. SUIF is available from
http://suif.stanford.edu/. Questions, comments, and bug reports
for this package should be e-mailed to
machsuif-bugs@eecs.harvard.edu. As the technology matures, this
package will migrate into the SUIF distribution, and we will track the
updates to the base SUIF system. As other machine-specific
optimizations become available, we will add them to our distribution
site.
I gratefully acknowledge the support of the HUBE research group at Harvard and the SUIF research group at Stanford. In particular, I would like to acknowledge the help of Cliff Young and Glenn Holloway. Cliff helped me to implement our extensions to the SUIF system, revamped the control-flow graph library, and authored the HALT package for instrumentation and profiling under SUIF. Glenn wrote our first real register allocator and helped to implement our dataflow analysis library.
This work is supported in part by an DARPA/NSF infrastructure grant (NDA904-97-C-0225) and a NSF Young Investigator award (CCR-9457779). We also gratefully acknowledge the generous support of this research by Advanced Micro Devices, Digital Equipment, Hewlett-Packard, International Business Machines, Intel, and Microsoft.
[1] M. Benitez and J. Davidson. ``Target-specific Global Code Improvement,'' Dept. of Computer Science Technical Report CS-94-42, University of Virginia, November 1994.
[2] L. George and A. Appel. ``Iterated Register Coalescing,'' Transactions on Programming Languages and Systems, 18(3):300--324, May 1996.
[3] IMPACT Research Group. See
http://www.crhc.uiuc.edu/Impact/.
[4] N. Ramsey. ``Literate Programming Simplified,'' IEEE Software, 11(5):97--105, September 1994.
[5] Stanford Compiler Group. The SUIF Library. The SUIF compiler documentation set, Stanford University, 1994.