Begin work on making LLVM backend work with multiple modules for possible faster compilation

This commit is contained in:
gingerBill
2021-05-03 17:43:14 +01:00
parent e4286d0ff9
commit 746e880eb5
4 changed files with 416 additions and 278 deletions

View File

@@ -207,6 +207,8 @@ struct BuildContext {
bool ignore_microsoft_magic;
bool linker_map_file;
bool use_separate_modules;
u32 cmd_doc_flags;
Array<String> 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

View File

@@ -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<lbValue> 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<lbValue> 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<lbValue> 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<lbGlobalVariable> &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<lbGlobalVariable> &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);
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);
}
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);
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;
}
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);
}
}
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
}

View File

@@ -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<lbProcedure *> equal_procs; // Key: Type *
Map<lbProcedure *> hasher_procs; // Key: Type *
u32 global_array_index;
u32 global_generated_index;
u32 nested_type_name_guid;
Array<lbProcedure *> procedures_to_generate;
@@ -131,7 +131,11 @@ struct lbGenerator {
String output_base;
String output_name;
Map<lbModule *> modules; // Key: AstPackage *
Map<lbModule *> 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);

View File

@@ -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<u8>(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)