Browse Source

Prepare to multithread object generation

gingerBill 4 years ago
parent
commit
a5eea97edb
3 changed files with 119 additions and 25 deletions
  1. 116 22
      src/llvm_backend.cpp
  2. 2 2
      src/llvm_backend.hpp
  3. 1 1
      src/main.cpp

+ 116 - 22
src/llvm_backend.cpp

@@ -2,6 +2,11 @@
 #define USE_SEPARTE_MODULES build_context.use_separate_modules
 #define USE_SEPARTE_MODULES build_context.use_separate_modules
 #endif
 #endif
 
 
+#ifndef MULTITHREAD_OBJECT_GENERATION
+#define MULTITHREAD_OBJECT_GENERATION 0
+#endif
+
+
 #include "llvm_backend.hpp"
 #include "llvm_backend.hpp"
 #include "llvm_abi.cpp"
 #include "llvm_abi.cpp"
 #include "llvm_backend_opt.cpp"
 #include "llvm_backend_opt.cpp"
@@ -13026,7 +13031,6 @@ void lb_init_module(lbModule *m, Checker *c) {
 		m->debug_builder = LLVMCreateDIBuilder(m->mod);
 		m->debug_builder = LLVMCreateDIBuilder(m->mod);
 	}
 	}
 
 
-	gb_mutex_init(&m->mutex);
 	gbAllocator a = heap_allocator();
 	gbAllocator a = heap_allocator();
 	map_init(&m->types, a);
 	map_init(&m->types, a);
 	map_init(&m->llvm_types, a);
 	map_init(&m->llvm_types, a);
@@ -13098,6 +13102,8 @@ bool lb_init_generator(lbGenerator *gen, Checker *c) {
 	map_init(&gen->modules, permanent_allocator(), gen->info->packages.entries.count*2);
 	map_init(&gen->modules, permanent_allocator(), gen->info->packages.entries.count*2);
 	map_init(&gen->modules_through_ctx, permanent_allocator(), gen->info->packages.entries.count*2);
 	map_init(&gen->modules_through_ctx, permanent_allocator(), gen->info->packages.entries.count*2);
 
 
+	gb_mutex_init(&gen->mutex);
+
 	if (USE_SEPARTE_MODULES) {
 	if (USE_SEPARTE_MODULES) {
 		for_array(i, gen->info->packages.entries) {
 		for_array(i, gen->info->packages.entries) {
 			AstPackage *pkg = gen->info->packages.entries[i].value;
 			AstPackage *pkg = gen->info->packages.entries[i].value;
@@ -13945,7 +13951,6 @@ struct lbGlobalVariable {
 
 
 lbProcedure *lb_create_startup_type_info(lbModule *m) {
 lbProcedure *lb_create_startup_type_info(lbModule *m) {
 	LLVMPassManagerRef default_function_pass_manager = LLVMCreateFunctionPassManagerForModule(m->mod);
 	LLVMPassManagerRef default_function_pass_manager = LLVMCreateFunctionPassManagerForModule(m->mod);
-	defer (LLVMDisposePassManager(default_function_pass_manager));
 	lb_populate_function_pass_manager(default_function_pass_manager, false, build_context.optimization_level);
 	lb_populate_function_pass_manager(default_function_pass_manager, false, build_context.optimization_level);
 	LLVMFinalizeFunctionPassManager(default_function_pass_manager);
 	LLVMFinalizeFunctionPassManager(default_function_pass_manager);
 
 
@@ -13977,7 +13982,6 @@ lbProcedure *lb_create_startup_type_info(lbModule *m) {
 
 
 lbProcedure *lb_create_startup_runtime(lbModule *main_module, lbProcedure *startup_type_info, Array<lbGlobalVariable> &global_variables) { // Startup Runtime
 lbProcedure *lb_create_startup_runtime(lbModule *main_module, lbProcedure *startup_type_info, Array<lbGlobalVariable> &global_variables) { // Startup Runtime
 	LLVMPassManagerRef default_function_pass_manager = LLVMCreateFunctionPassManagerForModule(main_module->mod);
 	LLVMPassManagerRef default_function_pass_manager = LLVMCreateFunctionPassManagerForModule(main_module->mod);
-	defer (LLVMDisposePassManager(default_function_pass_manager));
 	lb_populate_function_pass_manager(default_function_pass_manager, false, build_context.optimization_level);
 	lb_populate_function_pass_manager(default_function_pass_manager, false, build_context.optimization_level);
 	LLVMFinalizeFunctionPassManager(default_function_pass_manager);
 	LLVMFinalizeFunctionPassManager(default_function_pass_manager);
 
 
@@ -14068,7 +14072,6 @@ lbProcedure *lb_create_startup_runtime(lbModule *main_module, lbProcedure *start
 
 
 lbProcedure *lb_create_main_procedure(lbModule *m, lbProcedure *startup_runtime) {
 lbProcedure *lb_create_main_procedure(lbModule *m, lbProcedure *startup_runtime) {
 	LLVMPassManagerRef default_function_pass_manager = LLVMCreateFunctionPassManagerForModule(m->mod);
 	LLVMPassManagerRef default_function_pass_manager = LLVMCreateFunctionPassManagerForModule(m->mod);
-	defer (LLVMDisposePassManager(default_function_pass_manager));
 	lb_populate_function_pass_manager(default_function_pass_manager, false, build_context.optimization_level);
 	lb_populate_function_pass_manager(default_function_pass_manager, false, build_context.optimization_level);
 	LLVMFinalizeFunctionPassManager(default_function_pass_manager);
 	LLVMFinalizeFunctionPassManager(default_function_pass_manager);
 
 
@@ -14221,6 +14224,67 @@ String lb_filepath_obj_for_module(lbModule *m) {
 }
 }
 
 
 
 
+bool lb_is_module_empty(lbModule *m) {
+	if (LLVMGetFirstFunction(m->mod) == nullptr &&
+	    LLVMGetFirstGlobal(m->mod) == nullptr) {
+		return true;
+	}
+	for (auto fn = LLVMGetFirstFunction(m->mod); fn != nullptr; fn = LLVMGetNextFunction(fn)) {
+		if (LLVMGetFirstBasicBlock(fn) != nullptr) {
+			return false;
+		}
+	}
+
+	for (auto g = LLVMGetFirstGlobal(m->mod); g != nullptr; g = LLVMGetNextGlobal(g)) {
+		if (LLVMGetLinkage(g) == LLVMExternalLinkage) {
+			continue;
+		}
+		if (!LLVMIsExternallyInitialized(g)) {
+			return false;
+		}
+	}
+	return true;
+}
+
+struct lbLLVMEmitWorker {
+	LLVMTargetMachineRef target_machine;
+	LLVMCodeGenFileType code_gen_file_type;
+	String filepath_obj;
+	lbModule *m;
+};
+
+WORKER_TASK_PROC(lb_llvm_emit_worker_proc) {
+	GB_ASSERT(MULTITHREAD_OBJECT_GENERATION);
+
+	char *llvm_error = nullptr;
+
+	auto wd = cast(lbLLVMEmitWorker *)data;
+	gbMutex *mutex = &wd->m->gen->mutex;
+
+
+#if 1
+	gb_mutex_lock(mutex);
+	defer (gb_mutex_unlock(mutex));
+	if (LLVMTargetMachineEmitToFile(wd->target_machine, wd->m->mod, cast(char *)wd->filepath_obj.text, wd->code_gen_file_type, &llvm_error)) {
+		gb_printf_err("LLVM Error: %s\n", llvm_error);
+		gb_exit(1);
+		return 1;
+	}
+#else
+	LLVMMemoryBufferRef mem_buf = nullptr;
+
+	if (LLVMTargetMachineEmitToMemoryBuffer(wd->target_machine, wd->m->mod, wd->code_gen_file_type, &llvm_error, &mem_buf)) {
+		gb_printf_err("LLVM Error: %s\n", llvm_error);
+		gb_exit(1);
+		return 1;
+	}
+#endif
+
+	return 0;
+}
+
+
+
 void lb_generate_code(lbGenerator *gen) {
 void lb_generate_code(lbGenerator *gen) {
 	#define TIME_SECTION(str) do { if (build_context.show_more_timings) timings_start_section(&global_timings, str_lit(str)); } while (0)
 	#define TIME_SECTION(str) do { if (build_context.show_more_timings) timings_start_section(&global_timings, str_lit(str)); } while (0)
 
 
@@ -14728,10 +14792,6 @@ void lb_generate_code(lbGenerator *gen) {
 		LLVMPassManagerRef function_pass_manager_minimal = LLVMCreateFunctionPassManagerForModule(m->mod);
 		LLVMPassManagerRef function_pass_manager_minimal = LLVMCreateFunctionPassManagerForModule(m->mod);
 		LLVMPassManagerRef function_pass_manager_size = LLVMCreateFunctionPassManagerForModule(m->mod);
 		LLVMPassManagerRef function_pass_manager_size = LLVMCreateFunctionPassManagerForModule(m->mod);
 		LLVMPassManagerRef function_pass_manager_speed = LLVMCreateFunctionPassManagerForModule(m->mod);
 		LLVMPassManagerRef function_pass_manager_speed = LLVMCreateFunctionPassManagerForModule(m->mod);
-		defer (LLVMDisposePassManager(default_function_pass_manager));
-		defer (LLVMDisposePassManager(function_pass_manager_minimal));
-		defer (LLVMDisposePassManager(function_pass_manager_size));
-		defer (LLVMDisposePassManager(function_pass_manager_speed));
 
 
 		LLVMInitializeFunctionPassManager(default_function_pass_manager);
 		LLVMInitializeFunctionPassManager(default_function_pass_manager);
 		LLVMInitializeFunctionPassManager(function_pass_manager_minimal);
 		LLVMInitializeFunctionPassManager(function_pass_manager_minimal);
@@ -14750,7 +14810,6 @@ void lb_generate_code(lbGenerator *gen) {
 
 
 
 
 		LLVMPassManagerRef default_function_pass_manager_without_memcpy = LLVMCreateFunctionPassManagerForModule(m->mod);
 		LLVMPassManagerRef default_function_pass_manager_without_memcpy = LLVMCreateFunctionPassManagerForModule(m->mod);
-		defer (LLVMDisposePassManager(default_function_pass_manager_without_memcpy));
 		LLVMInitializeFunctionPassManager(default_function_pass_manager_without_memcpy);
 		LLVMInitializeFunctionPassManager(default_function_pass_manager_without_memcpy);
 		lb_populate_function_pass_manager(default_function_pass_manager_without_memcpy, true, build_context.optimization_level);
 		lb_populate_function_pass_manager(default_function_pass_manager_without_memcpy, true, build_context.optimization_level);
 		LLVMFinalizeFunctionPassManager(default_function_pass_manager_without_memcpy);
 		LLVMFinalizeFunctionPassManager(default_function_pass_manager_without_memcpy);
@@ -14798,7 +14857,6 @@ void lb_generate_code(lbGenerator *gen) {
 	TIME_SECTION("LLVM Module Pass");
 	TIME_SECTION("LLVM Module Pass");
 
 
 	LLVMPassManagerRef module_pass_manager = LLVMCreatePassManager();
 	LLVMPassManagerRef module_pass_manager = LLVMCreatePassManager();
-	defer (LLVMDisposePassManager(module_pass_manager));
 	lb_populate_module_pass_manager(target_machine, module_pass_manager, build_context.optimization_level);
 	lb_populate_module_pass_manager(target_machine, module_pass_manager, build_context.optimization_level);
 
 
 	for_array(i, gen->modules.entries) {
 	for_array(i, gen->modules.entries) {
@@ -14839,8 +14897,7 @@ void lb_generate_code(lbGenerator *gen) {
 		for_array(j, gen->modules.entries) {
 		for_array(j, gen->modules.entries) {
 			lbModule *m = gen->modules.entries[j].value;
 			lbModule *m = gen->modules.entries[j].value;
 
 
-			if (LLVMGetFirstFunction(m->mod) == nullptr &&
-			    LLVMGetFirstGlobal(m->mod) == nullptr) {
+			if (lb_is_module_empty(m)) {
 				continue;
 				continue;
 			}
 			}
 
 
@@ -14859,8 +14916,8 @@ void lb_generate_code(lbGenerator *gen) {
 		}
 		}
 	}
 	}
 
 
-	TIME_SECTION("LLVM Object Generation");
 
 
+	TIME_SECTION("LLVM Add Foreign Library Paths");
 	for_array(j, gen->modules.entries) {
 	for_array(j, gen->modules.entries) {
 		lbModule *m = gen->modules.entries[j].value;
 		lbModule *m = gen->modules.entries[j].value;
 		for_array(i, m->info->required_foreign_imports_through_force) {
 		for_array(i, m->info->required_foreign_imports_through_force) {
@@ -14868,23 +14925,60 @@ void lb_generate_code(lbGenerator *gen) {
 			lb_add_foreign_library_path(m, e);
 			lb_add_foreign_library_path(m, e);
 		}
 		}
 
 
-		if (LLVMGetFirstFunction(m->mod) == nullptr &&
-		    LLVMGetFirstGlobal(m->mod) == nullptr) {
+		if (lb_is_module_empty(m)) {
 			continue;
 			continue;
 		}
 		}
+	}
 
 
-		String filepath_obj = lb_filepath_obj_for_module(m);
+	TIME_SECTION("LLVM Object Generation");
 
 
-		if (LLVMTargetMachineEmitToFile(target_machine, m->mod, cast(char *)filepath_obj.text, code_gen_file_type, &llvm_error)) {
-			gb_printf_err("LLVM Error: %s\n", llvm_error);
-			gb_exit(1);
-			return;
+	isize thread_count = gb_max(build_context.thread_count, 1);
+	isize worker_count = thread_count-1;
+	if (USE_SEPARTE_MODULES && MULTITHREAD_OBJECT_GENERATION && worker_count > 0) {
+		ThreadPool pool = {};
+		thread_pool_init(&pool, heap_allocator(), worker_count, "LLVMEmitWork");
+		defer (thread_pool_destroy(&pool));
+
+		for_array(j, gen->modules.entries) {
+			lbModule *m = gen->modules.entries[j].value;
+			if (lb_is_module_empty(m)) {
+				continue;
+			}
+			String filepath_ll = lb_filepath_ll_for_module(m);
+			String filepath_obj = lb_filepath_obj_for_module(m);
+			array_add(&gen->output_object_paths, filepath_obj);
+			array_add(&gen->output_temp_paths, filepath_ll);
+
+			auto *wd = gb_alloc_item(heap_allocator(), lbLLVMEmitWorker);
+			wd->target_machine = target_machine;
+			wd->code_gen_file_type = code_gen_file_type;
+			wd->filepath_obj = filepath_obj;
+			wd->m = m;
+
+			thread_pool_add_task(&pool, lb_llvm_emit_worker_proc, wd);
 		}
 		}
 
 
-		array_add(&gen->output_object_paths, filepath_obj);
+		thread_pool_start(&pool);
+		thread_pool_wait_to_process(&pool);
+	} else {
+		for_array(j, gen->modules.entries) {
+			lbModule *m = gen->modules.entries[j].value;
+			if (lb_is_module_empty(m)) {
+				continue;
+			}
+			// TIME_SECTION("LLVM Generate Object");
 
 
-	}
+			String filepath_obj = lb_filepath_obj_for_module(m);
 
 
+			if (LLVMTargetMachineEmitToFile(target_machine, m->mod, cast(char *)filepath_obj.text, code_gen_file_type, &llvm_error)) {
+				gb_printf_err("LLVM Error: %s\n", llvm_error);
+				gb_exit(1);
+				return;
+			}
+
+			array_add(&gen->output_object_paths, filepath_obj);
+		}
+	}
 
 
 
 
 
 

+ 2 - 2
src/llvm_backend.hpp

@@ -90,8 +90,6 @@ struct lbModule {
 	CheckerInfo *info;
 	CheckerInfo *info;
 	AstPackage *pkg; // associated
 	AstPackage *pkg; // associated
 
 
-	gbMutex mutex;
-
 	Map<LLVMTypeRef> types; // Key: Type *
 	Map<LLVMTypeRef> types; // Key: Type *
 	Map<Type *> llvm_types; // Key: LLVMTypeRef
 	Map<Type *> llvm_types; // Key: LLVMTypeRef
 	i32 internal_type_level;
 	i32 internal_type_level;
@@ -127,6 +125,8 @@ struct lbModule {
 struct lbGenerator {
 struct lbGenerator {
 	CheckerInfo *info;
 	CheckerInfo *info;
 
 
+	gbMutex mutex;
+
 	Array<String> output_object_paths;
 	Array<String> output_object_paths;
 	Array<String> output_temp_paths;
 	Array<String> output_temp_paths;
 	String   output_base;
 	String   output_base;

+ 1 - 1
src/main.cpp

@@ -1929,7 +1929,7 @@ int main(int arg_count, char const **arg_ptr) {
 
 
 	Timings *timings = &global_timings;
 	Timings *timings = &global_timings;
 
 
-	timings_init(timings, str_lit("Total Time"), 128);
+	timings_init(timings, str_lit("Total Time"), 2048);
 	defer (timings_destroy(timings));
 	defer (timings_destroy(timings));
 
 
 	arena_init(&permanent_arena, heap_allocator());
 	arena_init(&permanent_arena, heap_allocator());