   Copyright (C) 1994 Stanford University.

The Simple-SUIF Compiler
************************

   Simple-SUIF is a small and simple interface to the SUIF compiler
system.  It is designed to be used for implementing some basic
optimizations in the context of a compiler course.  This file describes
the interface to the Simple-SUIF library.

- Other Nodes -

The Simple-SUIF Library

Registers

Introduction
************

   This document describes Simple-SUIF, a compiler system for real
languages and machines that is simple enough for use in a compiler
course.  Simple-SUIF provides a simplified interface to the full SUIF
compiler system which has been developed by the compiler research group
at Stanford.  Although it is not a production-quality compiler, SUIF
runs on most UNIX systems, is capable of handling large programs written
in ANSI C and FORTRAN 77, and can generate code for MIPS processors,
which are used in DECstations and SGI workstations.

Using Simple-SUIF
*****************

   Before running a Simple-SUIF program, the source file must first be
run through the front-end of the SUIF compiler to produce a binary SUIF
file (1).  This file can then be read by a Simple-SUIF program.  Such a
program is produced by linking with the Simple-SUIF library, which
takes care of all of the details of working with SUIF files.  Only the
main program and a function to process each procedure must be provided.
The main program is a simple C++ program to read the command-line
arguments, initialize the SUIF library, and call the Simple-SUIF
driver.  Because this program rarely needs to be changed, most
applications can just copy the main program from another Simple-SUIF
program (e.g. printsimple).

   The library's driver function reads each procedure and converts it
to a list of Simple-SUIF instructions.  It then passes the list of
instructions to the `do_procedure' function provided by the user.  The
code in the `do_procedure' function can then analyze the instructions
and implement various optimizations.  When it is finished, it returns
the list of instructions, which the driver then converts back to SUIF
and writes to the output file.

   ---------- Footnotes ----------

   (1)  Simple-SUIF requires that its input files use a certain style
of SUIF.  Specifically, each procedure body must be a simple list of
instructions.  No abstract syntax trees (ASTs) or nested blocks are
allowed.  Complex instructions (e.g. array accesses) must be expanded to
low-level code.  If the input does not conform to this style, the
Simple-SUIF library functions will probably fail.

The Simple-SUIF Library
***********************

   The Simple-SUIF interface is designed for implementing back-end
optimizations.  To reduce the complexity, much of the information in a
SUIF file is hidden behind this interface.  This means that, although
the Simple-SUIF interface could not be used to build a complete code
generator, it is quite small and easy to use.  There are two include
files that define the Simple SUIF data structures and instruction
opcodes.  The `simple.h' file contains declarations for all of the data
structures described in this section.  The `simple_ops.def' file
contains a list of the instruction opcodes and their formats.

Types
=====

   Types are used in two different places in Simple-SUIF.  All
Simple-SUIF instructions contain a field to specify the type of the
result, although this field is not used if an instruction does not
produce a value for the destination operand.  Each variable symbol also
has a type.  Simple-SUIF types are represented by `simple_type'
structures.

   Each `simple_type' structure contains fields which specify the base
type and the size in bits.  The base types are:

`VOID_TYPE'
     Used to indicate that there is no value present.

`SIGNED_TYPE'
     Signed integers.

`UNSIGNED_TYPE'
     Unsigned integers.

`FLOAT_TYPE'
     Floating-point values.

`ADDRESS_TYPE'
     Pointers.

`RECORD_TYPE'
     Structures, unions, and arrays.

   The `SIGNED_TYPE', `UNSIGNED_TYPE', `FLOAT_TYPE', and `ADDRESS_TYPE'
types are all considered to be *scalar* types.

   Together, the base type and size constitute the only type information
that is available in Simple-SUIF.  The rest of the type information is
recorded internally in the full SUIF type structures pointed to by the
`suif_type' fields in the `simple_type' structures.

   You cannot directly create new types or modify existing ones.
Pointers to some commonly used types are declared in the Simple-SUIF
library.  Only use these predefined types or the types that are already
present in a procedure.  The `get_ptr_type' function may be used to find
the type that is a pointer to another type.  This may be needed to
generate new memory accesses with the correct types.

   Because a base type and size do not uniquely define a type, you must
compare the addresses of two `simple_type' structures to determine
whether or not they represent exactly the same type.  However, many
Simple-SUIF instructions only require that their operands have
*compatible*, but not necessarily equivalent, types.  Except for
`RECORD_TYPE' types, two `simple_type' structures are compatible if
their base types and sizes are equal.

Symbols
=======

   Symbols are used to refer to variables, labels, and procedures.  Each
symbol is represented by a unique instance of a `simple_sym' structure,
which records the kind of symbol (`VAR_SYM', `LABEL_SYM', or
`PROC_SYM') and the symbol name.  For variable symbols, the
`simple_sym' structure includes another field to record the type of the
variable.  Other information about symbols is not accessible in
Simple-SUIF but is recorded in the underlying SUIF symbol structures
pointed to by the `suif_sym' fields in the `simple_sym' structures.

   Rules for manipulating Simple-SUIF symbols are similar to those for
types.  As the data in a `simple_sym' structure does not uniquely
define the symbol, always refer to symbols by the addresses of their
`simple_sym' structures and use these addresses to test for equality.
As with types, you cannot directly modify or create new `simple_sym'
structures.  However, the library provides several functions for
creating new symbols.  The `new_label' function creates and returns a
new label symbol.  New local variables are generated by the
`new_register' function (see Registers.).  There is currently no
way to create new global variables or procedure symbols.

Registers
=========

   The operands of SUIF instructions are contained in registers.  These
registers are divided into several classes: pseudo registers, temporary
registers, and machine registers.  The pseudo registers hold scalar
variables that are guaranteed not to be aliased, temporary registers
hold intermediate results within basic blocks, and machine registers
represent the actual hardware registers in the target architecture.
Within each class, each register is given a unique number.  Each
register contains a particular variable.  Variables that are in
registers can be used directly as instruction operands.  Other variables
must be accessed with load and store instructions.

   The `simple_reg' structure is used to represent Simple-SUIF
registers.  This structure records the kind of the register
(`PSEUDO_REG', `TEMP_REG', or `MACHINE_REG'), the register number, and
the variable that is held in the register.  The Simple-SUIF library
keeps the `simple_reg' objects in a table, so each register is
represented by a unique `simple_reg' instance and you can just refer to
registers by the addresses of their `simple_reg' structures.  The
`NO_REGISTER' constant should be used as the address whenever a
register field is empty.

   The `new_register' function may be used to create new registers.
You need to specify the register kind and the type of the variable to
be stored in the register.  The function then creates a new variable of
the specified type.  A new register is entered in the library's
register table using the next available register number.  You cannot
create new machine registers.  Note that the `new_register' function
can also be used to create local variables even if they cannot be
stored in registers.  In that case, you can ignore the resulting
registers and just use the variables that are created along with the
registers.

   In general, you may not modify any of the fields in a `simple_reg'
structure.  However, there is one exception to this rule.  The register
kind may be changed between `PSEUDO_REG' and `TEMP_REG'.  The current
implementation of the library guarantees that none of the registers in
these two classes will ever have the same register number, so a register
can be moved back and forth between the two classes without changing its
number.  Of course, if you change the kind of a register, it is up to
you to make sure that it is used according to the conventions described
below.

Pseudo Registers
----------------

   Pseudo registers can only contain scalar variables that cannot be
aliased.  This means that global variables, local variables that have
their addresses taken, and aggregates (e.g. structures and unions)
cannot be stored in pseudo registers, and thus they must be accessed
with separate load and store instructions.  Because of the guarantee
that pseudo registers are not aliased, they are ideal targets for
optimization.  Most basic optimizations cannot handle variables that are
potentially aliased, so they ignore any variables that are not in pseudo
registers.  Only `cpy' (copy) instructions are allowed to assign to
pseudo registers.  This makes it easier to do value numbering and common
subexpression elimination.

   Another Simple-SUIF convention is that the pseudo registers with the
lowest register numbers are the formal parameters of the procedure.  For
this reason, do not be surprised to find references to pseudo registers
that have not yet been defined within the procedure.

Temporary Registers
-------------------

   Temporary registers are used to hold intermediate results of
computations within a basic block.  Each temporary register must be
defined in exactly one place and used in exactly one place.  It is
illegal to assign a value to a temporary register that is never used,
and you may not use the value in a temporary register more than once.
The Simple-SUIF library checks to make sure that these conventions are
followed.

Machine Registers
-----------------

   Machine registers correspond directly to the processor registers in
the target architecture.  They are only needed when doing register
allocation.  The machine registers are divided into general-purpose and
floating-point registers.  Each of these groups is further divided into
callee-saved and caller-saved registers.  The values in callee-saved
registers are preserved across procedures but you have to explicitly
save the caller-saved registers at each call site where they are live.
The different classes of machine registers are identified by the
following constants:

`CALLEE_GPRS'
     Callee-saved general-purpose registers.

`CALLER_GPRS'
     Caller-saved general-purpose registers.

`CALLEE_FPRS'
     Callee-saved floating-point registers.

`CALLER_FPRS'
     Caller-saved floating-point registers.

   The `num_machine_regs' array contains the number of machine
registers in each class.  For example, `num_machine_regs[CALLER_GPRS]'
is equal to the number of caller-saved general-purpose registers.
Pointers to the actual `simple_reg' structures for machine registers
are stored in the two-dimensional `machine_regs' array.  The first
array index identifies the machine register class and the second index
identifies a particular register within the class.  Note that the
second array index ranges from zero to `num_machine_regs[class]'; it is
*not* the register number.

   The current library only handles machine registers for MIPS-based
architectures.  The general-purpose registers contain signed 32-bit
variables, and the floating-point registers contain 64-bit
floating-point variables.  There is no way to access a floating-point
register as a pair of 32-bit values.  Support for other architectures
may be added in the future.

Immediate Values
================

   The `ldc' (load constant) instruction requires an operand that is a
constant value stored in a `simple_immed' structure.  These constant
values may be integers or floating-point numbers or symbolic addresses.
A `simple_immed' contains a union of these fields along with a tag to
identify which field is used.  The tag value may be `IMMED_INT',
`IMMED_FLOAT', or `IMMED_SYMBOL'.

   A symbolic address is specified by a symbol and a constant integer
offset.  The offset is specified in terms of bits.  For example, to get
the address of a field within a structure, the `simple_immed' would
contain a pointer to the `simple_sym' of the variable with the offset
equal to the number of bits between the beginning of the structure and
the desired field.

Instructions
============

   Instructions are the primary data structure in Simple-SUIF.  Each
procedure is represented by a doubly-linked list of instructions.  These
instructions contain references to the various types, symbols, and
registers.  Simple-SUIF instructions resemble assembly language
instructions.  Each one performs a relatively simple operation specified
by its opcode.  Most instructions have several operands in registers.

   Instructions are stored in `simple_instr' structures.  All
instructions share several fields: the opcode, the result type, and
pointers to the next and previous instructions.  Since different
instructions require different kinds of operands, the rest of the fields
in the `simple_instr' structure are specific to the instruction format.
The `simple_op_format' function may be used to identify the format
used for a particular opcode.  The possible format values are:

`BASE_FORM'
     This format provides a destination register and two source
     registers and is used for most of the opcodes.  Not all of the
     registers are always used.  For example, `nop' (no operation)
     instructions use none of the registers, and `cpy' (copy)
     instruction only use the destination and one of the source
     registers.

`BJ_FORM'
     Branch and jump instructions use this format which includes a
     reference to the target label and an optional source register.
     The source register is only used with conditional branch
     instructions.

`LDC_FORM'
     Load constant (`ldc') instructions use this format.  It includes a
     destination register and a `simple_immed' structure to hold the
     immediate value.  See Immediate Values.

`CALL_FORM'
     This format is only used for procedure `call' instructions.  There
     are at least two register operands: the destination and the
     address of the procedure to be called.  The format also includes a
     field to record the number of arguments and an array of the
     argument registers.

`MBR_FORM'
     Multi-way branch (`mbr') instructions use this format.  The fields
     include a source register, an integer offset, a default target
     label, and an array of other target labels.

`LABEL_FORM'
     Label (`lab') instructions identify the position of a label in the
     instruction list.  They use this format which only contains a
     reference to the label symbol.

   The result type of an instruction identifies the type of the value
produced for the destination register.  If the instruction format does
not contain a destination register or if the particular opcode does not
use the destination, the result type should always be a `VOID_TYPE'.
Otherwise, the result type must always be supplied and should generally
be the same as the type of the variable in the destination register.
In rare cases, the destination register field may be set to
`NO_REGISTER' even though the instruction produces a result.  When this
happens, the result type should indicate the type of the value that is
actually produced even though that value is unused.

   Unlike the other Simple-SUIF data structures, instructions can be
freely modified and rearranged.  The library includes functions to help
create new instructions and deallocate them when they are no longer
needed.  The `new_instr' function creates a new `simple_instr' object
given the opcode and result type.  The other fields must be filled in
separately.  Note that this function is merely a convenience; nothing
special is required when creating new instructions, and users are free
to create them by calling `malloc' and setting the opcode and result
type manually.  The `free_instr' function deallocates the storage used
by an instruction.  Again, this function does nothing magic and is only
provided for convenience.

   The following table lists all of the Simple-SUIF opcodes.  Each
opcode has an internal representation that is a member of the
`simple_op' enumeration.  The `simple_op_name' function may be used to
produce a textual representation for an opcode.  The table lists both
forms.  Unless indicated otherwise, the opcodes use the `BASE_FORM'
format.

`nop NOP_OP'
     Do nothing at all.  All of the register operands for these
     instructions should be set to `NO_REGISTER', and the result type
     should be a `VOID_TYPE'.

`load LOAD_OP'
     Load the value at the address contained in the `src1' register and
     put it in the `dst' register.  The result type may be any type and
     indicates the type of the value being loaded.  The type of the
     variable in `src1' must be a pointer to the result type.  The
     `src2' register is not used.

`str STR_OP'
     Store the value in the `src2' register at the address contained in
     the `src1' register.  Both registers must be specified.  The
     `src2' register may have any type.  The `src1' register should
     contain a variable that is a pointer to the type of the variable
     being stored.  The `dst' register is not used.

`mcpy MCPY_OP'
     Memory-to-memory copy.  Load the value from the address in the
     `src2' register and store it at the address in the `src1'
     register.  Objects of any type may be copied.  Both of the source
     registers must be pointers to the type of the object that is being
     copied.  The `dst' register is not used.

`cpy CPY_OP'
     Copy the `src1' register to the `dst' register.  The `src2'
     register is not used.  The result type must be compatible with the
     type of the source register but need not necessarily be
     equivalent.  Only scalar types are allowed here.

`cvt CVT_OP'
     Convert the `src1' register to the result type and put it in the
     `dst' register.  The `src2' register is not used.  Conversions
     should be performed in steps, changing only one attribute at a
     time.  For example, when converting from an unsigned 8-bit type to
     a signed 32-bit type, use one `cvt' instruction to change the size
     and another to make it signed.  Conversions between integer and
     floating-point types should always be made using types that are as
     close as possible in size.  Nothing can be converted to or from a
     `VOID_TYPE' type or a `RECORD_TYPE'.  `ADDRESS_TYPE' types can
     only be converted to and from integer types.

`ldc LDC_OP'
     Load a constant value.  This instruction uses the `LDC_FORM'
     format.  The `value' operand is an immediate constant stored in a
     `simple_immed' structure (see Immediate Values.).  If the
     immediate value is an integer, the result type must be a
     `SIGNED_TYPE', `UNSIGNED_TYPE' or `ADDRESS_TYPE' type.  The result
     type should be a `FLOAT_TYPE' type if the immediate is a
     floating-point value.  And finally, if the immediate value is a
     symbolic address, the result type should always be an
     `ADDRESS_TYPE' type.

`neg NEG_OP'
     Negation.  Change the sign of the value in the `src1' register and
     put the result in the `dst' register.  The `src2' register is
     unused.  The result type and the type of the registers must be
     compatible integer or floating-point types.

`add ADD_OP'
     Add the values in the `src1' and `src2' registers and put the
     result in the `dst' register.  Except for pointer additions, the
     result type and the types of the registers must be compatible
     integer or floating-point types.  Pointer addition is a special
     case.  One of the source registers may have an `ADDRESS_TYPE'
     type, as long as the other source register contains a variable
     with an integer type of the same size as the pointer; the result
     type must also be an `ADDRESS_TYPE' type.

`sub SUB_OP'
     Subtract the value in the `src2' register from the value in the
     `src1' register and put the result in the `dst' register.  Except
     for pointer subtractions, the result type and the types of the
     registers must be compatible integer or floating-point types.
     There are two special cases for pointer subtractions.  In either
     case, the `src1' register must have an `ADDRESS_TYPE' type.  First,
     the `src2' register may have an integer type of the same size as
     the pointer to produce an `ADDRESS_TYPE' value in the `dst'
     register.  Second, the `src2' register may be another
     `ADDRESS_TYPE' value to produce a value in the `dst' register with
     an integer type that is the same size as the pointers.

`mul MUL_OP'
`div DIV_OP'
     Multiply or divide the value in the `src1' register by the value in
     the `src2' register and put the result in the `dst' register.  The
     result type and the types of the registers must be compatible
     integer or floating-point types.  Integer multiplication and
     division are defined according to the rules for ANSI C.

`rem REM_OP'
`mod MOD_OP'
     Remainder and modulus.  These two instructions are very similar.
     Both divide the value in the `src1' register by the value in the
     `src2' register to find the remainder or modulus.  The `rem'
     instruction is identical to the modulus operator in ANSI C, and the
     `mod' instruction is the same except that its result is always
     guaranteed to be positive.  The result type and the types of the
     destination and source registers must be compatible integer types.

`not NOT_OP'
     Bit-wise inversion.  Compute the one's complement negation of the
     value in the `src1' register and put the result in the `dst'
     register.  The `src2' register is not used.  The result type and
     the types of the registers must be compatible `UNSIGNED_TYPE'
     types.

`and AND_OP'
`ior IOR_OP'
`xor XOR_OP'
     Compute the bit-wise AND, inclusive OR, or exclusive OR of the
     values in the `src1' and `src2' registers and put the result in the
     `dst' register.  The result type and the types of the registers
     must be compatible `UNSIGNED_TYPE' types.

`asr ASR_OP'
`lsr LSR_OP'
`lsl LSL_OP'
     Shift the value in the `src1' register right or left by the amount
     specified in the `src2' register.  The variable in the `src2'
     register must always have an `UNSIGNED_TYPE' type.  The `asr'
     instruction performs sign extension and requires that the result
     type and the types of the `dst' and `src1' registers be compatible
     `SIGNED_TYPE' types.  The `lsr' instructions does not perform sign
     extension and requires that the result type and types of the `dst'
     and `src1' register be compatible `UNSIGNED_TYPE' types.  Sign
     extension is not an issue for left shifts, so the `lsl'
     instruction only requires that the result type and the types of
     the `dst' and `src1' register be compatible integer types.

`rot ROT_OP'
     Rotate the value in the `src1' register left or right by the amount
     specified in the `src2' register.  The variable in the `src2'
     register must always have an `SIGNED_TYPE' type.  If the shift
     amount is positive, the value is rotated to the left; if it is
     negative, the value is rotated to the right.  The result type and
     the types of the `dst' and `src1' registers must be compatible
     integer types.

`seq SEQ_OP'
`sne SNE_OP'
`sl SL_OP'
`sle SLE_OP'
     Comparison instructions.  If the `src1' register is equal, not
     equal, less than, or less than or equal, respectively, to the
     `src2' register, assign the integer value one to the `dst'
     register.  Otherwise, set the `dst' register to zero.  The result
     type must always be a `SIGNED_TYPE' type.  The source registers
     must have compatible scalar types.

`jmp JMP_OP'
     Unconditional jump.  This instruction uses the `BJ_FORM' format,
     but the `src' register is unused.  The flow of control is
     unconditionally transferred to the code at target label.

`btru BTRUE_OP'
`bfls BFALSE_OP'
     Branch if true or false.  This instruction uses the `BJ_FORM'
     format.  If the `src' register, which must have an integer type,
     contains a true (non-zero) or false (zero) value, respectively,
     the flow of control is transferred to the code at the target
     label.  Otherwise, it continues with the next instruction in
     sequential order.

`mbr MBR_OP'
     Multi-way branch.  This instruction uses the `MBR_FORM' format,
     which includes an array of target labels.  The number of labels in
     the array is identified by the value of the `ntargets' field.
     Control is transferred to one of these labels depending on the
     value in the `src' register.  The variable in the `src' register
     must have a `SIGNED_TYPE' or `UNSIGNED_TYPE' type.  The integer
     value in the `offset' field is subtracted from the value in the
     `src' register and the result is used to index into the array of
     target labels.  If the index is within the range of the array, the
     instruction branches to the label at that position in the array;
     otherwise, it branches to the default label in the `deflab' field.

`lab LABEL_OP'
     Label pseudo-instruction.  This instruction uses the `LABEL_FORM'
     format.  No operation is performed by a label instruction.  Its
     only purpose is to mark the location of a label symbol in the
     instruction list.  The `lab' field must be a pointer to the
     `simple_sym' for the label.

`call CALL_OP'
     Call a procedure.  This instruction uses the `CALL_FORM' format.
     The `proc' register must hold a pointer to the procedure to be
     called.  The type of the variable in that register must be a
     pointer to the type of the procedure.  Note: Simple SUIF currently
     cannot represent procedure types, so you must use the pointer
     types that are used in the input list when referring to procedure
     addresses.  The result type of the `call' instruction must match
     the return type of the procedure.  If the result type is not a
     `VOID_TYPE' type, the `dst' register will be assigned the value
     returned by the procedure.  The `nargs' field in the `call'
     instruction indicates how many arguments are in the `args' array.
     Each entry in the `args' array is a register holding the value of
     an argument to the procedure.

`ret RET_OP'
     Return from a procedure.  Only the `src1' register is used and it
     is optional.  If specified, it is the return value and may contain
     a variable of any type.