Browse Source

Improve multiple return value copy-elision

gingerBill 4 years ago
parent
commit
feeb342c00
4 changed files with 96 additions and 49 deletions
  1. 0 9
      src/check_type.cpp
  2. 17 17
      src/ir.cpp
  3. 68 23
      src/llvm_backend.cpp
  4. 11 0
      src/types.cpp

+ 0 - 9
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;

+ 17 - 17
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);
 				}
 			}
 		}

+ 68 - 23
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));
 	{

+ 11 - 0
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, "<no type>");