Skip to content

Instantly share code, notes, and snippets.

@m4rw3r
Created July 8, 2012 12:53
Show Gist options
  • Select an option

  • Save m4rw3r/3070816 to your computer and use it in GitHub Desktop.

Select an option

Save m4rw3r/3070816 to your computer and use it in GitHub Desktop.
Test interpreter with function-pointers
#include <inttypes.h>
#include <stdio.h>
#define Util_StaticAssert_CONCAT_(a, b) a##b
#define Util_StaticAssert_CONCAT(a, b) Util_StaticAssert_CONCAT_(a, b)
#define Util_StaticAssert(e, msg) \
enum { Util_StaticAssert_CONCAT(assert_line_, __LINE__) = 1/(!!(e)) }
struct Instruction;
union Instruction_Param;
struct Context;
typedef struct Instruction Instruction;
typedef union Instruction_Param Instruction_Param;
typedef struct Context Context;
/* TODO: More params needed? */
struct InstrFuncPtr;
typedef struct InstrFuncPtr (*InstrFunc)(Instruction *, Context *, Instruction_Param);
struct InstrFuncPtr
{
InstrFunc func;
};
union Instruction_Param
{
uint64_t asBits;
double asDouble;
struct {
uint32_t p1;
uint32_t p2;
} asUint32;
struct {
uint16_t p1;
uint16_t p2;
uint16_t p3;
uint16_t p4;
} asUint16;
};
struct Instruction
{
InstrFunc func;
Instruction_Param params;
};
Util_StaticAssert(sizeof(Instruction) == 16, "sizeof(Instruction) != 128 byte");
struct Context
{
Instruction *next_trace;
int64_t data[];
};
#define INSTR(instr_name) INSTR_ ## instr_name
#define EXPANDQUOTE(str) #str
#define INSTR_STRING(instr_name) EXPANDQUOTE(INSTR(instr_name))
#define INSTR_HANDLER(instr_name) \
/* RAX */ struct InstrFuncPtr INSTR(instr_name)(/* RDX */ Instruction *instr, /* RSI */ Context *ctx, /*RDI */ Instruction_Param params)
#define INSTR_RETURN(f) return (struct InstrFuncPtr) {.func = f};
INSTR_HANDLER(ESCAPE)
{
INSTR_RETURN(INSTR(ESCAPE));
}
#define FIRE_ESCAPE INSTR(ESCAPE)
INSTR_HANDLER(NOP)
{
INSTR_RETURN(instr[1].func);
}
INSTR_HANDLER(SUB)
{
ctx->data[params.asUint16.p1] = ctx->data[params.asUint16.p2] - ctx->data[params.asUint16.p3];
INSTR_RETURN(instr[1].func);
}
INSTR_HANDLER(BLTZ)
{
if(ctx->data[params.asUint16.p1] < 0) {
ctx->next_trace = &instr[(int32_t) params.asUint32.p2];
INSTR_RETURN(FIRE_ESCAPE);
}
INSTR_RETURN(instr[1].func);
}
INSTR_HANDLER(ADDI)
{
ctx->data[params.asUint32.p1] += (int32_t) params.asUint32.p2;
INSTR_RETURN(instr[1].func);
}
INSTR_HANDLER(ADD)
{
ctx->data[params.asUint16.p1] = ctx->data[params.asUint16.p2] + ctx->data[params.asUint16.p3];
INSTR_RETURN(instr[1].func);
}
INSTR_HANDLER(MOVE)
{
ctx->data[params.asUint16.p1] = ctx->data[params.asUint16.p2];
INSTR_RETURN(instr[1].func);
}
INSTR_HANDLER(JMP)
{
ctx->next_trace = &instr[(int32_t) params.asUint32.p1];
INSTR_RETURN(FIRE_ESCAPE);
}
INSTR_HANDLER(SET)
{
ctx->data[params.asUint16.p1] = (int32_t) params.asUint32.p2;
INSTR_RETURN(instr[1].func);
}
/* OR upper immediate */
INSTR_HANDLER(ORUI)
{
ctx->data[params.asUint16.p1] |= (params.asUint32.p2) << (uint64_t) 32;
INSTR_RETURN(instr[1].func);
}
INSTR_HANDLER(PRINT)
{
printf("var%u: %lld\n", params.asUint16.p1, ctx->data[params.asUint16.p1]);
INSTR_RETURN(instr[1].func);
}
INSTR_HANDLER(EXIT)
{
ctx->next_trace = NULL;
INSTR_RETURN(FIRE_ESCAPE);
}
void interpret(Context *ctx)
{
Instruction *iarray = ctx->next_trace;
while(iarray != NULL) {
InstrFunc iptr = iarray[0].func;
#define INTERP_STEP(i) iptr = (*iptr)(&iarray[i], ctx, iarray[i].params).func
/* TODO: Benchmarks needed to decide the number of calls in a row here */
INTERP_STEP(0);
INTERP_STEP(1);
/* iarray += 2; */
INTERP_STEP(2);
INTERP_STEP(3);
iarray += 4;
/*
INTERP_STEP(4);
INTERP_STEP(5);
iarray += 6;*/
if(iptr == INSTR(ESCAPE)) {
iarray = ctx->next_trace;
}
}
}
int main (int argc, char const *argv[])
{
uint32_t size = 32;
Context *ctx = malloc(sizeof(Context) + sizeof(uint64_t) * size);
ctx->data[0] = 44; // n
ctx->data[1] = 0; // a
ctx->data[2] = 0; // i
ctx->data[3] = 1; // b
ctx->data[4] = 0; // sum
ctx->data[5] = 0; // tmp
ctx->data[6] = 10000000; // ii
Instruction itrace[] = {
{.func = INSTR(BLTZ), .params.asUint32.p1 = 6, .params.asUint32.p2 = 15},
{.func = INSTR(SET), .params.asUint32.p1 = 0, .params.asUint32.p2 = 44},
{.func = INSTR(SET), .params.asUint32.p1 = 1, .params.asUint32.p2 = 0},
{.func = INSTR(SET), .params.asUint32.p1 = 2, .params.asUint32.p2 = 0},
{.func = INSTR(SET), .params.asUint32.p1 = 3, .params.asUint32.p2 = 1},
{.func = INSTR(SET), .params.asUint32.p1 = 4, .params.asUint32.p2 = 0},
{.func = INSTR(SUB), .params.asUint16.p1 = 5, .params.asUint16.p2 = 0, .params.asUint16.p3 = 2},
{.func = INSTR(BLTZ), .params.asUint32.p1 = 5, .params.asUint32.p2 = 6},
{.func = INSTR(ADDI), .params.asUint32.p1 = 2, .params.asUint32.p2 = 1},
{.func = INSTR(ADD), .params.asUint16.p1 = 4, .params.asUint16.p2 = 1, .params.asUint16.p3 = 3},
{.func = INSTR(MOVE), .params.asUint16.p1 = 1, .params.asUint16.p2 = 3},
{.func = INSTR(MOVE), .params.asUint16.p1 = 3, .params.asUint16.p2 = 4},
{.func = INSTR(JMP), .params.asUint32.p1 = (int32_t) -6},
{.func = INSTR(ADDI), .params.asUint32.p1 = 6, .params.asUint32.p2 = -1},
{.func = INSTR(JMP), .params.asUint32.p1 = (int32_t) -14},
{.func = INSTR(EXIT)}
};
ctx->next_trace = itrace;
interpret(ctx);
printf("sum: %lld\n", ctx->data[4]);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment