| author | |
| committer | |
| log | ead2d32be871411685f846e604ec7e4253b9f25a |
| tree | f9e3f930aef5ed60d452c4cf20776879b086acf1 |
| parent | e220812f2f0fe2becd570308971f98e0290835db |
| signature |
7 files changed, 238 insertions(+), 118 deletions(-)
src/all_types.hpp+10-7| ... | ... | @@ -35,6 +35,7 @@ struct ConstExprValue; |
| 35 | 35 | struct IrInstruction; |
| 36 | 36 | struct IrInstructionCast; |
| 37 | 37 | struct IrInstructionAllocaGen; |
| 38 | struct IrInstructionCallGen; | |
| 38 | 39 | struct IrBasicBlock; |
| 39 | 40 | struct ScopeDecls; |
| 40 | 41 | struct ZigWindowsSDK; |
| ... | ... | @@ -1336,11 +1337,6 @@ struct GlobalExport { |
| 1336 | 1337 | GlobalLinkageId linkage; |
| 1337 | 1338 | }; |
| 1338 | 1339 | |
| 1339 | struct FnCall { | |
| 1340 | AstNode *source_node; | |
| 1341 | ZigFn *callee; | |
| 1342 | }; | |
| 1343 | ||
| 1344 | 1340 | struct ZigFn { |
| 1345 | 1341 | LLVMValueRef llvm_value; |
| 1346 | 1342 | const char *llvm_name; |
| ... | ... | @@ -1387,7 +1383,7 @@ struct ZigFn { |
| 1387 | 1383 | ZigFn *inferred_async_fn; |
| 1388 | 1384 | |
| 1389 | 1385 | ZigList<GlobalExport> export_list; |
| 1390 | ZigList<FnCall> call_list; | |
| 1386 | ZigList<IrInstructionCallGen *> call_list; | |
| 1391 | 1387 | |
| 1392 | 1388 | LLVMValueRef valgrind_client_request_array; |
| 1393 | 1389 | LLVMBasicBlockRef preamble_llvm_block; |
| ... | ... | @@ -2585,6 +2581,8 @@ struct IrInstructionCallGen { |
| 2585 | 2581 | size_t arg_count; |
| 2586 | 2582 | IrInstruction **args; |
| 2587 | 2583 | IrInstruction *result_loc; |
| 2584 | IrInstruction *frame_result_loc; | |
| 2585 | IrBasicBlock *resume_block; | |
| 2588 | 2586 | |
| 2589 | 2587 | IrInstruction *new_stack; |
| 2590 | 2588 | FnInline fn_inline; |
| ... | ... | @@ -3645,7 +3643,12 @@ static const size_t err_union_err_index = 0; |
| 3645 | 3643 | static const size_t err_union_payload_index = 1; |
| 3646 | 3644 | |
| 3647 | 3645 | static const size_t coro_resume_index_index = 0; |
| 3648 | static const size_t coro_arg_start = 1; | |
| 3646 | static const size_t coro_fn_ptr_index = 1; | |
| 3647 | static const size_t coro_awaiter_index = 2; | |
| 3648 | static 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. | |
| 3651 | static const size_t coro_extra_resume_block_count = 2; | |
| 3649 | 3652 | |
| 3650 | 3653 | // TODO call graph analysis to find out what this number needs to be for every function |
| 3651 | 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 | 1869 | return ErrorNone; |
| 1870 | 1870 | } |
| 1871 | 1871 | |
| 1872 | static 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 | ||
| 1946 | 1872 | static bool type_is_valid_extern_enum_tag(CodeGen *g, ZigType *ty) { |
| 1947 | 1873 | // Only integer types are allowed by the C ABI |
| 1948 | 1874 | if(ty->id != ZigTypeIdInt) |
| ... | ... | @@ -3861,18 +3787,24 @@ static void analyze_fn_async(CodeGen *g, ZigFn *fn) { |
| 3861 | 3787 | } |
| 3862 | 3788 | |
| 3863 | 3789 | for (size_t i = 0; i < fn->call_list.length; i += 1) { |
| 3864 | FnCall *call = &fn->call_list.at(i); | |
| 3865 | if (call->callee->type_entry->data.fn.fn_type_id.cc != CallingConventionUnspecified) | |
| 3790 | IrInstructionCallGen *call = fn->call_list.at(i); | |
| 3791 | ZigFn *callee = call->fn_entry; | |
| 3792 | if (callee == nullptr) { | |
| 3793 | // TODO function pointer call here, could be anything | |
| 3866 | 3794 | continue; |
| 3867 | assert(call->callee->anal_state == FnAnalStateComplete); | |
| 3868 | analyze_fn_async(g, call->callee); | |
| 3869 | if (call->callee->anal_state == FnAnalStateInvalid) { | |
| 3795 | } | |
| 3796 | ||
| 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 | 3802 | fn->anal_state = FnAnalStateInvalid; |
| 3871 | 3803 | return; |
| 3872 | 3804 | } |
| 3873 | if (fn_is_async(call->callee)) { | |
| 3874 | fn->inferred_async_node = call->source_node; | |
| 3875 | fn->inferred_async_fn = call->callee; | |
| 3805 | if (fn_is_async(callee)) { | |
| 3806 | fn->inferred_async_node = call->base.source_node; | |
| 3807 | fn->inferred_async_fn = callee; | |
| 3876 | 3808 | if (must_not_be_async) { |
| 3877 | 3809 | ErrorMsg *msg = add_node_error(g, fn->proto_node, |
| 3878 | 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 | 5079 | return type_resolve(g, type_entry, ResolveStatusSizeKnown); |
| 5148 | 5080 | } |
| 5149 | 5081 | |
| 5082 | static 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 | ||
| 5150 | 5203 | Error type_resolve(CodeGen *g, ZigType *ty, ResolveStatus status) { |
| 5151 | 5204 | if (type_is_invalid(ty)) |
| 5152 | 5205 | return ErrorSemanticAnalyzeFail; |
| ... | ... | @@ -7343,9 +7396,6 @@ static void resolve_llvm_types_coro_frame(CodeGen *g, ZigType *frame_type, Resol |
| 7343 | 7396 | resolve_llvm_types_struct(g, frame_type->data.frame.locals_struct, wanted_resolve_status); |
| 7344 | 7397 | frame_type->llvm_type = frame_type->data.frame.locals_struct->llvm_type; |
| 7345 | 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 | } |
| 7350 | 7400 | |
| 7351 | 7401 | static 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 | 3324 | static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstructionCallGen *instruction) { |
| 3325 | 3325 | LLVMValueRef fn_val; |
| 3326 | 3326 | ZigType *fn_type; |
| 3327 | bool callee_is_async; | |
| 3327 | 3328 | if (instruction->fn_entry) { |
| 3328 | 3329 | fn_val = fn_llvm_value(g, instruction->fn_entry); |
| 3329 | 3330 | fn_type = instruction->fn_entry->type_entry; |
| 3331 | callee_is_async = fn_is_async(instruction->fn_entry); | |
| 3330 | 3332 | } else { |
| 3331 | 3333 | assert(instruction->fn_ref); |
| 3332 | 3334 | fn_val = ir_llvm_value(g, instruction->fn_ref); |
| 3333 | 3335 | fn_type = instruction->fn_ref->value.type; |
| 3336 | callee_is_async = fn_type->data.fn.fn_type_id.cc == CallingConventionAsync; | |
| 3334 | 3337 | } |
| 3335 | 3338 | |
| 3336 | 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 | 3348 | bool is_var_args = fn_type_id->is_var_args; |
| 3346 | 3349 | ZigList<LLVMValueRef> gen_param_values = {}; |
| 3347 | 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 | 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 | 3371 | assert(instruction->fn_entry != nullptr); |
| 3351 | LLVMValueRef resume_index_ptr = LLVMBuildStructGEP(g->builder, result_loc, coro_resume_index_index, ""); | |
| 3352 | LLVMValueRef zero = LLVMConstNull(g->builtin_types.entry_usize->llvm_type); | |
| 3372 | LLVMValueRef resume_index_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, coro_resume_index_index, ""); | |
| 3353 | 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); | |
| 3354 | 3378 | |
| 3355 | 3379 | if (prefix_arg_err_ret_stack) { |
| 3356 | 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 | 3392 | if (first_arg_ret) { |
| 3360 | 3393 | gen_param_values.append(result_loc); |
| 3361 | 3394 | } |
| ... | ... | @@ -3386,14 +3419,28 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr |
| 3386 | 3419 | LLVMCallConv llvm_cc = get_llvm_cc(g, cc); |
| 3387 | 3420 | LLVMValueRef result; |
| 3388 | 3421 | |
| 3389 | if (instruction->is_async) { | |
| 3390 | size_t ret_1_or_0 = type_has_bits(fn_type->data.fn.fn_type_id.return_type) ? 1 : 0; | |
| 3422 | if (instruction->is_async || callee_is_async) { | |
| 3423 | size_t ret_2_or_0 = type_has_bits(fn_type->data.fn.fn_type_id.return_type) ? 2 : 0; | |
| 3391 | 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, | |
| 3393 | coro_arg_start + ret_1_or_0 + arg_i, ""); | |
| 3425 | LLVMValueRef arg_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, | |
| 3426 | coro_arg_start + ret_2_or_0 + arg_i, ""); | |
| 3394 | 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 | 3444 | return nullptr; |
| 3398 | 3445 | } |
| 3399 | 3446 | |
| ... | ... | @@ -6174,7 +6221,7 @@ static void do_code_gen(CodeGen *g) { |
| 6174 | 6221 | clear_debug_source_node(g); |
| 6175 | 6222 | |
| 6176 | 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); | |
| 6178 | 6225 | |
| 6179 | 6226 | if (want_sret || is_async) { |
| 6180 | 6227 | g->cur_ret_ptr = LLVMGetParam(fn, 0); |
| ... | ... | @@ -6385,8 +6432,9 @@ static void do_code_gen(CodeGen *g) { |
| 6385 | 6432 | LLVMAddCase(switch_instr, one, get_size_block); |
| 6386 | 6433 | |
| 6387 | 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); | |
| 6389 | LLVMAddCase(switch_instr, case_value, fn_table_entry->resume_blocks.at(resume_i)->llvm_block); | |
| 6435 | IrBasicBlock *resume_block = fn_table_entry->resume_blocks.at(resume_i); | |
| 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 | 6439 | } else { |
| 6392 | 6440 | // 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 | 1385 | return &call_instruction->base; |
| 1386 | 1386 | } |
| 1387 | 1387 | |
| 1388 | static IrInstruction *ir_build_call_gen(IrAnalyze *ira, IrInstruction *source_instruction, | |
| 1388 | static IrInstructionCallGen *ir_build_call_gen(IrAnalyze *ira, IrInstruction *source_instruction, | |
| 1389 | 1389 | ZigFn *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args, |
| 1390 | 1390 | FnInline fn_inline, bool is_async, IrInstruction *new_stack, |
| 1391 | 1391 | IrInstruction *result_loc, ZigType *return_type) |
| ... | ... | @@ -1408,7 +1408,7 @@ static IrInstruction *ir_build_call_gen(IrAnalyze *ira, IrInstruction *source_in |
| 1408 | 1408 | if (new_stack != nullptr) ir_ref_instruction(new_stack, ira->new_irb.current_basic_block); |
| 1409 | 1409 | if (result_loc != nullptr) ir_ref_instruction(result_loc, ira->new_irb.current_basic_block); |
| 1410 | 1410 | |
| 1411 | return &call_instruction->base; | |
| 1411 | return call_instruction; | |
| 1412 | 1412 | } |
| 1413 | 1413 | |
| 1414 | 1414 | static 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 | 14650 | if (result_loc != nullptr && (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc))) { |
| 14651 | 14651 | return result_loc; |
| 14652 | 14652 | } |
| 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); | |
| 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)->base; | |
| 14655 | 14655 | } |
| 14656 | 14656 | static bool ir_analyze_fn_call_inline_arg(IrAnalyze *ira, AstNode *fn_proto_node, |
| 14657 | 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 | 15387 | if (impl_fn_type_id->cc == CallingConventionAsync && parent_fn_entry->inferred_async_node == nullptr) { |
| 15388 | 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 | } |
| 15392 | 15391 | |
| 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 | 15393 | impl_fn, nullptr, impl_param_count, casted_args, fn_inline, |
| 15395 | 15394 | call_instruction->is_async, casted_new_stack, result_loc, |
| 15396 | 15395 | impl_fn_type_id->return_type); |
| 15397 | 15396 | |
| 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 | } |
| 15400 | 15401 | |
| 15401 | 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 | 15470 | if (fn_type_id->cc == CallingConventionAsync && parent_fn_entry->inferred_async_node == nullptr) { |
| 15470 | 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 | } |
| 15476 | 15474 | |
| 15477 | 15475 | if (call_instruction->is_async) { |
| ... | ... | @@ -15491,10 +15489,11 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c |
| 15491 | 15489 | result_loc = nullptr; |
| 15492 | 15490 | } |
| 15493 | 15491 | |
| 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 | 15493 | call_param_count, casted_args, fn_inline, false, casted_new_stack, |
| 15496 | 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 | } |
| 15499 | 15498 | |
| 15500 | 15499 | static 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 | 24153 | ZigFn *fn_entry = exec_fn_entry(ira->new_irb.exec); |
| 24155 | 24154 | ir_assert(fn_entry != nullptr, &instruction->base); |
| 24156 | 24155 | |
| 24157 | // +2 - one for the GetSize block, one for the Entry block, resume blocks are indexed after that. | |
| 24158 | new_bb->resume_index = fn_entry->resume_blocks.length + 2; | |
| 24156 | new_bb->resume_index = fn_entry->resume_blocks.length + coro_extra_resume_block_count; | |
| 24159 | 24157 | |
| 24160 | 24158 | fn_entry->resume_blocks.append(new_bb); |
| 24161 | 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 | 898 | return wrap(unwrap(builder)->CreateAShr(unwrap(LHS), unwrap(RHS), name, true)); |
| 899 | 899 | } |
| 900 | 900 | |
| 901 | void ZigLLVMSetTailCall(LLVMValueRef Call) { | |
| 902 | unwrap<CallInst>(Call)->setTailCallKind(CallInst::TCK_MustTail); | |
| 903 | } | |
| 904 | ||
| 901 | 905 | |
| 902 | 906 | class MyOStream: public raw_ostream { |
| 903 | 907 | public: |
src/zig_llvm.h+1| ... | ... | @@ -211,6 +211,7 @@ ZIG_EXTERN_C LLVMValueRef ZigLLVMInsertDeclare(struct ZigLLVMDIBuilder *dibuilde |
| 211 | 211 | ZIG_EXTERN_C struct ZigLLVMDILocation *ZigLLVMGetDebugLoc(unsigned line, unsigned col, struct ZigLLVMDIScope *scope); |
| 212 | 212 | |
| 213 | 213 | ZIG_EXTERN_C void ZigLLVMSetFastMath(LLVMBuilderRef builder_wrapped, bool on_state); |
| 214 | ZIG_EXTERN_C void ZigLLVMSetTailCall(LLVMValueRef Call); | |
| 214 | 215 | |
| 215 | 216 | ZIG_EXTERN_C void ZigLLVMAddFunctionAttr(LLVMValueRef fn, const char *attr_name, const char *attr_value); |
| 216 | 217 | ZIG_EXTERN_C void ZigLLVMAddFunctionAttrCold(LLVMValueRef fn); |
test/stage1/behavior/coroutines.zig+16| ... | ... | @@ -77,6 +77,22 @@ test "local variable in async function" { |
| 77 | 77 | S.doTheTest(); |
| 78 | 78 | } |
| 79 | 79 | |
| 80 | test "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 | 96 | //test "coroutine suspend, resume" { |
| 81 | 97 | // seq('a'); |
| 82 | 98 | // const p = try async<allocator> testAsyncSeq(); |