#include #include #include // Control which program gets run #define ADD1 0 #define LOOP_ITERS 10000000 // Turn on instruction counting #define COUNT 0 // Turn on direct threading #define DIRECT_THREADING 1 // Control which interp #define STACK_BASED 0 // Enable/disable CHUD #define CHUD 0 #if CHUD #include #define CHUD_INIT chudInitialize(); chudAcquireRemoteAccess(); #define CHUD_START chudStartRemotePerfMonitor("uinterp"); #define CHUD_STOP chudStopRemotePerfMonitor(); #define CHUD_CLOSE chudReleaseRemoteAccess(); #else #define CHUD_INIT #define CHUD_START #define CHUD_STOP #define CHUD_CLOSE #endif #if COUNT #define COUNT_DECL int icount = 0; #define COUNT_INCR ++icount; #define COUNT_PRINT do { std::cout << "ins count: " << icount << std::endl; std::cout << "usec/ins: " << ((double) Timer::dt()) / icount << std::endl; } while (0); #else #define COUNT_DECL #define COUNT_INCR #define COUNT_PRINT #endif #if DIRECT_THREADING typedef void *itype; #define BEGINCASE(op) op: #define ENDCASE COUNT_INCR goto **ip++; #else typedef int itype; #define BEGINCASE(op) case op: #define ENDCASE break; #endif typedef double number; namespace Timer { struct timeval t0, t1; long operator-(const struct timeval &t1, const struct timeval &t0) { return (t1.tv_usec-t0.tv_usec) + 1000000*(t1.tv_sec-t0.tv_sec); } long dt() { return t1-t0; } void start() { gettimeofday(&t0, 0); } void stop() { gettimeofday(&t1, 0); std::cout << "timer: " << dt() << std::endl; } } // Stack-based interpreter namespace Stack { #if !DIRECT_THREADING enum Op { LOAD, ADD, JMP, STORE, HALT, JGE, INCR, LOAD0, LOAD1, STORE0 }; #endif void run() { #if ADD1 #if DIRECT_THREADING itype program[] = { &&LOAD, (itype) 1, &&LOAD, (itype) 2, &&ADD, &&STORE, (itype) 0, &&HALT }; #else itype program[] = { LOAD, (itype) 1, LOAD, (itype) 2, ADD, STORE, (itype) 0, HALT }; #endif number slots[] = { 0, 2, 3 }; #else #if 0 itype program[] = { LOAD, 0, LOAD, 1, JGE, 7, LOAD, 0, INCR, STORE, 0, JMP, -13, HALT }; #endif #if DIRECT_THREADING itype program[] = { &&LOAD0, &&LOAD1, &&JGE, (itype) 6, &&LOAD0, &&INCR, &&STORE0, &&JMP, (itype) -8, &&HALT }; #else itype program[] = { LOAD0, LOAD1, JGE, (itype) 6, LOAD0, INCR, STORE0, JMP, (itype) -8, HALT }; #endif number slots[] = { 0, LOOP_ITERS }; #endif COUNT_DECL itype *ip = &program[0]; number *stack = new number[16]; --stack; Timer::start(); CHUD_START number op1, op2; #if DIRECT_THREADING COUNT_INCR goto **ip++; #else for (;;) { COUNT_INCR switch (*ip++) { #endif BEGINCASE(LOAD) *(++stack) = slots[(int) *(ip++)]; ENDCASE BEGINCASE(LOAD0) *(++stack) = slots[0]; ENDCASE BEGINCASE(LOAD1) *(++stack) = slots[1]; ENDCASE BEGINCASE(ADD) op2 = *(stack--); *stack += op2; ENDCASE BEGINCASE(INCR) ++(*stack); ENDCASE; BEGINCASE(STORE) slots[(int) *(ip++)] = *(stack--); ENDCASE BEGINCASE(STORE0) slots[0] = *(stack--); ENDCASE BEGINCASE(JGE) op2 = *(stack--); op1 = *(stack--); if (op1 >= op2) { ip += (int) (*ip); } else { ip++; } ENDCASE BEGINCASE(JMP) ip += (int) (*ip); ENDCASE BEGINCASE(HALT) goto done; #if !DIRECT_THREADING default: assert(0); } } #endif done: CHUD_STOP Timer::stop(); COUNT_PRINT std::cout << "Bytecode size: " << (sizeof(program)/sizeof(program[0])) << std::endl; std::cout << "Final data state:" << std::endl; for (int i = 0; i < sizeof(slots) / sizeof(slots[0]); ++i) { std::cout << "Slot " << i << ": " << slots[i] << std::endl; } } } // Regier-based interpreter namespace Register { #if !DIRECT_THREADING enum Op { LOAD, ADD, JMP, STORE, HALT, JGE, INCR }; #endif void run() { #if ADD1 #if DIRECT_THREADING itype program[] = { &&ADD, (itype) 1, (itype) 2, (itype) 0, &&HALT }; #else itype program[] = { ADD, 1, 2, 0, HALT }; #endif number slots[] = { 0, 2, 3 }; #else #if DIRECT_THREADING itype program[] = { &&JGE, (itype) 0, (itype) 1, (itype) 5, &&INCR, (itype) 0, &&JMP, (itype) -7, &&HALT }; #else itype program[] = { JGE, 0, 1, 5, INCR, 0, JMP, -7, HALT }; #endif number slots[] = { 0, LOOP_ITERS }; #endif COUNT_DECL itype *ip = &program[0]; Timer::start(); CHUD_START number op1, op2; #if DIRECT_THREADING COUNT_INCR; goto **ip++; #else for (;;) { COUNT_INCR; //std::cerr << "ip " << (ip - program) << std::endl; switch (*ip++) { #endif BEGINCASE(ADD) op1 = slots[(int) *(ip++)]; op2 = slots[(int) *(ip++)]; slots[(int) *(ip++)] = op1 + op2; ENDCASE BEGINCASE(INCR) ++slots[(int) *ip++]; ENDCASE BEGINCASE(JGE) op1 = slots[(int) *(ip++)]; op2 = slots[(int) *(ip++)]; if (op1 >= op2) { ip += (int) (*ip); } else { ip++; } ENDCASE; BEGINCASE(JMP) ip += (int) (*ip); ENDCASE; BEGINCASE(HALT) goto done; #if !DIRECT_THREADING default: std::cerr << (int) (*ip) << " " << ADD << std::endl; assert(0); } } #endif done: CHUD_STOP Timer::stop(); COUNT_PRINT std::cout << "Bytecode size: " << (sizeof(program)/sizeof(program[0])) << std::endl; std::cout << "Final data state:" << std::endl; for (int i = 0; i < sizeof(slots) / sizeof(slots[0]); ++i) { std::cout << "Slot " << i << ": " << slots[i] << std::endl; } } } int main() { CHUD_INIT #if STACK_BASED Stack::run(); #else Register::run(); #endif CHUD_CLOSE return 0; }