Re: ultra fast but too complex ... summary (Fergus James HENDERSON)
Tue, 23 Mar 1993 13:26:36 GMT

          From comp.compilers

Related articles
ultra fast but too complex interpreter. (1993-03-17)
ultra fast but too complex ... summary (1993-03-22)
Re: ultra fast but too complex ... summary (1993-03-23)
| List of all articles for this month |

Newsgroups: comp.compilers
From: (Fergus James HENDERSON)
Keywords: interpreter
Organization: Computer Science, University of Melbourne, Australia
References: 93-03-060 93-03-080
Date: Tue, 23 Mar 1993 13:26:36 GMT (Frans van Hoesel) writes:

>My conclusions:
>gnu-cc is faster for both the all approaches (it has global registers, and
>values-as-labels), but the features needed from gnu-c are *NOT* ansi.
>Well, how cares you could say, almost any machine has gnu-c... forget
>about ansi. I won't! I need optimizing compilers, and vectorrizing
>compilers to handle the primitive functions that will handle my vector
>data (those functions would be highly optimized) threading is only really
>fast in non-standard environments. I like the concept very much, but it
>will not work in ansi.

I happen to be writing an interpreter at the moment. For simplicity we
decided to use a stack-based bytecode, at least for the first
implementation. However that still leaves a lot of implementation
choices, eg. ie. do you use a switch statement, or do you use gcc's
labels-as-values extension, or alterately do you make each the code to
interpret each instruction a separate function, etc.

What we have done is to use a little bit of C macro-hackery to enable us
to easily code up all of these implementation strategies and select
between them by means of conditional compilation. This means that we can
actually run performance comparisons between the different versions,
instead of just guessing at the beginning of the project which method to
use, and being forced into a major rewrite if we decide to use a different

So what I would suggest to you is *don't* decide which method you will
use, until *after* you have implemented several different methods and
compared the performance of each method. (You could even have the Makefile
for your interpreter automatically generate several different versions,
test their efficiency, and then automatically install the fastest one. :-)

A description of the C macro-hackery follows; skip it if you're not

Basically it works like this: all the code to interpret each
opcode is defined in a file 'opcodes.def' like this:
/* the code to interpret POP goes here */
/* the code to interpret PUSH goes here */
By #including this file with different definitions for the OPCODE macro,
you can generate interpreters using a variety of different implementation
strategies. For example,

interpret(...some parameters...)
    ... declarations for your interpreter's registers ...

#ifdef __GNUC__
    /* Use Gnu C's "labels-as-values" extension */
    /* We use a 'paste' macro (which can be defined using ANSI C's ## operator)
          to generate labels INTERPRET_PUSH, INTERPRET_POP, etc. */
    static void *interpret_op[] = {
        #define OPCODE(opcode,code) &&paste(INTERPRET_,opcode),
        #include "opcodes.def"
        #undef OPCODE

    ... initialize the registers ...

#ifdef __GNUC__

    /* Use Gnu C's "labels-as-values" extension */

    goto *interpret_op[*reg_ip++];

    #define OPCODE(opcode,code) \
        paste(INTERPRET_,opcode): \
            { code } \
            goto *interpret_op[*reg_ip++];
    #include "opcodes.def"
    #undef OPCODE

#else /* __GNUC__ */

    /* We can't use any gcc extensions.
          Use a big switch statement instead. */

        switch (*reg_ip++)
/* We use opcodes.def to build the different cases
for the switch statement */

#define OPCODE(opcode,operand_type,code) \
case opcode: \
{ code } \
                #include "opcodes.def"
#undef OPCODE

#endif /* __GNUC__ */

Fergus Henderson

Post a followup to this message

Return to the comp.compilers page.
Search the comp.compilers archives again.