\section{Contexts}
\label{sec:Contexts}

As mentioned in Section~\ref{sec:extension-bases}, a \emph{context} gathers
all the items that characterize the target machine into one record.  OPI
programmers don't need to concern themselves with the context data
structure; they only need to keep it set correctly for the current target.
But users who add target-machine descriptions do so by developing a refined
context that holds the characteristics of the machine they want to add.

Machine SUIF deals with only one context at a time, because compilation
typically deals with only one kinds of machine at a time.  For the rare
cases in which two machine descriptions might be needed simultaneously, you
divide the task into two phases, one for each machine.

As an OPI programmer, you see target characteristics through global
functions and through the data structures that they return.  Function
[[target_printer]], which returns a [[Printer]] pointer, is typical.  But all
this function does is to access [[the_context]], a global variable of type
[[Context*]].  This global context has a method named [[target_printer]] that
provides the implementation of the global function, which calls that
method.

So why not call such methods of [[the_context]] directly?  For one thing,
it's shorter to write calls on global functions, and these things occur
quite frequently.  More importantly, the context is not needed in some
compilation settings, such as run-time optimization.  So for portability,
code written against the OPI should be almost ``context free''.

But there is still another reason why context methods are not accessed in
OPI code.  It has to do with the way contexts are built for extensibility.
Class [[Context]] itself has no interesting functionality.  The
[[target_printer]] method is actually declared in another class, called
[[MachineContext]].  It is an interface class: [[target_printer]] and other
public methods are pure virtual methods.  [[MachineContext]] is not a
subclass of [[Context]].  It is a chunk of interface that target libraries
use when composing an actual context instance that is right for the target
in question.  The method of composition is multiple inheritance.  A typical
concrete context inherits from [[Context]], [[MachineContext]], and
[[SuifVmContext]].  (Context-interface classes are named for the libraries
that define them: [[MachineContext]] is defined in the [[machine]] library,
[[SuifVmContext]] in the [[suifvm]] library, and so on.)

So while the declared type of [[the_context]] is [[Context*]], it normally
points to an object whose class inherits not only from [[Context]], but
also from several interface classes.  A method such as [[target_printer]] is
invoked by casting [[the_context]] to type [[MachineContext*]]:

\begin{verbatim}
    dynamic_cast<MachineContext*>(the_context)->target_printer();
\end{verbatim}

Further motivation and a description of how we use multiple inheritance
from independent context-interface classes, together with dynamic casting
based on run-time type information (RTTI), can be found in the
\emph{Extender's Guide}.


\subsection{Establishing context}
\label{sec:establishing-context}

Any Machine-SUIF pass that calls one or more target-characterization
functions must first set [[the_context]].  This is accomplished by calling
[[focus(FileBlock*)]], which sets [[the_context]] using the
[[target_context]] function.

<<context creation>>=
extern Context *the_context;

Context* target_context(FileBlock*);
Context* find_context(IdString lib_name);
@

Function [[target_context]] expects to find a [[target_lib]] note on its
file-block argument giving the name of the target-specific library for the
file.  It calls [[find_context]] to obtain the corresponding context.  If
necessary [[find_context]] loads that library.  The library's
initialization code registers a function that creates a new
target-characterization context.  It registers this context-creator
function in the following map:

<<context-creator registry>>=

extern Map<IdString,Context*(*)()> the_context_creator_registry;
@

Most passes have no need to be aware of [[the_context]] or the
[[target_lib]] annotation; the latter is attached by a code-generation pass
and is usually retained through subsequent phases.  There is no need to
delete [[the_context]] at the end of the pass; [[target_context]] builds a
cache, so that context records are reused while compilation is going on and
then deleted all at once when a pass terminates.



\subsection{Class [[Context]]}

[[Context]] is an empty interface class.  It is used as a completely
library-independent handle on the current library-created context.
Although it is not expected to have subclasses, we give it a virtual
destructor.  That's because the C++ RTTI machinery can only navigate to
so-called ``polymorphic'' classes, which means those having virtual
methods.

<<class [[Context]]>>=
class Context {
  public:
    Context() { }
    virtual ~Context() { }
};
@


\subsection{Class [[MachineContext]]}

Class [[MachineContext]] is a non-trivial interface class.  It declares the
virtual methods for instruction properties and register properties.  Note
that it is \emph{not} derived fron [[Context]].

<<class [[MachineContext]]>>=
class MachineContext {
  public:
    MachineContext();
    virtual ~MachineContext();

    <<[[MachineContext]] generic-pointer method>>

    <<[[MachineContext]] register-info methods>>

    <<[[MachineContext]] printer methods>>

    <<[[MachineContext]] code-finalizer method>>

    <<[[MachineContext]] instruction-predicate methods>>

    <<[[MachineContext]] opcode-generator methods>>

    <<[[MachineContext]] opcode query methods>>

  protected:
    <<[[MachineContext]] protected matter>>
};
@

\paragraph{Target-characterization methods.}

The target's generic-pointer type, the value produced by function
[[type_addr]] (see Section~\ref{sec:types}), is fetched by:

<<[[MachineContext]] generic-pointer method>>=
    virtual TypeId type_addr() const = 0;
@

In addition, the following methods implement like-named functions for use
by register allocators (Section~\ref{sec-reg-desc}):

<<[[MachineContext]] register-info methods>>=
    virtual const Vector<const char*>& reg_names() const
	{ claim(false); static Vector<const char*> v; return v; }
    virtual const Vector<int>& reg_widths() const
	{ claim(false); static Vector<int> v; return v; }
    virtual const Vector<RegCells>& reg_models() const
	{ claim(false); static Vector<RegCells> v; return v; }

    virtual const NatSet* reg_allocatables(bool maximals = false) const
	{ claim(false); return NULL; }
    virtual const NatSet* reg_caller_saves(bool maximals = false) const
	{ claim(false); return NULL; }
    virtual const NatSet* reg_callee_saves(bool maximals = false) const
	{ claim(false); return NULL; }
    virtual int reg_maximal(int reg) const
	{ return reg; }
    virtual int reg_freedom(RegClassMask) const
	{ claim(false); return -1; }
    virtual void reg_classify(Instr*, OpndCatalog*, RegClassMap*) const
	{ claim(false); }
    virtual int reg_choice(const NatSet *pool, RegClassMask,
			   const RegCells &excluded, int width,
			   bool rotate) const
	{ claim(false); return -1; }
@

The target's [[Printer]] pointer, which corresponds to global variable
[[printer]] (Section~\ref{sec:printer}), is fetched by:

<<[[MachineContext]] printer methods>>=
    virtual Printer* target_printer() const = 0;
@

And similarly for its [[CPrinter]] pointer:

<<[[MachineContext]] printer methods>>=
    virtual CPrinter* target_c_printer() const = 0;
@

The target's [[CodeFin]] generator, which corresponds to global function
[[target_code_fin]] (Section~\ref{sec:CodeFin}), is fetched by the method:

<<[[MachineContext]] code-finalizer method>>=
    virtual CodeFin* target_code_fin() const = 0;
@

The target-specific instruction predicates described in
Section~\ref{sec:machine-instr-predicates} are implemented by like-named
methods of [[MachineContext]].

<<[[MachineContext]] instruction-predicate methods>>=
    virtual bool is_ldc(Instr*) const = 0;
    virtual bool is_move(Instr*) const = 0;
    virtual bool is_cmove(Instr*) const = 0;
    virtual bool is_line(Instr*) const = 0;
    virtual bool is_ubr(Instr*) const = 0;
    virtual bool is_cbr(Instr*) const = 0;
    virtual bool is_call(Instr*) const = 0;
    virtual bool is_return(Instr*) const = 0;
    virtual bool is_binary_exp(Instr*) const = 0;
    virtual bool is_unary_exp(Instr*) const = 0;
    virtual bool is_commutative(Instr*) const = 0;
    virtual bool is_two_opnd(Instr*) const = 0;
    virtual bool reads_memory(Instr*) const = 0;
    virtual bool writes_memory(Instr*) const = 0;
    virtual bool is_builtin(Instr*) const = 0;
@

The target-specific opcode generators described in
Section~\ref{sec:machine-opcodes} are implemented by like-named methods of
[[MachineContext]].

<<[[MachineContext]] opcode-generator methods>>=
    virtual int opcode_line() const = 0;
    virtual int opcode_ubr() const = 0;
    virtual int opcode_move(TypeId) const = 0;
    virtual int opcode_load(TypeId) const = 0;
    virtual int opcode_store(TypeId) const = 0;
    virtual int opcode_cbr_inverse(int cbr_opcode) const = 0;
@

Likewise for the functions that ask target-specific questions about
opcodes.

<<[[MachineContext]] opcode query methods>>=
    virtual bool target_implements(int opcode) const = 0;
    virtual char* opcode_name(int opcode) const = 0;
@


\paragraph{Protected fields.}
\label{sec:context-implementation}

Class [[MachineContext]] is not quite a pure abstract interface.  For the
convenience of target-library implementors, it contains fields for caching
the heap-allocated data objects that may be produced through the interface.
These are owned by the context and are deleted when it is destructed.

<<[[MachineContext]] protected matter>>=
    mutable Printer *cached_printer;
    mutable CPrinter *cached_c_printer;
    mutable CodeFin *cached_code_fin;
@


\subsection{Header file [[contexts.h]]}

The header file for contexts has the following outline:

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

<<Machine-SUIF copyright>>

#ifndef MACHINE_CONTEXT_H
#define MACHINE_CONTEXT_H

#include <machine/copyright.h>

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

#include <machine/substrate.h>
#include <machine/problems.h>
#include <machine/opnd.h>
#include <machine/instr.h>
#include <machine/reg_info.h>
#include <machine/code_fin.h>
#include <machine/printer.h>
#include <machine/c_printer.h>

<<class [[Context]]>>

<<class [[MachineContext]]>>

<<context creation>>

<<context-creator registry>>

#endif /* MACHINE_CONTEXT_H */
@
