diff --git a/src/llvm_abi.cpp b/src/llvm_abi.cpp index 298041aa6..31773e1a2 100644 --- a/src/llvm_abi.cpp +++ b/src/llvm_abi.cpp @@ -1,3 +1,5 @@ +#define ALLOW_SPLIT_MULTI_RETURNS true + enum lbArgKind { lbArg_Direct, lbArg_Indirect, @@ -48,8 +50,16 @@ struct lbFunctionType { ProcCallingConvention calling_convention; Array args; lbArgType ret; + + LLVMTypeRef multiple_return_original_type; // nullptr if not used + isize original_arg_count; }; +gbAllocator lb_function_type_args_allocator(void) { + return heap_allocator(); +} + + i64 llvm_align_formula(i64 off, i64 a) { return (off + a - 1) / a * a; } @@ -100,7 +110,9 @@ LLVMTypeRef lb_function_type_to_llvm_raw(lbFunctionType *ft, bool is_var_arg) { } args[arg_index++] = arg_type; } else if (arg->kind == lbArg_Indirect) { - GB_ASSERT(!lb_is_type_kind(arg->type, LLVMPointerTypeKind)); + if (ft->multiple_return_original_type == nullptr || i < ft->original_arg_count) { + GB_ASSERT(!lb_is_type_kind(arg->type, LLVMPointerTypeKind)); + } args[arg_index++] = LLVMPointerType(arg->type, 0); } else if (arg->kind == lbArg_Ignore) { // ignore @@ -147,6 +159,13 @@ void lb_add_function_type_attributes(LLVMValueRef fn, lbFunctionType *ft, ProcCa LLVMAddAttributeAtIndex(fn, arg_index+1, arg->align_attribute); } + if (ft->multiple_return_original_type) { + if (ft->original_arg_count <= i) { + LLVMAddAttributeAtIndex(fn, arg_index+1, noalias_attr); + LLVMAddAttributeAtIndex(fn, arg_index+1, nonnull_attr); + } + } + arg_index++; } @@ -307,7 +326,7 @@ i64 lb_alignof(LLVMTypeRef type) { } -#define LB_ABI_INFO(name) lbFunctionType *name(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count, LLVMTypeRef return_type, bool return_is_defined, ProcCallingConvention calling_convention) +#define LB_ABI_INFO(name) lbFunctionType *name(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count, LLVMTypeRef return_type, bool return_is_defined, bool return_is_tuple, ProcCallingConvention calling_convention) typedef LB_ABI_INFO(lbAbiInfoType); @@ -353,7 +372,7 @@ namespace lbAbi386 { } Array compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count) { - auto args = array_make(heap_allocator(), arg_count); + auto args = array_make(lb_function_type_args_allocator(), arg_count); for (unsigned i = 0; i < arg_count; i++) { LLVMTypeRef t = arg_types[i]; @@ -392,19 +411,19 @@ namespace lbAbi386 { namespace lbAbiAmd64Win64 { Array compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count); - + lbArgType compute_return_type(lbFunctionType *ft, LLVMContextRef c, LLVMTypeRef return_type, bool return_is_defined, bool return_is_tuple); LB_ABI_INFO(abi_info) { lbFunctionType *ft = gb_alloc_item(permanent_allocator(), lbFunctionType); ft->ctx = c; ft->args = compute_arg_types(c, arg_types, arg_count); - ft->ret = lbAbi386::compute_return_type(c, return_type, return_is_defined); + ft->ret = compute_return_type(ft, c, return_type, return_is_defined, return_is_tuple); ft->calling_convention = calling_convention; return ft; } Array compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count) { - auto args = array_make(heap_allocator(), arg_count); + auto args = array_make(lb_function_type_args_allocator(), arg_count); for (unsigned i = 0; i < arg_count; i++) { LLVMTypeRef t = arg_types[i]; @@ -428,6 +447,45 @@ namespace lbAbiAmd64Win64 { } return args; } + + lbArgType compute_return_type(lbFunctionType *ft, LLVMContextRef c, LLVMTypeRef return_type, bool return_is_defined, bool return_is_tuple) { + if (!return_is_defined) { + return lb_arg_type_direct(LLVMVoidTypeInContext(c)); + } else if (lb_is_type_kind(return_type, LLVMStructTypeKind) || lb_is_type_kind(return_type, LLVMArrayTypeKind)) { + i64 sz = lb_sizeof(return_type); + switch (sz) { + case 1: return lb_arg_type_direct(return_type, LLVMIntTypeInContext(c, 8), nullptr, nullptr); + case 2: return lb_arg_type_direct(return_type, LLVMIntTypeInContext(c, 16), nullptr, nullptr); + case 4: return lb_arg_type_direct(return_type, LLVMIntTypeInContext(c, 32), nullptr, nullptr); + case 8: return lb_arg_type_direct(return_type, LLVMIntTypeInContext(c, 64), nullptr, nullptr); + } + + if (return_is_tuple) { + GB_ASSERT(lb_is_type_kind(return_type, LLVMStructTypeKind)); + unsigned field_count = LLVMCountStructElementTypes(return_type); + + if (field_count > 1) { + ft->original_arg_count = ft->args.count; + ft->multiple_return_original_type = return_type; + + for (unsigned i = 0; i < field_count-1; i++) { + LLVMTypeRef field_type = LLVMStructGetTypeAtIndex(return_type, i); + LLVMTypeRef field_pointer_type = LLVMPointerType(field_type, 0); + lbArgType ret_partial = lb_arg_type_direct(field_pointer_type); + array_add(&ft->args, ret_partial); + } + + // override the return type for the last field + LLVMTypeRef new_return_type = LLVMStructGetTypeAtIndex(return_type, field_count-1); + return compute_return_type(ft, c, new_return_type, true, false); + } + } + + LLVMAttributeRef attr = lb_create_enum_attribute_with_type(c, "sret", return_type); + return lb_arg_type_indirect(return_type, attr); + } + return lbAbi386::non_struct(c, return_type, true); + } }; // NOTE(bill): I hate `namespace` in C++ but this is just because I don't want to prefix everything @@ -490,7 +548,7 @@ namespace lbAbiAmd64SysV { ft->ctx = c; ft->calling_convention = calling_convention; - ft->args = array_make(heap_allocator(), arg_count); + ft->args = array_make(lb_function_type_args_allocator(), arg_count); for (unsigned i = 0; i < arg_count; i++) { ft->args[i] = amd64_type(c, arg_types[i], Amd64TypeAttribute_ByVal, calling_convention); } @@ -1056,7 +1114,7 @@ namespace lbAbiArm64 { } Array compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count) { - auto args = array_make(heap_allocator(), arg_count); + auto args = array_make(lb_function_type_args_allocator(), arg_count); for (unsigned i = 0; i < arg_count; i++) { LLVMTypeRef type = arg_types[i]; @@ -1188,7 +1246,7 @@ namespace lbAbiWasm { Array compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count) { - auto args = array_make(heap_allocator(), arg_count); + auto args = array_make(lb_function_type_args_allocator(), arg_count); for (unsigned i = 0; i < arg_count; i++) { LLVMTypeRef t = arg_types[i]; @@ -1266,7 +1324,7 @@ namespace lbAbiArm32 { } Array compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count, ProcCallingConvention calling_convention) { - auto args = array_make(heap_allocator(), arg_count); + auto args = array_make(lb_function_type_args_allocator(), arg_count); for (unsigned i = 0; i < arg_count; i++) { LLVMTypeRef t = arg_types[i]; @@ -1307,14 +1365,14 @@ namespace lbAbiArm32 { }; -LB_ABI_INFO(lb_get_abi_info) { +LB_ABI_INFO(lb_get_abi_info_internal) { switch (calling_convention) { case ProcCC_None: case ProcCC_InlineAsm: { lbFunctionType *ft = gb_alloc_item(permanent_allocator(), lbFunctionType); ft->ctx = c; - ft->args = array_make(heap_allocator(), arg_count); + ft->args = array_make(lb_function_type_args_allocator(), arg_count); for (unsigned i = 0; i < arg_count; i++) { ft->args[i] = lb_arg_type_direct(arg_types[i]); } @@ -1328,32 +1386,43 @@ LB_ABI_INFO(lb_get_abi_info) { } case ProcCC_Win64: GB_ASSERT(build_context.metrics.arch == TargetArch_amd64); - return lbAbiAmd64Win64::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention); + return lbAbiAmd64Win64::abi_info(c, arg_types, arg_count, return_type, return_is_defined, return_is_tuple, calling_convention); case ProcCC_SysV: GB_ASSERT(build_context.metrics.arch == TargetArch_amd64); - return lbAbiAmd64SysV::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention); + return lbAbiAmd64SysV::abi_info(c, arg_types, arg_count, return_type, return_is_defined, return_is_tuple, calling_convention); } switch (build_context.metrics.arch) { case TargetArch_amd64: if (build_context.metrics.os == TargetOs_windows || build_context.metrics.abi == TargetABI_Win64) { - return lbAbiAmd64Win64::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention); + return lbAbiAmd64Win64::abi_info(c, arg_types, arg_count, return_type, return_is_defined, return_is_tuple, calling_convention); } else if (build_context.metrics.abi == TargetABI_SysV) { - return lbAbiAmd64SysV::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention); + return lbAbiAmd64SysV::abi_info(c, arg_types, arg_count, return_type, return_is_defined, return_is_tuple, calling_convention); } else { - return lbAbiAmd64SysV::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention); + return lbAbiAmd64SysV::abi_info(c, arg_types, arg_count, return_type, return_is_defined, return_is_tuple, calling_convention); } case TargetArch_i386: - return lbAbi386::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention); + return lbAbi386::abi_info(c, arg_types, arg_count, return_type, return_is_defined, return_is_tuple, calling_convention); case TargetArch_arm32: - return lbAbiArm32::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention); + return lbAbiArm32::abi_info(c, arg_types, arg_count, return_type, return_is_defined, return_is_tuple, calling_convention); case TargetArch_arm64: - return lbAbiArm64::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention); + return lbAbiArm64::abi_info(c, arg_types, arg_count, return_type, return_is_defined, return_is_tuple, calling_convention); case TargetArch_wasm32: case TargetArch_wasm64: - return lbAbiWasm::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention); + return lbAbiWasm::abi_info(c, arg_types, arg_count, return_type, return_is_defined, return_is_tuple, calling_convention); } GB_PANIC("Unsupported ABI"); return {}; } + + +LB_ABI_INFO(lb_get_abi_info) { + lbFunctionType *ft = lb_get_abi_info_internal(c, arg_types, arg_count, return_type, return_is_defined, ALLOW_SPLIT_MULTI_RETURNS && return_is_tuple, calling_convention); + if (calling_convention == ProcCC_Odin) { + // append the `context` pointer + lbArgType context_param = lb_arg_type_direct(LLVMPointerType(LLVMInt8TypeInContext(c), 0)); + array_add(&ft->args, context_param); + } + return ft; +} diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index 050168e8e..382c01042 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -1499,9 +1499,6 @@ LLVMTypeRef lb_type_internal_for_procedures_raw(lbModule *m, Type *type) { } unsigned param_count = 0; - if (type->Proc.calling_convention == ProcCC_Odin) { - param_count += 1; - } if (type->Proc.param_count != 0) { GB_ASSERT(type->Proc.params->kind == Type_Tuple); @@ -1519,21 +1516,23 @@ LLVMTypeRef lb_type_internal_for_procedures_raw(lbModule *m, Type *type) { m->internal_type_level += 1; defer (m->internal_type_level -= 1); + bool return_is_tuple = false; LLVMTypeRef ret = nullptr; LLVMTypeRef *params = gb_alloc_array(permanent_allocator(), LLVMTypeRef, param_count); bool *params_by_ptr = gb_alloc_array(permanent_allocator(), bool, param_count); if (type->Proc.result_count != 0) { Type *single_ret = reduce_tuple_to_single_type(type->Proc.results); - if (is_type_proc(single_ret)) { + if (is_type_proc(single_ret)) { single_ret = t_rawptr; } ret = lb_type(m, single_ret); - if (ret != nullptr) { - if (is_type_boolean(single_ret) && - is_calling_convention_none(type->Proc.calling_convention) && - type_size_of(single_ret) <= 1) { - ret = LLVMInt1TypeInContext(m->ctx); - } + if (is_type_tuple(single_ret)) { + return_is_tuple = true; + } + if (is_type_boolean(single_ret) && + is_calling_convention_none(type->Proc.calling_convention) && + type_size_of(single_ret) <= 1) { + ret = LLVMInt1TypeInContext(m->ctx); } } @@ -1571,12 +1570,8 @@ LLVMTypeRef lb_type_internal_for_procedures_raw(lbModule *m, Type *type) { params[param_index++] = param_type; } } - if (param_index < param_count) { - params[param_index++] = lb_type(m, t_rawptr); - } GB_ASSERT(param_index == param_count); - - lbFunctionType *ft = lb_get_abi_info(m->ctx, params, param_count, ret, ret != nullptr, type->Proc.calling_convention); + lbFunctionType *ft = lb_get_abi_info(m->ctx, params, param_count, ret, ret != nullptr, return_is_tuple, type->Proc.calling_convention); { for_array(j, ft->args) { auto arg = ft->args[j]; @@ -1593,10 +1588,10 @@ LLVMTypeRef lb_type_internal_for_procedures_raw(lbModule *m, Type *type) { LLVMPrintTypeToString(ft->ret.type), LLVMGetTypeContext(ft->ret.type), ft->ctx, LLVMGetGlobalContext()); } - for_array(j, ft->args) { - if (params_by_ptr[j]) { + for (unsigned i = 0; i < param_count; i++) { + if (params_by_ptr[i]) { // NOTE(bill): The parameter needs to be passed "indirectly", override it - ft->args[j].kind = lbArg_Indirect; + ft->args[i].kind = lbArg_Indirect; } } @@ -2161,11 +2156,11 @@ LLVMTypeRef lb_type(lbModule *m, Type *type) { return llvm_type; } -lbFunctionType *lb_get_function_type(lbModule *m, lbProcedure *p, Type *pt) { +lbFunctionType *lb_get_function_type(lbModule *m, Type *pt) { lbFunctionType **ft_found = nullptr; ft_found = map_get(&m->function_type_map, pt); if (!ft_found) { - LLVMTypeRef llvm_proc_type = lb_type(p->module, pt); + LLVMTypeRef llvm_proc_type = lb_type(m, pt); gb_unused(llvm_proc_type); ft_found = map_get(&m->function_type_map, pt); } diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 968a702e2..b47168541 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -501,6 +501,14 @@ void lb_begin_procedure_body(lbProcedure *p) { // NOTE(bill): this must be parameter 0 String name = str_lit("agg.result"); + if (ft->multiple_return_original_type && + p->type->Proc.has_named_results) { + auto const &variables = p->type->Proc.results->Tuple.variables; + Entity *e = variables[variables.count-1]; + if (!is_blank_ident(e->token)) { + name = e->token.string; + } + } Type *ptr_type = alloc_type_pointer(reduce_tuple_to_single_type(p->type->Proc.results)); Entity *e = alloc_entity_param(nullptr, make_token_ident(name), ptr_type, false, false); @@ -580,14 +588,31 @@ void lb_begin_procedure_body(lbProcedure *p) { if (e->token.string != "") { GB_ASSERT(!is_blank_ident(e->token)); - // NOTE(bill): Don't even bother trying to optimize this with the return ptr value - // This will violate the defer rules if you do: - // foo :: proc() -> (x, y: T) { - // defer x = ... // defer is executed after the `defer` - // return // the values returned should be zeroed - // } - // NOTE(bill): REALLY, don't even bother. - lbAddr res = lb_add_local(p, e->type, e); + lbAddr res = {}; + + lbFunctionType *ft = p->abi_function_type; + if (ft->multiple_return_original_type && + i < results->variables.count-1) { + isize ret_offset = param_offset + ft->original_arg_count + i; + lbValue ptr = {}; + ptr.value = LLVMGetParam(p->value, cast(unsigned)ret_offset); + ptr.type = alloc_type_pointer(e->type); + res = lb_addr(ptr); + + lb_add_entity(p->module, e, ptr); + lb_add_debug_local_variable(p, ptr.value, e->type, e->token); + } else { + + // NOTE(bill): Don't even bother trying to optimize this with the return ptr value + // This will violate the defer rules if you do: + // foo :: proc() -> (x, y: T) { + // defer x = ... // defer is executed after the `defer` + // return // the values returned should be zeroed + // } + // NOTE(bill): REALLY, don't even bother. + res = lb_add_local(p, e->type, e); + } + if (e->Variable.param_value.kind != ParameterValue_Invalid) { lbValue c = lb_handle_param_value(p, e->type, e->Variable.param_value, e->token.pos); lb_addr_store(p, res, c); @@ -734,6 +759,7 @@ lbValue lb_emit_call_internal(lbProcedure *p, lbValue value, lbValue return_ptr, if (return_ptr.value != nullptr) { args[arg_index++] = return_ptr.value; } + for_array(i, processed_args) { lbValue arg = processed_args[i]; if (is_type_proc(arg.type)) { @@ -741,16 +767,23 @@ lbValue lb_emit_call_internal(lbProcedure *p, lbValue value, lbValue return_ptr, } args[arg_index++] = arg.value; } + if (context_ptr.addr.value != nullptr) { LLVMValueRef cp = context_ptr.addr.value; cp = LLVMBuildPointerCast(p->builder, cp, lb_type(p->module, t_rawptr), ""); args[arg_index++] = cp; } + + GB_ASSERT(arg_index == arg_count); + LLVMBasicBlockRef curr_block = LLVMGetInsertBlock(p->builder); GB_ASSERT(curr_block != p->decl_block->block); { - LLVMTypeRef fnp = lb_type_internal_for_procedures_raw(p->module, value.type); + Type *proc_type = base_type(value.type); + GB_ASSERT(proc_type->kind == Type_Proc); + + LLVMTypeRef fnp = lb_type_internal_for_procedures_raw(p->module, proc_type); LLVMTypeRef ftp = LLVMPointerType(fnp, 0); LLVMValueRef fn = value.value; if (!lb_is_type_kind(LLVMTypeOf(value.value), LLVMFunctionTypeKind)) { @@ -775,10 +808,11 @@ lbValue lb_emit_call_internal(lbProcedure *p, lbValue value, lbValue return_ptr, // LLVMTypeKind arg_kind = LLVMGetTypeKind(arg_type); GB_ASSERT_MSG( arg_type == param_type, - "Parameter types do not match: %s != %s, argument: %s", + "Parameter types do not match: %s != %s, argument: %s\n\t%s", LLVMPrintTypeToString(arg_type), LLVMPrintTypeToString(param_type), - LLVMPrintValueToString(args[i]) + LLVMPrintValueToString(args[i]), + LLVMPrintTypeToString(fnp) ); } } @@ -915,8 +949,9 @@ lbValue lb_emit_call(lbProcedure *p, lbValue value, Array const &args, bool is_odin_cc = is_calling_convention_odin(pt->Proc.calling_convention); - lbFunctionType *ft = lb_get_function_type(m, p, pt); + lbFunctionType *ft = lb_get_function_type(m, pt); bool return_by_pointer = ft->ret.kind == lbArg_Indirect; + bool split_returns = ft->multiple_return_original_type != nullptr; unsigned param_index = 0; for (isize i = 0; i < param_count; i++) { @@ -979,13 +1014,19 @@ lbValue lb_emit_call(lbProcedure *p, lbValue value, Array const &args, } Type *rt = reduce_tuple_to_single_type(results); - if (return_by_pointer) { - lbValue return_ptr = {}; - if (return_ptr.value == nullptr) { - lbAddr r = lb_add_local_generated(p, rt, true); - return_ptr = r.addr; + Type *original_rt = rt; + if (split_returns) { + GB_ASSERT(rt->kind == Type_Tuple); + for (isize j = 0; j < rt->Tuple.variables.count-1; j++) { + Type *partial_return_type = rt->Tuple.variables[j]->type; + lbValue partial_return_ptr = lb_add_local_generated(p, partial_return_type, true).addr; + array_add(&processed_args, partial_return_ptr); } - GB_ASSERT(is_type_pointer(return_ptr.type)); + rt = reduce_tuple_to_single_type(rt->Tuple.variables[rt->Tuple.variables.count-1]->type); + } + + if (return_by_pointer) { + lbValue return_ptr = lb_add_local_generated(p, rt, true).addr; lb_emit_call_internal(p, value, return_ptr, processed_args, nullptr, context_ptr, inlining); result = lb_emit_load(p, return_ptr); } else if (rt != nullptr) { @@ -1005,6 +1046,22 @@ lbValue lb_emit_call(lbProcedure *p, lbValue value, Array const &args, lb_emit_call_internal(p, value, {}, processed_args, nullptr, context_ptr, inlining); } + if (original_rt != rt) { + GB_ASSERT(split_returns); + GB_ASSERT(original_rt->kind == Type_Tuple); + lbValue result_ptr = lb_add_local_generated(p, original_rt, false).addr; + isize ret_count = original_rt->Tuple.variables.count; + isize offset = ft->original_arg_count; + for (isize j = 0; j < ret_count-1; j++) { + lbValue ret_arg_ptr = processed_args[offset + j]; + lbValue ret_arg = lb_emit_load(p, ret_arg_ptr); + lb_emit_store(p, lb_emit_struct_ep(p, result_ptr, cast(i32)j), ret_arg); + } + lb_emit_store(p, lb_emit_struct_ep(p, result_ptr, cast(i32)(ret_count-1)), result); + + result = lb_emit_load(p, result_ptr); + } + } Entity **found = map_get(&p->module->procedure_values, value.value); diff --git a/src/llvm_backend_stmt.cpp b/src/llvm_backend_stmt.cpp index 9159f7550..1d28ea1c6 100644 --- a/src/llvm_backend_stmt.cpp +++ b/src/llvm_backend_stmt.cpp @@ -1576,9 +1576,27 @@ void lb_build_assignment(lbProcedure *p, Array &lvals, Slice cons } } -void lb_build_return_stmt_internal(lbProcedure *p, lbValue const &res) { - lbFunctionType *ft = lb_get_function_type(p->module, p, p->type); +void lb_build_return_stmt_internal(lbProcedure *p, lbValue res) { + lbFunctionType *ft = lb_get_function_type(p->module, p->type); bool return_by_pointer = ft->ret.kind == lbArg_Indirect; + bool split_returns = ft->multiple_return_original_type != nullptr; + + if (split_returns) { + GB_ASSERT(res.value != nullptr); + Type *res_type = res.type; + GB_ASSERT(is_type_tuple(res_type)); + isize res_count = res_type->Tuple.variables.count; + + isize param_offset = return_by_pointer ? 1 : 0; + param_offset += ft->original_arg_count; + for (isize i = 0; i < res_count-1; i++) { + lbValue ret_ptr = {}; + ret_ptr.value = LLVMGetParam(p->value, cast(unsigned)(param_offset + i)); + ret_ptr.type = alloc_type_pointer(res_type->Tuple.variables[i]->type); + lb_emit_store(p, ret_ptr, lb_emit_struct_ev(p, res, cast(i32)i)); + } + res = lb_emit_struct_ev(p, res, cast(i32)(res_count-1)); + } if (return_by_pointer) { if (res.value != nullptr) { @@ -1617,7 +1635,7 @@ void lb_build_return_stmt(lbProcedure *p, Slice const &return_results) { isize return_count = p->type->Proc.result_count; isize res_count = return_results.count; - lbFunctionType *ft = lb_get_function_type(p->module, p, p->type); + lbFunctionType *ft = lb_get_function_type(p->module, p->type); bool return_by_pointer = ft->ret.kind == lbArg_Indirect; if (return_count == 0) { diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp index 42f84ade0..fa8433a36 100644 --- a/src/llvm_backend_utility.cpp +++ b/src/llvm_backend_utility.cpp @@ -436,7 +436,7 @@ lbValue lb_emit_or_else(lbProcedure *p, Ast *arg, Ast *else_expr, TypeAndValue c } void lb_build_return_stmt(lbProcedure *p, Slice const &return_results); -void lb_build_return_stmt_internal(lbProcedure *p, lbValue const &res); +void lb_build_return_stmt_internal(lbProcedure *p, lbValue res); lbValue lb_emit_or_return(lbProcedure *p, Ast *arg, TypeAndValue const &tv) { lbValue lhs = {};