| ... | @@ -3850,73 +3850,74 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr | ... | @@ -3850,73 +3850,74 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr |
| 3850 | LLVMValueRef frame_result_loc; | 3850 | LLVMValueRef frame_result_loc; |
| 3851 | LLVMValueRef awaiter_init_val; | 3851 | LLVMValueRef awaiter_init_val; |
| 3852 | LLVMValueRef ret_ptr; | 3852 | LLVMValueRef ret_ptr; |
| 3853 | if (instruction->is_async) { | 3853 | if (callee_is_async) { |
| 3854 | awaiter_init_val = zero; | 3854 | if (instruction->is_async) { |
| 3855 | | 3855 | if (instruction->new_stack == nullptr) { |
| 3856 | if (instruction->new_stack == nullptr) { | 3856 | awaiter_init_val = zero; |
| 3857 | frame_result_loc = result_loc; | 3857 | frame_result_loc = result_loc; |
| 3858 | | 3858 | |
| 3859 | if (ret_has_bits) { | 3859 | if (ret_has_bits) { |
| 3860 | // Use the result location which is inside the frame if this is an async call. | 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, ""); | 3861 | ret_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, frame_ret_start + 2, ""); |
| 3862 | } | 3862 | } |
| 3863 | } else { | 3863 | } else if (cc == CallingConventionAsync) { |
| 3864 | LLVMValueRef frame_slice_ptr = ir_llvm_value(g, instruction->new_stack); | 3864 | awaiter_init_val = zero; |
| 3865 | if (ir_want_runtime_safety(g, &instruction->base)) { | 3865 | LLVMValueRef frame_slice_ptr = ir_llvm_value(g, instruction->new_stack); |
| 3866 | LLVMValueRef given_len_ptr = LLVMBuildStructGEP(g->builder, frame_slice_ptr, slice_len_index, ""); | 3866 | if (ir_want_runtime_safety(g, &instruction->base)) { |
| 3867 | LLVMValueRef given_frame_len = LLVMBuildLoad(g->builder, given_len_ptr, ""); | 3867 | LLVMValueRef given_len_ptr = LLVMBuildStructGEP(g->builder, frame_slice_ptr, slice_len_index, ""); |
| 3868 | LLVMValueRef actual_frame_len = gen_frame_size(g, fn_val); | 3868 | LLVMValueRef given_frame_len = LLVMBuildLoad(g->builder, given_len_ptr, ""); |
| 3869 | | 3869 | LLVMValueRef actual_frame_len = gen_frame_size(g, fn_val); |
| 3870 | LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "FrameSizeCheckFail"); | 3870 | |
| 3871 | LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "FrameSizeCheckOk"); | 3871 | LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "FrameSizeCheckFail"); |
| 3872 | | 3872 | LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "FrameSizeCheckOk"); |
| 3873 | LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntUGE, given_frame_len, actual_frame_len, ""); | 3873 | |
| 3874 | LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block); | 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 | LLVMPositionBuilderAtEnd(g->builder, fail_block); |
| 3877 | gen_safety_crash(g, PanicMsgIdFrameTooSmall); | 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 | if (ret_has_bits) { | 3898 | if (ret_has_bits) { |
| 3887 | // Use the result location provided to the @asyncCall builtin | 3899 | if (result_loc == nullptr) { |
| 3888 | ret_ptr = result_loc; | 3900 | // return type is a scalar, but we still need a pointer to it. Use the async fn frame. |
| 3889 | } | 3901 | ret_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, frame_ret_start + 2, ""); |
| 3890 | } | 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 | 3907 | // Store a zero in the awaiter's result ptr to indicate we do not need a copy made. |
| 3893 | // initialization. | 3908 | LLVMValueRef awaiter_ret_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, frame_ret_start + 1, ""); |
| 3894 | } else if (callee_is_async) { | 3909 | LLVMValueRef zero_ptr = LLVMConstNull(LLVMGetElementType(LLVMTypeOf(awaiter_ret_ptr))); |
| 3895 | frame_result_loc = ir_llvm_value(g, instruction->frame_result_loc); | 3910 | LLVMBuildStore(g->builder, zero_ptr, awaiter_ret_ptr); |
| 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; | | |
| 3904 | } | 3911 | } |
| 3905 | | 3912 | |
| 3906 | // Store a zero in the awaiter's result ptr to indicate we do not need a copy made. | 3913 | if (prefix_arg_err_ret_stack) { |
| 3907 | LLVMValueRef awaiter_ret_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, frame_ret_start + 1, ""); | 3914 | LLVMValueRef err_ret_trace_ptr_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, |
| 3908 | LLVMValueRef zero_ptr = LLVMConstNull(LLVMGetElementType(LLVMTypeOf(awaiter_ret_ptr))); | 3915 | frame_index_trace_arg(g, src_return_type), ""); |
| 3909 | LLVMBuildStore(g->builder, zero_ptr, awaiter_ret_ptr); | 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 | assert(frame_result_loc != nullptr); | 3921 | assert(frame_result_loc != nullptr); |
| 3921 | | 3922 | |
| 3922 | LLVMValueRef fn_ptr_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, frame_fn_ptr_index, ""); | 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,6 +3935,29 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr |
| 3934 | LLVMValueRef ret_ptr_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, frame_ret_start, ""); | 3935 | LLVMValueRef ret_ptr_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, frame_ret_start, ""); |
| 3935 | LLVMBuildStore(g->builder, ret_ptr, ret_ptr_ptr); | 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 | } else { | 3961 | } else { |
| 3938 | if (first_arg_ret) { | 3962 | if (first_arg_ret) { |
| 3939 | gen_param_values.append(result_loc); | 3963 | gen_param_values.append(result_loc); |
| ... | @@ -3966,7 +3990,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr | ... | @@ -3966,7 +3990,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr |
| 3966 | LLVMCallConv llvm_cc = get_llvm_cc(g, cc); | 3990 | LLVMCallConv llvm_cc = get_llvm_cc(g, cc); |
| 3967 | LLVMValueRef result; | 3991 | LLVMValueRef result; |
| 3968 | | 3992 | |
| 3969 | if (instruction->is_async || callee_is_async) { | 3993 | if (callee_is_async) { |
| 3970 | uint32_t arg_start_i = frame_index_arg(g, fn_type->data.fn.fn_type_id.return_type); | 3994 | uint32_t arg_start_i = frame_index_arg(g, fn_type->data.fn.fn_type_id.return_type); |
| 3971 | | 3995 | |
| 3972 | LLVMValueRef casted_frame; | 3996 | LLVMValueRef casted_frame; |
| ... | @@ -3992,39 +4016,42 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr | ... | @@ -3992,39 +4016,42 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr |
| 3992 | gen_assign_raw(g, arg_ptr, get_pointer_to_type(g, gen_param_types.at(arg_i), true), | 4016 | gen_assign_raw(g, arg_ptr, get_pointer_to_type(g, gen_param_types.at(arg_i), true), |
| 3993 | gen_param_values.at(arg_i)); | 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); | 4029 | LLVMBasicBlockRef call_bb = gen_suspend_begin(g, "CallResume"); |
| 4008 | set_tail_call_if_appropriate(g, call_inst); | 4030 | |
| 4009 | LLVMBuildRetVoid(g->builder); | 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); | 4035 | LLVMPositionBuilderAtEnd(g->builder, call_bb); |
| 4012 | gen_assert_resume_id(g, &instruction->base, ResumeIdReturn, PanicMsgIdResumedAnAwaitingFn, nullptr); | 4036 | gen_assert_resume_id(g, &instruction->base, ResumeIdReturn, PanicMsgIdResumedAnAwaitingFn, nullptr); |
| 4013 | render_async_var_decls(g, instruction->base.scope); | 4037 | render_async_var_decls(g, instruction->base.scope); |
| 4014 | | 4038 | |
| 4015 | if (!type_has_bits(src_return_type)) | 4039 | if (!type_has_bits(src_return_type)) |
| 4016 | return nullptr; | 4040 | return nullptr; |
| 4017 | | 4041 | |
| 4018 | if (result_loc != nullptr) | 4042 | if (result_loc != nullptr) |
| 4019 | return get_handle_value(g, result_loc, src_return_type, ptr_result_type); | 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, ""); | 4045 | LLVMValueRef result_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, frame_ret_start + 2, ""); |
| 4022 | return LLVMBuildLoad(g->builder, result_ptr, ""); | 4046 | return LLVMBuildLoad(g->builder, result_ptr, ""); |
| | 4047 | } |
| 4023 | } | 4048 | } |
| 4024 | | 4049 | |
| 4025 | if (instruction->new_stack == nullptr) { | 4050 | if (instruction->new_stack == nullptr) { |
| 4026 | result = ZigLLVMBuildCall(g->builder, fn_val, | 4051 | result = ZigLLVMBuildCall(g->builder, fn_val, |
| 4027 | gen_param_values.items, (unsigned)gen_param_values.length, llvm_cc, fn_inline, ""); | 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 | } else { | 4055 | } else { |
| 4029 | LLVMValueRef stacksave_fn_val = get_stacksave_fn_val(g); | 4056 | LLVMValueRef stacksave_fn_val = get_stacksave_fn_val(g); |
| 4030 | LLVMValueRef stackrestore_fn_val = get_stackrestore_fn_val(g); | 4057 | LLVMValueRef stackrestore_fn_val = get_stackrestore_fn_val(g); |