aboutsummaryrefslogtreecommitdiff
path: root/src/llvm_backend.cpp
diff options
context:
space:
mode:
authorMichael Lee <leecommamichael@gmail.com>2025-12-23 16:12:53 -0600
committerGitHub <noreply@github.com>2025-12-23 16:12:53 -0600
commit550e57aba977ff766e5ab38a4c13a8dc18d55992 (patch)
tree6704ea53d838f7d7427e5bf6faa1d586378869b3 /src/llvm_backend.cpp
parent729d0a8e8ace759d5d1358b14b20e19f68f44ff0 (diff)
parent57352d9933785097e21c282807f5e845ec8f6d85 (diff)
Merge branch 'odin-lang:master' into core-image-tga
Diffstat (limited to 'src/llvm_backend.cpp')
-rw-r--r--src/llvm_backend.cpp722
1 files changed, 453 insertions, 269 deletions
diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp
index ff17e9c10..1cde65640 100644
--- a/src/llvm_backend.cpp
+++ b/src/llvm_backend.cpp
@@ -8,9 +8,15 @@
#endif
#ifndef LLVM_IGNORE_VERIFICATION
-#define LLVM_IGNORE_VERIFICATION 0
+#define LLVM_IGNORE_VERIFICATION build_context.internal_ignore_llvm_verification
#endif
+#ifndef LLVM_WEAK_MONOMORPHIZATION
+#define LLVM_WEAK_MONOMORPHIZATION (USE_SEPARATE_MODULES && build_context.internal_weak_monomorphization)
+#endif
+
+#define LLVM_SET_INTERNAL_WEAK_LINKAGE(value) LLVMSetLinkage(value, USE_SEPARATE_MODULES ? LLVMWeakAnyLinkage : LLVMInternalLinkage);
+
#include "llvm_backend.hpp"
#include "llvm_abi.cpp"
@@ -33,12 +39,10 @@ gb_internal String get_default_microarchitecture() {
// x86-64-v2: (close to Nehalem) CMPXCHG16B, LAHF-SAHF, POPCNT, SSE3, SSE4.1, SSE4.2, SSSE3
// x86-64-v3: (close to Haswell) AVX, AVX2, BMI1, BMI2, F16C, FMA, LZCNT, MOVBE, XSAVE
// x86-64-v4: AVX512F, AVX512BW, AVX512CD, AVX512DQ, AVX512VL
- if (ODIN_LLVM_MINIMUM_VERSION_12) {
- if (build_context.metrics.os == TargetOs_freestanding) {
- default_march = str_lit("x86-64");
- } else {
- default_march = str_lit("x86-64-v2");
- }
+ if (build_context.metrics.os == TargetOs_freestanding) {
+ default_march = str_lit("x86-64");
+ } else {
+ default_march = str_lit("x86-64-v2");
}
} else if (build_context.metrics.arch == TargetArch_riscv64) {
default_march = str_lit("generic-rv64");
@@ -168,7 +172,7 @@ gb_internal void lb_correct_entity_linkage(lbGenerator *gen) {
if (ec.e->kind == Entity_Variable) {
other_global = LLVMGetNamedGlobal(ec.other_module->mod, ec.cname);
if (other_global) {
- LLVMSetLinkage(other_global, LLVMWeakAnyLinkage);
+ LLVM_SET_INTERNAL_WEAK_LINKAGE(other_global);
if (!ec.e->Variable.is_export && !ec.e->Variable.is_foreign) {
LLVMSetVisibility(other_global, LLVMHiddenVisibility);
}
@@ -176,7 +180,7 @@ gb_internal void lb_correct_entity_linkage(lbGenerator *gen) {
} else if (ec.e->kind == Entity_Procedure) {
other_global = LLVMGetNamedFunction(ec.other_module->mod, ec.cname);
if (other_global) {
- LLVMSetLinkage(other_global, LLVMWeakAnyLinkage);
+ LLVM_SET_INTERNAL_WEAK_LINKAGE(other_global);
if (!ec.e->Procedure.is_export && !ec.e->Procedure.is_foreign) {
LLVMSetVisibility(other_global, LLVMHiddenVisibility);
}
@@ -242,26 +246,12 @@ gb_internal String lb_internal_gen_name_from_type(char const *prefix, Type *type
return proc_name;
}
-
-gb_internal lbValue lb_equal_proc_for_type(lbModule *m, Type *type) {
- type = base_type(type);
- GB_ASSERT(is_type_comparable(type));
+gb_internal void lb_equal_proc_generate_body(lbModule *m, lbProcedure *p) {
+ Type *type = p->internal_gen_type;
Type *pt = alloc_type_pointer(type);
LLVMTypeRef ptr_type = lb_type(m, pt);
- String proc_name = lb_internal_gen_name_from_type("__$equal", type);
- lbProcedure **found = string_map_get(&m->gen_procs, proc_name);
- lbProcedure *compare_proc = nullptr;
- if (found) {
- compare_proc = *found;
- GB_ASSERT(compare_proc != nullptr);
- return {compare_proc->value, compare_proc->type};
- }
-
-
- lbProcedure *p = lb_create_dummy_procedure(m, proc_name, t_equal_proc);
- string_map_set(&m->gen_procs, proc_name, p);
lb_begin_procedure_body(p);
LLVMSetLinkage(p->value, LLVMInternalLinkage);
@@ -389,9 +379,29 @@ gb_internal lbValue lb_equal_proc_for_type(lbModule *m, Type *type) {
}
lb_end_procedure_body(p);
+}
- compare_proc = p;
- return {compare_proc->value, compare_proc->type};
+gb_internal lbValue lb_equal_proc_for_type(lbModule *m, Type *type) {
+ type = base_type(type);
+ GB_ASSERT(is_type_comparable(type));
+
+ String proc_name = lb_internal_gen_name_from_type("__$equal", type);
+ lbProcedure **found = string_map_get(&m->gen_procs, proc_name);
+ if (found) {
+ lbProcedure *p = *found;
+ GB_ASSERT(p != nullptr);
+ return {p->value, p->type};
+ }
+
+ lbProcedure *p = lb_create_dummy_procedure(m, proc_name, t_equal_proc);
+ string_map_set(&m->gen_procs, proc_name, p);
+ p->internal_gen_type = type;
+ p->generate_body = lb_equal_proc_generate_body;
+
+ // p->generate_body(m, p);
+ mpsc_enqueue(&m->procedures_to_generate, p);
+
+ return {p->value, p->type};
}
gb_internal lbValue lb_simple_compare_hash(lbProcedure *p, Type *type, lbValue data, lbValue seed) {
@@ -620,6 +630,7 @@ gb_internal lbValue lb_hasher_proc_for_type(lbModule *m, Type *type) {
#define LLVM_SET_VALUE_NAME(value, name) LLVMSetValueName2((value), (name), gb_count_of((name))-1);
+
gb_internal lbValue lb_map_get_proc_for_type(lbModule *m, Type *type) {
GB_ASSERT(!build_context.dynamic_map_calls);
type = base_type(type);
@@ -634,6 +645,9 @@ gb_internal lbValue lb_map_get_proc_for_type(lbModule *m, Type *type) {
lbProcedure *p = lb_create_dummy_procedure(m, proc_name, t_map_get_proc);
string_map_set(&m->gen_procs, proc_name, p);
+
+ p->internal_gen_type = type;
+
lb_begin_procedure_body(p);
defer (lb_end_procedure_body(p));
@@ -1153,15 +1167,6 @@ gb_internal lbValue lb_dynamic_map_reserve(lbProcedure *p, lbValue const &map_pt
return lb_emit_runtime_call(p, "__dynamic_map_reserve", args);
}
-
-struct lbGlobalVariable {
- lbValue var;
- lbValue init;
- DeclInfo *decl;
- bool is_initialized;
-};
-
-
gb_internal lbProcedure *lb_create_objc_names(lbModule *main_module) {
if (build_context.metrics.os != TargetOs_darwin) {
return nullptr;
@@ -1412,8 +1417,21 @@ String lb_get_objc_type_encoding(Type *t, isize pointer_depth = 0) {
return str_lit("?");
case Type_Proc:
return str_lit("?");
- case Type_BitSet:
- return lb_get_objc_type_encoding(t->BitSet.underlying, pointer_depth);
+ case Type_BitSet: {
+ Type *bitset_integer_type = t->BitSet.underlying;
+ if (!bitset_integer_type) {
+ switch (t->cached_size) {
+ case 1: bitset_integer_type = t_u8; break;
+ case 2: bitset_integer_type = t_u16; break;
+ case 4: bitset_integer_type = t_u32; break;
+ case 8: bitset_integer_type = t_u64; break;
+ case 16: bitset_integer_type = t_u128; break;
+ }
+ }
+ GB_ASSERT_MSG(bitset_integer_type, "Could not determine bit_set integer size for objc_type_encoding");
+
+ return lb_get_objc_type_encoding(bitset_integer_type, pointer_depth);
+ }
case Type_SimdVector: {
String type_str = lb_get_objc_type_encoding(t->SimdVector.elem, pointer_depth);
@@ -1447,7 +1465,10 @@ String lb_get_objc_type_encoding(Type *t, isize pointer_depth = 0) {
struct lbObjCGlobalClass {
lbObjCGlobal g;
- lbValue class_value; // Local registered class value
+ union {
+ lbValue class_value; // Local registered class value
+ lbAddr class_global; // Global class pointer. Placeholder for class implementations which are registered in order of definition.
+ };
};
gb_internal void lb_register_objc_thing(
@@ -1477,44 +1498,43 @@ gb_internal void lb_register_objc_thing(
LLVMSetInitializer(v.value, LLVMConstNull(t));
}
- lbValue class_ptr = {};
- lbValue class_name = lb_const_value(m, t_cstring, exact_value_string(g.name));
-
// If this class requires an implementation, save it for registration below.
if (g.class_impl_type != nullptr) {
// Make sure the superclass has been initialized before us
- lbValue superclass_value = lb_const_nil(m, t_objc_Class);
-
auto &tn = g.class_impl_type->Named.type_name->TypeName;
Type *superclass = tn.objc_superclass;
if (superclass != nullptr) {
auto& superclass_global = string_map_must_get(&class_map, superclass->Named.type_name->TypeName.objc_class_name);
lb_register_objc_thing(handled, m, args, class_impls, class_map, p, superclass_global.g, call);
- GB_ASSERT(superclass_global.class_value.value);
-
- superclass_value = superclass_global.class_value;
+ GB_ASSERT(superclass_global.class_global.addr.value);
}
- args.count = 3;
- args[0] = superclass_value;
- args[1] = class_name;
- args[2] = lb_const_int(m, t_uint, 0);
- class_ptr = lb_emit_runtime_call(p, "objc_allocateClassPair", args);
+ lbObjCGlobalClass impl_global = {};
+ impl_global.g = g;
+ impl_global.class_global = addr;
+
+ array_add(&class_impls, impl_global);
- array_add(&class_impls, lbObjCGlobalClass{g, class_ptr});
+ lbObjCGlobalClass* class_global = string_map_get(&class_map, g.name);
+ if (class_global != nullptr) {
+ class_global->class_global = addr;
+ }
}
else {
+ lbValue class_ptr = {};
+ lbValue class_name = lb_const_value(m, t_cstring, exact_value_string(g.name));
+
args.count = 1;
args[0] = class_name;
class_ptr = lb_emit_runtime_call(p, call, args);
- }
- lb_addr_store(p, addr, class_ptr);
+ lb_addr_store(p, addr, class_ptr);
- lbObjCGlobalClass* class_global = string_map_get(&class_map, g.name);
- if (class_global != nullptr) {
- class_global->class_value = class_ptr;
+ lbObjCGlobalClass* class_global = string_map_get(&class_map, g.name);
+ if (class_global != nullptr) {
+ class_global->class_value = class_ptr;
+ }
}
}
@@ -1577,7 +1597,7 @@ gb_internal void lb_finalize_objc_names(lbGenerator *gen, lbProcedure *p) {
string_map_init(&global_class_map, (usize)gen->objc_classes.count);
defer (string_map_destroy(&global_class_map));
- for (lbObjCGlobal g :referenced_classes) {
+ for (lbObjCGlobal g : referenced_classes) {
string_map_set(&global_class_map, g.name, lbObjCGlobalClass{g});
}
@@ -1624,9 +1644,36 @@ gb_internal void lb_finalize_objc_names(lbGenerator *gen, lbProcedure *p) {
for (const auto &cd : class_impls) {
auto &g = cd.g;
- Type *class_type = g.class_impl_type;
+
+ Type *class_type = g.class_impl_type;
Type *class_ptr_type = alloc_type_pointer(class_type);
- lbValue class_value = cd.class_value;
+
+ // Begin class registration: create class pair and update global reference
+ lbValue class_value = {};
+
+ {
+ lbValue superclass_value = lb_const_nil(m, t_objc_Class);
+
+ auto& tn = class_type->Named.type_name->TypeName;
+ Type *superclass = tn.objc_superclass;
+
+ if (superclass != nullptr) {
+ auto& superclass_global = string_map_must_get(&global_class_map, superclass->Named.type_name->TypeName.objc_class_name);
+ superclass_value = superclass_global.class_value;
+ }
+
+ args.count = 3;
+ args[0] = superclass_value;
+ args[1] = lb_const_value(m, t_cstring, exact_value_string(g.name));
+ args[2] = lb_const_int(m, t_uint, 0);
+ class_value = lb_emit_runtime_call(p, "objc_allocateClassPair", args);
+
+ lbObjCGlobalClass &mapped_global = string_map_must_get(&global_class_map, tn.objc_class_name);
+ lb_addr_store(p, mapped_global.class_global, class_value);
+
+ mapped_global.class_value = class_value;
+ }
+
Type *ivar_type = class_type->Named.type_name->TypeName.objc_ivar;
@@ -1646,7 +1693,6 @@ gb_internal void lb_finalize_objc_names(lbGenerator *gen, lbProcedure *p) {
is_context_provider_ivar = ivar_type != nullptr && internal_check_is_assignable_to(contex_provider_self_named_type, ivar_type);
}
-
Array<ObjcMethodData> *methods = map_get(&m->info->objc_method_implementations, class_type);
if (!methods) {
continue;
@@ -1705,17 +1751,21 @@ gb_internal void lb_finalize_objc_names(lbGenerator *gen, lbProcedure *p) {
wrapper_results_tuple, method_type->Proc.result_count, false, ProcCC_CDecl);
lbProcedure *wrapper_proc = lb_create_dummy_procedure(m, proc_name, wrapper_proc_type);
- lb_add_attribute_to_proc(wrapper_proc->module, wrapper_proc->value, "nounwind");
+
+ lb_add_function_type_attributes(wrapper_proc->value, lb_get_function_type(m, wrapper_proc_type), ProcCC_CDecl);
// Emit the wrapper
- LLVMSetLinkage(wrapper_proc->value, LLVMExternalLinkage);
+ // LLVMSetLinkage(wrapper_proc->value, LLVMInternalLinkage);
+ LLVMSetDLLStorageClass(wrapper_proc->value, LLVMDLLExportStorageClass);
+ lb_add_attribute_to_proc(wrapper_proc->module, wrapper_proc->value, "nounwind");
+
lb_begin_procedure_body(wrapper_proc);
{
+ LLVMValueRef context_addr = nullptr;
if (method_type->Proc.calling_convention == ProcCC_Odin) {
GB_ASSERT(context_provider);
// Emit the get odin context call
-
get_context_args[0] = lbValue {
wrapper_proc->raw_input_parameters[0],
contex_provider_self_ptr_type,
@@ -1731,44 +1781,58 @@ gb_internal void lb_finalize_objc_names(lbGenerator *gen, lbProcedure *p) {
get_context_args[0] = lb_handle_objc_ivar_for_objc_object_pointer(wrapper_proc, real_self);
}
- lbValue context = lb_emit_call(wrapper_proc, context_provider_proc_value, get_context_args);
- lbAddr context_addr = lb_addr(lb_address_from_load_or_generate_local(wrapper_proc, context));
- lb_push_context_onto_stack(wrapper_proc, context_addr);
+ lbValue context = lb_emit_call(wrapper_proc, context_provider_proc_value, get_context_args);
+ context_addr = lb_address_from_load(wrapper_proc, context).value;//lb_address_from_load_or_generate_local(wrapper_proc, context));
+ // context_addr = LLVMGetOperand(context.value, 0);
}
+ isize method_forward_arg_count = method_param_count + method_param_offset;
+ isize method_forward_return_arg_offset = 0;
+ auto raw_method_args = array_make<LLVMValueRef>(temporary_allocator(), 0, method_forward_arg_count+1);
+
+ lbValue method_proc_value = lb_find_procedure_value_from_entity(m, md.proc_entity);
+ lbFunctionType* ft = lb_get_function_type(m, method_type);
+ bool has_return = false;
+ lbArgKind return_kind = {};
- auto method_call_args = array_make<lbValue>(temporary_allocator(), method_param_count + method_param_offset);
+ if (wrapper_results_tuple != nullptr) {
+ has_return = true;
+ return_kind = ft->ret.kind;
+
+ if (return_kind == lbArg_Indirect) {
+ method_forward_return_arg_offset = 1;
+ array_add(&raw_method_args, wrapper_proc->return_ptr.addr.value);
+ }
+ }
if (!md.ac.objc_is_class_method) {
- method_call_args[0] = lbValue {
- wrapper_proc->raw_input_parameters[0],
- class_ptr_type,
- };
+ array_add(&raw_method_args, wrapper_proc->raw_input_parameters[method_forward_return_arg_offset]);
}
for (isize i = 0; i < method_param_count; i++) {
- method_call_args[i+method_param_offset] = lbValue {
- wrapper_proc->raw_input_parameters[i+2],
- method_type->Proc.params->Tuple.variables[i+method_param_offset]->type,
- };
+ array_add(&raw_method_args, wrapper_proc->raw_input_parameters[i+2+method_forward_return_arg_offset]);
+ }
+
+ if (method_type->Proc.calling_convention == ProcCC_Odin) {
+ array_add(&raw_method_args, context_addr);
}
- lbValue method_proc_value = lb_find_procedure_value_from_entity(m, md.proc_entity);
// Call real procedure for method from here, passing the parameters expected, if any.
- lbValue return_value = lb_emit_call(wrapper_proc, method_proc_value, method_call_args);
+ LLVMTypeRef fnp = lb_type_internal_for_procedures_raw(m, method_type);
+ LLVMValueRef ret_val_raw = LLVMBuildCall2(wrapper_proc->builder, fnp, method_proc_value.value, raw_method_args.data, (unsigned)raw_method_args.count, "");
- if (wrapper_results_tuple != nullptr) {
- auto &result_var = method_type->Proc.results->Tuple.variables[0];
- return_value = lb_emit_conv(wrapper_proc, return_value, result_var->type);
- lb_build_return_stmt_internal(wrapper_proc, return_value, result_var->token.pos);
+ if (has_return && return_kind != lbArg_Indirect) {
+ LLVMBuildRet(wrapper_proc->builder, ret_val_raw);
+ }
+ else {
+ LLVMBuildRetVoid(wrapper_proc->builder);
}
}
lb_end_procedure_body(wrapper_proc);
-
// Add the method to the class
String method_encoding = str_lit("v");
- // TODO (harold): Checker must ensure that objc_methods have a single return value or none!
+
GB_ASSERT(method_type->Proc.result_count <= 1);
if (method_type->Proc.result_count != 0) {
method_encoding = lb_get_objc_type_encoding(method_type->Proc.results->Tuple.variables[0]->type);
@@ -1780,8 +1844,8 @@ gb_internal void lb_finalize_objc_names(lbGenerator *gen, lbProcedure *p) {
method_encoding = concatenate_strings(temporary_allocator(), method_encoding, str_lit("#:"));
}
- for (isize i = method_param_offset; i < method_param_count; i++) {
- Type *param_type = method_type->Proc.params->Tuple.variables[i]->type;
+ for (isize i = 0; i < method_param_count; i++) {
+ Type *param_type = method_type->Proc.params->Tuple.variables[i + method_param_offset]->type;
String param_encoding = lb_get_objc_type_encoding(param_type);
method_encoding = concatenate_strings(temporary_allocator(), method_encoding, param_encoding);
@@ -1800,7 +1864,7 @@ gb_internal void lb_finalize_objc_names(lbGenerator *gen, lbProcedure *p) {
args[2] = lbValue { wrapper_proc->value, wrapper_proc->type };
args[3] = lb_const_value(m, t_cstring, exact_value_string(method_encoding));
- // TODO(harold): Emit check BOOL result and panic if false.
+ // TODO(harold): Emit check BOOL result and panic if false?
lb_emit_runtime_call(p, "class_addMethod", args);
} // End methods
@@ -1848,7 +1912,7 @@ gb_internal void lb_finalize_objc_names(lbGenerator *gen, lbProcedure *p) {
// Defined in an external package, define it now in the main package
LLVMTypeRef t = lb_type(m, t_int);
- lbValue global{};
+ lbValue global = {};
global.value = LLVMAddGlobal(m->mod, t, g.global_name);
global.type = t_int_ptr;
@@ -1900,12 +1964,16 @@ gb_internal void lb_verify_function(lbModule *m, lbProcedure *p, bool dump_ll=fa
}
gb_internal WORKER_TASK_PROC(lb_llvm_module_verification_worker_proc) {
+ if (LLVM_IGNORE_VERIFICATION) {
+ return 0;
+ }
+
char *llvm_error = nullptr;
defer (LLVMDisposeMessage(llvm_error));
lbModule *m = cast(lbModule *)data;
if (LLVMVerifyModule(m->mod, LLVMReturnStatusAction, &llvm_error)) {
- gb_printf_err("LLVM Error:\n%s\n", llvm_error);
+ gb_printf_err("LLVM Error in module %s:\n%s\n", m->module_name, llvm_error);
if (build_context.keep_temp_files) {
TIME_SECTION("LLVM Print Module to File");
String filepath_ll = lb_filepath_ll_for_module(m);
@@ -1921,118 +1989,153 @@ gb_internal WORKER_TASK_PROC(lb_llvm_module_verification_worker_proc) {
return 0;
}
+gb_internal bool lb_init_global_var(lbModule *m, lbProcedure *p, Entity *e, Ast *init_expr, lbGlobalVariable &var) {
+ if (init_expr != nullptr) {
+ lbValue init = lb_build_expr(p, init_expr);
+ if (init.value == nullptr) {
+ LLVMTypeRef global_type = llvm_addr_type(p->module, var.var);
+ if (is_type_untyped_nil(init.type)) {
+ LLVMSetInitializer(var.var.value, LLVMConstNull(global_type));
+ var.is_initialized = true;
+ if (e->Variable.is_rodata) {
+ LLVMSetGlobalConstant(var.var.value, true);
+ }
+ return true;
+ }
+ GB_PANIC("Invalid init value, got %s", expr_to_string(init_expr));
+ }
-gb_internal lbProcedure *lb_create_startup_runtime(lbModule *main_module, lbProcedure *objc_names, Array<lbGlobalVariable> &global_variables) { // Startup Runtime
- Type *proc_type = alloc_type_proc(nullptr, nullptr, 0, nullptr, 0, false, ProcCC_Odin);
+ if (is_type_any(e->type)) {
+ var.init = init;
+ } else if (lb_is_const_or_global(init)) {
+ if (!var.is_initialized) {
+ if (is_type_proc(init.type)) {
+ init.value = LLVMConstPointerCast(init.value, lb_type(p->module, init.type));
+ }
+ LLVMSetInitializer(var.var.value, init.value);
+ var.is_initialized = true;
- lbProcedure *p = lb_create_dummy_procedure(main_module, str_lit(LB_STARTUP_RUNTIME_PROC_NAME), proc_type);
- p->is_startup = true;
- lb_add_attribute_to_proc(p->module, p->value, "optnone");
- lb_add_attribute_to_proc(p->module, p->value, "noinline");
+ if (e->Variable.is_rodata) {
+ LLVMSetGlobalConstant(var.var.value, true);
+ }
+ return true;
+ }
+ } else {
+ var.init = init;
+ }
+ }
- // Make sure shared libraries call their own runtime startup on Linux.
- LLVMSetVisibility(p->value, LLVMHiddenVisibility);
- LLVMSetLinkage(p->value, LLVMWeakAnyLinkage);
+ if (var.init.value != nullptr) {
+ GB_ASSERT(!var.is_initialized);
+ Type *t = type_deref(var.var.type);
+
+ if (is_type_any(t)) {
+ // NOTE(bill): Edge case for 'any' type
+ Type *var_type = default_type(var.init.type);
+ gbString var_name = gb_string_make(permanent_allocator(), "__$global_any::");
+ gbString e_str = string_canonical_entity_name(temporary_allocator(), e);
+ var_name = gb_string_append_length(var_name, e_str, gb_strlen(e_str));
+ lbAddr g = lb_add_global_generated_with_name(m, var_type, {}, make_string_c(var_name));
+ 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_typeid(p->module, var_type));
+ } else {
+ LLVMTypeRef vt = llvm_addr_type(p->module, var.var);
+ lbValue src0 = lb_emit_conv(p, var.init, t);
+ LLVMValueRef src = OdinLLVMBuildTransmute(p, src0.value, vt);
+ LLVMValueRef dst = var.var.value;
+ LLVMBuildStore(p->builder, src, dst);
+ }
+
+ var.is_initialized = true;
+ }
+ return false;
+}
+
+gb_internal void lb_create_startup_runtime_generate_body(lbModule *m, lbProcedure *p) {
lb_begin_procedure_body(p);
- lb_setup_type_info_data(main_module);
+ lb_setup_type_info_data(m);
- if (objc_names) {
- LLVMBuildCall2(p->builder, lb_type_internal_for_procedures_raw(main_module, objc_names->type), objc_names->value, nullptr, 0, "");
+ if (p->objc_names) {
+ LLVMBuildCall2(p->builder, lb_type_internal_for_procedures_raw(m, p->objc_names->type), p->objc_names->value, nullptr, 0, "");
}
+ Type *dummy_type = alloc_type_proc(nullptr, nullptr, 0, nullptr, 0, false, ProcCC_Odin);
+ LLVMTypeRef raw_dummy_type = lb_type_internal_for_procedures_raw(m, dummy_type);
- for (auto &var : global_variables) {
+ for (auto &var : *p->global_variables) {
if (var.is_initialized) {
continue;
}
- lbModule *entity_module = main_module;
+ lbModule *entity_module = m;
Entity *e = var.decl->entity;
GB_ASSERT(e->kind == Entity_Variable);
e->code_gen_module = entity_module;
-
Ast *init_expr = var.decl->init_expr;
- if (init_expr != nullptr) {
- lbValue init = lb_build_expr(p, init_expr);
- if (init.value == nullptr) {
- LLVMTypeRef global_type = llvm_addr_type(p->module, var.var);
- if (is_type_untyped_nil(init.type)) {
- LLVMSetInitializer(var.var.value, LLVMConstNull(global_type));
- var.is_initialized = true;
-
- if (e->Variable.is_rodata) {
- LLVMSetGlobalConstant(var.var.value, true);
- }
- continue;
- }
- GB_PANIC("Invalid init value, got %s", expr_to_string(init_expr));
- }
-
- if (is_type_any(e->type) || is_type_union(e->type)) {
- var.init = init;
- } else if (lb_is_const_or_global(init)) {
- if (!var.is_initialized) {
- if (is_type_proc(init.type)) {
- init.value = LLVMConstPointerCast(init.value, lb_type(p->module, init.type));
- }
- LLVMSetInitializer(var.var.value, init.value);
- var.is_initialized = true;
- if (e->Variable.is_rodata) {
- LLVMSetGlobalConstant(var.var.value, true);
- }
- continue;
- }
- } else {
- var.init = init;
- }
+ if (init_expr == nullptr && var.init.value == nullptr) {
+ continue;
}
- if (var.init.value != nullptr) {
- GB_ASSERT(!var.is_initialized);
- Type *t = type_deref(var.var.type);
-
- if (is_type_any(t)) {
- // NOTE(bill): Edge case for 'any' type
- Type *var_type = default_type(var.init.type);
- gbString var_name = gb_string_make(permanent_allocator(), "__$global_any::");
- gbString e_str = string_canonical_entity_name(temporary_allocator(), e);
- var_name = gb_string_append_length(var_name, e_str, gb_strlen(e_str));
- lbAddr g = lb_add_global_generated_with_name(main_module, var_type, {}, make_string_c(var_name));
- 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_typeid(p->module, var_type));
- } else {
- LLVMTypeRef vt = llvm_addr_type(p->module, var.var);
- lbValue src0 = lb_emit_conv(p, var.init, t);
- LLVMValueRef src = OdinLLVMBuildTransmute(p, src0.value, vt);
- LLVMValueRef dst = var.var.value;
- LLVMBuildStore(p->builder, src, dst);
- }
+ if (false && type_size_of(e->type) > 8) {
+ String ename = lb_get_entity_name(m, e);
+ gbString name = gb_string_make(permanent_allocator(), "");
+ name = gb_string_appendc(name, "__$startup$");
+ name = gb_string_append_length(name, ename.text, ename.len);
- var.is_initialized = true;
- }
+ lbProcedure *dummy = lb_create_dummy_procedure(m, make_string_c(name), dummy_type);
+ dummy->is_startup = true;
+ LLVMSetVisibility(dummy->value, LLVMHiddenVisibility);
+ LLVM_SET_INTERNAL_WEAK_LINKAGE(p->value);
+ lb_begin_procedure_body(dummy);
+ lb_init_global_var(m, dummy, e, init_expr, var);
+ lb_end_procedure_body(dummy);
+ LLVMValueRef context_ptr = lb_find_or_generate_context_ptr(p).addr.value;
+ LLVMValueRef cast_ctx = LLVMBuildBitCast(p->builder, context_ptr, LLVMPointerType(LLVMInt8TypeInContext(m->ctx), 0), "");
+ LLVMBuildCall2(p->builder, raw_dummy_type, dummy->value, &cast_ctx, 1, "");
+ } else {
+ lb_init_global_var(m, p, e, init_expr, var);
+ }
}
- CheckerInfo *info = main_module->gen->info;
-
+ CheckerInfo *info = m->gen->info;
+
for (Entity *e : info->init_procedures) {
- lbValue value = lb_find_procedure_value_from_entity(main_module, e);
+ lbValue value = lb_find_procedure_value_from_entity(m, e);
lb_emit_call(p, value, {}, ProcInlining_none);
}
lb_end_procedure_body(p);
+}
+
+
+gb_internal lbProcedure *lb_create_startup_runtime(lbModule *main_module, lbProcedure *objc_names, Array<lbGlobalVariable> &global_variables) { // Startup Runtime
+ Type *proc_type = alloc_type_proc(nullptr, nullptr, 0, nullptr, 0, false, ProcCC_Odin);
+
+ lbProcedure *p = lb_create_dummy_procedure(main_module, str_lit(LB_STARTUP_RUNTIME_PROC_NAME), proc_type);
+ p->is_startup = true;
+ lb_add_attribute_to_proc(p->module, p->value, "optnone");
+ lb_add_attribute_to_proc(p->module, p->value, "noinline");
+
+ // Make sure shared libraries call their own runtime startup on Linux.
+ LLVMSetVisibility(p->value, LLVMHiddenVisibility);
+ LLVM_SET_INTERNAL_WEAK_LINKAGE(p->value);
+
+ p->global_variables = &global_variables;
+ p->objc_names = objc_names;
+
+ lb_create_startup_runtime_generate_body(main_module, p);
- lb_verify_function(main_module, p);
return p;
}
@@ -2046,7 +2149,7 @@ gb_internal lbProcedure *lb_create_cleanup_runtime(lbModule *main_module) { // C
// Make sure shared libraries call their own runtime cleanup on Linux.
LLVMSetVisibility(p->value, LLVMHiddenVisibility);
- LLVMSetLinkage(p->value, LLVMWeakAnyLinkage);
+ LLVM_SET_INTERNAL_WEAK_LINKAGE(p->value);
lb_begin_procedure_body(p);
@@ -2073,7 +2176,7 @@ gb_internal WORKER_TASK_PROC(lb_generate_procedures_and_types_per_module) {
for (Entity *e : m->global_procedures_to_create) {
(void)lb_get_entity_name(m, e);
- array_add(&m->procedures_to_generate, lb_create_procedure(m, e));
+ mpsc_enqueue(&m->procedures_to_generate, lb_create_procedure(m, e));
}
return 0;
}
@@ -2097,8 +2200,6 @@ gb_internal GB_COMPARE_PROC(llvm_global_entity_cmp) {
}
gb_internal void lb_create_global_procedures_and_types(lbGenerator *gen, CheckerInfo *info, bool do_threading) {
- auto *min_dep_set = &info->minimum_dependency_set;
-
for (Entity *e : info->entities) {
String name = e->token.string;
Scope * scope = e->scope;
@@ -2135,18 +2236,28 @@ gb_internal void lb_create_global_procedures_and_types(lbGenerator *gen, Checker
}
}
- if (!polymorphic_struct && !ptr_set_exists(min_dep_set, e)) {
+ if (!polymorphic_struct && e->min_dep_count.load(std::memory_order_relaxed) == 0) {
// NOTE(bill): Nothing depends upon it so doesn't need to be built
continue;
}
+ // if (!polymorphic_struct && !ptr_set_exists(min_dep_set, e)) {
+ // // NOTE(bill): Nothing depends upon it so doesn't need to be built
+ // continue;
+ // }
+
lbModule *m = &gen->default_module;
if (USE_SEPARATE_MODULES) {
- m = lb_module_of_entity(gen, e);
+ m = lb_module_of_entity(gen, e, m);
}
GB_ASSERT(m != nullptr);
if (e->kind == Entity_Procedure) {
+ if (e->Procedure.is_foreign && e->Procedure.is_objc_impl_or_import) {
+ // Do not generate declarations for foreign Objective-C methods. These are called indirectly through the Objective-C runtime.
+ continue;
+ }
+
array_add(&m->global_procedures_to_create, e);
} else if (e->kind == Entity_TypeName) {
array_add(&m->global_types_to_create, e);
@@ -2258,7 +2369,7 @@ gb_internal WORKER_TASK_PROC(lb_llvm_function_pass_per_module) {
lb_llvm_function_pass_per_function_internal(m, m->gen->objc_names);
}
- for (lbProcedure *p : m->procedures_to_generate) {
+ MUTEX_GUARD_BLOCK(&m->generated_procedures_mutex) for (lbProcedure *p : m->generated_procedures) {
if (p->body != nullptr) { // Build Procedure
lbFunctionPassManagerKind pass_manager_kind = lbFunctionPassManager_default;
if (p->flags & lbProcedureFlag_WithoutMemcpyPass) {
@@ -2297,17 +2408,23 @@ gb_internal WORKER_TASK_PROC(lb_llvm_function_pass_per_module) {
}
+void lb_remove_unused_functions_and_globals(lbGenerator *gen) {
+ for (auto &entry : gen->modules) {
+ lbModule *m = entry.value;
+ lb_run_remove_unused_function_pass(m);
+ lb_run_remove_unused_globals_pass(m);
+ }
+}
+
struct lbLLVMModulePassWorkerData {
lbModule *m;
LLVMTargetMachineRef target_machine;
+ bool do_threading;
};
gb_internal WORKER_TASK_PROC(lb_llvm_module_pass_worker_proc) {
auto wd = cast(lbLLVMModulePassWorkerData *)data;
- lb_run_remove_unused_function_pass(wd->m);
- lb_run_remove_unused_globals_pass(wd->m);
-
LLVMPassManagerRef module_pass_manager = LLVMCreatePassManager();
lb_populate_module_pass_manager(wd->target_machine, module_pass_manager, build_context.optimization_level);
LLVMRunPassManager(module_pass_manager, wd->m->mod);
@@ -2383,6 +2500,17 @@ gb_internal WORKER_TASK_PROC(lb_llvm_module_pass_worker_proc) {
return 1;
}
#endif
+
+ if (LLVM_IGNORE_VERIFICATION) {
+ return 0;
+ }
+
+ if (wd->do_threading) {
+ thread_pool_add_task(lb_llvm_module_verification_worker_proc, wd->m);
+ } else {
+ lb_llvm_module_verification_worker_proc(wd->m);
+ }
+
return 0;
}
@@ -2390,8 +2518,7 @@ gb_internal WORKER_TASK_PROC(lb_llvm_module_pass_worker_proc) {
gb_internal WORKER_TASK_PROC(lb_generate_procedures_worker_proc) {
lbModule *m = cast(lbModule *)data;
- for (isize i = 0; i < m->procedures_to_generate.count; i++) {
- lbProcedure *p = m->procedures_to_generate[i];
+ for (lbProcedure *p = nullptr; mpsc_dequeue(&m->procedures_to_generate, &p); /**/) {
lb_generate_procedure(p->module, p);
}
return 0;
@@ -2415,15 +2542,22 @@ gb_internal void lb_generate_procedures(lbGenerator *gen, bool do_threading) {
gb_internal WORKER_TASK_PROC(lb_generate_missing_procedures_to_check_worker_proc) {
lbModule *m = cast(lbModule *)data;
- for (isize i = 0; i < m->missing_procedures_to_check.count; i++) {
- lbProcedure *p = m->missing_procedures_to_check[i];
- debugf("Generate missing procedure: %.*s module %p\n", LIT(p->name), m);
- lb_generate_procedure(m, p);
+ for (lbProcedure *p = nullptr; mpsc_dequeue(&m->missing_procedures_to_check, &p); /**/) {
+ if (!p->is_done.load(std::memory_order_relaxed)) {
+ debugf("Generate missing procedure: %.*s module %p\n", LIT(p->name), m);
+ lb_generate_procedure(m, p);
+ }
+
+ for (lbProcedure *nested = nullptr; mpsc_dequeue(&m->procedures_to_generate, &nested); /**/) {
+ mpsc_enqueue(&m->missing_procedures_to_check, nested);
+ }
}
return 0;
}
gb_internal void lb_generate_missing_procedures(lbGenerator *gen, bool do_threading) {
+ isize retry_count = 0;
+retry:;
if (do_threading) {
for (auto const &entry : gen->modules) {
lbModule *m = entry.value;
@@ -2438,6 +2572,20 @@ gb_internal void lb_generate_missing_procedures(lbGenerator *gen, bool do_thread
lb_generate_missing_procedures_to_check_worker_proc(m);
}
}
+
+ for (auto const &entry : gen->modules) {
+ lbModule *m = entry.value;
+ if (m->missing_procedures_to_check.count != 0) {
+ if (retry_count > gen->modules.count) {
+ GB_ASSERT(m->missing_procedures_to_check.count == 0);
+ }
+
+ retry_count += 1;
+ goto retry;
+ }
+ GB_ASSERT(m->missing_procedures_to_check.count == 0);
+ GB_ASSERT(m->procedures_to_generate.count == 0);
+ }
}
gb_internal void lb_debug_info_complete_types_and_finalize(lbGenerator *gen) {
@@ -2465,19 +2613,16 @@ gb_internal void lb_llvm_function_passes(lbGenerator *gen, bool do_threading) {
}
-gb_internal void lb_llvm_module_passes(lbGenerator *gen, bool do_threading) {
+gb_internal void lb_llvm_module_passes_and_verification(lbGenerator *gen, bool do_threading) {
if (do_threading) {
for (auto const &entry : gen->modules) {
lbModule *m = entry.value;
auto wd = gb_alloc_item(permanent_allocator(), lbLLVMModulePassWorkerData);
wd->m = m;
wd->target_machine = m->target_machine;
+ wd->do_threading = true;
- if (do_threading) {
- thread_pool_add_task(lb_llvm_module_pass_worker_proc, wd);
- } else {
- lb_llvm_module_pass_worker_proc(wd);
- }
+ thread_pool_add_task(lb_llvm_module_pass_worker_proc, wd);
}
thread_pool_wait();
} else {
@@ -2486,6 +2631,7 @@ gb_internal void lb_llvm_module_passes(lbGenerator *gen, bool do_threading) {
auto wd = gb_alloc_item(permanent_allocator(), lbLLVMModulePassWorkerData);
wd->m = m;
wd->target_machine = m->target_machine;
+ wd->do_threading = false;
lb_llvm_module_pass_worker_proc(wd);
}
}
@@ -2566,31 +2712,6 @@ gb_internal String lb_filepath_obj_for_module(lbModule *m) {
}
-
-gb_internal bool lb_llvm_module_verification(lbGenerator *gen, bool do_threading) {
- if (LLVM_IGNORE_VERIFICATION) {
- return true;
- }
-
- if (do_threading) {
- for (auto const &entry : gen->modules) {
- lbModule *m = entry.value;
- thread_pool_add_task(lb_llvm_module_verification_worker_proc, m);
- }
- thread_pool_wait();
-
- } else {
- for (auto const &entry : gen->modules) {
- lbModule *m = entry.value;
- if (lb_llvm_module_verification_worker_proc(m)) {
- return false;
- }
- }
- }
-
- return true;
-}
-
gb_internal void lb_add_foreign_library_paths(lbGenerator *gen) {
for (auto const &entry : gen->modules) {
lbModule *m = entry.value;
@@ -2686,8 +2807,15 @@ gb_internal lbProcedure *lb_create_main_procedure(lbModule *m, lbProcedure *star
params->Tuple.variables[1] = alloc_entity_param(nullptr, make_token_ident("fdwReason"), t_u32, false, true);
params->Tuple.variables[2] = alloc_entity_param(nullptr, make_token_ident("lpReserved"), t_rawptr, false, true);
call_cleanup = false;
- } else if (build_context.metrics.os == TargetOs_windows && (build_context.metrics.arch == TargetArch_i386 || build_context.no_crt)) {
+ } else if (build_context.metrics.os == TargetOs_windows && build_context.no_crt) {
name = str_lit("mainCRTStartup");
+ } else if (build_context.metrics.os == TargetOs_windows && build_context.metrics.arch == TargetArch_i386 && !build_context.no_crt) {
+ // Windows i386 with CRT: libcmt expects _main (main with underscore prefix)
+ name = str_lit("main");
+ has_args = true;
+ slice_init(&params->Tuple.variables, permanent_allocator(), 2);
+ params->Tuple.variables[0] = alloc_entity_param(nullptr, make_token_ident("argc"), t_i32, false, true);
+ params->Tuple.variables[1] = alloc_entity_param(nullptr, make_token_ident("argv"), t_ptr_cstring, false, true);
} else if (is_arch_wasm()) {
name = str_lit("_start");
call_cleanup = false;
@@ -2775,7 +2903,18 @@ gb_internal lbProcedure *lb_create_main_procedure(lbModule *m, lbProcedure *star
args[0] = lb_addr_load(p, all_tests_slice);
lbValue result = lb_emit_call(p, runner, args);
- lbValue exit_runner = lb_find_package_value(m, str_lit("os"), str_lit("exit"));
+ lbValue exit_runner = {};
+ {
+ AstPackage *pkg = get_runtime_package(m->info);
+
+ String name = str_lit("exit");
+ Entity *e = scope_lookup_current(pkg->scope, name);
+ if (e == nullptr) {
+ compiler_error("Could not find type declaration for '%.*s.%.*s'\n", LIT(pkg->name), LIT(name));
+ }
+ exit_runner = lb_find_value_from_entity(m, e);
+ }
+
auto exit_args = array_make<lbValue>(temporary_allocator(), 1);
exit_args[0] = lb_emit_select(p, result, lb_const_int(m, t_int, 0), lb_const_int(m, t_int, 1));
lb_emit_call(p, exit_runner, exit_args, ProcInlining_none);
@@ -2813,16 +2952,19 @@ gb_internal lbProcedure *lb_create_main_procedure(lbModule *m, lbProcedure *star
}
gb_internal void lb_generate_procedure(lbModule *m, lbProcedure *p) {
- if (p->is_done) {
+ if (p->is_done.load(std::memory_order_relaxed)) {
return;
}
+
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;
+ p->is_done.store(true, std::memory_order_relaxed);
m->curr_procedure = nullptr;
+ } else if (p->generate_body != nullptr) {
+ p->generate_body(m, p);
}
// Add Flags
@@ -2831,6 +2973,9 @@ gb_internal void lb_generate_procedure(lbModule *m, lbProcedure *p) {
}
lb_verify_function(m, p, true);
+
+ MUTEX_GUARD(&m->generated_procedures_mutex);
+ array_add(&m->generated_procedures, p);
}
@@ -2845,8 +2990,6 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
lbModule *default_module = &gen->default_module;
CheckerInfo *info = gen->info;
- auto *min_dep_set = &info->minimum_dependency_set;
-
switch (build_context.metrics.arch) {
case TargetArch_amd64:
case TargetArch_i386:
@@ -2917,8 +3060,14 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
LLVMCodeModel code_mode = LLVMCodeModelDefault;
if (is_arch_wasm()) {
code_mode = LLVMCodeModelJITDefault;
+ debugf("LLVM code mode: LLVMCodeModelJITDefault\n");
} else if (is_arch_x86() && build_context.metrics.os == TargetOs_freestanding) {
code_mode = LLVMCodeModelKernel;
+ debugf("LLVM code mode: LLVMCodeModelKernel\n");
+ }
+
+ if (code_mode == LLVMCodeModelDefault) {
+ debugf("LLVM code mode: LLVMCodeModelDefault\n");
}
String llvm_cpu = get_final_microarchitecture();
@@ -2934,7 +3083,10 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
}
first = false;
- llvm_features = gb_string_appendc(llvm_features, "+");
+ if (*str.text != '+' && *str.text != '-') {
+ llvm_features = gb_string_appendc(llvm_features, "+");
+ }
+
llvm_features = gb_string_append_length(llvm_features, str.text, str.len);
}
@@ -3162,6 +3314,7 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
String link_name = e->Procedure.link_name;
if (e->pkg->kind == Package_Runtime) {
if (link_name == "main" ||
+ link_name == "_main" ||
link_name == "DllMain" ||
link_name == "WinMain" ||
link_name == "wWinMain" ||
@@ -3184,7 +3337,7 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
continue;
}
- if (!ptr_set_exists(min_dep_set, e)) {
+ if (e->min_dep_count.load(std::memory_order_relaxed) == 0) {
continue;
}
@@ -3194,47 +3347,32 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
}
GB_ASSERT(e->kind == Entity_Variable);
+
bool is_foreign = e->Variable.is_foreign;
bool is_export = e->Variable.is_export;
+ lbModule *default_module = &gen->default_module;
- 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));
- g.type = alloc_type_pointer(e->type);
-
- lb_apply_thread_local_model(g.value, e->Variable.thread_local_model);
+ lbModule *m = default_module;
+ lbModule *e_module = lb_module_of_entity(gen, e, default_module);
- if (is_foreign) {
- LLVMSetLinkage(g.value, LLVMExternalLinkage);
- LLVMSetDLLStorageClass(g.value, LLVMDLLImportStorageClass);
- LLVMSetExternallyInitialized(g.value, true);
- lb_add_foreign_library_path(m, e->Variable.foreign_library);
- } else {
- LLVMSetInitializer(g.value, LLVMConstNull(lb_type(m, e->type)));
- }
- if (is_export) {
- LLVMSetLinkage(g.value, LLVMDLLExportLinkage);
- LLVMSetDLLStorageClass(g.value, LLVMDLLExportStorageClass);
- } else if (!is_foreign) {
- LLVMSetLinkage(g.value, USE_SEPARATE_MODULES ? LLVMWeakAnyLinkage : LLVMInternalLinkage);
- }
- lb_set_linkage_from_entity_flags(m, g.value, e->flags);
- LLVMSetAlignment(g.value, cast(u32)type_align_of(e->type));
-
- if (e->Variable.link_section.len > 0) {
- LLVMSetSection(g.value, alloc_cstring(permanent_allocator(), e->Variable.link_section));
+ bool const split_globals_across_modules = false;
+ if (split_globals_across_modules) {
+ m = e_module;
}
+ String name = lb_get_entity_name(m, e);
+
lbGlobalVariable var = {};
- var.var = g;
var.decl = decl;
+ lbValue g = {};
+ g.type = alloc_type_pointer(e->type);
+ g.value = LLVMAddGlobal(m->mod, lb_type(m, e->type), alloc_cstring(permanent_allocator(), name));
+
if (decl->init_expr != nullptr) {
TypeAndValue tav = type_and_value_of_expr(decl->init_expr);
- if (!is_type_any(e->type) && !is_type_union(e->type)) {
+ if (!is_type_any(e->type)) {
if (tav.mode != Addressing_Invalid) {
if (tav.value.kind != ExactValue_Invalid) {
auto cc = LB_CONST_CONTEXT_DEFAULT;
@@ -3244,6 +3382,11 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
ExactValue v = tav.value;
lbValue init = lb_const_value(m, tav.type, v, cc);
+
+ LLVMDeleteGlobal(g.value);
+ g.value = nullptr;
+ g.value = LLVMAddGlobal(m->mod, LLVMTypeOf(init.value), alloc_cstring(permanent_allocator(), name));
+
LLVMSetInitializer(g.value, init.value);
var.is_initialized = true;
if (cc.is_rodata) {
@@ -3262,15 +3405,32 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
LLVMSetGlobalConstant(g.value, true);
}
- if (e->flags & EntityFlag_Require) {
- lb_append_to_compiler_used(m, g.value);
- }
- array_add(&global_variables, var);
+ lb_apply_thread_local_model(g.value, e->Variable.thread_local_model);
- lb_add_entity(m, e, g);
- lb_add_member(m, name, g);
+ if (is_foreign) {
+ LLVMSetLinkage(g.value, LLVMExternalLinkage);
+ LLVMSetDLLStorageClass(g.value, LLVMDLLImportStorageClass);
+ LLVMSetExternallyInitialized(g.value, true);
+ lb_add_foreign_library_path(m, e->Variable.foreign_library);
+ } else if (LLVMGetInitializer(g.value) == nullptr) {
+ LLVMSetInitializer(g.value, LLVMConstNull(lb_type(m, e->type)));
+ }
+ if (is_export) {
+ LLVMSetLinkage(g.value, LLVMDLLExportLinkage);
+ LLVMSetDLLStorageClass(g.value, LLVMDLLExportStorageClass);
+ } else if (!is_foreign) {
+ LLVM_SET_INTERNAL_WEAK_LINKAGE(g.value);
+ }
+ lb_set_linkage_from_entity_flags(m, g.value, e->flags);
+ LLVMSetAlignment(g.value, cast(u32)type_align_of(e->type));
+ if (e->Variable.link_section.len > 0) {
+ LLVMSetSection(g.value, alloc_cstring(permanent_allocator(), e->Variable.link_section));
+ }
+ if (e->flags & EntityFlag_Require) {
+ lb_append_to_compiler_used(m, g.value);
+ }
if (m->debug_builder) {
String global_name = e->token.string;
@@ -3300,6 +3460,27 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
LLVMGlobalSetMetadata(g.value, 0, global_variable_metadata);
}
}
+
+ if (default_module == m) {
+ g.value = LLVMConstPointerCast(g.value, lb_type(m, alloc_type_pointer(e->type)));
+
+ var.var = g;
+ array_add(&global_variables, var);
+ } else {
+ lbValue local_g = {};
+ local_g.type = alloc_type_pointer(e->type);
+ local_g.value = LLVMAddGlobal(default_module->mod, lb_type(default_module, e->type), alloc_cstring(permanent_allocator(), name));
+ LLVMSetLinkage(local_g.value, LLVMExternalLinkage);
+
+ var.var = local_g;
+ array_add(&global_variables, var);
+
+ lb_add_entity(default_module, e, local_g);
+ lb_add_member(default_module, name, local_g);
+ }
+
+ lb_add_entity(m, e, g);
+ lb_add_member(m, name, g);
}
if (build_context.ODIN_DEBUG) {
@@ -3471,15 +3652,23 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
}
}
+ TIME_SECTION("LLVM Add Foreign Library Paths");
+ lb_add_foreign_library_paths(gen);
+
TIME_SECTION("LLVM Function Pass");
lb_llvm_function_passes(gen, do_threading && !build_context.ODIN_DEBUG);
- TIME_SECTION("LLVM Module Pass");
- lb_llvm_module_passes(gen, do_threading);
+ TIME_SECTION("LLVM Remove Unused Functions and Globals");
+ lb_remove_unused_functions_and_globals(gen);
- TIME_SECTION("LLVM Module Verification");
- if (!lb_llvm_module_verification(gen, do_threading)) {
- return false;
+ TIME_SECTION("LLVM Module Pass and Verification");
+ lb_llvm_module_passes_and_verification(gen, do_threading);
+
+ TIME_SECTION("LLVM Correct Entity Linkage");
+ lb_correct_entity_linkage(gen);
+
+ if (build_context.build_diagnostics) {
+ lb_do_build_diagnostics(gen);
}
llvm_error = nullptr;
@@ -3508,11 +3697,6 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
}
}
- TIME_SECTION("LLVM Add Foreign Library Paths");
- lb_add_foreign_library_paths(gen);
-
- TIME_SECTION("LLVM Correct Entity Linkage");
- lb_correct_entity_linkage(gen);
////////////////////////////////////////////
for (auto const &entry: gen->modules) {