| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
By default, GNU lightning is able to compile different functions at the same time as long as it happens in different object files, and on the other hand constrains code generation tasks to reside in a single object file.
The reason for this is not apparent, but is easily explained:
the `lightning.h' header file defines its state as a
static variable, so calls to jit_set_ip and
jit_get_ip residing in different files access different
instruction pointers. This was not done without reason: it makes
the usage of GNU lightning much simpler, as it limits the initialization
tasks to the bare minimum and removes the need to link the program
with a separate library.
On the other hand, multi-threaded or otherwise concurrent programs
require reentrancy in the code generator, so this approach cannot be
the only one. In fact, it is possible to define your own copy of
GNU lightning's instruction state by defining a variable of type
jit_state and #define-ing _jit to it:
struct jit_state lightning;
#define _jit lightning
|
You are free to define the jit_state variable as you like:
extern, static to a function, auto, or global.
This feature takes advantage of an aspect of macros (cascaded macros), which is documented thus in CPP's reference manual:
A cascade of macros is when one macro's body contains a reference to another macro. This is very common practice. For example,This is not at all the same as defining
#define BUFSIZE 1020 #define TABLESIZE BUFSIZETABLESIZEto be `1020'. The#defineforTABLESIZEuses exactly the body you specify--in this case,BUFSIZE---and does not check to see whether it too is the name of a macro; it's only when you useTABLESIZEthat the result of its expansion is checked for more macro names.This makes a difference if you change the definition of
BUFSIZEat some point in the source file.TABLESIZE, defined as shown, will always expand using the definition ofBUFSIZEthat is currently in effect: #define BUFSIZE 1020 #define TABLESIZE BUFSIZE #undef BUFSIZE #define BUFSIZE 37Now
TABLESIZEexpands (in two stages) to `37'. (The#undefis to prevent any warning about the nontrivial redefinition ofBUFSIZE.)
In the same way, jit_get_label will adopt whatever definition of
_jit is in effect:
#define jit_get_label() (_jit.pc) |
Special care must be taken when functions residing in separate files
must access the same state. This could be the case, for example, if a
special library contained function for strength reduction of
multiplications to adds & shifts, or maybe of divisions to
multiplications and shifts. The function would be compiled using a
single definition of _jit and that definition would be used
whenever the function would be called.
Since GNU lightning uses a feature of the preprocessor to obtain re-entrancy, it makes sense to rely on the preprocessor in this case too.
The idea is to pass the current struct jit_state to the
function:
static void
_opt_muli_i(jit, dest, source, n)
register struct jit_state *jit;
register int dest, source, n;
{
#define _jit jit
...
#undef _jit
}
|
doing this unbeknownst to the client, using a macro in the header file:
extern void _opt_muli_i(struct jit_state *, int, int, int); #define opt_muli_i(rd, rs, n) _opt_muli_i(&_jit, (rd), (rs), (n)) |
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |