authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-07-23 18:54:45-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-07-23 18:54:45-04:00
log7e9760de10e05a4c2a7bae4c4bb945351b9ae0cb
treeb755e4c57ec91d62f0ce60a12001dac03bd286ad
parent317d1ecb2cf3234b0259daf6cc0baac7d86264e2
signaturelock-open Commit is signed but in an unrecognized format.

inferring async from async calls


6 files changed, 123 insertions(+), 28 deletions(-)

build.zig+3-1
......@@ -375,7 +375,9 @@ fn addLibUserlandStep(b: *Builder) void {
375375 artifact.bundle_compiler_rt = true;
376376 artifact.setTarget(builtin.arch, builtin.os, builtin.abi);
377377 artifact.linkSystemLibrary("c");
378 artifact.linkSystemLibrary("ntdll");
378 if (builtin.os == .windows) {
379 artifact.linkSystemLibrary("ntdll");
380 }
379381 const libuserland_step = b.step("libuserland", "Build the userland compiler library for use in stage1");
380382 libuserland_step.dependOn(&artifact.step);
381383
src/all_types.hpp+7
......@@ -1336,6 +1336,11 @@ struct GlobalExport {
13361336 GlobalLinkageId linkage;
13371337};
13381338
1339struct FnCall {
1340 AstNode *source_node;
1341 ZigFn *callee;
1342};
1343
13391344struct ZigFn {
13401345 CodeGen *codegen;
13411346 LLVMValueRef llvm_value;
......@@ -1379,8 +1384,10 @@ struct ZigFn {
13791384 AstNode *set_alignstack_node;
13801385
13811386 AstNode *set_cold_node;
1387 const AstNode *inferred_async_node;
13821388
13831389 ZigList<GlobalExport> export_list;
1390 ZigList<FnCall> call_list;
13841391
13851392 LLVMValueRef valgrind_client_request_array;
13861393 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
3131static void preview_use_decl(CodeGen *g, TldUsingNamespace *using_namespace, ScopeDecls *dest_decls_scope);
3232static void resolve_use_decl(CodeGen *g, TldUsingNamespace *tld_using_namespace, ScopeDecls *dest_decls_scope);
3333
34// nullptr means not analyzed yet; this one means currently being analyzed
35static const AstNode *inferred_async_checking = reinterpret_cast<AstNode *>(0x1);
36// this one means analyzed and it's not async
37static const AstNode *inferred_async_none = reinterpret_cast<AstNode *>(0x2);
38
3439static bool is_top_level_struct(ZigType *import) {
3540 return import->id == ZigTypeIdStruct && import->data.structure.root_struct != nullptr;
3641}
......@@ -1892,8 +1897,12 @@ static Error resolve_coro_frame(CodeGen *g, ZigType *frame_type) {
18921897 field_names.append("resume_index");
18931898 field_types.append(g->builtin_types.entry_usize);
18941899
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];
18971906 AstNode *param_decl_node = get_param_decl_node(fn, arg_i);
18981907 Buf *param_name;
18991908 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) {
27962805 g->fn_defs.append(fn_table_entry);
27972806 }
27982807
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
27992818 if (scope_is_root_decls(tld_fn->base.parent_scope) &&
28002819 (import == g->root_import || import->data.structure.root_struct->package == g->panic_package))
28012820 {
......@@ -3767,6 +3786,55 @@ bool resolve_inferred_error_set(CodeGen *g, ZigType *err_set_type, AstNode *sour
37673786 return true;
37683787}
37693788
3789static 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
3798bool 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.
3805static 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
37703838static void analyze_fn_ir(CodeGen *g, ZigFn *fn_table_entry, AstNode *return_type_node) {
37713839 ZigType *fn_type = fn_table_entry->type_entry;
37723840 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
38243892 ir_print(g, stderr, &fn_table_entry->analyzed_executable, 4);
38253893 fprintf(stderr, "}\n");
38263894 }
3827
38283895 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 }
38383896}
38393897
38403898static void analyze_fn_body(CodeGen *g, ZigFn *fn_table_entry) {
......@@ -4004,6 +4062,16 @@ void semantic_analyze(CodeGen *g) {
40044062 analyze_fn_body(g, fn_entry);
40054063 }
40064064 }
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 }
40074075}
40084076
40094077ZigType *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) {
71737241 if (fn->raw_di_type != nullptr) return;
71747242
71757243 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)) {
71817245 resolve_llvm_types_fn_type(g, fn_type);
71827246 fn->raw_type_ref = fn_type->data.fn.raw_type_ref;
71837247 fn->raw_di_type = fn_type->data.fn.raw_di_type;
......@@ -7223,8 +7287,6 @@ static void resolve_llvm_types_anyerror(CodeGen *g) {
72237287}
72247288
72257289static 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
72287290 resolve_llvm_types_struct(g, frame_type->data.frame.locals_struct, wanted_resolve_status);
72297291 frame_type->llvm_type = frame_type->data.frame.locals_struct->llvm_type;
72307292 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);
248248ConstExprValue *analyze_const_value(CodeGen *g, Scope *scope, AstNode *node, ZigType *type_entry, Buf *type_name);
249249
250250void resolve_llvm_types_fn(CodeGen *g, ZigFn *fn);
251bool fn_is_async(ZigFn *fn);
251252
252253#endif
src/codegen.cpp+12-8
......@@ -371,7 +371,7 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) {
371371 symbol_name = buf_sprintf("\x01_%s", buf_ptr(symbol_name));
372372 }
373373
374 bool is_async = fn_table_entry->resume_blocks.length != 0 || cc == CallingConventionAsync;
374 bool is_async = fn_is_async(fn_table_entry);
375375
376376
377377 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_
18471847 }
18481848 case FnWalkIdInits: {
18491849 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)) {
18511851 LLVMValueRef arg = LLVMGetParam(llvm_fn, fn_walk->data.inits.gen_i);
18521852 LLVMTypeRef ptr_to_int_type_ref = LLVMPointerType(LLVMIntType((unsigned)ty_size * 8), 0);
18531853 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) {
19451945 assert(variable);
19461946 assert(variable->value_ref);
19471947
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)) {
19491949 clear_debug_source_node(g);
19501950 ZigType *fn_type = fn_table_entry->type_entry;
19511951 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
19861986}
19871987
19881988static 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)) {
19901990 if (ir_want_runtime_safety(g, &return_instruction->base)) {
19911991 LLVMValueRef locals_ptr = g->cur_ret_ptr;
19921992 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
33873387 LLVMValueRef result;
33883388
33893389 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;
33903391 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, "");
33923394 LLVMBuildStore(g->builder, gen_param_values.at(arg_i), arg_ptr);
33933395 }
33943396 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) {
59835985 assert(executable->basic_block_list.length > 0);
59845986 LLVMValueRef fn_val = fn_llvm_value(g, fn);
59855987 LLVMBasicBlockRef first_bb = nullptr;
5986 if (fn->resume_blocks.length != 0) {
5988 if (fn_is_async(fn)) {
59875989 first_bb = LLVMAppendBasicBlock(fn_val, "AsyncSwitch");
59885990 fn->preamble_llvm_block = first_bb;
59895991 }
......@@ -6171,7 +6173,7 @@ static void do_code_gen(CodeGen *g) {
61716173 build_all_basic_blocks(g, fn_table_entry);
61726174 clear_debug_source_node(g);
61736175
6174 bool is_async = cc == CallingConventionAsync || fn_table_entry->resume_blocks.length != 0;
6176 bool is_async = fn_is_async(fn_table_entry);
61756177
61766178 if (want_sret || is_async) {
61776179 g->cur_ret_ptr = LLVMGetParam(fn, 0);
......@@ -6261,7 +6263,9 @@ static void do_code_gen(CodeGen *g) {
62616263 fn_walk_var.data.vars.var = var;
62626264 iter_function_params_c_abi(g, fn_table_entry->type_entry, &fn_walk_var, var->src_arg_index);
62636265 } 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, "");
62656269 if (var->decl_node) {
62666270 var->di_loc_var = ZigLLVMCreateAutoVariable(g->dbuilder, get_di_scope(g, var->parent_scope),
62676271 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
1538315383 zig_panic("TODO async call");
1538415384 }
1538515385
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
1538615393 IrInstruction *new_call_instruction = ir_build_call_gen(ira, &call_instruction->base,
1538715394 impl_fn, nullptr, impl_param_count, casted_args, fn_inline,
1538815395 call_instruction->is_async, casted_new_stack, result_loc,
......@@ -15458,6 +15465,15 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c
1545815465 return ira->codegen->invalid_instruction;
1545915466 }
1546015467
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
1546115477 if (call_instruction->is_async) {
1546215478 IrInstruction *result = ir_analyze_async_call(ira, call_instruction, fn_entry, fn_type, fn_ref,
1546315479 casted_args, call_param_count);
......@@ -24142,6 +24158,9 @@ static IrInstruction *ir_analyze_instruction_suspend_br(IrAnalyze *ira, IrInstru
2414224158 new_bb->resume_index = fn_entry->resume_blocks.length + 2;
2414324159
2414424160 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 }
2414524164
2414624165 ir_push_resume_block(ira, old_dest_block);
2414724166