From 5a8f36b16a046f370cbccaa68a6b3b934238b6bc Mon Sep 17 00:00:00 2001 From: Krzosa Karol Date: Mon, 20 Jun 2022 19:27:22 +0200 Subject: [PATCH] Bytecode interpreter init --- bytecode_interpreter.cpp | 208 +++++++++++++++++++++++++ bytecode_interpreter_generated.cpp | 234 +++++++++++++++++++++++++++++ code_generating_script.py | 68 +++++++++ main.cpp | 3 + programs/any.kl | 2 +- 5 files changed, 514 insertions(+), 1 deletion(-) create mode 100644 bytecode_interpreter.cpp create mode 100644 bytecode_interpreter_generated.cpp create mode 100644 code_generating_script.py diff --git a/bytecode_interpreter.cpp b/bytecode_interpreter.cpp new file mode 100644 index 0000000..2582d21 --- /dev/null +++ b/bytecode_interpreter.cpp @@ -0,0 +1,208 @@ +// +// Instructions +// +enum{ + INS_PUSH_S64, + INS_PUSH_S32, + INS_PUSH_S16, + INS_PUSH_S8 , + INS_PUSH_U64, + INS_PUSH_U32, + INS_PUSH_U16, + INS_PUSH_U8 , + INS_PUSH_F64 , + INS_PUSH_F32 , + INS_POP, + + INS_ADD, + INS_SUB, + INS_MUL, + INS_DIV, +}; + +// +// Bytecode interpreter context +// +struct Bc{ + U8 *ins_pointer; + U8 *stack_pointer; + U8 *stack_bottom; + Arena instructions; + Arena stack; +}; +#define C(type, data) ((type *)data)[0] // Cast value to type and unpack the pointer so you can write to it +#include "bytecode_interpreter_generated.cpp" + +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.ins_pointer = b.instructions.memory.data; + } + + { + arena_init(&b.stack, "Bytecode stack"_s); + b.stack.alignment = 8; + + // Commit + arena_push_size(&b.stack, 16); + arena_clear(&b.stack); + b.stack_pointer = b.stack_bottom = b.stack.memory.data; + } + + return b; +} + +force_inline void +emit_pop(Bc *bc){ + U8 *instruction = (U8 *)arena_push_size(&bc->instructions, sizeof(U8)); + *instruction = INS_POP; +} + +force_inline void * +stack_pop(Bc *b){ + assert_msg(b->stack_pointer != b->stack_bottom, "Reached bottom of bytecode interpreter stack"); + b->stack_pointer -= sizeof(U64); + // @warning we don't do anything with type for now + Ast_Type_Kind *type = (Ast_Type_Kind *)b->stack_pointer; + b->stack_pointer -= sizeof(U64); + return b->stack_pointer; +} + +function void +run_bytecode_interp(Bc *b){ + for(;;){ + U8 instruction = *b->ins_pointer++; + switch(instruction){ + + case INS_POP:{ + void *value = stack_pop(b); + S64 *s64 = (S64 *)value; + F64 *f64 = (F64 *)value; + U64 *u64 = (U64 *)value; + } break; + + // + // Generated using code_generating_script.py + // + + case INS_PUSH_S64:{ + // Fetch value from instruction + // instructions are tightly packed so we + // move pointer by the type size + auto value = (S64 *)b->ins_pointer; + b->ins_pointer += sizeof(S64); + stack_push_s64(b, *value); + } break; + + case INS_PUSH_S32:{ + // Fetch value from instruction + // instructions are tightly packed so we + // move pointer by the type size + auto value = (S32 *)b->ins_pointer; + b->ins_pointer += sizeof(S32); + stack_push_s32(b, *value); + } break; + + case INS_PUSH_S16:{ + // Fetch value from instruction + // instructions are tightly packed so we + // move pointer by the type size + auto value = (S16 *)b->ins_pointer; + b->ins_pointer += sizeof(S16); + stack_push_s16(b, *value); + } break; + + case INS_PUSH_S8:{ + // Fetch value from instruction + // instructions are tightly packed so we + // move pointer by the type size + auto value = (S8 *)b->ins_pointer; + b->ins_pointer += sizeof(S8); + stack_push_s8(b, *value); + } break; + + case INS_PUSH_U64:{ + // Fetch value from instruction + // instructions are tightly packed so we + // move pointer by the type size + auto value = (U64 *)b->ins_pointer; + b->ins_pointer += sizeof(U64); + stack_push_u64(b, *value); + } break; + + case INS_PUSH_U32:{ + // Fetch value from instruction + // instructions are tightly packed so we + // move pointer by the type size + auto value = (U32 *)b->ins_pointer; + b->ins_pointer += sizeof(U32); + stack_push_u32(b, *value); + } break; + + case INS_PUSH_U16:{ + // Fetch value from instruction + // instructions are tightly packed so we + // move pointer by the type size + auto value = (U16 *)b->ins_pointer; + b->ins_pointer += sizeof(U16); + stack_push_u16(b, *value); + } break; + + case INS_PUSH_U8:{ + // Fetch value from instruction + // instructions are tightly packed so we + // move pointer by the type size + auto value = (U8 *)b->ins_pointer; + b->ins_pointer += sizeof(U8); + stack_push_u8(b, *value); + } break; + + case INS_PUSH_F32:{ + // Fetch value from instruction + // instructions are tightly packed so we + // move pointer by the type size + auto value = (F32 *)b->ins_pointer; + b->ins_pointer += sizeof(F32); + stack_push_f32(b, *value); + } break; + + case INS_PUSH_F64:{ + // Fetch value from instruction + // instructions are tightly packed so we + // move pointer by the type size + auto value = (F64 *)b->ins_pointer; + b->ins_pointer += sizeof(F64); + stack_push_f64(b, *value); + } break; + + // + // **End** of generated using code_generating_script.py + // + + default: invalid_codepath; + } + + + } +} + +function void +test_interpreter(){ + Bc b = create_bytecode_interp(); + emit_push_s64(&b, 1); + emit_push_f64(&b, 2.42f); + emit_push_s8(&b, 3); + emit_push_u16(&b, 4); + emit_pop(&b); + emit_pop(&b); + emit_pop(&b); + emit_pop(&b); + run_bytecode_interp(&b); +} \ No newline at end of file diff --git a/bytecode_interpreter_generated.cpp b/bytecode_interpreter_generated.cpp new file mode 100644 index 0000000..432cf05 --- /dev/null +++ b/bytecode_interpreter_generated.cpp @@ -0,0 +1,234 @@ + +// +// Generated using code_generating_script.py +// + + + force_inline void + stack_push_s64(Bc *b, S64 value){ + U64 allocation_size = 2*sizeof(U64); + auto data = (U8 *)arena_push_size(&b->stack, allocation_size); + + C(S64, data) = value; + data += sizeof(U64); + + C(U64, data) = TYPE_S64; + + b->stack_pointer += allocation_size; + } + + force_inline void + emit_push_s64(Bc *bc, S64 emit_value){ + U8 *instruction = (U8 *)arena_push_size(&bc->instructions, sizeof(U8)+sizeof(S64)); + *instruction = INS_PUSH_S64; + + S64 *value = (S64 *)(instruction + 1); + *value = emit_value; + } + + + force_inline void + stack_push_s32(Bc *b, S32 value){ + U64 allocation_size = 2*sizeof(U64); + auto data = (U8 *)arena_push_size(&b->stack, allocation_size); + + C(S32, data) = value; + data += sizeof(U64); + + C(U64, data) = TYPE_S32; + + b->stack_pointer += allocation_size; + } + + force_inline void + emit_push_s32(Bc *bc, S32 emit_value){ + U8 *instruction = (U8 *)arena_push_size(&bc->instructions, sizeof(U8)+sizeof(S32)); + *instruction = INS_PUSH_S32; + + S32 *value = (S32 *)(instruction + 1); + *value = emit_value; + } + + + force_inline void + stack_push_s16(Bc *b, S16 value){ + U64 allocation_size = 2*sizeof(U64); + auto data = (U8 *)arena_push_size(&b->stack, allocation_size); + + C(S16, data) = value; + data += sizeof(U64); + + C(U64, data) = TYPE_S16; + + b->stack_pointer += allocation_size; + } + + force_inline void + emit_push_s16(Bc *bc, S16 emit_value){ + U8 *instruction = (U8 *)arena_push_size(&bc->instructions, sizeof(U8)+sizeof(S16)); + *instruction = INS_PUSH_S16; + + S16 *value = (S16 *)(instruction + 1); + *value = emit_value; + } + + + force_inline void + stack_push_s8(Bc *b, S8 value){ + U64 allocation_size = 2*sizeof(U64); + auto data = (U8 *)arena_push_size(&b->stack, allocation_size); + + C(S8, data) = value; + data += sizeof(U64); + + C(U64, data) = TYPE_S8; + + b->stack_pointer += allocation_size; + } + + force_inline void + emit_push_s8(Bc *bc, S8 emit_value){ + U8 *instruction = (U8 *)arena_push_size(&bc->instructions, sizeof(U8)+sizeof(S8)); + *instruction = INS_PUSH_S8; + + S8 *value = (S8 *)(instruction + 1); + *value = emit_value; + } + + + force_inline void + stack_push_u64(Bc *b, U64 value){ + U64 allocation_size = 2*sizeof(U64); + auto data = (U8 *)arena_push_size(&b->stack, allocation_size); + + C(U64, data) = value; + data += sizeof(U64); + + C(U64, data) = TYPE_U64; + + b->stack_pointer += allocation_size; + } + + force_inline void + emit_push_u64(Bc *bc, U64 emit_value){ + U8 *instruction = (U8 *)arena_push_size(&bc->instructions, sizeof(U8)+sizeof(U64)); + *instruction = INS_PUSH_U64; + + U64 *value = (U64 *)(instruction + 1); + *value = emit_value; + } + + + force_inline void + stack_push_u32(Bc *b, U32 value){ + U64 allocation_size = 2*sizeof(U64); + auto data = (U8 *)arena_push_size(&b->stack, allocation_size); + + C(U32, data) = value; + data += sizeof(U64); + + C(U64, data) = TYPE_U32; + + b->stack_pointer += allocation_size; + } + + force_inline void + emit_push_u32(Bc *bc, U32 emit_value){ + U8 *instruction = (U8 *)arena_push_size(&bc->instructions, sizeof(U8)+sizeof(U32)); + *instruction = INS_PUSH_U32; + + U32 *value = (U32 *)(instruction + 1); + *value = emit_value; + } + + + force_inline void + stack_push_u16(Bc *b, U16 value){ + U64 allocation_size = 2*sizeof(U64); + auto data = (U8 *)arena_push_size(&b->stack, allocation_size); + + C(U16, data) = value; + data += sizeof(U64); + + C(U64, data) = TYPE_U16; + + b->stack_pointer += allocation_size; + } + + force_inline void + emit_push_u16(Bc *bc, U16 emit_value){ + U8 *instruction = (U8 *)arena_push_size(&bc->instructions, sizeof(U8)+sizeof(U16)); + *instruction = INS_PUSH_U16; + + U16 *value = (U16 *)(instruction + 1); + *value = emit_value; + } + + + force_inline void + stack_push_u8(Bc *b, U8 value){ + U64 allocation_size = 2*sizeof(U64); + auto data = (U8 *)arena_push_size(&b->stack, allocation_size); + + C(U8, data) = value; + data += sizeof(U64); + + C(U64, data) = TYPE_U8; + + b->stack_pointer += allocation_size; + } + + force_inline void + emit_push_u8(Bc *bc, U8 emit_value){ + U8 *instruction = (U8 *)arena_push_size(&bc->instructions, sizeof(U8)+sizeof(U8)); + *instruction = INS_PUSH_U8; + + U8 *value = (U8 *)(instruction + 1); + *value = emit_value; + } + + + force_inline void + stack_push_f32(Bc *b, F32 value){ + U64 allocation_size = 2*sizeof(U64); + auto data = (U8 *)arena_push_size(&b->stack, allocation_size); + + C(F32, data) = value; + data += sizeof(U64); + + C(U64, data) = TYPE_F32; + + b->stack_pointer += allocation_size; + } + + force_inline void + emit_push_f32(Bc *bc, F32 emit_value){ + U8 *instruction = (U8 *)arena_push_size(&bc->instructions, sizeof(U8)+sizeof(F32)); + *instruction = INS_PUSH_F32; + + F32 *value = (F32 *)(instruction + 1); + *value = emit_value; + } + + + force_inline void + stack_push_f64(Bc *b, F64 value){ + U64 allocation_size = 2*sizeof(U64); + auto data = (U8 *)arena_push_size(&b->stack, allocation_size); + + C(F64, data) = value; + data += sizeof(U64); + + C(U64, data) = TYPE_F64; + + b->stack_pointer += allocation_size; + } + + force_inline void + emit_push_f64(Bc *bc, F64 emit_value){ + U8 *instruction = (U8 *)arena_push_size(&bc->instructions, sizeof(U8)+sizeof(F64)); + *instruction = INS_PUSH_F64; + + F64 *value = (F64 *)(instruction + 1); + *value = emit_value; + } diff --git a/code_generating_script.py b/code_generating_script.py new file mode 100644 index 0000000..5da7986 --- /dev/null +++ b/code_generating_script.py @@ -0,0 +1,68 @@ +result = """ +// +// Generated using code_generating_script.py +// +""" + +types = ["S64", "S32", "S16", "S8", "U64", "U32", "U16", "U8", "F32", "F64"] + +# +# Generate utility functions +# +if False: + for T in types: + t = T.lower() + result += f""" + + force_inline void + stack_push_{t}(Bc *b, {T} value){{ + U64 allocation_size = 2*sizeof(U64); + auto data = (U8 *)arena_push_size(&b->stack, allocation_size); + + C({T}, data) = value; + data += sizeof(U64); + + C(U64, data) = TYPE_{T}; + + b->stack_pointer += allocation_size; + }} + + force_inline void + emit_push_{t}(Bc *bc, {T} emit_value){{ + U8 *instruction = (U8 *)arena_push_size(&bc->instructions, sizeof(U8)+sizeof({T})); + *instruction = INS_PUSH_{T}; + + {T} *value = ({T} *)(instruction + 1); + *value = emit_value; + }} + """ + +# +# Generate switch cases +# +if True: + for T in types: + t = T.lower() + result += f""" +case INS_PUSH_{T}:{{ + // Fetch value from instruction + // instructions are tightly packed so we + // move pointer by the type size + auto value = ({T} *)b->ins_pointer; + b->ins_pointer += sizeof({T}); + stack_push_{t}(b, *value); +}} break; + """ + +result += """ +// +// **End** of generated using code_generating_script.py +// +""" + +# +# Copy to **WINDOWS** clipboard +# +import subprocess +subprocess.run("clip", universal_newlines=True, input=result) + diff --git a/main.cpp b/main.cpp index 7bdaac7..4e390ad 100644 --- a/main.cpp +++ b/main.cpp @@ -162,6 +162,7 @@ want to export all the symbols, we can namespace them optionally. #include "typechecking.h" #include "typechecking.cpp" #include "ccodegen.cpp" +#include "bytecode_interpreter.cpp" int main(int argument_count, char **arguments){ @@ -174,6 +175,8 @@ int main(int argument_count, char **arguments){ test_string_builder(); test_intern_table(); + test_interpreter(); + exit(0); emit_line_directives = true; String program_name = "main.kl"_s; diff --git a/programs/any.kl b/programs/any.kl index 2f3ab9d..6788f54 100644 --- a/programs/any.kl +++ b/programs/any.kl @@ -33,7 +33,7 @@ test_arrays :: () for i := 0, i < length_of(array1), i+=1;; assert(0 == array1[i]) print("Thing % %", {30, 20}) - test_array_any(10, {20, 30}) + test_array_any(array_of_any = {20, 30}, any = 10) // test_array_any(10, 20, 30) // @fix Some_Struct :: struct