From fbf21efd24bf812e0fd52a5917708a4c45f05b5e Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 4 Aug 2019 18:57:59 -0400 Subject: [PATCH] simpler, less memory intensive suspend/resume implementation --- src/all_types.hpp | 16 ++++------ src/codegen.cpp | 54 ++++++++++++++++------------------ src/ir.cpp | 74 ++++++++++++++++++----------------------------- src/ir_print.cpp | 10 +++---- 4 files changed, 62 insertions(+), 92 deletions(-) diff --git a/src/all_types.hpp b/src/all_types.hpp index 653e6b6254..7c903677a8 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1386,7 +1386,6 @@ struct ZigFn { ZigList alloca_gen_list; ZigList variable_list; - ZigList resume_blocks; Buf *section_name; AstNode *set_alignstack_node; @@ -1719,6 +1718,7 @@ struct CodeGen { LLVMValueRef cur_async_resume_index_ptr; LLVMValueRef cur_async_awaiter_ptr; LLVMBasicBlockRef cur_preamble_llvm_block; + size_t cur_resume_block_count; LLVMValueRef cur_err_ret_trace_val_arg; LLVMValueRef cur_err_ret_trace_val_stack; LLVMValueRef memcpy_fn_val; @@ -2114,7 +2114,6 @@ struct ScopeRuntime { struct ScopeSuspend { Scope base; - IrBasicBlock *resume_block; bool reported_err; }; @@ -2169,8 +2168,6 @@ struct IrBasicBlock { size_t ref_count; // index into the basic block list size_t index; - // for async functions, the resume index which corresponds to this block - size_t resume_index; LLVMBasicBlockRef llvm_block; LLVMBasicBlockRef llvm_exit_block; // The instruction that referenced this basic block and caused us to @@ -2354,7 +2351,7 @@ enum IrInstructionId { IrInstructionIdPtrOfArrayToSlice, IrInstructionIdUnionInitNamedField, IrInstructionIdSuspendBegin, - IrInstructionIdSuspendBr, + IrInstructionIdSuspendFinish, IrInstructionIdAwait, IrInstructionIdCoroResume, }; @@ -3600,13 +3597,13 @@ struct IrInstructionPtrOfArrayToSlice { struct IrInstructionSuspendBegin { IrInstruction base; - IrBasicBlock *resume_block; + LLVMBasicBlockRef resume_bb; }; -struct IrInstructionSuspendBr { +struct IrInstructionSuspendFinish { IrInstruction base; - IrBasicBlock *resume_block; + IrInstructionSuspendBegin *begin; }; struct IrInstructionAwait { @@ -3710,9 +3707,6 @@ static const size_t coro_resume_index = 1; static const size_t coro_awaiter_index = 2; static const size_t coro_arg_start = 3; -// one for the Entry block, resume blocks are indexed after that. -static const size_t coro_extra_resume_block_count = 1; - // TODO call graph analysis to find out what this number needs to be for every function // MUST BE A POWER OF TWO. static const size_t stack_trace_ptr_count = 32; diff --git a/src/codegen.cpp b/src/codegen.cpp index 13b3ab5073..1b9019ad08 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -3661,8 +3661,8 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr ZigType *ptr_result_type = get_pointer_to_type(g, src_return_type, true); LLVMBasicBlockRef call_bb = LLVMAppendBasicBlock(g->cur_fn_val, "CallResume"); - size_t new_block_index = g->cur_fn->resume_blocks.length + coro_extra_resume_block_count; - g->cur_fn->resume_blocks.append(nullptr); + size_t new_block_index = g->cur_resume_block_count; + g->cur_resume_block_count += 1; LLVMValueRef new_block_index_val = LLVMConstInt(usize_type_ref, new_block_index, false); LLVMAddCase(g->cur_async_switch_instr, new_block_index_val, call_bb); @@ -5153,15 +5153,22 @@ static LLVMValueRef ir_render_suspend_begin(CodeGen *g, IrExecutable *executable IrInstructionSuspendBegin *instruction) { LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type; - LLVMValueRef new_resume_index = LLVMConstInt(usize_type_ref, instruction->resume_block->resume_index, false); - LLVMBuildStore(g->builder, new_resume_index, g->cur_async_resume_index_ptr); + instruction->resume_bb = LLVMAppendBasicBlock(g->cur_fn_val, "SuspendResume"); + size_t new_block_index = g->cur_resume_block_count; + g->cur_resume_block_count += 1; + LLVMValueRef new_block_index_val = LLVMConstInt(usize_type_ref, new_block_index, false); + LLVMAddCase(g->cur_async_switch_instr, new_block_index_val, instruction->resume_bb); + LLVMBuildStore(g->builder, new_block_index_val, g->cur_async_resume_index_ptr); return nullptr; } -static LLVMValueRef ir_render_suspend_br(CodeGen *g, IrExecutable *executable, - IrInstructionSuspendBr *instruction) +static LLVMValueRef ir_render_suspend_finish(CodeGen *g, IrExecutable *executable, + IrInstructionSuspendFinish *instruction) { LLVMBuildRetVoid(g->builder); + + LLVMPositionBuilderAtEnd(g->builder, instruction->begin->resume_bb); + render_async_var_decls(g, instruction->base.scope); return nullptr; } @@ -5173,8 +5180,8 @@ static LLVMValueRef ir_render_await(CodeGen *g, IrExecutable *executable, IrInst // Prepare to be suspended LLVMBasicBlockRef resume_bb = LLVMAppendBasicBlock(g->cur_fn_val, "AwaitResume"); - size_t new_block_index = g->cur_fn->resume_blocks.length + coro_extra_resume_block_count; - g->cur_fn->resume_blocks.append(nullptr); + size_t new_block_index = g->cur_resume_block_count; + g->cur_resume_block_count += 1; LLVMValueRef new_block_index_val = LLVMConstInt(usize_type_ref, new_block_index, false); LLVMAddCase(g->cur_async_switch_instr, new_block_index_val, resume_bb); LLVMBuildStore(g->builder, new_block_index_val, g->cur_async_resume_index_ptr); @@ -5534,8 +5541,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, return ir_render_ptr_of_array_to_slice(g, executable, (IrInstructionPtrOfArrayToSlice *)instruction); case IrInstructionIdSuspendBegin: return ir_render_suspend_begin(g, executable, (IrInstructionSuspendBegin *)instruction); - case IrInstructionIdSuspendBr: - return ir_render_suspend_br(g, executable, (IrInstructionSuspendBr *)instruction); + case IrInstructionIdSuspendFinish: + return ir_render_suspend_finish(g, executable, (IrInstructionSuspendFinish *)instruction); case IrInstructionIdCoroResume: return ir_render_coro_resume(g, executable, (IrInstructionCoroResume *)instruction); case IrInstructionIdFrameSizeGen: @@ -5552,19 +5559,10 @@ static void ir_render(CodeGen *g, ZigFn *fn_entry) { IrExecutable *executable = &fn_entry->analyzed_executable; assert(executable->basic_block_list.length > 0); - if (fn_is_async(fn_entry)) { - IrBasicBlock *entry_block = executable->basic_block_list.at(0); - LLVMPositionBuilderAtEnd(g->builder, entry_block->llvm_block); - render_async_var_decls(g, entry_block->instruction_list.at(0)->scope); - } - for (size_t block_i = 0; block_i < executable->basic_block_list.length; block_i += 1) { IrBasicBlock *current_block = executable->basic_block_list.at(block_i); assert(current_block->llvm_block); LLVMPositionBuilderAtEnd(g->builder, current_block->llvm_block); - if (current_block->resume_index != 0) { - render_async_var_decls(g, current_block->instruction_list.at(0)->scope); - } for (size_t instr_i = 0; instr_i < current_block->instruction_list.length; instr_i += 1) { IrInstruction *instruction = current_block->instruction_list.at(instr_i); if (instruction->ref_count == 0 && !ir_has_side_effects(instruction)) @@ -6757,6 +6755,8 @@ static void do_code_gen(CodeGen *g) { } if (is_async) { + g->cur_resume_block_count = 0; + LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type; LLVMValueRef size_val = LLVMConstInt(usize_type_ref, fn_table_entry->frame_type->abi_size, false); ZigLLVMFunctionSetPrefixData(fn_table_entry->llvm_value, size_val); @@ -6777,19 +6777,15 @@ static void do_code_gen(CodeGen *g) { LLVMValueRef resume_index_ptr = LLVMBuildStructGEP(g->builder, g->cur_ret_ptr, coro_resume_index, ""); g->cur_async_resume_index_ptr = resume_index_ptr; LLVMValueRef resume_index = LLVMBuildLoad(g->builder, resume_index_ptr, ""); - LLVMValueRef switch_instr = LLVMBuildSwitch(g->builder, resume_index, bad_resume_block, - fn_table_entry->resume_blocks.length + coro_extra_resume_block_count); + LLVMValueRef switch_instr = LLVMBuildSwitch(g->builder, resume_index, bad_resume_block, 4); g->cur_async_switch_instr = switch_instr; LLVMValueRef zero = LLVMConstNull(usize_type_ref); - LLVMAddCase(switch_instr, zero, executable->basic_block_list.at(0)->llvm_block); - - for (size_t resume_i = 0; resume_i < fn_table_entry->resume_blocks.length; resume_i += 1) { - IrBasicBlock *resume_block = fn_table_entry->resume_blocks.at(resume_i); - LLVMValueRef case_value = LLVMConstInt(usize_type_ref, resume_block->resume_index, false); - LLVMAddCase(switch_instr, case_value, resume_block->llvm_block); - } - + IrBasicBlock *entry_block = executable->basic_block_list.at(0); + LLVMAddCase(switch_instr, zero, entry_block->llvm_block); + g->cur_resume_block_count += 1; + LLVMPositionBuilderAtEnd(g->builder, entry_block->llvm_block); + render_async_var_decls(g, entry_block->instruction_list.at(0)->scope); } else { // create debug variable declarations for parameters // rely on the first variables in the variable_list being parameters. diff --git a/src/ir.cpp b/src/ir.cpp index c81000573c..45a48d6f50 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -1049,8 +1049,8 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionSuspendBegin *) return IrInstructionIdSuspendBegin; } -static constexpr IrInstructionId ir_instruction_id(IrInstructionSuspendBr *) { - return IrInstructionIdSuspendBr; +static constexpr IrInstructionId ir_instruction_id(IrInstructionSuspendFinish *) { + return IrInstructionIdSuspendFinish; } static constexpr IrInstructionId ir_instruction_id(IrInstructionAwait *) { @@ -3260,25 +3260,21 @@ static IrInstruction *ir_build_end_expr(IrBuilder *irb, Scope *scope, AstNode *s return &instruction->base; } -static IrInstruction *ir_build_suspend_begin(IrBuilder *irb, Scope *scope, AstNode *source_node, - IrBasicBlock *resume_block) -{ +static IrInstructionSuspendBegin *ir_build_suspend_begin(IrBuilder *irb, Scope *scope, AstNode *source_node) { IrInstructionSuspendBegin *instruction = ir_build_instruction(irb, scope, source_node); instruction->base.value.type = irb->codegen->builtin_types.entry_void; - instruction->resume_block = resume_block; - ir_ref_bb(resume_block); - - return &instruction->base; + return instruction; } -static IrInstruction *ir_build_suspend_br(IrBuilder *irb, Scope *scope, AstNode *source_node, - IrBasicBlock *resume_block) +static IrInstruction *ir_build_suspend_finish(IrBuilder *irb, Scope *scope, AstNode *source_node, + IrInstructionSuspendBegin *begin) { - IrInstructionSuspendBr *instruction = ir_build_instruction(irb, scope, source_node); - instruction->resume_block = resume_block; + IrInstructionSuspendFinish *instruction = ir_build_instruction(irb, scope, source_node); + instruction->base.value.type = irb->codegen->builtin_types.entry_void; + instruction->begin = begin; - ir_ref_bb(resume_block); + ir_ref_instruction(&begin->base, irb->current_basic_block); return &instruction->base; } @@ -7890,22 +7886,15 @@ static IrInstruction *ir_gen_suspend(IrBuilder *irb, Scope *parent_scope, AstNod return irb->codegen->invalid_instruction; } - IrBasicBlock *resume_block = ir_create_basic_block(irb, parent_scope, "SuspendResume"); - - ir_build_suspend_begin(irb, parent_scope, node, resume_block); + IrInstructionSuspendBegin *begin = ir_build_suspend_begin(irb, parent_scope, node); if (node->data.suspend.block != nullptr) { - Scope *child_scope; ScopeSuspend *suspend_scope = create_suspend_scope(irb->codegen, node, parent_scope); - suspend_scope->resume_block = resume_block; - child_scope = &suspend_scope->base; + Scope *child_scope = &suspend_scope->base; IrInstruction *susp_res = ir_gen_node(irb, node->data.suspend.block, child_scope); ir_mark_gen(ir_build_check_statement_is_void(irb, child_scope, node->data.suspend.block, susp_res)); } - IrInstruction *result = ir_build_suspend_br(irb, parent_scope, node, resume_block); - result->value.type = irb->codegen->builtin_types.entry_void; - ir_set_cursor_at_end_and_append_block(irb, resume_block); - return result; + return ir_build_suspend_finish(irb, parent_scope, node, begin); } static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scope, @@ -24458,35 +24447,28 @@ static IrInstruction *ir_analyze_instruction_union_init_named_field(IrAnalyze *i } static IrInstruction *ir_analyze_instruction_suspend_begin(IrAnalyze *ira, IrInstructionSuspendBegin *instruction) { - IrBasicBlock *new_bb = ir_get_new_bb_runtime(ira, instruction->resume_block, &instruction->base); - if (new_bb == nullptr) - return ir_unreach_error(ira); - return ir_build_suspend_begin(&ira->new_irb, instruction->base.scope, instruction->base.source_node, new_bb); + IrInstructionSuspendBegin *result = ir_build_suspend_begin(&ira->new_irb, instruction->base.scope, + instruction->base.source_node); + return &result->base; } -static IrInstruction *ir_analyze_instruction_suspend_br(IrAnalyze *ira, IrInstructionSuspendBr *instruction) { - IrBasicBlock *old_dest_block = instruction->resume_block; - - IrBasicBlock *new_bb = ir_get_new_bb_runtime(ira, old_dest_block, &instruction->base); - if (new_bb == nullptr) - return ir_unreach_error(ira); +static IrInstruction *ir_analyze_instruction_suspend_finish(IrAnalyze *ira, + IrInstructionSuspendFinish *instruction) +{ + IrInstruction *begin_base = instruction->begin->base.child; + if (type_is_invalid(begin_base->value.type)) + return ira->codegen->invalid_instruction; + ir_assert(begin_base->id == IrInstructionIdSuspendBegin, &instruction->base); + IrInstructionSuspendBegin *begin = reinterpret_cast(begin_base); ZigFn *fn_entry = exec_fn_entry(ira->new_irb.exec); ir_assert(fn_entry != nullptr, &instruction->base); - new_bb->resume_index = fn_entry->resume_blocks.length + coro_extra_resume_block_count; - - fn_entry->resume_blocks.append(new_bb); if (fn_entry->inferred_async_node == nullptr) { fn_entry->inferred_async_node = instruction->base.source_node; } - ir_push_resume_block(ira, old_dest_block); - - IrInstruction *result = ir_build_suspend_br(&ira->new_irb, - instruction->base.scope, instruction->base.source_node, new_bb); - result->value.type = ira->codegen->builtin_types.entry_unreachable; - return ir_finish_anal(ira, result); + return ir_build_suspend_finish(&ira->new_irb, instruction->base.scope, instruction->base.source_node, begin); } static IrInstruction *ir_analyze_instruction_await(IrAnalyze *ira, IrInstructionAwait *instruction) { @@ -24847,8 +24829,8 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction return ir_analyze_instruction_union_init_named_field(ira, (IrInstructionUnionInitNamedField *)instruction); case IrInstructionIdSuspendBegin: return ir_analyze_instruction_suspend_begin(ira, (IrInstructionSuspendBegin *)instruction); - case IrInstructionIdSuspendBr: - return ir_analyze_instruction_suspend_br(ira, (IrInstructionSuspendBr *)instruction); + case IrInstructionIdSuspendFinish: + return ir_analyze_instruction_suspend_finish(ira, (IrInstructionSuspendFinish *)instruction); case IrInstructionIdCoroResume: return ir_analyze_instruction_coro_resume(ira, (IrInstructionCoroResume *)instruction); case IrInstructionIdAwait: @@ -24986,7 +24968,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdVectorToArray: case IrInstructionIdResetResult: case IrInstructionIdSuspendBegin: - case IrInstructionIdSuspendBr: + case IrInstructionIdSuspendFinish: case IrInstructionIdCoroResume: case IrInstructionIdAwait: return true; diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 46d2906d30..549da9de19 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -1534,10 +1534,8 @@ static void ir_print_suspend_begin(IrPrint *irp, IrInstructionSuspendBegin *inst fprintf(irp->f, "@suspendBegin()"); } -static void ir_print_suspend_br(IrPrint *irp, IrInstructionSuspendBr *instruction) { - fprintf(irp->f, "@suspendBr("); - ir_print_other_block(irp, instruction->resume_block); - fprintf(irp->f, ")"); +static void ir_print_suspend_finish(IrPrint *irp, IrInstructionSuspendFinish *instruction) { + fprintf(irp->f, "@suspendFinish()"); } static void ir_print_coro_resume(IrPrint *irp, IrInstructionCoroResume *instruction) { @@ -2025,8 +2023,8 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdSuspendBegin: ir_print_suspend_begin(irp, (IrInstructionSuspendBegin *)instruction); break; - case IrInstructionIdSuspendBr: - ir_print_suspend_br(irp, (IrInstructionSuspendBr *)instruction); + case IrInstructionIdSuspendFinish: + ir_print_suspend_finish(irp, (IrInstructionSuspendFinish *)instruction); break; case IrInstructionIdCoroResume: ir_print_coro_resume(irp, (IrInstructionCoroResume *)instruction);