diff options
Diffstat (limited to 'src/llvm_backend_proc.cpp')
| -rw-r--r-- | src/llvm_backend_proc.cpp | 76 |
1 files changed, 64 insertions, 12 deletions
diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index f14fc8a8c..f8dffa9b6 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -1,4 +1,3 @@ - LLVMValueRef lb_call_intrinsic(lbProcedure *p, const char *name, LLVMValueRef* args, unsigned arg_count, LLVMTypeRef* types, unsigned type_count) { unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name)); @@ -596,16 +595,69 @@ 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. - // - // IMPORTANT NOTE(bill): REALLY, don't even bother!!!!!! - lbAddr res = lb_add_local(p, e->type, e); + lbAddr res = {}; + if (p->entity && p->entity->decl_info && + p->entity->decl_info->defer_use_checked && + p->entity->decl_info->defer_used == 0) { + + // NOTE(bill): this is a bodge to get around the issue of the problem BELOW + // We check to see if we ever use a defer statement ever within a procedure and if it + // if it never happens, see if you can possibly do take the return value pointer + // + // NOTE(bill): this could be buggy in that I have missed a case where `defer` was used + // + // TODO(bill): This could be optimized to check to see where a `defer` only uses + // the variable in question + + bool has_return_ptr = p->return_ptr.addr.value != nullptr; + lbValue ptr = {}; + + if (ft->multiple_return_original_type != nullptr) { + isize the_offset = -1; + if (i+1 < results->variables.count) { + the_offset = cast(isize)param_offset + ft->original_arg_count + i; + } else if (has_return_ptr) { + GB_ASSERT(i+1 == results->variables.count); + the_offset = 0; + } + if (the_offset >= 0) { + lbValue ptr = {}; + ptr.value = LLVMGetParam(p->value, cast(unsigned)the_offset); + ptr.type = alloc_type_pointer(e->type); + + + } + } else if (has_return_ptr) { + lbValue ptr = p->return_ptr.addr; + + if (results->variables.count > 1) { + ptr = lb_emit_tuple_ep(p, ptr, cast(i32)i); + } + GB_ASSERT(is_type_pointer(ptr.type)); + GB_ASSERT(are_types_identical(type_deref(ptr.type), e->type)); + } + + if (ptr.value != nullptr) { + lb_add_entity(p->module, e, ptr); + lb_add_debug_local_variable(p, ptr.value, e->type, e->token); + // NOTE(bill): no need to zero on the callee side as it is zeroed on the caller side + + res = lb_addr(ptr); + } + } + + if (res.addr.type == nullptr) { + // 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. + // + // IMPORTANT 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); @@ -1006,7 +1058,7 @@ lbValue lb_emit_call(lbProcedure *p, lbValue value, Array<lbValue> const &args, 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; + lbValue partial_return_ptr = lb_add_local(p, partial_return_type, nullptr, true, false).addr; array_add(&processed_args, partial_return_ptr); } rt = reduce_tuple_to_single_type(rt->Tuple.variables[rt->Tuple.variables.count-1]->type); |