// REG - Register // INS - Instruction // // Instructions // enum Operation: U16{ END_OF_INSTRUCTIONS, POP_STACK, PUSH_STACK, LOAD_CONSTANT, LOAD_FROM_MEMORY8, LOAD_FROM_MEMORY16, LOAD_FROM_MEMORY32, LOAD_FROM_MEMORY64, STORE_TO_MEMORY8, STORE_TO_MEMORY16, STORE_TO_MEMORY32, STORE_TO_MEMORY64, // // Generated using code_generating_script.py // INS_ADD_S64, INS_SUB_S64, INS_DIV_S64, INS_MUL_S64, INS_MOD_S64, INS_SHR_S64, INS_SHL_S64, INS_BITAND_S64, INS_BITOR_S64, INS_BITXOR_S64, INS_BITNOT_S64, INS_EQ_S64, INS_NEQ_S64, INS_GT_S64, INS_LT_S64, INS_OR_S64, INS_GTE_S64, INS_LTE_S64, INS_ADD_U64, INS_SUB_U64, INS_DIV_U64, INS_MUL_U64, INS_MOD_U64, INS_SHR_U64, INS_SHL_U64, INS_BITAND_U64, INS_BITOR_U64, INS_BITXOR_U64, INS_BITNOT_U64, INS_EQ_U64, INS_NEQ_U64, INS_GT_U64, INS_LT_U64, INS_OR_U64, INS_GTE_U64, INS_LTE_U64, INS_ADD_F64, INS_SUB_F64, INS_DIV_F64, INS_MUL_F64, INS_EQ_F64, INS_NEQ_F64, INS_GT_F64, INS_LT_F64, INS_GTE_F64, INS_LTE_F64, // // **End** of generated using code_generating_script.py // }; union Register{ F64 f64; S64 s64; U64 *pointer_u64; U64 u64; S64 *pointer_s64; F64 *pointer_f64; U64 *pointer64; U8 *pointer; }; enum{ REG_STACK_POINTER, REG_INS_POINTER, }; struct Instruction{ Operation operation; U16 left; union{U16 right; U16 src;}; U16 dst; U64 di; // @debug_id }; struct Instruction_Constant{ Operation operation; U32 dst; Register constant; U64 di; // @debug_id U64 debug_padding; }; static_assert(sizeof(Instruction)*2 == sizeof(Instruction_Constant), "Should be double the size"); static_assert(sizeof(Instruction) % 8 == 0,"Should be 8 bit aligned"); static_assert(sizeof(Instruction_Constant) % 8 == 0,"Should be 8 bit aligned"); // // Bytecode interpreter context // struct Bc{ U64 dis; // @debug_id U8 *stack_bottom; Register registers[256]; Arena instructions; Arena stack; // We reserve 4 gibs and allocate only 4 kibs to make sure we know when we // accidently overshoot the stack by 2 gigabytes woo yeee }; function Bc create_bytecode_interp(){ Bc b = {}; { arena_init(&b.instructions, "Bytecode instructions"_s); b.instructions.alignment = 1; // Commit arena_push_size(&b.instructions, 16); arena_clear(&b.instructions); b.registers[REG_INS_POINTER].pointer = b.instructions.memory.data; } { arena_init(&b.stack, "Bytecode stack"_s); b.stack.alignment = 8; // Setup a 4 kilobyte stack arena_push_size(&b.stack, kib(4)); b.registers[REG_STACK_POINTER].pointer = b.stack_bottom = b.stack.memory.data; } return b; } function void emit_load_constant_f64(Bc *b, U8 dst, F64 constant){ auto i = exp_alloc_type(&b->instructions, Instruction_Constant); i->di = b->dis++; i->operation = LOAD_CONSTANT; i->constant.f64 = constant; i->dst = dst; } function void emit_load_constant_s64(Bc *b, U8 dst, S64 constant){ auto i = exp_alloc_type(&b->instructions, Instruction_Constant); i->di = b->dis++; i->operation = LOAD_CONSTANT; i->constant.s64 = constant; i->dst = dst; } function void emit_load_constant_u64(Bc *b, U8 dst, U64 constant){ auto i = exp_alloc_type(&b->instructions, Instruction_Constant); i->di = b->dis++; i->operation = LOAD_CONSTANT; i->constant.u64 = constant; i->dst = dst; } function void emit_push(Bc *b, U8 src){ Instruction *i = exp_alloc_type(&b->instructions, Instruction); i->di = b->dis++; i->operation = PUSH_STACK; i->src = src; } function void emit_pop(Bc *b, U8 dst){ Instruction *i = exp_alloc_type(&b->instructions, Instruction); i->di = b->dis++; i->operation = POP_STACK; i->dst = dst; } function void emit_memory(Bc *b, Operation ins, U8 dst, U8 src){ Instruction *i = exp_alloc_type(&b->instructions, Instruction); i->di = b->dis++; i->operation = ins; i->dst = dst; i->src = src; } function void emit_arithmetic(Bc *b, Operation ins, U8 left, U8 right, U8 dst){ Instruction *i = exp_alloc_type(&b->instructions, Instruction); i->di = b->dis++; i->operation = ins; i->left = left; i->right = right; i->dst = dst; } function void emit_end(Bc *b){ Instruction *i = exp_alloc_type(&b->instructions, Instruction); i->di = b->dis++; i->operation = END_OF_INSTRUCTIONS; } function void run_bytecode_interp(Bc *b){ for(;;){ auto instr = (Instruction *)b->registers[REG_INS_POINTER].pointer64; b->registers[REG_INS_POINTER].pointer += sizeof(Instruction); switch(instr->operation){ case LOAD_FROM_MEMORY64:{ U64 *load_address = b->registers[instr->src].pointer64; b->registers[instr->dst].u64 = *load_address; }break; case STORE_TO_MEMORY64:{ U64 *store_address = b->registers[instr->dst].pointer64; *store_address = b->registers[instr->src].u64; }break; case PUSH_STACK:{ U64 *stack = b->registers[REG_STACK_POINTER].pointer64; U64 src = b->registers[instr->src].u64; *stack++ = src; }break; case POP_STACK:{ U64 *stack = --b->registers[REG_STACK_POINTER].pointer64; b->registers[instr->dst].u64 = *stack; }break; case END_OF_INSTRUCTIONS:{ goto end_of_program; }break; case LOAD_CONSTANT: { b->registers[REG_INS_POINTER].pointer+=sizeof(Instruction); // Constant is twice the size of regular auto i = (Instruction_Constant *)instr; b->registers[i->dst] = i->constant; }break; // // Generated using code_generating_script.py // case INS_ADD_S64:{ S64 left = b->registers[instr->left].s64; S64 right = b->registers[instr->right].s64; b->registers[instr->dst].s64 = left + right; break; }break; case INS_SUB_S64:{ S64 left = b->registers[instr->left].s64; S64 right = b->registers[instr->right].s64; b->registers[instr->dst].s64 = left - right; break; }break; case INS_DIV_S64:{ S64 left = b->registers[instr->left].s64; S64 right = b->registers[instr->right].s64; b->registers[instr->dst].s64 = left / right; break; }break; case INS_MUL_S64:{ S64 left = b->registers[instr->left].s64; S64 right = b->registers[instr->right].s64; b->registers[instr->dst].s64 = left * right; break; }break; case INS_MOD_S64:{ S64 left = b->registers[instr->left].s64; S64 right = b->registers[instr->right].s64; b->registers[instr->dst].s64 = left % right; break; }break; case INS_SHR_S64:{ S64 left = b->registers[instr->left].s64; S64 right = b->registers[instr->right].s64; b->registers[instr->dst].s64 = left >> right; break; }break; case INS_SHL_S64:{ S64 left = b->registers[instr->left].s64; S64 right = b->registers[instr->right].s64; b->registers[instr->dst].s64 = left << right; break; }break; case INS_BITAND_S64:{ S64 left = b->registers[instr->left].s64; S64 right = b->registers[instr->right].s64; b->registers[instr->dst].s64 = left & right; break; }break; case INS_BITOR_S64:{ S64 left = b->registers[instr->left].s64; S64 right = b->registers[instr->right].s64; b->registers[instr->dst].s64 = left | right; break; }break; case INS_BITXOR_S64:{ S64 left = b->registers[instr->left].s64; S64 right = b->registers[instr->right].s64; b->registers[instr->dst].s64 = left ^ right; break; }break; case INS_BITNOT_S64:{ S64 left = (S64)b->registers[instr->left].s64; S64 *dst = b->registers[instr->dst].pointer_s64; *dst = ~left; }break; case INS_EQ_S64:{ S64 left = b->registers[instr->left].s64; S64 right = b->registers[instr->right].s64; b->registers[instr->dst].s64 = left == right; break; }break; case INS_NEQ_S64:{ S64 left = b->registers[instr->left].s64; S64 right = b->registers[instr->right].s64; b->registers[instr->dst].s64 = left != right; break; }break; case INS_GT_S64:{ S64 left = b->registers[instr->left].s64; S64 right = b->registers[instr->right].s64; b->registers[instr->dst].s64 = left > right; break; }break; case INS_LT_S64:{ S64 left = b->registers[instr->left].s64; S64 right = b->registers[instr->right].s64; b->registers[instr->dst].s64 = left < right; break; }break; case INS_OR_S64:{ S64 left = b->registers[instr->left].s64; S64 right = b->registers[instr->right].s64; b->registers[instr->dst].s64 = left || right; break; }break; case INS_GTE_S64:{ S64 left = b->registers[instr->left].s64; S64 right = b->registers[instr->right].s64; b->registers[instr->dst].s64 = left >= right; break; }break; case INS_LTE_S64:{ S64 left = b->registers[instr->left].s64; S64 right = b->registers[instr->right].s64; b->registers[instr->dst].s64 = left <= right; break; }break; case INS_ADD_U64:{ U64 left = b->registers[instr->left].u64; U64 right = b->registers[instr->right].u64; b->registers[instr->dst].u64 = left + right; break; }break; case INS_SUB_U64:{ U64 left = b->registers[instr->left].u64; U64 right = b->registers[instr->right].u64; b->registers[instr->dst].u64 = left - right; break; }break; case INS_DIV_U64:{ U64 left = b->registers[instr->left].u64; U64 right = b->registers[instr->right].u64; b->registers[instr->dst].u64 = left / right; break; }break; case INS_MUL_U64:{ U64 left = b->registers[instr->left].u64; U64 right = b->registers[instr->right].u64; b->registers[instr->dst].u64 = left * right; break; }break; case INS_MOD_U64:{ U64 left = b->registers[instr->left].u64; U64 right = b->registers[instr->right].u64; b->registers[instr->dst].u64 = left % right; break; }break; case INS_SHR_U64:{ U64 left = b->registers[instr->left].u64; U64 right = b->registers[instr->right].u64; b->registers[instr->dst].u64 = left >> right; break; }break; case INS_SHL_U64:{ U64 left = b->registers[instr->left].u64; U64 right = b->registers[instr->right].u64; b->registers[instr->dst].u64 = left << right; break; }break; case INS_BITAND_U64:{ U64 left = b->registers[instr->left].u64; U64 right = b->registers[instr->right].u64; b->registers[instr->dst].u64 = left & right; break; }break; case INS_BITOR_U64:{ U64 left = b->registers[instr->left].u64; U64 right = b->registers[instr->right].u64; b->registers[instr->dst].u64 = left | right; break; }break; case INS_BITXOR_U64:{ U64 left = b->registers[instr->left].u64; U64 right = b->registers[instr->right].u64; b->registers[instr->dst].u64 = left ^ right; break; }break; case INS_BITNOT_U64:{ U64 left = (U64)b->registers[instr->left].u64; U64 *dst = b->registers[instr->dst].pointer_u64; *dst = ~left; }break; case INS_EQ_U64:{ U64 left = b->registers[instr->left].u64; U64 right = b->registers[instr->right].u64; b->registers[instr->dst].u64 = left == right; break; }break; case INS_NEQ_U64:{ U64 left = b->registers[instr->left].u64; U64 right = b->registers[instr->right].u64; b->registers[instr->dst].u64 = left != right; break; }break; case INS_GT_U64:{ U64 left = b->registers[instr->left].u64; U64 right = b->registers[instr->right].u64; b->registers[instr->dst].u64 = left > right; break; }break; case INS_LT_U64:{ U64 left = b->registers[instr->left].u64; U64 right = b->registers[instr->right].u64; b->registers[instr->dst].u64 = left < right; break; }break; case INS_OR_U64:{ U64 left = b->registers[instr->left].u64; U64 right = b->registers[instr->right].u64; b->registers[instr->dst].u64 = left || right; break; }break; case INS_GTE_U64:{ U64 left = b->registers[instr->left].u64; U64 right = b->registers[instr->right].u64; b->registers[instr->dst].u64 = left >= right; break; }break; case INS_LTE_U64:{ U64 left = b->registers[instr->left].u64; U64 right = b->registers[instr->right].u64; b->registers[instr->dst].u64 = left <= right; break; }break; case INS_ADD_F64:{ F64 left = b->registers[instr->left].f64; F64 right = b->registers[instr->right].f64; b->registers[instr->dst].f64 = left + right; break; }break; case INS_SUB_F64:{ F64 left = b->registers[instr->left].f64; F64 right = b->registers[instr->right].f64; b->registers[instr->dst].f64 = left - right; break; }break; case INS_DIV_F64:{ F64 left = b->registers[instr->left].f64; F64 right = b->registers[instr->right].f64; b->registers[instr->dst].f64 = left / right; break; }break; case INS_MUL_F64:{ F64 left = b->registers[instr->left].f64; F64 right = b->registers[instr->right].f64; b->registers[instr->dst].f64 = left * right; break; }break; case INS_EQ_F64:{ F64 left = b->registers[instr->left].f64; F64 right = b->registers[instr->right].f64; b->registers[instr->dst].f64 = left == right; break; }break; case INS_NEQ_F64:{ F64 left = b->registers[instr->left].f64; F64 right = b->registers[instr->right].f64; b->registers[instr->dst].f64 = left != right; break; }break; case INS_GT_F64:{ F64 left = b->registers[instr->left].f64; F64 right = b->registers[instr->right].f64; b->registers[instr->dst].f64 = left > right; break; }break; case INS_LT_F64:{ F64 left = b->registers[instr->left].f64; F64 right = b->registers[instr->right].f64; b->registers[instr->dst].f64 = left < right; break; }break; case INS_GTE_F64:{ F64 left = b->registers[instr->left].f64; F64 right = b->registers[instr->right].f64; b->registers[instr->dst].f64 = left >= right; break; }break; case INS_LTE_F64:{ F64 left = b->registers[instr->left].f64; F64 right = b->registers[instr->right].f64; b->registers[instr->dst].f64 = left <= right; break; }break; // // **End** of generated using code_generating_script.py // } } end_of_program:; } function void test_interpreter(){ Bc b = create_bytecode_interp(); emit_load_constant_f64(&b, 2, 100.32); emit_load_constant_f64(&b, 3, 200.68); emit_arithmetic(&b, INS_ADD_F64, 2, 3, 4); emit_end(&b); run_bytecode_interp(&b); }