authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-08-29 21:51:31-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-08-29 21:51:37-04:00
log03910925f06f6127e81de47ff22ce4d24ca565b2
tree280f12a0b8e28667b4120d1fbc0e00861d4fdfdd
parent8e939916347888e755d737c579042b034e215aa8
signaturelock-open Commit is signed but in an unrecognized format.

await does not force async if callee is blocking

closes #3067

7 files changed, 169 insertions(+), 68 deletions(-)

src/all_types.hpp+4
...@@ -36,6 +36,7 @@ struct IrInstruction;...@@ -36,6 +36,7 @@ struct IrInstruction;
36struct IrInstructionCast;36struct IrInstructionCast;
37struct IrInstructionAllocaGen;37struct IrInstructionAllocaGen;
38struct IrInstructionCallGen;38struct IrInstructionCallGen;
39struct IrInstructionAwaitGen;
39struct IrBasicBlock;40struct IrBasicBlock;
40struct ScopeDecls;41struct ScopeDecls;
41struct ZigWindowsSDK;42struct ZigWindowsSDK;
...@@ -1486,6 +1487,7 @@ struct ZigFn {...@@ -1486,6 +1487,7 @@ struct ZigFn {
1486 AstNode **param_source_nodes;1487 AstNode **param_source_nodes;
1487 Buf **param_names;1488 Buf **param_names;
1488 IrInstruction *err_code_spill;1489 IrInstruction *err_code_spill;
1490 AstNode *assumed_non_async;
14891491
1490 AstNode *fn_no_inline_set_node;1492 AstNode *fn_no_inline_set_node;
1491 AstNode *fn_static_eval_set_node;1493 AstNode *fn_static_eval_set_node;
...@@ -1503,6 +1505,7 @@ struct ZigFn {...@@ -1503,6 +1505,7 @@ struct ZigFn {
15031505
1504 ZigList<GlobalExport> export_list;1506 ZigList<GlobalExport> export_list;
1505 ZigList<IrInstructionCallGen *> call_list;1507 ZigList<IrInstructionCallGen *> call_list;
1508 ZigList<IrInstructionAwaitGen *> await_list;
15061509
1507 LLVMValueRef valgrind_client_request_array;1510 LLVMValueRef valgrind_client_request_array;
15081511
...@@ -3717,6 +3720,7 @@ struct IrInstructionAwaitGen {...@@ -3717,6 +3720,7 @@ struct IrInstructionAwaitGen {
37173720
3718 IrInstruction *frame;3721 IrInstruction *frame;
3719 IrInstruction *result_loc;3722 IrInstruction *result_loc;
3723 ZigFn *target_fn;
3720};3724};
37213725
3722struct IrInstructionResume {3726struct IrInstructionResume {
src/analyze.cpp+75-33
...@@ -31,6 +31,7 @@ static void analyze_fn_body(CodeGen *g, ZigFn *fn_table_entry);...@@ -31,6 +31,7 @@ static void analyze_fn_body(CodeGen *g, ZigFn *fn_table_entry);
31static void resolve_llvm_types(CodeGen *g, ZigType *type, ResolveStatus wanted_resolve_status);31static void resolve_llvm_types(CodeGen *g, ZigType *type, ResolveStatus wanted_resolve_status);
32static void preview_use_decl(CodeGen *g, TldUsingNamespace *using_namespace, ScopeDecls *dest_decls_scope);32static void preview_use_decl(CodeGen *g, TldUsingNamespace *using_namespace, ScopeDecls *dest_decls_scope);
33static void resolve_use_decl(CodeGen *g, TldUsingNamespace *tld_using_namespace, ScopeDecls *dest_decls_scope);33static void resolve_use_decl(CodeGen *g, TldUsingNamespace *tld_using_namespace, ScopeDecls *dest_decls_scope);
34static void analyze_fn_async(CodeGen *g, ZigFn *fn, bool resolve_frame);
3435
35// nullptr means not analyzed yet; this one means currently being analyzed36// nullptr means not analyzed yet; this one means currently being analyzed
36static const AstNode *inferred_async_checking = reinterpret_cast<AstNode *>(0x1);37static const AstNode *inferred_async_checking = reinterpret_cast<AstNode *>(0x1);
...@@ -4196,6 +4197,54 @@ static void add_async_error_notes(CodeGen *g, ErrorMsg *msg, ZigFn *fn) {...@@ -4196,6 +4197,54 @@ static void add_async_error_notes(CodeGen *g, ErrorMsg *msg, ZigFn *fn) {
4196 }4197 }
4197}4198}
41984199
4200// ErrorNone - not async
4201// ErrorIsAsync - yes async
4202// ErrorSemanticAnalyzeFail - compile error emitted result is invalid
4203static Error analyze_callee_async(CodeGen *g, ZigFn *fn, ZigFn *callee, AstNode *call_node,
4204 bool must_not_be_async)
4205{
4206 if (callee->type_entry->data.fn.fn_type_id.cc != CallingConventionUnspecified)
4207 return ErrorNone;
4208 if (callee->anal_state == FnAnalStateReady) {
4209 analyze_fn_body(g, callee);
4210 if (callee->anal_state == FnAnalStateInvalid) {
4211 return ErrorSemanticAnalyzeFail;
4212 }
4213 }
4214 bool callee_is_async;
4215 if (callee->anal_state == FnAnalStateComplete) {
4216 analyze_fn_async(g, callee, true);
4217 if (callee->anal_state == FnAnalStateInvalid) {
4218 return ErrorSemanticAnalyzeFail;
4219 }
4220 callee_is_async = fn_is_async(callee);
4221 } else {
4222 // If it's already been determined, use that value. Otherwise
4223 // assume non-async, emit an error later if it turned out to be async.
4224 if (callee->inferred_async_node == nullptr ||
4225 callee->inferred_async_node == inferred_async_checking)
4226 {
4227 callee->assumed_non_async = call_node;
4228 callee_is_async = false;
4229 } else {
4230 callee_is_async = callee->inferred_async_node != inferred_async_none;
4231 }
4232 }
4233 if (callee_is_async) {
4234 fn->inferred_async_node = call_node;
4235 fn->inferred_async_fn = callee;
4236 if (must_not_be_async) {
4237 ErrorMsg *msg = add_node_error(g, fn->proto_node,
4238 buf_sprintf("function with calling convention '%s' cannot be async",
4239 calling_convention_name(fn->type_entry->data.fn.fn_type_id.cc)));
4240 add_async_error_notes(g, msg, fn);
4241 return ErrorSemanticAnalyzeFail;
4242 }
4243 return ErrorIsAsync;
4244 }
4245 return ErrorNone;
4246}
4247
4199// This function resolves functions being inferred async.4248// This function resolves functions being inferred async.
4200static void analyze_fn_async(CodeGen *g, ZigFn *fn, bool resolve_frame) {4249static void analyze_fn_async(CodeGen *g, ZigFn *fn, bool resolve_frame) {
4201 if (fn->inferred_async_node == inferred_async_checking) {4250 if (fn->inferred_async_node == inferred_async_checking) {
...@@ -4222,47 +4271,40 @@ static void analyze_fn_async(CodeGen *g, ZigFn *fn, bool resolve_frame) {...@@ -4222,47 +4271,40 @@ static void analyze_fn_async(CodeGen *g, ZigFn *fn, bool resolve_frame) {
42224271
4223 for (size_t i = 0; i < fn->call_list.length; i += 1) {4272 for (size_t i = 0; i < fn->call_list.length; i += 1) {
4224 IrInstructionCallGen *call = fn->call_list.at(i);4273 IrInstructionCallGen *call = fn->call_list.at(i);
4225 ZigFn *callee = call->fn_entry;4274 if (call->fn_entry == nullptr) {
4226 if (callee == nullptr) {
4227 // TODO function pointer call here, could be anything4275 // TODO function pointer call here, could be anything
4228 continue;4276 continue;
4229 }4277 }
42304278 switch (analyze_callee_async(g, fn, call->fn_entry, call->base.source_node, must_not_be_async)) {
4231 if (callee->type_entry->data.fn.fn_type_id.cc != CallingConventionUnspecified)4279 case ErrorSemanticAnalyzeFail:
4232 continue;
4233 if (callee->anal_state == FnAnalStateReady) {
4234 analyze_fn_body(g, callee);
4235 if (callee->anal_state == FnAnalStateInvalid) {
4236 fn->anal_state = FnAnalStateInvalid;4280 fn->anal_state = FnAnalStateInvalid;
4237 return;4281 return;
4238 }4282 case ErrorNone:
4239 }4283 continue;
4240 if (callee->anal_state != FnAnalStateComplete) {4284 case ErrorIsAsync:
4241 add_node_error(g, call->base.source_node,4285 if (resolve_frame) {
4242 buf_sprintf("call to function '%s' depends on itself", buf_ptr(&callee->symbol_name)));4286 resolve_async_fn_frame(g, fn);
4243 fn->anal_state = FnAnalStateInvalid;4287 }
4244 return;4288 return;
4245 }4289 default:
4246 analyze_fn_async(g, callee, true);4290 zig_unreachable();
4247 if (callee->anal_state == FnAnalStateInvalid) {
4248 fn->anal_state = FnAnalStateInvalid;
4249 return;
4250 }4291 }
4251 if (fn_is_async(callee)) {4292 }
4252 fn->inferred_async_node = call->base.source_node;4293 for (size_t i = 0; i < fn->await_list.length; i += 1) {
4253 fn->inferred_async_fn = callee;4294 IrInstructionAwaitGen *await = fn->await_list.at(i);
4254 if (must_not_be_async) {4295 switch (analyze_callee_async(g, fn, await->target_fn, await->base.source_node, must_not_be_async)) {
4255 ErrorMsg *msg = add_node_error(g, fn->proto_node,4296 case ErrorSemanticAnalyzeFail:
4256 buf_sprintf("function with calling convention '%s' cannot be async",
4257 calling_convention_name(fn->type_entry->data.fn.fn_type_id.cc)));
4258 add_async_error_notes(g, msg, fn);
4259 fn->anal_state = FnAnalStateInvalid;4297 fn->anal_state = FnAnalStateInvalid;
4260 return;4298 return;
4261 }4299 case ErrorNone:
4262 if (resolve_frame) {4300 continue;
4263 resolve_async_fn_frame(g, fn);4301 case ErrorIsAsync:
4264 }4302 if (resolve_frame) {
4265 return;4303 resolve_async_fn_frame(g, fn);
4304 }
4305 return;
4306 default:
4307 zig_unreachable();
4266 }4308 }
4267 }4309 }
4268 fn->inferred_async_node = inferred_async_none;4310 fn->inferred_async_node = inferred_async_none;
src/codegen.cpp+53-25
...@@ -3924,7 +3924,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr...@@ -3924,7 +3924,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
3924 LLVMBuildStore(g->builder, awaiter_init_val, awaiter_ptr);3924 LLVMBuildStore(g->builder, awaiter_init_val, awaiter_ptr);
39253925
3926 if (ret_has_bits) {3926 if (ret_has_bits) {
3927 LLVMValueRef ret_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, frame_ret_start + 2, "");3927 ret_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, frame_ret_start + 2, "");
3928 LLVMValueRef ret_ptr_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, frame_ret_start, "");3928 LLVMValueRef ret_ptr_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, frame_ret_start, "");
3929 LLVMBuildStore(g->builder, ret_ptr, ret_ptr_ptr);3929 LLVMBuildStore(g->builder, ret_ptr, ret_ptr_ptr);
39303930
...@@ -4067,6 +4067,9 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr...@@ -4067,6 +4067,9 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
4067 LLVMValueRef store_instr = LLVMBuildStore(g->builder, result, result_loc);4067 LLVMValueRef store_instr = LLVMBuildStore(g->builder, result, result_loc);
4068 LLVMSetAlignment(store_instr, get_ptr_align(g, instruction->result_loc->value.type));4068 LLVMSetAlignment(store_instr, get_ptr_align(g, instruction->result_loc->value.type));
4069 return result_loc;4069 return result_loc;
4070 } else if (!callee_is_async && instruction->is_async) {
4071 LLVMBuildStore(g->builder, result, ret_ptr);
4072 return result_loc;
4070 } else {4073 } else {
4071 return result;4074 return result;
4072 }4075 }
...@@ -5498,6 +5501,44 @@ static LLVMValueRef ir_render_suspend_finish(CodeGen *g, IrExecutable *executabl...@@ -5498,6 +5501,44 @@ static LLVMValueRef ir_render_suspend_finish(CodeGen *g, IrExecutable *executabl
5498 return nullptr;5501 return nullptr;
5499}5502}
55005503
5504static LLVMValueRef gen_await_early_return(CodeGen *g, IrInstruction *source_instr,
5505 LLVMValueRef target_frame_ptr, ZigType *result_type, ZigType *ptr_result_type,
5506 LLVMValueRef result_loc, bool non_async)
5507{
5508 LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type;
5509 LLVMValueRef their_result_ptr = nullptr;
5510 if (type_has_bits(result_type) && (non_async || result_loc != nullptr)) {
5511 LLVMValueRef their_result_ptr_ptr = LLVMBuildStructGEP(g->builder, target_frame_ptr, frame_ret_start, "");
5512 their_result_ptr = LLVMBuildLoad(g->builder, their_result_ptr_ptr, "");
5513 if (result_loc != nullptr) {
5514 LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0);
5515 LLVMValueRef dest_ptr_casted = LLVMBuildBitCast(g->builder, result_loc, ptr_u8, "");
5516 LLVMValueRef src_ptr_casted = LLVMBuildBitCast(g->builder, their_result_ptr, ptr_u8, "");
5517 bool is_volatile = false;
5518 uint32_t abi_align = get_abi_alignment(g, result_type);
5519 LLVMValueRef byte_count_val = LLVMConstInt(usize_type_ref, type_size(g, result_type), false);
5520 ZigLLVMBuildMemCpy(g->builder,
5521 dest_ptr_casted, abi_align,
5522 src_ptr_casted, abi_align, byte_count_val, is_volatile);
5523 }
5524 }
5525 if (codegen_fn_has_err_ret_tracing_arg(g, result_type)) {
5526 LLVMValueRef their_trace_ptr_ptr = LLVMBuildStructGEP(g->builder, target_frame_ptr,
5527 frame_index_trace_arg(g, result_type), "");
5528 LLVMValueRef src_trace_ptr = LLVMBuildLoad(g->builder, their_trace_ptr_ptr, "");
5529 LLVMValueRef dest_trace_ptr = get_cur_err_ret_trace_val(g, source_instr->scope);
5530 LLVMValueRef args[] = { dest_trace_ptr, src_trace_ptr };
5531 ZigLLVMBuildCall(g->builder, get_merge_err_ret_traces_fn_val(g), args, 2,
5532 get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, "");
5533 }
5534 if (non_async && type_has_bits(result_type)) {
5535 LLVMValueRef result_ptr = (result_loc == nullptr) ? their_result_ptr : result_loc;
5536 return get_handle_value(g, result_ptr, result_type, ptr_result_type);
5537 } else {
5538 return nullptr;
5539 }
5540}
5541
5501static LLVMValueRef ir_render_await(CodeGen *g, IrExecutable *executable, IrInstructionAwaitGen *instruction) {5542static LLVMValueRef ir_render_await(CodeGen *g, IrExecutable *executable, IrInstructionAwaitGen *instruction) {
5502 LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type;5543 LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type;
5503 LLVMValueRef zero = LLVMConstNull(usize_type_ref);5544 LLVMValueRef zero = LLVMConstNull(usize_type_ref);
...@@ -5505,6 +5546,14 @@ static LLVMValueRef ir_render_await(CodeGen *g, IrExecutable *executable, IrInst...@@ -5505,6 +5546,14 @@ static LLVMValueRef ir_render_await(CodeGen *g, IrExecutable *executable, IrInst
5505 ZigType *result_type = instruction->base.value.type;5546 ZigType *result_type = instruction->base.value.type;
5506 ZigType *ptr_result_type = get_pointer_to_type(g, result_type, true);5547 ZigType *ptr_result_type = get_pointer_to_type(g, result_type, true);
55075548
5549 LLVMValueRef result_loc = (instruction->result_loc == nullptr) ?
5550 nullptr : ir_llvm_value(g, instruction->result_loc);
5551
5552 if (instruction->target_fn != nullptr && !fn_is_async(instruction->target_fn)) {
5553 return gen_await_early_return(g, &instruction->base, target_frame_ptr, result_type,
5554 ptr_result_type, result_loc, true);
5555 }
5556
5508 // Prepare to be suspended5557 // Prepare to be suspended
5509 LLVMBasicBlockRef resume_bb = gen_suspend_begin(g, "AwaitResume");5558 LLVMBasicBlockRef resume_bb = gen_suspend_begin(g, "AwaitResume");
5510 LLVMBasicBlockRef end_bb = LLVMAppendBasicBlock(g->cur_fn_val, "AwaitEnd");5559 LLVMBasicBlockRef end_bb = LLVMAppendBasicBlock(g->cur_fn_val, "AwaitEnd");
...@@ -5512,9 +5561,8 @@ static LLVMValueRef ir_render_await(CodeGen *g, IrExecutable *executable, IrInst...@@ -5512,9 +5561,8 @@ static LLVMValueRef ir_render_await(CodeGen *g, IrExecutable *executable, IrInst
5512 // At this point resuming the function will continue from resume_bb.5561 // At this point resuming the function will continue from resume_bb.
5513 // This code is as if it is running inside the suspend block.5562 // This code is as if it is running inside the suspend block.
55145563
5564
5515 // supply the awaiter return pointer5565 // supply the awaiter return pointer
5516 LLVMValueRef result_loc = (instruction->result_loc == nullptr) ?
5517 nullptr : ir_llvm_value(g, instruction->result_loc);
5518 if (type_has_bits(result_type)) {5566 if (type_has_bits(result_type)) {
5519 LLVMValueRef awaiter_ret_ptr_ptr = LLVMBuildStructGEP(g->builder, target_frame_ptr, frame_ret_start + 1, "");5567 LLVMValueRef awaiter_ret_ptr_ptr = LLVMBuildStructGEP(g->builder, target_frame_ptr, frame_ret_start + 1, "");
5520 if (result_loc == nullptr) {5568 if (result_loc == nullptr) {
...@@ -5562,28 +5610,8 @@ static LLVMValueRef ir_render_await(CodeGen *g, IrExecutable *executable, IrInst...@@ -5562,28 +5610,8 @@ static LLVMValueRef ir_render_await(CodeGen *g, IrExecutable *executable, IrInst
5562 // Early return: The async function has already completed. We must copy the result and5610 // Early return: The async function has already completed. We must copy the result and
5563 // the error return trace if applicable.5611 // the error return trace if applicable.
5564 LLVMPositionBuilderAtEnd(g->builder, early_return_block);5612 LLVMPositionBuilderAtEnd(g->builder, early_return_block);
5565 if (type_has_bits(result_type) && result_loc != nullptr) {5613 gen_await_early_return(g, &instruction->base, target_frame_ptr, result_type, ptr_result_type,
5566 LLVMValueRef their_result_ptr_ptr = LLVMBuildStructGEP(g->builder, target_frame_ptr, frame_ret_start, "");5614 result_loc, false);
5567 LLVMValueRef their_result_ptr = LLVMBuildLoad(g->builder, their_result_ptr_ptr, "");
5568 LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0);
5569 LLVMValueRef dest_ptr_casted = LLVMBuildBitCast(g->builder, result_loc, ptr_u8, "");
5570 LLVMValueRef src_ptr_casted = LLVMBuildBitCast(g->builder, their_result_ptr, ptr_u8, "");
5571 bool is_volatile = false;
5572 uint32_t abi_align = get_abi_alignment(g, result_type);
5573 LLVMValueRef byte_count_val = LLVMConstInt(usize_type_ref, type_size(g, result_type), false);
5574 ZigLLVMBuildMemCpy(g->builder,
5575 dest_ptr_casted, abi_align,
5576 src_ptr_casted, abi_align, byte_count_val, is_volatile);
5577 }
5578 if (codegen_fn_has_err_ret_tracing_arg(g, result_type)) {
5579 LLVMValueRef their_trace_ptr_ptr = LLVMBuildStructGEP(g->builder, target_frame_ptr,
5580 frame_index_trace_arg(g, result_type), "");
5581 LLVMValueRef src_trace_ptr = LLVMBuildLoad(g->builder, their_trace_ptr_ptr, "");
5582 LLVMValueRef dest_trace_ptr = get_cur_err_ret_trace_val(g, instruction->base.scope);
5583 LLVMValueRef args[] = { dest_trace_ptr, src_trace_ptr };
5584 ZigLLVMBuildCall(g->builder, get_merge_err_ret_traces_fn_val(g), args, 2,
5585 get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, "");
5586 }
5587 LLVMBuildBr(g->builder, end_bb);5615 LLVMBuildBr(g->builder, end_bb);
55885616
5589 LLVMPositionBuilderAtEnd(g->builder, resume_bb);5617 LLVMPositionBuilderAtEnd(g->builder, resume_bb);
src/error.cpp+1
...@@ -56,6 +56,7 @@ const char *err_str(Error err) {...@@ -56,6 +56,7 @@ const char *err_str(Error err) {
56 case ErrorNoSpaceLeft: return "no space left";56 case ErrorNoSpaceLeft: return "no space left";
57 case ErrorNoCCompilerInstalled: return "no C compiler installed";57 case ErrorNoCCompilerInstalled: return "no C compiler installed";
58 case ErrorNotLazy: return "not lazy";58 case ErrorNotLazy: return "not lazy";
59 case ErrorIsAsync: return "is async";
59 }60 }
60 return "(invalid error)";61 return "(invalid error)";
61}62}
src/ir.cpp+25-10
...@@ -3268,7 +3268,7 @@ static IrInstruction *ir_build_await_src(IrBuilder *irb, Scope *scope, AstNode *...@@ -3268,7 +3268,7 @@ static IrInstruction *ir_build_await_src(IrBuilder *irb, Scope *scope, AstNode *
3268 return &instruction->base;3268 return &instruction->base;
3269}3269}
32703270
3271static IrInstruction *ir_build_await_gen(IrAnalyze *ira, IrInstruction *source_instruction,3271static IrInstructionAwaitGen *ir_build_await_gen(IrAnalyze *ira, IrInstruction *source_instruction,
3272 IrInstruction *frame, ZigType *result_type, IrInstruction *result_loc)3272 IrInstruction *frame, ZigType *result_type, IrInstruction *result_loc)
3273{3273{
3274 IrInstructionAwaitGen *instruction = ir_build_instruction<IrInstructionAwaitGen>(&ira->new_irb,3274 IrInstructionAwaitGen *instruction = ir_build_instruction<IrInstructionAwaitGen>(&ira->new_irb,
...@@ -3280,7 +3280,7 @@ static IrInstruction *ir_build_await_gen(IrAnalyze *ira, IrInstruction *source_i...@@ -3280,7 +3280,7 @@ static IrInstruction *ir_build_await_gen(IrAnalyze *ira, IrInstruction *source_i
3280 ir_ref_instruction(frame, ira->new_irb.current_basic_block);3280 ir_ref_instruction(frame, ira->new_irb.current_basic_block);
3281 if (result_loc != nullptr) ir_ref_instruction(result_loc, ira->new_irb.current_basic_block);3281 if (result_loc != nullptr) ir_ref_instruction(result_loc, ira->new_irb.current_basic_block);
32823282
3283 return &instruction->base;3283 return instruction;
3284}3284}
32853285
3286static IrInstruction *ir_build_resume(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *frame) {3286static IrInstruction *ir_build_resume(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *frame) {
...@@ -24763,18 +24763,22 @@ static IrInstruction *ir_analyze_instruction_suspend_finish(IrAnalyze *ira,...@@ -24763,18 +24763,22 @@ static IrInstruction *ir_analyze_instruction_suspend_finish(IrAnalyze *ira,
24763}24763}
2476424764
24765static IrInstruction *analyze_frame_ptr_to_anyframe_T(IrAnalyze *ira, IrInstruction *source_instr,24765static IrInstruction *analyze_frame_ptr_to_anyframe_T(IrAnalyze *ira, IrInstruction *source_instr,
24766 IrInstruction *frame_ptr)24766 IrInstruction *frame_ptr, ZigFn **target_fn)
24767{24767{
24768 if (type_is_invalid(frame_ptr->value.type))24768 if (type_is_invalid(frame_ptr->value.type))
24769 return ira->codegen->invalid_instruction;24769 return ira->codegen->invalid_instruction;
2477024770
24771 *target_fn = nullptr;
24772
24771 ZigType *result_type;24773 ZigType *result_type;
24772 IrInstruction *frame;24774 IrInstruction *frame;
24773 if (frame_ptr->value.type->id == ZigTypeIdPointer &&24775 if (frame_ptr->value.type->id == ZigTypeIdPointer &&
24774 frame_ptr->value.type->data.pointer.ptr_len == PtrLenSingle &&24776 frame_ptr->value.type->data.pointer.ptr_len == PtrLenSingle &&
24775 frame_ptr->value.type->data.pointer.child_type->id == ZigTypeIdFnFrame)24777 frame_ptr->value.type->data.pointer.child_type->id == ZigTypeIdFnFrame)
24776 {24778 {
24777 result_type = frame_ptr->value.type->data.pointer.child_type->data.frame.fn->type_entry->data.fn.fn_type_id.return_type;24779 ZigFn *func = frame_ptr->value.type->data.pointer.child_type->data.frame.fn;
24780 result_type = func->type_entry->data.fn.fn_type_id.return_type;
24781 *target_fn = func;
24778 frame = frame_ptr;24782 frame = frame_ptr;
24779 } else {24783 } else {
24780 frame = ir_get_deref(ira, source_instr, frame_ptr, nullptr);24784 frame = ir_get_deref(ira, source_instr, frame_ptr, nullptr);
...@@ -24782,7 +24786,9 @@ static IrInstruction *analyze_frame_ptr_to_anyframe_T(IrAnalyze *ira, IrInstruct...@@ -24782,7 +24786,9 @@ static IrInstruction *analyze_frame_ptr_to_anyframe_T(IrAnalyze *ira, IrInstruct
24782 frame->value.type->data.pointer.ptr_len == PtrLenSingle &&24786 frame->value.type->data.pointer.ptr_len == PtrLenSingle &&
24783 frame->value.type->data.pointer.child_type->id == ZigTypeIdFnFrame)24787 frame->value.type->data.pointer.child_type->id == ZigTypeIdFnFrame)
24784 {24788 {
24785 result_type = frame->value.type->data.pointer.child_type->data.frame.fn->type_entry->data.fn.fn_type_id.return_type;24789 ZigFn *func = frame->value.type->data.pointer.child_type->data.frame.fn;
24790 result_type = func->type_entry->data.fn.fn_type_id.return_type;
24791 *target_fn = func;
24786 } else if (frame->value.type->id != ZigTypeIdAnyFrame ||24792 } else if (frame->value.type->id != ZigTypeIdAnyFrame ||
24787 frame->value.type->data.any_frame.result_type == nullptr)24793 frame->value.type->data.any_frame.result_type == nullptr)
24788 {24794 {
...@@ -24803,7 +24809,11 @@ static IrInstruction *analyze_frame_ptr_to_anyframe_T(IrAnalyze *ira, IrInstruct...@@ -24803,7 +24809,11 @@ static IrInstruction *analyze_frame_ptr_to_anyframe_T(IrAnalyze *ira, IrInstruct
24803}24809}
2480424810
24805static IrInstruction *ir_analyze_instruction_await(IrAnalyze *ira, IrInstructionAwaitSrc *instruction) {24811static IrInstruction *ir_analyze_instruction_await(IrAnalyze *ira, IrInstructionAwaitSrc *instruction) {
24806 IrInstruction *frame = analyze_frame_ptr_to_anyframe_T(ira, &instruction->base, instruction->frame->child);24812 IrInstruction *operand = instruction->frame->child;
24813 if (type_is_invalid(operand->value.type))
24814 return ira->codegen->invalid_instruction;
24815 ZigFn *target_fn;
24816 IrInstruction *frame = analyze_frame_ptr_to_anyframe_T(ira, &instruction->base, operand, &target_fn);
24807 if (type_is_invalid(frame->value.type))24817 if (type_is_invalid(frame->value.type))
24808 return ira->codegen->invalid_instruction;24818 return ira->codegen->invalid_instruction;
2480924819
...@@ -24812,8 +24822,11 @@ static IrInstruction *ir_analyze_instruction_await(IrAnalyze *ira, IrInstruction...@@ -24812,8 +24822,11 @@ static IrInstruction *ir_analyze_instruction_await(IrAnalyze *ira, IrInstruction
24812 ZigFn *fn_entry = exec_fn_entry(ira->new_irb.exec);24822 ZigFn *fn_entry = exec_fn_entry(ira->new_irb.exec);
24813 ir_assert(fn_entry != nullptr, &instruction->base);24823 ir_assert(fn_entry != nullptr, &instruction->base);
2481424824
24815 if (fn_entry->inferred_async_node == nullptr) {24825 // If it's not @Frame(func) then it's definitely a suspend point
24816 fn_entry->inferred_async_node = instruction->base.source_node;24826 if (target_fn == nullptr) {
24827 if (fn_entry->inferred_async_node == nullptr) {
24828 fn_entry->inferred_async_node = instruction->base.source_node;
24829 }
24817 }24830 }
2481824831
24819 if (type_can_fail(result_type)) {24832 if (type_can_fail(result_type)) {
...@@ -24830,8 +24843,10 @@ static IrInstruction *ir_analyze_instruction_await(IrAnalyze *ira, IrInstruction...@@ -24830,8 +24843,10 @@ static IrInstruction *ir_analyze_instruction_await(IrAnalyze *ira, IrInstruction
24830 result_loc = nullptr;24843 result_loc = nullptr;
24831 }24844 }
2483224845
24833 IrInstruction *result = ir_build_await_gen(ira, &instruction->base, frame, result_type, result_loc);24846 IrInstructionAwaitGen *result = ir_build_await_gen(ira, &instruction->base, frame, result_type, result_loc);
24834 return ir_finish_anal(ira, result);24847 result->target_fn = target_fn;
24848 fn_entry->await_list.append(result);
24849 return ir_finish_anal(ira, &result->base);
24835}24850}
2483624851
24837static IrInstruction *ir_analyze_instruction_resume(IrAnalyze *ira, IrInstructionResume *instruction) {24852static IrInstruction *ir_analyze_instruction_resume(IrAnalyze *ira, IrInstructionResume *instruction) {
src/userland.h+1
...@@ -76,6 +76,7 @@ enum Error {...@@ -76,6 +76,7 @@ enum Error {
76 ErrorBrokenPipe,76 ErrorBrokenPipe,
77 ErrorNoSpaceLeft,77 ErrorNoSpaceLeft,
78 ErrorNotLazy,78 ErrorNotLazy,
79 ErrorIsAsync,
79};80};
8081
81// ABI warning82// ABI warning
test/stage1/behavior/async_fn.zig+10
...@@ -844,3 +844,13 @@ test "cast fn to async fn when it is inferred to be async" {...@@ -844,3 +844,13 @@ test "cast fn to async fn when it is inferred to be async" {
844 resume S.frame;844 resume S.frame;
845 expect(S.ok);845 expect(S.ok);
846}846}
847
848test "await does not force async if callee is blocking" {
849 const S = struct {
850 fn simple() i32 {
851 return 1234;
852 }
853 };
854 var x = async S.simple();
855 expect(await x == 1234);
856}