From 2323ca6c9ec3c8ee76b9acf13745b80b92952a6a Mon Sep 17 00:00:00 2001 From: dec05eba Date: Mon, 18 Mar 2019 23:47:45 +0100 Subject: Add struct, import caching, binop ops etc --- src/compiler.c | 138 +++++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 115 insertions(+), 23 deletions(-) (limited to 'src/compiler.c') diff --git a/src/compiler.c b/src/compiler.c index c56221b..f0e5928 100644 --- a/src/compiler.c +++ b/src/compiler.c @@ -3,13 +3,21 @@ #include "../include/ssa/ssa.h" #include "../include/std/log.h" #include "../include/std/mem.h" +#include "../include/std/hash.h" +#include "../include/std/file.h" #include "../include/std/alloc.h" #include #include +#include #include #define MIN(a, b) ((a) < (b) ? (a) : (b)) +typedef struct { + BufferView path; + Scope *file_scope; +} FileQueueItem; + static CHECK_RESULT int get_thread_count_env_var(int *thread_count) { char *threads; threads = getenv("THREADS"); @@ -19,6 +27,49 @@ static CHECK_RESULT int get_thread_count_env_var(int *thread_count) { return 0; } +static usize strnlen(const char *str, usize max_length) { + usize len; + len = 0; + while(len < max_length && *str != '\0') { + ++len; + ++str; + } + return len; +} + +/* TODO: Allow to specify size and members? */ +static CHECK_RESULT int create_default_type(amal_compiler *compiler, const char *name) { + StructDecl *struct_decl; + LhsExpr *lhs_expr; + Ast expr; + + return_if_error(scoped_allocator_alloc(&compiler->allocator, sizeof(StructDecl), (void**)&struct_decl)); + return_if_error(structdecl_init(struct_decl, &compiler->root_scope, &compiler->allocator)); + + return_if_error(scoped_allocator_alloc(&compiler->allocator, sizeof(LhsExpr), (void**)&lhs_expr)); + lhsexpr_init(lhs_expr, bool_true, create_buffer_view(name, strnlen(name, PATH_MAX))); + ast_init(&lhs_expr->rhs_expr, struct_decl, AST_STRUCT_DECL); + ast_init(&expr, lhs_expr, AST_LHS); + return scope_add_child(&compiler->root_scope, &expr); +} + +static CHECK_RESULT int init_default_types(amal_compiler *compiler) { + return_if_error(create_default_type(compiler, "i8")); + return_if_error(create_default_type(compiler, "i16")); + return_if_error(create_default_type(compiler, "i32")); + return_if_error(create_default_type(compiler, "i64")); + return_if_error(create_default_type(compiler, "u8")); + return_if_error(create_default_type(compiler, "u16")); + return_if_error(create_default_type(compiler, "u32")); + return_if_error(create_default_type(compiler, "u64")); + return_if_error(create_default_type(compiler, "isize")); + return_if_error(create_default_type(compiler, "usize")); + return_if_error(create_default_type(compiler, "f32")); + return_if_error(create_default_type(compiler, "f64")); + return_if_error(create_default_type(compiler, "str")); + return 0; +} + int amal_compiler_init(amal_compiler *self) { int i; int result; @@ -37,20 +88,22 @@ int amal_compiler_init(amal_compiler *self) { } am_memset(&self->allocator, 0, sizeof(self->allocator)); - am_memset(&self->main_thread_allocator, 0, sizeof(self->main_thread_allocator)); + am_memset(&self->root_scope, 0, sizeof(self->root_scope)); self->started = bool_false; self->generic_work_object_index = 0; amal_mutex_init(&self->mutex); return_if_error(scoped_allocator_init(&self->allocator)); - cleanup_if_error(scoped_allocator_init(&self->main_thread_allocator)); + cleanup_if_error(scope_init(&self->root_scope, NULL, &self->allocator)); cleanup_if_error(buffer_init(&self->parsers, &self->allocator)); cleanup_if_error(buffer_init(&self->queued_files, &self->allocator)); + cleanup_if_error(hash_map_init(&self->file_scopes, &self->allocator, sizeof(FileScopeReference*), hash_compare_string, amal_hash_string)); cleanup_if_error(scoped_allocator_alloc(&self->allocator, self->usable_thread_count * sizeof(ParserThreadData), (void**)&self->threads)); for(i = 0; i < self->usable_thread_count; ++i) cleanup_if_error(parser_thread_data_init(&self->threads[i])); + cleanup_if_error(init_default_types(self)); return AMAL_COMPILER_OK; cleanup: @@ -72,7 +125,6 @@ int amal_compiler_deinit(amal_compiler *self) { amal_mutex_deinit(&self->mutex); scoped_allocator_deinit(&self->allocator); - scoped_allocator_deinit(&self->main_thread_allocator); return result; } @@ -108,11 +160,13 @@ static CHECK_RESULT int amal_compiler_load_in_this_thread(amal_compiler *self, B int result; result = AMAL_COMPILER_ERR; - return_if_error(scoped_allocator_alloc(&self->allocator, sizeof(Parser), (void**)&parser)); + amal_log_info("Started parsing %.*s", (int)filepath.size, filepath.data); + return_if_error(scoped_allocator_alloc(allocator, sizeof(Parser), (void**)&parser)); return_if_error(parser_init(parser, self, allocator)); return_if_error(parser_parse_file(parser, filepath)); cleanup_if_error(amal_mutex_lock(&self->mutex, "amal_compiler_load_in_this_thread")); cleanup_if_error(buffer_append(&self->parsers, &parser, sizeof(parser))); + amal_log_info("Finished parsing %.*s", (int)filepath.size, filepath.data); result = AMAL_COMPILER_OK; cleanup: @@ -156,13 +210,10 @@ static CHECK_RESULT int thread_resolve_ast(Parser *parser) { compiler_context.parser = parser; compiler_context.scope = NULL; result = setjmp(compiler_context.env); - assert(!parser->scope.parent); if(result == 0) { amal_log_debug("Resolving AST for file: %.*s", parser->tokenizer.code_name.size, parser->tokenizer.code_name.data); scope_resolve(&parser->scope, &compiler_context); } - if(result == 0) - assert(!compiler_context.scope); return result; } @@ -226,7 +277,7 @@ static CHECK_RESULT int amal_compiler_select_thread_for_work(amal_compiler *self void *thread_user_data; thread_user_data = NULL; *thread_selected = NULL; - result = AMAL_COMPILER_ERR; + result = AMAL_COMPILER_OK; cleanup_if_error(amal_mutex_lock(&self->mutex, "amal_compiler_select_thread_for_work")); for(i = 0; i < self->usable_thread_count; ++i) { @@ -270,23 +321,21 @@ static CHECK_RESULT int amal_compiler_select_thread_for_work(amal_compiler *self return result; } -static CHECK_RESULT int amal_compiler_check_all_threads_done(amal_compiler *self, bool *done) { +static CHECK_RESULT bool amal_compiler_check_all_threads_done(amal_compiler *self) { int i; - int result; - result = AMAL_COMPILER_OK; - *done = bool_false; + bool result; + result = bool_false; cleanup_if_error(amal_mutex_lock(&self->mutex, "amal_compiler_check_all_threads_done")); for(i = 0; i < self->usable_thread_count; ++i) { ParserThreadData *parser_thread_data; parser_thread_data = &self->threads[i]; if(parser_thread_data->status == PARSER_THREAD_STATUS_RUNNING) { - result = AMAL_COMPILER_ERR; goto cleanup; } } - *done = bool_true; + result = bool_true; cleanup: amal_mutex_tryunlock(&self->mutex); return result; @@ -316,7 +365,8 @@ static CHECK_RESULT int amal_compiler_load_file_join_threads(amal_compiler *self amal_mutex_tryunlock(&self->mutex); if(result != 0) goto cleanup; - ignore_result_int(parser_thread_data_join(parser_thread_data, &thread_return_data)); + /* TODO: Cleanup remaining threads if join fails */ + cleanup_if_error(parser_thread_data_join(parser_thread_data, &thread_return_data)); if(thread_return_data != NULL) { /* TODO: Somehow exit running jobs */ amal_log_error("Failed, waiting for jobs to finish"); @@ -324,7 +374,7 @@ static CHECK_RESULT int amal_compiler_load_file_join_threads(amal_compiler *self } } - cleanup_if_error(amal_compiler_check_all_threads_done(self, &done)); + done = amal_compiler_check_all_threads_done(self); if(done) break; } @@ -355,19 +405,56 @@ static CHECK_RESULT int amal_compiler_dispatch_generic(amal_compiler *self, Thre return amal_compiler_load_file_join_threads(self); } +static CHECK_RESULT int try_create_file_scope(amal_compiler *compiler, const char *filepath, FileScopeReference **file_scope, bool *new_entry) { + int ret; + char *result_path; + usize result_path_size; + BufferView path_view; + + ret = -1; + result_path = NULL; + *new_entry = bool_false; + + return_if_error(file_get_canonical_path(filepath, &result_path, &result_path_size)); + path_view = create_buffer_view(result_path, result_path_size); + cleanup_if_error(amal_mutex_lock(&compiler->mutex, "try_create_file_scope")); + if(!hash_map_get(&compiler->file_scopes, path_view, file_scope)) { + cleanup_if_error(scoped_allocator_alloc(&compiler->allocator, sizeof(FileScopeReference), (void**)file_scope)); + /* @(*file_scope)->canonical_path won't change after this, so it's fine if allocator belongs to non-thread safe compiler instance */ + cleanup_if_error(file_scope_reference_init(*file_scope, path_view, &compiler->allocator)); + cleanup_if_error(hash_map_insert(&compiler->file_scopes, path_view, file_scope)); + *new_entry = bool_true; + } + + ret = 0; + cleanup: + amal_mutex_tryunlock(&compiler->mutex); + am_free(result_path); + return ret; +} + /* amal_compiler_load_file is called by the user for the first file to compile but also called by the parser when it sees @import */ -int amal_compiler_load_file(amal_compiler *self, BufferView filepath) { +int amal_compiler_load_file(amal_compiler *self, const char *filepath, FileScopeReference **file_scope) { int result; + BufferView filepath_view; ParserThreadData *parser_thread_data; ThreadWorkData thread_work_data; bool main_job; + bool new_entry; + + return_if_error(try_create_file_scope(self, filepath, file_scope, &new_entry)); + filepath_view = create_buffer_view((*file_scope)->canonical_path.data, (*file_scope)->canonical_path.size); + if(!new_entry) { + amal_log_info("amal_compiler_load_file: file already parsed: %.*s", filepath_view.size, filepath_view.data); + return 0; + } result = AMAL_COMPILER_ERR; thread_work_data.type = THREAD_WORK_PARSE; - thread_work_data.value.filepath = filepath; + thread_work_data.value.filepath = filepath_view; main_job = bool_false; /* The first time we get here, this will run single-threaded so this part doesn't need mutex */ @@ -379,13 +466,18 @@ int amal_compiler_load_file(amal_compiler *self, BufferView filepath) { return_if_error(amal_compiler_select_thread_for_work(self, thread_work_data, &parser_thread_data)); if(main_job) { - /*amal_log_info("Parsing %.*s using %d thread(s)", (int)filepath.size, filepath.data, self->usable_thread_count);*/ - /*return_if_error(amal_compiler_load_first_this_thread(self, filepath, &self->main_thread_allocator));*/ return_if_error(amal_compiler_load_file_join_threads(self)); - amal_log_debug("Finished parsing all files, resolving AST"); + assert(amal_compiler_check_all_threads_done(self)); + amal_log_info("Finished parsing all files, resolving AST"); + return_if_error(amal_compiler_dispatch_generic(self, THREAD_WORK_RESOLVE_AST)); - amal_log_debug("Finished resolving AST, generating SSA"); + assert(amal_compiler_check_all_threads_done(self)); + amal_log_info("Finished resolving AST, generating SSA"); + return_if_error(amal_compiler_dispatch_generic(self, THREAD_WORK_GENERATE_SSA)); + assert(amal_compiler_check_all_threads_done(self)); + amal_log_info("Finished generating SSA"); + return AMAL_COMPILER_OK; } @@ -393,7 +485,7 @@ int amal_compiler_load_file(amal_compiler *self, BufferView filepath) { return AMAL_COMPILER_OK; cleanup_if_error(amal_mutex_lock(&self->mutex, "amal_compiler_load_file")); - cleanup_if_error(buffer_append(&self->queued_files, &filepath, sizeof(filepath))); + cleanup_if_error(buffer_append(&self->queued_files, &filepath_view, sizeof(filepath_view))); result = AMAL_COMPILER_OK; cleanup: -- cgit v1.2.3