Skip to content

Commit 026aebf

Browse files
committed
another workaround for llvm coroutines
this one doesn't work either
1 parent d243453 commit 026aebf

File tree

6 files changed

+222
-51
lines changed

6 files changed

+222
-51
lines changed

src/all_types.hpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1634,6 +1634,7 @@ struct CodeGen {
16341634
LLVMValueRef coro_free_fn_val;
16351635
LLVMValueRef coro_resume_fn_val;
16361636
LLVMValueRef coro_save_fn_val;
1637+
LLVMValueRef coro_alloc_helper_fn_val;
16371638
bool error_during_imports;
16381639

16391640
const char **clang_argv;
@@ -2004,6 +2005,7 @@ enum IrInstructionId {
20042005
IrInstructionIdCoroFree,
20052006
IrInstructionIdCoroResume,
20062007
IrInstructionIdCoroSave,
2008+
IrInstructionIdCoroAllocHelper,
20072009
};
20082010

20092011
struct IrInstruction {
@@ -2913,6 +2915,13 @@ struct IrInstructionCoroSave {
29132915
IrInstruction *coro_handle;
29142916
};
29152917

2918+
struct IrInstructionCoroAllocHelper {
2919+
IrInstruction base;
2920+
2921+
IrInstruction *alloc_fn;
2922+
IrInstruction *coro_size;
2923+
};
2924+
29162925
static const size_t slice_ptr_index = 0;
29172926
static const size_t slice_len_index = 1;
29182927

src/analyze.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1001,9 +1001,7 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
10011001
bool first_arg_return = calling_convention_does_first_arg_return(fn_type_id->cc) &&
10021002
handle_is_ptr(fn_type_id->return_type);
10031003
bool is_async = fn_type_id->cc == CallingConventionAsync;
1004-
bool prefix_arg_error_return_trace = g->have_err_ret_tracing &&
1005-
(fn_type_id->return_type->id == TypeTableEntryIdErrorUnion ||
1006-
fn_type_id->return_type->id == TypeTableEntryIdErrorSet);
1004+
bool prefix_arg_error_return_trace = g->have_err_ret_tracing && fn_type_can_fail(fn_type_id);
10071005
// +1 for maybe making the first argument the return value
10081006
// +1 for maybe first argument the error return trace
10091007
// +2 for maybe arguments async allocator and error code pointer
@@ -5795,3 +5793,9 @@ bool type_is_global_error_set(TypeTableEntry *err_set_type) {
57955793
uint32_t get_coro_frame_align_bytes(CodeGen *g) {
57965794
return g->pointer_size_bytes * 2;
57975795
}
5796+
5797+
bool fn_type_can_fail(FnTypeId *fn_type_id) {
5798+
TypeTableEntry *return_type = fn_type_id->return_type;
5799+
return return_type->id == TypeTableEntryIdErrorUnion || return_type->id == TypeTableEntryIdErrorSet ||
5800+
fn_type_id->cc == CallingConventionAsync;
5801+
}

src/analyze.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,5 +192,6 @@ void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry);
192192
TypeTableEntry *get_auto_err_set_type(CodeGen *g, FnTableEntry *fn_entry);
193193

194194
uint32_t get_coro_frame_align_bytes(CodeGen *g);
195+
bool fn_type_can_fail(FnTypeId *fn_type_id);
195196

196197
#endif

src/codegen.cpp

Lines changed: 141 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -412,10 +412,10 @@ static uint32_t get_err_ret_trace_arg_index(CodeGen *g, FnTableEntry *fn_table_e
412412
return UINT32_MAX;
413413
}
414414
TypeTableEntry *fn_type = fn_table_entry->type_entry;
415-
TypeTableEntry *return_type = fn_type->data.fn.fn_type_id.return_type;
416-
if (return_type->id != TypeTableEntryIdErrorUnion && return_type->id != TypeTableEntryIdErrorSet) {
415+
if (!fn_type_can_fail(&fn_type->data.fn.fn_type_id)) {
417416
return UINT32_MAX;
418417
}
418+
TypeTableEntry *return_type = fn_type->data.fn.fn_type_id.return_type;
419419
bool first_arg_ret = type_has_bits(return_type) && handle_is_ptr(return_type);
420420
return first_arg_ret ? 1 : 0;
421421
}
@@ -2662,21 +2662,23 @@ static LLVMValueRef ir_render_elem_ptr(CodeGen *g, IrExecutable *executable, IrI
26622662
}
26632663
}
26642664

2665-
static bool get_prefix_arg_err_ret_stack(CodeGen *g, TypeTableEntry *src_return_type) {
2665+
static bool get_prefix_arg_err_ret_stack(CodeGen *g, FnTypeId *fn_type_id) {
26662666
return g->have_err_ret_tracing &&
2667-
(src_return_type->id == TypeTableEntryIdErrorUnion || src_return_type->id == TypeTableEntryIdErrorSet);
2667+
(fn_type_id->return_type->id == TypeTableEntryIdErrorUnion ||
2668+
fn_type_id->return_type->id == TypeTableEntryIdErrorSet ||
2669+
fn_type_id->cc == CallingConventionAsync);
26682670
}
26692671

2670-
static size_t get_async_allocator_arg_index(CodeGen *g, TypeTableEntry *src_return_type) {
2672+
static size_t get_async_allocator_arg_index(CodeGen *g, FnTypeId *fn_type_id) {
26712673
// 0 1 2 3
26722674
// err_ret_stack allocator_ptr err_code other_args...
2673-
return get_prefix_arg_err_ret_stack(g, src_return_type) ? 1 : 0;
2675+
return get_prefix_arg_err_ret_stack(g, fn_type_id) ? 1 : 0;
26742676
}
26752677

2676-
static size_t get_async_err_code_arg_index(CodeGen *g, TypeTableEntry *src_return_type) {
2678+
static size_t get_async_err_code_arg_index(CodeGen *g, FnTypeId *fn_type_id) {
26772679
// 0 1 2 3
26782680
// err_ret_stack allocator_ptr err_code other_args...
2679-
return 1 + get_async_allocator_arg_index(g, src_return_type);
2681+
return 1 + get_async_allocator_arg_index(g, fn_type_id);
26802682
}
26812683

26822684
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
26982700

26992701
bool first_arg_ret = ret_has_bits && handle_is_ptr(src_return_type) &&
27002702
calling_convention_does_first_arg_return(fn_type->data.fn.fn_type_id.cc);
2701-
bool prefix_arg_err_ret_stack = get_prefix_arg_err_ret_stack(g, src_return_type);
2703+
bool prefix_arg_err_ret_stack = get_prefix_arg_err_ret_stack(g, fn_type_id);
27022704
// +2 for the async args
27032705
size_t actual_param_count = instruction->arg_count + (first_arg_ret ? 1 : 0) + (prefix_arg_err_ret_stack ? 1 : 0) + 2;
27042706
bool is_var_args = fn_type_id->is_var_args;
@@ -2717,7 +2719,6 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
27172719
gen_param_index += 1;
27182720

27192721
LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, err_union_err_index, "");
2720-
LLVMBuildStore(g->builder, LLVMConstNull(g->builtin_types.entry_global_error_set->type_ref), err_val_ptr);
27212722
gen_param_values[gen_param_index] = err_val_ptr;
27222723
gen_param_index += 1;
27232724
}
@@ -3293,8 +3294,7 @@ static LLVMValueRef ir_render_cancel(CodeGen *g, IrExecutable *executable, IrIns
32933294
static LLVMValueRef ir_render_get_implicit_allocator(CodeGen *g, IrExecutable *executable,
32943295
IrInstructionGetImplicitAllocator *instruction)
32953296
{
3296-
TypeTableEntry *src_return_type = g->cur_fn->type_entry->data.fn.fn_type_id.return_type;
3297-
size_t allocator_arg_index = get_async_allocator_arg_index(g, src_return_type);
3297+
size_t allocator_arg_index = get_async_allocator_arg_index(g, &g->cur_fn->type_entry->data.fn.fn_type_id);
32983298
return LLVMGetParam(g->cur_fn_val, allocator_arg_index);
32993299
}
33003300

@@ -3926,8 +3926,7 @@ static LLVMValueRef ir_render_coro_begin(CodeGen *g, IrExecutable *executable, I
39263926
static LLVMValueRef ir_render_coro_alloc_fail(CodeGen *g, IrExecutable *executable,
39273927
IrInstructionCoroAllocFail *instruction)
39283928
{
3929-
TypeTableEntry *src_return_type = g->cur_fn->type_entry->data.fn.fn_type_id.return_type;
3930-
size_t err_code_ptr_arg_index = get_async_err_code_arg_index(g, src_return_type);
3929+
size_t err_code_ptr_arg_index = get_async_err_code_arg_index(g, &g->cur_fn->type_entry->data.fn.fn_type_id);
39313930
LLVMValueRef err_code_ptr_val = LLVMGetParam(g->cur_fn_val, err_code_ptr_arg_index);
39323931
LLVMValueRef err_code = ir_llvm_value(g, instruction->err_val);
39333932
LLVMBuildStore(g->builder, err_code, err_code_ptr_val);
@@ -3985,6 +3984,132 @@ static LLVMValueRef ir_render_coro_save(CodeGen *g, IrExecutable *executable, Ir
39853984
return LLVMBuildCall(g->builder, get_coro_save_fn_val(g), &coro_handle, 1, "");
39863985
}
39873986

3987+
static LLVMValueRef get_coro_alloc_helper_fn_val(CodeGen *g, LLVMTypeRef alloc_fn_type_ref, TypeTableEntry *fn_type) {
3988+
if (g->coro_alloc_helper_fn_val != nullptr)
3989+
return g->coro_alloc_fn_val;
3990+
3991+
assert(fn_type->id == TypeTableEntryIdFn);
3992+
3993+
TypeTableEntry *ptr_to_err_code_type = get_pointer_to_type(g, g->builtin_types.entry_global_error_set, false);
3994+
3995+
LLVMTypeRef alloc_raw_fn_type_ref = LLVMGetElementType(alloc_fn_type_ref);
3996+
LLVMTypeRef *alloc_fn_arg_types = allocate<LLVMTypeRef>(LLVMCountParamTypes(alloc_raw_fn_type_ref));
3997+
LLVMGetParamTypes(alloc_raw_fn_type_ref, alloc_fn_arg_types);
3998+
3999+
ZigList<LLVMTypeRef> arg_types = {};
4000+
arg_types.append(alloc_fn_type_ref);
4001+
if (g->have_err_ret_tracing) {
4002+
arg_types.append(alloc_fn_arg_types[1]);
4003+
}
4004+
arg_types.append(alloc_fn_arg_types[g->have_err_ret_tracing ? 2 : 1]);
4005+
arg_types.append(ptr_to_err_code_type->type_ref);
4006+
arg_types.append(g->builtin_types.entry_usize->type_ref);
4007+
4008+
LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMPointerType(LLVMInt8Type(), 0),
4009+
arg_types.items, arg_types.length, false);
4010+
4011+
Buf *fn_name = get_mangled_name(g, buf_create_from_str("__zig_coro_alloc_helper"), false);
4012+
LLVMValueRef fn_val = LLVMAddFunction(g->module, buf_ptr(fn_name), fn_type_ref);
4013+
LLVMSetLinkage(fn_val, LLVMInternalLinkage);
4014+
LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified));
4015+
addLLVMFnAttr(fn_val, "nounwind");
4016+
addLLVMArgAttr(fn_val, (unsigned)0, "nonnull");
4017+
addLLVMArgAttr(fn_val, (unsigned)1, "nonnull");
4018+
4019+
LLVMBasicBlockRef prev_block = LLVMGetInsertBlock(g->builder);
4020+
LLVMValueRef prev_debug_location = LLVMGetCurrentDebugLocation(g->builder);
4021+
FnTableEntry *prev_cur_fn = g->cur_fn;
4022+
LLVMValueRef prev_cur_fn_val = g->cur_fn_val;
4023+
4024+
LLVMBasicBlockRef entry_block = LLVMAppendBasicBlock(fn_val, "Entry");
4025+
LLVMPositionBuilderAtEnd(g->builder, entry_block);
4026+
ZigLLVMClearCurrentDebugLocation(g->builder);
4027+
g->cur_fn = nullptr;
4028+
g->cur_fn_val = fn_val;
4029+
4030+
LLVMValueRef sret_ptr = LLVMBuildAlloca(g->builder, LLVMGetElementType(alloc_fn_arg_types[0]), "");
4031+
4032+
size_t next_arg = 0;
4033+
LLVMValueRef alloc_fn_val = LLVMGetParam(fn_val, next_arg);
4034+
next_arg += 1;
4035+
4036+
LLVMValueRef stack_trace_val;
4037+
if (g->have_err_ret_tracing) {
4038+
stack_trace_val = LLVMGetParam(fn_val, next_arg);
4039+
next_arg += 1;
4040+
}
4041+
4042+
LLVMValueRef allocator_val = LLVMGetParam(fn_val, next_arg);
4043+
next_arg += 1;
4044+
LLVMValueRef err_code_ptr = LLVMGetParam(fn_val, next_arg);
4045+
next_arg += 1;
4046+
LLVMValueRef coro_size = LLVMGetParam(fn_val, next_arg);
4047+
next_arg += 1;
4048+
LLVMValueRef alignment_val = LLVMConstInt(g->builtin_types.entry_u29->type_ref,
4049+
2 * g->pointer_size_bytes, false);
4050+
4051+
ZigList<LLVMValueRef> args = {};
4052+
args.append(sret_ptr);
4053+
if (g->have_err_ret_tracing) {
4054+
args.append(stack_trace_val);
4055+
}
4056+
args.append(allocator_val);
4057+
args.append(coro_size);
4058+
args.append(alignment_val);
4059+
ZigLLVMBuildCall(g->builder, alloc_fn_val, args.items, args.length,
4060+
get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, "");
4061+
LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, sret_ptr, err_union_err_index, "");
4062+
LLVMValueRef err_val = LLVMBuildLoad(g->builder, err_val_ptr, "");
4063+
LLVMBuildStore(g->builder, err_val, err_code_ptr);
4064+
LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, err_val, LLVMConstNull(LLVMTypeOf(err_val)), "");
4065+
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(fn_val, "AllocOk");
4066+
LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(fn_val, "AllocFail");
4067+
LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block);
4068+
4069+
LLVMPositionBuilderAtEnd(g->builder, ok_block);
4070+
LLVMValueRef payload_ptr = LLVMBuildStructGEP(g->builder, sret_ptr, err_union_payload_index, "");
4071+
TypeTableEntry *u8_ptr_type = get_pointer_to_type(g, g->builtin_types.entry_u8, false);
4072+
TypeTableEntry *slice_type = get_slice_type(g, u8_ptr_type);
4073+
size_t ptr_field_index = slice_type->data.structure.fields[slice_ptr_index].gen_index;
4074+
LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, payload_ptr, ptr_field_index, "");
4075+
LLVMValueRef ptr_val = LLVMBuildLoad(g->builder, ptr_field_ptr, "");
4076+
LLVMBuildRet(g->builder, ptr_val);
4077+
4078+
LLVMPositionBuilderAtEnd(g->builder, fail_block);
4079+
LLVMBuildRet(g->builder, LLVMConstNull(LLVMPointerType(LLVMInt8Type(), 0)));
4080+
4081+
g->cur_fn = prev_cur_fn;
4082+
g->cur_fn_val = prev_cur_fn_val;
4083+
LLVMPositionBuilderAtEnd(g->builder, prev_block);
4084+
LLVMSetCurrentDebugLocation(g->builder, prev_debug_location);
4085+
4086+
g->coro_alloc_helper_fn_val = fn_val;
4087+
return fn_val;
4088+
}
4089+
4090+
static LLVMValueRef ir_render_coro_alloc_helper(CodeGen *g, IrExecutable *executable,
4091+
IrInstructionCoroAllocHelper *instruction)
4092+
{
4093+
LLVMValueRef alloc_fn = ir_llvm_value(g, instruction->alloc_fn);
4094+
LLVMValueRef coro_size = ir_llvm_value(g, instruction->coro_size);
4095+
LLVMValueRef fn_val = get_coro_alloc_helper_fn_val(g, LLVMTypeOf(alloc_fn), instruction->alloc_fn->value.type);
4096+
size_t err_code_ptr_arg_index = get_async_err_code_arg_index(g, &g->cur_fn->type_entry->data.fn.fn_type_id);
4097+
size_t allocator_arg_index = get_async_allocator_arg_index(g, &g->cur_fn->type_entry->data.fn.fn_type_id);
4098+
4099+
ZigList<LLVMValueRef> params = {};
4100+
params.append(alloc_fn);
4101+
uint32_t err_ret_trace_arg_index = get_err_ret_trace_arg_index(g, g->cur_fn);
4102+
if (err_ret_trace_arg_index != UINT32_MAX) {
4103+
params.append(LLVMGetParam(g->cur_fn_val, err_ret_trace_arg_index));
4104+
}
4105+
params.append(LLVMGetParam(g->cur_fn_val, allocator_arg_index));
4106+
params.append(LLVMGetParam(g->cur_fn_val, err_code_ptr_arg_index));
4107+
params.append(coro_size);
4108+
4109+
return ZigLLVMBuildCall(g->builder, fn_val, params.items, params.length,
4110+
get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, "");
4111+
}
4112+
39884113
static void set_debug_location(CodeGen *g, IrInstruction *instruction) {
39894114
AstNode *source_node = instruction->source_node;
39904115
Scope *scope = instruction->scope;
@@ -4190,6 +4315,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
41904315
return ir_render_coro_resume(g, executable, (IrInstructionCoroResume *)instruction);
41914316
case IrInstructionIdCoroSave:
41924317
return ir_render_coro_save(g, executable, (IrInstructionCoroSave *)instruction);
4318+
case IrInstructionIdCoroAllocHelper:
4319+
return ir_render_coro_alloc_helper(g, executable, (IrInstructionCoroAllocHelper *)instruction);
41934320
}
41944321
zig_unreachable();
41954322
}

0 commit comments

Comments
 (0)