\section{Types}
\label{sec:types}


The parlance of compiler infrastructure overloads a number of terms, such
as ``type'', ``variable'', and ``procedure'', which makes it difficult to
talk clearly about the implementation of a system like Machine SUIF.  When
we say ``OPI type'' or ``SUIF type'' or ``C++ type'', we are talking about
artifacts of our compiler's implementation.  But often we use ``type'' to
mean either a property of the program being compiled, or the object in the
compiler that represents that property.  As the length of the preceding
sentence indicates, we don't have nice crisp terminology for the latter
type of types, except to call them ``source types'', which isn't great.
It might work to say ``type object'' when referring to elements of the
infrastructure that represent types in the program being compiled, but the
OPI attempts to make a distinction between IR objects, which are accessed
indirectly via explicity pointers, and potentially lighter-weight things
like operands and types, which might not need to involve pointers.

The OPI uses the term \emph{type identifier} (and the name [[TypeId]]) for
this lightweight type representation.




The SUIF system provides us with a rich type system.  As much as
possible, we attempt to maintain type information when converting from
a SUIF IR to the Machine-SUIF IR and when performing optimizations in
Machine SUIF.  Often, however, we are interested only in some simple
type information.  For these times, we provide several predefined
type variables for your use.

The first set of predefined type variables are those that are target
independent.  We declare these type variables in
[[<<target-independent types>>]].  Each of these types is aligned.

\begin{itemize}

  \item [[type_v0]] describes a void value of size 0 bits.

  \item [[type_s8]], [[type_s16]], [[type_s32]], and [[type_s64]]
describe aligned, signed integers of the specified bit sizes.

  \item [[type_u8]], [[type_u16]], [[type_u32]], and [[type_u64]]
describe aligned, unsigned integers of the specified bit sizes.

  \item [[type_f32]], [[type_f64]], and [[type_f128]] describe
aligned, floating-point values of the specified bit sizes.

\end{itemize}

The second set are type objects whose definitions depend upon a specific
target machine.

\begin{itemize}

  \item [[type_addr]] is a function that returns the type ``pointer to
[[type_v0]]''.  The size of this type depends upon the target.  This occurs
so frequently in code, that we define the macro [[type_ptr]] to be
equivalent to [[type_addr()]].  As mentioned earlier, this is the type that
we use as the type of an address expression.

\end{itemize}

\paragraph{Target-independent type objects.}

The following are predefined type variables that are globally available
to any Machine-SUIF pass. These target-independent types are aligned.
They are initialized in [[machine/init.cc]].

<<target-independent types>>=
extern TypeId type_v0;	// void
extern TypeId type_s8;	// signed ints
extern TypeId type_s16;
extern TypeId type_s32;
extern TypeId type_s64;
extern TypeId type_u8;	// unsigned ints 
extern TypeId type_u16;
extern TypeId type_u32;
extern TypeId type_u64;
extern TypeId type_f32;	// floats
extern TypeId type_f64;
extern TypeId type_f128;
extern TypeId type_p32;	// pointers
extern TypeId type_p64;

void attach_opi_predefined_types(FileSetBlock*);
void set_opi_predefined_types(FileSetBlock*);
@

Function [[set_opi_predefined_types]] fills in the target-independent
types, which it obtains from the [[generic_types]] annotation of a
[[file_set_block]].  This note is created once at the time the Machine-SUIF
representation of a file set is first created (by function
[[attach_opi_predefined_types]]), and it is carried along
as the file set is transformed.  Using this note is an efficient way
to avoid creating redundant types in a global symbol
table.

A pass typically calls [[set_opi_predefined_types]] during its
[[do_file_set_block]] method.


\paragraph{Target-dependent type object.}

For now Machine SUIF has one target-dependent type parameter, namely the
type of a generic pointer or address on the target machine.  You fetch it
from the target context by calling [[type_addr()]].  To permit a uniform
style between the target-independent and the target-dependent types, we
define a macro, [[type_ptr]] that expands to [[type_addr()]].  Thus in both
cases a reference looks like a simple constant.

<<target-dependent type>>=
#define type_ptr type_addr()

TypeId type_addr();
@

\subsection{Header file for module [[types.h]]}

The interface file has the following layout:

<<types.h>>=
/* file "machine/types.h" */

<<Machine-SUIF copyright>>

#ifndef MACHINE_TYPES_H
#define MACHINE_TYPES_H

#include <machine/copyright.h>

#ifndef SUPPRESS_PRAGMA_INTERFACE
#pragma interface "machine/types.h"
#endif

#include <machine/substrate.h>

<<target-independent types>>

<<target-dependent type>>

void fprint(FILE*, TypeId);

#endif /* MACHINE_TYPES_H */
@
