authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-08-14 12:52:20-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-08-14 12:52:20-04:00
log64c293f8a4ce5fcbb506c32b989a88d982f005ce
treed3f8332a227ddd4a316bd08ca93ba1d8624b4b6a
parentf3f838cc016fd8190a9bba46fa495fbc27325492
signature Commit is signed but in an unrecognized format.

codegen for async call of blocking function


2 files changed, 151 insertions(+), 90 deletions(-)

src/analyze.cpp+44-10
......@@ -3831,7 +3831,7 @@ static void add_async_error_notes(CodeGen *g, ErrorMsg *msg, ZigFn *fn) {
38313831}
38323832
38333833// This function resolves functions being inferred async.
3834static void analyze_fn_async(CodeGen *g, ZigFn *fn) {
3834static void analyze_fn_async(CodeGen *g, ZigFn *fn, bool resolve_frame) {
38353835 if (fn->inferred_async_node == inferred_async_checking) {
38363836 // TODO call graph cycle detected, disallow the recursion
38373837 fn->inferred_async_node = inferred_async_none;
......@@ -3841,7 +3841,9 @@ static void analyze_fn_async(CodeGen *g, ZigFn *fn) {
38413841 return;
38423842 }
38433843 if (fn->inferred_async_node != nullptr) {
3844 resolve_async_fn_frame(g, fn);
3844 if (resolve_frame) {
3845 resolve_async_fn_frame(g, fn);
3846 }
38453847 return;
38463848 }
38473849 fn->inferred_async_node = inferred_async_checking;
......@@ -3870,7 +3872,7 @@ static void analyze_fn_async(CodeGen *g, ZigFn *fn) {
38703872 }
38713873 }
38723874 assert(callee->anal_state == FnAnalStateComplete);
3873 analyze_fn_async(g, callee);
3875 analyze_fn_async(g, callee, true);
38743876 if (callee->anal_state == FnAnalStateInvalid) {
38753877 fn->anal_state = FnAnalStateInvalid;
38763878 return;
......@@ -3886,7 +3888,9 @@ static void analyze_fn_async(CodeGen *g, ZigFn *fn) {
38863888 fn->anal_state = FnAnalStateInvalid;
38873889 return;
38883890 }
3889 resolve_async_fn_frame(g, fn);
3891 if (resolve_frame) {
3892 resolve_async_fn_frame(g, fn);
3893 }
38903894 return;
38913895 }
38923896 }
......@@ -4141,7 +4145,7 @@ void semantic_analyze(CodeGen *g) {
41414145 // second pass over functions for detecting async
41424146 for (g->fn_defs_index = 0; g->fn_defs_index < g->fn_defs.length; g->fn_defs_index += 1) {
41434147 ZigFn *fn_entry = g->fn_defs.at(g->fn_defs_index);
4144 analyze_fn_async(g, fn_entry);
4148 analyze_fn_async(g, fn_entry, true);
41454149 }
41464150}
41474151
......@@ -5212,6 +5216,36 @@ static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) {
52125216 return ErrorSemanticAnalyzeFail;
52135217 }
52145218 }
5219 analyze_fn_async(g, fn, false);
5220 if (fn->anal_state == FnAnalStateInvalid)
5221 return ErrorSemanticAnalyzeFail;
5222
5223 if (!fn_is_async(fn)) {
5224 ZigType *fn_type = fn->type_entry;
5225 FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id;
5226 ZigType *ptr_return_type = get_pointer_to_type(g, fn_type_id->return_type, false);
5227
5228 // label (grep this): [fn_frame_struct_layout]
5229 ZigList<SrcField> fields = {};
5230
5231 fields.append({"@fn_ptr", g->builtin_types.entry_usize, 0});
5232 fields.append({"@resume_index", g->builtin_types.entry_usize, 0});
5233 fields.append({"@awaiter", g->builtin_types.entry_usize, 0});
5234 fields.append({"@prev_val", g->builtin_types.entry_usize, 0});
5235
5236 fields.append({"@result_ptr_callee", ptr_return_type, 0});
5237 fields.append({"@result_ptr_awaiter", ptr_return_type, 0});
5238 fields.append({"@result", fn_type_id->return_type, 0});
5239
5240 frame_type->data.frame.locals_struct = get_struct_type(g, buf_ptr(&frame_type->name),
5241 fields.items, fields.length, target_fn_align(g->zig_target));
5242 frame_type->abi_size = frame_type->data.frame.locals_struct->abi_size;
5243 frame_type->abi_align = frame_type->data.frame.locals_struct->abi_align;
5244 frame_type->size_in_bits = frame_type->data.frame.locals_struct->size_in_bits;
5245
5246 return ErrorNone;
5247 }
5248
52155249 ZigType *fn_type = get_async_fn_type(g, fn->type_entry);
52165250
52175251 if (fn->analyzed_executable.need_err_code_spill) {
......@@ -5252,7 +5286,7 @@ static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) {
52525286 frame_type->data.frame.locals_struct = g->builtin_types.entry_invalid;
52535287 return ErrorSemanticAnalyzeFail;
52545288 }
5255 analyze_fn_async(g, callee);
5289 analyze_fn_async(g, callee, true);
52565290 if (!fn_is_async(callee))
52575291 continue;
52585292
......@@ -5268,6 +5302,8 @@ static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) {
52685302 fn->alloca_gen_list.append(alloca_gen);
52695303 call->frame_result_loc = &alloca_gen->base;
52705304 }
5305 FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id;
5306 ZigType *ptr_return_type = get_pointer_to_type(g, fn_type_id->return_type, false);
52715307
52725308 // label (grep this): [fn_frame_struct_layout]
52735309 ZigList<SrcField> fields = {};
......@@ -5277,9 +5313,6 @@ static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) {
52775313 fields.append({"@awaiter", g->builtin_types.entry_usize, 0});
52785314 fields.append({"@prev_val", g->builtin_types.entry_usize, 0});
52795315
5280 FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id;
5281 ZigType *ptr_return_type = get_pointer_to_type(g, fn_type_id->return_type, false);
5282
52835316 fields.append({"@result_ptr_callee", ptr_return_type, 0});
52845317 fields.append({"@result_ptr_awaiter", ptr_return_type, 0});
52855318 fields.append({"@result", fn_type_id->return_type, 0});
......@@ -7651,7 +7684,8 @@ static void resolve_llvm_types_anyerror(CodeGen *g) {
76517684}
76527685
76537686static void resolve_llvm_types_async_frame(CodeGen *g, ZigType *frame_type, ResolveStatus wanted_resolve_status) {
7654 resolve_llvm_types_struct(g, frame_type->data.frame.locals_struct, wanted_resolve_status, frame_type);
7687 ZigType *passed_frame_type = fn_is_async(frame_type->data.frame.fn) ? frame_type : nullptr;
7688 resolve_llvm_types_struct(g, frame_type->data.frame.locals_struct, wanted_resolve_status, passed_frame_type);
76557689 frame_type->llvm_type = frame_type->data.frame.locals_struct->llvm_type;
76567690 frame_type->llvm_di_type = frame_type->data.frame.locals_struct->llvm_di_type;
76577691}
src/codegen.cpp+107-80
......@@ -3850,73 +3850,74 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
38503850 LLVMValueRef frame_result_loc;
38513851 LLVMValueRef awaiter_init_val;
38523852 LLVMValueRef ret_ptr;
3853 if (instruction->is_async) {
3854 awaiter_init_val = zero;
3855
3856 if (instruction->new_stack == nullptr) {
3857 frame_result_loc = result_loc;
3858
3859 if (ret_has_bits) {
3860 // Use the result location which is inside the frame if this is an async call.
3861 ret_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, frame_ret_start + 2, "");
3862 }
3863 } else {
3864 LLVMValueRef frame_slice_ptr = ir_llvm_value(g, instruction->new_stack);
3865 if (ir_want_runtime_safety(g, &instruction->base)) {
3866 LLVMValueRef given_len_ptr = LLVMBuildStructGEP(g->builder, frame_slice_ptr, slice_len_index, "");
3867 LLVMValueRef given_frame_len = LLVMBuildLoad(g->builder, given_len_ptr, "");
3868 LLVMValueRef actual_frame_len = gen_frame_size(g, fn_val);
3869
3870 LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "FrameSizeCheckFail");
3871 LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "FrameSizeCheckOk");
3872
3873 LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntUGE, given_frame_len, actual_frame_len, "");
3874 LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block);
3853 if (callee_is_async) {
3854 if (instruction->is_async) {
3855 if (instruction->new_stack == nullptr) {
3856 awaiter_init_val = zero;
3857 frame_result_loc = result_loc;
3858
3859 if (ret_has_bits) {
3860 // Use the result location which is inside the frame if this is an async call.
3861 ret_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, frame_ret_start + 2, "");
3862 }
3863 } else if (cc == CallingConventionAsync) {
3864 awaiter_init_val = zero;
3865 LLVMValueRef frame_slice_ptr = ir_llvm_value(g, instruction->new_stack);
3866 if (ir_want_runtime_safety(g, &instruction->base)) {
3867 LLVMValueRef given_len_ptr = LLVMBuildStructGEP(g->builder, frame_slice_ptr, slice_len_index, "");
3868 LLVMValueRef given_frame_len = LLVMBuildLoad(g->builder, given_len_ptr, "");
3869 LLVMValueRef actual_frame_len = gen_frame_size(g, fn_val);
3870
3871 LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "FrameSizeCheckFail");
3872 LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "FrameSizeCheckOk");
3873
3874 LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntUGE, given_frame_len, actual_frame_len, "");
3875 LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block);
38753876
3876 LLVMPositionBuilderAtEnd(g->builder, fail_block);
3877 gen_safety_crash(g, PanicMsgIdFrameTooSmall);
3877 LLVMPositionBuilderAtEnd(g->builder, fail_block);
3878 gen_safety_crash(g, PanicMsgIdFrameTooSmall);
38783879
3879 LLVMPositionBuilderAtEnd(g->builder, ok_block);
3880 LLVMPositionBuilderAtEnd(g->builder, ok_block);
3881 }
3882 LLVMValueRef frame_ptr_ptr = LLVMBuildStructGEP(g->builder, frame_slice_ptr, slice_ptr_index, "");
3883 LLVMValueRef frame_ptr = LLVMBuildLoad(g->builder, frame_ptr_ptr, "");
3884 frame_result_loc = LLVMBuildBitCast(g->builder, frame_ptr,
3885 get_llvm_type(g, instruction->base.value.type), "");
3886
3887 if (ret_has_bits) {
3888 // Use the result location provided to the @asyncCall builtin
3889 ret_ptr = result_loc;
3890 }
38803891 }
3881 LLVMValueRef frame_ptr_ptr = LLVMBuildStructGEP(g->builder, frame_slice_ptr, slice_ptr_index, "");
3882 LLVMValueRef frame_ptr = LLVMBuildLoad(g->builder, frame_ptr_ptr, "");
3883 frame_result_loc = LLVMBuildBitCast(g->builder, frame_ptr,
3884 get_llvm_type(g, instruction->base.value.type), "");
38853892
3893 // even if prefix_arg_err_ret_stack is true, let the async function do its own
3894 // initialization.
3895 } else {
3896 frame_result_loc = ir_llvm_value(g, instruction->frame_result_loc);
3897 awaiter_init_val = LLVMBuildPtrToInt(g->builder, g->cur_frame_ptr, usize_type_ref, ""); // caller's own frame pointer
38863898 if (ret_has_bits) {
3887 // Use the result location provided to the @asyncCall builtin
3888 ret_ptr = result_loc;
3889 }
3890 }
3899 if (result_loc == nullptr) {
3900 // return type is a scalar, but we still need a pointer to it. Use the async fn frame.
3901 ret_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, frame_ret_start + 2, "");
3902 } else {
3903 // Use the call instruction's result location.
3904 ret_ptr = result_loc;
3905 }
38913906
3892 // even if prefix_arg_err_ret_stack is true, let the async function do its own
3893 // initialization.
3894 } else if (callee_is_async) {
3895 frame_result_loc = ir_llvm_value(g, instruction->frame_result_loc);
3896 awaiter_init_val = LLVMBuildPtrToInt(g->builder, g->cur_frame_ptr, usize_type_ref, ""); // caller's own frame pointer
3897 if (ret_has_bits) {
3898 if (result_loc == nullptr) {
3899 // return type is a scalar, but we still need a pointer to it. Use the async fn frame.
3900 ret_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, frame_ret_start + 2, "");
3901 } else {
3902 // Use the call instruction's result location.
3903 ret_ptr = result_loc;
3907 // Store a zero in the awaiter's result ptr to indicate we do not need a copy made.
3908 LLVMValueRef awaiter_ret_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, frame_ret_start + 1, "");
3909 LLVMValueRef zero_ptr = LLVMConstNull(LLVMGetElementType(LLVMTypeOf(awaiter_ret_ptr)));
3910 LLVMBuildStore(g->builder, zero_ptr, awaiter_ret_ptr);
39043911 }
39053912
3906 // Store a zero in the awaiter's result ptr to indicate we do not need a copy made.
3907 LLVMValueRef awaiter_ret_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, frame_ret_start + 1, "");
3908 LLVMValueRef zero_ptr = LLVMConstNull(LLVMGetElementType(LLVMTypeOf(awaiter_ret_ptr)));
3909 LLVMBuildStore(g->builder, zero_ptr, awaiter_ret_ptr);
3913 if (prefix_arg_err_ret_stack) {
3914 LLVMValueRef err_ret_trace_ptr_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc,
3915 frame_index_trace_arg(g, src_return_type), "");
3916 LLVMValueRef my_err_ret_trace_val = get_cur_err_ret_trace_val(g, instruction->base.scope);
3917 LLVMBuildStore(g->builder, my_err_ret_trace_val, err_ret_trace_ptr_ptr);
3918 }
39103919 }
39113920
3912 if (prefix_arg_err_ret_stack) {
3913 LLVMValueRef err_ret_trace_ptr_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc,
3914 frame_index_trace_arg(g, src_return_type), "");
3915 LLVMValueRef my_err_ret_trace_val = get_cur_err_ret_trace_val(g, instruction->base.scope);
3916 LLVMBuildStore(g->builder, my_err_ret_trace_val, err_ret_trace_ptr_ptr);
3917 }
3918 }
3919 if (instruction->is_async || callee_is_async) {
39203921 assert(frame_result_loc != nullptr);
39213922
39223923 LLVMValueRef fn_ptr_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, frame_fn_ptr_index, "");
......@@ -3934,6 +3935,29 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
39343935 LLVMValueRef ret_ptr_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, frame_ret_start, "");
39353936 LLVMBuildStore(g->builder, ret_ptr, ret_ptr_ptr);
39363937 }
3938 } else if (instruction->is_async) {
3939 // Async call of blocking function
3940 if (instruction->new_stack != nullptr) {
3941 zig_panic("TODO @asyncCall of non-async function");
3942 }
3943 frame_result_loc = result_loc;
3944 awaiter_init_val = LLVMConstAllOnes(usize_type_ref);
3945
3946 LLVMValueRef awaiter_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, frame_awaiter_index, "");
3947 LLVMBuildStore(g->builder, awaiter_init_val, awaiter_ptr);
3948
3949 if (ret_has_bits) {
3950 LLVMValueRef ret_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, frame_ret_start + 2, "");
3951 LLVMValueRef ret_ptr_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, frame_ret_start, "");
3952 LLVMBuildStore(g->builder, ret_ptr, ret_ptr_ptr);
3953
3954 if (first_arg_ret) {
3955 gen_param_values.append(ret_ptr);
3956 }
3957 }
3958 if (prefix_arg_err_ret_stack) {
3959 gen_param_values.append(get_cur_err_ret_trace_val(g, instruction->base.scope));
3960 }
39373961 } else {
39383962 if (first_arg_ret) {
39393963 gen_param_values.append(result_loc);
......@@ -3966,7 +3990,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
39663990 LLVMCallConv llvm_cc = get_llvm_cc(g, cc);
39673991 LLVMValueRef result;
39683992
3969 if (instruction->is_async || callee_is_async) {
3993 if (callee_is_async) {
39703994 uint32_t arg_start_i = frame_index_arg(g, fn_type->data.fn.fn_type_id.return_type);
39713995
39723996 LLVMValueRef casted_frame;
......@@ -3992,39 +4016,42 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
39924016 gen_assign_raw(g, arg_ptr, get_pointer_to_type(g, gen_param_types.at(arg_i), true),
39934017 gen_param_values.at(arg_i));
39944018 }
3995 }
3996 if (instruction->is_async) {
3997 gen_resume(g, fn_val, frame_result_loc, ResumeIdCall, nullptr);
3998 if (instruction->new_stack != nullptr) {
3999 return frame_result_loc;
4000 }
4001 return nullptr;
4002 } else if (callee_is_async) {
4003 ZigType *ptr_result_type = get_pointer_to_type(g, src_return_type, true);
40044019
4005 LLVMBasicBlockRef call_bb = gen_suspend_begin(g, "CallResume");
4020 if (instruction->is_async) {
4021 gen_resume(g, fn_val, frame_result_loc, ResumeIdCall, nullptr);
4022 if (instruction->new_stack != nullptr) {
4023 return frame_result_loc;
4024 }
4025 return nullptr;
4026 } else {
4027 ZigType *ptr_result_type = get_pointer_to_type(g, src_return_type, true);
40064028
4007 LLVMValueRef call_inst = gen_resume(g, fn_val, frame_result_loc, ResumeIdCall, nullptr);
4008 set_tail_call_if_appropriate(g, call_inst);
4009 LLVMBuildRetVoid(g->builder);
4029 LLVMBasicBlockRef call_bb = gen_suspend_begin(g, "CallResume");
4030
4031 LLVMValueRef call_inst = gen_resume(g, fn_val, frame_result_loc, ResumeIdCall, nullptr);
4032 set_tail_call_if_appropriate(g, call_inst);
4033 LLVMBuildRetVoid(g->builder);
40104034
4011 LLVMPositionBuilderAtEnd(g->builder, call_bb);
4012 gen_assert_resume_id(g, &instruction->base, ResumeIdReturn, PanicMsgIdResumedAnAwaitingFn, nullptr);
4013 render_async_var_decls(g, instruction->base.scope);
4035 LLVMPositionBuilderAtEnd(g->builder, call_bb);
4036 gen_assert_resume_id(g, &instruction->base, ResumeIdReturn, PanicMsgIdResumedAnAwaitingFn, nullptr);
4037 render_async_var_decls(g, instruction->base.scope);
40144038
4015 if (!type_has_bits(src_return_type))
4016 return nullptr;
4039 if (!type_has_bits(src_return_type))
4040 return nullptr;
40174041
4018 if (result_loc != nullptr)
4019 return get_handle_value(g, result_loc, src_return_type, ptr_result_type);
4042 if (result_loc != nullptr)
4043 return get_handle_value(g, result_loc, src_return_type, ptr_result_type);
40204044
4021 LLVMValueRef result_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, frame_ret_start + 2, "");
4022 return LLVMBuildLoad(g->builder, result_ptr, "");
4045 LLVMValueRef result_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, frame_ret_start + 2, "");
4046 return LLVMBuildLoad(g->builder, result_ptr, "");
4047 }
40234048 }
40244049
40254050 if (instruction->new_stack == nullptr) {
40264051 result = ZigLLVMBuildCall(g->builder, fn_val,
40274052 gen_param_values.items, (unsigned)gen_param_values.length, llvm_cc, fn_inline, "");
4053 } else if (instruction->is_async) {
4054 zig_panic("TODO @asyncCall of non-async function");
40284055 } else {
40294056 LLVMValueRef stacksave_fn_val = get_stacksave_fn_val(g);
40304057 LLVMValueRef stackrestore_fn_val = get_stackrestore_fn_val(g);