diff options
Diffstat (limited to 'src/compiler.c')
-rw-r--r-- | src/compiler.c | 94 |
1 files changed, 72 insertions, 22 deletions
diff --git a/src/compiler.c b/src/compiler.c index c9ae09a..d10d9fb 100644 --- a/src/compiler.c +++ b/src/compiler.c @@ -11,8 +11,6 @@ #include <limits.h> #include <assert.h> -#define MIN(a, b) ((a) < (b) ? (a) : (b)) - static CHECK_RESULT int get_thread_count_env_var(int *thread_count) { char *threads; threads = getenv("THREADS"); @@ -68,7 +66,12 @@ static CHECK_RESULT int init_default_types(amal_compiler *compiler) { return 0; } -int amal_compiler_init(amal_compiler *self) { +void amal_compiler_options_init(amal_compiler_options *self) { + self->error_callback = NULL; + self->error_callback_userdata = NULL; +} + +int amal_compiler_init(amal_compiler *self, const amal_compiler_options *options) { int i; int result; @@ -87,7 +90,12 @@ int amal_compiler_init(amal_compiler *self) { am_memset(&self->allocator, 0, sizeof(self->allocator)); am_memset(&self->root_scope, 0, sizeof(self->root_scope)); + if(options) + am_memcpy(&self->options, options, sizeof(self->options)); + else + am_memset(&self->options, 0, sizeof(self->options)); self->started = bool_false; + self->used = bool_false; self->generic_work_object_index = 0; amal_mutex_init(&self->mutex); @@ -129,7 +137,8 @@ int amal_compiler_deinit(amal_compiler *self) { typedef enum { THREAD_WORK_PARSE, THREAD_WORK_RESOLVE_AST, - THREAD_WORK_GENERATE_SSA + THREAD_WORK_GENERATE_SSA, + THREAD_WORK_GENERATE_BYTECODE } ThreadWorkType; typedef struct { @@ -153,7 +162,7 @@ typedef struct { ThreadWorkType type; } ThreadWorkData; -static CHECK_RESULT int amal_compiler_load_in_this_thread(amal_compiler *self, FileScopeReference *file_scope, ScopedAllocator *allocator) { +static CHECK_RESULT int amal_compiler_load_in_this_thread(amal_compiler *compiler, FileScopeReference *file_scope, ScopedAllocator *allocator) { Parser *parser; int result; BufferView filepath; @@ -162,16 +171,16 @@ static CHECK_RESULT int amal_compiler_load_in_this_thread(amal_compiler *self, F filepath = create_buffer_view(file_scope->canonical_path.data, file_scope->canonical_path.size); amal_log_info("Started parsing %.*s", 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_init(parser, compiler, allocator)); file_scope->parser = parser; 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))); + cleanup_if_error(amal_mutex_lock(&compiler->mutex, "amal_compiler_load_in_this_thread")); + cleanup_if_error(buffer_append(&compiler->parsers, &parser, sizeof(parser))); amal_log_info("Finished parsing %.*s", filepath.size, filepath.data); result = AMAL_COMPILER_OK; cleanup: - amal_mutex_tryunlock(&self->mutex); + amal_mutex_tryunlock(&compiler->mutex); return result; } @@ -200,6 +209,14 @@ static void* thread_callback_parse_file(void *userdata) { result = NULL; cleanup: + /* + To stop all other parsers from working cleanly, we simply clear the file queue, + and the other threads will stop when they are done with the file they are currently parsing. + */ + if(result != NULL) { + ignore_result_int(amal_mutex_lock(&compiler_parser_userdata.compiler->mutex, "thread_callback_parse_file")); + buffer_clear(&compiler_parser_userdata.compiler->queued_files); + } compiler_parser_userdata.parser_thread_data->status = PARSER_THREAD_STATUS_IDLE; amal_mutex_tryunlock(&compiler_parser_userdata.compiler->mutex); return result; @@ -219,17 +236,30 @@ static CHECK_RESULT int thread_resolve_ast(amal_compiler *compiler, Parser *pars } static CHECK_RESULT int thread_generate_ssa(Parser *parser) { - SsaCompilerContext compiler_context; + SsaCompilerContext *compiler_context; int result; - result = setjmp(compiler_context.env); - if(result == 0) { - return_if_error(ssa_init(&compiler_context.ssa, parser->allocator)); - amal_log_debug("Generating SSA for file: %.*s", parser->tokenizer.code_name.size, parser->tokenizer.code_name.data); - scope_generate_ssa(&parser->struct_decl.body, &compiler_context); - } + + return_if_error(scoped_allocator_alloc(parser->allocator, sizeof(SsaCompilerContext), (void**)&compiler_context)); + return_if_error(ssa_init(&compiler_context->ssa, parser->allocator)); + /* TODO: Maybe instead of creating a ssa context for every parser (every file), create one for every thread */ + parser->ssa_context = compiler_context; + amal_log_debug("Generating SSA for file: %.*s", parser->tokenizer.code_name.size, parser->tokenizer.code_name.data); + result = setjmp(compiler_context->env); + + if(result == 0) + scope_generate_ssa(&parser->struct_decl.body, compiler_context); + return result; } +static CHECK_RESULT int thread_generate_bytecode(amal_compiler *compiler, Parser *parser) { + /* TODO: Implement */ + (void)compiler; + (void)parser; + /*assert(bool_false);*/ + return 0; +} + /* TODO: Handle errors (stop work in all other threads and report errors/warnings) */ static void* thread_callback_generic(void *userdata) { CompilerGenericThreadUserData compiler_userdata; @@ -254,6 +284,9 @@ static void* thread_callback_generic(void *userdata) { case THREAD_WORK_GENERATE_SSA: cleanup_if_error(thread_generate_ssa(parser)); break; + case THREAD_WORK_GENERATE_BYTECODE: + cleanup_if_error(thread_generate_bytecode(compiler_userdata.compiler, parser)); + break; } cleanup_if_error(amal_mutex_lock(&compiler_userdata.compiler->mutex, "thread_callback_generic")); if(compiler_userdata.compiler->generic_work_object_index + 1 >= (int)buffer_get_size(&compiler_userdata.compiler->parsers, Parser*)) @@ -265,6 +298,14 @@ static void* thread_callback_generic(void *userdata) { result = NULL; cleanup: + /* + To stop all other worker threads cleanly, we simply say we are done with all work in the queue, + and the other threads will stop when they are done with the work they are currently working on. + */ + if(result != NULL) { + cleanup_if_error(amal_mutex_lock(&compiler_userdata.compiler->mutex, "thread_callback_generic")); + compiler_userdata.compiler->generic_work_object_index = (int)buffer_get_size(&compiler_userdata.compiler->parsers, Parser*); + } compiler_userdata.parser_thread_data->status = PARSER_THREAD_STATUS_IDLE; amal_mutex_tryunlock(&compiler_userdata.compiler->mutex); return result; @@ -297,7 +338,8 @@ static CHECK_RESULT int amal_compiler_select_thread_for_work(amal_compiler *self break; } case THREAD_WORK_RESOLVE_AST: - case THREAD_WORK_GENERATE_SSA: { + case THREAD_WORK_GENERATE_SSA: + case THREAD_WORK_GENERATE_BYTECODE: { CompilerGenericThreadUserData *userdata; cleanup_if_error(am_malloc(sizeof(CompilerGenericThreadUserData), (void**)&userdata)); thread_user_data = userdata; @@ -432,11 +474,15 @@ static CHECK_RESULT int try_create_file_scope(amal_compiler *compiler, const cha 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, const char *filepath, FileScopeReference **file_scope) { +int amal_compiler_load_file(amal_compiler *self, const char *filepath) { + FileScopeReference *file_scope; + if(self->used) + return AMAL_COMPILER_ERR; + self->used = bool_true; + return amal_compiler_internal_load_file(self, filepath, &file_scope); +} + +int amal_compiler_internal_load_file(amal_compiler *self, const char *filepath, FileScopeReference **file_scope) { int result; BufferView filepath_view; ParserThreadData *parser_thread_data; @@ -478,6 +524,10 @@ int amal_compiler_load_file(amal_compiler *self, const char *filepath, FileScope assert(amal_compiler_check_all_threads_done(self)); amal_log_info("Finished generating SSA"); + return_if_error(amal_compiler_dispatch_generic(self, THREAD_WORK_GENERATE_BYTECODE)); + assert(amal_compiler_check_all_threads_done(self)); + amal_log_info("Finished generating bytecode"); + return AMAL_COMPILER_OK; } |