Browse Source

Nearly approach full functionality for -use-separate-modules coupled with multithreading

gingerBill 4 years ago
parent
commit
17001bf38c
2 changed files with 129 additions and 91 deletions
  1. 129 88
      src/llvm_backend.cpp
  2. 0 3
      src/thread_pool.cpp

+ 129 - 88
src/llvm_backend.cpp

@@ -13,7 +13,9 @@
 #include "llvm_abi.cpp"
 #include "llvm_backend_opt.cpp"
 
-gb_global lbAddr lb_global_type_info_data           = {};
+gb_global ThreadPool lb_thread_pool = {};
+
+gb_global Entity *lb_global_type_info_data_entity   = {};
 gb_global lbAddr lb_global_type_info_member_types   = {};
 gb_global lbAddr lb_global_type_info_member_names   = {};
 gb_global lbAddr lb_global_type_info_member_offsets = {};
@@ -28,6 +30,12 @@ gb_global isize lb_global_type_info_member_usings_index  = 0;
 gb_global isize lb_global_type_info_member_tags_index    = 0;
 
 
+lbValue lb_global_type_info_data_ptr(lbModule *m) {
+	lbValue v = lb_find_value_from_entity(m, lb_global_type_info_data_entity);
+	return v;
+}
+
+
 struct lbLoopData {
 	lbAddr idx_addr;
 	lbValue idx;
@@ -2539,6 +2547,7 @@ void lb_ensure_abi_function_type(lbModule *m, lbProcedure *p) {
 
 lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool ignore_body) {
 	GB_ASSERT(entity != nullptr);
+	GB_ASSERT(entity->kind == Entity_Procedure);
 
 	String link_name = {};
 
@@ -5674,7 +5683,7 @@ lbValue lb_type_info(lbModule *m, Type *type) {
 	};
 
 	lbValue value = {};
-	value.value = LLVMConstGEP(lb_global_type_info_data.addr.value, indices, gb_count_of(indices));
+	value.value = LLVMConstGEP(lb_global_type_info_data_ptr(m).value, indices, gb_count_of(indices));
 	value.type = t_type_info_ptr;
 	return value;
 }
@@ -5736,7 +5745,7 @@ lbValue lb_find_procedure_value_from_entity(lbModule *m, Entity *e) {
 lbValue lb_find_value_from_entity(lbModule *m, Entity *e) {
 	e = strip_entity_wrapping(e);
 	GB_ASSERT(e != nullptr);
-	if (is_type_proc(e->type)) {
+	if (e->kind == Entity_Procedure) {
 		return lb_find_procedure_value_from_entity(m, e);
 	}
 
@@ -13184,7 +13193,7 @@ lbValue lb_get_type_info_ptr(lbModule *m, Type *type) {
 
 	lbValue res = {};
 	res.type = t_type_info_ptr;
-	res.value = LLVMConstGEP(lb_global_type_info_data.addr.value, indices, cast(unsigned)gb_count_of(indices));
+	res.value = LLVMConstGEP(lb_global_type_info_data_ptr(m).value, indices, cast(unsigned)gb_count_of(indices));
 	return res;
 }
 
@@ -13251,12 +13260,12 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
 	{
 		// NOTE(bill): Set the type_table slice with the global backing array
 		lbValue global_type_table = lb_find_runtime_value(m, str_lit("type_table"));
-		Type *type = base_type(lb_addr_type(lb_global_type_info_data));
+		Type *type = base_type(lb_global_type_info_data_entity->type);
 		GB_ASSERT(is_type_array(type));
 
 		LLVMValueRef indices[2] = {llvm_zero(m), llvm_zero(m)};
 		LLVMValueRef values[2] = {
-			LLVMConstInBoundsGEP(lb_global_type_info_data.addr.value, indices, gb_count_of(indices)),
+			LLVMConstInBoundsGEP(lb_global_type_info_data_ptr(m).value, indices, gb_count_of(indices)),
 			LLVMConstInt(lb_type(m, t_int), type->Array.count, true),
 		};
 		LLVMValueRef slice = llvm_const_named_struct(llvm_addr_type(global_type_table), values, gb_count_of(values));
@@ -13288,7 +13297,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
 		}
 
 		lbValue tag = {};
-		lbValue ti_ptr = lb_emit_array_epi(p, lb_global_type_info_data.addr, cast(i32)entry_index);
+		lbValue ti_ptr = lb_emit_array_epi(p, lb_global_type_info_data_ptr(m), cast(i32)entry_index);
 		lbValue variant_ptr = lb_emit_struct_ep(p, ti_ptr, 4);
 
 		lbValue type_info_flags = lb_const_int(p->module, t_type_info_flags, type_info_flags_of_type(t));
@@ -14270,6 +14279,96 @@ WORKER_TASK_PROC(lb_llvm_emit_worker_proc) {
 	return 0;
 }
 
+WORKER_TASK_PROC(lb_llvm_function_pass_worker_proc) {
+	GB_ASSERT(MULTITHREAD_OBJECT_GENERATION);
+
+	auto m = cast(lbModule *)data;
+
+	LLVMPassManagerRef default_function_pass_manager = LLVMCreateFunctionPassManagerForModule(m->mod);
+	LLVMPassManagerRef function_pass_manager_minimal = LLVMCreateFunctionPassManagerForModule(m->mod);
+	LLVMPassManagerRef function_pass_manager_size = LLVMCreateFunctionPassManagerForModule(m->mod);
+	LLVMPassManagerRef function_pass_manager_speed = LLVMCreateFunctionPassManagerForModule(m->mod);
+
+	LLVMInitializeFunctionPassManager(default_function_pass_manager);
+	LLVMInitializeFunctionPassManager(function_pass_manager_minimal);
+	LLVMInitializeFunctionPassManager(function_pass_manager_size);
+	LLVMInitializeFunctionPassManager(function_pass_manager_speed);
+
+	lb_populate_function_pass_manager(default_function_pass_manager, false, build_context.optimization_level);
+	lb_populate_function_pass_manager_specific(function_pass_manager_minimal, 0);
+	lb_populate_function_pass_manager_specific(function_pass_manager_size,    1);
+	lb_populate_function_pass_manager_specific(function_pass_manager_speed,   2);
+
+	LLVMFinalizeFunctionPassManager(default_function_pass_manager);
+	LLVMFinalizeFunctionPassManager(function_pass_manager_minimal);
+	LLVMFinalizeFunctionPassManager(function_pass_manager_size);
+	LLVMFinalizeFunctionPassManager(function_pass_manager_speed);
+
+
+	LLVMPassManagerRef default_function_pass_manager_without_memcpy = LLVMCreateFunctionPassManagerForModule(m->mod);
+	LLVMInitializeFunctionPassManager(default_function_pass_manager_without_memcpy);
+	lb_populate_function_pass_manager(default_function_pass_manager_without_memcpy, true, build_context.optimization_level);
+	LLVMFinalizeFunctionPassManager(default_function_pass_manager_without_memcpy);
+
+
+	for_array(i, m->procedures_to_generate) {
+		lbProcedure *p = m->procedures_to_generate[i];
+		if (p->body != nullptr) { // Build Procedure
+			if (p->flags & lbProcedureFlag_WithoutMemcpyPass) {
+				LLVMRunFunctionPassManager(default_function_pass_manager_without_memcpy, p->value);
+			} else {
+				if (p->entity && p->entity->kind == Entity_Procedure) {
+					switch (p->entity->Procedure.optimization_mode) {
+					case ProcedureOptimizationMode_None:
+					case ProcedureOptimizationMode_Minimal:
+						LLVMRunFunctionPassManager(function_pass_manager_minimal, p->value);
+						break;
+					case ProcedureOptimizationMode_Size:
+						LLVMRunFunctionPassManager(function_pass_manager_size, p->value);
+						break;
+					case ProcedureOptimizationMode_Speed:
+						LLVMRunFunctionPassManager(function_pass_manager_speed, p->value);
+						break;
+					default:
+						LLVMRunFunctionPassManager(default_function_pass_manager, p->value);
+						break;
+					}
+				} else {
+					LLVMRunFunctionPassManager(default_function_pass_manager, p->value);
+				}
+			}
+		}
+	}
+
+	for_array(i, m->equal_procs.entries) {
+		lbProcedure *p = m->equal_procs.entries[i].value;
+		LLVMRunFunctionPassManager(default_function_pass_manager, p->value);
+	}
+	for_array(i, m->hasher_procs.entries) {
+		lbProcedure *p = m->hasher_procs.entries[i].value;
+		LLVMRunFunctionPassManager(default_function_pass_manager, p->value);
+	}
+
+	return 0;
+}
+
+
+struct lbLLVMModulePassWorkerData {
+	lbModule *m;
+	LLVMTargetMachineRef target_machine;
+};
+
+WORKER_TASK_PROC(lb_llvm_module_pass_worker_proc) {
+	GB_ASSERT(MULTITHREAD_OBJECT_GENERATION);
+
+	auto wd = cast(lbLLVMModulePassWorkerData *)data;
+
+	LLVMPassManagerRef module_pass_manager = LLVMCreatePassManager();
+	lb_populate_module_pass_manager(wd->target_machine, module_pass_manager, build_context.optimization_level);
+	LLVMRunPassManager(module_pass_manager, wd->m->mod);
+
+	return 0;
+}
 
 
 void lb_generate_code(lbGenerator *gen) {
@@ -14278,6 +14377,14 @@ void lb_generate_code(lbGenerator *gen) {
 
 	TIME_SECTION("LLVM Initializtion");
 
+	isize thread_count = gb_max(build_context.thread_count, 1);
+	isize worker_count = thread_count-1;
+
+	LLVMBool do_threading = (LLVMIsMultithreaded() && USE_SEPARTE_MODULES && MULTITHREAD_OBJECT_GENERATION && worker_count > 0);
+
+	thread_pool_init(&lb_thread_pool, heap_allocator(), worker_count, "LLVMBackend");
+	defer (thread_pool_destroy(&lb_thread_pool));
+
 	lbModule *default_module = &gen->default_module;
 	CheckerInfo *info = gen->info;
 
@@ -14415,7 +14522,9 @@ void lb_generate_code(lbGenerator *gen) {
 			lbValue value = {};
 			value.value = g;
 			value.type = alloc_type_pointer(t);
-			lb_global_type_info_data = lb_addr(value);
+
+			lb_global_type_info_data_entity = alloc_entity_variable(nullptr, blank_token, t, EntityState_Resolved);
+			lb_add_entity(m, lb_global_type_info_data_entity, value);
 		}
 		{ // Type info member buffer
 			// NOTE(bill): Removes need for heap allocation by making it global memory
@@ -14776,82 +14885,22 @@ void lb_generate_code(lbGenerator *gen) {
 	for_array(i, gen->modules.entries) {
 		lbModule *m = gen->modules.entries[i].value;
 
-		LLVMPassManagerRef default_function_pass_manager = LLVMCreateFunctionPassManagerForModule(m->mod);
-		LLVMPassManagerRef function_pass_manager_minimal = LLVMCreateFunctionPassManagerForModule(m->mod);
-		LLVMPassManagerRef function_pass_manager_size = LLVMCreateFunctionPassManagerForModule(m->mod);
-		LLVMPassManagerRef function_pass_manager_speed = LLVMCreateFunctionPassManagerForModule(m->mod);
-
-		LLVMInitializeFunctionPassManager(default_function_pass_manager);
-		LLVMInitializeFunctionPassManager(function_pass_manager_minimal);
-		LLVMInitializeFunctionPassManager(function_pass_manager_size);
-		LLVMInitializeFunctionPassManager(function_pass_manager_speed);
-
-		lb_populate_function_pass_manager(default_function_pass_manager, false, build_context.optimization_level);
-		lb_populate_function_pass_manager_specific(function_pass_manager_minimal, 0);
-		lb_populate_function_pass_manager_specific(function_pass_manager_size,    1);
-		lb_populate_function_pass_manager_specific(function_pass_manager_speed,   2);
-
-		LLVMFinalizeFunctionPassManager(default_function_pass_manager);
-		LLVMFinalizeFunctionPassManager(function_pass_manager_minimal);
-		LLVMFinalizeFunctionPassManager(function_pass_manager_size);
-		LLVMFinalizeFunctionPassManager(function_pass_manager_speed);
-
-
-		LLVMPassManagerRef default_function_pass_manager_without_memcpy = LLVMCreateFunctionPassManagerForModule(m->mod);
-		LLVMInitializeFunctionPassManager(default_function_pass_manager_without_memcpy);
-		lb_populate_function_pass_manager(default_function_pass_manager_without_memcpy, true, build_context.optimization_level);
-		LLVMFinalizeFunctionPassManager(default_function_pass_manager_without_memcpy);
-
-
-		for_array(i, m->procedures_to_generate) {
-			lbProcedure *p = m->procedures_to_generate[i];
-			if (p->body != nullptr) { // Build Procedure
-				if (p->flags & lbProcedureFlag_WithoutMemcpyPass) {
-					LLVMRunFunctionPassManager(default_function_pass_manager_without_memcpy, p->value);
-				} else {
-					if (p->entity && p->entity->kind == Entity_Procedure) {
-						switch (p->entity->Procedure.optimization_mode) {
-						case ProcedureOptimizationMode_None:
-						case ProcedureOptimizationMode_Minimal:
-							LLVMRunFunctionPassManager(function_pass_manager_minimal, p->value);
-							break;
-						case ProcedureOptimizationMode_Size:
-							LLVMRunFunctionPassManager(function_pass_manager_size, p->value);
-							break;
-						case ProcedureOptimizationMode_Speed:
-							LLVMRunFunctionPassManager(function_pass_manager_speed, p->value);
-							break;
-						default:
-							LLVMRunFunctionPassManager(default_function_pass_manager, p->value);
-							break;
-						}
-					} else {
-						LLVMRunFunctionPassManager(default_function_pass_manager, p->value);
-					}
-				}
-			}
-		}
-
-		for_array(i, m->equal_procs.entries) {
-			lbProcedure *p = m->equal_procs.entries[i].value;
-			LLVMRunFunctionPassManager(default_function_pass_manager, p->value);
-		}
-		for_array(i, m->hasher_procs.entries) {
-			lbProcedure *p = m->hasher_procs.entries[i].value;
-			LLVMRunFunctionPassManager(default_function_pass_manager, p->value);
-		}
+		lb_llvm_function_pass_worker_proc(m);
 	}
 
 	TIME_SECTION("LLVM Module Pass");
 
 	for_array(i, gen->modules.entries) {
-		LLVMPassManagerRef module_pass_manager = LLVMCreatePassManager();
-		auto target_machine = target_machines[i];
-		lb_populate_module_pass_manager(target_machine, module_pass_manager, build_context.optimization_level);
 		lbModule *m = gen->modules.entries[i].value;
-		LLVMRunPassManager(module_pass_manager, m->mod);
+
+		auto wd = gb_alloc_item(permanent_allocator(), lbLLVMModulePassWorkerData);
+		wd->m = m;
+		wd->target_machine = target_machines[i];
+
+		lb_llvm_module_pass_worker_proc(wd);
 	}
 
+
 	llvm_error = nullptr;
 	defer (LLVMDisposeMessage(llvm_error));
 
@@ -14921,15 +14970,7 @@ void lb_generate_code(lbGenerator *gen) {
 
 	TIME_SECTION("LLVM Object Generation");
 
-	isize thread_count = gb_max(build_context.thread_count, 1);
-	isize worker_count = thread_count-1;
-
-	LLVMBool do_threading = LLVMIsMultithreaded();
-	if (do_threading && 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));
-
+	if (do_threading) {
 		for_array(j, gen->modules.entries) {
 			lbModule *m = gen->modules.entries[j].value;
 			if (lb_is_module_empty(m)) {
@@ -14946,11 +14987,11 @@ void lb_generate_code(lbGenerator *gen) {
 			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);
+			thread_pool_add_task(&lb_thread_pool, lb_llvm_emit_worker_proc, wd);
 		}
 
-		thread_pool_start(&pool);
-		thread_pool_wait_to_process(&pool);
+		thread_pool_start(&lb_thread_pool);
+		thread_pool_wait_to_process(&lb_thread_pool);
 	} else {
 		for_array(j, gen->modules.entries) {
 			lbModule *m = gen->modules.entries[j].value;

+ 0 - 3
src/thread_pool.cpp

@@ -35,8 +35,6 @@ void thread_pool_destroy(ThreadPool *pool);
 void thread_pool_start(ThreadPool *pool);
 void thread_pool_join(ThreadPool *pool);
 void thread_pool_add_task(ThreadPool *pool, WorkerTaskProc *proc, void *data);
-void thread_pool_kick(ThreadPool *pool);
-void thread_pool_kick_and_wait(ThreadPool *pool);
 GB_THREAD_PROC(worker_thread_internal);
 
 void thread_pool_init(ThreadPool *pool, gbAllocator const &a, isize thread_count, char const *worker_prefix) {
@@ -181,4 +179,3 @@ GB_THREAD_PROC(worker_thread_internal) {
 
 	return 0;
 }
-