authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-06-21 14:44:49-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-06-21 14:44:49-04:00
log142e77abbb8a88c2c6473921d0c600faf3d34a62
treef434e498c71cf8bd5ce979d7705b15373b8b6582
parent48ccf427afa59fbcae969f3edd224b44eef153c9
signaturelock-open Commit is signed but in an unrecognized format.

fix extern functions returning byval structs


2 files changed, 50 insertions(+), 19 deletions(-)

src/codegen.cpp+29-19
......@@ -2394,24 +2394,31 @@ static LLVMValueRef ir_render_save_err_ret_addr(CodeGen *g, IrExecutable *execut
23942394}
23952395
23962396static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrInstructionReturn *return_instruction) {
2397 if (return_instruction->value == nullptr) {
2398 LLVMBuildRetVoid(g->builder);
2399 return nullptr;
2400 }
2401
2402 ZigType *return_type = return_instruction->value->value.type;
2403
24042397 if (want_first_arg_sret(g, &g->cur_fn->type_entry->data.fn.fn_type_id)) {
2398 if (return_instruction->value == nullptr) {
2399 LLVMBuildRetVoid(g->builder);
2400 return nullptr;
2401 }
24052402 assert(g->cur_ret_ptr);
24062403 src_assert(return_instruction->value->value.special != ConstValSpecialRuntime,
24072404 return_instruction->base.source_node);
24082405 LLVMValueRef value = ir_llvm_value(g, return_instruction->value);
2406 ZigType *return_type = return_instruction->value->value.type;
24092407 gen_assign_raw(g, g->cur_ret_ptr, get_pointer_to_type(g, return_type, false), value);
24102408 LLVMBuildRetVoid(g->builder);
2411 } else if (handle_is_ptr(return_type)) {
2412 LLVMValueRef value = ir_llvm_value(g, return_instruction->value);
2413 LLVMValueRef by_val_value = gen_load_untyped(g, value, 0, false, "");
2414 LLVMBuildRet(g->builder, by_val_value);
2409 } else if (g->cur_fn->type_entry->data.fn.fn_type_id.cc != CallingConventionAsync &&
2410 handle_is_ptr(g->cur_fn->type_entry->data.fn.fn_type_id.return_type))
2411 {
2412 if (return_instruction->value == nullptr) {
2413 LLVMValueRef by_val_value = gen_load_untyped(g, g->cur_ret_ptr, 0, false, "");
2414 LLVMBuildRet(g->builder, by_val_value);
2415 } else {
2416 LLVMValueRef value = ir_llvm_value(g, return_instruction->value);
2417 LLVMValueRef by_val_value = gen_load_untyped(g, value, 0, false, "");
2418 LLVMBuildRet(g->builder, by_val_value);
2419 }
2420 } else if (return_instruction->value == nullptr) {
2421 LLVMBuildRetVoid(g->builder);
24152422 } else {
24162423 LLVMValueRef value = ir_llvm_value(g, return_instruction->value);
24172424 LLVMBuildRet(g->builder, value);
......@@ -3755,7 +3762,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
37553762 bool prefix_arg_err_ret_stack = get_prefix_arg_err_ret_stack(g, fn_type_id);
37563763 bool is_var_args = fn_type_id->is_var_args;
37573764 ZigList<LLVMValueRef> gen_param_values = {};
3758 LLVMValueRef result_loc = (first_arg_ret || instruction->is_async) ? ir_llvm_value(g, instruction->result_loc) : nullptr;
3765 LLVMValueRef result_loc = instruction->result_loc ? ir_llvm_value(g, instruction->result_loc) : nullptr;
37593766 if (first_arg_ret) {
37603767 gen_param_values.append(result_loc);
37613768 }
......@@ -6804,20 +6811,24 @@ static void do_code_gen(CodeGen *g) {
68046811 FnTypeId *fn_type_id = &fn_table_entry->type_entry->data.fn.fn_type_id;
68056812 CallingConvention cc = fn_type_id->cc;
68066813 bool is_c_abi = cc == CallingConventionC;
6814 bool want_sret = want_first_arg_sret(g, fn_type_id);
68076815
68086816 LLVMValueRef fn = fn_llvm_value(g, fn_table_entry);
68096817 g->cur_fn = fn_table_entry;
68106818 g->cur_fn_val = fn;
6811 ZigType *return_type = fn_type_id->return_type;
6812 if (handle_is_ptr(return_type)) {
6819
6820 build_all_basic_blocks(g, fn_table_entry);
6821 clear_debug_source_node(g);
6822
6823 if (want_sret) {
68136824 g->cur_ret_ptr = LLVMGetParam(fn, 0);
6825 } else if (handle_is_ptr(fn_type_id->return_type)) {
6826 g->cur_ret_ptr = build_alloca(g, fn_type_id->return_type, "result", 0);
6827 // TODO add debug info variable for this
68146828 } else {
68156829 g->cur_ret_ptr = nullptr;
68166830 }
68176831
6818 build_all_basic_blocks(g, fn_table_entry);
6819 clear_debug_source_node(g);
6820
68216832 uint32_t err_ret_trace_arg_index = get_err_ret_trace_arg_index(g, fn_table_entry);
68226833 bool have_err_ret_trace_arg = err_ret_trace_arg_index != UINT32_MAX;
68236834 if (have_err_ret_trace_arg) {
......@@ -6863,8 +6874,7 @@ static void do_code_gen(CodeGen *g) {
68636874 }
68646875
68656876 ZigType *import = get_scope_import(&fn_table_entry->fndef_scope->base);
6866
6867 unsigned gen_i_init = want_first_arg_sret(g, fn_type_id) ? 1 : 0;
6877 unsigned gen_i_init = want_sret ? 1 : 0;
68686878
68696879 // create debug variable declarations for variables and allocate all local variables
68706880 FnWalk fn_walk_var = {};
test/stage1/behavior/struct.zig+21
......@@ -578,3 +578,24 @@ test "default struct initialization fields" {
578578 };
579579 expectEqual(1239, x.a + x.b);
580580}
581
582test "extern fn returns struct by value" {
583 const S = struct {
584 fn entry() void {
585 var x = makeBar(10);
586 expectEqual(i32(10), x.handle);
587 }
588
589 const ExternBar = extern struct {
590 handle: i32,
591 };
592
593 extern fn makeBar(t: i32) ExternBar {
594 return ExternBar{
595 .handle = t,
596 };
597 }
598 };
599 S.entry();
600 comptime S.entry();
601}