mirror of
https://github.com/ziglang/zig.git
synced 2026-02-13 04:48:20 +00:00
simpler, less memory intensive suspend/resume implementation
This commit is contained in:
parent
042914de75
commit
fbf21efd24
@ -1386,7 +1386,6 @@ struct ZigFn {
|
||||
|
||||
ZigList<IrInstructionAllocaGen *> alloca_gen_list;
|
||||
ZigList<ZigVar *> variable_list;
|
||||
ZigList<IrBasicBlock *> 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;
|
||||
|
||||
@ -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.
|
||||
|
||||
74
src/ir.cpp
74
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<IrInstructionSuspendBegin>(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<IrInstructionSuspendBr>(irb, scope, source_node);
|
||||
instruction->resume_block = resume_block;
|
||||
IrInstructionSuspendFinish *instruction = ir_build_instruction<IrInstructionSuspendFinish>(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<IrInstructionSuspendBegin *>(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;
|
||||
|
||||
@ -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);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user