aboutsummaryrefslogtreecommitdiff
path: root/src/ir.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/ir.cpp')
-rw-r--r--src/ir.cpp136
1 files changed, 94 insertions, 42 deletions
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<IrInstructionCall>(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<IrInstructionGetImplicitAllocator>(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<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);
+ 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<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
- 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;
}