From 16aaaa19a3ef4220726007d3e644ced0c9e06513 Mon Sep 17 00:00:00 2001 From: dec05eba Date: Mon, 9 Sep 2019 01:08:34 +0200 Subject: Allow referencing code in imported file (right now for function calls, allow calling a function in another file) --- src/bytecode/bytecode.c | 268 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 203 insertions(+), 65 deletions(-) (limited to 'src/bytecode') diff --git a/src/bytecode/bytecode.c b/src/bytecode/bytecode.c index 47d492c..0ee066c 100644 --- a/src/bytecode/bytecode.c +++ b/src/bytecode/bytecode.c @@ -20,11 +20,17 @@ } while(0) int bytecode_init(Bytecode *self, ArenaAllocator *allocator) { + self->import_index = 0; + self->funcs_index = 0; + self->extern_funcs_index = 0; + self->offset = 0; return buffer_init(&self->data, allocator); } /*doc(Bytecode) -The layout of the full bytecode is: Header (Intermediates Strings Functions External_Functions Exported_Functions Instructions)* +The layout of the full bytecode is: Header (X Intermediates X Strings X Functions X External_Functions X Exported_Functions X Imports X Instructions)*\ +Where the X is a magic number to make it easier to find errors while decoding the bytecode.\ +The value of the magic number is @AMAL_BYTECODE_SECTION_MAGIC_NUMBER */ CHECK_RESULT int buffer_append_header(Buffer *program_data) { @@ -61,10 +67,10 @@ static CHECK_RESULT usize ssa_extract_data(u8 *instruction_data, void *result, u static void add_intermediates(BytecodeCompilerContext *self) { /*doc(Bytecode intermediates) # Intermediates layout - |Type |Field |Description | - |------------|------------------|-------------------------------------------------------------------------------| - |u32 |Intermediates size|The size of the intermediates section, in bytes. | - |Intermediate|Intermediate data |Multiple intermediates, where the total size is defined by @Intermediates size.| + |Type |Field |Description | + |--------------|------------------|-------------------------------------------------------------------------------| + |u32 |Intermediates size|The size of all intermediates, in bytes. | + |Intermediate[]|Intermediate data |Multiple intermediates, where the total size is defined by @Intermediates size.| # Intermediate |Type|Field|Description | @@ -74,7 +80,7 @@ static void add_intermediates(BytecodeCompilerContext *self) { */ Ssa *ssa = self->parser->ssa; - Buffer *instructions = &self->bytecode.data; + Buffer *instructions = &self->bytecode->data; SsaNumber *intermediate = buffer_begin(&ssa->intermediates); SsaNumber *intermediates_end = buffer_end(&ssa->intermediates); int i = 0; @@ -93,11 +99,11 @@ static void add_intermediates(BytecodeCompilerContext *self) { static void add_strings(BytecodeCompilerContext *self) { /*doc(Bytecode strings) # Strings layout - |Type |Field |Description | - |------|-----------------|------------------------------------------------------------------| - |u16 |Number of strings|The number of strings. | - |u32 |Strings size |The size of the strings section, in bytes. | - |String|Strings data |Multiple strings, where the total size is defined by @Strings size| + |Type |Field |Description | + |--------|-----------------|------------------------------------------------------------------| + |u16 |Number of strings|The number of strings. | + |u32 |Strings size |The size of all strings, in bytes. | + |String[]|Strings data |Multiple strings, where the total size is defined by @Strings size| # String |Type|Field|Description | @@ -107,7 +113,7 @@ static void add_strings(BytecodeCompilerContext *self) { */ Ssa *ssa = self->parser->ssa; - Buffer *instructions = &self->bytecode.data; + Buffer *instructions = &self->bytecode->data; BufferView *string = buffer_begin(&ssa->strings); BufferView *strings_end = buffer_end(&ssa->strings); u32 strings_size = 0; @@ -128,36 +134,105 @@ static void add_strings(BytecodeCompilerContext *self) { } } +static TypeSize function_signature_get_params_size(FunctionSignature *self) { + FunctionParameter *param = buffer_begin(&self->parameters); + FunctionParameter *param_end = buffer_end(&self->parameters); + TypeSize params_total_size; + params_total_size.num_pointers = 0; + params_total_size.fixed_size = 0; + for(; param != param_end; ++param) { + TypeSize param_size = resolved_type_get_byte_size(¶m->resolve_data.type); + params_total_size.num_pointers += param_size.num_pointers; + params_total_size.fixed_size += param_size.fixed_size; + } + return params_total_size; +} + +static TypeSize function_signature_get_return_types_size(FunctionSignature *self) { + FunctionReturnType *return_type = buffer_begin(&self->return_types); + FunctionReturnType *return_type_end = buffer_end(&self->return_types); + TypeSize return_types_total_size; + return_types_total_size.num_pointers = 0; + return_types_total_size.fixed_size = 0; + for(; return_type != return_type_end; ++return_type) { + TypeSize param_size = resolved_type_get_byte_size(&return_type->resolved_type); + return_types_total_size.num_pointers += param_size.num_pointers; + return_types_total_size.fixed_size += param_size.fixed_size; + } + return return_types_total_size; +} + static void add_functions(BytecodeCompilerContext *self) { /*doc(Bytecode functions) - # Internal functions layout - |Type|Field |Description | - |----|-------------------|---------------------------------| - |u16 |Number of functions|The number of internal functions.| + # Functions layout + |Type |Field |Description | + |----------|----------|--------------------------------------------------------------------------------------| + |u16 |num_funcs |The number of non-extern functions. | + |u32 |funcs_size|The size of all functions, in bytes. | + |Function[]|Functions |Multiple non-extern functions, where the number of functions is defined by @num_funcs.| + + # Function + |Type|Field |Description | + |----|-------------------------|------------------------------------------------------------------------------------------------------------------------| + |u32 |func_offset |The offset in the program code (machine code) where the function starts. Is always 0 until the program has been started.| + |u8 |num_params |The number of parameters. | + |u32 |params_num_pointers |The number of pointers in the parameters. | + |u32 |params_fixed_size |The size of all non-pointer type parameters, in bytes. | + |u8 |num_return_types |The number of return values. | + |u32 |return_types_num_pointers|The number of pointers in the return types. | + |u32 |return_types_fixed_size |The size of all non-pointer type return types, in bytes. | */ - assert(sizeof(SsaFuncIndex) == sizeof(u16) && "Program decoder needs to be updated since size of func index has changed"); - throw_if_error(buffer_append(&self->bytecode.data, &self->parser->ssa->func_counter, sizeof(u16))); + Ssa *ssa = self->parser->ssa; + Buffer *instructions = &self->bytecode->data; + SsaFunc *func = buffer_begin(&ssa->funcs); + SsaFunc *func_end = buffer_end(&ssa->funcs); + u32 funcs_size = ssa->func_counter * sizeof(BytecodeHeaderFunction); + assert(sizeof(BytecodeHeaderFunction) == 22); + + self->bytecode->funcs_index = instructions->size; + amal_log_debug("func index: %d", self->bytecode->funcs_index); + throw_if_error(buffer_expand(instructions, sizeof(u16) + sizeof(u32) + funcs_size)); + throw_if_error(buffer_append(instructions, &ssa->func_counter, sizeof(u16))); + throw_if_error(buffer_append(instructions, &funcs_size, sizeof(u32))); + for(; func != func_end; ++func) { + BytecodeHeaderFunction header_func; + TypeSize params_total_size = function_signature_get_params_size(func->func_sig); + TypeSize return_types_total_size = function_signature_get_return_types_size(func->func_sig); + + header_func.func_offset = 0; + + header_func.num_params = buffer_get_size(&func->func_sig->parameters, FunctionParameter); + header_func.params_num_pointers = params_total_size.num_pointers; + header_func.params_fixed_size = params_total_size.fixed_size; + + header_func.num_return_types = buffer_get_size(&func->func_sig->return_types, FunctionReturnType); + header_func.return_types_num_pointers = return_types_total_size.num_pointers; + header_func.return_types_fixed_size = return_types_total_size.fixed_size; + throw_if_error(buffer_append(instructions, &header_func, sizeof(header_func))); + } + + assert(sizeof(ssa->func_counter) == sizeof(u16) && "Program decoder needs to be updated since size of func index has changed"); } static void add_extern_functions(BytecodeCompilerContext *self) { /*doc(Bytecode external functions) # External functions layout - |Type |Field |Description | - |-----------------|------------------|-----------------------------------------------------------------------------------------| - |u16 |num_extern_func |The number of external functions. | - |u32 |extern_funcs_size |The size of the external functions section, in bytes. | - |External function|External functions|Multiple external functions, where the number of functions is defined by @num_extern_func| + |Type |Field |Description | + |-------------------|------------------|-----------------------------------------------------------------------------------------| + |u16 |num_extern_func |The number of external functions. | + |u32 |extern_funcs_size |The size of all external functions, in bytes. | + |External function[]|External functions|Multiple external functions, where the number of functions is defined by @num_extern_func| # External function - |Type|Field |Description | - |----|--------|-----------------------------------------------------------------------------------------------------| - |u8 |num_args|The number of arguments the functions has. | - |u8 |name_len|The length of the external function name, in bytes. Excluding the null-terminate character. | - |u8* |name |The name of the external function, where the size is defined by @name_len. Names are null-terminated.| + |Type|Field |Description | + |----|----------|-----------------------------------------------------------------------------------------------------| + |u8 |num_params|The number of parameters the functions has. | + |u8 |name_len |The length of the external function name, in bytes. Excluding the null-terminate character. | + |u8[]|name |The name of the external function, where the size is defined by @name_len. Names are null-terminated.| */ Ssa *ssa = self->parser->ssa; - Buffer *instructions = &self->bytecode.data; + Buffer *instructions = &self->bytecode->data; SsaExternFunc *extern_func = buffer_begin(&ssa->extern_funcs); SsaExternFunc *extern_func_end = buffer_end(&ssa->extern_funcs); u32 extern_funcs_size = 0; @@ -167,14 +242,16 @@ static void add_extern_functions(BytecodeCompilerContext *self) { } extern_func = buffer_begin(&ssa->extern_funcs); + self->bytecode->extern_funcs_index = instructions->size; throw_if_error(buffer_expand(instructions, sizeof(u16) + sizeof(u32) + extern_funcs_size)); throw_if_error(buffer_append(instructions, &ssa->extern_func_counter, sizeof(u16))); throw_if_error(buffer_append(instructions, &extern_funcs_size, sizeof(u32))); for(; extern_func != extern_func_end; ++extern_func) { const char null_s = '\0'; - u8 num_args = buffer_get_size(&extern_func->func_sig->parameters, FunctionParameter); - throw_if_error(buffer_append(instructions, &num_args, sizeof(num_args))); + u8 num_params = buffer_get_size(&extern_func->func_sig->parameters, FunctionParameter); + throw_if_error(buffer_append(instructions, &num_params, sizeof(num_params))); /* TODO: Add namespace to the function name */ + /* u8 is fine, because the max length of a variable is 255 */ throw_if_error(buffer_append(instructions, &extern_func->name.size, sizeof(u8))); throw_if_error(buffer_append(instructions, extern_func->name.data, extern_func->name.size)); throw_if_error(buffer_append(instructions, &null_s, sizeof(char))); @@ -186,11 +263,11 @@ static void add_extern_functions(BytecodeCompilerContext *self) { static void add_export_functions(BytecodeCompilerContext *self) { /*doc(Bytecode exported functions) # Exported functions layout - |Type |Field |Description | - |-----------------|------------------|-----------------------------------------------------------------------------------------| - |u16 |num_export_func |The number of exported functions. | - |u32 |export_funcs_size |The size of the exported functions section, in bytes. | - |Exported function|Exported functions|Multiple exported functions, where the number of functions is defined by @num_export_func| + |Type |Field |Description | + |-------------------|------------------|-----------------------------------------------------------------------------------------| + |u16 |num_export_func |The number of exported functions. | + |u32 |export_funcs_size |The size of all exported functions, in bytes. | + |Exported function[]|Exported functions|Multiple exported functions, where the number of functions is defined by @num_export_func| # Exported function |Type|Field |Description | @@ -198,10 +275,10 @@ static void add_export_functions(BytecodeCompilerContext *self) { |u32 |instruction_offset|The offset in the instruction data where the exported function is defined. Is always 0 until the program has been started.| |u8 |num_args |The number of arguments the functions has. | |u8 |name_len |The length of the exported function name, in bytes. Excluding the null-terminate character. | - |u8* |name |The name of the exported function, where the size is defined by @name_len. Names are null-terminated. | + |u8[]|name |The name of the exported function, where the size is defined by @name_len. Names are null-terminated. | */ Ssa *ssa = self->parser->ssa; - Buffer *instructions = &self->bytecode.data; + Buffer *instructions = &self->bytecode->data; SsaExportFunc *export_func = buffer_begin(&ssa->export_funcs); SsaExportFunc *export_func_end = buffer_end(&ssa->export_funcs); u32 export_funcs_size = 0; @@ -228,8 +305,51 @@ static void add_export_functions(BytecodeCompilerContext *self) { assert(sizeof(SsaExportFuncIndex) == sizeof(u16) && "Program decoder needs to be updated since size of export func index has changed"); } +static void add_imports(BytecodeCompilerContext *self) { + /*doc(Bytecode imports) + # Imports layout + |Type |Field |Description | + |--------|------------|-------------------------------------------------------------------------| + |u8 |num_imports |The number of imports. | + |u32 |imports_size|The size of all imports, in bytes. | + |Import[]|Import |Multiple imports, where the number of imports is defined by @num_imports.| + + # Import + |Type|Field |Description | + |----|---------------------|----------------------------------------------------------------------------------------| + |u32 |function_index |The index in the bytecode where function header begins for the imported file. | + |u32 |extern_function_index|The index in the bytecode where the extern function header begins for the imported file.| + */ + Parser *parser = self->parser; + Buffer *instructions = &self->bytecode->data; + ParserFileScopeReference **import = buffer_begin(&parser->imports); + ParserFileScopeReference **import_end = buffer_end(&parser->imports); + u8 num_imports = 1 + (import_end - import); + u32 imports_size = num_imports * sizeof(BytecodeHeaderImport); + assert(sizeof(BytecodeHeaderImport) == 8); + + self->bytecode->import_index = instructions->size; + throw_if_error(buffer_expand(instructions, sizeof(u8) + sizeof(u32) + imports_size)); + throw_if_error(buffer_append(instructions, &num_imports, sizeof(num_imports))); + throw_if_error(buffer_append(instructions, &imports_size, sizeof(imports_size))); + + /* The first import is always a reference to itself */ + throw_if_error(buffer_append(instructions, &self->bytecode->funcs_index, sizeof(self->bytecode->funcs_index))); + throw_if_error(buffer_append(instructions, &self->bytecode->extern_funcs_index, sizeof(self->bytecode->extern_funcs_index))); + for(; import != import_end; ++import) { + /* + We don't know the index to the functions yet, so first fill them with the parser index that owns them + and after bytecode has been generated for each parser (file), modify these function indices + to point to the parsers function index in the bytecode. + */ + u32 parser_index = (*import)->file_scope_ref->parser->index; + throw_if_error(buffer_append(instructions, &parser_index, sizeof(parser_index))); + throw_if_error(buffer_append(instructions, &parser_index, sizeof(parser_index))); + } +} + static void add_ins1(BytecodeCompilerContext *self, AmalOpcode opcode, const char *fmt) { - throw_if_error(buffer_append(&self->bytecode.data, &opcode, sizeof(AmalOpcodeType))); + throw_if_error(buffer_append(&self->bytecode->data, &opcode, sizeof(AmalOpcodeType))); if(fmt) { fprintf(stderr, fmt); fputc('\n', stderr); @@ -237,7 +357,7 @@ static void add_ins1(BytecodeCompilerContext *self, AmalOpcode opcode, const cha } static void add_ins2(BytecodeCompilerContext *self, AmalOpcode opcode, i8 reg, const char *fmt) { - Buffer *instructions = &self->bytecode.data; + Buffer *instructions = &self->bytecode->data; size_t index = instructions->size; throw_if_error(buffer_append_empty(instructions, sizeof(AmalOpcodeType) + sizeof(reg))); @@ -248,7 +368,7 @@ static void add_ins2(BytecodeCompilerContext *self, AmalOpcode opcode, i8 reg, c } static void add_ins3(BytecodeCompilerContext *self, AmalOpcode opcode, i8 dst_reg, i8 src_reg, const char *fmt) { - Buffer *instructions = &self->bytecode.data; + Buffer *instructions = &self->bytecode->data; size_t index = instructions->size; throw_if_error(buffer_append_empty(instructions, sizeof(AmalOpcodeType) + sizeof(dst_reg) + sizeof(src_reg))); @@ -260,7 +380,7 @@ static void add_ins3(BytecodeCompilerContext *self, AmalOpcode opcode, i8 dst_re } static void add_ins4(BytecodeCompilerContext *self, AmalOpcode opcode, u16 data, const char *fmt) { - Buffer *instructions = &self->bytecode.data; + Buffer *instructions = &self->bytecode->data; size_t index = instructions->size; throw_if_error(buffer_append_empty(instructions, sizeof(AmalOpcodeType) + sizeof(data))); @@ -271,7 +391,7 @@ static void add_ins4(BytecodeCompilerContext *self, AmalOpcode opcode, u16 data, } static void add_ins5(BytecodeCompilerContext *self, AmalOpcode opcode, i8 dst_reg, i8 reg1, i8 reg2, const char *fmt) { - Buffer *instructions = &self->bytecode.data; + Buffer *instructions = &self->bytecode->data; size_t index = instructions->size; throw_if_error(buffer_append_empty(instructions, sizeof(AmalOpcodeType) + sizeof(dst_reg) + sizeof(reg1) + sizeof(reg2))); @@ -284,7 +404,7 @@ static void add_ins5(BytecodeCompilerContext *self, AmalOpcode opcode, i8 dst_re } static void add_ins6(BytecodeCompilerContext *self, AmalOpcode opcode, i8 dst_reg, u16 data, const char *fmt) { - Buffer *instructions = &self->bytecode.data; + Buffer *instructions = &self->bytecode->data; size_t index = instructions->size; throw_if_error(buffer_append_empty(instructions, sizeof(AmalOpcodeType) + sizeof(dst_reg) + sizeof(data))); @@ -295,16 +415,16 @@ static void add_ins6(BytecodeCompilerContext *self, AmalOpcode opcode, i8 dst_re fputc('\n', stderr); } -static void add_ins7(BytecodeCompilerContext *self, AmalOpcode opcode, u16 idx, i8 num_args, i8 dst_reg, const char *fmt) { - Buffer *instructions = &self->bytecode.data; +static void add_ins7(BytecodeCompilerContext *self, AmalOpcode opcode, u8 import_index, u16 func_index, i8 num_args, const char *fmt) { + Buffer *instructions = &self->bytecode->data; size_t index = instructions->size; - throw_if_error(buffer_append_empty(instructions, sizeof(AmalOpcodeType) + sizeof(idx) + sizeof(num_args) + sizeof(dst_reg))); + throw_if_error(buffer_append_empty(instructions, sizeof(AmalOpcodeType) + sizeof(import_index) + sizeof(func_index) + sizeof(num_args))); instructions->data[index] = opcode; - memcpy(instructions->data + index + sizeof(AmalOpcodeType), &idx, sizeof(idx)); - instructions->data[index + sizeof(AmalOpcodeType) + sizeof(idx)] = num_args; - instructions->data[index + sizeof(AmalOpcodeType) + sizeof(idx) + sizeof(num_args)] = dst_reg; - fprintf(stderr, fmt, idx, num_args, dst_reg); + memcpy(instructions->data + index + sizeof(AmalOpcodeType), &import_index, sizeof(import_index)); + memcpy(instructions->data + index + sizeof(AmalOpcodeType) + sizeof(import_index), &func_index, sizeof(func_index)); + memcpy(instructions->data + index + sizeof(AmalOpcodeType) + sizeof(import_index) + sizeof(func_index), &num_args, sizeof(num_args)); + fprintf(stderr, fmt, import_index, func_index, num_args); fputc('\n', stderr); } @@ -330,8 +450,8 @@ static void add_instructions(BytecodeCompilerContext *self) { u8 *instructions_end = buffer_end(&ssa->instructions); u16 label_counter = 0; - u32 num_instructions_index = self->bytecode.data.size; - throw_if_error(buffer_append_empty(&self->bytecode.data, sizeof(num_instructions_index))); + u32 num_instructions_index = self->bytecode->data.size; + throw_if_error(buffer_append_empty(&self->bytecode->data, sizeof(num_instructions_index))); /* TODO: Keep all registers under 256 */ while(instruction != instructions_end) { @@ -404,22 +524,21 @@ static void add_instructions(BytecodeCompilerContext *self) { add_ins2(self, AMAL_OP_PUSH, reg, "push r%d"); break; } + case SSA_PUSH_RET: { + SsaRegister reg; + am_memcpy(®, instruction, sizeof(SsaRegister)); + instruction += sizeof(SsaRegister); + add_ins2(self, AMAL_OP_PUSH_RET, reg, "push_ret r%d"); + break; + } case SSA_CALL: { - /* - TODO: Using ssa_func_index only works correctly if the function was defined in the same - file as the function call. To make this work with calling functions in other files, - ssa_func_index should also have an offset index or something like that. - So each file has it's own function list with indices and when they need to be combined in the end, - the function indices can be increased by their block index (ssa_func_index + block index), where block index - is defined as the size of all previous files' number of functions. - */ instruction += ssa_extract_data(instruction, &ssa_ins_func_call, sizeof(ssa_ins_func_call)); - add_ins7(self, AMAL_OP_CALL, ssa_ins_func_call.func_decl->ssa_func_index, ssa_ins_func_call.num_args, ssa_ins_func_call.result, "call f%d, %d, r%d"); + add_ins7(self, AMAL_OP_CALL, ssa_ins_func_call.import_index, ssa_ins_func_call.func_decl->ssa_func_index, ssa_ins_func_call.num_args, "call f(%d,%d), %d"); break; } case SSA_CALL_EXTERN: { instruction += ssa_extract_data(instruction, &ssa_ins_func_call_extern, sizeof(ssa_ins_func_call_extern)); - add_ins7(self, AMAL_OP_CALLE, ssa_ins_func_call_extern.extern_func_index, ssa_ins_func_call_extern.num_args, ssa_ins_func_call_extern.result, "calle ef%d, %d, r%d"); + add_ins7(self, AMAL_OP_CALLE, ssa_ins_func_call_extern.import_index, ssa_ins_func_call_extern.func_decl_lhs->extern_index, ssa_ins_func_call_extern.num_args, "calle ef(%d,%d), %d"); break; } case SSA_JUMP_ZERO: { @@ -450,16 +569,35 @@ static void add_instructions(BytecodeCompilerContext *self) { /* Prepend instructions with its size */ { /* -sizeof to Remove the count itself from the size of the instructions size */ - const u32 instructions_size = self->bytecode.data.size - num_instructions_index - sizeof(instructions_size); - am_memcpy(self->bytecode.data.data + num_instructions_index, &instructions_size, sizeof(instructions_size)); + const u32 instructions_size = self->bytecode->data.size - num_instructions_index - sizeof(instructions_size); + am_memcpy(self->bytecode->data.data + num_instructions_index, &instructions_size, sizeof(instructions_size)); } } +static void add_section_magic_number(BytecodeCompilerContext *self) { + const u32 section_magic_number = AMAL_BYTECODE_SECTION_MAGIC_NUMBER; + throw_if_error(buffer_append(&self->bytecode->data, §ion_magic_number, sizeof(section_magic_number))); +} + void generate_bytecode_from_ssa(BytecodeCompilerContext *self) { + add_section_magic_number(self); add_intermediates(self); + + add_section_magic_number(self); add_strings(self); + + add_section_magic_number(self); add_functions(self); + + add_section_magic_number(self); add_extern_functions(self); + + add_section_magic_number(self); add_export_functions(self); + + add_section_magic_number(self); + add_imports(self); + + add_section_magic_number(self); add_instructions(self); } -- cgit v1.2.3