Created
July 8, 2012 12:53
-
-
Save m4rw3r/3070816 to your computer and use it in GitHub Desktop.
Test interpreter with function-pointers
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #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