aboutsummaryrefslogtreecommitdiff
path: root/src/llvm_backend_proc.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/llvm_backend_proc.cpp')
-rw-r--r--src/llvm_backend_proc.cpp19
1 files changed, 19 insertions, 0 deletions
diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp
index 5aee5b639..fee825a2f 100644
--- a/src/llvm_backend_proc.cpp
+++ b/src/llvm_backend_proc.cpp
@@ -579,6 +579,8 @@ gb_internal void lb_begin_procedure_body(lbProcedure *p) {
p->raw_input_parameters = array_make<LLVMValueRef>(permanent_allocator(), raw_input_parameters_count);
LLVMGetParams(p->value, p->raw_input_parameters.data);
+ bool is_odin_cc = is_calling_convention_odin(ft->calling_convention);
+
unsigned param_index = 0;
for_array(i, params->variables) {
Entity *e = params->variables[i];
@@ -613,9 +615,26 @@ gb_internal void lb_begin_procedure_body(lbProcedure *p) {
}
} else if (arg_type->kind == lbArg_Indirect) {
if (e->token.string.len != 0 && !is_blank_ident(e->token.string)) {
+ i64 sz = type_size_of(e->type);
+ bool do_callee_copy = false;
+
+ if (is_odin_cc) {
+ do_callee_copy = sz <= 16;
+ if (build_context.internal_by_value) {
+ do_callee_copy = true;
+ }
+ }
+
lbValue ptr = {};
ptr.value = LLVMGetParam(p->value, param_offset+param_index);
ptr.type = alloc_type_pointer(e->type);
+
+ if (do_callee_copy) {
+ lbValue new_ptr = lb_add_local_generated(p, e->type, false).addr;
+ lb_mem_copy_non_overlapping(p, new_ptr, ptr, lb_const_int(p->module, t_uint, sz));
+ ptr = new_ptr;
+ }
+
lb_add_entity(p->module, e, ptr);
lb_add_debug_param_variable(p, ptr.value, e->type, e->token, param_index+1, p->decl_block);
}