aboutsummaryrefslogtreecommitdiff
path: root/src/llvm_backend.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/llvm_backend.cpp')
-rw-r--r--src/llvm_backend.cpp227
1 files changed, 154 insertions, 73 deletions
diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp
index b47e2788f..23efa8d22 100644
--- a/src/llvm_backend.cpp
+++ b/src/llvm_backend.cpp
@@ -37,12 +37,10 @@ gb_internal String get_default_microarchitecture() {
// x86-64-v2: (close to Nehalem) CMPXCHG16B, LAHF-SAHF, POPCNT, SSE3, SSE4.1, SSE4.2, SSSE3
// x86-64-v3: (close to Haswell) AVX, AVX2, BMI1, BMI2, F16C, FMA, LZCNT, MOVBE, XSAVE
// x86-64-v4: AVX512F, AVX512BW, AVX512CD, AVX512DQ, AVX512VL
- if (ODIN_LLVM_MINIMUM_VERSION_12) {
- if (build_context.metrics.os == TargetOs_freestanding) {
- default_march = str_lit("x86-64");
- } else {
- default_march = str_lit("x86-64-v2");
- }
+ if (build_context.metrics.os == TargetOs_freestanding) {
+ default_march = str_lit("x86-64");
+ } else {
+ default_march = str_lit("x86-64-v2");
}
} else if (build_context.metrics.arch == TargetArch_riscv64) {
default_march = str_lit("generic-rv64");
@@ -1417,8 +1415,21 @@ String lb_get_objc_type_encoding(Type *t, isize pointer_depth = 0) {
return str_lit("?");
case Type_Proc:
return str_lit("?");
- case Type_BitSet:
- return lb_get_objc_type_encoding(t->BitSet.underlying, pointer_depth);
+ case Type_BitSet: {
+ Type *bitset_integer_type = t->BitSet.underlying;
+ if (!bitset_integer_type) {
+ switch (t->cached_size) {
+ case 1: bitset_integer_type = t_u8; break;
+ case 2: bitset_integer_type = t_u16; break;
+ case 4: bitset_integer_type = t_u32; break;
+ case 8: bitset_integer_type = t_u64; break;
+ case 16: bitset_integer_type = t_u128; break;
+ }
+ }
+ GB_ASSERT_MSG(bitset_integer_type, "Could not determine bit_set integer size for objc_type_encoding");
+
+ return lb_get_objc_type_encoding(bitset_integer_type, pointer_depth);
+ }
case Type_SimdVector: {
String type_str = lb_get_objc_type_encoding(t->SimdVector.elem, pointer_depth);
@@ -1452,7 +1463,10 @@ String lb_get_objc_type_encoding(Type *t, isize pointer_depth = 0) {
struct lbObjCGlobalClass {
lbObjCGlobal g;
- lbValue class_value; // Local registered class value
+ union {
+ lbValue class_value; // Local registered class value
+ lbAddr class_global; // Global class pointer. Placeholder for class implementations which are registered in order of definition.
+ };
};
gb_internal void lb_register_objc_thing(
@@ -1482,44 +1496,43 @@ gb_internal void lb_register_objc_thing(
LLVMSetInitializer(v.value, LLVMConstNull(t));
}
- lbValue class_ptr = {};
- lbValue class_name = lb_const_value(m, t_cstring, exact_value_string(g.name));
-
// If this class requires an implementation, save it for registration below.
if (g.class_impl_type != nullptr) {
// Make sure the superclass has been initialized before us
- lbValue superclass_value = lb_const_nil(m, t_objc_Class);
-
auto &tn = g.class_impl_type->Named.type_name->TypeName;
Type *superclass = tn.objc_superclass;
if (superclass != nullptr) {
auto& superclass_global = string_map_must_get(&class_map, superclass->Named.type_name->TypeName.objc_class_name);
lb_register_objc_thing(handled, m, args, class_impls, class_map, p, superclass_global.g, call);
- GB_ASSERT(superclass_global.class_value.value);
-
- superclass_value = superclass_global.class_value;
+ GB_ASSERT(superclass_global.class_global.addr.value);
}
- args.count = 3;
- args[0] = superclass_value;
- args[1] = class_name;
- args[2] = lb_const_int(m, t_uint, 0);
- class_ptr = lb_emit_runtime_call(p, "objc_allocateClassPair", args);
+ lbObjCGlobalClass impl_global = {};
+ impl_global.g = g;
+ impl_global.class_global = addr;
+
+ array_add(&class_impls, impl_global);
- array_add(&class_impls, lbObjCGlobalClass{g, class_ptr});
+ lbObjCGlobalClass* class_global = string_map_get(&class_map, g.name);
+ if (class_global != nullptr) {
+ class_global->class_global = addr;
+ }
}
else {
+ lbValue class_ptr = {};
+ lbValue class_name = lb_const_value(m, t_cstring, exact_value_string(g.name));
+
args.count = 1;
args[0] = class_name;
class_ptr = lb_emit_runtime_call(p, call, args);
- }
- lb_addr_store(p, addr, class_ptr);
+ lb_addr_store(p, addr, class_ptr);
- lbObjCGlobalClass* class_global = string_map_get(&class_map, g.name);
- if (class_global != nullptr) {
- class_global->class_value = class_ptr;
+ lbObjCGlobalClass* class_global = string_map_get(&class_map, g.name);
+ if (class_global != nullptr) {
+ class_global->class_value = class_ptr;
+ }
}
}
@@ -1582,7 +1595,7 @@ gb_internal void lb_finalize_objc_names(lbGenerator *gen, lbProcedure *p) {
string_map_init(&global_class_map, (usize)gen->objc_classes.count);
defer (string_map_destroy(&global_class_map));
- for (lbObjCGlobal g :referenced_classes) {
+ for (lbObjCGlobal g : referenced_classes) {
string_map_set(&global_class_map, g.name, lbObjCGlobalClass{g});
}
@@ -1629,9 +1642,36 @@ gb_internal void lb_finalize_objc_names(lbGenerator *gen, lbProcedure *p) {
for (const auto &cd : class_impls) {
auto &g = cd.g;
- Type *class_type = g.class_impl_type;
+
+ Type *class_type = g.class_impl_type;
Type *class_ptr_type = alloc_type_pointer(class_type);
- lbValue class_value = cd.class_value;
+
+ // Begin class registration: create class pair and update global reference
+ lbValue class_value = {};
+
+ {
+ lbValue superclass_value = lb_const_nil(m, t_objc_Class);
+
+ auto& tn = class_type->Named.type_name->TypeName;
+ Type *superclass = tn.objc_superclass;
+
+ if (superclass != nullptr) {
+ auto& superclass_global = string_map_must_get(&global_class_map, superclass->Named.type_name->TypeName.objc_class_name);
+ superclass_value = superclass_global.class_value;
+ }
+
+ args.count = 3;
+ args[0] = superclass_value;
+ args[1] = lb_const_value(m, t_cstring, exact_value_string(g.name));
+ args[2] = lb_const_int(m, t_uint, 0);
+ class_value = lb_emit_runtime_call(p, "objc_allocateClassPair", args);
+
+ lbObjCGlobalClass &mapped_global = string_map_must_get(&global_class_map, tn.objc_class_name);
+ lb_addr_store(p, mapped_global.class_global, class_value);
+
+ mapped_global.class_value = class_value;
+ }
+
Type *ivar_type = class_type->Named.type_name->TypeName.objc_ivar;
@@ -1651,7 +1691,6 @@ gb_internal void lb_finalize_objc_names(lbGenerator *gen, lbProcedure *p) {
is_context_provider_ivar = ivar_type != nullptr && internal_check_is_assignable_to(contex_provider_self_named_type, ivar_type);
}
-
Array<ObjcMethodData> *methods = map_get(&m->info->objc_method_implementations, class_type);
if (!methods) {
continue;
@@ -1710,17 +1749,21 @@ gb_internal void lb_finalize_objc_names(lbGenerator *gen, lbProcedure *p) {
wrapper_results_tuple, method_type->Proc.result_count, false, ProcCC_CDecl);
lbProcedure *wrapper_proc = lb_create_dummy_procedure(m, proc_name, wrapper_proc_type);
- lb_add_attribute_to_proc(wrapper_proc->module, wrapper_proc->value, "nounwind");
+
+ lb_add_function_type_attributes(wrapper_proc->value, lb_get_function_type(m, wrapper_proc_type), ProcCC_CDecl);
// Emit the wrapper
- LLVMSetLinkage(wrapper_proc->value, LLVMExternalLinkage);
+ // LLVMSetLinkage(wrapper_proc->value, LLVMInternalLinkage);
+ LLVMSetDLLStorageClass(wrapper_proc->value, LLVMDLLExportStorageClass);
+ lb_add_attribute_to_proc(wrapper_proc->module, wrapper_proc->value, "nounwind");
+
lb_begin_procedure_body(wrapper_proc);
{
+ LLVMValueRef context_addr = nullptr;
if (method_type->Proc.calling_convention == ProcCC_Odin) {
GB_ASSERT(context_provider);
// Emit the get odin context call
-
get_context_args[0] = lbValue {
wrapper_proc->raw_input_parameters[0],
contex_provider_self_ptr_type,
@@ -1736,44 +1779,58 @@ gb_internal void lb_finalize_objc_names(lbGenerator *gen, lbProcedure *p) {
get_context_args[0] = lb_handle_objc_ivar_for_objc_object_pointer(wrapper_proc, real_self);
}
- lbValue context = lb_emit_call(wrapper_proc, context_provider_proc_value, get_context_args);
- lbAddr context_addr = lb_addr(lb_address_from_load_or_generate_local(wrapper_proc, context));
- lb_push_context_onto_stack(wrapper_proc, context_addr);
+ lbValue context = lb_emit_call(wrapper_proc, context_provider_proc_value, get_context_args);
+ context_addr = lb_address_from_load(wrapper_proc, context).value;//lb_address_from_load_or_generate_local(wrapper_proc, context));
+ // context_addr = LLVMGetOperand(context.value, 0);
}
+ isize method_forward_arg_count = method_param_count + method_param_offset;
+ isize method_forward_return_arg_offset = 0;
+ auto raw_method_args = array_make<LLVMValueRef>(temporary_allocator(), 0, method_forward_arg_count+1);
- auto method_call_args = array_make<lbValue>(temporary_allocator(), method_param_count + method_param_offset);
+ 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) {
- method_call_args[0] = lbValue {
- wrapper_proc->raw_input_parameters[0],
- class_ptr_type,
- };
+ array_add(&raw_method_args, wrapper_proc->raw_input_parameters[method_forward_return_arg_offset]);
}
for (isize i = 0; i < method_param_count; i++) {
- method_call_args[i+method_param_offset] = lbValue {
- wrapper_proc->raw_input_parameters[i+2],
- method_type->Proc.params->Tuple.variables[i+method_param_offset]->type,
- };
+ array_add(&raw_method_args, wrapper_proc->raw_input_parameters[i+2+method_forward_return_arg_offset]);
+ }
+
+ if (method_type->Proc.calling_convention == ProcCC_Odin) {
+ array_add(&raw_method_args, context_addr);
}
- lbValue method_proc_value = lb_find_procedure_value_from_entity(m, md.proc_entity);
// Call real procedure for method from here, passing the parameters expected, if any.
- lbValue return_value = lb_emit_call(wrapper_proc, method_proc_value, method_call_args);
+ LLVMTypeRef fnp = lb_type_internal_for_procedures_raw(m, method_type);
+ LLVMValueRef ret_val_raw = LLVMBuildCall2(wrapper_proc->builder, fnp, method_proc_value.value, raw_method_args.data, (unsigned)raw_method_args.count, "");
- if (wrapper_results_tuple != nullptr) {
- auto &result_var = method_type->Proc.results->Tuple.variables[0];
- return_value = lb_emit_conv(wrapper_proc, return_value, result_var->type);
- lb_build_return_stmt_internal(wrapper_proc, return_value, result_var->token.pos);
+ if (has_return && return_kind != lbArg_Indirect) {
+ LLVMBuildRet(wrapper_proc->builder, ret_val_raw);
+ }
+ else {
+ LLVMBuildRetVoid(wrapper_proc->builder);
}
}
lb_end_procedure_body(wrapper_proc);
-
// Add the method to the class
String method_encoding = str_lit("v");
- // TODO (harold): Checker must ensure that objc_methods have a single return value or none!
+
GB_ASSERT(method_type->Proc.result_count <= 1);
if (method_type->Proc.result_count != 0) {
method_encoding = lb_get_objc_type_encoding(method_type->Proc.results->Tuple.variables[0]->type);
@@ -1785,8 +1842,8 @@ gb_internal void lb_finalize_objc_names(lbGenerator *gen, lbProcedure *p) {
method_encoding = concatenate_strings(temporary_allocator(), method_encoding, str_lit("#:"));
}
- for (isize i = method_param_offset; i < method_param_count; i++) {
- Type *param_type = method_type->Proc.params->Tuple.variables[i]->type;
+ for (isize i = 0; i < method_param_count; i++) {
+ Type *param_type = method_type->Proc.params->Tuple.variables[i + method_param_offset]->type;
String param_encoding = lb_get_objc_type_encoding(param_type);
method_encoding = concatenate_strings(temporary_allocator(), method_encoding, param_encoding);
@@ -1805,7 +1862,7 @@ gb_internal void lb_finalize_objc_names(lbGenerator *gen, lbProcedure *p) {
args[2] = lbValue { wrapper_proc->value, wrapper_proc->type };
args[3] = lb_const_value(m, t_cstring, exact_value_string(method_encoding));
- // TODO(harold): Emit check BOOL result and panic if false.
+ // TODO(harold): Emit check BOOL result and panic if false?
lb_emit_runtime_call(p, "class_addMethod", args);
} // End methods
@@ -1853,7 +1910,7 @@ gb_internal void lb_finalize_objc_names(lbGenerator *gen, lbProcedure *p) {
// Defined in an external package, define it now in the main package
LLVMTypeRef t = lb_type(m, t_int);
- lbValue global{};
+ lbValue global = {};
global.value = LLVMAddGlobal(m->mod, t, g.global_name);
global.type = t_int_ptr;
@@ -2041,7 +2098,8 @@ gb_internal void lb_create_startup_runtime_generate_body(lbModule *m, lbProcedur
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, "");
+ LLVMValueRef cast_ctx = LLVMBuildBitCast(p->builder, context_ptr, LLVMPointerType(LLVMInt8TypeInContext(m->ctx), 0), "");
+ LLVMBuildCall2(p->builder, raw_dummy_type, dummy->value, &cast_ctx, 1, "");
} else {
lb_init_global_var(m, p, e, init_expr, var);
}
@@ -2192,6 +2250,11 @@ gb_internal void lb_create_global_procedures_and_types(lbGenerator *gen, Checker
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);
@@ -2990,7 +3053,10 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
}
first = false;
- llvm_features = gb_string_appendc(llvm_features, "+");
+ if (*str.text != '+' && *str.text != '-') {
+ llvm_features = gb_string_appendc(llvm_features, "+");
+ }
+
llvm_features = gb_string_append_length(llvm_features, str.text, str.len);
}
@@ -3245,10 +3311,6 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
continue;
}
- // if (!ptr_set_exists(min_dep_set, e)) {
- // continue;
- // }
-
DeclInfo *decl = decl_info_of_entity(e);
if (decl == nullptr) {
continue;
@@ -3259,8 +3321,16 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
bool is_foreign = e->Variable.is_foreign;
bool is_export = e->Variable.is_export;
+ lbModule *default_module = &gen->default_module;
+
+ lbModule *m = default_module;
+ lbModule *e_module = lb_module_of_entity(gen, e, default_module);
+
+ bool const split_globals_across_modules = false;
+ if (split_globals_across_modules) {
+ m = e_module;
+ }
- lbModule *m = &gen->default_module;
String name = lb_get_entity_name(m, e);
lbGlobalVariable var = {};
@@ -3361,15 +3431,26 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
}
}
- g.value = LLVMConstPointerCast(g.value, lb_type(m, alloc_type_pointer(e->type)));
+ 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);
+ 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);
- lb_add_entity(m, e, g);
- lb_add_member(m, name, g);
+ 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) {
@@ -3556,8 +3637,8 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
TIME_SECTION("LLVM Correct Entity Linkage");
lb_correct_entity_linkage(gen);
- if (build_context.para_poly_diagnostics) {
- lb_do_para_poly_diagnostics(gen);
+ if (build_context.build_diagnostics) {
+ lb_do_build_diagnostics(gen);
}
llvm_error = nullptr;