diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/ast.c | 149 | ||||
-rw-r--r-- | src/bytecode/bytecode.c | 268 | ||||
-rw-r--r-- | src/compiler.c | 93 | ||||
-rw-r--r-- | src/parser.c | 91 | ||||
-rw-r--r-- | src/program.c | 238 | ||||
-rw-r--r-- | src/ssa/ssa.c | 99 | ||||
-rw-r--r-- | src/std/buffer.c | 13 | ||||
-rw-r--r-- | src/std/buffer_view.c | 2 | ||||
-rw-r--r-- | src/std/hash_map.c | 32 | ||||
-rw-r--r-- | src/std/log.c | 4 | ||||
-rw-r--r-- | src/std/mem.c | 3 | ||||
-rw-r--r-- | src/std/thread.c | 8 |
12 files changed, 778 insertions, 222 deletions
@@ -296,9 +296,17 @@ int funccall_init(FunctionCall *self, BufferView name, ArenaAllocator *allocator } int structdecl_init(StructDecl *self, Scope *parent, ArenaAllocator *allocator) { + self->fields_num_pointers = 0; + self->fields_fixed_size_bytes = 0; return scope_init(&self->body, parent, allocator); } +int structdecl_add_field(StructDecl *self, StructField *field, ArenaAllocator *allocator) { + Ast *body_obj; + return_if_error(ast_create(allocator, field, AST_STRUCT_FIELD, &body_obj)); + return scope_add_child(&self->body, body_obj); +} + LhsExpr* structdecl_get_field_by_name(StructDecl *self, BufferView field_name) { Ast* result; if(!hash_map_get(&self->body.named_objects, field_name, &result)) @@ -431,17 +439,16 @@ void scope_resolve(Scope *self, AstCompilerContext *context) { } static void compiler_print_error(amal_compiler *compiler, const char *ref, const char *fmt, ...) { - Tokenizer *tokenizer = amal_compiler_find_tokenizer_by_code_reference(compiler, ref); + Tokenizer *tokenizer; + va_list args; + va_start(args, fmt); + + tokenizer = amal_compiler_find_tokenizer_by_code_reference(compiler, ref); if(!tokenizer) { amal_log_error("Failed to find tokenizer for code reference %p. Is it an invalid reference?", ref ? ref : "(null)"); return; } - - va_list args; - va_start(args, fmt); - tokenizer_print_error_args(tokenizer, - tokenizer_get_code_reference_index(tokenizer, ref), - fmt, args); + tokenizer_print_error_args(tokenizer, tokenizer_get_code_reference_index(tokenizer, ref), fmt, args); va_end(args); } @@ -672,19 +679,20 @@ static void import_resolve(Ast *ast, AstCompilerContext *context) { (void)context; self = ast->value.import; ast->resolve_data.type.type = RESOLVED_TYPE_LHS_EXPR; - ast->resolve_data.type.value.lhs_expr = &self->file_scope->parser->file_decl; + ast->resolve_data.type.value.lhs_expr = &self->file_scope->file_scope_ref->parser->file_decl; } static Scope* lhsexpr_get_scope(LhsExpr *self) { - AstValue value; - value = self->rhs_expr->value; + AstValue value = self->rhs_expr->value; switch(self->rhs_expr->type) { case AST_FUNCTION_DECL: return &value.func_decl->body; case AST_STRUCT_DECL: return &value.struct_decl->body; case AST_IMPORT: - return &value.import->file_scope->parser->struct_decl.body; + /* *import_index = 1 + value.import->file_scope->import_index;*/ + assert(bool_false); + return &value.import->file_scope->file_scope_ref->parser->struct_decl.body; default: break; } @@ -715,25 +723,11 @@ static void funcdecl_resolve(Ast *self, AstCompilerContext *context) { self->resolve_data.type.value.func_sig = self->value.func_decl->signature; } -/* - Dont need to check if @self is resolved, since it will always be partially resolved when called from @funccall_resolve. - Meaning the resolve status wont be set to solved but the resolve type will be set. -*/ -bool resolved_type_is_func_decl(Ast *self) { - LhsExpr *resolved_type; - if(self->resolve_data.type.type != RESOLVED_TYPE_LHS_EXPR) - return bool_false; - resolved_type = self->resolve_data.type.value.lhs_expr; - return (resolved_type->rhs_expr && resolved_type->rhs_expr->type == AST_FUNCTION_DECL) || - resolved_type->type.type == VARIABLE_TYPE_SIGNATURE; -} - static void funccall_resolve(Ast *self, AstCompilerContext *context) { - FunctionCall *func_call; Ast **ast; Ast **ast_end; - func_call = self->value.func_call; + FunctionCall *func_call = self->value.func_call; variable_resolve(&func_call->func, context, &self->resolve_data.type); /* Attemping to use call syntax (variable_name ( ) ) with a variable that is not a function */ if(self->resolve_data.type.type != RESOLVED_TYPE_FUNC_SIG) { @@ -753,16 +747,46 @@ static void funccall_resolve(Ast *self, AstCompilerContext *context) { } } +static TypeSize variable_type_get_byte_size(VariableType *self) { + TypeSize type_size; + type_size.num_pointers = 0; + type_size.fixed_size = 0; + switch(self->type) { + case VARIABLE_TYPE_NONE: + break; + case VARIABLE_TYPE_VARIABLE: + type_size = resolved_type_get_byte_size(&self->value.variable->resolved_var.resolve_data->type); + break; + case VARIABLE_TYPE_SIGNATURE: + type_size.num_pointers = 1; + break; + } + return type_size; +} + static void structdecl_resolve(Ast *self, AstCompilerContext *context) { - StructDecl *struct_decl; - struct_decl = self->value.struct_decl; - scope_resolve(&struct_decl->body, context); + StructDecl *struct_decl = self->value.struct_decl; + Scope *body = &struct_decl->body; + scope_resolve(body, context); + + { + /* + Sum the size of all the fields into the struct, so the struct can know it's full size + without searching for it. + TODO: Exclude functions, but not function pointers. + */ + Ast **ast = buffer_begin(&body->ast_objects); + Ast **ast_end = buffer_end(&body->ast_objects); + for(; ast != ast_end; ++ast) { + TypeSize type_size = variable_type_get_byte_size(&(*ast)->value.struct_field->type); + struct_decl->fields_num_pointers += type_size.num_pointers; + struct_decl->fields_fixed_size_bytes += type_size.fixed_size; + } + } } static void structfield_resolve(Ast *self, AstCompilerContext *context) { - /* TODO: Implement */ - StructField *struct_field; - struct_field = self->value.struct_field; + StructField *struct_field = self->value.struct_field; variable_type_resolve(&struct_field->type, context, &self->resolve_data.type); } @@ -806,12 +830,30 @@ static void binop_resolve_dot_access(Ast *ast, AstCompilerContext *context) { throw(AST_ERR); } - if(self->rhs->resolve_data.type.type != RESOLVED_TYPE_LHS_EXPR || !LHS_EXPR_IS_PUB(self->rhs->resolve_data.type.value.lhs_expr)) { - compiler_print_error(context->compiler, caller_code_ref.data, "Can't access non-public field \"%.*s\"", caller_code_ref.size, caller_code_ref.data); - /* TODO: use tokenizer_print_note, once it has been added */ - /* TODO: Print type */ - compiler_print_error(context->compiler, callee_code_ref.data, "Type was declared non-public here"); - throw(AST_ERR); + { + bool invalid_dot_access = bool_true; + switch(self->rhs->resolve_data.type.type) { + case RESOLVED_TYPE_NONE: + assert(bool_false); + break; + case RESOLVED_TYPE_FUNC_SIG: { + FunctionSignature *func_sig = self->rhs->resolve_data.type.value.func_sig; + if(func_sig->func_decl && func_sig->func_decl->lhs_expr && LHS_EXPR_IS_PUB(func_sig->func_decl->lhs_expr)) + invalid_dot_access = bool_false; + break; + } + case RESOLVED_TYPE_LHS_EXPR: + invalid_dot_access = !LHS_EXPR_IS_PUB(self->rhs->resolve_data.type.value.lhs_expr); + break; + } + + if(invalid_dot_access) { + compiler_print_error(context->compiler, caller_code_ref.data, "Can't access non-public field \"%.*s\"", caller_code_ref.size, caller_code_ref.data); + /* TODO: use tokenizer_print_note, once it has been added */ + /* TODO: Print type */ + compiler_print_error(context->compiler, callee_code_ref.data, "Type was declared non-public here"); + throw(AST_ERR); + } } } @@ -895,6 +937,37 @@ static void return_expr_resolve(ReturnExpr *self, AstCompilerContext *context) { ast_resolve(self->rhs_expr, context); } +TypeSize resolved_type_get_byte_size(AstResolvedType *self) { + TypeSize type_size; + type_size.num_pointers = 0; + type_size.fixed_size = 0; + switch(self->type) { + case RESOLVED_TYPE_NONE: + break; + case RESOLVED_TYPE_LHS_EXPR: { + /* Resolved type until rhs is StructDecl or FunctionSignature */ + LhsExpr *lhs_expr = self->value.lhs_expr; + if(lhs_expr->type.type != VARIABLE_TYPE_NONE) + type_size = variable_type_get_byte_size(&lhs_expr->type); + else { + assert(lhs_expr->rhs_expr); + if(lhs_expr->rhs_expr->type == AST_STRUCT_DECL) { + StructDecl *struct_decl = lhs_expr->rhs_expr->value.struct_decl; + type_size.num_pointers = struct_decl->fields_num_pointers; + type_size.fixed_size = struct_decl->fields_fixed_size_bytes; + } else { + type_size = resolved_type_get_byte_size(&lhs_expr->rhs_expr->resolve_data.type); + } + } + break; + } + case RESOLVED_TYPE_FUNC_SIG: + type_size.num_pointers = 1; + break; + } + return type_size; +} + void ast_resolve(Ast *self, AstCompilerContext *context) { assert(self); assert(context->parser); 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); } diff --git a/src/compiler.c b/src/compiler.c index dbc1498..8dda1c6 100644 --- a/src/compiler.c +++ b/src/compiler.c @@ -25,13 +25,15 @@ static usize strnlen(const char *str, usize max_length) { } /* TODO: Allow to specify size and members? */ -static CHECK_RESULT int create_default_type(amal_compiler *compiler, const char *name, amal_default_type **default_type) { +static CHECK_RESULT int create_default_type(amal_compiler *compiler, const char *name, u32 num_pointers, u32 fixed_size, amal_default_type **default_type) { StructDecl *struct_decl; Ast *expr; LhsExpr *lhs_expr; return_if_error(arena_allocator_alloc(&compiler->allocator, sizeof(StructDecl), (void**)&struct_decl)); return_if_error(structdecl_init(struct_decl, &compiler->root_scope, &compiler->allocator)); + struct_decl->fields_num_pointers = num_pointers; + struct_decl->fields_fixed_size_bytes = fixed_size; return_if_error(arena_allocator_alloc(&compiler->allocator, sizeof(amal_default_type), (void**)default_type)); lhs_expr = &(*default_type)->lhs_expr; @@ -45,20 +47,29 @@ static CHECK_RESULT int create_default_type(amal_compiler *compiler, const char return scope_add_child(&compiler->root_scope, expr); } +static CHECK_RESULT int create_default_type_num_pointers(amal_compiler *compiler, const char *name, u32 num_pointers, amal_default_type **default_type) { + return create_default_type(compiler, name, num_pointers, 0, default_type); +} + +static CHECK_RESULT int create_default_type_fixed_size(amal_compiler *compiler, const char *name, u32 byte_size, amal_default_type **default_type) { + return create_default_type(compiler, name, 0, byte_size, default_type); +} + static CHECK_RESULT int init_default_types(amal_compiler *compiler) { - return_if_error(create_default_type(compiler, "i8", &compiler->default_types.i8)); - return_if_error(create_default_type(compiler, "i16", &compiler->default_types.i16)); - return_if_error(create_default_type(compiler, "i32", &compiler->default_types.i32)); - return_if_error(create_default_type(compiler, "i64", &compiler->default_types.i64)); - return_if_error(create_default_type(compiler, "u8", &compiler->default_types.u8)); - return_if_error(create_default_type(compiler, "u16", &compiler->default_types.u16)); - return_if_error(create_default_type(compiler, "u32", &compiler->default_types.u32)); - return_if_error(create_default_type(compiler, "u64", &compiler->default_types.u64)); - return_if_error(create_default_type(compiler, "isize", &compiler->default_types.isize)); - return_if_error(create_default_type(compiler, "usize", &compiler->default_types.usize)); - return_if_error(create_default_type(compiler, "f32", &compiler->default_types.f32)); - return_if_error(create_default_type(compiler, "f64", &compiler->default_types.f64)); - return_if_error(create_default_type(compiler, "str", &compiler->default_types.str)); + return_if_error(create_default_type_fixed_size(compiler, "i8", 1, &compiler->default_types.i8)); + return_if_error(create_default_type_fixed_size(compiler, "i16", 2, &compiler->default_types.i16)); + return_if_error(create_default_type_fixed_size(compiler, "i32", 3, &compiler->default_types.i32)); + return_if_error(create_default_type_fixed_size(compiler, "i64", 4, &compiler->default_types.i64)); + return_if_error(create_default_type_fixed_size(compiler, "u8", 1, &compiler->default_types.u8)); + return_if_error(create_default_type_fixed_size(compiler, "u16", 2, &compiler->default_types.u16)); + return_if_error(create_default_type_fixed_size(compiler, "u32", 3, &compiler->default_types.u32)); + return_if_error(create_default_type_fixed_size(compiler, "u64", 4, &compiler->default_types.u64)); + return_if_error(create_default_type_num_pointers(compiler, "isize", 1, &compiler->default_types.isize)); + return_if_error(create_default_type_num_pointers(compiler, "usize", 1, &compiler->default_types.usize)); + return_if_error(create_default_type_fixed_size(compiler, "f32", 4, &compiler->default_types.f32)); + return_if_error(create_default_type_fixed_size(compiler, "f64", 8, &compiler->default_types.f64)); + /* TODO: str should be a struct with the fields @data (ptr) and @size (usize) */ + return_if_error(create_default_type_num_pointers(compiler, "str", 1, &compiler->default_types.str)); compiler->default_types.arithmetic_types[0] = compiler->default_types.i8; compiler->default_types.arithmetic_types[1] = compiler->default_types.u8; @@ -185,6 +196,7 @@ static CHECK_RESULT int amal_compiler_load_in_this_thread(amal_compiler *compile file_scope->parser = parser; return_if_error(parser_parse_file(parser, filepath)); cleanup_if_error(amal_mutex_lock(&compiler->mutex, "amal_compiler_load_in_this_thread, add parser")); + parser->index = buffer_get_size(&compiler->parsers, Parser*); cleanup_if_error(buffer_append(&compiler->parsers, &parser, sizeof(parser))); amal_log_info("Finished parsing %.*s", filepath.size, filepath.data); result = AMAL_COMPILER_OK; @@ -224,6 +236,7 @@ static CHECK_RESULT int thread_generate_ssa(Parser *parser) { return_if_error(arena_allocator_alloc(parser->allocator, sizeof(Ssa), (void**)&compiler_context.ssa)); return_if_error(ssa_init(compiler_context.ssa, parser)); compiler_context.compiler = parser->compiler; + compiler_context.import_index = 0; parser->ssa = compiler_context.ssa; amal_log_debug("Generating SSA for file: %.*s", parser->tokenizer.code_name.size, parser->tokenizer.code_name.data); result = setjmp(compiler_context.env); @@ -238,7 +251,8 @@ static CHECK_RESULT int thread_generate_bytecode(Parser *parser) { BytecodeCompilerContext compiler_context; int result; - return_if_error(bytecode_init(&compiler_context.bytecode, parser->allocator)); + return_if_error(arena_allocator_alloc(parser->allocator, sizeof(Bytecode), (void**)&compiler_context.bytecode)); + return_if_error(bytecode_init(compiler_context.bytecode, parser->allocator)); compiler_context.parser = parser; amal_log_debug("Generating bytecode for file: %.*s", parser->tokenizer.code_name.size, parser->tokenizer.code_name.data); result = setjmp(compiler_context.env); @@ -320,14 +334,11 @@ static CHECK_RESULT int amal_compiler_dispatch_generic(amal_compiler *self, Thre } static CHECK_RESULT int amal_compiler_generate_program(amal_compiler *self) { - /* - TODO: Copying the bytecode to the program can be done using multiple threads. - Use self->threads for that. - */ + /* TODO: Copying the bytecode to the program can be done using multiple threads */ Parser **parser = buffer_begin(&self->parsers); Parser **parser_end = buffer_end(&self->parsers); for(; parser != parser_end; ++parser) { - return_if_error(amal_program_append_bytecode(self->program, &(*parser)->bytecode)); + return_if_error(amal_program_append_bytecode(self->program, (*parser)->bytecode)); } return 0; } @@ -419,6 +430,47 @@ static CHECK_RESULT int validate_main_func(FileScopeReference *main_file_scope, return 0; } +static void amal_compiler_parsers_set_bytecode_offsets(amal_compiler *self) { + /* magic number + major version + minor version + patch version */ + u32 offset = sizeof(u32) + sizeof(u8) + sizeof(u8) + sizeof(u8); + Parser **parser = buffer_begin(&self->parsers); + Parser **parser_end = buffer_end(&self->parsers); + for(; parser != parser_end; ++parser) { + (*parser)->bytecode->offset = offset; + offset += (*parser)->bytecode->data.size; + } +} + +/* TODO: Parallelize this? */ +static void amal_compiler_update_import_references(amal_compiler *self) { + Parser **parser_start = buffer_begin(&self->parsers); + Parser **parser = parser_start; + Parser **parser_end = buffer_end(&self->parsers); + amal_compiler_parsers_set_bytecode_offsets(self); + + for(; parser != parser_end; ++parser) { + u8 *import_start = (u8*)(*parser)->bytecode->data.data + (*parser)->bytecode->import_index; + u8 num_imports = *import_start; + /* TODO: Remove these kinds of offset with sizeof. They are prone to hard-to-find bugs after code change */ + BytecodeHeaderImport *header_import = (BytecodeHeaderImport*)(import_start + sizeof(u8) + sizeof(u32)); + BytecodeHeaderImport *header_import_end = header_import + num_imports; + + /* + The first import is the file itself and it already has function index, + but the index is localized to the function itself, so we need to add the offset + to the file itself as well. + */ + header_import->function_index += (*parser)->bytecode->offset; + header_import->extern_function_index += (*parser)->bytecode->offset; + ++header_import; + for(; header_import != header_import_end; ++header_import) { + Parser *imported_parser = *(parser_start + header_import->parser_index); + header_import->function_index = imported_parser->bytecode->offset + imported_parser->bytecode->funcs_index; + header_import->extern_function_index = imported_parser->bytecode->offset + imported_parser->bytecode->extern_funcs_index; + } + } +} + int amal_compiler_internal_load_file(amal_compiler *self, const char *filepath, FileScopeReference **file_scope) { ThreadWorkData thread_work_data; bool main_job; @@ -472,6 +524,7 @@ int amal_compiler_internal_load_file(amal_compiler *self, const char *filepath, amal_log_info("Finished generating SSA"); return_if_error(amal_compiler_dispatch_generic(self, THREAD_WORK_GENERATE_BYTECODE)); + amal_compiler_update_import_references(self); amal_log_info("Finished generating bytecode"); return_if_error(amal_compiler_generate_program(self)); diff --git a/src/parser.c b/src/parser.c index df326f0..01c1d9f 100644 --- a/src/parser.c +++ b/src/parser.c @@ -6,6 +6,7 @@ #include "../include/std/mem.h" #include "../include/std/log.h" #include "../include/std/alloc.h" +#include "../include/std/hash.h" #include <stdio.h> #include <stdlib.h> @@ -21,14 +22,16 @@ do { \ } while(0) #define VAR_MAX_LEN UINT8_MAX +#define FUNC_MAX_PARAMS 128 +#define FUNC_MAX_RETURN_TYPES 128 static CHECK_RESULT Ast* parser_parse_rhs(Parser *self); static CHECK_RESULT Ast* parser_parse_body(Parser *self); -static CHECK_RESULT Ast* parser_parse_struct_body(Parser *self); +static CHECK_RESULT StructField* parser_parse_struct_body(Parser *self); static CHECK_RESULT Ast* parser_parse_rhs_binop(Parser *self); static void parser_parse_var_type(Parser *self, VariableType *result); static void parser_parse_var_type_def(Parser *self, VariableType *result); -static void parser_queue_file(Parser *self, BufferView path, FileScopeReference **file_scope); +static void parser_queue_file(Parser *self, BufferView path, ParserFileScopeReference **parser_file_scope); int parser_init(Parser *self, amal_compiler *compiler, ArenaAllocator *allocator) { self->allocator = allocator; @@ -38,12 +41,15 @@ int parser_init(Parser *self, amal_compiler *compiler, ArenaAllocator *allocator self->error.index = 0; self->error.str = NULL; self->error_context = ERROR_CONTEXT_NONE; + self->index = 0; return_if_error(structdecl_init(&self->struct_decl, &compiler->root_scope, allocator)); lhsexpr_init(&self->file_decl, DECL_FLAG_EXTERN | DECL_FLAG_PUB | DECL_FLAG_CONST, create_buffer_view_null()); return_if_error(ast_create(self->allocator, &self->struct_decl, AST_STRUCT_DECL, &self->file_decl.rhs_expr)); + return_if_error(buffer_init(&self->imports, allocator)); + return_if_error(hash_map_init(&self->imports_by_name, allocator, sizeof(usize), hash_map_compare_string, amal_hash_string)); self->current_scope = &self->struct_decl.body; self->has_func_parent = bool_false; - am_memset(&self->bytecode, 0, sizeof(self->bytecode)); + self->bytecode = NULL; return PARSER_OK; } @@ -85,27 +91,24 @@ static void parser_parse_body_loop(Parser *self, Scope *scope, Token end_token) /* STRUCT_BODY_LOOP = '{' STRUCT_BODY* '}' */ -static void parser_parse_struct_body_loop(Parser *self, Scope *scope) { +static void parser_parse_struct_body_loop(Parser *self, StructDecl *struct_decl) { int result; throw_if_error(tokenizer_accept(&self->tokenizer, TOK_OPEN_BRACE)); for(;;) { - Ast *body_obj; + StructField *struct_field; bool is_end_token; throw_if_error(tokenizer_consume_if(&self->tokenizer, TOK_CLOSING_BRACE, &is_end_token)); if(is_end_token) break; - body_obj = parser_parse_struct_body(self); - result = scope_add_child(scope, body_obj); + struct_field = parser_parse_struct_body(self); + result = structdecl_add_field(struct_decl, struct_field, self->allocator); if(result == 0) { continue; } else if(result == AST_ERR_DEF_DUP) { - /* TODO: Convert ast type to string for error message */ - BufferView obj_name; - obj_name = ast_get_name(body_obj); - self->error = tokenizer_create_error(&self->tokenizer, - tokenizer_get_code_reference_index(&self->tokenizer, obj_name.data), - "Variable with the name %.*s was declared twice in the struct", obj_name.size, obj_name.data); + self->error = tokenizer_create_error(&self->tokenizer, + tokenizer_get_code_reference_index(&self->tokenizer, struct_field->name.data), + "Variable with the name %.*s was declared twice in the struct", struct_field->name.size, struct_field->name.data); self->error_context = ERROR_CONTEXT_NONE; throw(result); } else { @@ -183,18 +186,32 @@ static void parser_parse_function_return_types(Parser *self, FunctionSignature * if(var_type.type == VARIABLE_TYPE_NONE) { /* If function has no return types */ if(return_type_index == 0) - return; + break; self->error = tokenizer_create_error(&self->tokenizer, - tokenizer_get_error_index(&self->tokenizer), - "Expected type or closure signature"); + tokenizer_get_error_index(&self->tokenizer), + "Expected type or closure signature"); throw(PARSER_UNEXPECTED_TOKEN); } throw_if_error(function_signature_add_return_type(func_sig, &var_type)); throw_if_error(tokenizer_consume_if(&self->tokenizer, TOK_COMMA, &match)); if(!match) - return; + break; ++return_type_index; } + + if (buffer_get_size(&func_sig->parameters, FunctionParameter) > FUNC_MAX_PARAMS) { + self->error = tokenizer_create_error(&self->tokenizer, + tokenizer_get_error_index(&self->tokenizer), + "A closure can't have more than %d parameters", FUNC_MAX_PARAMS); + throw(PARSER_ERR); + } + + if (buffer_get_size(&func_sig->return_types, FunctionReturnType) > FUNC_MAX_RETURN_TYPES) { + self->error = tokenizer_create_error(&self->tokenizer, + tokenizer_get_error_index(&self->tokenizer), + "A closure can't have more than %d return values", FUNC_MAX_RETURN_TYPES); + throw(PARSER_ERR); + } } /* @@ -399,7 +416,7 @@ static CHECK_RESULT StructDecl* parser_parse_struct_decl(Parser *self) { throw_if_error(structdecl_init(result, self->current_scope, self->allocator)); self->current_scope = &result->body; - parser_parse_struct_body_loop(self, self->current_scope); + parser_parse_struct_body_loop(self, result); self->current_scope = result->body.parent; return result; } @@ -896,8 +913,7 @@ Ast* parser_parse_body(Parser *self) { /* STRUCT_BODY = TOK_IDENTIFIER VAR_TYPE_DEF ';' */ -Ast* parser_parse_struct_body(Parser *self) { - Ast *result; +StructField* parser_parse_struct_body(Parser *self) { BufferView var_name; VariableType var_type; StructField *struct_field; @@ -912,10 +928,9 @@ Ast* parser_parse_struct_body(Parser *self) { throw(PARSER_UNEXPECTED_TOKEN); } throw_if_error(tokenizer_accept(&self->tokenizer, TOK_SEMICOLON)); - throw_if_error(arena_allocator_alloc(self->allocator, sizeof(LhsExpr), (void**)&struct_field)); + throw_if_error(arena_allocator_alloc(self->allocator, sizeof(StructField), (void**)&struct_field)); structfield_init(struct_field, var_name, &var_type); - throw_if_error(ast_create(self->allocator, struct_field, AST_STRUCT_FIELD, &result)); - return result; + return struct_field; } /* @@ -974,8 +989,9 @@ static CHECK_RESULT int file_path_join(BufferView directory, BufferView file, ch Path can be path to included library path (or system library path) in which case the path separator is a dot, otherwise the path separator is forward slash '/' */ -void parser_queue_file(Parser *self, BufferView path, FileScopeReference **file_scope) { +void parser_queue_file(Parser *self, BufferView path, ParserFileScopeReference **parser_file_scope) { /* TODO: Parse special path (to include library path with dots) */ + FileScopeReference *file_scope; BufferView file_directory; char *path_relative; int result; @@ -983,7 +999,7 @@ void parser_queue_file(Parser *self, BufferView path, FileScopeReference **file_ file_directory = file_get_parent_directory(self->tokenizer.code_name); throw_if_error(file_path_join(file_directory, path, &path_relative)); /* We want buffer to be null-terminated but null character should not be included for the size */ - result = amal_compiler_internal_load_file(self->compiler, path_relative, file_scope); + result = amal_compiler_internal_load_file(self->compiler, path_relative, &file_scope); if(result != 0) { self->error = tokenizer_create_error(&self->tokenizer, tokenizer_get_code_reference_index(&self->tokenizer, path.data), @@ -992,4 +1008,29 @@ void parser_queue_file(Parser *self, BufferView path, FileScopeReference **file_ throw(result); } am_free(path_relative); + + { + usize parser_file_scope_index; + int num_imports; + BufferView import_path_canonical = create_buffer_view(file_scope->canonical_path.data, file_scope->canonical_path.size); + + if(hash_map_get(&self->imports_by_name, import_path_canonical, &parser_file_scope_index)) { + *parser_file_scope = buffer_get(&self->imports, parser_file_scope_index, sizeof(ParserFileScopeReference*)); + return; + } + + num_imports = buffer_get_size(&self->imports, ParserFileScopeReference*); + if(num_imports == 254) { + self->error = tokenizer_create_error(&self->tokenizer, + tokenizer_get_error_index(&self->tokenizer), + "One file can't have more than 255 imports"); + throw(PARSER_ERR); + } + + throw_if_error(arena_allocator_alloc(self->allocator, sizeof(ParserFileScopeReference*), (void**)parser_file_scope)); + (*parser_file_scope)->file_scope_ref = file_scope; + (*parser_file_scope)->import_index = num_imports; + throw_if_error(buffer_append(&self->imports, parser_file_scope, sizeof(ParserFileScopeReference*))); + throw_if_error(hash_map_insert(&self->imports_by_name, import_path_canonical, &parser_file_scope_index)); + } } diff --git a/src/program.c b/src/program.c index eef49b6..a0a2407 100644 --- a/src/program.c +++ b/src/program.c @@ -1,4 +1,5 @@ #include "../include/program.h" + #include "../include/std/mem.h" #include "../include/std/hash.h" #include "../include/std/alloc.h" @@ -29,6 +30,15 @@ typedef struct { NumberUnion value; } Number; +static int hash_map_compare_u64(const void *a, const void *b) { + return *(u64*)a == *(u64*)b; +} + +static usize hash_u64(const u8 *data, usize size) { + (void)size; + return *(u64*)data; +} + int amal_program_init(amal_program *self) { ignore_result_int(buffer_init(&self->data, NULL)); self->string_indices = NULL; @@ -38,16 +48,20 @@ int amal_program_init(amal_program *self) { self->extern_funcs_start = NULL; self->exported_funcs = NULL; self->exported_funcs_end = NULL; + self->imports_start = NULL; self->read_index = 0; - self->main_func_instruction_offset = ~0U; + self->main_func_instruction_offset = ~(u32)0U; self->num_intermediates = 0; self->num_strings = 0; self->num_functions = 0; self->num_extern_functions = 0; self->num_exported_functions = 0; + self->num_imports = 0; + self->return_value_index = 0; cleanup_if_error(arena_allocator_init(&self->allocator)); cleanup_if_error(hash_map_init(&self->extern_funcs_map, &self->allocator, sizeof(ProgramExternFunc), hash_map_compare_string, amal_hash_string)); + cleanup_if_error(hash_map_init(&self->deferred_func_calls, &self->allocator, sizeof(Buffer), hash_map_compare_u64, hash_u64)); cleanup_if_error(buffer_append_header(&self->data)); return 0; @@ -60,6 +74,8 @@ void amal_program_deinit(amal_program *self) { arena_allocator_deinit(&self->allocator); am_free(self->extern_func_indices); am_free(self->string_indices); + self->extern_func_indices = NULL; + self->string_indices = NULL; if(self->data.data) buffer_deinit(&self->data); } @@ -75,34 +91,46 @@ int amal_program_add_extern_func(amal_program *self, BufferView name, void *func return hash_map_insert(&self->extern_funcs_map, name, &extern_func); } -static CHECK_RESULT int amal_program_get_extern_func_by_index(amal_program *self, u16 index, ProgramExternFunc *result) { - u8 *extern_func_ptr; - u8 num_args; - u8 func_name_len; - BufferView func_name; - - if(index >= self->num_extern_functions) { - result->func = NULL; - result->args_byte_size = 0; - amal_log_error("Extern func index index %ld is out of range (%ld)", index, self->num_extern_functions); - return AMAL_PROGRAM_INSTRUCTION_INVALID_EXTERN_FUNC_INDEX; +static u8* amal_program_get_extern_funcs_start_by_import_index(amal_program *self, u8 import_index) { + BytecodeHeaderImport *header_import = (BytecodeHeaderImport*)self->imports_start; + header_import += import_index; + return (u8*)self->data.data + header_import->extern_function_index; +} + +typedef struct { + u8 num_params; + BufferView name; +} BytecodeHeaderExternFunction; + +/* TODO: Optimize this */ +static void amal_program_get_header_extern_function_by_index(amal_program *self, u8 import_index, u16 index, BytecodeHeaderExternFunction *result) { + u32 i; + u8 *extern_funcs_start = amal_program_get_extern_funcs_start_by_import_index(self, import_index); + extern_funcs_start += sizeof(u16) + sizeof(u32); + for(i = 0; i < (u32)index; ++i) { + u8 name_len = *(extern_funcs_start + sizeof(u8)); + /* +1 for the null-terminated character */ + extern_funcs_start += sizeof(u8) + sizeof(u8) + name_len + 1; } + result->num_params = extern_funcs_start[0]; + result->name.size = extern_funcs_start[1]; + result->name.data = (const char*)extern_funcs_start + sizeof(u8) + sizeof(u8); +} - extern_func_ptr = self->extern_funcs_start + self->extern_func_indices[index]; - am_memcpy(&num_args, extern_func_ptr, sizeof(num_args)); - am_memcpy(&func_name_len, extern_func_ptr + sizeof(num_args), sizeof(func_name_len)); - func_name.size = func_name_len; - func_name.data = (const char*)(extern_func_ptr + sizeof(num_args) + sizeof(func_name_len)); +static CHECK_RESULT int amal_program_get_extern_func_by_index(amal_program *self, u8 import_index, u16 index, ProgramExternFunc *result) { + BytecodeHeaderExternFunction extern_func; + amal_program_get_header_extern_function_by_index(self, import_index, index, &extern_func); - if(!hash_map_get(&self->extern_funcs_map, func_name, result)) { - amal_log_error("No such extern function: %.*s", func_name.size, func_name.data); + if(!hash_map_get(&self->extern_funcs_map, extern_func.name, result)) { + amal_log_error("No such extern function: %.*s", extern_func.name.size, extern_func.name.data); return AMAL_PROGRAM_NO_SUCH_EXTERNAL_FUNCTION; } /* TODO: This assumes all arguments are of size sizeof(isize) */ - if(result->args_byte_size != -1 && result->args_byte_size != num_args * (int)sizeof(isize)) { - amal_log_error("Extern function %.*s was registered to take %d byte(s), but the program says it takes %d byte(s)", func_name.size, func_name.data, result->args_byte_size, num_args * sizeof(isize)); + if(result->args_byte_size != -1 && result->args_byte_size != extern_func.num_params * (int)sizeof(isize)) { + amal_log_error("Extern function %.*s was registered to take %d byte(s), but the program says it takes %d byte(s)", + extern_func.name.size, extern_func.name.data, result->args_byte_size, extern_func.num_params * sizeof(isize)); return AMAL_PROGRAM_NO_SUCH_EXTERNAL_FUNCTION; } return 0; @@ -125,7 +153,7 @@ static CHECK_RESULT int amal_program_set_exported_function_instruction_offset_ad num_args = self->exported_funcs[sizeof(instruction_offset)]; func_name_size = self->exported_funcs[sizeof(instruction_offset) + sizeof(num_args)]; self->exported_funcs += sizeof(instruction_offset) + sizeof(num_args) + sizeof(func_name_size); - if(self->main_func_instruction_offset == ~0U && func_name_size == 4 && am_memeql(self->exported_funcs, "main", 4)) + if(self->main_func_instruction_offset == ~(u32)0U && func_name_size == 4 && am_memeql(self->exported_funcs, "main", 4)) self->main_func_instruction_offset = instruction_offset; /* +1 to skip null-termination character */ @@ -191,10 +219,25 @@ static CHECK_RESULT bool amal_program_read_advance(amal_program *self, void *out return bool_true; } +static CHECK_RESULT int amal_program_advance_section_magic_number(amal_program *self) { + u32 magic_number; + if(bytes_left_to_read(self) < sizeof(u32)) + return AMAL_PROGRAM_SECTION_ERROR; + + am_memcpy(&magic_number, self->data.data + self->read_index, sizeof(magic_number)); + if(magic_number != AMAL_BYTECODE_SECTION_MAGIC_NUMBER) + return AMAL_PROGRAM_SECTION_ERROR; + + self->read_index += sizeof(magic_number); + return 0; +} + static CHECK_RESULT int amal_program_read_intermediates(amal_program *self) { u32 intermediates_size; /*u32 read_end;*/ + return_if_error(amal_program_advance_section_magic_number(self)); + if(bytes_left_to_read(self) < sizeof(intermediates_size)) { amal_log_error("Not enough space in program to intermediates size"); return AMAL_PROGRAM_INVALID_INTERMEDIATES; @@ -219,6 +262,8 @@ static CHECK_RESULT int amal_program_read_strings(amal_program *self) { u32 strings_size; u32 *string_index_ptr; + return_if_error(amal_program_advance_section_magic_number(self)); + if(!amal_program_read_advance(self, &self->num_strings, sizeof(u16))) return AMAL_PROGRAM_INVALID_STRINGS; @@ -262,8 +307,18 @@ static CHECK_RESULT int amal_program_read_strings(amal_program *self) { } static CHECK_RESULT int amal_program_read_functions(amal_program *self) { + u32 funcs_size; + + return_if_error(amal_program_advance_section_magic_number(self)); + if(!amal_program_read_advance(self, &self->num_functions, sizeof(u16))) return AMAL_PROGRAM_INVALID_FUNCTIONS; + + if(!amal_program_read_advance(self, &funcs_size, sizeof(funcs_size)) || bytes_left_to_read(self) < funcs_size) + return AMAL_PROGRAM_INVALID_FUNCTIONS; + + self->funcs_start = (u8*)(self->data.data + self->read_index); + self->read_index += funcs_size; return AMAL_PROGRAM_OK; } @@ -271,6 +326,8 @@ static CHECK_RESULT int amal_program_read_external_functions(amal_program *self) u32 extern_funcs_size; u32 *extern_func_index_ptr; + return_if_error(amal_program_advance_section_magic_number(self)); + if(!amal_program_read_advance(self, &self->num_extern_functions, sizeof(u16))) return AMAL_PROGRAM_INVALID_EXTERNAL_FUNCTIONS; @@ -291,17 +348,17 @@ static CHECK_RESULT int amal_program_read_external_functions(amal_program *self) const u32 read_end = read_start + extern_funcs_size; self->extern_funcs_start = (u8*)(self->data.data + self->read_index); while(self->read_index < read_end) { - u8 num_args; + u8 num_params; u8 func_name_size; - if(bytes_left_to_read(self) < sizeof(num_args) + sizeof(func_name_size)) + if(bytes_left_to_read(self) < sizeof(num_params) + sizeof(func_name_size)) return AMAL_PROGRAM_INVALID_EXTERNAL_FUNCTIONS; *extern_func_index_ptr = self->read_index - read_start; ++extern_func_index_ptr; - num_args = self->data.data[self->read_index]; - func_name_size = self->data.data[self->read_index + sizeof(num_args)]; - self->read_index += sizeof(num_args) + sizeof(func_name_size); + num_params = self->data.data[self->read_index]; + func_name_size = self->data.data[self->read_index + sizeof(num_params)]; + self->read_index += sizeof(num_params) + sizeof(func_name_size); /* +1 to skip null-termination character */ if(bytes_left_to_read(self) < func_name_size + 1U) @@ -318,6 +375,8 @@ static CHECK_RESULT int amal_program_read_external_functions(amal_program *self) static CHECK_RESULT int amal_program_read_exported_functions(amal_program *self) { u32 export_funcs_size; + return_if_error(amal_program_advance_section_magic_number(self)); + if(!amal_program_read_advance(self, &self->num_exported_functions, sizeof(u16))) return AMAL_PROGRAM_INVALID_EXPORTED_FUNCTIONS; @@ -337,6 +396,22 @@ static CHECK_RESULT int amal_program_read_exported_functions(amal_program *self) return AMAL_PROGRAM_OK; } +static CHECK_RESULT int amal_program_read_imports(amal_program *self) { + u32 imports_size; + + return_if_error(amal_program_advance_section_magic_number(self)); + + if(!amal_program_read_advance(self, &self->num_imports, sizeof(u8))) + return AMAL_PROGRAM_INVALID_IMPORTS; + + if(!amal_program_read_advance(self, &imports_size, sizeof(imports_size)) || bytes_left_to_read(self) < imports_size) + return AMAL_PROGRAM_INVALID_IMPORTS; + + self->imports_start = (u8*)(self->data.data + self->read_index); + self->read_index += imports_size; + return AMAL_PROGRAM_OK; +} + static CHECK_RESULT int amal_program_get_intermediate_by_index(amal_program *self, u16 index, Number *result) { if(index >= self->num_intermediates) return AMAL_PROGRAM_INSTRUCTION_INVALID_INTERMEDIATE_INDEX; @@ -360,6 +435,48 @@ static CHECK_RESULT int amal_program_get_data_by_index(amal_program *self, u16 i return 0; } +static u8* amal_program_get_funcs_start_by_import_index(amal_program *self, u8 import_index) { + BytecodeHeaderImport *header_import = (BytecodeHeaderImport*)self->imports_start; + header_import += import_index; + return (u8*)self->data.data + header_import->function_index; +} + +static BytecodeHeaderFunction* amal_program_get_header_function_by_index(amal_program *self, u8 import_index, u16 index) { + u8 *funcs_start = amal_program_get_funcs_start_by_import_index(self, import_index); + BytecodeHeaderFunction *header_func = (BytecodeHeaderFunction*)(funcs_start + sizeof(u16) + sizeof(u32)); + return header_func + index; +} + +static u64 deferred_func_call_get_key(amal_program *self, u8 import_index, u16 func_index) { + BytecodeHeaderImport *header_import = (BytecodeHeaderImport*)self->imports_start; + header_import += import_index; + return ((u64)func_index << 32) | (u64)header_import->function_index; +} + +static CHECK_RESULT int resolve_deferred_func_calls(amal_program *self, amal_executor *executor, u16 func_index) { + u64 key = deferred_func_call_get_key(self, 0, func_index); + BufferView key_mem = create_buffer_view((char*)&key, sizeof(key)); + u32 current_code_offset = amal_exec_get_code_offset(executor); + + Buffer* deferred_func_call_list; + if(!hash_map_get_ref(&self->deferred_func_calls, key_mem, (void**)&deferred_func_call_list)) + return 0; + + { + u32 *code_offset = buffer_begin(deferred_func_call_list); + u32 *code_offset_end = buffer_end(deferred_func_call_list); + for(; code_offset != code_offset_end; ++code_offset) { + amal_exec_call_overwrite(executor, *code_offset, current_code_offset - *code_offset); + } + return buffer_set_capacity(deferred_func_call_list, 0); + } +} + +static void header_func_set_offset(amal_program *self, u16 func_index, u32 code_offset) { + BytecodeHeaderFunction *header_func = ((BytecodeHeaderFunction*)self->funcs_start) + func_index; + header_func->func_offset = code_offset; +} + static CHECK_RESULT int amal_program_read_instructions(amal_program *self, amal_executor *executor) { u32 instructions_size; u32 read_start; @@ -370,6 +487,9 @@ static CHECK_RESULT int amal_program_read_instructions(amal_program *self, amal_ inside_func = bool_false; (void)inside_func; func_counter = 0; + self->return_value_index = 0; + + return_if_error(amal_program_advance_section_magic_number(self)); if(!amal_program_read_advance(self, &instructions_size, sizeof(instructions_size))) return AMAL_PROGRAM_INVALID_INSTRUCTIONS_SIZE; @@ -484,14 +604,51 @@ static CHECK_RESULT int amal_program_read_instructions(amal_program *self, amal_ self->read_index += 2; break; } + case AMAL_OP_PUSH_RET: { + /* TODO: Validate return value index doesn't go out of bounds? */ + self->return_values_stack[self->return_value_index++] = self->data.data[self->read_index]; + self->read_index += 1; + break; + } case AMAL_OP_CALL: { + u8 import_index; u16 func_index; u8 num_args; + BytecodeHeaderFunction *func_def; i8 dst_reg; - am_memcpy(&func_index, self->data.data + self->read_index, sizeof(func_index)); - num_args = self->data.data[self->read_index + sizeof(func_index)]; - dst_reg = self->data.data[self->read_index + sizeof(func_index) + sizeof(num_args)]; - return_if_error(amal_exec_call(executor, func_index, num_args, dst_reg)); + + am_memcpy(&import_index, self->data.data + self->read_index, sizeof(import_index)); + am_memcpy(&func_index, self->data.data + self->read_index + sizeof(import_index), sizeof(func_index)); + am_memcpy(&num_args, self->data.data + self->read_index + sizeof(import_index) + sizeof(func_index), sizeof(num_args)); + func_def = amal_program_get_header_function_by_index(self, import_index, func_index); + assert(func_def->num_return_types == 1 && "TODO: Support 0 and more than 1 return values"); + assert(self->return_value_index == 1); + dst_reg = self->return_values_stack[0]; + self->return_value_index -= func_def->num_return_types; + + if((char*)func_def < self->data.data + self->read_index) { + return_if_error(amal_exec_call(executor, func_def->func_offset, num_args, dst_reg)); + } else { + /* + The code for the function has not been generated yet (the function is defined after the current location). + Make a dummy call and replace the call target after the function has been generated + */ + u64 key = deferred_func_call_get_key(self, import_index, func_index); + BufferView key_mem = create_buffer_view((char*)&key, sizeof(key)); + u32 code_offset = amal_exec_get_code_offset(executor); + + Buffer* deferred_func_call_list; + if(hash_map_get_ref(&self->deferred_func_calls, key_mem, (void**)&deferred_func_call_list)) + return_if_error(buffer_append(deferred_func_call_list, &code_offset, sizeof(code_offset))); + else { + Buffer new_deferred_call_list; + return_if_error(buffer_init(&new_deferred_call_list, &self->allocator)); + return_if_error(buffer_append(&new_deferred_call_list, &code_offset, sizeof(code_offset))); + return_if_error(hash_map_insert(&self->deferred_func_calls, key_mem, &new_deferred_call_list)); + } + /* Dummy call to offset 0, offset will be replace later when the target function hits AMAL_OP_FUNC_START */ + return_if_error(amal_exec_call(executor, 0, num_args, dst_reg)); + } self->read_index += 4; break; } @@ -500,16 +657,21 @@ static CHECK_RESULT int amal_program_read_instructions(amal_program *self, amal_ self->read_index += 2; break; case AMAL_OP_CALLE: { + u8 import_index; u16 extern_func_index; u8 num_args; i8 dst_reg; - am_memcpy(&extern_func_index, self->data.data + self->read_index, sizeof(extern_func_index)); - num_args = self->data.data[self->read_index + sizeof(extern_func_index)]; - dst_reg = self->data.data[self->read_index + sizeof(extern_func_index) + sizeof(num_args)]; + + am_memcpy(&import_index, self->data.data + self->read_index, sizeof(import_index)); + am_memcpy(&extern_func_index, self->data.data + self->read_index + sizeof(import_index), sizeof(extern_func_index)); + am_memcpy(&num_args, self->data.data + self->read_index + sizeof(import_index) + sizeof(extern_func_index), sizeof(num_args)); + assert(self->return_value_index == 1 && "TODO: Support extern functions that don't return any value"); + dst_reg = self->return_values_stack[0]; + self->return_value_index = 0; { ProgramExternFunc extern_func; - return_if_error(amal_program_get_extern_func_by_index(self, extern_func_index, &extern_func)); + return_if_error(amal_program_get_extern_func_by_index(self, import_index, extern_func_index, &extern_func)); return_if_error(amal_exec_calle(executor, extern_func.func, num_args, dst_reg)); } self->read_index += 4; @@ -549,6 +711,9 @@ static CHECK_RESULT int amal_program_read_instructions(amal_program *self, amal_ assert(!inside_func); inside_func = bool_true; assert(func_counter < self->num_functions); + + header_func_set_offset(self, func_counter, amal_exec_get_code_offset(executor)); + return_if_error(resolve_deferred_func_calls(self, executor, func_counter)); ++func_counter; func_flags = self->data.data[self->read_index]; @@ -595,9 +760,10 @@ int amal_program_run(amal_program *self) { cleanup_if_error(amal_program_read_functions(self)); cleanup_if_error(amal_program_read_external_functions(self)); cleanup_if_error(amal_program_read_exported_functions(self)); + cleanup_if_error(amal_program_read_imports(self)); cleanup_if_error(amal_program_read_instructions(self, executor)); } - if(self->main_func_instruction_offset == ~0U) { + if(self->main_func_instruction_offset == ~(u32)0U) { amal_log_error("The program is missing a main function"); result = AMAL_PROGRAM_NO_MAIN_FUNC; goto cleanup; diff --git a/src/ssa/ssa.c b/src/ssa/ssa.c index 5c625b2..19aa036 100644 --- a/src/ssa/ssa.c +++ b/src/ssa/ssa.c @@ -26,6 +26,8 @@ do { \ /* Max length of a string that fits in u16 */ #define MAX_STRING_LENGTH UINT16_MAX +static CHECK_RESULT SsaRegister variable_generate_ssa(Variable *self, SsaCompilerContext *context); + static int compare_number(const void *a, const void *b) { const SsaNumber *lhs = a; const SsaNumber *rhs = b; @@ -62,13 +64,14 @@ int ssa_init(Ssa *self, Parser *parser) { return_if_error(hash_map_init(&self->extern_funcs_map, parser->allocator, sizeof(SsaExternFuncIndex), hash_map_compare_string, amal_hash_string)); return_if_error(buffer_init(&self->extern_funcs, parser->allocator)); return_if_error(buffer_init(&self->export_funcs, parser->allocator)); + return_if_error(buffer_init(&self->funcs, parser->allocator)); self->intermediate_counter = 0; self->string_counter = 0; self->extern_func_counter = 0; self->export_func_counter = 0; + self->func_counter = 0; self->reg_counter = 0; self->param_counter = 0; - self->func_counter = 0; self->label_counter = 0; self->parser = parser; return 0; @@ -186,7 +189,7 @@ static CHECK_RESULT int ssa_try_add_extern_func(Ssa *self, FunctionSignature *fu *result_index = self->extern_func_counter; ++self->extern_func_counter; - amal_log_debug("ef%u = \"%.*s\"", *result_index, name.size, name.data); + amal_log_debug("extern_func%u = %.*s", *result_index, name.size, name.data); { SsaExternFunc extern_func; extern_func.func_sig = func_sig; @@ -209,7 +212,7 @@ static CHECK_RESULT int ssa_try_add_export_func(Ssa *self, FunctionSignature *fu return -1; } - amal_log_debug("ef%u = \"%.*s\"", self->export_func_counter, name.size, name.data); + amal_log_debug("exported_func%u = %.*s", self->export_func_counter, name.size, name.data); ++self->export_func_counter; { SsaExportFunc export_func; @@ -274,7 +277,7 @@ static CHECK_RESULT int ssa_ins_binop(Ssa *self, SsaInstruction binop_type, SsaR return ssa_add_ins_form2(self, binop_type, lhs, rhs, result); } -static CHECK_RESULT int ssa_ins_func_start(Ssa *self, u8 func_flags, SsaFuncIndex *result, usize *func_metadata_index) { +static CHECK_RESULT int ssa_ins_func_start(Ssa *self, u8 func_flags, FunctionSignature *func_sig, SsaFuncIndex *result, usize *func_metadata_index) { const u8 ins_type = SSA_FUNC_START; SsaInsFuncStart ins_func_start; @@ -285,13 +288,18 @@ static CHECK_RESULT int ssa_ins_func_start(Ssa *self, u8 func_flags, SsaFuncInde } *result = self->func_counter++; + { + SsaFunc func; + func.func_sig = func_sig; + return_if_error(buffer_append(&self->funcs, &func, sizeof(func))); + } ins_func_start.flags = func_flags; /* Dont set number of local registers yet. That will be set by @func_metadata_index later when it's known */ /*ins_func_start.num_local_vars_regs = ---*/ return_if_error(buffer_append(&self->instructions, &ins_type, 1)); return_if_error(buffer_append(&self->instructions, &ins_func_start, sizeof(ins_func_start))); *func_metadata_index = self->instructions.size - sizeof(ins_func_start.num_local_vars_regs); - amal_log_debug("FUNC_START f%u", *result); + amal_log_debug("FUNC_START f%u(%d) %d", *result, buffer_get_size(&func_sig->parameters, FunctionParameter), buffer_get_size(&func_sig->return_types, FunctionReturnType)); return 0; } @@ -308,27 +316,31 @@ static CHECK_RESULT int ssa_ins_push(Ssa *self, SsaRegister reg) { return buffer_append(&self->instructions, ®, sizeof(reg)); } -static CHECK_RESULT int ssa_ins_call(Ssa *self, FunctionDecl *func_decl, u8 num_args, SsaRegister *result) { +static CHECK_RESULT int ssa_ins_push_ret(Ssa *self, SsaRegister reg) { + const u8 ins_type = SSA_PUSH_RET; + amal_log_debug("PUSH RET r%d", reg); + return_if_error(buffer_append(&self->instructions, &ins_type, 1)); + return buffer_append(&self->instructions, ®, sizeof(reg)); +} + +static CHECK_RESULT int ssa_ins_call(Ssa *self, int import_index, FunctionDecl *func_decl, u8 num_args) { const u8 ins_type = SSA_CALL; SsaInsFuncCall ins_func_call; - return_if_error(ssa_get_unique_reg(self, result)); ins_func_call.num_args = num_args; - ins_func_call.result = *result; ins_func_call.func_decl = func_decl; - amal_log_debug("r%d = CALL %d, %p", *result, num_args, func_decl); + ins_func_call.import_index = import_index; + amal_log_debug("CALL %d, f(%d,%p)", num_args, import_index, func_decl); return_if_error(buffer_append(&self->instructions, &ins_type, 1)); return buffer_append(&self->instructions, &ins_func_call, sizeof(ins_func_call)); } -static CHECK_RESULT int ssa_ins_call_extern(Ssa *self, SsaExternFuncIndex extern_func_index, u8 num_args, SsaRegister *result) { +static CHECK_RESULT int ssa_ins_call_extern(Ssa *self, int import_index, LhsExpr *func_decl_lhs, u8 num_args) { const u8 ins_type = SSA_CALL_EXTERN; SsaInsFuncCallExtern ins_func_call_extern; - return_if_error(ssa_get_unique_reg(self, result)); - assert(extern_func_index < self->extern_func_counter); ins_func_call_extern.num_args = num_args; - ins_func_call_extern.result = *result; - ins_func_call_extern.extern_func_index = extern_func_index; - amal_log_debug("r%d = CALL_EXTERN %d, %d", *result, num_args, extern_func_index); + ins_func_call_extern.func_decl_lhs = func_decl_lhs; + ins_func_call_extern.import_index = import_index; + amal_log_debug("CALL_EXTERN %d, ef(%d,%p)", num_args, import_index, func_decl_lhs); return_if_error(buffer_append(&self->instructions, &ins_type, 1)); return buffer_append(&self->instructions, &ins_func_call_extern, sizeof(ins_func_call_extern)); } @@ -608,10 +620,11 @@ static CHECK_RESULT SsaRegister funcdecl_generate_ssa(FunctionDecl *self, SsaCom amal_log_debug("SSA funcdecl %p", self); /* Anonymous closure doesn't have lhs_expr, and neither can it have any flags (extern, export etc) */ if(self->lhs_expr) { + assert(!LHS_EXPR_IS_EXTERN(self->lhs_expr)); if(LHS_EXPR_IS_EXPORT(self->lhs_expr)) func_flags |= FUNC_FLAG_EXPORTED; } - throw_if_error(ssa_ins_func_start(context->ssa, func_flags, &self->ssa_func_index, &func_metadata_index)); + throw_if_error(ssa_ins_func_start(context->ssa, func_flags, self->signature, &self->ssa_func_index, &func_metadata_index)); scope_generate_ssa(&self->body, context); throw_if_error(ssa_ins_func_end(context->ssa)); @@ -624,28 +637,41 @@ static CHECK_RESULT SsaRegister funccall_generate_ssa(FunctionCall *self, AstRes SsaRegister reg; FunctionDecl *func_decl; LhsExpr *func_lhs_expr; + int import_index = context->import_index; + context->import_index = 0; + throw_if_error(ssa_get_unique_reg(context->ssa, ®)); + + func_decl = resolve_data->type.value.func_sig->func_decl; + assert(resolve_data->type.type == RESOLVED_TYPE_FUNC_SIG); + func_lhs_expr = NULL; + if(self->func.resolved_var.type == NAMED_OBJECT_LHS_EXPR) + func_lhs_expr = self->func.resolved_var.value.lhs_expr; + + /* Push return arguments */ + { + /* + TODO: When amalgam supports multiple return types in assignment/declaration, update this to take + all of them into account. Right now it only uses one return type. + It should also take into account the size of the type. + */ + throw_if_error(ssa_ins_push_ret(context->ssa, reg)); + } + /* Push parameter arguments */ { Ast **arg = buffer_begin(&self->args); Ast **arg_end = buffer_end(&self->args); for(; arg != arg_end; ++arg) { - SsaRegister arg_reg; - arg_reg = ast_generate_ssa(*arg, context); + SsaRegister arg_reg = ast_generate_ssa(*arg, context); throw_if_error(ssa_ins_push(context->ssa, arg_reg)); } } - func_decl = resolve_data->type.value.func_sig->func_decl; - assert(resolve_data->type.type == RESOLVED_TYPE_FUNC_SIG); - func_lhs_expr = NULL; - if(self->func.resolved_var.type == NAMED_OBJECT_LHS_EXPR) - func_lhs_expr = self->func.resolved_var.value.lhs_expr; - if(func_lhs_expr && LHS_EXPR_IS_EXTERN(func_lhs_expr)) { - throw_if_error(ssa_ins_call_extern(context->ssa, func_lhs_expr->extern_index, buffer_get_size(&self->args, Ast*), ®)); + throw_if_error(ssa_ins_call_extern(context->ssa, import_index, func_lhs_expr, buffer_get_size(&self->args, Ast*))); } else { /* rhs wont be null here because only extern variable can't have rhs */ - throw_if_error(ssa_ins_call(context->ssa, func_decl, buffer_get_size(&self->args, Ast*), ®)); + throw_if_error(ssa_ins_call(context->ssa, import_index, func_decl, buffer_get_size(&self->args, Ast*))); } return reg; @@ -673,7 +699,7 @@ static CHECK_RESULT SsaRegister string_generate_ssa(String *self, SsaCompilerCon return reg; } -static CHECK_RESULT SsaRegister variable_generate_ssa(Variable *self, SsaCompilerContext *context) { +SsaRegister variable_generate_ssa(Variable *self, SsaCompilerContext *context) { /* TODO: If resolved_var refers to a variable in another file, use a cross file reference that requires no locking (not yet implemented) */ /* This is not thread-safe:*/ assert(self->resolved_var.type != NAMED_OBJECT_NONE); @@ -699,6 +725,16 @@ static SsaInstruction binop_type_to_ssa_type(BinopType binop_type, amal_default_ return 0; } +/* Returns the import statement for lhs of binop dot expression, where lhs is a variable name */ +static Import* binop_lhs_get_import_or_null(Binop *self) { + if(self->lhs->type == AST_VARIABLE) { + ScopeNamedObject *resolved_var = &self->lhs->value.variable->resolved_var; + if(resolved_var->type == NAMED_OBJECT_LHS_EXPR && resolved_var->value.lhs_expr->rhs_expr && resolved_var->value.lhs_expr->rhs_expr->type == AST_IMPORT) + return resolved_var->value.lhs_expr->rhs_expr->value.import; + } + return NULL; +} + static CHECK_RESULT SsaRegister binop_generate_ssa(Binop *self, SsaCompilerContext *context) { SsaRegister reg; @@ -707,8 +743,12 @@ static CHECK_RESULT SsaRegister binop_generate_ssa(Binop *self, SsaCompilerConte const std = @import("std.amal"); std.printf */ - if(self->type == BINOP_DOT && resolved_type_is_func_decl(self->rhs)) { + if(self->type == BINOP_DOT && self->rhs->resolve_data.type.type == RESOLVED_TYPE_FUNC_SIG) { + Import *lhs_import = binop_lhs_get_import_or_null(self); + if(lhs_import) + context->import_index = 1 + lhs_import->file_scope->import_index; reg = ast_generate_ssa(self->rhs, context); + context->import_index = 0; } else { const SsaRegister lhs_reg = ast_generate_ssa(self->lhs, context); const SsaRegister rhs_reg = ast_generate_ssa(self->rhs, context); @@ -774,9 +814,10 @@ static void while_statement_generate_ssa(WhileStatement *while_stmt, SsaCompiler SsaLabelIndex before_condition_label; SsaLabelIndex skip_body_label; usize jump_after_condition_index; + SsaRegister condition_reg; throw_if_error(ssa_ins_label(context->ssa, &before_condition_label)); - SsaRegister condition_reg = ast_generate_ssa(while_stmt->condition, context); + condition_reg = ast_generate_ssa(while_stmt->condition, context); throw_if_error(ssa_ins_jumpzero(context->ssa, condition_reg, 0, &jump_after_condition_index)); scope_generate_ssa(&while_stmt->body, context); diff --git a/src/std/buffer.c b/src/std/buffer.c index a482bb9..021fce8 100644 --- a/src/std/buffer.c +++ b/src/std/buffer.c @@ -94,6 +94,19 @@ void buffer_clear(Buffer *self) { self->size = 0; } +int buffer_set_capacity(Buffer *self, usize new_capacity) { + if(am_realloc(self->data, new_capacity, (void**)&self->data) != ALLOC_OK) + return BUFFER_ALLOC_FAIL; + + self->capacity = new_capacity; + if(self->size < self->capacity) + self->size = self->capacity; + /* Update list of buffers in the allocator with the new address of the buffer data */ + if(self->allocator) + am_memcpy(self->allocator->mems.data + sizeof(void*) * self->allocator_index, &self->data, sizeof(void*)); + return BUFFER_OK; +} + void* buffer_begin(Buffer *self) { return self->data; } diff --git a/src/std/buffer_view.c b/src/std/buffer_view.c index f2d79c0..249928b 100644 --- a/src/std/buffer_view.c +++ b/src/std/buffer_view.c @@ -1,7 +1,7 @@ #include "../../include/std/buffer_view.h" #include "../../include/std/mem.h" -BufferView create_buffer_view_null() { +BufferView create_buffer_view_null(void) { BufferView buffer_view; buffer_view.data = NULL; buffer_view.size = 0; diff --git a/src/std/hash_map.c b/src/std/hash_map.c index 98ebf40..234f3e3 100644 --- a/src/std/hash_map.c +++ b/src/std/hash_map.c @@ -178,6 +178,7 @@ int hash_map_insert(HashMap *self, BufferView key, void *value) { } bool hash_map_get(HashMap *self, BufferView key, void *value) { +#if 0 usize bucket_size; usize bucket_index; usize hash; @@ -200,6 +201,37 @@ bool hash_map_get(HashMap *self, BufferView key, void *value) { } return bool_false; +#endif + void *ref; + if(!hash_map_get_ref(self, key, &ref)) + return bool_false; + am_memcpy(value, ref, self->value_type_size); + return bool_true; +} + +bool hash_map_get_ref(HashMap *self, BufferView key, void **value) { + usize bucket_size; + usize bucket_index; + usize hash; + HashMapBucket *bucket; + HashMapBucketNode *bucket_node; + + bucket_size = buffer_get_size(&self->buckets, HashMapBucket); + hash = self->hash_func((const u8*)key.data, key.size); + bucket_index = hash % bucket_size; + + bucket = ((HashMapBucket*)self->buckets.data) + bucket_index; + for(bucket_node = bucket->start; bucket_node; bucket_node = bucket_node_get_next(bucket_node)) { + BufferView bucket_key; + bucket_key = bucket_node_get_key(bucket_node); + if(hash == bucket_node_get_hash(bucket_node) && self->compare_func(&key, &bucket_key) == 0) { + if(value) + *value = bucket_node_get_value(bucket_node); + return bool_true; + } + } + + return bool_false; } bool hash_map_contains(HashMap *self, BufferView key) { diff --git a/src/std/log.c b/src/std/log.c index 59e0319..68f1f2e 100644 --- a/src/std/log.c +++ b/src/std/log.c @@ -10,14 +10,14 @@ static amal_mutex mutex; static bool mutex_initialized = bool_false; /* Safe to call multiple times */ -static void mutex_init() { +static void mutex_init(void) { if(!mutex_initialized) { ignore_result_int(amal_mutex_init(&mutex)); mutex_initialized = bool_true; } } -amal_mutex* amal_log_get_mutex() { +amal_mutex* amal_log_get_mutex(void) { mutex_init(); return &mutex; } diff --git a/src/std/mem.c b/src/std/mem.c index 95edcb9..8658781 100644 --- a/src/std/mem.c +++ b/src/std/mem.c @@ -18,7 +18,6 @@ void am_memset(void *dest, int value, usize size) { memset(dest, value, size); } -long am_pagesize() { +long am_pagesize(void) { return sysconf(_SC_PAGESIZE); } - diff --git a/src/std/thread.c b/src/std/thread.c index 87362d2..9b9b764 100644 --- a/src/std/thread.c +++ b/src/std/thread.c @@ -120,11 +120,11 @@ void amal_mutex_deinit(amal_mutex *self) { pthread_mutex_destroy(&self->mutex); } -static long amal_process_get_id() { +static long amal_process_get_id(void) { return getpid(); } -static long amal_thread_get_id() { +static long amal_thread_get_id(void) { return syscall(SYS_gettid); } @@ -173,11 +173,11 @@ void amal_mutex_tryunlock(amal_mutex *self) { ignore_result_int(amal_mutex_unlock(self)); } -bool amal_thread_is_main() { +bool amal_thread_is_main(void) { /* TODO: This only works for linux, use equivalent functions on other platforms */ return amal_thread_get_id() == amal_process_get_id(); } -int amal_get_usable_thread_count() { +int amal_get_usable_thread_count(void) { return get_nprocs(); } |