| author | |
| committer | |
| log | 03910925f06f6127e81de47ff22ce4d24ca565b2 |
| tree | 280f12a0b8e28667b4120d1fbc0e00861d4fdfdd |
| parent | 8e939916347888e755d737c579042b034e215aa8 |
| signature |
closes #30677 files changed, 169 insertions(+), 68 deletions(-)
src/all_types.hpp+4| ... | @@ -36,6 +36,7 @@ struct IrInstruction; | ... | @@ -36,6 +36,7 @@ struct IrInstruction; |
| 36 | struct IrInstructionCast; | 36 | struct IrInstructionCast; |
| 37 | struct IrInstructionAllocaGen; | 37 | struct IrInstructionAllocaGen; |
| 38 | struct IrInstructionCallGen; | 38 | struct IrInstructionCallGen; |
| 39 | struct IrInstructionAwaitGen; | ||
| 39 | struct IrBasicBlock; | 40 | struct IrBasicBlock; |
| 40 | struct ScopeDecls; | 41 | struct ScopeDecls; |
| 41 | struct ZigWindowsSDK; | 42 | struct 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; | ||
| 1489 | 1491 | ||
| 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 { |
| 1503 | 1505 | ||
| 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; | ||
| 1506 | 1509 | ||
| 1507 | LLVMValueRef valgrind_client_request_array; | 1510 | LLVMValueRef valgrind_client_request_array; |
| 1508 | 1511 | ||
| ... | @@ -3717,6 +3720,7 @@ struct IrInstructionAwaitGen { | ... | @@ -3717,6 +3720,7 @@ struct IrInstructionAwaitGen { |
| 3717 | 3720 | ||
| 3718 | IrInstruction *frame; | 3721 | IrInstruction *frame; |
| 3719 | IrInstruction *result_loc; | 3722 | IrInstruction *result_loc; |
| 3723 | ZigFn *target_fn; | ||
| 3720 | }; | 3724 | }; |
| 3721 | 3725 | ||
| 3722 | struct IrInstructionResume { | 3726 | struct 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); |
| 31 | static void resolve_llvm_types(CodeGen *g, ZigType *type, ResolveStatus wanted_resolve_status); | 31 | static void resolve_llvm_types(CodeGen *g, ZigType *type, ResolveStatus wanted_resolve_status); |
| 32 | static void preview_use_decl(CodeGen *g, TldUsingNamespace *using_namespace, ScopeDecls *dest_decls_scope); | 32 | static void preview_use_decl(CodeGen *g, TldUsingNamespace *using_namespace, ScopeDecls *dest_decls_scope); |
| 33 | static void resolve_use_decl(CodeGen *g, TldUsingNamespace *tld_using_namespace, ScopeDecls *dest_decls_scope); | 33 | static void resolve_use_decl(CodeGen *g, TldUsingNamespace *tld_using_namespace, ScopeDecls *dest_decls_scope); |
| 34 | static void analyze_fn_async(CodeGen *g, ZigFn *fn, bool resolve_frame); | ||
| 34 | 35 | ||
| 35 | // nullptr means not analyzed yet; this one means currently being analyzed | 36 | // nullptr means not analyzed yet; this one means currently being analyzed |
| 36 | static const AstNode *inferred_async_checking = reinterpret_cast<AstNode *>(0x1); | 37 | static 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 | } |
| 4198 | 4199 | ||
| 4200 | // ErrorNone - not async | ||
| 4201 | // ErrorIsAsync - yes async | ||
| 4202 | // ErrorSemanticAnalyzeFail - compile error emitted result is invalid | ||
| 4203 | static 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. |
| 4200 | static void analyze_fn_async(CodeGen *g, ZigFn *fn, bool resolve_frame) { | 4249 | static 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) { |
| 4222 | 4271 | ||
| 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 anything | 4275 | // TODO function pointer call here, could be anything |
| 4228 | continue; | 4276 | continue; |
| 4229 | } | 4277 | } |
| 4230 | 4278 | 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); |
| 3925 | 3925 | ||
| 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); |
| 3930 | 3930 | ||
| ... | @@ -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 | } |
| 5500 | 5503 | ||
| 5504 | static 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 | |||
| 5501 | static LLVMValueRef ir_render_await(CodeGen *g, IrExecutable *executable, IrInstructionAwaitGen *instruction) { | 5542 | static 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); |
| 5507 | 5548 | ||
| 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 suspended | 5557 | // 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. |
| 5514 | 5563 | ||
| 5564 | |||
| 5515 | // supply the awaiter return pointer | 5565 | // 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 and | 5610 | // 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); |
| 5588 | 5616 | ||
| 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 | } |
| 3270 | 3270 | ||
| 3271 | static IrInstruction *ir_build_await_gen(IrAnalyze *ira, IrInstruction *source_instruction, | 3271 | static 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); |
| 3282 | 3282 | ||
| 3283 | return &instruction->base; | 3283 | return instruction; |
| 3284 | } | 3284 | } |
| 3285 | 3285 | ||
| 3286 | static IrInstruction *ir_build_resume(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *frame) { | 3286 | static 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 | } |
| 24764 | 24764 | ||
| 24765 | static IrInstruction *analyze_frame_ptr_to_anyframe_T(IrAnalyze *ira, IrInstruction *source_instr, | 24765 | static 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; |
| 24770 | 24770 | ||
| 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 | } |
| 24804 | 24810 | ||
| 24805 | static IrInstruction *ir_analyze_instruction_await(IrAnalyze *ira, IrInstructionAwaitSrc *instruction) { | 24811 | static 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; |
| 24809 | 24819 | ||
| ... | @@ -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); |
| 24814 | 24824 | ||
| 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 | } |
| 24818 | 24831 | ||
| 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 | } |
| 24832 | 24845 | ||
| 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 | } |
| 24836 | 24851 | ||
| 24837 | static IrInstruction *ir_analyze_instruction_resume(IrAnalyze *ira, IrInstructionResume *instruction) { | 24852 | static 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 | }; |
| 80 | 81 | ||
| 81 | // ABI warning | 82 | // 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 | |||
| 848 | test "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 | } |