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.cpp466
1 files changed, 352 insertions, 114 deletions
diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp
index 62d5a58a6..d3bc3d0f8 100644
--- a/src/llvm_backend.cpp
+++ b/src/llvm_backend.cpp
@@ -391,11 +391,37 @@ void lb_addr_store(lbProcedure *p, lbAddr addr, lbValue value) {
lb_insert_dynamic_map_key_and_value(p, addr, addr.map.type, addr.map.key, value, p->curr_stmt);
return;
} else if (addr.kind == lbAddr_Context) {
- lbValue old = lb_addr_load(p, lb_find_or_generate_context_ptr(p));
- lbAddr next_addr = lb_add_local_generated(p, t_context, true);
- lb_addr_store(p, next_addr, old);
- lb_push_context_onto_stack(p, next_addr);
- lbValue next = lb_addr_get_ptr(p, next_addr);
+ lbAddr old_addr = lb_find_or_generate_context_ptr(p);
+
+
+ // IMPORTANT NOTE(bill, 2021-04-22): reuse unused 'context' variables to minimize stack usage
+ // This has to be done manually since the optimizer cannot determine when this is possible
+ bool create_new = true;
+ for_array(i, p->context_stack) {
+ lbContextData *ctx_data = &p->context_stack[i];
+ if (ctx_data->ctx.addr.value == old_addr.addr.value) {
+ if (ctx_data->uses > 0) {
+ create_new = true;
+ } else if (p->scope_index > ctx_data->scope_index) {
+ create_new = true;
+ } else {
+ // gb_printf_err("%.*s (curr:%td) (ctx:%td) (uses:%td)\n", LIT(p->name), p->scope_index, ctx_data->scope_index, ctx_data->uses);
+ create_new = false;
+ }
+ break;
+ }
+ }
+
+ lbValue next = {};
+ if (create_new) {
+ lbValue old = lb_addr_load(p, old_addr);
+ lbAddr next_addr = lb_add_local_generated(p, t_context, true);
+ lb_addr_store(p, next_addr, old);
+ lb_push_context_onto_stack(p, next_addr);
+ next = next_addr.addr;
+ } else {
+ next = old_addr.addr;
+ }
if (addr.ctx.sel.index.count > 0) {
lbValue lhs = lb_emit_deep_field_gep(p, next, addr.ctx.sel);
@@ -623,6 +649,13 @@ lbValue lb_addr_load(lbProcedure *p, lbAddr const &addr) {
}
} else if (addr.kind == lbAddr_Context) {
lbValue a = addr.addr;
+ for_array(i, p->context_stack) {
+ lbContextData *ctx_data = &p->context_stack[i];
+ if (ctx_data->ctx.addr.value == a.value) {
+ ctx_data->uses += 1;
+ break;
+ }
+ }
a.value = LLVMBuildPointerCast(p->builder, a.value, lb_type(p->module, t_context_ptr), "");
if (addr.ctx.sel.index.count > 0) {
@@ -1445,9 +1478,6 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
}
case Type_SimdVector:
- if (type->SimdVector.is_x86_mmx) {
- return LLVMX86MMXTypeInContext(ctx);
- }
return LLVMVectorType(lb_type(m, type->SimdVector.elem), cast(unsigned)type->SimdVector.count);
case Type_RelativePointer:
@@ -1899,9 +1929,6 @@ LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) {
break;
case Type_SimdVector:
- if (type->SimdVector.is_x86_mmx) {
- return LLVMDIBuilderCreateVectorType(m->debug_builder, 2, 8*cast(unsigned)type_align_of(type), lb_debug_type(m, t_f64), nullptr, 0);
- }
return LLVMDIBuilderCreateVectorType(m->debug_builder, cast(unsigned)type->SimdVector.count, 8*cast(unsigned)type_align_of(type), lb_debug_type(m, type->SimdVector.elem), nullptr, 0);
case Type_RelativePointer: {
@@ -2523,7 +2550,7 @@ lbProcedure *lb_create_procedure(lbModule *m, Entity *entity) {
p->type = entity->type;
p->type_expr = decl->type_expr;
p->body = pl->body;
- p->inlining = ProcInlining_none;
+ p->inlining = pl->inlining;
p->is_foreign = entity->Procedure.is_foreign;
p->is_export = entity->Procedure.is_export;
p->is_entry_point = false;
@@ -2558,9 +2585,6 @@ lbProcedure *lb_create_procedure(lbModule *m, Entity *entity) {
LLVMSetFunctionCallConv(p->value, cc_kind);
}
- if (entity->flags & EntityFlag_Cold) {
- lb_add_attribute_to_proc(m, p->value, "cold");
- }
if (pt->Proc.diverging) {
lb_add_attribute_to_proc(m, p->value, "noreturn");
@@ -2575,6 +2599,28 @@ lbProcedure *lb_create_procedure(lbModule *m, Entity *entity) {
break;
}
+ if (entity->flags & EntityFlag_Cold) {
+ lb_add_attribute_to_proc(m, p->value, "cold");
+ }
+
+ switch (entity->Procedure.optimization_mode) {
+ case ProcedureOptimizationMode_None:
+ lb_add_attribute_to_proc(m, p->value, "optnone");
+ break;
+ case ProcedureOptimizationMode_Minimal:
+ lb_add_attribute_to_proc(m, p->value, "optnone");
+ break;
+ case ProcedureOptimizationMode_Size:
+ lb_add_attribute_to_proc(m, p->value, "optsize");
+ break;
+ case ProcedureOptimizationMode_Speed:
+ // TODO(bill): handle this correctly
+ lb_add_attribute_to_proc(m, p->value, "optsize");
+ break;
+ }
+
+
+
// lbCallingConventionKind cc_kind = lbCallingConvention_C;
// // TODO(bill): Clean up this logic
// if (build_context.metrics.os != TargetOs_js) {
@@ -2624,26 +2670,16 @@ lbProcedure *lb_create_procedure(lbModule *m, Entity *entity) {
for (isize i = 0; i < pt->Proc.param_count; i++) {
Entity *e = params->variables[i];
Type *original_type = e->type;
- Type *abi_type = pt->Proc.abi_compat_params[i];
if (e->kind != Entity_Variable) continue;
if (i+1 == params->variables.count && pt->Proc.c_vararg) {
continue;
}
- if (is_type_tuple(abi_type)) {
- for_array(j, abi_type->Tuple.variables) {
- Type *tft = abi_type->Tuple.variables[j]->type;
- if (e->flags&EntityFlag_NoAlias) {
- lb_add_proc_attribute_at_index(p, offset+parameter_index+j, "noalias");
- }
- }
- parameter_index += abi_type->Tuple.variables.count;
- } else {
- if (e->flags&EntityFlag_NoAlias) {
- lb_add_proc_attribute_at_index(p, offset+parameter_index, "noalias");
- }
- parameter_index += 1;
+
+ if (e->flags&EntityFlag_NoAlias) {
+ lb_add_proc_attribute_at_index(p, offset+parameter_index, "noalias");
}
+ parameter_index += 1;
}
}
@@ -7567,6 +7603,7 @@ lbContextData *lb_push_context_onto_stack_from_implicit_parameter(lbProcedure *p
lbContextData *cd = array_add_and_get(&p->context_stack);
cd->ctx = ctx_addr;
cd->scope_index = -1;
+ cd->uses = +1; // make sure it has been used already
return cd;
}
@@ -9031,6 +9068,145 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
}
return {};
+
+ case BuiltinProc_debug_trap:
+ case BuiltinProc_trap:
+ {
+ char const *name = nullptr;
+ switch (id) {
+ case BuiltinProc_debug_trap: name = "llvm.debugtrap"; break;
+ case BuiltinProc_trap: name = "llvm.trap"; break;
+ }
+
+ unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
+ GB_ASSERT_MSG(id != 0, "Unable to find %s", name);
+ LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, nullptr, 0);
+
+ LLVMBuildCall(p->builder, ip, nullptr, 0, "");
+ if (id == BuiltinProc_trap) {
+ LLVMBuildUnreachable(p->builder);
+ }
+ return {};
+ }
+
+ case BuiltinProc_read_cycle_counter:
+ {
+ char const *name = "llvm.readcyclecounter";
+ unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
+ GB_ASSERT_MSG(id != 0, "Unable to find %s", name);
+ LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, nullptr, 0);
+
+ lbValue res = {};
+ res.value = LLVMBuildCall(p->builder, ip, nullptr, 0, "");
+ res.type = tv.type;
+ return res;
+ }
+
+ case BuiltinProc_trailing_zeros:
+ {
+ lbValue x = lb_build_expr(p, ce->args[0]);
+ x = lb_emit_conv(p, x, tv.type);
+
+ char const *name = "llvm.cttz";
+ LLVMTypeRef types[1] = {lb_type(p->module, tv.type)};
+ unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
+ GB_ASSERT_MSG(id != 0, "Unable to find %s.%s", name, LLVMPrintTypeToString(types[0]));
+ LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types));
+
+ LLVMValueRef args[2] = {};
+ args[0] = x.value;
+ args[1] = LLVMConstNull(LLVMInt1TypeInContext(p->module->ctx));
+
+ lbValue res = {};
+ res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), "");
+ res.type = tv.type;
+ return res;
+ }
+
+ case BuiltinProc_count_ones:
+ case BuiltinProc_reverse_bits:
+ {
+ lbValue x = lb_build_expr(p, ce->args[0]);
+ x = lb_emit_conv(p, x, tv.type);
+
+ char const *name = nullptr;
+ switch (id) {
+ case BuiltinProc_count_ones: name = "llvm.ctpop"; break;
+ case BuiltinProc_reverse_bits: name = "llvm.bitreverse"; break;
+ }
+ LLVMTypeRef types[1] = {lb_type(p->module, tv.type)};
+ unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
+ GB_ASSERT_MSG(id != 0, "Unable to find %s.%s", name, LLVMPrintTypeToString(types[0]));
+ LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types));
+
+ LLVMValueRef args[1] = {};
+ args[0] = x.value;
+
+ lbValue res = {};
+ res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), "");
+ res.type = tv.type;
+ return res;
+ }
+
+ case BuiltinProc_byte_swap:
+ {
+ lbValue x = lb_build_expr(p, ce->args[0]);
+ x = lb_emit_conv(p, x, tv.type);
+ return lb_emit_byte_swap(p, x, tv.type);
+ }
+
+ case BuiltinProc_overflow_add:
+ case BuiltinProc_overflow_sub:
+ case BuiltinProc_overflow_mul:
+ {
+ Type *tuple = tv.type;
+ GB_ASSERT(is_type_tuple(tuple));
+ Type *type = tuple->Tuple.variables[0]->type;
+
+ lbValue x = lb_build_expr(p, ce->args[0]);
+ lbValue y = lb_build_expr(p, ce->args[1]);
+ x = lb_emit_conv(p, x, type);
+ y = lb_emit_conv(p, y, type);
+
+ char const *name = nullptr;
+ if (is_type_unsigned(type)) {
+ switch (id) {
+ case BuiltinProc_overflow_add: name = "llvm.uadd.with.overflow"; break;
+ case BuiltinProc_overflow_sub: name = "llvm.usub.with.overflow"; break;
+ case BuiltinProc_overflow_mul: name = "llvm.umul.with.overflow"; break;
+ }
+ } else {
+ switch (id) {
+ case BuiltinProc_overflow_add: name = "llvm.sadd.with.overflow"; break;
+ case BuiltinProc_overflow_sub: name = "llvm.ssub.with.overflow"; break;
+ case BuiltinProc_overflow_mul: name = "llvm.smul.with.overflow"; break;
+ }
+ }
+ LLVMTypeRef types[1] = {lb_type(p->module, type)};
+ unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
+ GB_ASSERT_MSG(id != 0, "Unable to find %s.%s", name, LLVMPrintTypeToString(types[0]));
+ LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types));
+
+ LLVMValueRef args[2] = {};
+ args[0] = x.value;
+ args[1] = y.value;
+
+ Type *res_type = nullptr;
+ {
+ gbAllocator a = permanent_allocator();
+ res_type = alloc_type_tuple();
+ array_init(&res_type->Tuple.variables, a, 2);
+ res_type->Tuple.variables[0] = alloc_entity_field(nullptr, blank_token, type, false, 0);
+ res_type->Tuple.variables[1] = alloc_entity_field(nullptr, blank_token, t_llvm_bool, false, 1);
+ }
+
+ lbValue res = {};
+ res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), "");
+ res.type = res_type;
+ return res;
+ }
+
+
case BuiltinProc_atomic_fence:
LLVMBuildFence(p->builder, LLVMAtomicOrderingSequentiallyConsistent, false, "");
return {};
@@ -9304,6 +9480,30 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
res.type = platform_type;
return lb_emit_conv(p, res, tv.type);
}
+
+ case BuiltinProc_expect:
+ {
+ Type *t = default_type(tv.type);
+ lbValue x = lb_emit_conv(p, lb_build_expr(p, ce->args[0]), t);
+ lbValue y = lb_emit_conv(p, lb_build_expr(p, ce->args[1]), t);
+
+ char const *name = "llvm.expect";
+
+ LLVMTypeRef types[1] = {lb_type(p->module, t)};
+ unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
+ GB_ASSERT_MSG(id != 0, "Unable to find %s.%s", name, LLVMPrintTypeToString(types[0]));
+ LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types));
+
+ lbValue res = {};
+
+ LLVMValueRef args[2] = {};
+ args[0] = x.value;
+ args[1] = y.value;
+
+ res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), "");
+ res.type = t;
+ return lb_emit_conv(p, res, t);
+ }
}
GB_PANIC("Unhandled built-in procedure %.*s", LIT(builtin_procs[id].name));
@@ -9692,6 +9892,7 @@ bool lb_is_const_nil(lbValue value) {
String lb_get_const_string(lbModule *m, lbValue value) {
GB_ASSERT(lb_is_const(value));
+ GB_ASSERT(LLVMIsConstant(value.value));
Type *t = base_type(value.type);
GB_ASSERT(are_types_identical(t, t_string));
@@ -9743,43 +9944,43 @@ LLVMValueRef lb_lookup_runtime_procedure(lbModule *m, String const &name) {
return found->value;
}
-lbValue lb_emit_byte_swap(lbProcedure *p, lbValue value, Type *platform_type) {
- Type *vt = core_type(value.type);
- GB_ASSERT(type_size_of(vt) == type_size_of(platform_type));
-
- // TODO(bill): lb_emit_byte_swap
- lbValue res = {};
- res.type = platform_type;
- res.value = value.value;
+lbValue lb_emit_byte_swap(lbProcedure *p, lbValue value, Type *end_type) {
+ GB_ASSERT(type_size_of(value.type) == type_size_of(end_type));
- int sz = cast(int)type_size_of(vt);
- if (sz > 1) {
- if (is_type_float(platform_type)) {
- String name = {};
- switch (sz) {
- case 2: name = str_lit("bswap_f16"); break;
- case 4: name = str_lit("bswap_f32"); break;
- case 8: name = str_lit("bswap_f64"); break;
- default: GB_PANIC("unhandled byteswap size"); break;
- }
- LLVMValueRef fn = lb_lookup_runtime_procedure(p->module, name);
- res.value = LLVMBuildCall(p->builder, fn, &value.value, 1, "");
- } else {
- GB_ASSERT(is_type_integer(platform_type));
- String name = {};
- switch (sz) {
- case 2: name = str_lit("bswap_16"); break;
- case 4: name = str_lit("bswap_32"); break;
- case 8: name = str_lit("bswap_64"); break;
- case 16: name = str_lit("bswap_128"); break;
- default: GB_PANIC("unhandled byteswap size"); break;
- }
- LLVMValueRef fn = lb_lookup_runtime_procedure(p->module, name);
+ if (type_size_of(value.type) < 2) {
+ return value;
+ }
- res.value = LLVMBuildCall(p->builder, fn, &value.value, 1, "");
+ Type *original_type = value.type;
+ if (is_type_float(original_type)) {
+ i64 sz = type_size_of(original_type);
+ Type *integer_type = nullptr;
+ switch (sz) {
+ case 2: integer_type = t_u16; break;
+ case 4: integer_type = t_u32; break;
+ case 8: integer_type = t_u64; break;
}
+ GB_ASSERT(integer_type != nullptr);
+ value = lb_emit_transmute(p, value, integer_type);
}
+ char const *name = "llvm.bswap";
+ LLVMTypeRef types[1] = {lb_type(p->module, value.type)};
+ unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
+ GB_ASSERT_MSG(id != 0, "Unable to find %s.%s", name, LLVMPrintTypeToString(types[0]));
+ LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types));
+
+ LLVMValueRef args[1] = {};
+ args[0] = value.value;
+
+ lbValue res = {};
+ res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), "");
+ res.type = value.type;
+
+ if (is_type_float(original_type)) {
+ res = lb_emit_transmute(p, res, original_type);
+ }
+ res.type = end_type;
return res;
}
@@ -10963,7 +11164,8 @@ lbValue lb_build_expr(lbProcedure *p, Ast *expr) {
case_end;
case_ast_node(ac, AutoCast, expr);
- return lb_build_expr(p, ac->expr);
+ lbValue value = lb_build_expr(p, ac->expr);
+ return lb_emit_conv(p, value, tv.type);
case_end;
case_ast_node(ue, UnaryExpr, expr);
@@ -13355,15 +13557,11 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
{
tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_simd_vector_ptr);
- LLVMValueRef vals[4] = {};
+ LLVMValueRef vals[3] = {};
- if (t->SimdVector.is_x86_mmx) {
- vals[3] = lb_const_bool(m, t_bool, true).value;
- } else {
- vals[0] = lb_get_type_info_ptr(m, t->SimdVector.elem).value;
- vals[1] = lb_const_int(m, t_int, type_size_of(t->SimdVector.elem)).value;
- vals[2] = lb_const_int(m, t_int, t->SimdVector.count).value;
- }
+ vals[0] = lb_get_type_info_ptr(m, t->SimdVector.elem).value;
+ vals[1] = lb_const_int(m, t_int, type_size_of(t->SimdVector.elem)).value;
+ vals[2] = lb_const_int(m, t_int, t->SimdVector.count).value;
lbValue res = {};
res.type = type_deref(tag.type);
@@ -13844,11 +14042,28 @@ void lb_generate_code(lbGenerator *gen) {
LLVMPassRegistryRef pass_registry = LLVMGetGlobalPassRegistry();
LLVMPassManagerRef default_function_pass_manager = LLVMCreateFunctionPassManagerForModule(mod);
+ LLVMPassManagerRef function_pass_manager_minimal = LLVMCreateFunctionPassManagerForModule(mod);
+ LLVMPassManagerRef function_pass_manager_size = LLVMCreateFunctionPassManagerForModule(mod);
+ LLVMPassManagerRef function_pass_manager_speed = LLVMCreateFunctionPassManagerForModule(mod);
defer (LLVMDisposePassManager(default_function_pass_manager));
+ defer (LLVMDisposePassManager(function_pass_manager_minimal));
+ defer (LLVMDisposePassManager(function_pass_manager_size));
+ defer (LLVMDisposePassManager(function_pass_manager_speed));
LLVMInitializeFunctionPassManager(default_function_pass_manager);
+ LLVMInitializeFunctionPassManager(function_pass_manager_minimal);
+ LLVMInitializeFunctionPassManager(function_pass_manager_size);
+ LLVMInitializeFunctionPassManager(function_pass_manager_speed);
+
lb_populate_function_pass_manager(default_function_pass_manager, false, build_context.optimization_level);
+ lb_populate_function_pass_manager_specific(function_pass_manager_minimal, 0);
+ lb_populate_function_pass_manager_specific(function_pass_manager_size, 1);
+ lb_populate_function_pass_manager_specific(function_pass_manager_speed, 2);
+
LLVMFinalizeFunctionPassManager(default_function_pass_manager);
+ LLVMFinalizeFunctionPassManager(function_pass_manager_minimal);
+ LLVMFinalizeFunctionPassManager(function_pass_manager_size);
+ LLVMFinalizeFunctionPassManager(function_pass_manager_speed);
LLVMPassManagerRef default_function_pass_manager_without_memcpy = LLVMCreateFunctionPassManagerForModule(mod);
@@ -13988,6 +14203,47 @@ void lb_generate_code(lbGenerator *gen) {
}*/
}
+ String filepath_ll = concatenate_strings(permanent_allocator(), gen->output_base, STR_LIT(".ll"));
+
+ TIME_SECTION("LLVM Procedure Generation");
+ for_array(i, m->procedures_to_generate) {
+ lbProcedure *p = m->procedures_to_generate[i];
+ if (p->is_done) {
+ continue;
+ }
+ if (p->body != nullptr) { // Build Procedure
+ m->curr_procedure = p;
+ lb_begin_procedure_body(p);
+ lb_build_stmt(p, p->body);
+ lb_end_procedure_body(p);
+ p->is_done = true;
+ m->curr_procedure = nullptr;
+ }
+ lb_end_procedure(p);
+
+ // Add Flags
+ if (p->body != nullptr) {
+ if (p->name == "memcpy" || p->name == "memmove" ||
+ p->name == "runtime.mem_copy" || p->name == "mem_copy_non_overlapping" ||
+ string_starts_with(p->name, str_lit("llvm.memcpy")) ||
+ string_starts_with(p->name, str_lit("llvm.memmove"))) {
+ p->flags |= lbProcedureFlag_WithoutMemcpyPass;
+ }
+ }
+
+ if (!m->debug_builder && LLVMVerifyFunction(p->value, LLVMReturnStatusAction)) {
+ gb_printf_err("LLVM CODE GEN FAILED FOR PROCEDURE: %.*s\n", LIT(p->name));
+ LLVMDumpValue(p->value);
+ gb_printf_err("\n\n\n\n");
+ if (LLVMPrintModuleToFile(mod, cast(char const *)filepath_ll.text, &llvm_error)) {
+ gb_printf_err("LLVM Error: %s\n", llvm_error);
+ }
+ LLVMVerifyFunction(p->value, LLVMPrintMessageAction);
+ gb_exit(1);
+ }
+ }
+
+
if (!(build_context.build_mode == BuildMode_DynamicLibrary && !has_dll_main)) {
TIME_SECTION("LLVM DLL main");
@@ -14075,7 +14331,7 @@ void lb_generate_code(lbGenerator *gen) {
} else {
lbValue *found = map_get(&m->values, hash_entity(entry_point));
GB_ASSERT(found != nullptr);
- LLVMBuildCall2(p->builder, LLVMGetElementType(lb_type(m, found->type)), found->value, nullptr, 0, "");
+ lb_emit_call(p, *found, {});
}
LLVMBuildRet(p->builder, LLVMConstInt(lb_type(m, t_i32), 0, false));
@@ -14093,47 +14349,6 @@ void lb_generate_code(lbGenerator *gen) {
}
- String filepath_ll = concatenate_strings(permanent_allocator(), gen->output_base, STR_LIT(".ll"));
-
- TIME_SECTION("LLVM Procedure Generation");
- for_array(i, m->procedures_to_generate) {
- lbProcedure *p = m->procedures_to_generate[i];
- if (p->is_done) {
- continue;
- }
- if (p->body != nullptr) { // Build Procedure
- m->curr_procedure = p;
- lb_begin_procedure_body(p);
- lb_build_stmt(p, p->body);
- lb_end_procedure_body(p);
- p->is_done = true;
- m->curr_procedure = nullptr;
- }
- lb_end_procedure(p);
-
- // Add Flags
- if (p->body != nullptr) {
- if (p->name == "memcpy" || p->name == "memmove" ||
- p->name == "runtime.mem_copy" || p->name == "mem_copy_non_overlapping" ||
- string_starts_with(p->name, str_lit("llvm.memcpy")) ||
- string_starts_with(p->name, str_lit("llvm.memmove"))) {
- p->flags |= lbProcedureFlag_WithoutMemcpyPass;
- }
- }
-
- if (!m->debug_builder && LLVMVerifyFunction(p->value, LLVMReturnStatusAction)) {
- gb_printf_err("LLVM CODE GEN FAILED FOR PROCEDURE: %.*s\n", LIT(p->name));
- LLVMDumpValue(p->value);
- gb_printf_err("\n\n\n\n");
- if (LLVMPrintModuleToFile(mod, cast(char const *)filepath_ll.text, &llvm_error)) {
- gb_printf_err("LLVM Error: %s\n", llvm_error);
- }
- LLVMVerifyFunction(p->value, LLVMPrintMessageAction);
- gb_exit(1);
- }
- }
-
-
if (m->debug_builder != nullptr) {
TIME_SECTION("LLVM Debug Info Complete Types");
lb_debug_complete_types(m);
@@ -14158,7 +14373,25 @@ void lb_generate_code(lbGenerator *gen) {
if (p->flags & lbProcedureFlag_WithoutMemcpyPass) {
LLVMRunFunctionPassManager(default_function_pass_manager_without_memcpy, p->value);
} else {
- LLVMRunFunctionPassManager(default_function_pass_manager, p->value);
+ if (p->entity && p->entity->kind == Entity_Procedure) {
+ switch (p->entity->Procedure.optimization_mode) {
+ case ProcedureOptimizationMode_None:
+ case ProcedureOptimizationMode_Minimal:
+ LLVMRunFunctionPassManager(function_pass_manager_minimal, p->value);
+ break;
+ case ProcedureOptimizationMode_Size:
+ LLVMRunFunctionPassManager(function_pass_manager_size, p->value);
+ break;
+ case ProcedureOptimizationMode_Speed:
+ LLVMRunFunctionPassManager(function_pass_manager_speed, p->value);
+ break;
+ default:
+ LLVMRunFunctionPassManager(default_function_pass_manager, p->value);
+ break;
+ }
+ } else {
+ LLVMRunFunctionPassManager(default_function_pass_manager, p->value);
+ }
}
}
}
@@ -14220,13 +14453,18 @@ void lb_generate_code(lbGenerator *gen) {
return;
}
llvm_error = nullptr;
- if (build_context.keep_temp_files) {
+ if (build_context.keep_temp_files ||
+ build_context.build_mode == BuildMode_LLVM_IR) {
TIME_SECTION("LLVM Print Module to File");
if (LLVMPrintModuleToFile(mod, cast(char const *)filepath_ll.text, &llvm_error)) {
gb_printf_err("LLVM Error: %s\n", llvm_error);
gb_exit(1);
return;
}
+ if (build_context.build_mode == BuildMode_LLVM_IR) {
+ gb_exit(0);
+ return;
+ }
}
TIME_SECTION("LLVM Object Generation");