From 71ac145f49efa816f49b462df3ec38288a57d776 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 28 Apr 2021 15:28:14 +0100 Subject: Remove dead code related to old backend --- src/build_settings.cpp | 61 -------------------------------------------------- 1 file changed, 61 deletions(-) (limited to 'src/build_settings.cpp') diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 82ed24f83..f48aa4999 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -173,8 +173,6 @@ struct BuildContext { String resource_filepath; String pdb_filepath; bool has_resource; - String opt_flags; - String llc_flags; String link_flags; String extra_linker_flags; String microarch; @@ -806,22 +804,12 @@ void init_build_context(TargetMetrics *cross_target) { bc->word_size = metrics->word_size; bc->max_align = metrics->max_align; bc->link_flags = str_lit(" "); - bc->opt_flags = str_lit(" "); - gbString llc_flags = gb_string_make_reserve(heap_allocator(), 64); - if (bc->ODIN_DEBUG) { - // llc_flags = gb_string_appendc(llc_flags, "-debug-compile "); - } - // NOTE(zangent): The linker flags to set the build architecture are different // across OSs. It doesn't make sense to allocate extra data on the heap // here, so I just #defined the linker flags to keep things concise. if (bc->metrics.arch == TargetArch_amd64) { - if (bc->microarch.len == 0) { - llc_flags = gb_string_appendc(llc_flags, "-march=x86-64 "); - } - switch (bc->metrics.os) { case TargetOs_windows: bc->link_flags = str_lit("/machine:x64 "); @@ -836,10 +824,6 @@ void init_build_context(TargetMetrics *cross_target) { break; } } else if (bc->metrics.arch == TargetArch_386) { - if (bc->microarch.len == 0) { - llc_flags = gb_string_appendc(llc_flags, "-march=x86 "); - } - switch (bc->metrics.os) { case TargetOs_windows: bc->link_flags = str_lit("/machine:x86 "); @@ -856,10 +840,6 @@ void init_build_context(TargetMetrics *cross_target) { break; } } else if (bc->metrics.arch == TargetArch_arm64) { - if (bc->microarch.len == 0) { - llc_flags = gb_string_appendc(llc_flags, "-march=arm64 "); - } - switch (bc->metrics.os) { case TargetOs_darwin: bc->link_flags = str_lit("-arch arm64 "); @@ -872,50 +852,9 @@ void init_build_context(TargetMetrics *cross_target) { gb_printf_err("Compiler Error: Unsupported architecture\n");; gb_exit(1); } - llc_flags = gb_string_appendc(llc_flags, " "); - bc->optimization_level = gb_clamp(bc->optimization_level, 0, 3); - gbString opt_flags = gb_string_make_reserve(heap_allocator(), 64); - - if (bc->microarch.len != 0) { - opt_flags = gb_string_appendc(opt_flags, "-march="); - opt_flags = gb_string_append_length(opt_flags, bc->microarch.text, bc->microarch.len); - opt_flags = gb_string_appendc(opt_flags, " "); - - // llc_flags = gb_string_appendc(opt_flags, "-march="); - // llc_flags = gb_string_append_length(llc_flags, bc->microarch.text, bc->microarch.len); - // llc_flags = gb_string_appendc(llc_flags, " "); - } - - - if (bc->optimization_level != 0) { - opt_flags = gb_string_append_fmt(opt_flags, "-O%d ", bc->optimization_level); - // NOTE(lachsinc): The following options were previously passed during call - // to opt in main.cpp:exec_llvm_opt(). - // -die: Dead instruction elimination - // -memcpyopt: MemCpy optimization - } - if (bc->ODIN_DEBUG == false) { - opt_flags = gb_string_appendc(opt_flags, "-mem2reg -die "); - } - - - - - - // NOTE(lachsinc): This optimization option was previously required to get - // around an issue in fmt.odin. Thank bp for tracking it down! Leaving for now until the issue - // is resolved and confirmed by Bill. Maybe it should be readded in non-debug builds. - // if (bc->ODIN_DEBUG == false) { - // opt_flags = gb_string_appendc(opt_flags, "-mem2reg "); - // } - - bc->opt_flags = make_string_c(opt_flags); - bc->llc_flags = make_string_c(llc_flags); - - #undef LINK_FLAG_X64 #undef LINK_FLAG_386 } -- cgit v1.2.3 From 3a556eb3046f3f7ff1183981b261ac38e38c0c87 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 3 May 2021 15:44:57 +0100 Subject: Add `-test-name:` flag to allow specific tests to be ran --- src/build_settings.cpp | 2 ++ src/checker.cpp | 35 +++++++++++++++++++++++++++++++++++ src/main.cpp | 32 +++++++++++++++++++++++++++++--- 3 files changed, 66 insertions(+), 3 deletions(-) (limited to 'src/build_settings.cpp') diff --git a/src/build_settings.cpp b/src/build_settings.cpp index f48aa4999..77d9cc506 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -212,6 +212,8 @@ struct BuildContext { QueryDataSetSettings query_data_set_settings; + StringSet test_names; + gbAffinity affinity; isize thread_count; diff --git a/src/checker.cpp b/src/checker.cpp index 523d2c297..3b7a58c5e 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -4502,6 +4502,38 @@ void check_unchecked_bodies(Checker *c) { } } +void check_test_names(Checker *c) { + if (build_context.test_names.entries.count == 0) { + return; + } + + AstPackage *pkg = c->info.init_package; + Scope *s = pkg->scope; + + for_array(i, build_context.test_names.entries) { + String name = build_context.test_names.entries[i].value; + Entity *e = scope_lookup(s, name); + if (e == nullptr) { + Token tok = {}; + if (pkg->files.count != 0) { + tok = pkg->files[0]->tokens[0]; + } + error(tok, "Unable to find the test '%.*s' in 'package %.*s' ", LIT(name), LIT(pkg->name)); + } + } + + for (isize i = 0; i < c->info.testing_procedures.count; /**/) { + Entity *e = c->info.testing_procedures[i]; + String name = e->token.string; + if (!string_set_exists(&build_context.test_names, name)) { + array_ordered_remove(&c->info.testing_procedures, i); + } else { + i += 1; + } + } + +} + void check_parsed_files(Checker *c) { #define TIME_SECTION(str) do { if (build_context.show_more_timings) timings_start_section(&global_timings, str_lit(str)); } while (0) @@ -4576,6 +4608,9 @@ void check_parsed_files(Checker *c) { TIME_SECTION("generate minimum dependency set"); generate_minimum_dependency_set(c, c->info.entry_point); + TIME_SECTION("check test names"); + check_test_names(c); + TIME_SECTION("calculate global init order"); // Calculate initialization order of global variables calculate_global_init_order(c); diff --git a/src/main.cpp b/src/main.cpp index 0a38d3496..48fb4dcc3 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -338,8 +338,8 @@ i32 linker_stage(lbGenerator *gen) { gbString lib_str = gb_string_make(heap_allocator(), "-L/"); defer (gb_string_free(lib_str)); - for_array(i, gen->module.foreign_library_paths) { - String lib = gen->module.foreign_library_paths[i]; + for_array(i, gen->default_module.foreign_library_paths) { + String lib = gen->default_module.foreign_library_paths[i]; // NOTE(zangent): Sometimes, you have to use -framework on MacOS. // This allows you to specify '-f' in a #foreign_system_library, @@ -603,6 +603,8 @@ enum BuildFlagKind { BuildFlag_ExtraLinkerFlags, BuildFlag_Microarch, + BuildFlag_TestName, + BuildFlag_DisallowDo, BuildFlag_DefaultToNilAllocator, BuildFlag_InsertSemicolon, @@ -721,6 +723,8 @@ bool parse_build_flags(Array args) { add_flag(&build_flags, BuildFlag_ExtraLinkerFlags, str_lit("extra-linker-flags"), BuildFlagParam_String, Command__does_build); add_flag(&build_flags, BuildFlag_Microarch, str_lit("microarch"), BuildFlagParam_String, Command__does_build); + add_flag(&build_flags, BuildFlag_TestName, str_lit("test-name"), BuildFlagParam_String, Command_test); + add_flag(&build_flags, BuildFlag_DisallowDo, str_lit("disallow-do"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_DefaultToNilAllocator, str_lit("default-to-nil-allocator"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_InsertSemicolon, str_lit("insert-semicolon"), BuildFlagParam_None, Command__does_check); @@ -1219,6 +1223,21 @@ bool parse_build_flags(Array args) { string_to_lower(&build_context.microarch); break; + case BuildFlag_TestName: + GB_ASSERT(value.kind == ExactValue_String); + { + String name = value.value_string; + if (!string_is_valid_identifier(name)) { + gb_printf_err("Test name '%.*s' must be a valid identifier\n", LIT(name)); + bad_flags = true; + break; + } + string_set_add(&build_context.test_names, name); + + // NOTE(bill): Allow for multiple -test-name + continue; + } + case BuildFlag_DisallowDo: build_context.disallow_do = true; break; @@ -1580,6 +1599,7 @@ void print_show_help(String const arg0, String const &command) { bool doc = command == "doc"; bool build = command == "build"; bool run_or_build = command == "run" || command == "build" || command == "test"; + bool test_only = command == "test"; bool check_only = command == "check"; bool check = run_or_build || command == "check"; @@ -1734,6 +1754,12 @@ void print_show_help(String const arg0, String const &command) { } } + if (test_only) { + print_usage_line(1, "-test-name:"); + print_usage_line(2, "Run specific test only by name"); + print_usage_line(0, ""); + } + if (run_or_build) { print_usage_line(1, "-extra-linker-flags:"); print_usage_line(2, "Adds extra linker specific flags in a string"); @@ -1925,7 +1951,7 @@ int main(int arg_count, char const **arg_ptr) { map_init(&build_context.defined_values, heap_allocator()); build_context.extra_packages.allocator = heap_allocator(); - + string_set_init(&build_context.test_names, heap_allocator()); Array args = setup_args(arg_count, arg_ptr); -- cgit v1.2.3 From 746e880eb521e6cf5b6a452004da9bc5d2095076 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 3 May 2021 17:43:14 +0100 Subject: Begin work on making LLVM backend work with multiple modules for possible faster compilation --- src/build_settings.cpp | 6 + src/llvm_backend.cpp | 668 +++++++++++++++++++++++++++++-------------------- src/llvm_backend.hpp | 11 +- src/main.cpp | 11 +- 4 files changed, 417 insertions(+), 279 deletions(-) (limited to 'src/build_settings.cpp') diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 77d9cc506..77046cf6d 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -207,6 +207,8 @@ struct BuildContext { bool ignore_microsoft_magic; bool linker_map_file; + bool use_separate_modules; + u32 cmd_doc_flags; Array extra_packages; @@ -807,6 +809,10 @@ void init_build_context(TargetMetrics *cross_target) { bc->max_align = metrics->max_align; bc->link_flags = str_lit(" "); + if (bc->metrics.os == TargetOs_windows) { + // bc->use_separate_modules = bc->optimization_level == 0; + } + // NOTE(zangent): The linker flags to set the build architecture are different // across OSs. It doesn't make sense to allocate extra data on the heap diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 2c61132dd..a7c149f06 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -1,3 +1,7 @@ +#ifndef USE_SEPARTE_MODULES +#define USE_SEPARTE_MODULES build_context.use_separate_modules +#endif + #include "llvm_backend.hpp" #include "llvm_abi.cpp" #include "llvm_backend_opt.cpp" @@ -74,6 +78,15 @@ bool lb_is_instr_terminating(LLVMValueRef instr) { +lbModule *lb_pkg_module(lbGenerator *gen, AstPackage *pkg) { + auto *found = map_get(&gen->modules, hash_pointer(pkg)); + if (found) { + return *found; + } + return &gen->default_module; +} + + lbAddr lb_addr(lbValue addr) { lbAddr v = {lbAddr_Default, addr}; if (addr.type != nullptr && is_type_relative_pointer(type_deref(addr.type))) { @@ -2528,10 +2541,17 @@ void lb_ensure_abi_function_type(lbModule *m, lbProcedure *p) { GB_ASSERT(p->abi_function_type != nullptr); } -lbProcedure *lb_create_procedure(lbModule *m, Entity *entity) { +lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool ignore_body) { GB_ASSERT(entity != nullptr); - String link_name = lb_get_entity_name(m, entity); + String link_name = {}; + + if (ignore_body) { + lbModule *other_module = lb_pkg_module(m->gen, entity->pkg); + link_name = lb_get_entity_name(other_module, entity); + } else { + link_name = lb_get_entity_name(m, entity); + } { StringHashKey key = string_hash_string(link_name); @@ -2699,6 +2719,10 @@ lbProcedure *lb_create_procedure(lbModule *m, Entity *entity) { } } + if (ignore_body) { + p->body = nullptr; + } + if (m->debug_builder) { // Debug Information Type *bt = base_type(p->type); @@ -5484,9 +5508,10 @@ LLVMValueRef lb_find_or_add_entity_string_ptr(lbModule *m, String const &str) { isize max_len = 7+8+1; char *name = gb_alloc_array(permanent_allocator(), char, max_len); - isize len = gb_snprintf(name, max_len, "csbs$%x", m->global_array_index); + + u32 id = cast(u32)gb_atomic32_fetch_add(&m->gen->global_array_index, 1); + isize len = gb_snprintf(name, max_len, "csbs$%x", id); len -= 1; - m->global_array_index++; LLVMValueRef global_data = LLVMAddGlobal(m->mod, LLVMTypeOf(data), name); LLVMSetInitializer(global_data, data); @@ -5526,9 +5551,9 @@ lbValue lb_find_or_add_entity_string_byte_slice(lbModule *m, String const &str) { isize max_len = 7+8+1; name = gb_alloc_array(permanent_allocator(), char, max_len); - isize len = gb_snprintf(name, max_len, "csbs$%x", m->global_array_index); + u32 id = cast(u32)gb_atomic32_fetch_add(&m->gen->global_array_index, 1); + isize len = gb_snprintf(name, max_len, "csbs$%x", id); len -= 1; - m->global_array_index++; } LLVMValueRef global_data = LLVMAddGlobal(m->mod, LLVMTypeOf(data), name); LLVMSetInitializer(global_data, data); @@ -5684,6 +5709,7 @@ LLVMValueRef lb_build_constant_array_values(lbModule *m, Type *type, Type *elem_ } lbValue lb_find_procedure_value_from_entity(lbModule *m, Entity *e) { + GB_ASSERT(is_type_proc(e->type)); e = strip_entity_wrapping(e); GB_ASSERT(e != nullptr); auto *found = map_get(&m->values, hash_entity(e)); @@ -5691,8 +5717,14 @@ lbValue lb_find_procedure_value_from_entity(lbModule *m, Entity *e) { return *found; } - // TODO(bill): this is - lbProcedure *missing_proc = lb_create_procedure(m, e); + bool ignore_body = false; + + if (USE_SEPARTE_MODULES) { + lbModule *other_module = lb_pkg_module(m->gen, e->pkg); + ignore_body = other_module != m; + } + + lbProcedure *missing_proc = lb_create_procedure(m, e, ignore_body); found = map_get(&m->values, hash_entity(e)); if (found) { return *found; @@ -5702,6 +5734,47 @@ lbValue lb_find_procedure_value_from_entity(lbModule *m, Entity *e) { return {}; } +lbValue lb_find_value_from_entity(lbModule *m, Entity *e) { + e = strip_entity_wrapping(e); + GB_ASSERT(e != nullptr); + if (is_type_proc(e->type)) { + return lb_find_procedure_value_from_entity(m, e); + } + + auto *found = map_get(&m->values, hash_entity(e)); + if (found) { + return *found; + } + + if (USE_SEPARTE_MODULES) { + lbModule *other_module = lb_pkg_module(m->gen, e->pkg); + bool is_external = other_module != m; + if (!is_external) { + other_module = e->code_gen_module; + is_external = other_module != m; + } + + if (is_external) { + String name = lb_get_entity_name(other_module, e); + + lbValue g = {}; + g.value = LLVMAddGlobal(m->mod, lb_type(m, e->type), alloc_cstring(permanent_allocator(), name)); + g.type = alloc_type_pointer(e->type); + LLVMSetExternallyInitialized(g.value, true); + + lb_add_entity(m, e, g); + lb_add_member(m, name, g); + return g; + } + } + + GB_PANIC("\n\tError in: %s, missing value %.*s\n", token_pos_to_string(e->token.pos), LIT(e->token.string)); + return {}; +} + + + + lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_local) { LLVMContextRef ctx = m->ctx; @@ -5777,8 +5850,8 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc } else { isize max_len = 7+8+1; char *str = gb_alloc_array(permanent_allocator(), char, max_len); - isize len = gb_snprintf(str, max_len, "csba$%x", m->global_array_index); - m->global_array_index++; + u32 id = cast(u32)gb_atomic32_fetch_add(&m->gen->global_array_index, 1); + isize len = gb_snprintf(str, max_len, "csba$%x", id); String name = make_string(cast(u8 *)str, len-1); @@ -8192,31 +8265,18 @@ lbValue lb_emit_call_internal(lbProcedure *p, lbValue value, lbValue return_ptr, } } -lbValue lb_emit_runtime_call(lbProcedure *p, char const *c_name, Array const &args) { - // LLVMMetadataRef curr_loc = LLVMGetCurrentDebugLocation2(p->builder); - // LLVMSetCurrentDebugLocation2(p->builder, nullptr); - // defer (if (curr_loc) { - // LLVMSetCurrentDebugLocation2(p->builder, curr_loc); - // }); - String name = make_string_c(c_name); - - - AstPackage *pkg = p->module->info->runtime_package; +lbValue lb_lookup_runtime_procedure(lbModule *m, String const &name) { + AstPackage *pkg = m->info->runtime_package; Entity *e = scope_lookup_current(pkg->scope, name); + return lb_find_procedure_value_from_entity(m, e); +} - lbValue *found = nullptr; - if (p->module != e->code_gen_module) { - gb_mutex_lock(&p->module->mutex); - } - GB_ASSERT(e->code_gen_module != nullptr); - found = map_get(&e->code_gen_module->values, hash_entity(e)); - if (p->module != e->code_gen_module) { - gb_mutex_unlock(&p->module->mutex); - } - GB_ASSERT_MSG(found != nullptr, "%s", c_name); - return lb_emit_call(p, *found, args); +lbValue lb_emit_runtime_call(lbProcedure *p, char const *c_name, Array const &args) { + String name = make_string_c(c_name); + lbValue proc = lb_lookup_runtime_procedure(p->module, name); + return lb_emit_call(p, proc, args); } lbValue lb_emit_call(lbProcedure *p, lbValue value, Array const &args, ProcInlining inlining, bool use_return_ptr_hint) { @@ -9946,24 +10006,6 @@ void lb_emit_increment(lbProcedure *p, lbValue addr) { } -LLVMValueRef lb_lookup_runtime_procedure(lbModule *m, String const &name) { - AstPackage *pkg = m->info->runtime_package; - Entity *e = scope_lookup_current(pkg->scope, name); - - lbValue *found = nullptr; - if (m != e->code_gen_module) { - gb_mutex_lock(&m->mutex); - } - GB_ASSERT(e->code_gen_module != nullptr); - found = map_get(&e->code_gen_module->values, hash_entity(e)); - if (m != e->code_gen_module) { - gb_mutex_unlock(&m->mutex); - } - GB_ASSERT(found != nullptr); - - return found->value; -} - lbValue lb_emit_byte_swap(lbProcedure *p, lbValue value, Type *end_type) { GB_ASSERT(type_size_of(value.type) == type_size_of(end_type)); @@ -11122,6 +11164,44 @@ lbValue lb_emit_any_cast(lbProcedure *p, lbValue value, Type *type, TokenPos pos } +lbValue lb_find_ident(lbProcedure *p, lbModule *m, Entity *e, Ast *expr) { + auto *found = map_get(&m->values, hash_entity(e)); + if (found) { + auto v = *found; + // NOTE(bill): This is because pointers are already pointers in LLVM + if (is_type_proc(v.type)) { + return v; + } + return lb_emit_load(p, v); + } else if (e != nullptr && e->kind == Entity_Variable) { + return lb_addr_load(p, lb_build_addr(p, expr)); + } + + if (USE_SEPARTE_MODULES) { + lbModule *other_module = lb_pkg_module(m->gen, e->pkg); + if (other_module != m) { + String name = lb_get_entity_name(other_module, e); + + lbValue g = {}; + g.value = LLVMAddGlobal(m->mod, lb_type(m, e->type), alloc_cstring(permanent_allocator(), name)); + g.type = alloc_type_pointer(e->type); + LLVMSetExternallyInitialized(g.value, true); + + lb_add_entity(m, e, g); + lb_add_member(m, name, g); + return lb_emit_load(p, g); + } + } + + String pkg = {}; + if (e->pkg) { + pkg = e->pkg->name; + } + gb_printf_err("Error in: %s\n", token_pos_to_string(ast_token(expr).pos)); + GB_PANIC("nullptr value for expression from identifier: %.*s.%.*s (%p) : %s @ %p", LIT(pkg), LIT(e->token.string), e, type_to_string(e->type), expr); + return {}; +} + lbValue lb_build_expr(lbProcedure *p, Ast *expr) { lbModule *m = p->module; @@ -11211,24 +11291,7 @@ lbValue lb_build_expr(lbProcedure *p, Ast *expr) { } GB_ASSERT(e->kind != Entity_ProcGroup); - auto *found = map_get(&p->module->values, hash_entity(e)); - if (found) { - auto v = *found; - // NOTE(bill): This is because pointers are already pointers in LLVM - if (is_type_proc(v.type)) { - return v; - } - return lb_emit_load(p, v); - } else if (e != nullptr && e->kind == Entity_Variable) { - return lb_addr_load(p, lb_build_addr(p, expr)); - } - gb_printf_err("Error in: %s\n", token_pos_to_string(i->token.pos)); - String pkg = {}; - if (e->pkg) { - pkg = e->pkg->name; - } - GB_PANIC("nullptr value for expression from identifier: %.*s.%.*s (%p) : %s @ %p", LIT(pkg), LIT(e->token.string), e, type_to_string(e->type), expr); - return {}; + return lb_find_ident(p, m, e, expr); case_end; case_ast_node(de, DerefExpr, expr); @@ -11609,11 +11672,14 @@ lbAddr lb_build_addr_from_entity(lbProcedure *p, Entity *e, Ast *expr) { return lb_get_soa_variable_addr(p, e); } + if (v.value == nullptr) { - error(expr, "%.*s Unknown value: %.*s, entity: %p %.*s", - LIT(p->name), - LIT(e->token.string), e, LIT(entity_strings[e->kind])); - GB_PANIC("Unknown value"); + return lb_addr(lb_find_value_from_entity(p->module, e)); + + // error(expr, "%.*s Unknown value: %.*s, entity: %p %.*s", + // LIT(p->name), + // LIT(e->token.string), e, LIT(entity_strings[e->kind])); + // GB_PANIC("Unknown value"); } return lb_addr(v); @@ -13031,18 +13097,31 @@ bool lb_init_generator(lbGenerator *gen, Checker *c) { gen->info = &c->info; map_init(&gen->modules, permanent_allocator(), gen->info->packages.entries.count*2); + map_init(&gen->modules_through_ctx, permanent_allocator(), gen->info->packages.entries.count*2); - for_array(i, gen->info->packages.entries) { - AstPackage *pkg = gen->info->packages.entries[i].value; + if (USE_SEPARTE_MODULES) { + for_array(i, gen->info->packages.entries) { + AstPackage *pkg = gen->info->packages.entries[i].value; - auto m = gb_alloc_item(permanent_allocator(), lbModule); - m->pkg = pkg; - map_set(&gen->modules, hash_pointer(pkg), m); - lb_init_module(m, c); + auto m = gb_alloc_item(permanent_allocator(), lbModule); + m->pkg = pkg; + m->gen = gen; + map_set(&gen->modules, hash_pointer(pkg), m); + lb_init_module(m, c); + } } + + gen->default_module.gen = gen; map_set(&gen->modules, hash_pointer(nullptr), &gen->default_module); lb_init_module(&gen->default_module, c); + + for_array(i, gen->modules.entries) { + lbModule *m = gen->modules.entries[i].value; + LLVMContextRef ctx = LLVMGetModuleContext(m->mod); + map_set(&gen->modules_through_ctx, hash_pointer(ctx), m); + } + return true; } @@ -13052,8 +13131,10 @@ lbAddr lb_add_global_generated(lbModule *m, Type *type, lbValue value) { isize max_len = 7+8+1; u8 *str = cast(u8 *)gb_alloc_array(permanent_allocator(), u8, max_len); - isize len = gb_snprintf(cast(char *)str, max_len, "ggv$%x", m->global_generated_index); - m->global_generated_index++; + + u32 id = cast(u32)gb_atomic32_fetch_add(&m->gen->global_generated_index, 1); + + isize len = gb_snprintf(cast(char *)str, max_len, "ggv$%x", id); String name = make_string(str, len-1); Scope *scope = nullptr; @@ -13076,17 +13157,12 @@ lbAddr lb_add_global_generated(lbModule *m, Type *type, lbValue value) { lbValue lb_find_runtime_value(lbModule *m, String const &name) { AstPackage *p = m->info->runtime_package; Entity *e = scope_lookup_current(p->scope, name); - lbValue *found = map_get(&m->values, hash_entity(e)); - GB_ASSERT_MSG(found != nullptr, "Unable to find runtime value '%.*s'", LIT(name)); - lbValue value = *found; - return value; + return lb_find_value_from_entity(m, e); } lbValue lb_find_package_value(lbModule *m, String const &pkg, String const &name) { Entity *e = find_entity_in_pkg(m->info, pkg, name); lbValue *found = map_get(&m->values, hash_entity(e)); - GB_ASSERT_MSG(found != nullptr, "Unable to find value '%.*s.%.*s'", LIT(pkg), LIT(name)); - lbValue value = *found; - return value; + return lb_find_value_from_entity(m, e); } lbValue lb_get_type_info_ptr(lbModule *m, Type *type) { @@ -13900,8 +13976,8 @@ lbProcedure *lb_create_startup_type_info(lbModule *m) { return p; } -lbProcedure *lb_create_startup_runtime(lbModule *m, lbProcedure *startup_type_info, Array &global_variables) { // Startup Runtime - LLVMPassManagerRef default_function_pass_manager = LLVMCreateFunctionPassManagerForModule(m->mod); +lbProcedure *lb_create_startup_runtime(lbModule *main_module, lbProcedure *startup_type_info, Array &global_variables) { // Startup Runtime + LLVMPassManagerRef default_function_pass_manager = LLVMCreateFunctionPassManagerForModule(main_module->mod); defer (LLVMDisposePassManager(default_function_pass_manager)); lb_populate_function_pass_manager(default_function_pass_manager, false, build_context.optimization_level); LLVMFinalizeFunctionPassManager(default_function_pass_manager); @@ -13911,12 +13987,12 @@ lbProcedure *lb_create_startup_runtime(lbModule *m, lbProcedure *startup_type_in Type *proc_type = alloc_type_proc(nullptr, nullptr, 0, nullptr, 0, false, ProcCC_CDecl); - lbProcedure *p = lb_create_dummy_procedure(m, str_lit(LB_STARTUP_RUNTIME_PROC_NAME), proc_type); + lbProcedure *p = lb_create_dummy_procedure(main_module, str_lit(LB_STARTUP_RUNTIME_PROC_NAME), proc_type); p->is_startup = true; lb_begin_procedure_body(p); - LLVMBuildCall2(p->builder, LLVMGetElementType(lb_type(m, startup_type_info->type)), startup_type_info->value, nullptr, 0, ""); + LLVMBuildCall2(p->builder, LLVMGetElementType(lb_type(main_module, startup_type_info->type)), startup_type_info->value, nullptr, 0, ""); for_array(i, global_variables) { auto *var = &global_variables[i]; @@ -13924,8 +14000,11 @@ lbProcedure *lb_create_startup_runtime(lbModule *m, lbProcedure *startup_type_in continue; } + lbModule *entity_module = main_module; + Entity *e = var->decl->entity; GB_ASSERT(e->kind == Entity_Variable); + e->code_gen_module = entity_module; if (var->decl->init_expr != nullptr) { // gb_printf_err("%s\n", expr_to_string(var->decl->init_expr)); @@ -13951,14 +14030,14 @@ lbProcedure *lb_create_startup_runtime(lbModule *m, lbProcedure *startup_type_in if (is_type_any(t)) { // NOTE(bill): Edge case for 'any' type Type *var_type = default_type(var->init.type); - lbAddr g = lb_add_global_generated(m, var_type, var->init); + lbAddr g = lb_add_global_generated(main_module, var_type, var->init); lb_addr_store(p, g, var->init); lbValue gp = lb_addr_get_ptr(p, g); lbValue data = lb_emit_struct_ep(p, var->var, 0); lbValue ti = lb_emit_struct_ep(p, var->var, 1); lb_emit_store(p, data, lb_emit_conv(p, gp, t_rawptr)); - lb_emit_store(p, ti, lb_type_info(m, var_type)); + lb_emit_store(p, ti, lb_type_info(main_module, var_type)); } else { LLVMTypeRef pvt = LLVMTypeOf(var->var.value); LLVMTypeRef vt = LLVMGetElementType(pvt); @@ -13975,7 +14054,7 @@ lbProcedure *lb_create_startup_runtime(lbModule *m, lbProcedure *startup_type_in lb_end_procedure_body(p); - if (!m->debug_builder && LLVMVerifyFunction(p->value, LLVMReturnStatusAction)) { + if (!main_module->debug_builder && LLVMVerifyFunction(p->value, LLVMReturnStatusAction)) { gb_printf_err("LLVM CODE GEN FAILED FOR PROCEDURE: %s\n", "main"); LLVMDumpValue(p->value); gb_printf_err("\n\n\n\n"); @@ -14085,9 +14164,8 @@ lbProcedure *lb_create_main_procedure(lbModule *m, lbProcedure *startup_runtime) args[0] = lb_addr_load(p, all_tests_slice); lb_emit_call(p, runner, args); } else { - lbValue *found = map_get(&m->values, hash_entity(m->info->entry_point)); - GB_ASSERT(found != nullptr); - lb_emit_call(p, *found, {}); + lbValue entry_point = lb_find_procedure_value_from_entity(m, m->info->entry_point); + lb_emit_call(p, entry_point, {}); } LLVMBuildRet(p->builder, LLVMConstInt(lb_type(m, t_i32), 0, false)); @@ -14105,13 +14183,51 @@ lbProcedure *lb_create_main_procedure(lbModule *m, lbProcedure *startup_runtime) return p; } +String lb_filepath_ll_for_module(lbModule *m) { + String path = m->gen->output_base; + if (m->pkg) { + path = concatenate3_strings(permanent_allocator(), path, STR_LIT("-"), m->pkg->name); + } + path = concatenate_strings(permanent_allocator(), path, STR_LIT(".ll")); + + return path; +} +String lb_filepath_obj_for_module(lbModule *m) { + String path = m->gen->output_base; + if (m->pkg) { + path = concatenate3_strings(permanent_allocator(), path, STR_LIT("-"), m->pkg->name); + } + + String ext = {}; + + if (build_context.build_mode == BuildMode_Assembly) { + ext = STR_LIT(".S"); + } else { + switch (build_context.metrics.os) { + case TargetOs_windows: + ext = STR_LIT(".obj"); + break; + case TargetOs_darwin: + case TargetOs_linux: + case TargetOs_essence: + ext = STR_LIT(".o"); + break; + case TargetOs_js: + ext = STR_LIT(".wasm-obj"); + break; + } + } + + return concatenate_strings(permanent_allocator(), path, ext); +} + void lb_generate_code(lbGenerator *gen) { #define TIME_SECTION(str) do { if (build_context.show_more_timings) timings_start_section(&global_timings, str_lit(str)); } while (0) TIME_SECTION("LLVM Initializtion"); - lbModule *m = &gen->default_module; + lbModule *default_module = &gen->default_module; CheckerInfo *info = gen->info; auto *min_dep_set = &info->minimum_dependency_set; @@ -14183,62 +14299,67 @@ void lb_generate_code(lbGenerator *gen) { LLVMSetModuleDataLayout(gen->modules.entries[i].value->mod, LLVMCreateTargetDataLayout(target_machine)); } - if (m->debug_builder) { // Debug Info - for_array(i, info->files.entries) { - AstFile *f = info->files.entries[i].value; - String fullpath = f->fullpath; - String filename = remove_directory_from_path(fullpath); - String directory = directory_from_path(fullpath); - LLVMMetadataRef res = LLVMDIBuilderCreateFile(m->debug_builder, - cast(char const *)filename.text, filename.len, - cast(char const *)directory.text, directory.len); - lb_set_llvm_metadata(m, f, res); - } - - gbString producer = gb_string_make(heap_allocator(), "odin"); - // producer = gb_string_append_fmt(producer, " version %.*s", LIT(ODIN_VERSION)); - // #ifdef NIGHTLY - // producer = gb_string_appendc(producer, "-nightly"); - // #endif - // #ifdef GIT_SHA - // producer = gb_string_append_fmt(producer, "-%s", GIT_SHA); - // #endif - - gbString split_name = gb_string_make(heap_allocator(), ""); - - LLVMBool is_optimized = build_context.optimization_level > 0; - AstFile *init_file = m->info->init_package->files[0]; - if (m->info->entry_point && m->info->entry_point->identifier && m->info->entry_point->identifier->file) { - init_file = m->info->entry_point->identifier->file; - } - - LLVMBool split_debug_inlining = false; - LLVMBool debug_info_for_profiling = false; - - m->debug_compile_unit = LLVMDIBuilderCreateCompileUnit(m->debug_builder, LLVMDWARFSourceLanguageC99, - lb_get_llvm_metadata(m, init_file), - producer, gb_string_length(producer), - is_optimized, "", 0, - 1, split_name, gb_string_length(split_name), - LLVMDWARFEmissionFull, - 0, split_debug_inlining, - debug_info_for_profiling, - "", 0, // sys_root - "", 0 // SDK - ); - GB_ASSERT(m->debug_compile_unit != nullptr); + for_array(i, gen->modules.entries) { + lbModule *m = gen->modules.entries[i].value; + if (m->debug_builder) { // Debug Info + for_array(i, info->files.entries) { + AstFile *f = info->files.entries[i].value; + String fullpath = f->fullpath; + String filename = remove_directory_from_path(fullpath); + String directory = directory_from_path(fullpath); + LLVMMetadataRef res = LLVMDIBuilderCreateFile(m->debug_builder, + cast(char const *)filename.text, filename.len, + cast(char const *)directory.text, directory.len); + lb_set_llvm_metadata(m, f, res); + } + + gbString producer = gb_string_make(heap_allocator(), "odin"); + // producer = gb_string_append_fmt(producer, " version %.*s", LIT(ODIN_VERSION)); + // #ifdef NIGHTLY + // producer = gb_string_appendc(producer, "-nightly"); + // #endif + // #ifdef GIT_SHA + // producer = gb_string_append_fmt(producer, "-%s", GIT_SHA); + // #endif + + gbString split_name = gb_string_make(heap_allocator(), ""); + + LLVMBool is_optimized = build_context.optimization_level > 0; + AstFile *init_file = m->info->init_package->files[0]; + if (m->info->entry_point && m->info->entry_point->identifier && m->info->entry_point->identifier->file) { + init_file = m->info->entry_point->identifier->file; + } + + LLVMBool split_debug_inlining = false; + LLVMBool debug_info_for_profiling = false; + + m->debug_compile_unit = LLVMDIBuilderCreateCompileUnit(m->debug_builder, LLVMDWARFSourceLanguageC99, + lb_get_llvm_metadata(m, init_file), + producer, gb_string_length(producer), + is_optimized, "", 0, + 1, split_name, gb_string_length(split_name), + LLVMDWARFEmissionFull, + 0, split_debug_inlining, + debug_info_for_profiling, + "", 0, // sys_root + "", 0 // SDK + ); + GB_ASSERT(m->debug_compile_unit != nullptr); + } } TIME_SECTION("LLVM Global Variables"); { + lbModule *m = default_module; + { // Add type info data isize max_type_info_count = info->minimum_dependency_type_info_set.entries.count+1; // gb_printf_err("max_type_info_count: %td\n", max_type_info_count); Type *t = alloc_type_array(t_type_info, max_type_info_count); LLVMValueRef g = LLVMAddGlobal(m->mod, lb_type(m, t), LB_TYPE_INFO_DATA_NAME); LLVMSetInitializer(g, LLVMConstNull(lb_type(m, t))); - LLVMSetLinkage(g, LLVMInternalLinkage); + // LLVMSetLinkage(g, LLVMInternalLinkage); lbValue value = {}; value.value = g; @@ -14276,7 +14397,7 @@ void lb_generate_code(lbGenerator *gen) { Type *t = alloc_type_array(t_type_info_ptr, count); LLVMValueRef g = LLVMAddGlobal(m->mod, lb_type(m, t), name); LLVMSetInitializer(g, LLVMConstNull(lb_type(m, t))); - LLVMSetLinkage(g, LLVMInternalLinkage); + // LLVMSetLinkage(g, LLVMInternalLinkage); lb_global_type_info_member_types = lb_addr({g, alloc_type_pointer(t)}); } @@ -14285,7 +14406,7 @@ void lb_generate_code(lbGenerator *gen) { Type *t = alloc_type_array(t_string, count); LLVMValueRef g = LLVMAddGlobal(m->mod, lb_type(m, t), name); LLVMSetInitializer(g, LLVMConstNull(lb_type(m, t))); - LLVMSetLinkage(g, LLVMInternalLinkage); + // LLVMSetLinkage(g, LLVMInternalLinkage); lb_global_type_info_member_names = lb_addr({g, alloc_type_pointer(t)}); } { @@ -14293,7 +14414,7 @@ void lb_generate_code(lbGenerator *gen) { Type *t = alloc_type_array(t_uintptr, count); LLVMValueRef g = LLVMAddGlobal(m->mod, lb_type(m, t), name); LLVMSetInitializer(g, LLVMConstNull(lb_type(m, t))); - LLVMSetLinkage(g, LLVMInternalLinkage); + // LLVMSetLinkage(g, LLVMInternalLinkage); lb_global_type_info_member_offsets = lb_addr({g, alloc_type_pointer(t)}); } @@ -14302,7 +14423,7 @@ void lb_generate_code(lbGenerator *gen) { Type *t = alloc_type_array(t_bool, count); LLVMValueRef g = LLVMAddGlobal(m->mod, lb_type(m, t), name); LLVMSetInitializer(g, LLVMConstNull(lb_type(m, t))); - LLVMSetLinkage(g, LLVMInternalLinkage); + // LLVMSetLinkage(g, LLVMInternalLinkage); lb_global_type_info_member_usings = lb_addr({g, alloc_type_pointer(t)}); } @@ -14311,7 +14432,7 @@ void lb_generate_code(lbGenerator *gen) { Type *t = alloc_type_array(t_string, count); LLVMValueRef g = LLVMAddGlobal(m->mod, lb_type(m, t), name); LLVMSetInitializer(g, LLVMConstNull(lb_type(m, t))); - LLVMSetLinkage(g, LLVMInternalLinkage); + // LLVMSetLinkage(g, LLVMInternalLinkage); lb_global_type_info_member_tags = lb_addr({g, alloc_type_pointer(t)}); } } @@ -14373,8 +14494,9 @@ void lb_generate_code(lbGenerator *gen) { bool is_foreign = e->Variable.is_foreign; bool is_export = e->Variable.is_export; - String name = lb_get_entity_name(m, e); + lbModule *m = &gen->default_module; + String name = lb_get_entity_name(m, e); lbValue g = {}; g.value = LLVMAddGlobal(m->mod, lb_type(m, e->type), alloc_cstring(permanent_allocator(), name)); @@ -14409,7 +14531,7 @@ void lb_generate_code(lbGenerator *gen) { } if (e->flags & EntityFlag_Static) { - LLVMSetLinkage(g.value, LLVMInternalLinkage); + // LLVMSetLinkage(g.value, LLVMInternalLinkage); } lbGlobalVariable var = {}; @@ -14439,6 +14561,7 @@ void lb_generate_code(lbGenerator *gen) { lb_add_entity(m, e, g); lb_add_member(m, name, g); + if (m->debug_builder) { String global_name = e->token.string; if (global_name.len != 0 && global_name != "_") { @@ -14509,6 +14632,10 @@ void lb_generate_code(lbGenerator *gen) { continue; } + lbModule *m = &gen->default_module; + if (USE_SEPARTE_MODULES) { + m = lb_pkg_module(gen, e->pkg); + } String mangled_name = lb_get_entity_name(m, e); @@ -14526,108 +14653,70 @@ void lb_generate_code(lbGenerator *gen) { } - TIME_SECTION("LLVM Registry Initializtion"); - - LLVMPassRegistryRef pass_registry = LLVMGetGlobalPassRegistry(); - - LLVMPassManagerRef default_function_pass_manager = LLVMCreateFunctionPassManagerForModule(m->mod); - LLVMPassManagerRef function_pass_manager_minimal = LLVMCreateFunctionPassManagerForModule(m->mod); - LLVMPassManagerRef function_pass_manager_size = LLVMCreateFunctionPassManagerForModule(m->mod); - LLVMPassManagerRef function_pass_manager_speed = LLVMCreateFunctionPassManagerForModule(m->mod); - defer (LLVMDisposePassManager(default_function_pass_manager)); - defer (LLVMDisposePassManager(function_pass_manager_minimal)); - defer (LLVMDisposePassManager(function_pass_manager_size)); - defer (LLVMDisposePassManager(function_pass_manager_speed)); - - LLVMInitializeFunctionPassManager(default_function_pass_manager); - LLVMInitializeFunctionPassManager(function_pass_manager_minimal); - LLVMInitializeFunctionPassManager(function_pass_manager_size); - LLVMInitializeFunctionPassManager(function_pass_manager_speed); - - lb_populate_function_pass_manager(default_function_pass_manager, false, build_context.optimization_level); - lb_populate_function_pass_manager_specific(function_pass_manager_minimal, 0); - lb_populate_function_pass_manager_specific(function_pass_manager_size, 1); - lb_populate_function_pass_manager_specific(function_pass_manager_speed, 2); - - LLVMFinalizeFunctionPassManager(default_function_pass_manager); - LLVMFinalizeFunctionPassManager(function_pass_manager_minimal); - LLVMFinalizeFunctionPassManager(function_pass_manager_size); - LLVMFinalizeFunctionPassManager(function_pass_manager_speed); - - - LLVMPassManagerRef default_function_pass_manager_without_memcpy = LLVMCreateFunctionPassManagerForModule(m->mod); - defer (LLVMDisposePassManager(default_function_pass_manager_without_memcpy)); - LLVMInitializeFunctionPassManager(default_function_pass_manager_without_memcpy); - lb_populate_function_pass_manager(default_function_pass_manager_without_memcpy, true, build_context.optimization_level); - LLVMFinalizeFunctionPassManager(default_function_pass_manager_without_memcpy); - TIME_SECTION("LLVM Runtime Type Information Creation"); - lbProcedure *startup_type_info = lb_create_startup_type_info(m); + lbProcedure *startup_type_info = lb_create_startup_type_info(default_module); TIME_SECTION("LLVM Runtime Startup Creation (Global Variables)"); - lbProcedure *startup_runtime = lb_create_startup_runtime(m, startup_type_info, global_variables); - + lbProcedure *startup_runtime = lb_create_startup_runtime(default_module, startup_type_info, global_variables); - String filepath_ll = concatenate_strings(permanent_allocator(), gen->output_base, STR_LIT(".ll")); TIME_SECTION("LLVM Procedure Generation"); - for_array(i, m->procedures_to_generate) { - lbProcedure *p = m->procedures_to_generate[i]; - if (p->is_done) { - continue; - } - if (p->body != nullptr) { // Build Procedure - m->curr_procedure = p; - lb_begin_procedure_body(p); - lb_build_stmt(p, p->body); - lb_end_procedure_body(p); - p->is_done = true; - m->curr_procedure = nullptr; - } - lb_end_procedure(p); - - // Add Flags - if (p->body != nullptr) { - if (p->name == "memcpy" || p->name == "memmove" || - p->name == "runtime.mem_copy" || p->name == "mem_copy_non_overlapping" || - string_starts_with(p->name, str_lit("llvm.memcpy")) || - string_starts_with(p->name, str_lit("llvm.memmove"))) { - p->flags |= lbProcedureFlag_WithoutMemcpyPass; + for_array(j, gen->modules.entries) { + lbModule *m = gen->modules.entries[j].value; + for_array(i, m->procedures_to_generate) { + lbProcedure *p = m->procedures_to_generate[i]; + if (p->is_done) { + continue; } - } - - if (!m->debug_builder && LLVMVerifyFunction(p->value, LLVMReturnStatusAction)) { - gb_printf_err("LLVM CODE GEN FAILED FOR PROCEDURE: %.*s\n", LIT(p->name)); - LLVMDumpValue(p->value); - gb_printf_err("\n\n\n\n"); - if (LLVMPrintModuleToFile(m->mod, cast(char const *)filepath_ll.text, &llvm_error)) { - gb_printf_err("LLVM Error: %s\n", llvm_error); + if (p->body != nullptr) { // Build Procedure + m->curr_procedure = p; + lb_begin_procedure_body(p); + lb_build_stmt(p, p->body); + lb_end_procedure_body(p); + p->is_done = true; + m->curr_procedure = nullptr; + } + lb_end_procedure(p); + + // Add Flags + if (p->body != nullptr) { + if (p->name == "memcpy" || p->name == "memmove" || + p->name == "runtime.mem_copy" || p->name == "mem_copy_non_overlapping" || + string_starts_with(p->name, str_lit("llvm.memcpy")) || + string_starts_with(p->name, str_lit("llvm.memmove"))) { + p->flags |= lbProcedureFlag_WithoutMemcpyPass; + } + } + + if (!m->debug_builder && LLVMVerifyFunction(p->value, LLVMReturnStatusAction)) { + gb_printf_err("LLVM CODE GEN FAILED FOR PROCEDURE: %.*s\n", LIT(p->name)); + LLVMDumpValue(p->value); + gb_printf_err("\n\n\n\n"); + String filepath_ll = lb_filepath_ll_for_module(m); + if (LLVMPrintModuleToFile(m->mod, cast(char const *)filepath_ll.text, &llvm_error)) { + gb_printf_err("LLVM Error: %s\n", llvm_error); + } + LLVMVerifyFunction(p->value, LLVMPrintMessageAction); + gb_exit(1); } - LLVMVerifyFunction(p->value, LLVMPrintMessageAction); - gb_exit(1); } } if (!(build_context.build_mode == BuildMode_DynamicLibrary && !has_dll_main)) { TIME_SECTION("LLVM main"); - lb_create_main_procedure(m, startup_runtime); + lb_create_main_procedure(default_module, startup_runtime); } - - if (m->debug_builder != nullptr) { - TIME_SECTION("LLVM Debug Info Complete Types"); - lb_debug_complete_types(m); - - - TIME_SECTION("LLVM Print Module to File"); - if (LLVMPrintModuleToFile(m->mod, cast(char const *)filepath_ll.text, &llvm_error)) { - gb_printf_err("LLVM Error: %s\n", llvm_error); - gb_exit(1); - return; + if (build_context.ODIN_DEBUG) { + TIME_SECTION("LLVM Debug Info Complete Types and Finalize"); + for_array(j, gen->modules.entries) { + lbModule *m = gen->modules.entries[j].value; + if (m->debug_builder != nullptr) { + lb_debug_complete_types(m); + LLVMDIBuilderFinalize(m->debug_builder); + } } - TIME_SECTION("LLVM Debug Info Builder Finalize"); - LLVMDIBuilderFinalize(m->debug_builder); } @@ -14635,6 +14724,38 @@ void lb_generate_code(lbGenerator *gen) { for_array(i, gen->modules.entries) { lbModule *m = gen->modules.entries[i].value; + LLVMPassManagerRef default_function_pass_manager = LLVMCreateFunctionPassManagerForModule(m->mod); + LLVMPassManagerRef function_pass_manager_minimal = LLVMCreateFunctionPassManagerForModule(m->mod); + LLVMPassManagerRef function_pass_manager_size = LLVMCreateFunctionPassManagerForModule(m->mod); + LLVMPassManagerRef function_pass_manager_speed = LLVMCreateFunctionPassManagerForModule(m->mod); + defer (LLVMDisposePassManager(default_function_pass_manager)); + defer (LLVMDisposePassManager(function_pass_manager_minimal)); + defer (LLVMDisposePassManager(function_pass_manager_size)); + defer (LLVMDisposePassManager(function_pass_manager_speed)); + + LLVMInitializeFunctionPassManager(default_function_pass_manager); + LLVMInitializeFunctionPassManager(function_pass_manager_minimal); + LLVMInitializeFunctionPassManager(function_pass_manager_size); + LLVMInitializeFunctionPassManager(function_pass_manager_speed); + + lb_populate_function_pass_manager(default_function_pass_manager, false, build_context.optimization_level); + lb_populate_function_pass_manager_specific(function_pass_manager_minimal, 0); + lb_populate_function_pass_manager_specific(function_pass_manager_size, 1); + lb_populate_function_pass_manager_specific(function_pass_manager_speed, 2); + + LLVMFinalizeFunctionPassManager(default_function_pass_manager); + LLVMFinalizeFunctionPassManager(function_pass_manager_minimal); + LLVMFinalizeFunctionPassManager(function_pass_manager_size); + LLVMFinalizeFunctionPassManager(function_pass_manager_speed); + + + LLVMPassManagerRef default_function_pass_manager_without_memcpy = LLVMCreateFunctionPassManagerForModule(m->mod); + defer (LLVMDisposePassManager(default_function_pass_manager_without_memcpy)); + LLVMInitializeFunctionPassManager(default_function_pass_manager_without_memcpy); + lb_populate_function_pass_manager(default_function_pass_manager_without_memcpy, true, build_context.optimization_level); + LLVMFinalizeFunctionPassManager(default_function_pass_manager_without_memcpy); + + for_array(i, m->procedures_to_generate) { lbProcedure *p = m->procedures_to_generate[i]; if (p->body != nullptr) { // Build Procedure @@ -14688,49 +14809,41 @@ void lb_generate_code(lbGenerator *gen) { llvm_error = nullptr; defer (LLVMDisposeMessage(llvm_error)); - String filepath_obj = {}; LLVMCodeGenFileType code_gen_file_type = LLVMObjectFile; - if (build_context.build_mode == BuildMode_Assembly) { - filepath_obj = concatenate_strings(permanent_allocator(), gen->output_base, STR_LIT(".S")); code_gen_file_type = LLVMAssemblyFile; - } else { - switch (build_context.metrics.os) { - case TargetOs_windows: - filepath_obj = concatenate_strings(permanent_allocator(), gen->output_base, STR_LIT(".obj")); - break; - case TargetOs_darwin: - case TargetOs_linux: - case TargetOs_essence: - filepath_obj = concatenate_strings(permanent_allocator(), gen->output_base, STR_LIT(".o")); - break; - case TargetOs_js: - filepath_obj = concatenate_strings(permanent_allocator(), gen->output_base, STR_LIT(".wasm-obj")); - break; - } } - if (LLVMVerifyModule(m->mod, LLVMReturnStatusAction, &llvm_error)) { - gb_printf_err("LLVM Error:\n%s\n", llvm_error); - if (build_context.keep_temp_files) { - TIME_SECTION("LLVM Print Module to File"); - if (LLVMPrintModuleToFile(m->mod, cast(char const *)filepath_ll.text, &llvm_error)) { - gb_printf_err("LLVM Error: %s\n", llvm_error); - gb_exit(1); - return; + for_array(j, gen->modules.entries) { + lbModule *m = gen->modules.entries[j].value; + if (LLVMVerifyModule(m->mod, LLVMReturnStatusAction, &llvm_error)) { + gb_printf_err("LLVM Error:\n%s\n", llvm_error); + if (build_context.keep_temp_files) { + TIME_SECTION("LLVM Print Module to File"); + String filepath_ll = lb_filepath_ll_for_module(m); + if (LLVMPrintModuleToFile(m->mod, cast(char const *)filepath_ll.text, &llvm_error)) { + gb_printf_err("LLVM Error: %s\n", llvm_error); + gb_exit(1); + return; + } } + gb_exit(1); + return; } - gb_exit(1); - return; } llvm_error = nullptr; if (build_context.keep_temp_files || build_context.build_mode == BuildMode_LLVM_IR) { TIME_SECTION("LLVM Print Module to File"); - if (LLVMPrintModuleToFile(m->mod, cast(char const *)filepath_ll.text, &llvm_error)) { - gb_printf_err("LLVM Error: %s\n", llvm_error); - gb_exit(1); - return; + + for_array(j, gen->modules.entries) { + lbModule *m = gen->modules.entries[j].value; + String filepath_ll = lb_filepath_ll_for_module(m); + if (LLVMPrintModuleToFile(m->mod, cast(char const *)filepath_ll.text, &llvm_error)) { + gb_printf_err("LLVM Error: %s\n", llvm_error); + gb_exit(1); + return; + } } if (build_context.build_mode == BuildMode_LLVM_IR) { gb_exit(0); @@ -14740,18 +14853,25 @@ void lb_generate_code(lbGenerator *gen) { TIME_SECTION("LLVM Object Generation"); - if (LLVMTargetMachineEmitToFile(target_machine, m->mod, cast(char *)filepath_obj.text, code_gen_file_type, &llvm_error)) { - gb_printf_err("LLVM Error: %s\n", llvm_error); - gb_exit(1); - return; - } + for_array(j, gen->modules.entries) { + lbModule *m = gen->modules.entries[j].value; + String filepath_obj = lb_filepath_obj_for_module(m); - array_add(&gen->output_object_paths, filepath_obj); + if (LLVMTargetMachineEmitToFile(target_machine, m->mod, cast(char *)filepath_obj.text, code_gen_file_type, &llvm_error)) { + gb_printf_err("LLVM Error: %s\n", llvm_error); + gb_exit(1); + return; + } - for_array(i, m->info->required_foreign_imports_through_force) { - Entity *e = m->info->required_foreign_imports_through_force[i]; - lb_add_foreign_library_path(m, e); + array_add(&gen->output_object_paths, filepath_obj); + for_array(i, m->info->required_foreign_imports_through_force) { + Entity *e = m->info->required_foreign_imports_through_force[i]; + lb_add_foreign_library_path(m, e); + } } + + + #undef TIME_SECTION } diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index 392c15ea4..8a4f06117 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -85,6 +85,8 @@ struct lbModule { LLVMModuleRef mod; LLVMContextRef ctx; + struct lbGenerator *gen; + CheckerInfo *info; AstPackage *pkg; // associated @@ -108,8 +110,6 @@ struct lbModule { Map equal_procs; // Key: Type * Map hasher_procs; // Key: Type * - u32 global_array_index; - u32 global_generated_index; u32 nested_type_name_guid; Array procedures_to_generate; @@ -131,7 +131,11 @@ struct lbGenerator { String output_base; String output_name; Map modules; // Key: AstPackage * + Map modules_through_ctx; // Key: LLVMContextRef * lbModule default_module; + + gbAtomic32 global_array_index; + gbAtomic32 global_generated_index; }; @@ -271,7 +275,7 @@ String lb_get_entity_name(lbModule *m, Entity *e, String name = {}); LLVMAttributeRef lb_create_enum_attribute(LLVMContextRef ctx, char const *name, u64 value=0); void lb_add_proc_attribute_at_index(lbProcedure *p, isize index, char const *name, u64 value); void lb_add_proc_attribute_at_index(lbProcedure *p, isize index, char const *name); -lbProcedure *lb_create_procedure(lbModule *module, Entity *entity); +lbProcedure *lb_create_procedure(lbModule *module, Entity *entity, bool ignore_body=false); void lb_end_procedure(lbProcedure *p); @@ -383,6 +387,7 @@ lbValue lb_gen_map_hash(lbProcedure *p, lbValue key, Type *key_type); void lb_insert_dynamic_map_key_and_value(lbProcedure *p, lbAddr addr, Type *map_type, lbValue map_key, lbValue map_value, Ast *node); + void lb_store_type_case_implicit(lbProcedure *p, Ast *clause, lbValue value); lbAddr lb_store_range_stmt_val(lbProcedure *p, Ast *stmt_val, lbValue value); lbValue lb_emit_source_code_location(lbProcedure *p, String const &procedure, TokenPos const &pos); diff --git a/src/main.cpp b/src/main.cpp index 48fb4dcc3..530492cbb 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1542,12 +1542,19 @@ void show_timings(Checker *c, Timings *t) { } } -void remove_temp_files(String output_base) { +void remove_temp_files(lbGenerator *gen) { if (build_context.keep_temp_files) return; + String output_base = gen->output_base; + auto data = array_make(heap_allocator(), output_base.len + 30); defer (array_free(&data)); + for_array(i, gen->output_object_paths) { + String path = gen->output_object_paths[i]; + gb_file_remove(cast(char const *)path.text); + } + isize n = output_base.len; gb_memmove(data.data, output_base.text, n); #define EXT_REMOVE(s) do { \ @@ -2183,7 +2190,7 @@ int main(int arg_count, char const **arg_ptr) { show_timings(&checker, timings); } - remove_temp_files(gen.output_base); + remove_temp_files(&gen); if (run_output) { #if defined(GB_SYSTEM_WINDOWS) -- cgit v1.2.3 From dfe1dedeb1f948bebd6121e3cc31fcd4562ab0cd Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 3 May 2021 19:39:36 +0100 Subject: Experimental support for `-use-separate-modules` --- src/build_settings.cpp | 4 ---- src/llvm_backend.cpp | 56 ++++++++++++++++++++++++++++++++++++++++++-------- src/llvm_backend.hpp | 1 + src/main.cpp | 42 ++++++++++++++++--------------------- 4 files changed, 66 insertions(+), 37 deletions(-) (limited to 'src/build_settings.cpp') diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 77046cf6d..09d860cfc 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -809,10 +809,6 @@ void init_build_context(TargetMetrics *cross_target) { bc->max_align = metrics->max_align; bc->link_flags = str_lit(" "); - if (bc->metrics.os == TargetOs_windows) { - // bc->use_separate_modules = bc->optimization_level == 0; - } - // NOTE(zangent): The linker flags to set the build architecture are different // across OSs. It doesn't make sense to allocate extra data on the heap diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 9649af6c9..2acbbcff8 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -2721,6 +2721,7 @@ lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool ignore_body) if (ignore_body) { p->body = nullptr; + LLVMSetLinkage(p->value, LLVMExternalLinkage); } @@ -5762,7 +5763,7 @@ lbValue lb_find_value_from_entity(lbModule *m, Entity *e) { lbValue g = {}; g.value = LLVMAddGlobal(m->mod, lb_type(m, e->type), alloc_cstring(permanent_allocator(), name)); g.type = alloc_type_pointer(e->type); - LLVMSetExternallyInitialized(g.value, true); + LLVMSetLinkage(g.value, LLVMExternalLinkage); lb_add_entity(m, e, g); lb_add_member(m, name, g); @@ -11179,15 +11180,19 @@ lbValue lb_find_ident(lbProcedure *p, lbModule *m, Entity *e, Ast *expr) { return lb_addr_load(p, lb_build_addr(p, expr)); } + if (e->kind == Entity_Procedure) { + return lb_find_procedure_value_from_entity(m, e); + } if (USE_SEPARTE_MODULES) { lbModule *other_module = lb_pkg_module(m->gen, e->pkg); if (other_module != m) { + String name = lb_get_entity_name(other_module, e); lbValue g = {}; g.value = LLVMAddGlobal(m->mod, lb_type(m, e->type), alloc_cstring(permanent_allocator(), name)); g.type = alloc_type_pointer(e->type); - LLVMSetExternallyInitialized(g.value, true); + LLVMSetLinkage(g.value, LLVMExternalLinkage); lb_add_entity(m, e, g); lb_add_member(m, name, g); @@ -12995,13 +13000,15 @@ lbAddr lb_build_addr(lbProcedure *p, Ast *expr) { void lb_init_module(lbModule *m, Checker *c) { m->info = &c->info; - gbString module_name = nullptr; + gbString module_name = gb_string_make(heap_allocator(), "odin_package-"); if (m->pkg) { - module_name = gb_string_make(heap_allocator(), "odin_package-"); module_name = gb_string_append_length(module_name, m->pkg->name.text, m->pkg->name.len); + } else if (USE_SEPARTE_MODULES) { + module_name = gb_string_appendc(module_name, "builtin"); + } else { + module_name = "odin_package"; } - m->ctx = LLVMContextCreate(); m->mod = LLVMModuleCreateWithNameInContext(module_name ? module_name : "odin_package", m->ctx); // m->debug_builder = nullptr; @@ -13089,6 +13096,7 @@ bool lb_init_generator(lbGenerator *gen, Checker *c) { } gbAllocator ha = heap_allocator(); array_init(&gen->output_object_paths, ha); + array_init(&gen->output_temp_paths, ha); gen->output_base = path_to_full_path(ha, gen->output_base); @@ -14110,8 +14118,20 @@ lbProcedure *lb_create_main_procedure(lbModule *m, lbProcedure *startup_runtime) lb_fill_slice(p, args, argv, argc); } + { + auto args = array_make(permanent_allocator(), 1); + args[0] = lb_const_string(p->module, str_lit("Here0\n")); + lb_emit_runtime_call(p, "print_string", args); + } + LLVMBuildCall2(p->builder, LLVMGetElementType(lb_type(m, startup_runtime->type)), startup_runtime->value, nullptr, 0, ""); + { + auto args = array_make(permanent_allocator(), 1); + args[0] = lb_const_string(p->module, str_lit("Here1\n")); + lb_emit_runtime_call(p, "print_string", args); + } + if (build_context.command_kind == Command_test) { Type *t_Internal_Test = find_type_in_pkg(m->info, str_lit("testing"), str_lit("Internal_Test")); Type *array_type = alloc_type_array(t_Internal_Test, m->info->testing_procedures.count); @@ -14189,6 +14209,8 @@ String lb_filepath_ll_for_module(lbModule *m) { String path = m->gen->output_base; if (m->pkg) { path = concatenate3_strings(permanent_allocator(), path, STR_LIT("-"), m->pkg->name); + } else if (USE_SEPARTE_MODULES) { + path = concatenate_strings(permanent_allocator(), path, STR_LIT("-builtin")); } path = concatenate_strings(permanent_allocator(), path, STR_LIT(".ll")); @@ -14522,6 +14544,7 @@ void lb_generate_code(lbGenerator *gen) { LLVMSetThreadLocalMode(g.value, mode); } if (is_foreign) { + LLVMSetLinkage(g.value, LLVMExternalLinkage); LLVMSetExternallyInitialized(g.value, true); lb_add_foreign_library_path(m, e->Variable.foreign_library); } else { @@ -14840,12 +14863,20 @@ void lb_generate_code(lbGenerator *gen) { for_array(j, gen->modules.entries) { lbModule *m = gen->modules.entries[j].value; + + if (LLVMGetFirstFunction(m->mod) == nullptr && + LLVMGetFirstGlobal(m->mod) == nullptr) { + continue; + } + String filepath_ll = lb_filepath_ll_for_module(m); if (LLVMPrintModuleToFile(m->mod, cast(char const *)filepath_ll.text, &llvm_error)) { gb_printf_err("LLVM Error: %s\n", llvm_error); gb_exit(1); return; } + array_add(&gen->output_temp_paths, filepath_ll); + } if (build_context.build_mode == BuildMode_LLVM_IR) { gb_exit(0); @@ -14857,6 +14888,16 @@ void lb_generate_code(lbGenerator *gen) { for_array(j, gen->modules.entries) { lbModule *m = gen->modules.entries[j].value; + for_array(i, m->info->required_foreign_imports_through_force) { + Entity *e = m->info->required_foreign_imports_through_force[i]; + lb_add_foreign_library_path(m, e); + } + + if (LLVMGetFirstFunction(m->mod) == nullptr && + LLVMGetFirstGlobal(m->mod) == nullptr) { + continue; + } + String filepath_obj = lb_filepath_obj_for_module(m); if (LLVMTargetMachineEmitToFile(target_machine, m->mod, cast(char *)filepath_obj.text, code_gen_file_type, &llvm_error)) { @@ -14866,10 +14907,7 @@ void lb_generate_code(lbGenerator *gen) { } array_add(&gen->output_object_paths, filepath_obj); - for_array(i, m->info->required_foreign_imports_through_force) { - Entity *e = m->info->required_foreign_imports_through_force[i]; - lb_add_foreign_library_path(m, e); - } + } diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index 8a4f06117..4338edbc7 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -128,6 +128,7 @@ struct lbGenerator { CheckerInfo *info; Array output_object_paths; + Array output_temp_paths; String output_base; String output_name; Map modules; // Key: AstPackage * diff --git a/src/main.cpp b/src/main.cpp index 530492cbb..19b22ef4f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -596,6 +596,7 @@ enum BuildFlagKind { BuildFlag_NoCRT, BuildFlag_NoEntryPoint, BuildFlag_UseLLD, + BuildFlag_UseSeparateModules, BuildFlag_Vet, BuildFlag_VetExtra, BuildFlag_UseLLVMApi, @@ -716,6 +717,7 @@ bool parse_build_flags(Array args) { add_flag(&build_flags, BuildFlag_NoCRT, str_lit("no-crt"), BuildFlagParam_None, Command__does_build); add_flag(&build_flags, BuildFlag_NoEntryPoint, str_lit("no-entry-point"), BuildFlagParam_None, Command__does_check &~ Command_test); add_flag(&build_flags, BuildFlag_UseLLD, str_lit("lld"), BuildFlagParam_None, Command__does_build); + add_flag(&build_flags, BuildFlag_UseSeparateModules,str_lit("use-separate-modules"),BuildFlagParam_None, Command__does_build); add_flag(&build_flags, BuildFlag_Vet, str_lit("vet"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_VetExtra, str_lit("vet-extra"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_UseLLVMApi, str_lit("llvm-api"), BuildFlagParam_None, Command__does_build); @@ -1195,6 +1197,10 @@ bool parse_build_flags(Array args) { build_context.use_lld = true; break; + case BuildFlag_UseSeparateModules: + build_context.use_separate_modules = true; + break; + case BuildFlag_Vet: build_context.vet = true; break; @@ -1545,35 +1551,17 @@ void show_timings(Checker *c, Timings *t) { void remove_temp_files(lbGenerator *gen) { if (build_context.keep_temp_files) return; - String output_base = gen->output_base; - - auto data = array_make(heap_allocator(), output_base.len + 30); - defer (array_free(&data)); - - for_array(i, gen->output_object_paths) { - String path = gen->output_object_paths[i]; + for_array(i, gen->output_temp_paths) { + String path = gen->output_temp_paths[i]; gb_file_remove(cast(char const *)path.text); } - isize n = output_base.len; - gb_memmove(data.data, output_base.text, n); -#define EXT_REMOVE(s) do { \ - gb_memmove(data.data+n, s, gb_size_of(s)); \ - gb_file_remove(cast(char const *)data.data); \ - } while (0) - EXT_REMOVE(".ll"); - EXT_REMOVE(".bc"); - EXT_REMOVE("_memcpy_pass.bc"); if (build_context.build_mode != BuildMode_Object && !build_context.keep_object_files) { - #if defined(GB_SYSTEM_WINDOWS) - EXT_REMOVE(".obj"); - EXT_REMOVE(".res"); - #else - EXT_REMOVE(".o"); - #endif + for_array(i, gen->output_object_paths) { + String path = gen->output_object_paths[i]; + gb_file_remove(cast(char const *)path.text); + } } - -#undef EXT_REMOVE } @@ -1734,6 +1722,12 @@ void print_show_help(String const arg0, String const &command) { print_usage_line(1, "-use-lld"); print_usage_line(2, "Use the LLD linker rather than the default"); print_usage_line(0, ""); + + print_usage_line(1, "-use-separate-modules"); + print_usage_line(2, "The backend generates multiple build units which are then linked together"); + print_usage_line(2, "Normally, a single build unit is generated for a standard project"); + print_usage_line(0, ""); + } if (check) { -- cgit v1.2.3 From 86dbcb1b20e7a5575013f2acbf0f48d194595d27 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 19 May 2021 12:57:30 +0100 Subject: Add `-verbose-errors` which shows the error in the line of code --- src/build_settings.cpp | 5 +++ src/main.cpp | 6 ++++ src/parser.cpp | 43 +++++++++++++++++++++++ src/tokenizer.cpp | 92 ++++++++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 144 insertions(+), 2 deletions(-) (limited to 'src/build_settings.cpp') diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 09d860cfc..0207221bc 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -200,8 +200,10 @@ struct BuildContext { bool disallow_do; bool insert_semicolon; + bool ignore_warnings; bool warnings_as_errors; + bool show_error_line; bool use_subsystem_windows; bool ignore_microsoft_magic; @@ -746,6 +748,9 @@ String get_fullpath_core(gbAllocator a, String path) { return path_to_fullpath(a, res); } +bool show_error_line(void) { + return build_context.show_error_line; +} void init_build_context(TargetMetrics *cross_target) { diff --git a/src/main.cpp b/src/main.cpp index 0dd1e0c27..d16a110e3 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -621,6 +621,7 @@ enum BuildFlagKind { BuildFlag_IgnoreWarnings, BuildFlag_WarningsAsErrors, + BuildFlag_VerboseErrors, #if defined(GB_SYSTEM_WINDOWS) BuildFlag_IgnoreVsSearch, @@ -741,6 +742,7 @@ bool parse_build_flags(Array args) { add_flag(&build_flags, BuildFlag_IgnoreWarnings, str_lit("ignore-warnings"), BuildFlagParam_None, Command_all); add_flag(&build_flags, BuildFlag_WarningsAsErrors, str_lit("warnings-as-errors"), BuildFlagParam_None, Command_all); + add_flag(&build_flags, BuildFlag_VerboseErrors, str_lit("verbose-errors"), BuildFlagParam_None, Command_all); #if defined(GB_SYSTEM_WINDOWS) add_flag(&build_flags, BuildFlag_IgnoreVsSearch, str_lit("ignore-vs-search"), BuildFlagParam_None, Command__does_build); @@ -1320,6 +1322,10 @@ bool parse_build_flags(Array args) { } break; + case BuildFlag_VerboseErrors: + build_context.show_error_line = true; + break; + #if defined(GB_SYSTEM_WINDOWS) case BuildFlag_IgnoreVsSearch: GB_ASSERT(value.kind == ExactValue_Invalid); diff --git a/src/parser.cpp b/src/parser.cpp index 2e27b8698..77ce7ea70 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -115,6 +115,48 @@ Token token_end_of_line(AstFile *f, Token tok) { return tok; } +gbString get_file_line_as_string(TokenPos const &pos, i32 *offset_) { + AstFile *file = get_ast_file_from_id(pos.file_id); + if (file == nullptr) { + return nullptr; + } + isize offset = pos.offset; + + u8 *start = file->tokenizer.start; + u8 *end = file->tokenizer.end; + isize len = end-start; + if (len < offset) { + return nullptr; + } + + u8 *pos_offset = start+offset; + + u8 *line_start = pos_offset; + u8 *line_end = pos_offset; + while (line_start >= start) { + if (*line_start == '\n') { + line_start += 1; + break; + } + line_start -= 1; + } + + while (line_end < end) { + if (*line_end == '\n') { + line_end -= 1; + break; + } + line_end += 1; + } + String the_line = make_string(line_start, line_end-line_start); + the_line = string_trim_whitespace(the_line); + + if (offset_) *offset_ = cast(i32)(pos_offset - the_line.text); + + return gb_string_make_length(heap_allocator(), the_line.text, the_line.len); +} + + isize ast_node_size(AstKind kind) { return align_formula_isize(gb_size_of(AstCommonStuff) + ast_variant_sizes[kind], gb_align_of(void *)); @@ -4602,6 +4644,7 @@ ParseFileError init_ast_file(AstFile *f, String fullpath, TokenPos *err_pos) { GB_ASSERT(f != nullptr); f->fullpath = string_trim_whitespace(fullpath); // Just in case set_file_path_string(f->id, fullpath); + set_ast_file_from_id(f->id, f); if (!string_ends_with(f->fullpath, str_lit(".odin"))) { return ParseFile_WrongExtension; } diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index d1310b56e..84d6ac9e2 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -188,9 +188,11 @@ void init_keyword_hash_table(void) { GB_ASSERT(max_keyword_size < 16); } -gb_global Array global_file_path_strings; // index is file id +gb_global Array global_file_path_strings; // index is file id +gb_global Array global_files; // index is file id -String get_file_path_string(i32 index); +String get_file_path_string(i32 index); +struct AstFile *get_ast_file_from_id(i32 index); struct TokenPos { i32 file_id; @@ -284,6 +286,7 @@ void init_global_error_collector(void) { array_init(&global_error_collector.errors, heap_allocator()); array_init(&global_error_collector.error_buffer, heap_allocator()); array_init(&global_file_path_strings, heap_allocator(), 4096); + array_init(&global_files, heap_allocator(), 4096); } @@ -305,6 +308,24 @@ bool set_file_path_string(i32 index, String const &path) { return ok; } +bool set_ast_file_from_id(i32 index, AstFile *file) { + bool ok = false; + GB_ASSERT(index >= 0); + gb_mutex_lock(&global_error_collector.string_mutex); + + if (index >= global_files.count) { + array_resize(&global_files, index); + } + AstFile *prev = global_files[index]; + if (prev == nullptr) { + global_files[index] = file; + ok = true; + } + + gb_mutex_unlock(&global_error_collector.string_mutex); + return ok; +} + String get_file_path_string(i32 index) { GB_ASSERT(index >= 0); gb_mutex_lock(&global_error_collector.string_mutex); @@ -318,6 +339,20 @@ String get_file_path_string(i32 index) { return path; } +AstFile *get_ast_file_from_id(i32 index) { + GB_ASSERT(index >= 0); + gb_mutex_lock(&global_error_collector.string_mutex); + + AstFile *file = nullptr; + if (index < global_files.count) { + file = global_files[index]; + } + + gb_mutex_unlock(&global_error_collector.string_mutex); + return file; +} + + void begin_error_block(void) { gb_mutex_lock(&global_error_collector.mutex); global_error_collector.in_block = true; @@ -377,6 +412,8 @@ ErrorOutProc *error_out_va = default_error_out_va; // NOTE: defined in build_settings.cpp bool global_warnings_as_errors(void); bool global_ignore_warnings(void); +bool show_error_line(void); +gbString get_file_line_as_string(TokenPos const &pos, i32 *offset); void error_out(char const *fmt, ...) { va_list va; @@ -386,6 +423,53 @@ void error_out(char const *fmt, ...) { } +bool show_error_on_line(TokenPos const &pos) { + if (!show_error_line()) { + return false; + } + + i32 offset = 0; + gbString the_line = get_file_line_as_string(pos, &offset); + defer (gb_string_free(the_line)); + + if (the_line != nullptr) { + String line = make_string(cast(u8 const *)the_line, gb_string_length(the_line)); + + enum { + MAX_LINE_LENGTH = 76, + MAX_TAB_WIDTH = 8, + ELLIPSIS_PADDING = 8 + }; + + error_out("\n\t"); + if (line.len+MAX_TAB_WIDTH+ELLIPSIS_PADDING > MAX_LINE_LENGTH) { + i32 const half_width = MAX_LINE_LENGTH/2; + i32 left = cast(i32)(offset); + i32 right = cast(i32)(line.len - offset); + left = gb_min(left, half_width); + right = gb_min(right, half_width); + + line.text += offset-left; + line.len -= offset+right-left; + + line = string_trim_whitespace(line); + + offset = left + ELLIPSIS_PADDING/2; + + error_out("... %.*s ...", LIT(line)); + } else { + error_out("%.*s", LIT(line)); + } + error_out("\n\t"); + + for (i32 i = 0; i < offset; i++) error_out(" "); + error_out("^\n"); + error_out("\n"); + return true; + } + return false; +} + void error_va(Token token, char const *fmt, va_list va) { gb_mutex_lock(&global_error_collector.mutex); global_error_collector.count++; @@ -397,6 +481,7 @@ void error_va(Token token, char const *fmt, va_list va) { error_out("%s %s\n", token_pos_to_string(token.pos), gb_bprintf_va(fmt, va)); + show_error_on_line(token.pos); } gb_mutex_unlock(&global_error_collector.mutex); if (global_error_collector.count > MAX_ERROR_COLLECTOR_COUNT) { @@ -420,6 +505,7 @@ void warning_va(Token token, char const *fmt, va_list va) { error_out("%s Warning: %s\n", token_pos_to_string(token.pos), gb_bprintf_va(fmt, va)); + show_error_on_line(token.pos); } } gb_mutex_unlock(&global_error_collector.mutex); @@ -460,6 +546,7 @@ void syntax_error_va(Token token, char const *fmt, va_list va) { error_out("%s Syntax Error: %s\n", token_pos_to_string(token.pos), gb_bprintf_va(fmt, va)); + show_error_on_line(token.pos); } else if (token.pos.line == 0) { error_out("Syntax Error: %s\n", gb_bprintf_va(fmt, va)); } @@ -484,6 +571,7 @@ void syntax_warning_va(Token token, char const *fmt, va_list va) { error_out("%s Syntax Warning: %s\n", token_pos_to_string(token.pos), gb_bprintf_va(fmt, va)); + show_error_on_line(token.pos); } else if (token.pos.line == 0) { error_out("Warning: %s\n", gb_bprintf_va(fmt, va)); } -- cgit v1.2.3