| author | |
| committer | |
| log | 7e9760de10e05a4c2a7bae4c4bb945351b9ae0cb |
| tree | b755e4c57ec91d62f0ce60a12001dac03bd286ad |
| parent | 317d1ecb2cf3234b0259daf6cc0baac7d86264e2 |
| signature |
6 files changed, 123 insertions(+), 28 deletions(-)
build.zig+3-1| ... | ... | @@ -375,7 +375,9 @@ fn addLibUserlandStep(b: *Builder) void { |
| 375 | 375 | artifact.bundle_compiler_rt = true; |
| 376 | 376 | artifact.setTarget(builtin.arch, builtin.os, builtin.abi); |
| 377 | 377 | artifact.linkSystemLibrary("c"); |
| 378 | artifact.linkSystemLibrary("ntdll"); | |
| 378 | if (builtin.os == .windows) { | |
| 379 | artifact.linkSystemLibrary("ntdll"); | |
| 380 | } | |
| 379 | 381 | const libuserland_step = b.step("libuserland", "Build the userland compiler library for use in stage1"); |
| 380 | 382 | libuserland_step.dependOn(&artifact.step); |
| 381 | 383 |
src/all_types.hpp+7| ... | ... | @@ -1336,6 +1336,11 @@ struct GlobalExport { |
| 1336 | 1336 | GlobalLinkageId linkage; |
| 1337 | 1337 | }; |
| 1338 | 1338 | |
| 1339 | struct FnCall { | |
| 1340 | AstNode *source_node; | |
| 1341 | ZigFn *callee; | |
| 1342 | }; | |
| 1343 | ||
| 1339 | 1344 | struct ZigFn { |
| 1340 | 1345 | CodeGen *codegen; |
| 1341 | 1346 | LLVMValueRef llvm_value; |
| ... | ... | @@ -1379,8 +1384,10 @@ struct ZigFn { |
| 1379 | 1384 | AstNode *set_alignstack_node; |
| 1380 | 1385 | |
| 1381 | 1386 | AstNode *set_cold_node; |
| 1387 | const AstNode *inferred_async_node; | |
| 1382 | 1388 | |
| 1383 | 1389 | ZigList<GlobalExport> export_list; |
| 1390 | ZigList<FnCall> call_list; | |
| 1384 | 1391 | |
| 1385 | 1392 | LLVMValueRef valgrind_client_request_array; |
| 1386 | 1393 | LLVMBasicBlockRef preamble_llvm_block; |
src/analyze.cpp+81-19| ... | ... | @@ -31,6 +31,11 @@ static void resolve_llvm_types(CodeGen *g, ZigType *type, ResolveStatus wanted_r |
| 31 | 31 | static void preview_use_decl(CodeGen *g, TldUsingNamespace *using_namespace, ScopeDecls *dest_decls_scope); |
| 32 | 32 | static void resolve_use_decl(CodeGen *g, TldUsingNamespace *tld_using_namespace, ScopeDecls *dest_decls_scope); |
| 33 | 33 | |
| 34 | // nullptr means not analyzed yet; this one means currently being analyzed | |
| 35 | static const AstNode *inferred_async_checking = reinterpret_cast<AstNode *>(0x1); | |
| 36 | // this one means analyzed and it's not async | |
| 37 | static const AstNode *inferred_async_none = reinterpret_cast<AstNode *>(0x2); | |
| 38 | ||
| 34 | 39 | static bool is_top_level_struct(ZigType *import) { |
| 35 | 40 | return import->id == ZigTypeIdStruct && import->data.structure.root_struct != nullptr; |
| 36 | 41 | } |
| ... | ... | @@ -1892,8 +1897,12 @@ static Error resolve_coro_frame(CodeGen *g, ZigType *frame_type) { |
| 1892 | 1897 | field_names.append("resume_index"); |
| 1893 | 1898 | field_types.append(g->builtin_types.entry_usize); |
| 1894 | 1899 | |
| 1895 | for (size_t arg_i = 0; arg_i < fn->type_entry->data.fn.fn_type_id.param_count; arg_i += 1) { | |
| 1896 | FnTypeParamInfo *param_info = &fn->type_entry->data.fn.fn_type_id.param_info[arg_i]; | |
| 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]; | |
| 1897 | 1906 | AstNode *param_decl_node = get_param_decl_node(fn, arg_i); |
| 1898 | 1907 | Buf *param_name; |
| 1899 | 1908 | bool is_var_args = param_decl_node && param_decl_node->data.param_decl.is_var_args; |
| ... | ... | @@ -2796,6 +2805,16 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) { |
| 2796 | 2805 | g->fn_defs.append(fn_table_entry); |
| 2797 | 2806 | } |
| 2798 | 2807 | |
| 2808 | switch (fn_table_entry->type_entry->data.fn.fn_type_id.cc) { | |
| 2809 | case CallingConventionAsync: | |
| 2810 | fn_table_entry->inferred_async_node = fn_table_entry->proto_node; | |
| 2811 | break; | |
| 2812 | case CallingConventionUnspecified: | |
| 2813 | break; | |
| 2814 | default: | |
| 2815 | fn_table_entry->inferred_async_node = inferred_async_none; | |
| 2816 | } | |
| 2817 | ||
| 2799 | 2818 | if (scope_is_root_decls(tld_fn->base.parent_scope) && |
| 2800 | 2819 | (import == g->root_import || import->data.structure.root_struct->package == g->panic_package)) |
| 2801 | 2820 | { |
| ... | ... | @@ -3767,6 +3786,55 @@ bool resolve_inferred_error_set(CodeGen *g, ZigType *err_set_type, AstNode *sour |
| 3767 | 3786 | return true; |
| 3768 | 3787 | } |
| 3769 | 3788 | |
| 3789 | static void resolve_async_fn_frame(CodeGen *g, ZigFn *fn) { | |
| 3790 | ZigType *frame_type = get_coro_frame_type(g, fn); | |
| 3791 | Error err; | |
| 3792 | if ((err = type_resolve(g, frame_type, ResolveStatusSizeKnown))) { | |
| 3793 | fn->anal_state = FnAnalStateInvalid; | |
| 3794 | return; | |
| 3795 | } | |
| 3796 | } | |
| 3797 | ||
| 3798 | bool fn_is_async(ZigFn *fn) { | |
| 3799 | assert(fn->inferred_async_node != nullptr); | |
| 3800 | assert(fn->inferred_async_node != inferred_async_checking); | |
| 3801 | return fn->inferred_async_node != inferred_async_none; | |
| 3802 | } | |
| 3803 | ||
| 3804 | // This function resolves functions being inferred async. | |
| 3805 | static void analyze_fn_async(CodeGen *g, ZigFn *fn) { | |
| 3806 | if (fn->inferred_async_node == inferred_async_checking) { | |
| 3807 | // TODO call graph cycle detected, disallow the recursion | |
| 3808 | fn->inferred_async_node = inferred_async_none; | |
| 3809 | return; | |
| 3810 | } | |
| 3811 | if (fn->inferred_async_node == inferred_async_none) { | |
| 3812 | return; | |
| 3813 | } | |
| 3814 | if (fn->inferred_async_node != nullptr) { | |
| 3815 | resolve_async_fn_frame(g, fn); | |
| 3816 | return; | |
| 3817 | } | |
| 3818 | fn->inferred_async_node = inferred_async_checking; | |
| 3819 | for (size_t i = 0; i < fn->call_list.length; i += 1) { | |
| 3820 | FnCall *call = &fn->call_list.at(i); | |
| 3821 | if (call->callee->type_entry->data.fn.fn_type_id.cc != CallingConventionUnspecified) | |
| 3822 | continue; | |
| 3823 | assert(call->callee->anal_state == FnAnalStateComplete); | |
| 3824 | analyze_fn_async(g, call->callee); | |
| 3825 | if (call->callee->anal_state == FnAnalStateInvalid) { | |
| 3826 | fn->anal_state = FnAnalStateInvalid; | |
| 3827 | return; | |
| 3828 | } | |
| 3829 | if (fn_is_async(call->callee)) { | |
| 3830 | fn->inferred_async_node = call->source_node; | |
| 3831 | resolve_async_fn_frame(g, fn); | |
| 3832 | return; | |
| 3833 | } | |
| 3834 | } | |
| 3835 | fn->inferred_async_node = inferred_async_none; | |
| 3836 | } | |
| 3837 | ||
| 3770 | 3838 | static void analyze_fn_ir(CodeGen *g, ZigFn *fn_table_entry, AstNode *return_type_node) { |
| 3771 | 3839 | ZigType *fn_type = fn_table_entry->type_entry; |
| 3772 | 3840 | assert(!fn_type->data.fn.is_generic); |
| ... | ... | @@ -3824,17 +3892,7 @@ static void analyze_fn_ir(CodeGen *g, ZigFn *fn_table_entry, AstNode *return_typ |
| 3824 | 3892 | ir_print(g, stderr, &fn_table_entry->analyzed_executable, 4); |
| 3825 | 3893 | fprintf(stderr, "}\n"); |
| 3826 | 3894 | } |
| 3827 | ||
| 3828 | 3895 | fn_table_entry->anal_state = FnAnalStateComplete; |
| 3829 | ||
| 3830 | if (fn_table_entry->resume_blocks.length != 0) { | |
| 3831 | ZigType *frame_type = get_coro_frame_type(g, fn_table_entry); | |
| 3832 | Error err; | |
| 3833 | if ((err = type_resolve(g, frame_type, ResolveStatusSizeKnown))) { | |
| 3834 | fn_table_entry->anal_state = FnAnalStateInvalid; | |
| 3835 | return; | |
| 3836 | } | |
| 3837 | } | |
| 3838 | 3896 | } |
| 3839 | 3897 | |
| 3840 | 3898 | static void analyze_fn_body(CodeGen *g, ZigFn *fn_table_entry) { |
| ... | ... | @@ -4004,6 +4062,16 @@ void semantic_analyze(CodeGen *g) { |
| 4004 | 4062 | analyze_fn_body(g, fn_entry); |
| 4005 | 4063 | } |
| 4006 | 4064 | } |
| 4065 | ||
| 4066 | if (g->errors.length != 0) { | |
| 4067 | return; | |
| 4068 | } | |
| 4069 | ||
| 4070 | // second pass over functions for detecting async | |
| 4071 | for (g->fn_defs_index = 0; g->fn_defs_index < g->fn_defs.length; g->fn_defs_index += 1) { | |
| 4072 | ZigFn *fn_entry = g->fn_defs.at(g->fn_defs_index); | |
| 4073 | analyze_fn_async(g, fn_entry); | |
| 4074 | } | |
| 4007 | 4075 | } |
| 4008 | 4076 | |
| 4009 | 4077 | ZigType *get_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits) { |
| ... | ... | @@ -7173,11 +7241,7 @@ void resolve_llvm_types_fn(CodeGen *g, ZigFn *fn) { |
| 7173 | 7241 | if (fn->raw_di_type != nullptr) return; |
| 7174 | 7242 | |
| 7175 | 7243 | ZigType *fn_type = fn->type_entry; |
| 7176 | FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id; | |
| 7177 | bool cc_async = fn_type_id->cc == CallingConventionAsync; | |
| 7178 | bool inferred_async = fn->resume_blocks.length != 0; | |
| 7179 | bool is_async = cc_async || inferred_async; | |
| 7180 | if (!is_async) { | |
| 7244 | if (!fn_is_async(fn)) { | |
| 7181 | 7245 | resolve_llvm_types_fn_type(g, fn_type); |
| 7182 | 7246 | fn->raw_type_ref = fn_type->data.fn.raw_type_ref; |
| 7183 | 7247 | fn->raw_di_type = fn_type->data.fn.raw_di_type; |
| ... | ... | @@ -7223,8 +7287,6 @@ static void resolve_llvm_types_anyerror(CodeGen *g) { |
| 7223 | 7287 | } |
| 7224 | 7288 | |
| 7225 | 7289 | static void resolve_llvm_types_coro_frame(CodeGen *g, ZigType *frame_type, ResolveStatus wanted_resolve_status) { |
| 7226 | if (frame_type->llvm_di_type != nullptr) return; | |
| 7227 | ||
| 7228 | 7290 | resolve_llvm_types_struct(g, frame_type->data.frame.locals_struct, wanted_resolve_status); |
| 7229 | 7291 | frame_type->llvm_type = frame_type->data.frame.locals_struct->llvm_type; |
| 7230 | 7292 | frame_type->llvm_di_type = frame_type->data.frame.locals_struct->llvm_di_type; |
src/analyze.hpp+1| ... | ... | @@ -248,5 +248,6 @@ bool is_container(ZigType *type_entry); |
| 248 | 248 | ConstExprValue *analyze_const_value(CodeGen *g, Scope *scope, AstNode *node, ZigType *type_entry, Buf *type_name); |
| 249 | 249 | |
| 250 | 250 | void resolve_llvm_types_fn(CodeGen *g, ZigFn *fn); |
| 251 | bool fn_is_async(ZigFn *fn); | |
| 251 | 252 | |
| 252 | 253 | #endif |
src/codegen.cpp+12-8| ... | ... | @@ -371,7 +371,7 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) { |
| 371 | 371 | symbol_name = buf_sprintf("\x01_%s", buf_ptr(symbol_name)); |
| 372 | 372 | } |
| 373 | 373 | |
| 374 | bool is_async = fn_table_entry->resume_blocks.length != 0 || cc == CallingConventionAsync; | |
| 374 | bool is_async = fn_is_async(fn_table_entry); | |
| 375 | 375 | |
| 376 | 376 | |
| 377 | 377 | ZigType *fn_type = fn_table_entry->type_entry; |
| ... | ... | @@ -1847,7 +1847,7 @@ static bool iter_function_params_c_abi(CodeGen *g, ZigType *fn_type, FnWalk *fn_ |
| 1847 | 1847 | } |
| 1848 | 1848 | case FnWalkIdInits: { |
| 1849 | 1849 | clear_debug_source_node(g); |
| 1850 | if (fn_walk->data.inits.fn->resume_blocks.length == 0) { | |
| 1850 | if (!fn_is_async(fn_walk->data.inits.fn)) { | |
| 1851 | 1851 | LLVMValueRef arg = LLVMGetParam(llvm_fn, fn_walk->data.inits.gen_i); |
| 1852 | 1852 | LLVMTypeRef ptr_to_int_type_ref = LLVMPointerType(LLVMIntType((unsigned)ty_size * 8), 0); |
| 1853 | 1853 | LLVMValueRef bitcasted = LLVMBuildBitCast(g->builder, var->value_ref, ptr_to_int_type_ref, ""); |
| ... | ... | @@ -1945,7 +1945,7 @@ void walk_function_params(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk) { |
| 1945 | 1945 | assert(variable); |
| 1946 | 1946 | assert(variable->value_ref); |
| 1947 | 1947 | |
| 1948 | if (!handle_is_ptr(variable->var_type) && fn_walk->data.inits.fn->resume_blocks.length == 0) { | |
| 1948 | if (!handle_is_ptr(variable->var_type) && !fn_is_async(fn_walk->data.inits.fn)) { | |
| 1949 | 1949 | clear_debug_source_node(g); |
| 1950 | 1950 | ZigType *fn_type = fn_table_entry->type_entry; |
| 1951 | 1951 | unsigned gen_arg_index = fn_type->data.fn.gen_param_info[variable->src_arg_index].gen_index; |
| ... | ... | @@ -1986,7 +1986,7 @@ static LLVMValueRef ir_render_save_err_ret_addr(CodeGen *g, IrExecutable *execut |
| 1986 | 1986 | } |
| 1987 | 1987 | |
| 1988 | 1988 | static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrInstructionReturn *return_instruction) { |
| 1989 | if (g->cur_fn->resume_blocks.length != 0) { | |
| 1989 | if (fn_is_async(g->cur_fn)) { | |
| 1990 | 1990 | if (ir_want_runtime_safety(g, &return_instruction->base)) { |
| 1991 | 1991 | LLVMValueRef locals_ptr = g->cur_ret_ptr; |
| 1992 | 1992 | LLVMValueRef resume_index_ptr = LLVMBuildStructGEP(g->builder, locals_ptr, coro_resume_index_index, ""); |
| ... | ... | @@ -3387,8 +3387,10 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr |
| 3387 | 3387 | LLVMValueRef result; |
| 3388 | 3388 | |
| 3389 | 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; | |
| 3390 | 3391 | for (size_t arg_i = 0; arg_i < gen_param_values.length; arg_i += 1) { |
| 3391 | LLVMValueRef arg_ptr = LLVMBuildStructGEP(g->builder, result_loc, coro_arg_start + arg_i, ""); | |
| 3392 | LLVMValueRef arg_ptr = LLVMBuildStructGEP(g->builder, result_loc, | |
| 3393 | coro_arg_start + ret_1_or_0 + arg_i, ""); | |
| 3392 | 3394 | LLVMBuildStore(g->builder, gen_param_values.at(arg_i), arg_ptr); |
| 3393 | 3395 | } |
| 3394 | 3396 | ZigLLVMBuildCall(g->builder, fn_val, &result_loc, 1, llvm_cc, fn_inline, ""); |
| ... | ... | @@ -5983,7 +5985,7 @@ static void build_all_basic_blocks(CodeGen *g, ZigFn *fn) { |
| 5983 | 5985 | assert(executable->basic_block_list.length > 0); |
| 5984 | 5986 | LLVMValueRef fn_val = fn_llvm_value(g, fn); |
| 5985 | 5987 | LLVMBasicBlockRef first_bb = nullptr; |
| 5986 | if (fn->resume_blocks.length != 0) { | |
| 5988 | if (fn_is_async(fn)) { | |
| 5987 | 5989 | first_bb = LLVMAppendBasicBlock(fn_val, "AsyncSwitch"); |
| 5988 | 5990 | fn->preamble_llvm_block = first_bb; |
| 5989 | 5991 | } |
| ... | ... | @@ -6171,7 +6173,7 @@ static void do_code_gen(CodeGen *g) { |
| 6171 | 6173 | build_all_basic_blocks(g, fn_table_entry); |
| 6172 | 6174 | clear_debug_source_node(g); |
| 6173 | 6175 | |
| 6174 | bool is_async = cc == CallingConventionAsync || fn_table_entry->resume_blocks.length != 0; | |
| 6176 | bool is_async = fn_is_async(fn_table_entry); | |
| 6175 | 6177 | |
| 6176 | 6178 | if (want_sret || is_async) { |
| 6177 | 6179 | g->cur_ret_ptr = LLVMGetParam(fn, 0); |
| ... | ... | @@ -6261,7 +6263,9 @@ static void do_code_gen(CodeGen *g) { |
| 6261 | 6263 | fn_walk_var.data.vars.var = var; |
| 6262 | 6264 | iter_function_params_c_abi(g, fn_table_entry->type_entry, &fn_walk_var, var->src_arg_index); |
| 6263 | 6265 | } else if (is_async) { |
| 6264 | var->value_ref = LLVMBuildStructGEP(g->builder, g->cur_ret_ptr, coro_arg_start + var_i, ""); | |
| 6266 | size_t ret_1_or_0 = type_has_bits(fn_type_id->return_type) ? 1 : 0; | |
| 6267 | var->value_ref = LLVMBuildStructGEP(g->builder, g->cur_ret_ptr, | |
| 6268 | coro_arg_start + ret_1_or_0 + var_i, ""); | |
| 6265 | 6269 | if (var->decl_node) { |
| 6266 | 6270 | var->di_loc_var = ZigLLVMCreateAutoVariable(g->dbuilder, get_di_scope(g, var->parent_scope), |
| 6267 | 6271 | buf_ptr(&var->name), import->data.structure.root_struct->di_file, |
src/ir.cpp+19| ... | ... | @@ -15383,6 +15383,13 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c |
| 15383 | 15383 | zig_panic("TODO async call"); |
| 15384 | 15384 | } |
| 15385 | 15385 | |
| 15386 | if (!call_instruction->is_async) { | |
| 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; | |
| 15389 | } | |
| 15390 | parent_fn_entry->call_list.append({call_instruction->base.source_node, impl_fn}); | |
| 15391 | } | |
| 15392 | ||
| 15386 | 15393 | IrInstruction *new_call_instruction = ir_build_call_gen(ira, &call_instruction->base, |
| 15387 | 15394 | impl_fn, nullptr, impl_param_count, casted_args, fn_inline, |
| 15388 | 15395 | call_instruction->is_async, casted_new_stack, result_loc, |
| ... | ... | @@ -15458,6 +15465,15 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c |
| 15458 | 15465 | return ira->codegen->invalid_instruction; |
| 15459 | 15466 | } |
| 15460 | 15467 | |
| 15468 | if (!call_instruction->is_async) { | |
| 15469 | 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 | } | |
| 15472 | if (fn_entry != nullptr) { | |
| 15473 | parent_fn_entry->call_list.append({call_instruction->base.source_node, fn_entry}); | |
| 15474 | } | |
| 15475 | } | |
| 15476 | ||
| 15461 | 15477 | if (call_instruction->is_async) { |
| 15462 | 15478 | IrInstruction *result = ir_analyze_async_call(ira, call_instruction, fn_entry, fn_type, fn_ref, |
| 15463 | 15479 | casted_args, call_param_count); |
| ... | ... | @@ -24142,6 +24158,9 @@ static IrInstruction *ir_analyze_instruction_suspend_br(IrAnalyze *ira, IrInstru |
| 24142 | 24158 | new_bb->resume_index = fn_entry->resume_blocks.length + 2; |
| 24143 | 24159 | |
| 24144 | 24160 | fn_entry->resume_blocks.append(new_bb); |
| 24161 | if (fn_entry->inferred_async_node == nullptr) { | |
| 24162 | fn_entry->inferred_async_node = instruction->base.source_node; | |
| 24163 | } | |
| 24145 | 24164 | |
| 24146 | 24165 | ir_push_resume_block(ira, old_dest_block); |
| 24147 | 24166 |