Skip to content

Commit 132e604

Browse files
committed
llvm coroutine workaround: sret functions return sret pointer
1 parent 6e2a677 commit 132e604

File tree

2 files changed

+14
-4
lines changed

2 files changed

+14
-4
lines changed

src/analyze.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1026,7 +1026,10 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
10261026
gen_param_index += 1;
10271027
// after the gen_param_index += 1 because 0 is the return type
10281028
param_di_types[gen_param_index] = gen_type->di_type;
1029-
gen_return_type = g->builtin_types.entry_void;
1029+
1030+
// as a workaround for LLVM coroutines not understanding instruction dependencies,
1031+
// we return the sret pointer argument instead of returning void
1032+
gen_return_type = gen_type;
10301033
} else {
10311034
gen_return_type = fn_type_id->return_type;
10321035
}

src/codegen.cpp

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -547,7 +547,10 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {
547547
} else if (handle_is_ptr(return_type) &&
548548
calling_convention_does_first_arg_return(fn_type->data.fn.fn_type_id.cc))
549549
{
550-
addLLVMArgAttr(fn_table_entry->llvm_value, 0, "sret");
550+
// We do not add the sret attribute, because it would require the return type to be void,
551+
// and we want the return value to return the sret pointer, to work around LLVM Coroutine
552+
// transformation passes not understanding the data dependency.
553+
//addLLVMArgAttr(fn_table_entry->llvm_value, 0, "sret");
551554
addLLVMArgAttr(fn_table_entry->llvm_value, 0, "nonnull");
552555
}
553556

@@ -1616,7 +1619,9 @@ static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrIns
16161619
if (calling_convention_does_first_arg_return(g->cur_fn->type_entry->data.fn.fn_type_id.cc)) {
16171620
assert(g->cur_ret_ptr);
16181621
gen_assign_raw(g, g->cur_ret_ptr, get_pointer_to_type(g, return_type, false), value);
1619-
LLVMBuildRetVoid(g->builder);
1622+
// as a workaround for LLVM coroutines not understanding instruction dependencies,
1623+
// we return the sret pointer argument instead of returning void
1624+
LLVMBuildRet(g->builder, g->cur_ret_ptr);
16201625
} else {
16211626
LLVMValueRef by_val_value = gen_load_untyped(g, value, 0, false, "");
16221627
LLVMBuildRet(g->builder, by_val_value);
@@ -2775,7 +2780,9 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
27752780
} else if (!ret_has_bits) {
27762781
return nullptr;
27772782
} else if (first_arg_ret) {
2778-
return instruction->tmp_ptr;
2783+
// instead of returning instruction->tmp_ptr here, we trust that the function returned the first arg.
2784+
// this is a workaround for llvm coroutines not understanding the data dependency
2785+
return result;
27792786
} else {
27802787
return result;
27812788
}

0 commit comments

Comments
 (0)