From 05bf666eb690d1a1328234cc408960133dba9563 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 25 Feb 2018 02:47:31 -0500 Subject: [PATCH] codegen for calling an async function See #727 --- src/analyze.cpp | 34 +++++++++++++++++++++++++++++----- src/codegen.cpp | 22 ++++++++++++++++++---- src/ir.cpp | 2 ++ 3 files changed, 49 insertions(+), 9 deletions(-) diff --git a/src/analyze.cpp b/src/analyze.cpp index cf5d9e0ea..2126f5ba0 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -986,20 +986,25 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) { if (!skip_debug_info) { bool first_arg_return = calling_convention_does_first_arg_return(fn_type_id->cc) && handle_is_ptr(fn_type_id->return_type); + bool is_async = fn_type_id->cc == CallingConventionAsync; bool prefix_arg_error_return_trace = g->have_err_ret_tracing && (fn_type_id->return_type->id == TypeTableEntryIdErrorUnion || fn_type_id->return_type->id == TypeTableEntryIdErrorSet); // +1 for maybe making the first argument the return value - // +1 for maybe last argument the error return trace - LLVMTypeRef *gen_param_types = allocate(2 + fn_type_id->param_count); + // +1 for maybe first argument the error return trace + // +2 for maybe arguments async allocator and error code pointer + LLVMTypeRef *gen_param_types = allocate(4 + fn_type_id->param_count); // +1 because 0 is the return type and // +1 for maybe making first arg ret val and - // +1 for maybe last argument the error return trace - ZigLLVMDIType **param_di_types = allocate(3 + fn_type_id->param_count); + // +1 for maybe first argument the error return trace + // +2 for maybe arguments async allocator and error code pointer + ZigLLVMDIType **param_di_types = allocate(5 + fn_type_id->param_count); param_di_types[0] = fn_type_id->return_type->di_type; size_t gen_param_index = 0; TypeTableEntry *gen_return_type; - if (!type_has_bits(fn_type_id->return_type)) { + if (is_async) { + gen_return_type = get_pointer_to_type(g, g->builtin_types.entry_u8, false); + } else if (!type_has_bits(fn_type_id->return_type)) { gen_return_type = g->builtin_types.entry_void; } else if (first_arg_return) { TypeTableEntry *gen_type = get_pointer_to_type(g, fn_type_id->return_type, false); @@ -1020,6 +1025,25 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) { // after the gen_param_index += 1 because 0 is the return type param_di_types[gen_param_index] = gen_type->di_type; } + if (is_async) { + { + // async allocator param + TypeTableEntry *gen_type = fn_type_id->async_allocator_type; + gen_param_types[gen_param_index] = gen_type->type_ref; + gen_param_index += 1; + // after the gen_param_index += 1 because 0 is the return type + param_di_types[gen_param_index] = gen_type->di_type; + } + + { + // error code pointer + TypeTableEntry *gen_type = get_pointer_to_type(g, g->builtin_types.entry_global_error_set, false); + gen_param_types[gen_param_index] = gen_type->type_ref; + gen_param_index += 1; + // after the gen_param_index += 1 because 0 is the return type + param_di_types[gen_param_index] = gen_type->di_type; + } + } fn_type->data.fn.gen_param_info = allocate(fn_type_id->param_count); for (size_t i = 0; i < fn_type_id->param_count; i += 1) { diff --git a/src/codegen.cpp b/src/codegen.cpp index 6b1a2513c..ec14d8506 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -2521,13 +2521,12 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr } FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id; - if (fn_type_id->cc == CallingConventionAsync) { - zig_panic("TODO codegen async function call"); - } TypeTableEntry *src_return_type = fn_type_id->return_type; bool ret_has_bits = type_has_bits(src_return_type); - bool first_arg_ret = ret_has_bits && handle_is_ptr(src_return_type); + + bool first_arg_ret = ret_has_bits && handle_is_ptr(src_return_type) && + calling_convention_does_first_arg_return(fn_type->data.fn.fn_type_id.cc); bool prefix_arg_err_ret_stack = g->have_err_ret_tracing && (src_return_type->id == TypeTableEntryIdErrorUnion || src_return_type->id == TypeTableEntryIdErrorSet); size_t actual_param_count = instruction->arg_count + (first_arg_ret ? 1 : 0) + (prefix_arg_err_ret_stack ? 1 : 0); bool is_var_args = fn_type_id->is_var_args; @@ -2541,6 +2540,15 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr gen_param_values[gen_param_index] = g->cur_err_ret_trace_val; gen_param_index += 1; } + if (instruction->is_async) { + gen_param_values[gen_param_index] = ir_llvm_value(g, instruction->async_allocator); + gen_param_index += 1; + + LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, err_union_err_index, ""); + LLVMBuildStore(g->builder, LLVMConstNull(g->builtin_types.entry_global_error_set->type_ref), err_val_ptr); + gen_param_values[gen_param_index] = err_val_ptr; + gen_param_index += 1; + } for (size_t call_i = 0; call_i < instruction->arg_count; call_i += 1) { IrInstruction *param_instruction = instruction->args[call_i]; TypeTableEntry *param_type = param_instruction->value.type; @@ -2578,6 +2586,12 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr } } + if (instruction->is_async) { + LLVMValueRef payload_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, err_union_payload_index, ""); + LLVMBuildStore(g->builder, result, payload_ptr); + return instruction->tmp_ptr; + } + if (src_return_type->id == TypeTableEntryIdUnreachable) { return LLVMBuildUnreachable(g->builder); } else if (!ret_has_bits) { diff --git a/src/ir.cpp b/src/ir.cpp index cc57e20c6..f484f32e0 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -11775,6 +11775,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal if (call_instruction->is_async) { IrInstruction *result = ir_analyze_async_call(ira, call_instruction, impl_fn, impl_fn->type_entry, fn_ref, casted_args, impl_param_count, async_allocator_inst); ir_link_new_instruction(result, &call_instruction->base); + ir_add_alloca(ira, result, result->value.type); return ir_finish_anal(ira, result->value.type); } @@ -11862,6 +11863,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal IrInstruction *result = ir_analyze_async_call(ira, call_instruction, fn_entry, fn_type, fn_ref, casted_args, call_param_count, async_allocator_inst); ir_link_new_instruction(result, &call_instruction->base); + ir_add_alloca(ira, result, result->value.type); return ir_finish_anal(ira, result->value.type); }