aboutsummaryrefslogtreecommitdiff
path: root/src/compiler.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/compiler.c')
-rw-r--r--src/compiler.c94
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;
}