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...@@ -2394,24 +2394,31 @@ static LLVMValueRef ir_render_save_err_ret_addr(CodeGen *g, IrExecutable *execut
2394}2394}
23952395
2396static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrInstructionReturn *return_instruction) {2396static 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
2404 if (want_first_arg_sret(g, &g->cur_fn->type_entry->data.fn.fn_type_id)) {2397 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 }
2405 assert(g->cur_ret_ptr);2402 assert(g->cur_ret_ptr);
2406 src_assert(return_instruction->value->value.special != ConstValSpecialRuntime,2403 src_assert(return_instruction->value->value.special != ConstValSpecialRuntime,
2407 return_instruction->base.source_node);2404 return_instruction->base.source_node);
2408 LLVMValueRef value = ir_llvm_value(g, return_instruction->value);2405 LLVMValueRef value = ir_llvm_value(g, return_instruction->value);
2406 ZigType *return_type = return_instruction->value->value.type;
2409 gen_assign_raw(g, g->cur_ret_ptr, get_pointer_to_type(g, return_type, false), value);2407 gen_assign_raw(g, g->cur_ret_ptr, get_pointer_to_type(g, return_type, false), value);
2410 LLVMBuildRetVoid(g->builder);2408 LLVMBuildRetVoid(g->builder);
2411 } else if (handle_is_ptr(return_type)) {2409 } else if (g->cur_fn->type_entry->data.fn.fn_type_id.cc != CallingConventionAsync &&
2412 LLVMValueRef value = ir_llvm_value(g, return_instruction->value);2410 handle_is_ptr(g->cur_fn->type_entry->data.fn.fn_type_id.return_type))
2413 LLVMValueRef by_val_value = gen_load_untyped(g, value, 0, false, "");2411 {
2414 LLVMBuildRet(g->builder, by_val_value);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);
2415 } else {2422 } else {
2416 LLVMValueRef value = ir_llvm_value(g, return_instruction->value);2423 LLVMValueRef value = ir_llvm_value(g, return_instruction->value);
2417 LLVMBuildRet(g->builder, value);2424 LLVMBuildRet(g->builder, value);
...@@ -3755,7 +3762,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr...@@ -3755,7 +3762,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
3755 bool prefix_arg_err_ret_stack = get_prefix_arg_err_ret_stack(g, fn_type_id);3762 bool prefix_arg_err_ret_stack = get_prefix_arg_err_ret_stack(g, fn_type_id);
3756 bool is_var_args = fn_type_id->is_var_args;3763 bool is_var_args = fn_type_id->is_var_args;
3757 ZigList<LLVMValueRef> gen_param_values = {};3764 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;
3759 if (first_arg_ret) {3766 if (first_arg_ret) {
3760 gen_param_values.append(result_loc);3767 gen_param_values.append(result_loc);
3761 }3768 }
...@@ -6804,20 +6811,24 @@ static void do_code_gen(CodeGen *g) {...@@ -6804,20 +6811,24 @@ static void do_code_gen(CodeGen *g) {
6804 FnTypeId *fn_type_id = &fn_table_entry->type_entry->data.fn.fn_type_id;6811 FnTypeId *fn_type_id = &fn_table_entry->type_entry->data.fn.fn_type_id;
6805 CallingConvention cc = fn_type_id->cc;6812 CallingConvention cc = fn_type_id->cc;
6806 bool is_c_abi = cc == CallingConventionC;6813 bool is_c_abi = cc == CallingConventionC;
6814 bool want_sret = want_first_arg_sret(g, fn_type_id);
68076815
6808 LLVMValueRef fn = fn_llvm_value(g, fn_table_entry);6816 LLVMValueRef fn = fn_llvm_value(g, fn_table_entry);
6809 g->cur_fn = fn_table_entry;6817 g->cur_fn = fn_table_entry;
6810 g->cur_fn_val = fn;6818 g->cur_fn_val = fn;
6811 ZigType *return_type = fn_type_id->return_type;6819
6812 if (handle_is_ptr(return_type)) {6820 build_all_basic_blocks(g, fn_table_entry);
6821 clear_debug_source_node(g);
6822
6823 if (want_sret) {
6813 g->cur_ret_ptr = LLVMGetParam(fn, 0);6824 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
6814 } else {6828 } else {
6815 g->cur_ret_ptr = nullptr;6829 g->cur_ret_ptr = nullptr;
6816 }6830 }
68176831
6818 build_all_basic_blocks(g, fn_table_entry);
6819 clear_debug_source_node(g);
6820
6821 uint32_t err_ret_trace_arg_index = get_err_ret_trace_arg_index(g, fn_table_entry);6832 uint32_t err_ret_trace_arg_index = get_err_ret_trace_arg_index(g, fn_table_entry);
6822 bool have_err_ret_trace_arg = err_ret_trace_arg_index != UINT32_MAX;6833 bool have_err_ret_trace_arg = err_ret_trace_arg_index != UINT32_MAX;
6823 if (have_err_ret_trace_arg) {6834 if (have_err_ret_trace_arg) {
...@@ -6863,8 +6874,7 @@ static void do_code_gen(CodeGen *g) {...@@ -6863,8 +6874,7 @@ static void do_code_gen(CodeGen *g) {
6863 }6874 }
68646875
6865 ZigType *import = get_scope_import(&fn_table_entry->fndef_scope->base);6876 ZigType *import = get_scope_import(&fn_table_entry->fndef_scope->base);
68666877 unsigned gen_i_init = want_sret ? 1 : 0;
6867 unsigned gen_i_init = want_first_arg_sret(g, fn_type_id) ? 1 : 0;
68686878
6869 // create debug variable declarations for variables and allocate all local variables6879 // create debug variable declarations for variables and allocate all local variables
6870 FnWalk fn_walk_var = {};6880 FnWalk fn_walk_var = {};
test/stage1/behavior/struct.zig+21
...@@ -578,3 +578,24 @@ test "default struct initialization fields" {...@@ -578,3 +578,24 @@ test "default struct initialization fields" {
578 };578 };
579 expectEqual(1239, x.a + x.b);579 expectEqual(1239, x.a + x.b);
580}580}
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}