From 4ac6c4d6bfb8f7ada2799ddb5ce3a9797be0518d Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 26 Feb 2018 21:14:15 -0500 Subject: [PATCH] workaround llvm coro transformations by making alloc and free functions be parameters to async functions instead of using getelementptr in the DynAlloc block See #727 --- src/all_types.hpp | 11 ++++ src/analyze.cpp | 34 ++++++++++-- src/codegen.cpp | 37 +++++++++++-- src/ir.cpp | 136 ++++++++++++++++++++++++++++++++-------------- src/ir_print.cpp | 14 ++++- std/mem.zig | 16 ------ 6 files changed, 179 insertions(+), 69 deletions(-) diff --git a/src/all_types.hpp b/src/all_types.hpp index 63292dd8ec..4220523126 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -2208,7 +2208,10 @@ struct IrInstructionCall { LLVMValueRef tmp_ptr; FnInline fn_inline; bool is_async; + IrInstruction *async_allocator; + IrInstruction *alloc_fn; + IrInstruction *free_fn; }; struct IrInstructionConst { @@ -2849,8 +2852,16 @@ struct IrInstructionCancel { IrInstruction *target; }; +enum ImplicitAllocatorId { + ImplicitAllocatorIdContext, + ImplicitAllocatorIdAlloc, + ImplicitAllocatorIdFree, +}; + struct IrInstructionGetImplicitAllocator { IrInstruction base; + + ImplicitAllocatorId id; }; struct IrInstructionCoroId { diff --git a/src/analyze.cpp b/src/analyze.cpp index ce9e99f8fa..26924cc7db 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -1006,13 +1006,13 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) { fn_type_id->return_type->id == TypeTableEntryIdErrorSet); // +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 - LLVMTypeRef *gen_param_types = allocate(4 + fn_type_id->param_count); + // +4 for maybe arguments async allocator and error code pointer + LLVMTypeRef *gen_param_types = allocate(6 + fn_type_id->param_count); // +1 because 0 is the return type and // +1 for maybe making first arg ret val and // +1 for maybe first argument the error return trace - // +2 for maybe arguments async allocator and error code pointer - ZigLLVMDIType **param_di_types = allocate(5 + fn_type_id->param_count); + // +4 for maybe arguments async allocator and error code pointer + ZigLLVMDIType **param_di_types = allocate(7 + fn_type_id->param_count); param_di_types[0] = fn_type_id->return_type->di_type; size_t gen_param_index = 0; TypeTableEntry *gen_return_type; @@ -1049,6 +1049,32 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) { param_di_types[gen_param_index] = gen_type->di_type; } + { + // async alloc fn param + assert(fn_type_id->async_allocator_type->id == TypeTableEntryIdPointer); + TypeTableEntry *struct_type = fn_type_id->async_allocator_type->data.pointer.child_type; + TypeStructField *alloc_fn_field = find_struct_type_field(struct_type, buf_create_from_str("allocFn")); + assert(alloc_fn_field->type_entry->id == TypeTableEntryIdFn); + TypeTableEntry *gen_type = alloc_fn_field->type_entry; + gen_param_types[gen_param_index] = gen_type->type_ref; + gen_param_index += 1; + // after the gen_param_index += 1 because 0 is the return type + param_di_types[gen_param_index] = gen_type->di_type; + } + + { + // async free fn param + assert(fn_type_id->async_allocator_type->id == TypeTableEntryIdPointer); + TypeTableEntry *struct_type = fn_type_id->async_allocator_type->data.pointer.child_type; + TypeStructField *free_fn_field = find_struct_type_field(struct_type, buf_create_from_str("freeFn")); + assert(free_fn_field->type_entry->id == TypeTableEntryIdFn); + TypeTableEntry *gen_type = free_fn_field->type_entry; + gen_param_types[gen_param_index] = gen_type->type_ref; + gen_param_index += 1; + // after the gen_param_index += 1 because 0 is the return type + param_di_types[gen_param_index] = gen_type->di_type; + } + { // error code pointer TypeTableEntry *gen_type = get_pointer_to_type(g, g->builtin_types.entry_global_error_set, false); diff --git a/src/codegen.cpp b/src/codegen.cpp index f82c686b85..21fc28e4af 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -2667,6 +2667,18 @@ static bool get_prefix_arg_err_ret_stack(CodeGen *g, TypeTableEntry *src_return_ (src_return_type->id == TypeTableEntryIdErrorUnion || src_return_type->id == TypeTableEntryIdErrorSet); } +static size_t get_async_allocator_arg_index(CodeGen *g, TypeTableEntry *src_return_type) { + // 0 1 2 3 4 5 + // err_ret_stack allocator_ptr alloc free err_code other_args... + return get_prefix_arg_err_ret_stack(g, src_return_type) ? 1 : 0; +} + +static size_t get_async_err_code_arg_index(CodeGen *g, TypeTableEntry *src_return_type) { + // 0 1 2 3 4 5 + // err_ret_stack allocator_ptr alloc free err_code other_args... + return 3 + get_async_allocator_arg_index(g, src_return_type); +} + static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstructionCall *instruction) { LLVMValueRef fn_val; TypeTableEntry *fn_type; @@ -2687,7 +2699,8 @@ 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); - size_t actual_param_count = instruction->arg_count + (first_arg_ret ? 1 : 0) + (prefix_arg_err_ret_stack ? 1 : 0); + // +4 for the async args + size_t actual_param_count = instruction->arg_count + (first_arg_ret ? 1 : 0) + (prefix_arg_err_ret_stack ? 1 : 0) + 4; bool is_var_args = fn_type_id->is_var_args; LLVMValueRef *gen_param_values = allocate(actual_param_count); size_t gen_param_index = 0; @@ -2703,6 +2716,12 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr gen_param_values[gen_param_index] = ir_llvm_value(g, instruction->async_allocator); gen_param_index += 1; + gen_param_values[gen_param_index] = ir_llvm_value(g, instruction->alloc_fn); + gen_param_index += 1; + + gen_param_values[gen_param_index] = ir_llvm_value(g, instruction->free_fn); + 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; @@ -3281,9 +3300,16 @@ static LLVMValueRef ir_render_get_implicit_allocator(CodeGen *g, IrExecutable *e IrInstructionGetImplicitAllocator *instruction) { TypeTableEntry *src_return_type = g->cur_fn->type_entry->data.fn.fn_type_id.return_type; - bool prefix_arg_err_ret_stack = get_prefix_arg_err_ret_stack(g, src_return_type); - size_t allocator_arg_index = prefix_arg_err_ret_stack ? 1 : 0; - return LLVMGetParam(g->cur_fn_val, allocator_arg_index); + size_t allocator_arg_index = get_async_allocator_arg_index(g, src_return_type); + switch (instruction->id) { + case ImplicitAllocatorIdContext: + return LLVMGetParam(g->cur_fn_val, allocator_arg_index + 0); + case ImplicitAllocatorIdAlloc: + return LLVMGetParam(g->cur_fn_val, allocator_arg_index + 1); + case ImplicitAllocatorIdFree: + return LLVMGetParam(g->cur_fn_val, allocator_arg_index + 2); + } + zig_unreachable(); } static LLVMAtomicOrdering to_LLVMAtomicOrdering(AtomicOrder atomic_order) { @@ -3915,8 +3941,7 @@ static LLVMValueRef ir_render_coro_alloc_fail(CodeGen *g, IrExecutable *executab IrInstructionCoroAllocFail *instruction) { TypeTableEntry *src_return_type = g->cur_fn->type_entry->data.fn.fn_type_id.return_type; - bool prefix_arg_err_ret_stack = get_prefix_arg_err_ret_stack(g, src_return_type); - size_t err_code_ptr_arg_index = prefix_arg_err_ret_stack ? 2 : 1; + size_t err_code_ptr_arg_index = get_async_err_code_arg_index(g, src_return_type); 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); diff --git a/src/ir.cpp b/src/ir.cpp index 2600f5e948..bca133b8e5 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -1066,7 +1066,7 @@ static IrInstruction *ir_build_union_field_ptr_from(IrBuilder *irb, IrInstructio static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *source_node, FnTableEntry *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args, - bool is_comptime, FnInline fn_inline, bool is_async, IrInstruction *async_allocator) + bool is_comptime, FnInline fn_inline, bool is_async, IrInstruction *async_allocator, IrInstruction *alloc_fn, IrInstruction *free_fn) { IrInstructionCall *call_instruction = ir_build_instruction(irb, scope, source_node); call_instruction->fn_entry = fn_entry; @@ -1077,6 +1077,8 @@ static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *sourc call_instruction->arg_count = arg_count; call_instruction->is_async = is_async; call_instruction->async_allocator = async_allocator; + call_instruction->alloc_fn = alloc_fn; + call_instruction->free_fn = free_fn; if (fn_ref) ir_ref_instruction(fn_ref, irb->current_basic_block); @@ -1084,16 +1086,20 @@ static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *sourc ir_ref_instruction(args[i], irb->current_basic_block); if (async_allocator) ir_ref_instruction(async_allocator, irb->current_basic_block); + if (alloc_fn) + ir_ref_instruction(alloc_fn, irb->current_basic_block); + if (free_fn) + ir_ref_instruction(free_fn, irb->current_basic_block); return &call_instruction->base; } static IrInstruction *ir_build_call_from(IrBuilder *irb, IrInstruction *old_instruction, FnTableEntry *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args, - bool is_comptime, FnInline fn_inline, bool is_async, IrInstruction *async_allocator) + bool is_comptime, FnInline fn_inline, bool is_async, IrInstruction *async_allocator, IrInstruction *alloc_fn, IrInstruction *free_fn) { IrInstruction *new_instruction = ir_build_call(irb, old_instruction->scope, - old_instruction->source_node, fn_entry, fn_ref, arg_count, args, is_comptime, fn_inline, is_async, async_allocator); + old_instruction->source_node, fn_entry, fn_ref, arg_count, args, is_comptime, fn_inline, is_async, async_allocator, alloc_fn, free_fn); ir_link_new_instruction(new_instruction, old_instruction); return new_instruction; } @@ -2495,8 +2501,9 @@ static IrInstruction *ir_build_cancel(IrBuilder *irb, Scope *scope, AstNode *sou return &instruction->base; } -static IrInstruction *ir_build_get_implicit_allocator(IrBuilder *irb, Scope *scope, AstNode *source_node) { +static IrInstruction *ir_build_get_implicit_allocator(IrBuilder *irb, Scope *scope, AstNode *source_node, ImplicitAllocatorId id) { IrInstructionGetImplicitAllocator *instruction = ir_build_instruction(irb, scope, source_node); + instruction->id = id; return &instruction->base; } @@ -3970,7 +3977,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo } FnInline fn_inline = (builtin_fn->id == BuiltinFnIdInlineCall) ? FnInlineAlways : FnInlineNever; - return ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, fn_inline, false, nullptr); + return ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, fn_inline, false, nullptr, nullptr, nullptr); } case BuiltinFnIdTypeId: { @@ -4106,15 +4113,25 @@ static IrInstruction *ir_gen_fn_call(IrBuilder *irb, Scope *scope, AstNode *node bool is_async = node->data.fn_call_expr.is_async; IrInstruction *async_allocator = nullptr; + IrInstruction *alloc_fn = nullptr; + IrInstruction *free_fn = nullptr; if (is_async) { if (node->data.fn_call_expr.async_allocator) { async_allocator = ir_gen_node(irb, node->data.fn_call_expr.async_allocator, scope); if (async_allocator == irb->codegen->invalid_instruction) return async_allocator; + + Buf *alloc_field_name = buf_create_from_str(ASYNC_ALLOC_FIELD_NAME); + IrInstruction *alloc_fn_ptr = ir_build_field_ptr(irb, scope, node, async_allocator, alloc_field_name); + alloc_fn = ir_build_load_ptr(irb, scope, node, alloc_fn_ptr); + + Buf *free_field_name = buf_create_from_str(ASYNC_FREE_FIELD_NAME); + IrInstruction *free_fn_ptr = ir_build_field_ptr(irb, scope, node, async_allocator, free_field_name); + free_fn = ir_build_load_ptr(irb, scope, node, free_fn_ptr); } } - return ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, FnInlineAuto, is_async, async_allocator); + return ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, FnInlineAuto, is_async, async_allocator, alloc_fn, free_fn); } static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode *node) { @@ -6106,20 +6123,16 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec ir_set_cursor_at_end_and_append_block(irb, dyn_alloc_block); IrInstruction *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)); + irb->exec->implicit_allocator_ptr = ir_build_get_implicit_allocator(irb, scope, node, ImplicitAllocatorIdContext); + IrInstruction *alloc_fn = ir_build_get_implicit_allocator(irb, scope, node, ImplicitAllocatorIdAlloc); + IrInstruction *alignment = ir_build_const_u29(irb, scope, node, get_coro_frame_align_bytes(irb->codegen)); size_t arg_count = 3; IrInstruction **args = allocate(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); + FnInlineAuto, false, nullptr, nullptr, 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); IrBasicBlock *alloc_err_block = ir_create_basic_block(irb, scope, "AllocError"); @@ -6237,15 +6250,12 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec ir_build_cond_br(irb, scope, node, coro_need_dyn_alloc, dyn_free_block, end_free_block, const_bool_false); ir_set_cursor_at_end_and_append_block(irb, dyn_free_block); - Buf *free_field_name = buf_create_from_str(ASYNC_FREE_FIELD_NAME); - 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 *free_fn = ir_build_get_implicit_allocator(irb, scope, node, ImplicitAllocatorIdFree); size_t arg_count = 2; IrInstruction **args = allocate(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 - ir_build_call(irb, scope, node, nullptr, free_fn, arg_count, args, false, FnInlineAuto, false, nullptr); + ir_build_call(irb, scope, node, nullptr, free_fn, arg_count, args, false, FnInlineAuto, false, nullptr, nullptr, nullptr); ir_build_br(irb, scope, node, end_free_block, const_bool_false); ir_set_cursor_at_end_and_append_block(irb, end_free_block); @@ -11266,7 +11276,7 @@ static TypeTableEntry *ir_analyze_instruction_error_union(IrAnalyze *ira, return ira->codegen->builtin_types.entry_type; } -IrInstruction *ir_get_implicit_allocator(IrAnalyze *ira, IrInstruction *source_instr) { +IrInstruction *ir_get_implicit_allocator(IrAnalyze *ira, IrInstruction *source_instr, ImplicitAllocatorId id) { FnTableEntry *parent_fn_entry = exec_fn_entry(ira->new_irb.exec); if (parent_fn_entry == nullptr) { ir_add_error(ira, source_instr, buf_sprintf("no implicit allocator available")); @@ -11280,27 +11290,39 @@ IrInstruction *ir_get_implicit_allocator(IrAnalyze *ira, IrInstruction *source_i } assert(parent_fn_type->async_allocator_type != nullptr); - IrInstruction *result = ir_build_get_implicit_allocator(&ira->new_irb, source_instr->scope, source_instr->source_node); - result->value.type = parent_fn_type->async_allocator_type; + IrInstruction *result = ir_build_get_implicit_allocator(&ira->new_irb, source_instr->scope, source_instr->source_node, id); + switch (id) { + case ImplicitAllocatorIdContext: + result->value.type = parent_fn_type->async_allocator_type; + break; + case ImplicitAllocatorIdAlloc: + { + assert(parent_fn_type->async_allocator_type->id == TypeTableEntryIdPointer); + TypeTableEntry *struct_type = parent_fn_type->async_allocator_type->data.pointer.child_type; + TypeStructField *alloc_fn_field = find_struct_type_field(struct_type, buf_create_from_str(ASYNC_ALLOC_FIELD_NAME)); + assert(alloc_fn_field->type_entry->id == TypeTableEntryIdFn); + result->value.type = alloc_fn_field->type_entry; + break; + } + case ImplicitAllocatorIdFree: + { + assert(parent_fn_type->async_allocator_type->id == TypeTableEntryIdPointer); + TypeTableEntry *struct_type = parent_fn_type->async_allocator_type->data.pointer.child_type; + TypeStructField *free_fn_field = find_struct_type_field(struct_type, buf_create_from_str(ASYNC_FREE_FIELD_NAME)); + assert(free_fn_field->type_entry->id == TypeTableEntryIdFn); + result->value.type = free_fn_field->type_entry; + break; + } + } return result; } static IrInstruction *ir_analyze_async_call(IrAnalyze *ira, IrInstructionCall *call_instruction, FnTableEntry *fn_entry, TypeTableEntry *fn_type, - IrInstruction *fn_ref, IrInstruction **casted_args, size_t arg_count, IrInstruction *async_allocator_inst) + IrInstruction *fn_ref, IrInstruction **casted_args, size_t arg_count, IrInstruction *async_allocator_inst, IrInstruction *alloc_fn, IrInstruction *free_fn) { - Buf *alloc_field_name = buf_create_from_str(ASYNC_ALLOC_FIELD_NAME); - //Buf *free_field_name = buf_create_from_str("freeFn"); assert(async_allocator_inst->value.type->id == TypeTableEntryIdPointer); - TypeTableEntry *container_type = async_allocator_inst->value.type->data.pointer.child_type; - IrInstruction *field_ptr_inst = ir_analyze_container_field_ptr(ira, alloc_field_name, &call_instruction->base, - async_allocator_inst, container_type); - if (type_is_invalid(field_ptr_inst->value.type)) { - return ira->codegen->invalid_instruction; - } - TypeTableEntry *ptr_to_alloc_fn_type = field_ptr_inst->value.type; - assert(ptr_to_alloc_fn_type->id == TypeTableEntryIdPointer); - TypeTableEntry *alloc_fn_type = ptr_to_alloc_fn_type->data.pointer.child_type; + TypeTableEntry *alloc_fn_type = alloc_fn->value.type; if (alloc_fn_type->id != TypeTableEntryIdFn) { ir_add_error(ira, &call_instruction->base, buf_sprintf("expected allocation function, found '%s'", buf_ptr(&alloc_fn_type->name))); @@ -11319,7 +11341,7 @@ static IrInstruction *ir_analyze_async_call(IrAnalyze *ira, IrInstructionCall *c TypeTableEntry *async_return_type = get_error_union_type(ira->codegen, alloc_fn_error_set_type, promise_type); IrInstruction *result = ir_build_call(&ira->new_irb, call_instruction->base.scope, call_instruction->base.source_node, - fn_entry, fn_ref, arg_count, casted_args, false, FnInlineAuto, true, async_allocator_inst); + fn_entry, fn_ref, arg_count, casted_args, false, FnInlineAuto, true, async_allocator_inst, alloc_fn, free_fn); result->value.type = async_return_type; return result; } @@ -11842,7 +11864,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal } IrInstruction *uncasted_async_allocator_inst; if (call_instruction->async_allocator == nullptr) { - uncasted_async_allocator_inst = ir_get_implicit_allocator(ira, &call_instruction->base); + uncasted_async_allocator_inst = ir_get_implicit_allocator(ira, &call_instruction->base, ImplicitAllocatorIdContext); if (type_is_invalid(uncasted_async_allocator_inst->value.type)) return ira->codegen->builtin_types.entry_invalid; } else { @@ -11886,15 +11908,25 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal size_t impl_param_count = impl_fn->type_entry->data.fn.fn_type_id.param_count; if (call_instruction->is_async) { - IrInstruction *result = ir_analyze_async_call(ira, call_instruction, impl_fn, impl_fn->type_entry, fn_ref, casted_args, impl_param_count, async_allocator_inst); + IrInstruction *alloc_fn = call_instruction->alloc_fn->other; + if (type_is_invalid(alloc_fn->value.type)) + return ira->codegen->builtin_types.entry_invalid; + + IrInstruction *free_fn = call_instruction->free_fn->other; + if (type_is_invalid(free_fn->value.type)) + return ira->codegen->builtin_types.entry_invalid; + + IrInstruction *result = ir_analyze_async_call(ira, call_instruction, impl_fn, impl_fn->type_entry, fn_ref, casted_args, impl_param_count, + async_allocator_inst, alloc_fn, free_fn); ir_link_new_instruction(result, &call_instruction->base); ir_add_alloca(ira, result, result->value.type); return ir_finish_anal(ira, result->value.type); } + assert(async_allocator_inst == nullptr); IrInstruction *new_call_instruction = ir_build_call_from(&ira->new_irb, &call_instruction->base, impl_fn, nullptr, impl_param_count, casted_args, false, fn_inline, - call_instruction->is_async, async_allocator_inst); + call_instruction->is_async, nullptr, nullptr, nullptr); ir_add_alloca(ira, new_call_instruction, return_type); @@ -11961,20 +11993,40 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal if (call_instruction->is_async) { IrInstruction *uncasted_async_allocator_inst; + IrInstruction *uncasted_alloc_fn_inst; + IrInstruction *uncasted_free_fn_inst; if (call_instruction->async_allocator == nullptr) { - uncasted_async_allocator_inst = ir_get_implicit_allocator(ira, &call_instruction->base); + uncasted_async_allocator_inst = ir_get_implicit_allocator(ira, &call_instruction->base, ImplicitAllocatorIdContext); if (type_is_invalid(uncasted_async_allocator_inst->value.type)) return ira->codegen->builtin_types.entry_invalid; + + uncasted_alloc_fn_inst = ir_get_implicit_allocator(ira, &call_instruction->base, ImplicitAllocatorIdAlloc); + if (type_is_invalid(uncasted_alloc_fn_inst->value.type)) + return ira->codegen->builtin_types.entry_invalid; + + uncasted_free_fn_inst = ir_get_implicit_allocator(ira, &call_instruction->base, ImplicitAllocatorIdFree); + if (type_is_invalid(uncasted_free_fn_inst->value.type)) + return ira->codegen->builtin_types.entry_invalid; } else { uncasted_async_allocator_inst = call_instruction->async_allocator->other; if (type_is_invalid(uncasted_async_allocator_inst->value.type)) return ira->codegen->builtin_types.entry_invalid; + + uncasted_alloc_fn_inst = call_instruction->alloc_fn->other; + if (type_is_invalid(uncasted_alloc_fn_inst->value.type)) + return ira->codegen->builtin_types.entry_invalid; + + uncasted_free_fn_inst = call_instruction->free_fn->other; + if (type_is_invalid(uncasted_free_fn_inst->value.type)) + return ira->codegen->builtin_types.entry_invalid; + } IrInstruction *async_allocator_inst = ir_implicit_cast(ira, uncasted_async_allocator_inst, fn_type_id->async_allocator_type); if (type_is_invalid(async_allocator_inst->value.type)) return ira->codegen->builtin_types.entry_invalid; - IrInstruction *result = ir_analyze_async_call(ira, call_instruction, fn_entry, fn_type, fn_ref, casted_args, call_param_count, async_allocator_inst); + IrInstruction *result = ir_analyze_async_call(ira, call_instruction, fn_entry, fn_type, fn_ref, casted_args, call_param_count, + async_allocator_inst, uncasted_alloc_fn_inst, uncasted_free_fn_inst); ir_link_new_instruction(result, &call_instruction->base); ir_add_alloca(ira, result, result->value.type); return ir_finish_anal(ira, result->value.type); @@ -11982,7 +12034,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal IrInstruction *new_call_instruction = ir_build_call_from(&ira->new_irb, &call_instruction->base, - fn_entry, fn_ref, call_param_count, casted_args, false, fn_inline, false, nullptr); + fn_entry, fn_ref, call_param_count, casted_args, false, fn_inline, false, nullptr, nullptr, nullptr); ir_add_alloca(ira, new_call_instruction, return_type); return ir_finish_anal(ira, return_type); @@ -17222,7 +17274,7 @@ static TypeTableEntry *ir_analyze_instruction_coro_begin(IrAnalyze *ira, IrInstr } static TypeTableEntry *ir_analyze_instruction_get_implicit_allocator(IrAnalyze *ira, IrInstructionGetImplicitAllocator *instruction) { - IrInstruction *result = ir_get_implicit_allocator(ira, &instruction->base); + IrInstruction *result = ir_get_implicit_allocator(ira, &instruction->base, instruction->id); ir_link_new_instruction(result, &instruction->base); return result->value.type; } diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 2e367672a5..1314123110 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -1027,7 +1027,19 @@ static void ir_print_cancel(IrPrint *irp, IrInstructionCancel *instruction) { } static void ir_print_get_implicit_allocator(IrPrint *irp, IrInstructionGetImplicitAllocator *instruction) { - fprintf(irp->f, "@getImplicitAllocator()"); + fprintf(irp->f, "@getImplicitAllocator("); + switch (instruction->id) { + case ImplicitAllocatorIdContext: + fprintf(irp->f, "Context"); + break; + case ImplicitAllocatorIdAlloc: + fprintf(irp->f, "Alloc"); + break; + case ImplicitAllocatorIdFree: + fprintf(irp->f, "Free"); + break; + } + fprintf(irp->f, ")"); } static void ir_print_coro_id(IrPrint *irp, IrInstructionCoroId *instruction) { diff --git a/std/mem.zig b/std/mem.zig index 2adb647ef6..07521bfcb8 100644 --- a/std/mem.zig +++ b/std/mem.zig @@ -116,22 +116,6 @@ pub const Allocator = struct { const non_const_ptr = @intToPtr(&u8, @ptrToInt(bytes.ptr)); self.freeFn(self, non_const_ptr[0..bytes.len]); } - - pub const AsyncAllocator = struct { - allocator: &Allocator, - - fn alloc(self: &const AsyncAllocator, byte_count: usize, alignment: u29) Error![]u8 { - return self.allocator.allocFn(self.allocator, byte_count, alignment); - } - - fn free(self: &const AsyncAllocator, old_mem: []u8) void { - return self.allocator.freeFn(self.allocator, old_mem); - } - }; - - fn toAsync(self: &Allocator) AsyncAllocator { - return AsyncAllocator { .allocator = self }; - } }; /// Copy all of source into dest at position 0.