Skip to content

Commit

Permalink
workaround llvm coro transformations
Browse files Browse the repository at this point in the history
by making alloc and free functions be parameters to async
functions instead of using getelementptr in the DynAlloc block

See #727
  • Loading branch information
andrewrk committed Feb 27, 2018
1 parent 3e86fb5 commit 4ac6c4d
Show file tree
Hide file tree
Showing 6 changed files with 179 additions and 69 deletions.
11 changes: 11 additions & 0 deletions src/all_types.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -2849,8 +2852,16 @@ struct IrInstructionCancel {
IrInstruction *target;
};

enum ImplicitAllocatorId {
ImplicitAllocatorIdContext,
ImplicitAllocatorIdAlloc,
ImplicitAllocatorIdFree,
};

struct IrInstructionGetImplicitAllocator {
IrInstruction base;

ImplicitAllocatorId id;
};

struct IrInstructionCoroId {
Expand Down
34 changes: 30 additions & 4 deletions src/analyze.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<LLVMTypeRef>(4 + fn_type_id->param_count);
// +4 for maybe arguments async allocator and error code pointer
LLVMTypeRef *gen_param_types = allocate<LLVMTypeRef>(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<ZigLLVMDIType*>(5 + fn_type_id->param_count);
// +4 for maybe arguments async allocator and error code pointer
ZigLLVMDIType **param_di_types = allocate<ZigLLVMDIType*>(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;
Expand Down Expand Up @@ -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);
Expand Down
37 changes: 31 additions & 6 deletions src/codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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<LLVMValueRef>(actual_param_count);
size_t gen_param_index = 0;
Expand All @@ -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;
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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);
Expand Down
Loading

0 comments on commit 4ac6c4d

Please sign in to comment.