aboutsummaryrefslogtreecommitdiff
path: root/src/llvm_backend.cpp
diff options
context:
space:
mode:
authorCourtney Strachan <courtney.strachan@gmail.com>2025-10-06 02:41:44 +0100
committerGitHub <noreply@github.com>2025-10-06 02:41:44 +0100
commit6de2d6e8ca687c989bbb7806e5cbe8d791e425bf (patch)
tree03a2e0a84c7c1530215f8e3f59a7f643b39b3677 /src/llvm_backend.cpp
parentdbbe96ae5c343f0e803de6ee508207a62571534f (diff)
parent0f97382fa3e46da80705c00dfe02f3deb9562e4f (diff)
Merge branch 'odin-lang:master' into master
Diffstat (limited to 'src/llvm_backend.cpp')
-rw-r--r--src/llvm_backend.cpp2331
1 files changed, 1264 insertions, 1067 deletions
diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp
index 88e099930..921084250 100644
--- a/src/llvm_backend.cpp
+++ b/src/llvm_backend.cpp
@@ -8,7 +8,11 @@
#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
@@ -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);
+}
+
+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;
- compare_proc = p;
- return {compare_proc->value, compare_proc->type};
+ // 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) {
@@ -563,6 +573,53 @@ gb_internal lbValue lb_hasher_proc_for_type(lbModule *m, Type *type) {
lbValue res = lb_emit_runtime_call(p, "default_hasher_string", args);
lb_add_callsite_force_inline(p, res);
LLVMBuildRet(p->builder, res.value);
+ } else if (is_type_float(type)) {
+ lbValue ptr = lb_emit_conv(p, data, pt);
+ lbValue v = lb_emit_load(p, ptr);
+ v = lb_emit_conv(p, v, t_f64);
+
+ auto args = array_make<lbValue>(temporary_allocator(), 2);
+ args[0] = v;
+ args[1] = seed;
+ lbValue res = lb_emit_runtime_call(p, "default_hasher_f64", args);
+ lb_add_callsite_force_inline(p, res);
+ LLVMBuildRet(p->builder, res.value);
+ } else if (is_type_complex(type)) {
+ lbValue ptr = lb_emit_conv(p, data, pt);
+ lbValue xp = lb_emit_struct_ep(p, ptr, 0);
+ lbValue yp = lb_emit_struct_ep(p, ptr, 1);
+
+ lbValue x = lb_emit_conv(p, lb_emit_load(p, xp), t_f64);
+ lbValue y = lb_emit_conv(p, lb_emit_load(p, yp), t_f64);
+
+ auto args = array_make<lbValue>(temporary_allocator(), 3);
+ args[0] = x;
+ args[1] = y;
+ args[2] = seed;
+ lbValue res = lb_emit_runtime_call(p, "default_hasher_complex128", args);
+ lb_add_callsite_force_inline(p, res);
+ LLVMBuildRet(p->builder, res.value);
+ } else if (is_type_quaternion(type)) {
+ lbValue ptr = lb_emit_conv(p, data, pt);
+ lbValue xp = lb_emit_struct_ep(p, ptr, 0);
+ lbValue yp = lb_emit_struct_ep(p, ptr, 1);
+ lbValue zp = lb_emit_struct_ep(p, ptr, 2);
+ lbValue wp = lb_emit_struct_ep(p, ptr, 3);
+
+ lbValue x = lb_emit_conv(p, lb_emit_load(p, xp), t_f64);
+ lbValue y = lb_emit_conv(p, lb_emit_load(p, yp), t_f64);
+ lbValue z = lb_emit_conv(p, lb_emit_load(p, zp), t_f64);
+ lbValue w = lb_emit_conv(p, lb_emit_load(p, wp), t_f64);
+
+ auto args = array_make<lbValue>(temporary_allocator(), 5);
+ args[0] = x;
+ args[1] = y;
+ args[2] = z;
+ args[3] = w;
+ args[4] = seed;
+ lbValue res = lb_emit_runtime_call(p, "default_hasher_quaternion256", args);
+ lb_add_callsite_force_inline(p, res);
+ LLVMBuildRet(p->builder, res.value);
} else {
GB_PANIC("Unhandled type for hasher: %s", type_to_string(type));
}
@@ -573,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);
@@ -587,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));
@@ -1106,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;
@@ -1126,30 +1178,763 @@ gb_internal lbProcedure *lb_create_objc_names(lbModule *main_module) {
return p;
}
-gb_internal void lb_finalize_objc_names(lbProcedure *p) {
+String lb_get_objc_type_encoding(Type *t, isize pointer_depth = 0) {
+ // NOTE(harold): See https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html#//apple_ref/doc/uid/TP40008048-CH100
+
+ // NOTE(harold): Darwin targets are always 64-bit. Should we drop this and assume "q" always?
+ #define INT_SIZE_ENCODING (build_context.metrics.int_size == 4 ? "i" : "q")
+ switch (t->kind) {
+ case Type_Basic: {
+ switch (t->Basic.kind) {
+ case Basic_Invalid:
+ return str_lit("?");
+
+ case Basic_llvm_bool:
+ case Basic_bool:
+ case Basic_b8:
+ return str_lit("B");
+
+ case Basic_b16:
+ return str_lit("C");
+ case Basic_b32:
+ return str_lit("I");
+ case Basic_b64:
+ return str_lit("q");
+ case Basic_i8:
+ return str_lit("c");
+ case Basic_u8:
+ return str_lit("C");
+ case Basic_i16:
+ case Basic_i16le:
+ case Basic_i16be:
+ return str_lit("s");
+ case Basic_u16:
+ case Basic_u16le:
+ case Basic_u16be:
+ return str_lit("S");
+ case Basic_i32:
+ case Basic_i32le:
+ case Basic_i32be:
+ return str_lit("i");
+ case Basic_u32le:
+ case Basic_u32:
+ case Basic_u32be:
+ return str_lit("I");
+ case Basic_i64:
+ case Basic_i64le:
+ case Basic_i64be:
+ return str_lit("q");
+ case Basic_u64:
+ case Basic_u64le:
+ case Basic_u64be:
+ return str_lit("Q");
+ case Basic_i128:
+ case Basic_i128le:
+ case Basic_i128be:
+ return str_lit("t");
+ case Basic_u128:
+ case Basic_u128le:
+ case Basic_u128be:
+ return str_lit("T");
+ case Basic_rune:
+ return str_lit("I");
+ case Basic_f16:
+ case Basic_f16le:
+ case Basic_f16be:
+ return str_lit("s"); // @harold: Closest we've got?
+ case Basic_f32:
+ case Basic_f32le:
+ case Basic_f32be:
+ return str_lit("f");
+ case Basic_f64:
+ case Basic_f64le:
+ case Basic_f64be:
+ return str_lit("d");
+
+ case Basic_complex32: return str_lit("{complex32=ss}"); // No f16 encoding, so fallback to i16, as above in Basic_f16*
+ case Basic_complex64: return str_lit("{complex64=ff}");
+ case Basic_complex128: return str_lit("{complex128=dd}");
+ case Basic_quaternion64: return str_lit("{quaternion64=ssss}");
+ case Basic_quaternion128: return str_lit("{quaternion128=ffff}");
+ case Basic_quaternion256: return str_lit("{quaternion256=dddd}");
+
+ case Basic_int:
+ return str_lit(INT_SIZE_ENCODING);
+ case Basic_uint:
+ return build_context.metrics.int_size == 4 ? str_lit("I") : str_lit("Q");
+ case Basic_uintptr:
+ case Basic_rawptr:
+ return str_lit("^v");
+
+ case Basic_string:
+ return build_context.metrics.int_size == 4 ? str_lit("{string=*i}") : str_lit("{string=*q}");
+
+ case Basic_string16:
+ return build_context.metrics.int_size == 4 ? str_lit("{string16=*i}") : str_lit("{string16=*q}");
+
+ case Basic_cstring: return str_lit("*");
+ case Basic_cstring16: return str_lit("*");
+
+
+ case Basic_any: return str_lit("{any=^v^v}"); // rawptr + ^Type_Info
+
+ case Basic_typeid:
+ GB_ASSERT(t->Basic.size == 8);
+ return str_lit("q");
+
+ // Untyped types
+ case Basic_UntypedBool:
+ case Basic_UntypedInteger:
+ case Basic_UntypedFloat:
+ case Basic_UntypedComplex:
+ case Basic_UntypedQuaternion:
+ case Basic_UntypedString:
+ case Basic_UntypedRune:
+ case Basic_UntypedNil:
+ case Basic_UntypedUninit:
+ GB_PANIC("Untyped types cannot be @encoded()");
+ return str_lit("?");
+ }
+ break;
+ }
+
+ case Type_Named:
+ case Type_Struct:
+ case Type_Union: {
+ Type* base = t;
+ if (base->kind == Type_Named) {
+ base = base_type(base);
+ if(base->kind != Type_Struct && base->kind != Type_Union) {
+ return lb_get_objc_type_encoding(base, pointer_depth);
+ }
+ }
+
+ const bool is_union = base->kind == Type_Union;
+ if (!is_union) {
+ // Treat struct as an Objective-C Class?
+ if (has_type_got_objc_class_attribute(t) && pointer_depth == 0) {
+ return str_lit("#");
+ }
+ }
+
+ if (is_type_objc_object(base)) {
+ return str_lit("@");
+ }
+
+
+ gbString s = gb_string_make_reserve(temporary_allocator(), 16);
+ s = gb_string_append_length(s, is_union ? "(" :"{", 1);
+ if (t->kind == Type_Named) {
+ s = gb_string_append_length(s, t->Named.name.text, t->Named.name.len);
+ }
+
+ // Write fields
+ if (pointer_depth < 2) {
+ s = gb_string_append_length(s, "=", 1);
+
+ if (!is_union) {
+ for( auto& f : base->Struct.fields ) {
+ String field_type = lb_get_objc_type_encoding(f->type, pointer_depth);
+ s = gb_string_append_length(s, field_type.text, field_type.len);
+ }
+ } else {
+ for( auto& v : base->Union.variants ) {
+ String variant_type = lb_get_objc_type_encoding(v, pointer_depth);
+ s = gb_string_append_length(s, variant_type.text, variant_type.len);
+ }
+ }
+ }
+
+ s = gb_string_append_length(s, is_union ? ")" :"}", 1);
+
+ return make_string_c(s);
+ }
+
+ case Type_Generic:
+ GB_PANIC("Generic types cannot be @encoded()");
+ return str_lit("?");
+
+ case Type_Pointer: {
+ // NOTE: These types are pointers, so we must check here for special cases
+ // Check for objc_SEL
+ if (internal_check_is_assignable_to(t, t_objc_SEL)) {
+ return str_lit(":");
+ }
+
+ // Check for objc_Class
+ if (internal_check_is_assignable_to(t, t_objc_Class)) {
+ return str_lit("#");
+ }
+
+ String pointee = lb_get_objc_type_encoding(t->Pointer.elem, pointer_depth +1);
+ // Special case for Objective-C Objects
+ if (pointer_depth == 0 && pointee == "@") {
+ return pointee;
+ }
+
+ return concatenate_strings(temporary_allocator(), str_lit("^"), pointee);
+ }
+
+ case Type_MultiPointer:
+ return concatenate_strings(temporary_allocator(), str_lit("^"), lb_get_objc_type_encoding(t->Pointer.elem, pointer_depth +1));
+
+ case Type_Array: {
+ String type_str = lb_get_objc_type_encoding(t->Array.elem, pointer_depth);
+
+ gbString s = gb_string_make_reserve(temporary_allocator(), type_str.len + 8);
+ s = gb_string_append_fmt(s, "[%lld%.*s]", t->Array.count, LIT(type_str));
+ return make_string_c(s);
+ }
+
+ case Type_EnumeratedArray: {
+ String type_str = lb_get_objc_type_encoding(t->EnumeratedArray.elem, pointer_depth);
+
+ gbString s = gb_string_make_reserve(temporary_allocator(), type_str.len + 8);
+ s = gb_string_append_fmt(s, "[%lld%.*s]", t->EnumeratedArray.count, LIT(type_str));
+ return make_string_c(s);
+ }
+
+ case Type_Slice: {
+ String type_str = lb_get_objc_type_encoding(t->Slice.elem, pointer_depth);
+ gbString s = gb_string_make_reserve(temporary_allocator(), type_str.len + 8);
+ s = gb_string_append_fmt(s, "{slice=^%.*s%s}", LIT(type_str), INT_SIZE_ENCODING);
+ return make_string_c(s);
+ }
+
+ case Type_DynamicArray: {
+ String type_str = lb_get_objc_type_encoding(t->DynamicArray.elem, pointer_depth);
+ gbString s = gb_string_make_reserve(temporary_allocator(), type_str.len + 8);
+ s = gb_string_append_fmt(s, "{dynamic=^%.*s%s%sAllocator={?^v}}", LIT(type_str), INT_SIZE_ENCODING, INT_SIZE_ENCODING);
+ return make_string_c(s);
+ }
+
+ case Type_Map:
+ return str_lit("{^v^v{Allocator=?^v}}");
+ case Type_Enum:
+ return lb_get_objc_type_encoding(t->Enum.base_type, pointer_depth);
+ case Type_Tuple:
+ // NOTE(harold): Is this type allowed here?
+ return str_lit("?");
+ case Type_Proc:
+ return str_lit("?");
+ 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);
+ gbString s = gb_string_make_reserve(temporary_allocator(), type_str.len + 5);
+ gb_string_append_fmt(s, "[%lld%.*s]", t->SimdVector.count, LIT(type_str));
+ return make_string_c(s);
+ }
+
+ case Type_Matrix: {
+ String type_str = lb_get_objc_type_encoding(t->Matrix.elem, pointer_depth);
+ gbString s = gb_string_make_reserve(temporary_allocator(), type_str.len + 5);
+ i64 element_count = t->Matrix.column_count * t->Matrix.row_count;
+ gb_string_append_fmt(s, "[%lld%.*s]", element_count, LIT(type_str));
+ return make_string_c(s);
+ }
+
+ case Type_BitField:
+ return lb_get_objc_type_encoding(t->BitField.backing_type, pointer_depth);
+ case Type_SoaPointer: {
+ gbString s = gb_string_make_reserve(temporary_allocator(), 8);
+ s = gb_string_append_fmt(s, "{=^v%s}", INT_SIZE_ENCODING);
+ return make_string_c(s);
+ }
+
+ } // End switch t->kind
+ #undef INT_SIZE_ENCODING
+
+ GB_PANIC("Unreachable");
+ return str_lit("");
+}
+
+struct lbObjCGlobalClass {
+ lbObjCGlobal g;
+ 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(
+ StringSet &handled,
+ lbModule *m,
+ Array<lbValue> &args,
+ Array<lbObjCGlobalClass> &class_impls,
+ StringMap<lbObjCGlobalClass> &class_map,
+ lbProcedure *p,
+ lbObjCGlobal const &g,
+ char const *call
+) {
+ if (string_set_update(&handled, g.name)) {
+ return;
+ }
+
+ lbAddr addr = {};
+ lbValue *found = string_map_get(&m->members, g.global_name);
+ if (found) {
+ addr = lb_addr(*found);
+ } else {
+ lbValue v = {};
+ LLVMTypeRef t = lb_type(m, g.type);
+ v.value = LLVMAddGlobal(m->mod, t, g.global_name);
+ v.type = alloc_type_pointer(g.type);
+ addr = lb_addr(v);
+ LLVMSetInitializer(v.value, LLVMConstNull(t));
+ }
+
+ // 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
+ 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_global.addr.value);
+ }
+
+ lbObjCGlobalClass impl_global = {};
+ impl_global.g = g;
+ impl_global.class_global = addr;
+
+ array_add(&class_impls, impl_global);
+
+ 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);
+
+ lbObjCGlobalClass* class_global = string_map_get(&class_map, g.name);
+ if (class_global != nullptr) {
+ class_global->class_value = class_ptr;
+ }
+ }
+}
+
+gb_internal void lb_finalize_objc_names(lbGenerator *gen, lbProcedure *p) {
if (p == nullptr) {
return;
}
lbModule *m = p->module;
+ GB_ASSERT(m == &p->module->gen->default_module);
TEMPORARY_ALLOCATOR_GUARD();
- auto args = array_make<lbValue>(temporary_allocator(), 1);
+ StringSet handled = {};
+ string_set_init(&handled);
+ defer (string_set_destroy(&handled));
+
+ auto args = array_make<lbValue>(temporary_allocator(), 3, 8);
+ auto class_impls = array_make<lbObjCGlobalClass>(temporary_allocator(), 0, 16);
+
+ // Register all class implementations unconditionally, even if not statically referenced
+ for (Entity *e = {}; mpsc_dequeue(&gen->info->objc_class_implementations, &e); /**/) {
+ GB_ASSERT(e->kind == Entity_TypeName && e->TypeName.objc_is_implementation);
+ lb_handle_objc_find_or_register_class(p, e->TypeName.objc_class_name, e->type);
+ }
+
+ // Ensure classes that have been implicitly referenced through
+ // the objc_superclass attribute have a global variable available for them.
+ TypeSet class_set{};
+ type_set_init(&class_set, gen->objc_classes.count+16);
+ defer (type_set_destroy(&class_set));
+
+ auto referenced_classes = array_make<lbObjCGlobal>(temporary_allocator());
+ for (lbObjCGlobal g = {}; mpsc_dequeue(&gen->objc_classes, &g); /**/) {
+ array_add(&referenced_classes, g);
+
+ Type *cls = g.class_impl_type;
+ while (cls) {
+ if (type_set_update(&class_set, cls)) {
+ break;
+ }
+ GB_ASSERT(cls->kind == Type_Named);
+
+ cls = cls->Named.type_name->TypeName.objc_superclass;
+ }
+ }
+
+ for (auto pair : class_set) {
+ auto& tn = pair.type->Named.type_name->TypeName;
+ Type *class_impl = !tn.objc_is_implementation ? nullptr : pair.type;
+ lb_handle_objc_find_or_register_class(p, tn.objc_class_name, class_impl);
+ }
+ for (lbObjCGlobal g = {}; mpsc_dequeue(&gen->objc_classes, &g); /**/) {
+ array_add( &referenced_classes, g );
+ }
+
+ // Add all class globals to a map so that we can look them up dynamically
+ // in order to resolve out-of-order because classes that are being implemented
+ // require their superclasses to be registered before them.
+ StringMap<lbObjCGlobalClass> global_class_map{};
+ string_map_init(&global_class_map, (usize)gen->objc_classes.count);
+ defer (string_map_destroy(&global_class_map));
+
+ for (lbObjCGlobal g : referenced_classes) {
+ string_map_set(&global_class_map, g.name, lbObjCGlobalClass{g});
+ }
LLVMSetLinkage(p->value, LLVMInternalLinkage);
lb_begin_procedure_body(p);
- for (auto const &entry : m->objc_classes) {
- String name = entry.key;
- args[0] = lb_const_value(m, t_cstring, exact_value_string(name));
- lbValue ptr = lb_emit_runtime_call(p, "objc_lookUpClass", args);
- lb_addr_store(p, entry.value.local_module_addr, ptr);
+
+ // Register class globals, gathering classes that must be implemented
+ for (auto& kv : global_class_map) {
+ lb_register_objc_thing(handled, m, args, class_impls, global_class_map, p, kv.value.g, "objc_lookUpClass");
+ }
+
+ // Prefetch selectors for implemented methods so that they can also be registered.
+ for (const auto& cd : class_impls) {
+ auto& g = cd.g;
+ Type *class_type = g.class_impl_type;
+
+ Array<ObjcMethodData>* methods = map_get(&m->info->objc_method_implementations, class_type);
+ if (!methods) {
+ continue;
+ }
+
+ for (const ObjcMethodData& md : *methods) {
+ lb_handle_objc_find_or_register_selector(p, md.ac.objc_selector);
+ }
+ }
+
+ // Now we can register all referenced selectors
+ for (lbObjCGlobal g = {}; mpsc_dequeue(&gen->objc_selectors, &g); /**/) {
+ lb_register_objc_thing(handled, m, args, class_impls, global_class_map, p, g, "sel_registerName");
+ }
+
+
+ // Emit method wrapper implementations and registration
+ auto wrapper_args = array_make<Type *>(temporary_allocator(), 2, 8);
+ auto get_context_args = array_make<lbValue>(temporary_allocator(), 1);
+
+
+ PtrMap<Type *, lbObjCGlobal> ivar_map{};
+ map_init(&ivar_map, gen->objc_ivars.count);
+
+ for (lbObjCGlobal g = {}; mpsc_dequeue(&gen->objc_ivars, &g); /**/) {
+ map_set(&ivar_map, g.class_impl_type, g);
}
- for (auto const &entry : m->objc_selectors) {
- String name = entry.key;
- args[0] = lb_const_value(m, t_cstring, exact_value_string(name));
- lbValue ptr = lb_emit_runtime_call(p, "sel_registerName", args);
- lb_addr_store(p, entry.value.local_module_addr, ptr);
+ for (const auto &cd : class_impls) {
+ auto &g = cd.g;
+
+ Type *class_type = g.class_impl_type;
+ Type *class_ptr_type = alloc_type_pointer(class_type);
+
+ // 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;
+
+ Entity *context_provider = class_type->Named.type_name->TypeName.objc_context_provider;
+ Type *contex_provider_self_ptr_type = nullptr;
+ Type *contex_provider_self_named_type = nullptr;
+ bool is_context_provider_ivar = false;
+ lbValue context_provider_proc_value{};
+
+ if (context_provider) {
+ context_provider_proc_value = lb_find_procedure_value_from_entity(m, context_provider);
+
+ contex_provider_self_ptr_type = base_type(context_provider->type->Proc.params->Tuple.variables[0]->type);
+ GB_ASSERT(contex_provider_self_ptr_type->kind == Type_Pointer);
+ contex_provider_self_named_type = base_named_type(type_deref(contex_provider_self_ptr_type));
+
+ 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;
+ }
+
+ // Check if it has any class methods ahead of time so that we know to grab the meta_class
+ lbValue meta_class_value = {};
+ for (const ObjcMethodData &md : *methods) {
+ if (!md.ac.objc_is_class_method) {
+ continue;
+ }
+
+ // Get the meta_class
+ args.count = 1;
+ args[0] = class_value;
+ meta_class_value = lb_emit_runtime_call(p, "object_getClass", args);
+
+ break;
+ }
+
+ for (const ObjcMethodData &md : *methods) {
+ GB_ASSERT( md.proc_entity->kind == Entity_Procedure);
+ Type *method_type = md.proc_entity->type;
+
+ String proc_name = make_string_c("__$objc_method::");
+ proc_name = concatenate_strings(temporary_allocator(), proc_name, g.name);
+ proc_name = concatenate_strings(temporary_allocator(), proc_name, str_lit("::"));
+ proc_name = concatenate_strings( permanent_allocator(), proc_name, md.ac.objc_name);
+
+ wrapper_args.count = 2;
+ wrapper_args[0] = md.ac.objc_is_class_method ? t_objc_Class : class_ptr_type;
+ wrapper_args[1] = t_objc_SEL;
+
+ isize method_param_count = method_type->Proc.param_count;
+ isize method_param_offset = 0;
+
+ if (!md.ac.objc_is_class_method) {
+ GB_ASSERT(method_param_count >= 1);
+ method_param_count -= 1;
+ method_param_offset = 1;
+ }
+
+ for (isize i = 0; i < method_param_count; i++) {
+ array_add(&wrapper_args, method_type->Proc.params->Tuple.variables[method_param_offset+i]->type);
+ }
+
+ Type *wrapper_args_tuple = alloc_type_tuple_from_field_types(wrapper_args.data, wrapper_args.count, false, true);
+ Type *wrapper_results_tuple = nullptr;
+
+ if (method_type->Proc.result_count > 0) {
+ GB_ASSERT(method_type->Proc.result_count == 1);
+ wrapper_results_tuple = alloc_type_tuple_from_field_types(&method_type->Proc.results->Tuple.variables[0]->type, 1, false, true);
+ }
+
+ Type *wrapper_proc_type = alloc_type_proc(nullptr, wrapper_args_tuple, wrapper_args_tuple->Tuple.variables.count,
+ 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_function_type_attributes(wrapper_proc->value, lb_get_function_type(m, wrapper_proc_type), ProcCC_CDecl);
+
+ // Emit the wrapper
+ // 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,
+ };
+
+ if (is_context_provider_ivar) {
+ // The context provider takes the ivar's type.
+ // Emit an objc_ivar_get call and use that pointer for 'self' instead.
+ lbValue real_self {
+ wrapper_proc->raw_input_parameters[0],
+ class_ptr_type
+ };
+ 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);
+ 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 = {};
+
+ 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) {
+ array_add(&raw_method_args, wrapper_proc->raw_input_parameters[method_forward_return_arg_offset]);
+ }
+
+ for (isize i = 0; i < method_param_count; i++) {
+ 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);
+ }
+
+ // Call real procedure for method from here, passing the parameters expected, if any.
+ 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 (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");
+
+ 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);
+ }
+
+ if (!md.ac.objc_is_class_method) {
+ method_encoding = concatenate_strings(temporary_allocator(), method_encoding, str_lit("@:"));
+ } else {
+ method_encoding = concatenate_strings(temporary_allocator(), method_encoding, str_lit("#:"));
+ }
+
+ 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);
+ }
+
+ // Emit method registration
+ lbAddr* sel_address = string_map_get(&m->objc_selectors, md.ac.objc_selector);
+ GB_ASSERT(sel_address);
+ lbValue selector_value = lb_addr_load(p, *sel_address);
+
+ lbValue target_class = !md.ac.objc_is_class_method ? class_value : meta_class_value;
+
+ args.count = 4;
+ args[0] = target_class; // Class
+ args[1] = selector_value; // SEL
+ 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?
+ lb_emit_runtime_call(p, "class_addMethod", args);
+
+ } // End methods
+
+ // Add ivar if we have one
+ if (ivar_type != nullptr) {
+ // Register a single ivar for this class
+ Type *ivar_base = ivar_type->Named.base;
+
+ // @note(harold): The alignment is supposed to be passed as log2(alignment): https://developer.apple.com/documentation/objectivec/class_addivar(_:_:_:_:_:)?language=objc
+ const i64 size = type_size_of(ivar_base);
+ const i64 alignment = (i64)floor_log2((u64)type_align_of(ivar_base));
+
+ // NOTE(harold): I've opted to not emit the type encoding for ivars in order to keep the data private.
+ // If there is desire in the future to emit the type encoding for introspection through the Obj-C runtime,
+ // then perhaps an option can be added for it then.
+ // Should we pass the actual type encoding? Might not be ideal for obfuscation.
+ String ivar_name = str_lit("__$ivar");
+ String ivar_types = str_lit("{= }"); //lb_get_objc_type_encoding(ivar_type);
+ args.count = 5;
+ args[0] = class_value;
+ args[1] = lb_const_value(m, t_cstring, exact_value_string(ivar_name));
+ args[2] = lb_const_value(m, t_uint, exact_value_u64((u64)size));
+ args[3] = lb_const_value(m, t_u8, exact_value_u64((u64)alignment));
+ args[4] = lb_const_value(m, t_cstring, exact_value_string(ivar_types));
+ lb_emit_runtime_call(p, "class_addIvar", args);
+ }
+
+ // Complete the class registration
+ args.count = 1;
+ args[0] = class_value;
+ lb_emit_runtime_call(p, "objc_registerClassPair", args);
+ }
+
+ // Register ivar offsets for any `objc_ivar_get` expressions emitted.
+ for (auto const& kv : ivar_map) {
+ lbObjCGlobal const& g = kv.value;
+ lbAddr ivar_addr = {};
+ lbValue *found = string_map_get(&m->members, g.global_name);
+
+ if (found) {
+ ivar_addr = lb_addr(*found);
+ GB_ASSERT(ivar_addr.addr.type == t_int_ptr);
+ } else {
+ // Defined in an external package, define it now in the main package
+ LLVMTypeRef t = lb_type(m, t_int);
+
+ lbValue global = {};
+ global.value = LLVMAddGlobal(m->mod, t, g.global_name);
+ global.type = t_int_ptr;
+
+ LLVMSetInitializer(global.value, LLVMConstInt(t, 0, true));
+
+ ivar_addr = lb_addr(global);
+ }
+
+ String class_name = g.class_impl_type->Named.type_name->TypeName.objc_class_name;
+ lbValue class_value = string_map_must_get(&global_class_map, class_name).class_value;
+
+ args.count = 2;
+ args[0] = class_value;
+ args[1] = lb_const_value(m, t_cstring, exact_value_string(str_lit("__$ivar")));
+ lbValue ivar = lb_emit_runtime_call(p, "class_getInstanceVariable", args);
+
+ args.count = 1;
+ args[0] = ivar;
+ lbValue ivar_offset = lb_emit_runtime_call(p, "ivar_getOffset", args);
+ lbValue ivar_offset_int = lb_emit_conv(p, ivar_offset, t_int);
+
+ lb_addr_store(p, ivar_addr, ivar_offset_int);
}
lb_end_procedure_body(p);
@@ -1179,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);
@@ -1200,114 +1989,151 @@ 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;
+
+ if (e->Variable.is_rodata) {
+ LLVMSetGlobalConstant(var.var.value, true);
+ }
+ return true;
+ }
+ } else {
+ var.init = init;
+ }
+ }
+
+ 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;
+}
- 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");
+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, var.init, 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_type_info(p, 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 (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);
+ LLVMSetVisibility(dummy->value, LLVMHiddenVisibility);
+ LLVMSetLinkage(dummy->value, LLVMWeakAnyLinkage);
+ 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;
+ LLVMBuildCall2(p->builder, raw_dummy_type, dummy->value, &context_ptr, 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);
+ LLVMSetLinkage(p->value, LLVMWeakAnyLinkage);
+
+ 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;
}
@@ -1319,6 +2145,10 @@ gb_internal lbProcedure *lb_create_cleanup_runtime(lbModule *main_module) { // C
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 cleanup on Linux.
+ LLVMSetVisibility(p->value, LLVMHiddenVisibility);
+ LLVMSetLinkage(p->value, LLVMWeakAnyLinkage);
+
lb_begin_procedure_body(p);
CheckerInfo *info = main_module->gen->info;
@@ -1344,7 +2174,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;
}
@@ -1368,8 +2198,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;
@@ -1393,7 +2221,7 @@ gb_internal void lb_create_global_procedures_and_types(lbGenerator *gen, Checker
break;
case Entity_Constant:
if (build_context.ODIN_DEBUG) {
- add_debug_info_for_global_constant_from_entity(gen, e);
+ lb_add_debug_info_for_global_constant_from_entity(gen, e);
}
break;
}
@@ -1406,18 +2234,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);
@@ -1529,7 +2367,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) {
@@ -1568,17 +2406,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);
@@ -1591,797 +2435,7 @@ gb_internal WORKER_TASK_PROC(lb_llvm_module_pass_worker_proc) {
LLVMPassBuilderOptionsRef pb_options = LLVMCreatePassBuilderOptions();
defer (LLVMDisposePassBuilderOptions(pb_options));
- switch (build_context.optimization_level) {
- case -1:
- array_add(&passes, "function(annotation-remarks)");
- break;
- case 0:
- array_add(&passes, "always-inline");
- array_add(&passes, "function(annotation-remarks)");
- break;
- case 1:
-// default<Os>
-// Passes removed: coro, openmp, sroa
-#if LLVM_VERSION_MAJOR == 17
- array_add(&passes, u8R"(
-annotation2metadata,
-forceattrs,
-inferattrs,
-function<eager-inv>(
- lower-expect,
- simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;no-switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,
- early-cse<>
-),
-ipsccp,
-called-value-propagation,
-globalopt,
-function<eager-inv>(
- mem2reg,
- instcombine<max-iterations=1000;no-use-loop-info>,
- simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>
-),
-require<globals-aa>,
-function(
- invalidate<aa>
-),
-require<profile-summary>,
-cgscc(
- devirt<4>(
- inline<only-mandatory>,
- inline,
- function-attrs<skip-non-recursive>,
- function<eager-inv;no-rerun>(
- early-cse<memssa>,
- speculative-execution,
- jump-threading,
- correlated-propagation,
- simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,
- instcombine<max-iterations=1000;no-use-loop-info>,
- aggressive-instcombine,
- constraint-elimination,
- tailcallelim,
- simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,
- reassociate,
- loop-mssa(
- loop-instsimplify,
- loop-simplifycfg,
- licm<no-allowspeculation>,
- loop-rotate<header-duplication;no-prepare-for-lto>,
- licm<allowspeculation>,
- simple-loop-unswitch<no-nontrivial;trivial>
- ),
- simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,
- instcombine<max-iterations=1000;no-use-loop-info>,
- loop(
- loop-idiom,
- indvars,
- loop-deletion,
- loop-unroll-full
- ),
- vector-combine,
- mldst-motion<no-split-footer-bb>,
- gvn<>,
- sccp,
- bdce,
- instcombine<max-iterations=1000;no-use-loop-info>,
- jump-threading,
- correlated-propagation,
- adce,
- memcpyopt,
- dse,
- move-auto-init,
- loop-mssa(
- licm<allowspeculation>
- ),
- simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;hoist-common-insts;sink-common-insts;speculate-blocks;simplify-cond-branch>,
- instcombine<max-iterations=1000;no-use-loop-info>
- ),
- function-attrs,
- function(
- require<should-not-run-function-passes>
- )
- )
-),
-deadargelim,
-globalopt,
-globaldce,
-elim-avail-extern,
-rpo-function-attrs,
-recompute-globalsaa,
-function<eager-inv>(
- float2int,
- lower-constant-intrinsics,
- loop(
- loop-rotate<header-duplication;no-prepare-for-lto>,
- loop-deletion
- ),
- loop-distribute,
- inject-tli-mappings,
- loop-vectorize<no-interleave-forced-only;no-vectorize-forced-only;>,
- loop-load-elim,
- instcombine<max-iterations=1000;no-use-loop-info>,
- simplifycfg<bonus-inst-threshold=1;forward-switch-cond;switch-range-to-icmp;switch-to-lookup;no-keep-loops;hoist-common-insts;sink-common-insts;speculate-blocks;simplify-cond-branch>,
- slp-vectorizer,
- vector-combine,
- instcombine<max-iterations=1000;no-use-loop-info>,
- loop-unroll<O2>,
- transform-warning,
- instcombine<max-iterations=1000;no-use-loop-info>,
- loop-mssa(
- licm<allowspeculation>
- ),
- alignment-from-assumptions,
- loop-sink,
- instsimplify,
- div-rem-pairs,
- tailcallelim,
- simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>
-),
-globaldce,
-constmerge,
-cg-profile,
-rel-lookup-table-converter,
-function(
- annotation-remarks
-),
-verify
-)");
-#else
- array_add(&passes, u8R"(
-annotation2metadata,
-forceattrs,
-inferattrs,
-function<eager-inv>(
- lower-expect,
- simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;no-switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,
- sroa<modify-cfg>,
- early-cse<>
-),
-ipsccp,
-called-value-propagation,
-globalopt,
-function<eager-inv>(
- mem2reg,
- instcombine<max-iterations=1;no-use-loop-info;no-verify-fixpoint>,
- simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>
-),
-always-inline,
-require<globals-aa>,
-function(
- invalidate<aa>
-),
-require<profile-summary>,
-cgscc(
- devirt<4>(
- inline,
- function-attrs<skip-non-recursive-function-attrs>,
- function<eager-inv;no-rerun>(
- sroa<modify-cfg>,
- early-cse<memssa>,
- speculative-execution<only-if-divergent-target>,
- jump-threading,
- correlated-propagation,
- simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,
- instcombine<max-iterations=1;no-use-loop-info;no-verify-fixpoint>,
- aggressive-instcombine,
- tailcallelim,
- simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,
- reassociate,
- constraint-elimination,
- loop-mssa(
- loop-instsimplify,
- loop-simplifycfg,
- licm<no-allowspeculation>,
- loop-rotate<header-duplication;no-prepare-for-lto>,
- licm<allowspeculation>,
- simple-loop-unswitch<no-nontrivial;trivial>
- ),
- simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,
- instcombine<max-iterations=1;no-use-loop-info;no-verify-fixpoint>,
- loop(
- loop-idiom,
- indvars,
- loop-deletion,
- loop-unroll-full
- ),
- sroa<modify-cfg>,
- vector-combine,
- mldst-motion<no-split-footer-bb>,
- gvn<>,
- sccp,
- bdce,
- instcombine<max-iterations=1;no-use-loop-info;no-verify-fixpoint>,
- jump-threading,
- correlated-propagation,
- adce,
- memcpyopt,
- dse,
- move-auto-init,
- loop-mssa(
- licm<allowspeculation>
- ),
- simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;hoist-common-insts;sink-common-insts;speculate-blocks;simplify-cond-branch>,
- instcombine<max-iterations=1;no-use-loop-info;no-verify-fixpoint>
- ),
- function-attrs,
- function(
- require<should-not-run-function-passes>
- )
- )
-),
-deadargelim,
-globalopt,
-globaldce,
-elim-avail-extern,
-rpo-function-attrs,
-recompute-globalsaa,
-function<eager-inv>(
- float2int,
- lower-constant-intrinsics,
- loop(
- loop-rotate<header-duplication;no-prepare-for-lto>,
- loop-deletion
- ),
- loop-distribute,
- inject-tli-mappings,
- loop-vectorize<no-interleave-forced-only;no-vectorize-forced-only;>,
- infer-alignment,
- loop-load-elim,
- instcombine<max-iterations=1;no-use-loop-info;no-verify-fixpoint>,
- simplifycfg<bonus-inst-threshold=1;forward-switch-cond;switch-range-to-icmp;switch-to-lookup;no-keep-loops;hoist-common-insts;sink-common-insts;speculate-blocks;simplify-cond-branch>,
- slp-vectorizer,
- vector-combine,
- instcombine<max-iterations=1;no-use-loop-info;no-verify-fixpoint>,
- loop-unroll<O2>,
- transform-warning,
- sroa<preserve-cfg>,
- infer-alignment,
- instcombine<max-iterations=1;no-use-loop-info;no-verify-fixpoint>,
- loop-mssa(
- licm<allowspeculation>
- ),
- alignment-from-assumptions,
- loop-sink,
- instsimplify,
- div-rem-pairs,
- tailcallelim,
- simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>
-),
-globaldce,
-constmerge,
-cg-profile,
-rel-lookup-table-converter,
-function(
- annotation-remarks
-),
-verify
-)");
-#endif
- break;
-// default<O2>
-// Passes removed: coro, openmp, sroa
- case 2:
-#if LLVM_VERSION_MAJOR == 17
- array_add(&passes, u8R"(
-annotation2metadata,
-forceattrs,
-inferattrs,
-function<eager-inv>(
- lower-expect,
- simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;no-switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,
- early-cse<>
-),
-ipsccp,
-called-value-propagation,
-globalopt,
-function<eager-inv>(
- mem2reg,
- instcombine<max-iterations=1000;no-use-loop-info>,
- simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>
-),
-require<globals-aa>,
-function(
- invalidate<aa>
-),
-require<profile-summary>,
-cgscc(
- devirt<4>(
- inline<only-mandatory>,
- inline,
- function-attrs<skip-non-recursive>,
- function<eager-inv;no-rerun>(
- early-cse<memssa>,
- speculative-execution,
- jump-threading,
- correlated-propagation,
- simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,
- instcombine<max-iterations=1000;no-use-loop-info>,
- aggressive-instcombine,
- constraint-elimination,
- libcalls-shrinkwrap,
- tailcallelim,
- simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,
- reassociate,
- loop-mssa(
- loop-instsimplify,
- loop-simplifycfg,
- licm<no-allowspeculation>,
- loop-rotate<header-duplication;no-prepare-for-lto>,
- licm<allowspeculation>,
- simple-loop-unswitch<no-nontrivial;trivial>
- ),
- simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,
- instcombine<max-iterations=1000;no-use-loop-info>,
- loop(
- loop-idiom,
- indvars,
- loop-deletion,
- loop-unroll-full
- ),
- vector-combine,
- mldst-motion<no-split-footer-bb>,
- gvn<>,
- sccp,
- bdce,
- instcombine<max-iterations=1000;no-use-loop-info>,
- jump-threading,
- correlated-propagation,
- adce,
- memcpyopt,
- dse,
- move-auto-init,
- loop-mssa(
- licm<allowspeculation>
- ),
- simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;hoist-common-insts;sink-common-insts;speculate-blocks;simplify-cond-branch>,
- instcombine<max-iterations=1000;no-use-loop-info>
- ),
- function-attrs,
- function(
- require<should-not-run-function-passes>
- )
- )
-),
-deadargelim,
-globalopt,
-globaldce,
-elim-avail-extern,
-rpo-function-attrs,
-recompute-globalsaa,
-function<eager-inv>(
- float2int,
- lower-constant-intrinsics,
- loop(
- loop-rotate<header-duplication;no-prepare-for-lto>,
- loop-deletion
- ),
- loop-distribute,
- inject-tli-mappings,
- loop-vectorize<no-interleave-forced-only;no-vectorize-forced-only;>,
- loop-load-elim,
- instcombine<max-iterations=1000;no-use-loop-info>,
- simplifycfg<bonus-inst-threshold=1;forward-switch-cond;switch-range-to-icmp;switch-to-lookup;no-keep-loops;hoist-common-insts;sink-common-insts;speculate-blocks;simplify-cond-branch>,
- slp-vectorizer,
- vector-combine,
- instcombine<max-iterations=1000;no-use-loop-info>,
- loop-unroll<O2>,
- transform-warning,
- instcombine<max-iterations=1000;no-use-loop-info>,
- loop-mssa(
- licm<allowspeculation>
- ),
- alignment-from-assumptions,
- loop-sink,
- instsimplify,
- div-rem-pairs,
- tailcallelim,
- simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>
-),
-globaldce,
-constmerge,
-cg-profile,
-rel-lookup-table-converter,
-function(
- annotation-remarks
-),
-verify
-)");
-#else
- array_add(&passes, u8R"(
-annotation2metadata,
-forceattrs,
-inferattrs,
-function<eager-inv>(
- lower-expect,
- simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;no-switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,
- sroa<modify-cfg>,
- early-cse<>
-),
-ipsccp,
-called-value-propagation,
-globalopt,
-function<eager-inv>(
- mem2reg,
- instcombine<max-iterations=1;no-use-loop-info;no-verify-fixpoint>,
- simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>
-),
-always-inline,
-require<globals-aa>,
-function(
- invalidate<aa>
-),
-require<profile-summary>,
-cgscc(
- devirt<4>(
- inline,
- function-attrs<skip-non-recursive-function-attrs>,
- function<eager-inv;no-rerun>(
- sroa<modify-cfg>,
- early-cse<memssa>,
- speculative-execution<only-if-divergent-target>,
- jump-threading,
- correlated-propagation,
- simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,
- instcombine<max-iterations=1;no-use-loop-info;no-verify-fixpoint>,
- aggressive-instcombine,
- libcalls-shrinkwrap,
- tailcallelim,
- simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,
- reassociate,
- constraint-elimination,
- loop-mssa(
- loop-instsimplify,
- loop-simplifycfg,
- licm<no-allowspeculation>,
- loop-rotate<header-duplication;no-prepare-for-lto>,
- licm<allowspeculation>,
- simple-loop-unswitch<no-nontrivial;trivial>
- ),
- simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,
- instcombine<max-iterations=1;no-use-loop-info;no-verify-fixpoint>,
- loop(
- loop-idiom,
- indvars,
- loop-deletion,
- loop-unroll-full
- ),
- sroa<modify-cfg>,
- vector-combine,
- mldst-motion<no-split-footer-bb>,
- gvn<>,
- sccp,
- bdce,
- instcombine<max-iterations=1;no-use-loop-info;no-verify-fixpoint>,
- jump-threading,
- correlated-propagation,
- adce,
- memcpyopt,
- dse,
- move-auto-init,
- loop-mssa(
- licm<allowspeculation>
- ),
- simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;hoist-common-insts;sink-common-insts;speculate-blocks;simplify-cond-branch>,
- instcombine<max-iterations=1;no-use-loop-info;no-verify-fixpoint>
- ),
- function-attrs,
- function(
- require<should-not-run-function-passes>
- )
- )
-),
-deadargelim,
-globalopt,
-globaldce,
-elim-avail-extern,
-rpo-function-attrs,
-recompute-globalsaa,
-function<eager-inv>(
- float2int,
- lower-constant-intrinsics,
- loop(
- loop-rotate<header-duplication;no-prepare-for-lto>,
- loop-deletion
- ),
- loop-distribute,
- inject-tli-mappings,
- loop-vectorize<no-interleave-forced-only;no-vectorize-forced-only;>,
- infer-alignment,
- loop-load-elim,
- instcombine<max-iterations=1;no-use-loop-info;no-verify-fixpoint>,
- simplifycfg<bonus-inst-threshold=1;forward-switch-cond;switch-range-to-icmp;switch-to-lookup;no-keep-loops;hoist-common-insts;sink-common-insts;speculate-blocks;simplify-cond-branch>,
- slp-vectorizer,
- vector-combine,
- instcombine<max-iterations=1;no-use-loop-info;no-verify-fixpoint>,
- loop-unroll<O2>,
- transform-warning,
- sroa<modify-cfg>,
- infer-alignment,
- instcombine<max-iterations=1;no-use-loop-info;no-verify-fixpoint>,
- loop-mssa(
- licm<allowspeculation>
- ),
- alignment-from-assumptions,
- loop-sink,
- instsimplify,
- div-rem-pairs,
- tailcallelim,
- simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>
-),
-globaldce,
-constmerge,
-cg-profile,
-rel-lookup-table-converter,
-function(
- annotation-remarks
-),
-verify
-)");
-#endif
- break;
-
- case 3:
-// default<O3>
-// Passes removed: coro, openmp, sroa
-#if LLVM_VERSION_MAJOR == 17
- array_add(&passes, u8R"(
-annotation2metadata,
-forceattrs,
-inferattrs,
-function<eager-inv>(
- lower-expect,
- simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;no-switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,
- early-cse<>,
- callsite-splitting
-),
-ipsccp,
-called-value-propagation,
-globalopt,
-function<eager-inv>(
- mem2reg,
- instcombine<max-iterations=1000;no-use-loop-info>,
- simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>
-),
-require<globals-aa>,
-function(
- invalidate<aa>
-),
-require<profile-summary>,
-cgscc(
- devirt<4>(
- inline<only-mandatory>,
- inline,
- function-attrs<skip-non-recursive>,
- argpromotion,
- function<eager-inv;no-rerun>(
- early-cse<memssa>,
- speculative-execution,
- jump-threading,
- correlated-propagation,
- simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,
- instcombine<max-iterations=1000;no-use-loop-info>,
- aggressive-instcombine,
- constraint-elimination,
- libcalls-shrinkwrap,
- tailcallelim,
- simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,
- reassociate,
- loop-mssa(
- loop-instsimplify,
- loop-simplifycfg,
- licm<no-allowspeculation>,
- loop-rotate<header-duplication;no-prepare-for-lto>,
- licm<allowspeculation>,
- simple-loop-unswitch<nontrivial;trivial>
- ),
- simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,
- instcombine<max-iterations=1000;no-use-loop-info>,
- loop(
- loop-idiom,
- indvars,
- loop-deletion,
- loop-unroll-full
- ),
- vector-combine,
- mldst-motion<no-split-footer-bb>,
- gvn<>,
- sccp,
- bdce,
- instcombine<max-iterations=1000;no-use-loop-info>,
- jump-threading,
- correlated-propagation,
- adce,
- memcpyopt,
- dse,
- move-auto-init,
- loop-mssa(
- licm<allowspeculation>
- ),
- simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;hoist-common-insts;sink-common-insts;speculate-blocks;simplify-cond-branch>,
- instcombine<max-iterations=1000;no-use-loop-info>
- ),
- function-attrs,
- function(
- require<should-not-run-function-passes>
- )
- )
-),
-deadargelim,
-globalopt,
-globaldce,
-elim-avail-extern,
-rpo-function-attrs,
-recompute-globalsaa,
-function<eager-inv>(
- float2int,
- lower-constant-intrinsics,
- chr,
- loop(
- loop-rotate<header-duplication;no-prepare-for-lto>,
- loop-deletion
- ),
- loop-distribute,
- inject-tli-mappings,
- loop-vectorize<no-interleave-forced-only;no-vectorize-forced-only;>,
- loop-load-elim,
- instcombine<max-iterations=1000;no-use-loop-info>,
- simplifycfg<bonus-inst-threshold=1;forward-switch-cond;switch-range-to-icmp;switch-to-lookup;no-keep-loops;hoist-common-insts;sink-common-insts;speculate-blocks;simplify-cond-branch>,
- slp-vectorizer,
- vector-combine,
- instcombine<max-iterations=1000;no-use-loop-info>,
- loop-unroll<O3>,
- transform-warning,
- instcombine<max-iterations=1000;no-use-loop-info>,
- loop-mssa(
- licm<allowspeculation>
- ),
- alignment-from-assumptions,
- loop-sink,
- instsimplify,
- div-rem-pairs,
- tailcallelim,
- simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>
-),
-globaldce,
-constmerge,
-cg-profile,
-rel-lookup-table-converter,
-function(
- annotation-remarks
-),
-verify
-)");
-#else
- array_add(&passes, u8R"(
-annotation2metadata,
-forceattrs,
-inferattrs,
-function<eager-inv>(
- lower-expect,
- simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;no-switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,
- sroa<modify-cfg>,
- early-cse<>,
- callsite-splitting
-),
-ipsccp,
-called-value-propagation,
-globalopt,
-function<eager-inv>(
- mem2reg,
- instcombine<max-iterations=1;no-use-loop-info;no-verify-fixpoint>,
- simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>
-),
-always-inline,
-require<globals-aa>,
-function(invalidate<aa>),
-require<profile-summary>,
-cgscc(
- devirt<4>(
- inline,
- function-attrs<skip-non-recursive-function-attrs>,
- argpromotion,
- function<eager-inv;no-rerun>(
- sroa<modify-cfg>,
- early-cse<memssa>,
- speculative-execution<only-if-divergent-target>,
- jump-threading,
- correlated-propagation,
- simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,
- instcombine<max-iterations=1;no-use-loop-info;no-verify-fixpoint>,
- aggressive-instcombine,
- libcalls-shrinkwrap,
- tailcallelim,
- simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,
- reassociate,
- constraint-elimination,
- loop-mssa(
- loop-instsimplify,
- loop-simplifycfg,
- licm<no-allowspeculation>,
- loop-rotate<header-duplication;no-prepare-for-lto>,
- licm<allowspeculation>,
- simple-loop-unswitch<nontrivial;trivial>
- ),
- simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,
- instcombine<max-iterations=1;no-use-loop-info;no-verify-fixpoint>,
- loop(
- loop-idiom,
- indvars,
- loop-deletion,
- loop-unroll-full
- ),
- sroa<modify-cfg>,
- vector-combine,
- mldst-motion<no-split-footer-bb>,
- gvn<>,
- sccp,
- bdce,
- instcombine<max-iterations=1;no-use-loop-info;no-verify-fixpoint>,
- jump-threading,
- correlated-propagation,
- adce,
- memcpyopt,
- dse,
- move-auto-init,
- loop-mssa(licm<allowspeculation>),
- simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;hoist-common-insts;sink-common-insts;speculate-blocks;simplify-cond-branch>,
- instcombine<max-iterations=1;no-use-loop-info;no-verify-fixpoint>
- ),
- function-attrs,
- function(
- require<should-not-run-function-passes>
- )
- )
-),
-deadargelim,
-globalopt,
-globaldce,
-elim-avail-extern,
-rpo-function-attrs,
-recompute-globalsaa,
-function<eager-inv>(
- float2int,
- lower-constant-intrinsics,
- chr,
- loop(
- loop-rotate<header-duplication;no-prepare-for-lto>,
- loop-deletion
- ),
- loop-distribute,
- inject-tli-mappings,
- loop-vectorize<no-interleave-forced-only;no-vectorize-forced-only;>,
- infer-alignment,
- loop-load-elim,
- instcombine<max-iterations=1;no-use-loop-info;no-verify-fixpoint>,
- simplifycfg<bonus-inst-threshold=1;forward-switch-cond;switch-range-to-icmp;switch-to-lookup;no-keep-loops;hoist-common-insts;sink-common-insts;speculate-blocks;simplify-cond-branch>,
- slp-vectorizer,
- vector-combine,
- instcombine<max-iterations=1;no-use-loop-info;no-verify-fixpoint>,
- loop-unroll<O3>,
- transform-warning,
- sroa<preserve-cfg>,
- infer-alignment,
- instcombine<max-iterations=1;no-use-loop-info;no-verify-fixpoint>,
- loop-mssa(licm<allowspeculation>),
- alignment-from-assumptions,
- loop-sink,
- instsimplify,
- div-rem-pairs,
- tailcallelim,
- simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>
-),
-globaldce,
-constmerge,
-cg-profile,
-rel-lookup-table-converter,
-function(
- annotation-remarks
-),
-verify
-)");
-#endif
- break;
- }
+ #include "llvm_backend_passes.cpp"
// asan - Linux, Darwin, Windows
// msan - linux
@@ -2444,6 +2498,17 @@ verify
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;
}
@@ -2451,8 +2516,7 @@ verify
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;
@@ -2476,10 +2540,15 @@ 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;
}
@@ -2499,6 +2568,12 @@ 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;
+ 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) {
@@ -2526,19 +2601,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 {
@@ -2547,6 +2619,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);
}
}
@@ -2589,10 +2662,8 @@ gb_internal String lb_filepath_obj_for_module(lbModule *m) {
gbString path = gb_string_make_length(heap_allocator(), basename.text, basename.len);
path = gb_string_appendc(path, "/");
- path = gb_string_append_length(path, name.text, name.len);
-
- {
+ if (USE_SEPARATE_MODULES) {
GB_ASSERT(m->module_name != nullptr);
String s = make_string_c(m->module_name);
String prefix = str_lit("odin_package");
@@ -2602,6 +2673,8 @@ gb_internal String lb_filepath_obj_for_module(lbModule *m) {
}
path = gb_string_append_length(path, s.text, s.len);
+ } else {
+ path = gb_string_append_length(path, name.text, name.len);
}
if (use_temporary_directory) {
@@ -2612,69 +2685,21 @@ gb_internal String lb_filepath_obj_for_module(lbModule *m) {
String ext = {};
if (build_context.build_mode == BuildMode_Assembly) {
- ext = STR_LIT(".S");
+ ext = STR_LIT("S");
+ } else if (build_context.build_mode == BuildMode_Object) {
+ // Allow a user override for the object extension.
+ ext = build_context.build_paths[BuildPath_Output].ext;
} else {
- if (is_arch_wasm()) {
- ext = STR_LIT(".wasm.o");
- } else {
- switch (build_context.metrics.os) {
- case TargetOs_windows:
- ext = STR_LIT(".obj");
- break;
- default:
- case TargetOs_darwin:
- case TargetOs_linux:
- case TargetOs_essence:
- ext = STR_LIT(".o");
- break;
-
- case TargetOs_freestanding:
- switch (build_context.metrics.abi) {
- default:
- case TargetABI_Default:
- case TargetABI_SysV:
- ext = STR_LIT(".o");
- break;
- case TargetABI_Win64:
- ext = STR_LIT(".obj");
- break;
- }
- break;
- }
- }
+ ext = infer_object_extension_from_build_context();
}
+ path = gb_string_append_length(path, ".", 1);
path = gb_string_append_length(path, ext.text, ext.len);
return make_string(cast(u8 *)path, gb_string_length(path));
}
-
-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;
@@ -2770,8 +2795,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;
@@ -2826,8 +2858,8 @@ gb_internal lbProcedure *lb_create_main_procedure(lbModule *m, lbProcedure *star
if (testing_proc->pkg != nullptr) {
pkg_name = testing_proc->pkg->name;
}
- lbValue v_pkg = lb_find_or_add_entity_string(m, pkg_name);
- lbValue v_name = lb_find_or_add_entity_string(m, name);
+ lbValue v_pkg = lb_find_or_add_entity_string(m, pkg_name, false);
+ lbValue v_name = lb_find_or_add_entity_string(m, name, false);
lbValue v_proc = lb_find_procedure_value_from_entity(m, testing_proc);
indices[1] = LLVMConstInt(lb_type(m, t_int), testing_proc_index++, false);
@@ -2897,18 +2929,20 @@ 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);
}
- lb_end_procedure(p);
// Add Flags
if (p->entity && p->entity->kind == Entity_Procedure && p->entity->Procedure.is_memcpy_like) {
@@ -2916,6 +2950,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);
}
@@ -2930,8 +2967,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:
@@ -2959,13 +2994,24 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
LLVMInitializeWebAssemblyAsmParser();
LLVMInitializeWebAssemblyDisassembler();
break;
+ case TargetArch_riscv64:
+ LLVMInitializeRISCVTargetInfo();
+ LLVMInitializeRISCVTarget();
+ LLVMInitializeRISCVTargetMC();
+ LLVMInitializeRISCVAsmPrinter();
+ LLVMInitializeRISCVAsmParser();
+ LLVMInitializeRISCVDisassembler();
+ break;
+ case TargetArch_arm32:
+ LLVMInitializeARMTargetInfo();
+ LLVMInitializeARMTarget();
+ LLVMInitializeARMTargetMC();
+ LLVMInitializeARMAsmPrinter();
+ LLVMInitializeARMAsmParser();
+ LLVMInitializeARMDisassembler();
+ break;
default:
- LLVMInitializeAllTargetInfos();
- LLVMInitializeAllTargets();
- LLVMInitializeAllTargetMCs();
- LLVMInitializeAllAsmPrinters();
- LLVMInitializeAllAsmParsers();
- LLVMInitializeAllDisassemblers();
+ GB_PANIC("Unimplemented LLVM target initialization");
break;
}
@@ -3206,6 +3252,7 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
LLVMSetInitializer(g, LLVMConstNull(lb_type(m, t)));
LLVMSetLinkage(g, LLVMInternalLinkage);
lb_make_global_private_const(g);
+ lb_set_odin_rtti_section(g);
return lb_addr({g, alloc_type_pointer(t)});
};
@@ -3235,6 +3282,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" ||
@@ -3257,7 +3305,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;
}
@@ -3267,69 +3315,49 @@ 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);
+ lbModule *m = default_module;
+ lbModule *e_module = lb_module_of_entity(gen, e, default_module);
- lbValue g = {};
- g.value = LLVMAddGlobal(m->mod, lb_type(m, e->type), alloc_cstring(permanent_allocator(), name));
- g.type = alloc_type_pointer(e->type);
- if (e->Variable.thread_local_model != "") {
- LLVMSetThreadLocal(g.value, true);
-
- String m = e->Variable.thread_local_model;
- LLVMThreadLocalMode mode = LLVMGeneralDynamicTLSModel;
- if (m == "default") {
- mode = LLVMGeneralDynamicTLSModel;
- } else if (m == "localdynamic") {
- mode = LLVMLocalDynamicTLSModel;
- } else if (m == "initialexec") {
- mode = LLVMInitialExecTLSModel;
- } else if (m == "localexec") {
- mode = LLVMLocalExecTLSModel;
- } else {
- GB_PANIC("Unhandled thread local mode %.*s", LIT(m));
- }
- LLVMSetThreadLocalMode(g.value, mode);
- }
- 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);
-
- 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) {
- bool is_rodata = e->kind == Entity_Variable && e->Variable.is_rodata;
+ auto cc = LB_CONST_CONTEXT_DEFAULT;
+ cc.is_rodata = e->kind == Entity_Variable && e->Variable.is_rodata;
+ cc.allow_local = false;
+ cc.link_section = e->Variable.link_section;
+
ExactValue v = tav.value;
- lbValue init = lb_const_value(m, tav.type, v, false, is_rodata);
+ 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 (is_rodata) {
+ if (cc.is_rodata) {
LLVMSetGlobalConstant(g.value, true);
}
}
@@ -3344,11 +3372,33 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
} else if (e->kind == Entity_Variable && e->Variable.is_rodata) {
LLVMSetGlobalConstant(g.value, true);
}
- array_add(&global_variables, var);
- lb_add_entity(m, e, g);
- lb_add_member(m, name, g);
+ lb_apply_thread_local_model(g.value, e->Variable.thread_local_model);
+
+ 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) {
+ 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));
+ }
+ if (e->flags & EntityFlag_Require) {
+ lb_append_to_compiler_used(m, g.value);
+ }
if (m->debug_builder) {
String global_name = e->token.string;
@@ -3378,6 +3428,49 @@ 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) {
+ // Custom `.raddbg` section for its debugger
+ if (build_context.metrics.os == TargetOs_windows) {
+ lbModule *m = default_module;
+ LLVMModuleRef mod = m->mod;
+ LLVMContextRef ctx = m->ctx;
+
+ {
+ LLVMTypeRef type = LLVMArrayType(LLVMInt8TypeInContext(ctx), 1);
+ LLVMValueRef global = LLVMAddGlobal(mod, type, "raddbg_is_attached_byte_marker");
+ LLVMSetInitializer(global, LLVMConstNull(type));
+ LLVMSetSection(global, ".raddbg");
+ }
+
+ if (gen->info->entry_point) {
+ String mangled_name = lb_get_entity_name(m, gen->info->entry_point);
+ char const *str = alloc_cstring(temporary_allocator(), mangled_name);
+ lb_add_raddbg_string(m, "entry_point: \"", str, "\"");
+ }
+ }
}
TIME_SECTION("LLVM Runtime Objective-C Names Creation");
@@ -3393,7 +3486,7 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
if (build_context.ODIN_DEBUG) {
for (auto const &entry : builtin_pkg->scope->elements) {
Entity *e = entry.value;
- add_debug_info_for_global_constant_from_entity(gen, e);
+ lb_add_debug_info_for_global_constant_from_entity(gen, e);
}
}
@@ -3417,12 +3510,101 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
if (gen->objc_names) {
TIME_SECTION("Finalize objc names");
- lb_finalize_objc_names(gen->objc_names);
+ lb_finalize_objc_names(gen, gen->objc_names);
}
if (build_context.ODIN_DEBUG) {
TIME_SECTION("LLVM Debug Info Complete Types and Finalize");
lb_debug_info_complete_types_and_finalize(gen);
+
+ // Custom `.raddbg` section for its debugger
+ if (build_context.metrics.os == TargetOs_windows) {
+ lbModule *m = default_module;
+ LLVMModuleRef mod = m->mod;
+ LLVMContextRef ctx = m->ctx;
+
+ lb_add_raddbg_string(m, "type_view: {type: \"[]?\", expr: \"array(data, len)\"}");
+ lb_add_raddbg_string(m, "type_view: {type: \"string\", expr: \"array(data, len)\"}");
+ lb_add_raddbg_string(m, "type_view: {type: \"[dynamic]?\", expr: \"rows($, array(data, len), len, cap, allocator)\"}");
+
+ // column major matrices
+ lb_add_raddbg_string(m, "type_view: {type: \"matrix[1, ?]?\", expr: \"columns($.data, $[0])\"}");
+ lb_add_raddbg_string(m, "type_view: {type: \"matrix[2, ?]?\", expr: \"columns($.data, $[0], $[1])\"}");
+ lb_add_raddbg_string(m, "type_view: {type: \"matrix[3, ?]?\", expr: \"columns($.data, $[0], $[1], $[2])\"}");
+ lb_add_raddbg_string(m, "type_view: {type: \"matrix[4, ?]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3])\"}");
+ lb_add_raddbg_string(m, "type_view: {type: \"matrix[5, ?]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4])\"}");
+ lb_add_raddbg_string(m, "type_view: {type: \"matrix[6, ?]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5])\"}");
+ lb_add_raddbg_string(m, "type_view: {type: \"matrix[7, ?]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6])\"}");
+ lb_add_raddbg_string(m, "type_view: {type: \"matrix[8, ?]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7])\"}");
+ lb_add_raddbg_string(m, "type_view: {type: \"matrix[9, ?]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7], $[8])\"}");
+ lb_add_raddbg_string(m, "type_view: {type: \"matrix[10, ?]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7], $[8], $[9])\"}");
+ lb_add_raddbg_string(m, "type_view: {type: \"matrix[11, ?]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7], $[8], $[9], $[10])\"}");
+ lb_add_raddbg_string(m, "type_view: {type: \"matrix[12, ?]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7], $[8], $[9], $[10], $[11])\"}");
+ lb_add_raddbg_string(m, "type_view: {type: \"matrix[13, ?]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7], $[8], $[9], $[10], $[11], $[12])\"}");
+ lb_add_raddbg_string(m, "type_view: {type: \"matrix[14, ?]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7], $[8], $[9], $[10], $[11], $[12], $[13])\"}");
+ lb_add_raddbg_string(m, "type_view: {type: \"matrix[15, ?]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7], $[8], $[9], $[10], $[11], $[12], $[13], $[14])\"}");
+ lb_add_raddbg_string(m, "type_view: {type: \"matrix[16, ?]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7], $[8], $[9], $[10], $[11], $[12], $[13], $[14], $[15])\"}");
+
+ // row major matrices
+ lb_add_raddbg_string(m, "type_view: {type: \"#row_major matrix[?, 1]?\", expr: \"columns($.data, $[0])\"}");
+ lb_add_raddbg_string(m, "type_view: {type: \"#row_major matrix[?, 2]?\", expr: \"columns($.data, $[0], $[1])\"}");
+ lb_add_raddbg_string(m, "type_view: {type: \"#row_major matrix[?, 3]?\", expr: \"columns($.data, $[0], $[1], $[2])\"}");
+ lb_add_raddbg_string(m, "type_view: {type: \"#row_major matrix[?, 4]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3])\"}");
+ lb_add_raddbg_string(m, "type_view: {type: \"#row_major matrix[?, 5]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4])\"}");
+ lb_add_raddbg_string(m, "type_view: {type: \"#row_major matrix[?, 6]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5])\"}");
+ lb_add_raddbg_string(m, "type_view: {type: \"#row_major matrix[?, 7]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6])\"}");
+ lb_add_raddbg_string(m, "type_view: {type: \"#row_major matrix[?, 8]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7])\"}");
+ lb_add_raddbg_string(m, "type_view: {type: \"#row_major matrix[?, 9]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7], $[8])\"}");
+ lb_add_raddbg_string(m, "type_view: {type: \"#row_major matrix[?, 10]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7], $[8], $[9])\"}");
+ lb_add_raddbg_string(m, "type_view: {type: \"#row_major matrix[?, 11]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7], $[8], $[9], $[10])\"}");
+ lb_add_raddbg_string(m, "type_view: {type: \"#row_major matrix[?, 12]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7], $[8], $[9], $[10], $[11])\"}");
+ lb_add_raddbg_string(m, "type_view: {type: \"#row_major matrix[?, 13]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7], $[8], $[9], $[10], $[11], $[12])\"}");
+ lb_add_raddbg_string(m, "type_view: {type: \"#row_major matrix[?, 14]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7], $[8], $[9], $[10], $[11], $[12], $[13])\"}");
+ lb_add_raddbg_string(m, "type_view: {type: \"#row_major matrix[?, 15]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7], $[8], $[9], $[10], $[11], $[12], $[13], $[14])\"}");
+ lb_add_raddbg_string(m, "type_view: {type: \"#row_major matrix[?, 16]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7], $[8], $[9], $[10], $[11], $[12], $[13], $[14], $[15])\"}");
+
+
+ TEMPORARY_ALLOCATOR_GUARD();
+ for (RaddbgTypeView const &type_view : gen->info->raddbg_type_views) {
+ if (type_view.type == nullptr) {
+ continue;
+ }
+
+ if (type_view.view.len == 0) {
+ continue;
+ }
+
+ String t_str = type_to_canonical_string(temporary_allocator(), type_view.type);
+
+ gbString s = gb_string_make(temporary_allocator(), "");
+
+ s = gb_string_appendc(s, "type_view: {type: \"");
+ s = gb_string_append_length(s, t_str.text, t_str.len);
+ s = gb_string_appendc(s, "\", expr: \"");
+ s = gb_string_append_length(s, type_view.view.text, type_view.view.len);
+ s = gb_string_appendc(s, "\"}");
+
+ lb_add_raddbg_string(m, s);
+ }
+
+ TEMPORARY_ALLOCATOR_GUARD();
+ u32 global_name_index = 0;
+ for (String str = {}; mpsc_dequeue(&gen->raddebug_section_strings, &str); /**/) {
+ LLVMValueRef data = LLVMConstStringInContext(ctx, cast(char const *)str.text, cast(unsigned)str.len, false);
+ LLVMTypeRef type = LLVMTypeOf(data);
+
+ gbString global_name = gb_string_make(temporary_allocator(), "raddbg_data__");
+ global_name = gb_string_append_fmt(global_name, "%u", global_name_index);
+ global_name_index += 1;
+
+ LLVMValueRef global = LLVMAddGlobal(mod, type, global_name);
+
+ LLVMSetInitializer(global, data);
+ LLVMSetAlignment(global, 1);
+
+ LLVMSetSection(global, ".raddbg");
+ }
+ }
}
if (do_threading) {
@@ -3438,15 +3620,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;
@@ -3475,11 +3665,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) {
@@ -3505,36 +3690,48 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
if (build_context.sanitizer_flags & SanitizerFlag_Address) {
- if (build_context.metrics.os == TargetOs_windows) {
+ switch (build_context.metrics.os) {
+ case TargetOs_windows: {
auto paths = array_make<String>(heap_allocator(), 0, 1);
String path = concatenate_strings(permanent_allocator(), build_context.ODIN_ROOT, str_lit("\\bin\\llvm\\windows\\clang_rt.asan-x86_64.lib"));
array_add(&paths, path);
Entity *lib = alloc_entity_library_name(nullptr, make_token_ident("asan_lib"), nullptr, slice_from_array(paths), str_lit("asan_lib"));
array_add(&gen->foreign_libraries, lib);
- } else if (build_context.metrics.os == TargetOs_darwin || build_context.metrics.os == TargetOs_linux) {
+ } break;
+ case TargetOs_darwin:
+ case TargetOs_linux:
+ case TargetOs_freebsd:
if (!build_context.extra_linker_flags.text) {
build_context.extra_linker_flags = str_lit("-fsanitize=address");
} else {
build_context.extra_linker_flags = concatenate_strings(permanent_allocator(), build_context.extra_linker_flags, str_lit(" -fsanitize=address"));
}
+ break;
}
}
if (build_context.sanitizer_flags & SanitizerFlag_Memory) {
- if (build_context.metrics.os == TargetOs_darwin || build_context.metrics.os == TargetOs_linux) {
+ switch (build_context.metrics.os) {
+ case TargetOs_linux:
+ case TargetOs_freebsd:
if (!build_context.extra_linker_flags.text) {
build_context.extra_linker_flags = str_lit("-fsanitize=memory");
} else {
build_context.extra_linker_flags = concatenate_strings(permanent_allocator(), build_context.extra_linker_flags, str_lit(" -fsanitize=memory"));
}
+ break;
}
}
if (build_context.sanitizer_flags & SanitizerFlag_Thread) {
- if (build_context.metrics.os == TargetOs_darwin || build_context.metrics.os == TargetOs_linux) {
+ switch (build_context.metrics.os) {
+ case TargetOs_darwin:
+ case TargetOs_linux:
+ case TargetOs_freebsd:
if (!build_context.extra_linker_flags.text) {
build_context.extra_linker_flags = str_lit("-fsanitize=thread");
} else {
build_context.extra_linker_flags = concatenate_strings(permanent_allocator(), build_context.extra_linker_flags, str_lit(" -fsanitize=thread"));
}
+ break;
}
}