Register Classes

Overview

Two views of registers are used throughout the compiler: generic registers and machine registers. To facilitate retargeting, several classes of generic registers are defined to hide the machine registers from various phases of the compiler. Generic registers are mapped to machine registers with the likelihood that more than one class of generic registers map to a single class of machine registers. A generic register class exists for each of the register types seen by the ILI: address register, integer register (integers, booleans, char, etc.), single precision register, and double precision register. The generic register mappings are primarily used by the expander and optimizer when assigning global registers.

Depending on the target register numbers, when used as operands to ILI, reflect either actual machine register numbers or numbers which are mapped by the code scheduler to actual machine numbers. Registers can be used as arguments for calling intrinsics, and as operands to register define and move ILI. In the latter case, these ILI are typically generated by the expander and optimizer when registers have been assigned globally.

Data Structures

Machine Register Table

The target machine registers are divided into classes appropriate for the target’s architecture. Each machine register set has the following properities:

  1. each class is expressed as a set of increasing order of numbers.

  2. the scratch registers are defined by the code scheduler

  3. the global registers are allocated either in decreasing or increasing order from a given point.

  4. the scratch registers that can be changed by a procedure and intrinsic.

A machine register table is used to define the classes of machine registers, where there is one entry for each class. A table entry is defined by the following C structure declaration:

typedef struct {
    char min;
    char max;
    char first_global;
    char last_global;
    char next_global;
    char nused;
} MACH_REG;
min

minimum register number of the set.

max

maximum register number of the set (the set is defined by the closed interval [min..max]).

first_global

the first register number that can be global register.

last_global

the last register number that can be global.

next_global

the next register number that can be globally assigned. In the event that not all of the registers in the global set are assigned by the expander or optimizer, the scheduler may use the global registers not assigned as scratch registers.

nused

the number of global registers assigned by the expander or optimizer.

All but the fields next_global and nused are statically initialized; next_global and nused are modified when registers are allocated globally during the expander and optimizer phases.

It is possible that a machine’s registers cannot be expressed as the closed interval [min .. max]. If this occurs, the machine register table will describe “pseudo” machine registers which adhere to the above properties. These pseudo machine registers would be mapped to the actual machine registers. The ILI, expander, and optimizer would still refer to the registers from the machine register table. The scheduler would use the pseudo to machine register mapping when it’s neccessary to refer to an actual machine register.

Generic Register Table

The generic registers are divided into classes of registers which correspond to the types of the registers seen by the ILI. The mapping of generic registers to machine registers is described in the generic register table. Each table entry not only describes the mapping but provides information regarding global register allocation. Each table entry is defined by the following C structure declaration:

typedef struct {
    char      max;
    char      nused;
    char      joined;
    int       rcand;
    MACH_REG \*mach_reg;
    INT       const_flag;
} REG;
max

the maximum number of registers that can be globally assigned.

nused

the number of registers globally assigned.

joined

flag indicating that the registers are formed from multiple machine registers.

rcand

list of global register candidates.

mach_reg

pointer to the machine register table entry of the machine registers to which the generic class maps.

const_flag

a flag word which controls the assignment of constants to registers. The fields max, joined, mach_reg, and const_flag are statically initialized; fields nused and rcand in module machreg.c are modified when registers are allocated globally during the expander and optimizer phases.

Processing

The file machreg.h contains the specifics for the target machine’s registers such as definitions for the mach_reg structure, external declarations for the functions used to access the structure, and macro definitions used to represent various pieces of the machine registers. When constructing machreg.h, certain macros must be present: those which deal with register arguments and those which describe the machine registers. Argument macros are present which provided the register numbers for accessing argument registers where the arguments to the macros are machine dependent. There is one macro for each register type:

AR(i)

define an address register

IR(i)

define a integer register

SP(i)

define a single precision register for argument

DP(i)

define a double precision register for argument

ISP(i)

define a single precision register for an imaginary argument

IDP(i)

define a double precision register for an imaginary argument

Machine Register Macros

Special macros are used for defining the global registers in each of the unique register classes (the macro MR_UNIQ gives the number of unique classes). For each global set, the lower and upper bounds are specified in the form MR_L<i> to MR_U<i>, where <i> = 1 to MR_UNIQ. For example, if there are 2 unique classes, then the interval defined by macros MR_L1 to MR_U1 defines the global registers for set 1 and macros MR_L2 to MR_U2 defines the global registers for set 2. Note that the file machregdf.h uses these macros to data initialize the mach_reg table.

The macro, MR_NUMGLB, defines the total number of global registers for the machine. This macro is used by the optimizer to declare space for its global register history data structures.

The macro GR_THRESHOLD defines the count which a candidate must exceed before it’s assigned a register.

Program Units

The register module is composed of the C files register.c and machreg.c. The file register.c contains the following routines:

void reg_init()
  • This function initializes the register information for a function or subprogram which is passed on to the code generator and assembler.

void addrcand(ili)
int ili;
  • Add an ili to its register candidate list.

void dmprcand()
  • Dump the register candidate lists.

void dmprat(rat)
int rat;
  • Dump the register assigned table indexed by rat.

int getrcand(candl)
int candl;
  • Gets a register candidate for the list candl.

void storedums(bih, rat)
int bih, rat;
  • Generates stores of the registers in the table ```` assigned to Fortran dummy arguments. These stores are added to the block located by the block information header, bih.

void mkrtemp_init()
  • Initialize the register temporary areas; this is done when unique temps are desired during the processing of a unit (i.e., for an ILM block) but are still shared with the previous unit.

int mkrtemp(ili)
int ili;
  • Gets a register temporary whose register type is based on the type of ili.

void mkrtemp_end()
  • Routine called at the end of processing a function to so that the temps created for the next function are unique.

void mkrtemp_update(rtemp)
short rtemp[];
  • Update the maximum values for the register temporaries whose information is stored in rtemp.

void mkrtemp_copy(rtemp)
short rtemp[];
  • Copy the maximum values of the temporaries which have been allocated to the area rtemp.

int assn_rtemp(ili)
int ili;
  • Create a register temporary for ili and record the temporary and the ili in the appropriate register candidate list.

.The file machreg.c contains the following routines:

void mr_init()
  • This function initializes the fields of the structures, mach_reg and reg, for the current function or subprogram which are not statically initialized.

int mr_getreg(rtype)
int rtype;
  • This function returns a global machine register number for the register type specified by rtype. If one is not available, MR_NOREG is returned.

int mr_gindex(rtype, reg)
int rtype, reg;
  • This function maps a register type, rtype, and a global machine register number, reg, to an index value in the range 0..MR_NUMGLB-1. This routine is aware that certain register types may map to the same machine register set. This routine provides a mechanism for ensuring that the history of a machine register can be kept regardless of the many to one register type mapping.