| ... | ... | @@ -3850,73 +3850,74 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr |
| 3850 | 3850 | LLVMValueRef frame_result_loc; |
| 3851 | 3851 | LLVMValueRef awaiter_init_val; |
| 3852 | 3852 | 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); |
| 3875 | 3876 | |
| 3876 | | LLVMPositionBuilderAtEnd(g->builder, fail_block); |
| 3877 | | gen_safety_crash(g, PanicMsgIdFrameTooSmall); |
| 3877 | LLVMPositionBuilderAtEnd(g->builder, fail_block); |
| 3878 | gen_safety_crash(g, PanicMsgIdFrameTooSmall); |
| 3878 | 3879 | |
| 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 | } |
| 3880 | 3891 | } |
| 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), ""); |
| 3885 | 3892 | |
| 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 |
| 3886 | 3898 | 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 | } |
| 3891 | 3906 | |
| 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); |
| 3904 | 3911 | } |
| 3905 | 3912 | |
| 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 | } |
| 3910 | 3919 | } |
| 3911 | 3920 | |
| 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) { |
| 3920 | 3921 | assert(frame_result_loc != nullptr); |
| 3921 | 3922 | |
| 3922 | 3923 | 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 |
| 3934 | 3935 | LLVMValueRef ret_ptr_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, frame_ret_start, ""); |
| 3935 | 3936 | LLVMBuildStore(g->builder, ret_ptr, ret_ptr_ptr); |
| 3936 | 3937 | } |
| 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 | } |
| 3937 | 3961 | } else { |
| 3938 | 3962 | if (first_arg_ret) { |
| 3939 | 3963 | gen_param_values.append(result_loc); |
| ... | ... | @@ -3966,7 +3990,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr |
| 3966 | 3990 | LLVMCallConv llvm_cc = get_llvm_cc(g, cc); |
| 3967 | 3991 | LLVMValueRef result; |
| 3968 | 3992 | |
| 3969 | | if (instruction->is_async || callee_is_async) { |
| 3993 | if (callee_is_async) { |
| 3970 | 3994 | uint32_t arg_start_i = frame_index_arg(g, fn_type->data.fn.fn_type_id.return_type); |
| 3971 | 3995 | |
| 3972 | 3996 | LLVMValueRef casted_frame; |
| ... | ... | @@ -3992,39 +4016,42 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr |
| 3992 | 4016 | gen_assign_raw(g, arg_ptr, get_pointer_to_type(g, gen_param_types.at(arg_i), true), |
| 3993 | 4017 | gen_param_values.at(arg_i)); |
| 3994 | 4018 | } |
| 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); |
| 4004 | 4019 | |
| 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); |
| 4006 | 4028 | |
| 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); |
| 4010 | 4034 | |
| 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); |
| 4014 | 4038 | |
| 4015 | | if (!type_has_bits(src_return_type)) |
| 4016 | | return nullptr; |
| 4039 | if (!type_has_bits(src_return_type)) |
| 4040 | return nullptr; |
| 4017 | 4041 | |
| 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); |
| 4020 | 4044 | |
| 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 | } |
| 4023 | 4048 | } |
| 4024 | 4049 | |
| 4025 | 4050 | if (instruction->new_stack == nullptr) { |
| 4026 | 4051 | result = ZigLLVMBuildCall(g->builder, fn_val, |
| 4027 | 4052 | 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"); |
| 4028 | 4055 | } else { |
| 4029 | 4056 | LLVMValueRef stacksave_fn_val = get_stacksave_fn_val(g); |
| 4030 | 4057 | LLVMValueRef stackrestore_fn_val = get_stackrestore_fn_val(g); |