llvm coroutine workaround: sret functions return sret pointer

This commit is contained in:
Andrew Kelley 2018-02-27 17:12:53 -05:00
parent 6e2a67724c
commit 132e604aa3
2 changed files with 14 additions and 4 deletions

View File

@ -1026,7 +1026,10 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
gen_param_index += 1; gen_param_index += 1;
// after the gen_param_index += 1 because 0 is the return type // after the gen_param_index += 1 because 0 is the return type
param_di_types[gen_param_index] = gen_type->di_type; param_di_types[gen_param_index] = gen_type->di_type;
gen_return_type = g->builtin_types.entry_void;
// as a workaround for LLVM coroutines not understanding instruction dependencies,
// we return the sret pointer argument instead of returning void
gen_return_type = gen_type;
} else { } else {
gen_return_type = fn_type_id->return_type; gen_return_type = fn_type_id->return_type;
} }

View File

@ -547,7 +547,10 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {
} else if (handle_is_ptr(return_type) && } else if (handle_is_ptr(return_type) &&
calling_convention_does_first_arg_return(fn_type->data.fn.fn_type_id.cc)) calling_convention_does_first_arg_return(fn_type->data.fn.fn_type_id.cc))
{ {
addLLVMArgAttr(fn_table_entry->llvm_value, 0, "sret"); // We do not add the sret attribute, because it would require the return type to be void,
// and we want the return value to return the sret pointer, to work around LLVM Coroutine
// transformation passes not understanding the data dependency.
//addLLVMArgAttr(fn_table_entry->llvm_value, 0, "sret");
addLLVMArgAttr(fn_table_entry->llvm_value, 0, "nonnull"); addLLVMArgAttr(fn_table_entry->llvm_value, 0, "nonnull");
} }
@ -1616,7 +1619,9 @@ static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrIns
if (calling_convention_does_first_arg_return(g->cur_fn->type_entry->data.fn.fn_type_id.cc)) { if (calling_convention_does_first_arg_return(g->cur_fn->type_entry->data.fn.fn_type_id.cc)) {
assert(g->cur_ret_ptr); assert(g->cur_ret_ptr);
gen_assign_raw(g, g->cur_ret_ptr, get_pointer_to_type(g, return_type, false), value); gen_assign_raw(g, g->cur_ret_ptr, get_pointer_to_type(g, return_type, false), value);
LLVMBuildRetVoid(g->builder); // as a workaround for LLVM coroutines not understanding instruction dependencies,
// we return the sret pointer argument instead of returning void
LLVMBuildRet(g->builder, g->cur_ret_ptr);
} else { } else {
LLVMValueRef by_val_value = gen_load_untyped(g, value, 0, false, ""); LLVMValueRef by_val_value = gen_load_untyped(g, value, 0, false, "");
LLVMBuildRet(g->builder, by_val_value); LLVMBuildRet(g->builder, by_val_value);
@ -2775,7 +2780,9 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
} else if (!ret_has_bits) { } else if (!ret_has_bits) {
return nullptr; return nullptr;
} else if (first_arg_ret) { } else if (first_arg_ret) {
return instruction->tmp_ptr; // instead of returning instruction->tmp_ptr here, we trust that the function returned the first arg.
// this is a workaround for llvm coroutines not understanding the data dependency
return result;
} else { } else {
return result; return result;
} }