diff options
| -rw-r--r-- | src/all_types.hpp | 9 | ||||
| -rw-r--r-- | src/analyze.cpp | 10 | ||||
| -rw-r--r-- | src/analyze.hpp | 1 | ||||
| -rw-r--r-- | src/codegen.cpp | 155 | ||||
| -rw-r--r-- | src/ir.cpp | 87 | ||||
| -rw-r--r-- | src/ir_print.cpp | 11 |
6 files changed, 222 insertions, 51 deletions
diff --git a/src/all_types.hpp b/src/all_types.hpp index 5073ffaceb..9b4fa6d36c 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1634,6 +1634,7 @@ struct CodeGen { LLVMValueRef coro_free_fn_val; LLVMValueRef coro_resume_fn_val; LLVMValueRef coro_save_fn_val; + LLVMValueRef coro_alloc_helper_fn_val; bool error_during_imports; const char **clang_argv; @@ -2004,6 +2005,7 @@ enum IrInstructionId { IrInstructionIdCoroFree, IrInstructionIdCoroResume, IrInstructionIdCoroSave, + IrInstructionIdCoroAllocHelper, }; struct IrInstruction { @@ -2913,6 +2915,13 @@ struct IrInstructionCoroSave { IrInstruction *coro_handle; }; +struct IrInstructionCoroAllocHelper { + IrInstruction base; + + IrInstruction *alloc_fn; + IrInstruction *coro_size; +}; + static const size_t slice_ptr_index = 0; static const size_t slice_len_index = 1; diff --git a/src/analyze.cpp b/src/analyze.cpp index ce9e99f8fa..be01f6b5f8 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -1001,9 +1001,7 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) { bool first_arg_return = calling_convention_does_first_arg_return(fn_type_id->cc) && handle_is_ptr(fn_type_id->return_type); bool is_async = fn_type_id->cc == CallingConventionAsync; - bool prefix_arg_error_return_trace = g->have_err_ret_tracing && - (fn_type_id->return_type->id == TypeTableEntryIdErrorUnion || - fn_type_id->return_type->id == TypeTableEntryIdErrorSet); + bool prefix_arg_error_return_trace = g->have_err_ret_tracing && fn_type_can_fail(fn_type_id); // +1 for maybe making the first argument the return value // +1 for maybe first argument the error return trace // +2 for maybe arguments async allocator and error code pointer @@ -5795,3 +5793,9 @@ bool type_is_global_error_set(TypeTableEntry *err_set_type) { uint32_t get_coro_frame_align_bytes(CodeGen *g) { return g->pointer_size_bytes * 2; } + +bool fn_type_can_fail(FnTypeId *fn_type_id) { + TypeTableEntry *return_type = fn_type_id->return_type; + return return_type->id == TypeTableEntryIdErrorUnion || return_type->id == TypeTableEntryIdErrorSet || + fn_type_id->cc == CallingConventionAsync; +} diff --git a/src/analyze.hpp b/src/analyze.hpp index 926793c58a..068f321bfb 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -192,5 +192,6 @@ void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry); TypeTableEntry *get_auto_err_set_type(CodeGen *g, FnTableEntry *fn_entry); uint32_t get_coro_frame_align_bytes(CodeGen *g); +bool fn_type_can_fail(FnTypeId *fn_type_id); #endif diff --git a/src/codegen.cpp b/src/codegen.cpp index d650daa6cb..ec047ad9ec 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -412,10 +412,10 @@ static uint32_t get_err_ret_trace_arg_index(CodeGen *g, FnTableEntry *fn_table_e return UINT32_MAX; } TypeTableEntry *fn_type = fn_table_entry->type_entry; - TypeTableEntry *return_type = fn_type->data.fn.fn_type_id.return_type; - if (return_type->id != TypeTableEntryIdErrorUnion && return_type->id != TypeTableEntryIdErrorSet) { + if (!fn_type_can_fail(&fn_type->data.fn.fn_type_id)) { return UINT32_MAX; } + TypeTableEntry *return_type = fn_type->data.fn.fn_type_id.return_type; bool first_arg_ret = type_has_bits(return_type) && handle_is_ptr(return_type); return first_arg_ret ? 1 : 0; } @@ -2662,21 +2662,23 @@ static LLVMValueRef ir_render_elem_ptr(CodeGen *g, IrExecutable *executable, IrI } } -static bool get_prefix_arg_err_ret_stack(CodeGen *g, TypeTableEntry *src_return_type) { +static bool get_prefix_arg_err_ret_stack(CodeGen *g, FnTypeId *fn_type_id) { return g->have_err_ret_tracing && - (src_return_type->id == TypeTableEntryIdErrorUnion || src_return_type->id == TypeTableEntryIdErrorSet); + (fn_type_id->return_type->id == TypeTableEntryIdErrorUnion || + fn_type_id->return_type->id == TypeTableEntryIdErrorSet || + fn_type_id->cc == CallingConventionAsync); } -static size_t get_async_allocator_arg_index(CodeGen *g, TypeTableEntry *src_return_type) { +static size_t get_async_allocator_arg_index(CodeGen *g, FnTypeId *fn_type_id) { // 0 1 2 3 // err_ret_stack allocator_ptr err_code other_args... - return get_prefix_arg_err_ret_stack(g, src_return_type) ? 1 : 0; + return get_prefix_arg_err_ret_stack(g, fn_type_id) ? 1 : 0; } -static size_t get_async_err_code_arg_index(CodeGen *g, TypeTableEntry *src_return_type) { +static size_t get_async_err_code_arg_index(CodeGen *g, FnTypeId *fn_type_id) { // 0 1 2 3 // err_ret_stack allocator_ptr err_code other_args... - return 1 + get_async_allocator_arg_index(g, src_return_type); + return 1 + get_async_allocator_arg_index(g, fn_type_id); } static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstructionCall *instruction) { @@ -2698,7 +2700,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr bool first_arg_ret = ret_has_bits && handle_is_ptr(src_return_type) && calling_convention_does_first_arg_return(fn_type->data.fn.fn_type_id.cc); - bool prefix_arg_err_ret_stack = get_prefix_arg_err_ret_stack(g, src_return_type); + bool prefix_arg_err_ret_stack = get_prefix_arg_err_ret_stack(g, fn_type_id); // +2 for the async args size_t actual_param_count = instruction->arg_count + (first_arg_ret ? 1 : 0) + (prefix_arg_err_ret_stack ? 1 : 0) + 2; bool is_var_args = fn_type_id->is_var_args; @@ -2717,7 +2719,6 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr gen_param_index += 1; LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, err_union_err_index, ""); - LLVMBuildStore(g->builder, LLVMConstNull(g->builtin_types.entry_global_error_set->type_ref), err_val_ptr); gen_param_values[gen_param_index] = err_val_ptr; gen_param_index += 1; } @@ -3293,8 +3294,7 @@ static LLVMValueRef ir_render_cancel(CodeGen *g, IrExecutable *executable, IrIns static LLVMValueRef ir_render_get_implicit_allocator(CodeGen *g, IrExecutable *executable, IrInstructionGetImplicitAllocator *instruction) { - TypeTableEntry *src_return_type = g->cur_fn->type_entry->data.fn.fn_type_id.return_type; - size_t allocator_arg_index = get_async_allocator_arg_index(g, src_return_type); + size_t allocator_arg_index = get_async_allocator_arg_index(g, &g->cur_fn->type_entry->data.fn.fn_type_id); return LLVMGetParam(g->cur_fn_val, allocator_arg_index); } @@ -3926,8 +3926,7 @@ static LLVMValueRef ir_render_coro_begin(CodeGen *g, IrExecutable *executable, I static LLVMValueRef ir_render_coro_alloc_fail(CodeGen *g, IrExecutable *executable, IrInstructionCoroAllocFail *instruction) { - TypeTableEntry *src_return_type = g->cur_fn->type_entry->data.fn.fn_type_id.return_type; - size_t err_code_ptr_arg_index = get_async_err_code_arg_index(g, src_return_type); + size_t err_code_ptr_arg_index = get_async_err_code_arg_index(g, &g->cur_fn->type_entry->data.fn.fn_type_id); LLVMValueRef err_code_ptr_val = LLVMGetParam(g->cur_fn_val, err_code_ptr_arg_index); LLVMValueRef err_code = ir_llvm_value(g, instruction->err_val); LLVMBuildStore(g->builder, err_code, err_code_ptr_val); @@ -3985,6 +3984,132 @@ static LLVMValueRef ir_render_coro_save(CodeGen *g, IrExecutable *executable, Ir return LLVMBuildCall(g->builder, get_coro_save_fn_val(g), &coro_handle, 1, ""); } +static LLVMValueRef get_coro_alloc_helper_fn_val(CodeGen *g, LLVMTypeRef alloc_fn_type_ref, TypeTableEntry *fn_type) { + if (g->coro_alloc_helper_fn_val != nullptr) + return g->coro_alloc_fn_val; + + assert(fn_type->id == TypeTableEntryIdFn); + + TypeTableEntry *ptr_to_err_code_type = get_pointer_to_type(g, g->builtin_types.entry_global_error_set, false); + + LLVMTypeRef alloc_raw_fn_type_ref = LLVMGetElementType(alloc_fn_type_ref); + LLVMTypeRef *alloc_fn_arg_types = allocate<LLVMTypeRef>(LLVMCountParamTypes(alloc_raw_fn_type_ref)); + LLVMGetParamTypes(alloc_raw_fn_type_ref, alloc_fn_arg_types); + + ZigList<LLVMTypeRef> arg_types = {}; + arg_types.append(alloc_fn_type_ref); + if (g->have_err_ret_tracing) { + arg_types.append(alloc_fn_arg_types[1]); + } + arg_types.append(alloc_fn_arg_types[g->have_err_ret_tracing ? 2 : 1]); + arg_types.append(ptr_to_err_code_type->type_ref); + arg_types.append(g->builtin_types.entry_usize->type_ref); + + LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMPointerType(LLVMInt8Type(), 0), + arg_types.items, arg_types.length, false); + + Buf *fn_name = get_mangled_name(g, buf_create_from_str("__zig_coro_alloc_helper"), false); + LLVMValueRef fn_val = LLVMAddFunction(g->module, buf_ptr(fn_name), fn_type_ref); + LLVMSetLinkage(fn_val, LLVMInternalLinkage); + LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified)); + addLLVMFnAttr(fn_val, "nounwind"); + addLLVMArgAttr(fn_val, (unsigned)0, "nonnull"); + addLLVMArgAttr(fn_val, (unsigned)1, "nonnull"); + + LLVMBasicBlockRef prev_block = LLVMGetInsertBlock(g->builder); + LLVMValueRef prev_debug_location = LLVMGetCurrentDebugLocation(g->builder); + FnTableEntry *prev_cur_fn = g->cur_fn; + LLVMValueRef prev_cur_fn_val = g->cur_fn_val; + + LLVMBasicBlockRef entry_block = LLVMAppendBasicBlock(fn_val, "Entry"); + LLVMPositionBuilderAtEnd(g->builder, entry_block); + ZigLLVMClearCurrentDebugLocation(g->builder); + g->cur_fn = nullptr; + g->cur_fn_val = fn_val; + + LLVMValueRef sret_ptr = LLVMBuildAlloca(g->builder, LLVMGetElementType(alloc_fn_arg_types[0]), ""); + + size_t next_arg = 0; + LLVMValueRef alloc_fn_val = LLVMGetParam(fn_val, next_arg); + next_arg += 1; + + LLVMValueRef stack_trace_val; + if (g->have_err_ret_tracing) { + stack_trace_val = LLVMGetParam(fn_val, next_arg); + next_arg += 1; + } + + LLVMValueRef allocator_val = LLVMGetParam(fn_val, next_arg); + next_arg += 1; + LLVMValueRef err_code_ptr = LLVMGetParam(fn_val, next_arg); + next_arg += 1; + LLVMValueRef coro_size = LLVMGetParam(fn_val, next_arg); + next_arg += 1; + LLVMValueRef alignment_val = LLVMConstInt(g->builtin_types.entry_u29->type_ref, + 2 * g->pointer_size_bytes, false); + + ZigList<LLVMValueRef> args = {}; + args.append(sret_ptr); + if (g->have_err_ret_tracing) { + args.append(stack_trace_val); + } + args.append(allocator_val); + args.append(coro_size); + args.append(alignment_val); + ZigLLVMBuildCall(g->builder, alloc_fn_val, args.items, args.length, + get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, ""); + LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, sret_ptr, err_union_err_index, ""); + LLVMValueRef err_val = LLVMBuildLoad(g->builder, err_val_ptr, ""); + LLVMBuildStore(g->builder, err_val, err_code_ptr); + LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, err_val, LLVMConstNull(LLVMTypeOf(err_val)), ""); + LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(fn_val, "AllocOk"); + LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(fn_val, "AllocFail"); + LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block); + + LLVMPositionBuilderAtEnd(g->builder, ok_block); + LLVMValueRef payload_ptr = LLVMBuildStructGEP(g->builder, sret_ptr, err_union_payload_index, ""); + TypeTableEntry *u8_ptr_type = get_pointer_to_type(g, g->builtin_types.entry_u8, false); + TypeTableEntry *slice_type = get_slice_type(g, u8_ptr_type); + size_t ptr_field_index = slice_type->data.structure.fields[slice_ptr_index].gen_index; + LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, payload_ptr, ptr_field_index, ""); + LLVMValueRef ptr_val = LLVMBuildLoad(g->builder, ptr_field_ptr, ""); + LLVMBuildRet(g->builder, ptr_val); + + LLVMPositionBuilderAtEnd(g->builder, fail_block); + LLVMBuildRet(g->builder, LLVMConstNull(LLVMPointerType(LLVMInt8Type(), 0))); + + g->cur_fn = prev_cur_fn; + g->cur_fn_val = prev_cur_fn_val; + LLVMPositionBuilderAtEnd(g->builder, prev_block); + LLVMSetCurrentDebugLocation(g->builder, prev_debug_location); + + g->coro_alloc_helper_fn_val = fn_val; + return fn_val; +} + +static LLVMValueRef ir_render_coro_alloc_helper(CodeGen *g, IrExecutable *executable, + IrInstructionCoroAllocHelper *instruction) +{ + LLVMValueRef alloc_fn = ir_llvm_value(g, instruction->alloc_fn); + LLVMValueRef coro_size = ir_llvm_value(g, instruction->coro_size); + LLVMValueRef fn_val = get_coro_alloc_helper_fn_val(g, LLVMTypeOf(alloc_fn), instruction->alloc_fn->value.type); + size_t err_code_ptr_arg_index = get_async_err_code_arg_index(g, &g->cur_fn->type_entry->data.fn.fn_type_id); + size_t allocator_arg_index = get_async_allocator_arg_index(g, &g->cur_fn->type_entry->data.fn.fn_type_id); + + ZigList<LLVMValueRef> params = {}; + params.append(alloc_fn); + uint32_t err_ret_trace_arg_index = get_err_ret_trace_arg_index(g, g->cur_fn); + if (err_ret_trace_arg_index != UINT32_MAX) { + params.append(LLVMGetParam(g->cur_fn_val, err_ret_trace_arg_index)); + } + params.append(LLVMGetParam(g->cur_fn_val, allocator_arg_index)); + params.append(LLVMGetParam(g->cur_fn_val, err_code_ptr_arg_index)); + params.append(coro_size); + + return ZigLLVMBuildCall(g->builder, fn_val, params.items, params.length, + get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, ""); +} + static void set_debug_location(CodeGen *g, IrInstruction *instruction) { AstNode *source_node = instruction->source_node; Scope *scope = instruction->scope; @@ -4190,6 +4315,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, return ir_render_coro_resume(g, executable, (IrInstructionCoroResume *)instruction); case IrInstructionIdCoroSave: return ir_render_coro_save(g, executable, (IrInstructionCoroSave *)instruction); + case IrInstructionIdCoroAllocHelper: + return ir_render_coro_alloc_helper(g, executable, (IrInstructionCoroAllocHelper *)instruction); } zig_unreachable(); } diff --git a/src/ir.cpp b/src/ir.cpp index 9d213d1ddb..d2c28582d7 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -695,6 +695,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroSave *) { return IrInstructionIdCoroSave; } +static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroAllocHelper *) { + return IrInstructionIdCoroAllocHelper; +} + template<typename T> static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) { T *special_instruction = allocate<T>(1); @@ -829,14 +833,6 @@ static IrInstruction *ir_build_const_usize(IrBuilder *irb, Scope *scope, AstNode return &const_instruction->base; } -static IrInstruction *ir_build_const_u29(IrBuilder *irb, Scope *scope, AstNode *source_node, uint32_t value) { - IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(irb, scope, source_node); - const_instruction->base.value.type = irb->codegen->builtin_types.entry_u29; - const_instruction->base.value.special = ConstValSpecialStatic; - bigint_init_unsigned(&const_instruction->base.value.data.x_bigint, value); - return &const_instruction->base; -} - static IrInstruction *ir_build_const_u8(IrBuilder *irb, Scope *scope, AstNode *source_node, uint8_t value) { IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(irb, scope, source_node); const_instruction->base.value.type = irb->codegen->builtin_types.entry_u8; @@ -2600,6 +2596,19 @@ static IrInstruction *ir_build_coro_save(IrBuilder *irb, Scope *scope, AstNode * return &instruction->base; } +static IrInstruction *ir_build_coro_alloc_helper(IrBuilder *irb, Scope *scope, AstNode *source_node, + IrInstruction *alloc_fn, IrInstruction *coro_size) +{ + IrInstructionCoroAllocHelper *instruction = ir_build_instruction<IrInstructionCoroAllocHelper>(irb, scope, source_node); + instruction->alloc_fn = alloc_fn; + instruction->coro_size = coro_size; + + ir_ref_instruction(alloc_fn, irb->current_basic_block); + ir_ref_instruction(coro_size, irb->current_basic_block); + + return &instruction->base; +} + static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) { results[ReturnKindUnconditional] = 0; results[ReturnKindError] = 0; @@ -6074,10 +6083,11 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec bool is_async = fn_entry != nullptr && fn_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync; IrInstruction *u8_ptr_type; IrInstruction *const_bool_false; - IrInstruction *coro_unwrapped_mem_ptr; + IrInstruction *coro_size; IrInstruction *coro_id; IrInstruction *coro_promise_ptr; IrInstruction *coro_result_field_ptr; + IrInstruction *coro_mem_ptr; TypeTableEntry *return_type; Buf *result_ptr_field_name; if (is_async) { @@ -6095,39 +6105,25 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec get_pointer_to_type(irb->codegen, irb->codegen->builtin_types.entry_u8, false)); IrInstruction *promise_as_u8_ptr = ir_build_ptr_cast(irb, scope, node, u8_ptr_type, coro_promise_ptr); coro_id = ir_build_coro_id(irb, scope, node, promise_as_u8_ptr); - IrInstruction *coro_size = ir_build_coro_size(irb, scope, node); + coro_size = ir_build_coro_size(irb, scope, node); irb->exec->implicit_allocator_ptr = ir_build_get_implicit_allocator(irb, scope, node); Buf *alloc_field_name = buf_create_from_str(ASYNC_ALLOC_FIELD_NAME); IrInstruction *alloc_fn_ptr = ir_build_field_ptr(irb, scope, node, irb->exec->implicit_allocator_ptr, alloc_field_name); IrInstruction *alloc_fn = ir_build_load_ptr(irb, scope, node, alloc_fn_ptr); - IrInstruction *alignment = ir_build_const_u29(irb, scope, node, - get_coro_frame_align_bytes(irb->codegen)); - size_t arg_count = 3; - IrInstruction **args = allocate<IrInstruction *>(arg_count); - args[0] = irb->exec->implicit_allocator_ptr; // self - args[1] = coro_size; // byte_count - args[2] = alignment; // alignment - IrInstruction *alloc_result = ir_build_call(irb, scope, node, nullptr, alloc_fn, arg_count, args, false, - FnInlineAuto, false, nullptr); - IrInstruction *alloc_result_ptr = ir_build_ref(irb, scope, node, alloc_result, true, false); - IrInstruction *alloc_result_is_err = ir_build_test_err(irb, scope, node, alloc_result); + IrInstruction *maybe_coro_mem_ptr = ir_build_coro_alloc_helper(irb, scope, node, alloc_fn, coro_size); + IrInstruction *alloc_result_is_ok = ir_build_test_nonnull(irb, scope, node, maybe_coro_mem_ptr); IrBasicBlock *alloc_err_block = ir_create_basic_block(irb, scope, "AllocError"); IrBasicBlock *alloc_ok_block = ir_create_basic_block(irb, scope, "AllocOk"); - ir_build_cond_br(irb, scope, node, alloc_result_is_err, alloc_err_block, alloc_ok_block, const_bool_false); + ir_build_cond_br(irb, scope, node, alloc_result_is_ok, alloc_ok_block, alloc_err_block, const_bool_false); ir_set_cursor_at_end_and_append_block(irb, alloc_err_block); - IrInstruction *err_val = ir_build_unwrap_err_code(irb, scope, node, alloc_result_ptr); - ir_build_coro_alloc_fail(irb, scope, node, err_val); + IrInstruction *undef = ir_build_const_undefined(irb, scope, node); + ir_build_return(irb, scope, node, undef); ir_set_cursor_at_end_and_append_block(irb, alloc_ok_block); - coro_unwrapped_mem_ptr = ir_build_unwrap_err_payload(irb, scope, node, alloc_result_ptr, false); - Buf *ptr_field_name = buf_create_from_str("ptr"); - IrInstruction *coro_mem_ptr_field = ir_build_field_ptr(irb, scope, node, coro_unwrapped_mem_ptr, - ptr_field_name); - IrInstruction *coro_mem = ir_build_load_ptr(irb, scope, node, coro_mem_ptr_field); - - irb->exec->coro_handle = ir_build_coro_begin(irb, scope, node, coro_id, coro_mem); + coro_mem_ptr = ir_build_ptr_cast(irb, scope, node, u8_ptr_type, maybe_coro_mem_ptr); + irb->exec->coro_handle = ir_build_coro_begin(irb, scope, node, coro_id, coro_mem_ptr); Buf *awaiter_handle_field_name = buf_create_from_str(AWAITER_HANDLE_FIELD_NAME); irb->exec->coro_awaiter_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, @@ -6207,10 +6203,13 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec IrInstruction *free_fn_ptr = ir_build_field_ptr(irb, scope, node, irb->exec->implicit_allocator_ptr, free_field_name); IrInstruction *free_fn = ir_build_load_ptr(irb, scope, node, free_fn_ptr); + IrInstruction *zero = ir_build_const_usize(irb, scope, node, 0); + IrInstruction *coro_mem_ptr_ref = ir_build_ref(irb, scope, node, coro_mem_ptr, true, false); + IrInstruction *mem_slice = ir_build_slice(irb, scope, node, coro_mem_ptr_ref, zero, coro_size, false); size_t arg_count = 2; IrInstruction **args = allocate<IrInstruction *>(arg_count); args[0] = irb->exec->implicit_allocator_ptr; // self - args[1] = ir_build_load_ptr(irb, scope, node, coro_unwrapped_mem_ptr); // old_mem + args[1] = mem_slice; // old_mem ir_build_call(irb, scope, node, nullptr, free_fn, arg_count, args, false, FnInlineAuto, false, nullptr); IrBasicBlock *resume_block = ir_create_basic_block(irb, scope, "Resume"); @@ -11844,7 +11843,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal } TypeTableEntry *return_type = impl_fn->type_entry->data.fn.fn_type_id.return_type; - if (return_type->id == TypeTableEntryIdErrorSet || return_type->id == TypeTableEntryIdErrorUnion) { + if (fn_type_can_fail(&impl_fn->type_entry->data.fn.fn_type_id)) { parent_fn_entry->calls_errorable_function = true; } @@ -11870,7 +11869,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal FnTableEntry *parent_fn_entry = exec_fn_entry(ira->new_irb.exec); assert(fn_type_id->return_type != nullptr); assert(parent_fn_entry != nullptr); - if (fn_type_id->return_type->id == TypeTableEntryIdErrorSet || fn_type_id->return_type->id == TypeTableEntryIdErrorUnion) { + if (fn_type_can_fail(fn_type_id)) { parent_fn_entry->calls_errorable_function = true; } @@ -17274,6 +17273,23 @@ static TypeTableEntry *ir_analyze_instruction_coro_save(IrAnalyze *ira, IrInstru return result->value.type; } +static TypeTableEntry *ir_analyze_instruction_coro_alloc_helper(IrAnalyze *ira, IrInstructionCoroAllocHelper *instruction) { + IrInstruction *alloc_fn = instruction->alloc_fn->other; + if (type_is_invalid(alloc_fn->value.type)) + return ira->codegen->builtin_types.entry_invalid; + + IrInstruction *coro_size = instruction->coro_size->other; + if (type_is_invalid(coro_size->value.type)) + return ira->codegen->builtin_types.entry_invalid; + + IrInstruction *result = ir_build_coro_alloc_helper(&ira->new_irb, instruction->base.scope, + instruction->base.source_node, alloc_fn, coro_size); + ir_link_new_instruction(result, &instruction->base); + TypeTableEntry *u8_ptr_type = get_pointer_to_type(ira->codegen, ira->codegen->builtin_types.entry_u8, false); + result->value.type = get_maybe_type(ira->codegen, u8_ptr_type); + return result->value.type; +} + static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) { switch (instruction->id) { @@ -17501,6 +17517,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi return ir_analyze_instruction_coro_resume(ira, (IrInstructionCoroResume *)instruction); case IrInstructionIdCoroSave: return ir_analyze_instruction_coro_save(ira, (IrInstructionCoroSave *)instruction); + case IrInstructionIdCoroAllocHelper: + return ir_analyze_instruction_coro_alloc_helper(ira, (IrInstructionCoroAllocHelper *)instruction); } zig_unreachable(); } @@ -17624,6 +17642,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdCoroEnd: case IrInstructionIdCoroResume: case IrInstructionIdCoroSave: + case IrInstructionIdCoroAllocHelper: return true; case IrInstructionIdPhi: diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 2e367672a5..b9e02988c2 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -1096,6 +1096,14 @@ static void ir_print_coro_save(IrPrint *irp, IrInstructionCoroSave *instruction) fprintf(irp->f, ")"); } +static void ir_print_coro_alloc_helper(IrPrint *irp, IrInstructionCoroAllocHelper *instruction) { + fprintf(irp->f, "@coroAllocHelper("); + ir_print_other_instruction(irp, instruction->alloc_fn); + fprintf(irp->f, ","); + ir_print_other_instruction(irp, instruction->coro_size); + fprintf(irp->f, ")"); +} + static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { ir_print_prefix(irp, instruction); switch (instruction->id) { @@ -1452,6 +1460,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdCoroSave: ir_print_coro_save(irp, (IrInstructionCoroSave *)instruction); break; + case IrInstructionIdCoroAllocHelper: + ir_print_coro_alloc_helper(irp, (IrInstructionCoroAllocHelper *)instruction); + break; } fprintf(irp->f, "\n"); } |
