authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-07-25 00:03:06-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-07-25 00:03:06-04:00
logead2d32be871411685f846e604ec7e4253b9f25a
treef9e3f930aef5ed60d452c4cf20776879b086acf1
parente220812f2f0fe2becd570308971f98e0290835db
signaturelock-open Commit is signed but in an unrecognized format.

calling an inferred async function


7 files changed, 238 insertions(+), 118 deletions(-)

src/all_types.hpp+10-7
...@@ -35,6 +35,7 @@ struct ConstExprValue;...@@ -35,6 +35,7 @@ struct ConstExprValue;
35struct IrInstruction;35struct IrInstruction;
36struct IrInstructionCast;36struct IrInstructionCast;
37struct IrInstructionAllocaGen;37struct IrInstructionAllocaGen;
38struct IrInstructionCallGen;
38struct IrBasicBlock;39struct IrBasicBlock;
39struct ScopeDecls;40struct ScopeDecls;
40struct ZigWindowsSDK;41struct ZigWindowsSDK;
...@@ -1336,11 +1337,6 @@ struct GlobalExport {...@@ -1336,11 +1337,6 @@ struct GlobalExport {
1336 GlobalLinkageId linkage;1337 GlobalLinkageId linkage;
1337};1338};
13381339
1339struct FnCall {
1340 AstNode *source_node;
1341 ZigFn *callee;
1342};
1343
1344struct ZigFn {1340struct ZigFn {
1345 LLVMValueRef llvm_value;1341 LLVMValueRef llvm_value;
1346 const char *llvm_name;1342 const char *llvm_name;
...@@ -1387,7 +1383,7 @@ struct ZigFn {...@@ -1387,7 +1383,7 @@ struct ZigFn {
1387 ZigFn *inferred_async_fn;1383 ZigFn *inferred_async_fn;
13881384
1389 ZigList<GlobalExport> export_list;1385 ZigList<GlobalExport> export_list;
1390 ZigList<FnCall> call_list;1386 ZigList<IrInstructionCallGen *> call_list;
13911387
1392 LLVMValueRef valgrind_client_request_array;1388 LLVMValueRef valgrind_client_request_array;
1393 LLVMBasicBlockRef preamble_llvm_block;1389 LLVMBasicBlockRef preamble_llvm_block;
...@@ -2585,6 +2581,8 @@ struct IrInstructionCallGen {...@@ -2585,6 +2581,8 @@ struct IrInstructionCallGen {
2585 size_t arg_count;2581 size_t arg_count;
2586 IrInstruction **args;2582 IrInstruction **args;
2587 IrInstruction *result_loc;2583 IrInstruction *result_loc;
2584 IrInstruction *frame_result_loc;
2585 IrBasicBlock *resume_block;
25882586
2589 IrInstruction *new_stack;2587 IrInstruction *new_stack;
2590 FnInline fn_inline;2588 FnInline fn_inline;
...@@ -3645,7 +3643,12 @@ static const size_t err_union_err_index = 0;...@@ -3645,7 +3643,12 @@ static const size_t err_union_err_index = 0;
3645static const size_t err_union_payload_index = 1;3643static const size_t err_union_payload_index = 1;
36463644
3647static const size_t coro_resume_index_index = 0;3645static const size_t coro_resume_index_index = 0;
3648static const size_t coro_arg_start = 1;3646static const size_t coro_fn_ptr_index = 1;
3647static const size_t coro_awaiter_index = 2;
3648static const size_t coro_arg_start = 3;
3649
3650// one for the GetSize block, one for the Entry block, resume blocks are indexed after that.
3651static const size_t coro_extra_resume_block_count = 2;
36493652
3650// TODO call graph analysis to find out what this number needs to be for every function3653// TODO call graph analysis to find out what this number needs to be for every function
3651// MUST BE A POWER OF TWO.3654// MUST BE A POWER OF TWO.
src/analyze.cpp+135-85
...@@ -1869,80 +1869,6 @@ static Error resolve_union_type(CodeGen *g, ZigType *union_type) {...@@ -1869,80 +1869,6 @@ static Error resolve_union_type(CodeGen *g, ZigType *union_type) {
1869 return ErrorNone;1869 return ErrorNone;
1870}1870}
18711871
1872static Error resolve_coro_frame(CodeGen *g, ZigType *frame_type) {
1873 if (frame_type->data.frame.locals_struct != nullptr)
1874 return ErrorNone;
1875
1876 ZigFn *fn = frame_type->data.frame.fn;
1877 switch (fn->anal_state) {
1878 case FnAnalStateInvalid:
1879 return ErrorSemanticAnalyzeFail;
1880 case FnAnalStateComplete:
1881 break;
1882 case FnAnalStateReady:
1883 analyze_fn_body(g, fn);
1884 if (fn->anal_state == FnAnalStateInvalid)
1885 return ErrorSemanticAnalyzeFail;
1886 break;
1887 case FnAnalStateProbing:
1888 add_node_error(g, fn->proto_node,
1889 buf_sprintf("cannot resolve '%s': function not fully analyzed yet",
1890 buf_ptr(&frame_type->name)));
1891 return ErrorSemanticAnalyzeFail;
1892 }
1893 // TODO iterate over fn->alloca_gen_list
1894 ZigList<ZigType *> field_types = {};
1895 ZigList<const char *> field_names = {};
1896
1897 field_names.append("resume_index");
1898 field_types.append(g->builtin_types.entry_usize);
1899
1900 FnTypeId *fn_type_id = &fn->type_entry->data.fn.fn_type_id;
1901 field_names.append("result");
1902 field_types.append(fn_type_id->return_type);
1903
1904 for (size_t arg_i = 0; arg_i < fn_type_id->param_count; arg_i += 1) {
1905 FnTypeParamInfo *param_info = &fn_type_id->param_info[arg_i];
1906 AstNode *param_decl_node = get_param_decl_node(fn, arg_i);
1907 Buf *param_name;
1908 bool is_var_args = param_decl_node && param_decl_node->data.param_decl.is_var_args;
1909 if (param_decl_node && !is_var_args) {
1910 param_name = param_decl_node->data.param_decl.name;
1911 } else {
1912 param_name = buf_sprintf("arg%" ZIG_PRI_usize "", arg_i);
1913 }
1914 ZigType *param_type = param_info->type;
1915 field_names.append(buf_ptr(param_name));
1916 field_types.append(param_type);
1917 }
1918
1919 for (size_t alloca_i = 0; alloca_i < fn->alloca_gen_list.length; alloca_i += 1) {
1920 IrInstructionAllocaGen *instruction = fn->alloca_gen_list.at(alloca_i);
1921 ZigType *ptr_type = instruction->base.value.type;
1922 assert(ptr_type->id == ZigTypeIdPointer);
1923 ZigType *child_type = ptr_type->data.pointer.child_type;
1924 if (!type_has_bits(child_type))
1925 continue;
1926 if (instruction->base.ref_count == 0)
1927 continue;
1928 if (instruction->base.value.special != ConstValSpecialRuntime) {
1929 if (const_ptr_pointee(nullptr, g, &instruction->base.value, nullptr)->special !=
1930 ConstValSpecialRuntime)
1931 {
1932 continue;
1933 }
1934 }
1935 field_names.append(instruction->name_hint);
1936 field_types.append(child_type);
1937 }
1938
1939
1940 assert(field_names.length == field_types.length);
1941 frame_type->data.frame.locals_struct = get_struct_type(g, buf_ptr(&frame_type->name),
1942 field_names.items, field_types.items, field_names.length);
1943 return ErrorNone;
1944}
1945
1946static bool type_is_valid_extern_enum_tag(CodeGen *g, ZigType *ty) {1872static bool type_is_valid_extern_enum_tag(CodeGen *g, ZigType *ty) {
1947 // Only integer types are allowed by the C ABI1873 // Only integer types are allowed by the C ABI
1948 if(ty->id != ZigTypeIdInt)1874 if(ty->id != ZigTypeIdInt)
...@@ -3861,18 +3787,24 @@ static void analyze_fn_async(CodeGen *g, ZigFn *fn) {...@@ -3861,18 +3787,24 @@ static void analyze_fn_async(CodeGen *g, ZigFn *fn) {
3861 }3787 }
38623788
3863 for (size_t i = 0; i < fn->call_list.length; i += 1) {3789 for (size_t i = 0; i < fn->call_list.length; i += 1) {
3864 FnCall *call = &fn->call_list.at(i);3790 IrInstructionCallGen *call = fn->call_list.at(i);
3865 if (call->callee->type_entry->data.fn.fn_type_id.cc != CallingConventionUnspecified)3791 ZigFn *callee = call->fn_entry;
3792 if (callee == nullptr) {
3793 // TODO function pointer call here, could be anything
3866 continue;3794 continue;
3867 assert(call->callee->anal_state == FnAnalStateComplete);3795 }
3868 analyze_fn_async(g, call->callee);3796
3869 if (call->callee->anal_state == FnAnalStateInvalid) {3797 if (callee->type_entry->data.fn.fn_type_id.cc != CallingConventionUnspecified)
3798 continue;
3799 assert(callee->anal_state == FnAnalStateComplete);
3800 analyze_fn_async(g, callee);
3801 if (callee->anal_state == FnAnalStateInvalid) {
3870 fn->anal_state = FnAnalStateInvalid;3802 fn->anal_state = FnAnalStateInvalid;
3871 return;3803 return;
3872 }3804 }
3873 if (fn_is_async(call->callee)) {3805 if (fn_is_async(callee)) {
3874 fn->inferred_async_node = call->source_node;3806 fn->inferred_async_node = call->base.source_node;
3875 fn->inferred_async_fn = call->callee;3807 fn->inferred_async_fn = callee;
3876 if (must_not_be_async) {3808 if (must_not_be_async) {
3877 ErrorMsg *msg = add_node_error(g, fn->proto_node,3809 ErrorMsg *msg = add_node_error(g, fn->proto_node,
3878 buf_sprintf("function with calling convention '%s' cannot be async",3810 buf_sprintf("function with calling convention '%s' cannot be async",
...@@ -5147,6 +5079,127 @@ Error ensure_complete_type(CodeGen *g, ZigType *type_entry) {...@@ -5147,6 +5079,127 @@ Error ensure_complete_type(CodeGen *g, ZigType *type_entry) {
5147 return type_resolve(g, type_entry, ResolveStatusSizeKnown);5079 return type_resolve(g, type_entry, ResolveStatusSizeKnown);
5148}5080}
51495081
5082static Error resolve_coro_frame(CodeGen *g, ZigType *frame_type) {
5083 if (frame_type->data.frame.locals_struct != nullptr)
5084 return ErrorNone;
5085
5086 ZigFn *fn = frame_type->data.frame.fn;
5087 switch (fn->anal_state) {
5088 case FnAnalStateInvalid:
5089 return ErrorSemanticAnalyzeFail;
5090 case FnAnalStateComplete:
5091 break;
5092 case FnAnalStateReady:
5093 analyze_fn_body(g, fn);
5094 if (fn->anal_state == FnAnalStateInvalid)
5095 return ErrorSemanticAnalyzeFail;
5096 break;
5097 case FnAnalStateProbing:
5098 add_node_error(g, fn->proto_node,
5099 buf_sprintf("cannot resolve '%s': function not fully analyzed yet",
5100 buf_ptr(&frame_type->name)));
5101 return ErrorSemanticAnalyzeFail;
5102 }
5103
5104 for (size_t i = 0; i < fn->call_list.length; i += 1) {
5105 IrInstructionCallGen *call = fn->call_list.at(i);
5106 ZigFn *callee = call->fn_entry;
5107 assert(callee != nullptr);
5108
5109 analyze_fn_body(g, callee);
5110 if (callee->anal_state == FnAnalStateInvalid) {
5111 frame_type->data.frame.locals_struct = g->builtin_types.entry_invalid;
5112 return ErrorSemanticAnalyzeFail;
5113 }
5114 analyze_fn_async(g, callee);
5115 if (!fn_is_async(callee))
5116 continue;
5117
5118 IrBasicBlock *new_resume_block = allocate<IrBasicBlock>(1);
5119 new_resume_block->name_hint = "CallResume";
5120 new_resume_block->resume_index = fn->resume_blocks.length + coro_extra_resume_block_count;
5121 fn->resume_blocks.append(new_resume_block);
5122 call->resume_block = new_resume_block;
5123 fn->analyzed_executable.basic_block_list.append(new_resume_block);
5124
5125 ZigType *callee_frame_type = get_coro_frame_type(g, callee);
5126
5127 IrInstructionAllocaGen *alloca_gen = allocate<IrInstructionAllocaGen>(1);
5128 alloca_gen->base.id = IrInstructionIdAllocaGen;
5129 alloca_gen->base.source_node = call->base.source_node;
5130 alloca_gen->base.scope = call->base.scope;
5131 alloca_gen->base.value.type = get_pointer_to_type(g, callee_frame_type, false);
5132 alloca_gen->base.ref_count = 1;
5133 alloca_gen->name_hint = "";
5134 fn->alloca_gen_list.append(alloca_gen);
5135 call->frame_result_loc = &alloca_gen->base;
5136 }
5137
5138 ZigList<ZigType *> field_types = {};
5139 ZigList<const char *> field_names = {};
5140
5141 field_names.append("resume_index");
5142 field_types.append(g->builtin_types.entry_usize);
5143
5144 field_names.append("fn_ptr");
5145 field_types.append(fn->type_entry);
5146
5147 field_names.append("awaiter");
5148 field_types.append(g->builtin_types.entry_usize);
5149
5150 FnTypeId *fn_type_id = &fn->type_entry->data.fn.fn_type_id;
5151 ZigType *ptr_return_type = get_pointer_to_type(g, fn_type_id->return_type, false);
5152 field_names.append("result_ptr");
5153 field_types.append(ptr_return_type);
5154
5155 field_names.append("result");
5156 field_types.append(fn_type_id->return_type);
5157
5158 for (size_t arg_i = 0; arg_i < fn_type_id->param_count; arg_i += 1) {
5159 FnTypeParamInfo *param_info = &fn_type_id->param_info[arg_i];
5160 AstNode *param_decl_node = get_param_decl_node(fn, arg_i);
5161 Buf *param_name;
5162 bool is_var_args = param_decl_node && param_decl_node->data.param_decl.is_var_args;
5163 if (param_decl_node && !is_var_args) {
5164 param_name = param_decl_node->data.param_decl.name;
5165 } else {
5166 param_name = buf_sprintf("arg%" ZIG_PRI_usize "", arg_i);
5167 }
5168 ZigType *param_type = param_info->type;
5169 field_names.append(buf_ptr(param_name));
5170 field_types.append(param_type);
5171 }
5172
5173 for (size_t alloca_i = 0; alloca_i < fn->alloca_gen_list.length; alloca_i += 1) {
5174 IrInstructionAllocaGen *instruction = fn->alloca_gen_list.at(alloca_i);
5175 ZigType *ptr_type = instruction->base.value.type;
5176 assert(ptr_type->id == ZigTypeIdPointer);
5177 ZigType *child_type = ptr_type->data.pointer.child_type;
5178 if (!type_has_bits(child_type))
5179 continue;
5180 if (instruction->base.ref_count == 0)
5181 continue;
5182 if (instruction->base.value.special != ConstValSpecialRuntime) {
5183 if (const_ptr_pointee(nullptr, g, &instruction->base.value, nullptr)->special !=
5184 ConstValSpecialRuntime)
5185 {
5186 continue;
5187 }
5188 }
5189 field_names.append(instruction->name_hint);
5190 field_types.append(child_type);
5191 }
5192
5193
5194 assert(field_names.length == field_types.length);
5195 frame_type->data.frame.locals_struct = get_struct_type(g, buf_ptr(&frame_type->name),
5196 field_names.items, field_types.items, field_names.length);
5197 frame_type->abi_size = frame_type->data.frame.locals_struct->abi_size;
5198 frame_type->abi_align = frame_type->data.frame.locals_struct->abi_align;
5199 frame_type->size_in_bits = frame_type->data.frame.locals_struct->size_in_bits;
5200 return ErrorNone;
5201}
5202
5150Error type_resolve(CodeGen *g, ZigType *ty, ResolveStatus status) {5203Error type_resolve(CodeGen *g, ZigType *ty, ResolveStatus status) {
5151 if (type_is_invalid(ty))5204 if (type_is_invalid(ty))
5152 return ErrorSemanticAnalyzeFail;5205 return ErrorSemanticAnalyzeFail;
...@@ -7343,9 +7396,6 @@ static void resolve_llvm_types_coro_frame(CodeGen *g, ZigType *frame_type, Resol...@@ -7343,9 +7396,6 @@ static void resolve_llvm_types_coro_frame(CodeGen *g, ZigType *frame_type, Resol
7343 resolve_llvm_types_struct(g, frame_type->data.frame.locals_struct, wanted_resolve_status);7396 resolve_llvm_types_struct(g, frame_type->data.frame.locals_struct, wanted_resolve_status);
7344 frame_type->llvm_type = frame_type->data.frame.locals_struct->llvm_type;7397 frame_type->llvm_type = frame_type->data.frame.locals_struct->llvm_type;
7345 frame_type->llvm_di_type = frame_type->data.frame.locals_struct->llvm_di_type;7398 frame_type->llvm_di_type = frame_type->data.frame.locals_struct->llvm_di_type;
7346 frame_type->abi_size = frame_type->data.frame.locals_struct->abi_size;
7347 frame_type->abi_align = frame_type->data.frame.locals_struct->abi_align;
7348 frame_type->size_in_bits = frame_type->data.frame.locals_struct->size_in_bits;
7349}7399}
73507400
7351static void resolve_llvm_types(CodeGen *g, ZigType *type, ResolveStatus wanted_resolve_status) {7401static void resolve_llvm_types(CodeGen *g, ZigType *type, ResolveStatus wanted_resolve_status) {
src/codegen.cpp+60-12
...@@ -3324,13 +3324,16 @@ static void set_call_instr_sret(CodeGen *g, LLVMValueRef call_instr) {...@@ -3324,13 +3324,16 @@ static void set_call_instr_sret(CodeGen *g, LLVMValueRef call_instr) {
3324static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstructionCallGen *instruction) {3324static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstructionCallGen *instruction) {
3325 LLVMValueRef fn_val;3325 LLVMValueRef fn_val;
3326 ZigType *fn_type;3326 ZigType *fn_type;
3327 bool callee_is_async;
3327 if (instruction->fn_entry) {3328 if (instruction->fn_entry) {
3328 fn_val = fn_llvm_value(g, instruction->fn_entry);3329 fn_val = fn_llvm_value(g, instruction->fn_entry);
3329 fn_type = instruction->fn_entry->type_entry;3330 fn_type = instruction->fn_entry->type_entry;
3331 callee_is_async = fn_is_async(instruction->fn_entry);
3330 } else {3332 } else {
3331 assert(instruction->fn_ref);3333 assert(instruction->fn_ref);
3332 fn_val = ir_llvm_value(g, instruction->fn_ref);3334 fn_val = ir_llvm_value(g, instruction->fn_ref);
3333 fn_type = instruction->fn_ref->value.type;3335 fn_type = instruction->fn_ref->value.type;
3336 callee_is_async = fn_type->data.fn.fn_type_id.cc == CallingConventionAsync;
3334 }3337 }
33353338
3336 FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id;3339 FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id;
...@@ -3345,17 +3348,47 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr...@@ -3345,17 +3348,47 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
3345 bool is_var_args = fn_type_id->is_var_args;3348 bool is_var_args = fn_type_id->is_var_args;
3346 ZigList<LLVMValueRef> gen_param_values = {};3349 ZigList<LLVMValueRef> gen_param_values = {};
3347 LLVMValueRef result_loc = instruction->result_loc ? ir_llvm_value(g, instruction->result_loc) : nullptr;3350 LLVMValueRef result_loc = instruction->result_loc ? ir_llvm_value(g, instruction->result_loc) : nullptr;
3351 LLVMValueRef zero = LLVMConstNull(g->builtin_types.entry_usize->llvm_type);
3352 LLVMValueRef frame_result_loc;
3353 LLVMValueRef awaiter_init_val;
3354 LLVMValueRef ret_ptr;
3348 if (instruction->is_async) {3355 if (instruction->is_async) {
3349 assert(result_loc != nullptr);3356 frame_result_loc = result_loc;
3357 awaiter_init_val = zero;
3358 if (ret_has_bits) {
3359 ret_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, coro_arg_start + 1, "");
3360 }
3361 } else if (callee_is_async) {
3362 frame_result_loc = ir_llvm_value(g, instruction->frame_result_loc);
3363 awaiter_init_val = LLVMBuildPtrToInt(g->builder, g->cur_ret_ptr,
3364 g->builtin_types.entry_usize->llvm_type, ""); // caller's own frame pointer
3365 if (ret_has_bits) {
3366 ret_ptr = result_loc;
3367 }
3368 }
3369 if (instruction->is_async || callee_is_async) {
3370 assert(frame_result_loc != nullptr);
3350 assert(instruction->fn_entry != nullptr);3371 assert(instruction->fn_entry != nullptr);
3351 LLVMValueRef resume_index_ptr = LLVMBuildStructGEP(g->builder, result_loc, coro_resume_index_index, "");3372 LLVMValueRef resume_index_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, coro_resume_index_index, "");
3352 LLVMValueRef zero = LLVMConstNull(g->builtin_types.entry_usize->llvm_type);
3353 LLVMBuildStore(g->builder, zero, resume_index_ptr);3373 LLVMBuildStore(g->builder, zero, resume_index_ptr);
3374 LLVMValueRef fn_ptr_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, coro_fn_ptr_index, "");
3375 LLVMValueRef bitcasted_fn_val = LLVMBuildBitCast(g->builder, fn_val,
3376 LLVMGetElementType(LLVMTypeOf(fn_ptr_ptr)), "");
3377 LLVMBuildStore(g->builder, bitcasted_fn_val, fn_ptr_ptr);
33543378
3355 if (prefix_arg_err_ret_stack) {3379 if (prefix_arg_err_ret_stack) {
3356 zig_panic("TODO");3380 zig_panic("TODO");
3357 }3381 }
3358 } else {3382
3383 LLVMValueRef awaiter_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, coro_awaiter_index, "");
3384 LLVMBuildStore(g->builder, awaiter_init_val, awaiter_ptr);
3385
3386 if (ret_has_bits) {
3387 LLVMValueRef ret_ptr_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, coro_arg_start, "");
3388 LLVMBuildStore(g->builder, ret_ptr, ret_ptr_ptr);
3389 }
3390 }
3391 if (!instruction->is_async && !callee_is_async) {
3359 if (first_arg_ret) {3392 if (first_arg_ret) {
3360 gen_param_values.append(result_loc);3393 gen_param_values.append(result_loc);
3361 }3394 }
...@@ -3386,14 +3419,28 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr...@@ -3386,14 +3419,28 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
3386 LLVMCallConv llvm_cc = get_llvm_cc(g, cc);3419 LLVMCallConv llvm_cc = get_llvm_cc(g, cc);
3387 LLVMValueRef result;3420 LLVMValueRef result;
33883421
3389 if (instruction->is_async) {3422 if (instruction->is_async || callee_is_async) {
3390 size_t ret_1_or_0 = type_has_bits(fn_type->data.fn.fn_type_id.return_type) ? 1 : 0;3423 size_t ret_2_or_0 = type_has_bits(fn_type->data.fn.fn_type_id.return_type) ? 2 : 0;
3391 for (size_t arg_i = 0; arg_i < gen_param_values.length; arg_i += 1) {3424 for (size_t arg_i = 0; arg_i < gen_param_values.length; arg_i += 1) {
3392 LLVMValueRef arg_ptr = LLVMBuildStructGEP(g->builder, result_loc,3425 LLVMValueRef arg_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc,
3393 coro_arg_start + ret_1_or_0 + arg_i, "");3426 coro_arg_start + ret_2_or_0 + arg_i, "");
3394 LLVMBuildStore(g->builder, gen_param_values.at(arg_i), arg_ptr);3427 LLVMBuildStore(g->builder, gen_param_values.at(arg_i), arg_ptr);
3395 }3428 }
3396 ZigLLVMBuildCall(g->builder, fn_val, &result_loc, 1, llvm_cc, fn_inline, "");3429 }
3430 if (instruction->is_async) {
3431 ZigLLVMBuildCall(g->builder, fn_val, &frame_result_loc, 1, llvm_cc, fn_inline, "");
3432 return nullptr;
3433 } else if (callee_is_async) {
3434 LLVMValueRef resume_index_ptr = LLVMBuildStructGEP(g->builder, g->cur_ret_ptr, coro_resume_index_index, "");
3435 LLVMValueRef new_resume_index = LLVMConstInt(g->builtin_types.entry_usize->llvm_type,
3436 instruction->resume_block->resume_index, false);
3437 LLVMBuildStore(g->builder, new_resume_index, resume_index_ptr);
3438
3439 LLVMValueRef call_inst = ZigLLVMBuildCall(g->builder, fn_val, &frame_result_loc, 1, llvm_cc, fn_inline, "");
3440 ZigLLVMSetTailCall(call_inst);
3441 LLVMBuildRet(g->builder, call_inst);
3442
3443 LLVMPositionBuilderAtEnd(g->builder, instruction->resume_block->llvm_block);
3397 return nullptr;3444 return nullptr;
3398 }3445 }
33993446
...@@ -6174,7 +6221,7 @@ static void do_code_gen(CodeGen *g) {...@@ -6174,7 +6221,7 @@ static void do_code_gen(CodeGen *g) {
6174 clear_debug_source_node(g);6221 clear_debug_source_node(g);
61756222
6176 bool is_async = fn_is_async(fn_table_entry);6223 bool is_async = fn_is_async(fn_table_entry);
6177 size_t async_var_index = coro_arg_start + (type_has_bits(fn_type_id->return_type) ? 1 : 0);6224 size_t async_var_index = coro_arg_start + (type_has_bits(fn_type_id->return_type) ? 2 : 0);
61786225
6179 if (want_sret || is_async) {6226 if (want_sret || is_async) {
6180 g->cur_ret_ptr = LLVMGetParam(fn, 0);6227 g->cur_ret_ptr = LLVMGetParam(fn, 0);
...@@ -6385,8 +6432,9 @@ static void do_code_gen(CodeGen *g) {...@@ -6385,8 +6432,9 @@ static void do_code_gen(CodeGen *g) {
6385 LLVMAddCase(switch_instr, one, get_size_block);6432 LLVMAddCase(switch_instr, one, get_size_block);
63866433
6387 for (size_t resume_i = 0; resume_i < fn_table_entry->resume_blocks.length; resume_i += 1) {6434 for (size_t resume_i = 0; resume_i < fn_table_entry->resume_blocks.length; resume_i += 1) {
6388 LLVMValueRef case_value = LLVMConstInt(usize_type_ref, resume_i + 2, false);6435 IrBasicBlock *resume_block = fn_table_entry->resume_blocks.at(resume_i);
6389 LLVMAddCase(switch_instr, case_value, fn_table_entry->resume_blocks.at(resume_i)->llvm_block);6436 LLVMValueRef case_value = LLVMConstInt(usize_type_ref, resume_block->resume_index, false);
6437 LLVMAddCase(switch_instr, case_value, resume_block->llvm_block);
6390 }6438 }
6391 } else {6439 } else {
6392 // create debug variable declarations for parameters6440 // create debug variable declarations for parameters
src/ir.cpp+12-14
...@@ -1385,7 +1385,7 @@ static IrInstruction *ir_build_call_src(IrBuilder *irb, Scope *scope, AstNode *s...@@ -1385,7 +1385,7 @@ static IrInstruction *ir_build_call_src(IrBuilder *irb, Scope *scope, AstNode *s
1385 return &call_instruction->base;1385 return &call_instruction->base;
1386}1386}
13871387
1388static IrInstruction *ir_build_call_gen(IrAnalyze *ira, IrInstruction *source_instruction,1388static IrInstructionCallGen *ir_build_call_gen(IrAnalyze *ira, IrInstruction *source_instruction,
1389 ZigFn *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args,1389 ZigFn *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args,
1390 FnInline fn_inline, bool is_async, IrInstruction *new_stack,1390 FnInline fn_inline, bool is_async, IrInstruction *new_stack,
1391 IrInstruction *result_loc, ZigType *return_type)1391 IrInstruction *result_loc, ZigType *return_type)
...@@ -1408,7 +1408,7 @@ static IrInstruction *ir_build_call_gen(IrAnalyze *ira, IrInstruction *source_in...@@ -1408,7 +1408,7 @@ static IrInstruction *ir_build_call_gen(IrAnalyze *ira, IrInstruction *source_in
1408 if (new_stack != nullptr) ir_ref_instruction(new_stack, ira->new_irb.current_basic_block);1408 if (new_stack != nullptr) ir_ref_instruction(new_stack, ira->new_irb.current_basic_block);
1409 if (result_loc != nullptr) ir_ref_instruction(result_loc, ira->new_irb.current_basic_block);1409 if (result_loc != nullptr) ir_ref_instruction(result_loc, ira->new_irb.current_basic_block);
14101410
1411 return &call_instruction->base;1411 return call_instruction;
1412}1412}
14131413
1414static IrInstruction *ir_build_phi(IrBuilder *irb, Scope *scope, AstNode *source_node,1414static IrInstruction *ir_build_phi(IrBuilder *irb, Scope *scope, AstNode *source_node,
...@@ -14650,8 +14650,8 @@ static IrInstruction *ir_analyze_async_call(IrAnalyze *ira, IrInstructionCallSrc...@@ -14650,8 +14650,8 @@ static IrInstruction *ir_analyze_async_call(IrAnalyze *ira, IrInstructionCallSrc
14650 if (result_loc != nullptr && (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc))) {14650 if (result_loc != nullptr && (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc))) {
14651 return result_loc;14651 return result_loc;
14652 }14652 }
14653 return ir_build_call_gen(ira, &call_instruction->base, fn_entry, fn_ref, arg_count,14653 return &ir_build_call_gen(ira, &call_instruction->base, fn_entry, fn_ref, arg_count,
14654 casted_args, FnInlineAuto, true, nullptr, result_loc, frame_type);14654 casted_args, FnInlineAuto, true, nullptr, result_loc, frame_type)->base;
14655}14655}
14656static bool ir_analyze_fn_call_inline_arg(IrAnalyze *ira, AstNode *fn_proto_node,14656static bool ir_analyze_fn_call_inline_arg(IrAnalyze *ira, AstNode *fn_proto_node,
14657 IrInstruction *arg, Scope **exec_scope, size_t *next_proto_i)14657 IrInstruction *arg, Scope **exec_scope, size_t *next_proto_i)
...@@ -15387,15 +15387,16 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c...@@ -15387,15 +15387,16 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c
15387 if (impl_fn_type_id->cc == CallingConventionAsync && parent_fn_entry->inferred_async_node == nullptr) {15387 if (impl_fn_type_id->cc == CallingConventionAsync && parent_fn_entry->inferred_async_node == nullptr) {
15388 parent_fn_entry->inferred_async_node = fn_ref->source_node;15388 parent_fn_entry->inferred_async_node = fn_ref->source_node;
15389 }15389 }
15390 parent_fn_entry->call_list.append({call_instruction->base.source_node, impl_fn});
15391 }15390 }
1539215391
15393 IrInstruction *new_call_instruction = ir_build_call_gen(ira, &call_instruction->base,15392 IrInstructionCallGen *new_call_instruction = ir_build_call_gen(ira, &call_instruction->base,
15394 impl_fn, nullptr, impl_param_count, casted_args, fn_inline,15393 impl_fn, nullptr, impl_param_count, casted_args, fn_inline,
15395 call_instruction->is_async, casted_new_stack, result_loc,15394 call_instruction->is_async, casted_new_stack, result_loc,
15396 impl_fn_type_id->return_type);15395 impl_fn_type_id->return_type);
1539715396
15398 return ir_finish_anal(ira, new_call_instruction);15397 parent_fn_entry->call_list.append(new_call_instruction);
15398
15399 return ir_finish_anal(ira, &new_call_instruction->base);
15399 }15400 }
1540015401
15401 ZigFn *parent_fn_entry = exec_fn_entry(ira->new_irb.exec);15402 ZigFn *parent_fn_entry = exec_fn_entry(ira->new_irb.exec);
...@@ -15469,9 +15470,6 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c...@@ -15469,9 +15470,6 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c
15469 if (fn_type_id->cc == CallingConventionAsync && parent_fn_entry->inferred_async_node == nullptr) {15470 if (fn_type_id->cc == CallingConventionAsync && parent_fn_entry->inferred_async_node == nullptr) {
15470 parent_fn_entry->inferred_async_node = fn_ref->source_node;15471 parent_fn_entry->inferred_async_node = fn_ref->source_node;
15471 }15472 }
15472 if (fn_entry != nullptr) {
15473 parent_fn_entry->call_list.append({call_instruction->base.source_node, fn_entry});
15474 }
15475 }15473 }
1547615474
15477 if (call_instruction->is_async) {15475 if (call_instruction->is_async) {
...@@ -15491,10 +15489,11 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c...@@ -15491,10 +15489,11 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c
15491 result_loc = nullptr;15489 result_loc = nullptr;
15492 }15490 }
1549315491
15494 IrInstruction *new_call_instruction = ir_build_call_gen(ira, &call_instruction->base, fn_entry, fn_ref,15492 IrInstructionCallGen *new_call_instruction = ir_build_call_gen(ira, &call_instruction->base, fn_entry, fn_ref,
15495 call_param_count, casted_args, fn_inline, false, casted_new_stack,15493 call_param_count, casted_args, fn_inline, false, casted_new_stack,
15496 result_loc, return_type);15494 result_loc, return_type);
15497 return ir_finish_anal(ira, new_call_instruction);15495 parent_fn_entry->call_list.append(new_call_instruction);
15496 return ir_finish_anal(ira, &new_call_instruction->base);
15498}15497}
1549915498
15500static IrInstruction *ir_analyze_instruction_call(IrAnalyze *ira, IrInstructionCallSrc *call_instruction) {15499static IrInstruction *ir_analyze_instruction_call(IrAnalyze *ira, IrInstructionCallSrc *call_instruction) {
...@@ -24154,8 +24153,7 @@ static IrInstruction *ir_analyze_instruction_suspend_br(IrAnalyze *ira, IrInstru...@@ -24154,8 +24153,7 @@ static IrInstruction *ir_analyze_instruction_suspend_br(IrAnalyze *ira, IrInstru
24154 ZigFn *fn_entry = exec_fn_entry(ira->new_irb.exec);24153 ZigFn *fn_entry = exec_fn_entry(ira->new_irb.exec);
24155 ir_assert(fn_entry != nullptr, &instruction->base);24154 ir_assert(fn_entry != nullptr, &instruction->base);
2415624155
24157 // +2 - one for the GetSize block, one for the Entry block, resume blocks are indexed after that.24156 new_bb->resume_index = fn_entry->resume_blocks.length + coro_extra_resume_block_count;
24158 new_bb->resume_index = fn_entry->resume_blocks.length + 2;
2415924157
24160 fn_entry->resume_blocks.append(new_bb);24158 fn_entry->resume_blocks.append(new_bb);
24161 if (fn_entry->inferred_async_node == nullptr) {24159 if (fn_entry->inferred_async_node == nullptr) {
src/zig_llvm.cpp+4
...@@ -898,6 +898,10 @@ LLVMValueRef ZigLLVMBuildAShrExact(LLVMBuilderRef builder, LLVMValueRef LHS, LLV...@@ -898,6 +898,10 @@ LLVMValueRef ZigLLVMBuildAShrExact(LLVMBuilderRef builder, LLVMValueRef LHS, LLV
898 return wrap(unwrap(builder)->CreateAShr(unwrap(LHS), unwrap(RHS), name, true));898 return wrap(unwrap(builder)->CreateAShr(unwrap(LHS), unwrap(RHS), name, true));
899}899}
900900
901void ZigLLVMSetTailCall(LLVMValueRef Call) {
902 unwrap<CallInst>(Call)->setTailCallKind(CallInst::TCK_MustTail);
903}
904
901905
902class MyOStream: public raw_ostream {906class MyOStream: public raw_ostream {
903 public:907 public:
src/zig_llvm.h+1
...@@ -211,6 +211,7 @@ ZIG_EXTERN_C LLVMValueRef ZigLLVMInsertDeclare(struct ZigLLVMDIBuilder *dibuilde...@@ -211,6 +211,7 @@ ZIG_EXTERN_C LLVMValueRef ZigLLVMInsertDeclare(struct ZigLLVMDIBuilder *dibuilde
211ZIG_EXTERN_C struct ZigLLVMDILocation *ZigLLVMGetDebugLoc(unsigned line, unsigned col, struct ZigLLVMDIScope *scope);211ZIG_EXTERN_C struct ZigLLVMDILocation *ZigLLVMGetDebugLoc(unsigned line, unsigned col, struct ZigLLVMDIScope *scope);
212212
213ZIG_EXTERN_C void ZigLLVMSetFastMath(LLVMBuilderRef builder_wrapped, bool on_state);213ZIG_EXTERN_C void ZigLLVMSetFastMath(LLVMBuilderRef builder_wrapped, bool on_state);
214ZIG_EXTERN_C void ZigLLVMSetTailCall(LLVMValueRef Call);
214215
215ZIG_EXTERN_C void ZigLLVMAddFunctionAttr(LLVMValueRef fn, const char *attr_name, const char *attr_value);216ZIG_EXTERN_C void ZigLLVMAddFunctionAttr(LLVMValueRef fn, const char *attr_name, const char *attr_value);
216ZIG_EXTERN_C void ZigLLVMAddFunctionAttrCold(LLVMValueRef fn);217ZIG_EXTERN_C void ZigLLVMAddFunctionAttrCold(LLVMValueRef fn);
test/stage1/behavior/coroutines.zig+16
...@@ -77,6 +77,22 @@ test "local variable in async function" {...@@ -77,6 +77,22 @@ test "local variable in async function" {
77 S.doTheTest();77 S.doTheTest();
78}78}
7979
80test "calling an inferred async function" {
81 const S = struct {
82 fn doTheTest() void {
83 const p = async first();
84 }
85
86 fn first() void {
87 other();
88 }
89 fn other() void {
90 suspend;
91 }
92 };
93 S.doTheTest();
94}
95
80//test "coroutine suspend, resume" {96//test "coroutine suspend, resume" {
81// seq('a');97// seq('a');
82// const p = try async<allocator> testAsyncSeq();98// const p = try async<allocator> testAsyncSeq();