From feeb342c009022b3de6f903ef1e3cc40b54951ca Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 20 Oct 2020 17:08:55 +0100 Subject: [PATCH] Improve multiple return value copy-elision --- src/check_type.cpp | 9 ----- src/ir.cpp | 34 ++++++++--------- src/llvm_backend.cpp | 91 +++++++++++++++++++++++++++++++++----------- src/types.cpp | 11 ++++++ 4 files changed, 96 insertions(+), 49 deletions(-) diff --git a/src/check_type.cpp b/src/check_type.cpp index d305d6859..4d1359848 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -2318,15 +2318,6 @@ Type *type_to_abi_compat_param_type(gbAllocator a, Type *original_type, ProcCall return new_type; } -Type *reduce_tuple_to_single_type(Type *original_type) { - if (original_type != nullptr) { - Type *t = core_type(original_type); - if (t->kind == Type_Tuple && t->Tuple.variables.count == 1) { - return t->Tuple.variables[0]->type; - } - } - return original_type; -} Type *type_to_abi_compat_result_type(gbAllocator a, Type *original_type, ProcCallingConvention cc) { Type *new_type = original_type; diff --git a/src/ir.cpp b/src/ir.cpp index dad33762f..58f6b1799 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -11296,30 +11296,30 @@ void ir_begin_procedure_body(irProcedure *proc) { if (proc->type->Proc.has_named_results) { GB_ASSERT(proc->type->Proc.result_count > 0); TypeTuple *results = &proc->type->Proc.results->Tuple; + for_array(i, results->variables) { Entity *e = results->variables[i]; - if (e->kind != Entity_Variable) { - continue; - } + GB_ASSERT(e->kind == Entity_Variable); if (e->token.string != "") { GB_ASSERT(!is_blank_ident(e->token)); - irValue *res = ir_add_local(proc, e, e->identifier, true); - irValue *c = nullptr; - switch (e->Variable.param_value.kind) { - case ParameterValue_Constant: - c = ir_value_constant(e->type, e->Variable.param_value.value); - break; - case ParameterValue_Nil: - c = ir_value_nil(e->type); - break; - case ParameterValue_Location: - GB_PANIC("ParameterValue_Location"); - break; + irAddr res = {}; + if (proc->type->Proc.return_by_pointer) { + irValue *ptr = proc->return_ptr; + if (results->variables.count != 1) { + ptr = ir_emit_struct_ep(proc, ptr, cast(i32)i); + } + + res = ir_addr(ptr); + ir_module_add_value(proc->module, e, ptr); + } else { + res = ir_addr(ir_add_local(proc, e, e->identifier, true)); } - if (c != nullptr) { - ir_emit_store(proc, res, c); + + if (e->Variable.param_value.kind != ParameterValue_Invalid) { + irValue *c = ir_handle_param_value(proc, e->type, e->Variable.param_value, e->token.pos); + ir_addr_store(proc, res, c); } } } diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 904b07f23..8052bf759 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -2430,15 +2430,16 @@ void lb_begin_procedure_body(lbProcedure *p) { i32 parameter_index = 0; + + lbValue return_ptr_value = {}; if (p->type->Proc.return_by_pointer) { // NOTE(bill): this must be parameter 0 Type *ptr_type = alloc_type_pointer(reduce_tuple_to_single_type(p->type->Proc.results)); Entity *e = alloc_entity_param(nullptr, make_token_ident(str_lit("agg.result")), ptr_type, false, false); e->flags |= EntityFlag_Sret | EntityFlag_NoAlias; - lbValue return_ptr_value = {}; return_ptr_value.value = LLVMGetParam(p->value, 0); - return_ptr_value.type = alloc_type_pointer(p->type->Proc.abi_compat_result_type); + return_ptr_value.type = ptr_type; p->return_ptr = lb_addr(return_ptr_value); lb_add_entity(p->module, e, return_ptr_value); @@ -2475,37 +2476,31 @@ void lb_begin_procedure_body(lbProcedure *p) { GB_ASSERT(p->type->Proc.result_count > 0); TypeTuple *results = &p->type->Proc.results->Tuple; - isize result_index = 0; - for_array(i, results->variables) { Entity *e = results->variables[i]; - if (e->kind != Entity_Variable) { - continue; - } + GB_ASSERT(e->kind == Entity_Variable); if (e->token.string != "") { GB_ASSERT(!is_blank_ident(e->token)); - lbAddr res = lb_add_local(p, e->type, e); + lbAddr res = {}; + if (p->type->Proc.return_by_pointer) { + lbValue ptr = return_ptr_value; + if (results->variables.count != 1) { + ptr = lb_emit_struct_ep(p, ptr, cast(i32)i); + } - lbValue c = {}; - switch (e->Variable.param_value.kind) { - case ParameterValue_Constant: - c = lb_const_value(p->module, e->type, e->Variable.param_value.value); - break; - case ParameterValue_Nil: - c = lb_const_nil(p->module, e->type); - break; - case ParameterValue_Location: - GB_PANIC("ParameterValue_Location"); - break; + res = lb_addr(ptr); + lb_add_entity(p->module, e, ptr); + } else { + res = lb_add_local(p, e->type, e); } - if (c.value != nullptr) { + + if (e->Variable.param_value.kind != ParameterValue_Invalid) { + lbValue c = lb_handle_param_value(p, e->type, e->Variable.param_value, e->token.pos); lb_addr_store(p, res, c); } } - - result_index += 1; } } @@ -12188,7 +12183,7 @@ void lb_generate_code(lbGenerator *gen) { LLVMPassManagerRef default_function_pass_manager = LLVMCreateFunctionPassManagerForModule(mod); defer (LLVMDisposePassManager(default_function_pass_manager)); - { + /*{ LLVMAddMemCpyOptPass(default_function_pass_manager); LLVMAddPromoteMemoryToRegisterPass(default_function_pass_manager); LLVMAddMergedLoadStoreMotionPass(default_function_pass_manager); @@ -12219,8 +12214,58 @@ void lb_generate_code(lbGenerator *gen) { LLVMAddLoopVectorizePass(default_function_pass_manager); } + }*/ + if (build_context.optimization_level == 0 && false) { + auto dfpm = default_function_pass_manager; + + LLVMAddMemCpyOptPass(dfpm); + LLVMAddPromoteMemoryToRegisterPass(dfpm); + LLVMAddMergedLoadStoreMotionPass(dfpm); + LLVMAddAggressiveInstCombinerPass(dfpm); + LLVMAddConstantPropagationPass(dfpm); + LLVMAddAggressiveDCEPass(dfpm); + LLVMAddMergedLoadStoreMotionPass(dfpm); + LLVMAddPromoteMemoryToRegisterPass(dfpm); + LLVMAddCFGSimplificationPass(dfpm); + LLVMAddScalarizerPass(dfpm); + } else { + auto dfpm = default_function_pass_manager; + + LLVMAddMemCpyOptPass(dfpm); + LLVMAddPromoteMemoryToRegisterPass(dfpm); + LLVMAddMergedLoadStoreMotionPass(dfpm); + LLVMAddAggressiveInstCombinerPass(dfpm); + LLVMAddConstantPropagationPass(dfpm); + LLVMAddAggressiveDCEPass(dfpm); + LLVMAddMergedLoadStoreMotionPass(dfpm); + LLVMAddPromoteMemoryToRegisterPass(dfpm); + LLVMAddCFGSimplificationPass(dfpm); + + + // LLVMAddInstructionCombiningPass(dfpm); + LLVMAddSLPVectorizePass(dfpm); + LLVMAddLoopVectorizePass(dfpm); + LLVMAddEarlyCSEPass(dfpm); + LLVMAddEarlyCSEMemSSAPass(dfpm); + + LLVMAddScalarizerPass(dfpm); + LLVMAddLoopIdiomPass(dfpm); + + // LLVMAddAggressiveInstCombinerPass(dfpm); + // LLVMAddLowerExpectIntrinsicPass(dfpm); + + // LLVMAddPartiallyInlineLibCallsPass(dfpm); + + // LLVMAddAlignmentFromAssumptionsPass(dfpm); + // LLVMAddDeadStoreEliminationPass(dfpm); + // LLVMAddReassociatePass(dfpm); + // LLVMAddAddDiscriminatorsPass(dfpm); + // LLVMAddPromoteMemoryToRegisterPass(dfpm); + // LLVMAddCorrelatedValuePropagationPass(dfpm); + // LLVMAddMemCpyOptPass(dfpm); } + LLVMPassManagerRef default_function_pass_manager_without_memcpy = LLVMCreateFunctionPassManagerForModule(mod); defer (LLVMDisposePassManager(default_function_pass_manager_without_memcpy)); { diff --git a/src/types.cpp b/src/types.cpp index 5e696eaa7..03e071045 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -3338,6 +3338,17 @@ Type *get_struct_field_type(Type *t, isize index) { } +Type *reduce_tuple_to_single_type(Type *original_type) { + if (original_type != nullptr) { + Type *t = core_type(original_type); + if (t->kind == Type_Tuple && t->Tuple.variables.count == 1) { + return t->Tuple.variables[0]->type; + } + } + return original_type; +} + + gbString write_type_to_string(gbString str, Type *type) { if (type == nullptr) { return gb_string_appendc(str, "");