Browse Source

Begin cleanup for allowing for multiple LLVM modules

gingerBill 4 years ago
parent
commit
b44a56118e
3 changed files with 320 additions and 279 deletions
  1. 304 276
      src/llvm_backend.cpp
  2. 3 1
      src/llvm_backend.hpp
  3. 13 2
      src/main.cpp

+ 304 - 276
src/llvm_backend.cpp

@@ -12912,12 +12912,15 @@ lbAddr lb_build_addr(lbProcedure *p, Ast *expr) {
 void lb_init_module(lbModule *m, Checker *c) {
 	m->info = &c->info;
 
-#if 0
-	m->ctx = LLVMGetGlobalContext();
-#else
+	gbString module_name = nullptr;
+	if (m->pkg) {
+		module_name = gb_string_make(heap_allocator(), "odin_package-");
+		module_name = gb_string_append_length(module_name, m->pkg->name.text, m->pkg->name.len);
+	}
+
+
 	m->ctx = LLVMContextCreate();
-#endif
-	m->mod = LLVMModuleCreateWithNameInContext("odin_module", m->ctx);
+	m->mod = LLVMModuleCreateWithNameInContext(module_name ? module_name : "odin_package", m->ctx);
 	// m->debug_builder = nullptr;
 	if (build_context.ODIN_DEBUG) {
 		enum {DEBUG_METADATA_VERSION = 3};
@@ -13012,8 +13015,18 @@ bool lb_init_generator(lbGenerator *gen, Checker *c) {
 
 	gen->info = &c->info;
 
-	lb_init_module(&gen->module, c);
+	map_init(&gen->modules, permanent_allocator(), gen->info->packages.entries.count*2);
+
+	for_array(i, gen->info->packages.entries) {
+		AstPackage *pkg = gen->info->packages.entries[i].value;
 
+		auto m = gb_alloc_item(permanent_allocator(), lbModule);
+		m->pkg = pkg;
+		map_set(&gen->modules, hash_pointer(pkg), m);
+		lb_init_module(m, c);
+	}
+	map_set(&gen->modules, hash_pointer(nullptr), &gen->default_module);
+	lb_init_module(&gen->default_module, c);
 
 	return true;
 }
@@ -13833,18 +13846,261 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
 	}
 }
 
+struct lbGlobalVariable {
+	lbValue var;
+	lbValue init;
+	DeclInfo *decl;
+	bool is_initialized;
+};
+
+lbProcedure *lb_create_startup_type_info(lbModule *m) {
+	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);
+	LLVMFinalizeFunctionPassManager(default_function_pass_manager);
+
+	Type *params  = alloc_type_tuple();
+	Type *results = alloc_type_tuple();
+
+	Type *proc_type = alloc_type_proc(nullptr, nullptr, 0, nullptr, 0, false, ProcCC_CDecl);
+
+	lbProcedure *p = lb_create_dummy_procedure(m, str_lit(LB_STARTUP_TYPE_INFO_PROC_NAME), proc_type);
+	p->is_startup = true;
+
+	lb_begin_procedure_body(p);
+
+	lb_setup_type_info_data(p);
+
+	lb_end_procedure_body(p);
+
+	if (!m->debug_builder && LLVMVerifyFunction(p->value, LLVMReturnStatusAction)) {
+		gb_printf_err("LLVM CODE GEN FAILED FOR PROCEDURE: %s\n", "main");
+		LLVMDumpValue(p->value);
+		gb_printf_err("\n\n\n\n");
+		LLVMVerifyFunction(p->value, LLVMAbortProcessAction);
+	}
+
+	LLVMRunFunctionPassManager(default_function_pass_manager, p->value);
+
+	return p;
+}
+
+lbProcedure *lb_create_startup_runtime(lbModule *m, lbProcedure *startup_type_info, Array<lbGlobalVariable> &global_variables) { // Startup Runtime
+	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);
+	LLVMFinalizeFunctionPassManager(default_function_pass_manager);
+
+	Type *params  = alloc_type_tuple();
+	Type *results = alloc_type_tuple();
+
+	Type *proc_type = alloc_type_proc(nullptr, nullptr, 0, nullptr, 0, false, ProcCC_CDecl);
+
+	lbProcedure *p = lb_create_dummy_procedure(m, str_lit(LB_STARTUP_RUNTIME_PROC_NAME), proc_type);
+	p->is_startup = true;
+
+	lb_begin_procedure_body(p);
+
+	LLVMBuildCall2(p->builder, LLVMGetElementType(lb_type(m, startup_type_info->type)), startup_type_info->value, nullptr, 0, "");
+
+	for_array(i, global_variables) {
+		auto *var = &global_variables[i];
+		if (var->is_initialized) {
+			continue;
+		}
+
+		Entity *e = var->decl->entity;
+		GB_ASSERT(e->kind == Entity_Variable);
+
+		if (var->decl->init_expr != nullptr)  {
+			// gb_printf_err("%s\n", expr_to_string(var->decl->init_expr));
+			lbValue init = lb_build_expr(p, var->decl->init_expr);
+			LLVMValueKind value_kind = LLVMGetValueKind(init.value);
+			// gb_printf_err("%s %d\n", LLVMPrintValueToString(init.value));
+
+			if (lb_is_const_or_global(init)) {
+				if (!var->is_initialized) {
+					LLVMSetInitializer(var->var.value, init.value);
+					var->is_initialized = true;
+					continue;
+				}
+			} else {
+				var->init = init;
+			}
+		}
+
+		if (var->init.value != nullptr) {
+			GB_ASSERT(!var->is_initialized);
+			Type *t = type_deref(var->var.type);
+
+			if (is_type_any(t)) {
+				// NOTE(bill): Edge case for 'any' type
+				Type *var_type = default_type(var->init.type);
+				lbAddr g = lb_add_global_generated(m, var_type, var->init);
+				lb_addr_store(p, g, var->init);
+				lbValue gp = lb_addr_get_ptr(p, g);
+
+				lbValue data = lb_emit_struct_ep(p, var->var, 0);
+				lbValue ti   = lb_emit_struct_ep(p, var->var, 1);
+				lb_emit_store(p, data, lb_emit_conv(p, gp, t_rawptr));
+				lb_emit_store(p, ti,   lb_type_info(m, var_type));
+			} else {
+				LLVMTypeRef pvt = LLVMTypeOf(var->var.value);
+				LLVMTypeRef vt = LLVMGetElementType(pvt);
+				lbValue src0 = lb_emit_conv(p, var->init, t);
+				LLVMValueRef src = OdinLLVMBuildTransmute(p, src0.value, vt);
+				LLVMValueRef dst = var->var.value;
+				LLVMBuildStore(p->builder, src, dst);
+			}
+
+			var->is_initialized = true;
+		}
+	}
+
+
+	lb_end_procedure_body(p);
+
+	if (!m->debug_builder && LLVMVerifyFunction(p->value, LLVMReturnStatusAction)) {
+		gb_printf_err("LLVM CODE GEN FAILED FOR PROCEDURE: %s\n", "main");
+		LLVMDumpValue(p->value);
+		gb_printf_err("\n\n\n\n");
+		LLVMVerifyFunction(p->value, LLVMAbortProcessAction);
+	}
+
+	LLVMRunFunctionPassManager(default_function_pass_manager, p->value);
+
+	return p;
+}
+
+
+lbProcedure *lb_create_main_procedure(lbModule *m, lbProcedure *startup_runtime) {
+	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);
+	LLVMFinalizeFunctionPassManager(default_function_pass_manager);
+
+	Type *params  = alloc_type_tuple();
+	Type *results = alloc_type_tuple();
+
+	Type *t_ptr_cstring = alloc_type_pointer(t_cstring);
+
+	String name = str_lit("main");
+	if (build_context.metrics.os == TargetOs_windows && build_context.metrics.arch == TargetArch_386) {
+		name = str_lit("mainCRTStartup");
+	} else {
+		array_init(&params->Tuple.variables, permanent_allocator(), 2);
+		params->Tuple.variables[0] = alloc_entity_param(nullptr, make_token_ident("argc"), t_i32, false, true);
+		params->Tuple.variables[1] = alloc_entity_param(nullptr, make_token_ident("argv"), t_ptr_cstring, false, true);
+	}
+
+	array_init(&results->Tuple.variables, permanent_allocator(), 1);
+	results->Tuple.variables[0] = alloc_entity_param(nullptr, make_token_ident("_"),   t_i32, false, true);
+
+	Type *proc_type = alloc_type_proc(nullptr,
+		params, params->Tuple.variables.count,
+		results, results->Tuple.variables.count, false, ProcCC_CDecl);
+
+
+	lbProcedure *p = lb_create_dummy_procedure(m, name, proc_type);
+	p->is_startup = true;
+
+	lb_begin_procedure_body(p);
+
+	{ // initialize `runtime.args__`
+		lbValue argc = {LLVMGetParam(p->value, 0), t_i32};
+		argc = lb_emit_conv(p, argc, t_int);
+		lbValue argv = {LLVMGetParam(p->value, 1), t_ptr_cstring};
+		lbAddr args = lb_addr(lb_find_runtime_value(p->module, str_lit("args__")));
+		lb_fill_slice(p, args, argv, argc);
+	}
+
+	LLVMBuildCall2(p->builder, LLVMGetElementType(lb_type(m, startup_runtime->type)), startup_runtime->value, nullptr, 0, "");
+
+	if (build_context.command_kind == Command_test) {
+		Type *t_Internal_Test = find_type_in_pkg(m->info, str_lit("testing"), str_lit("Internal_Test"));
+		Type *array_type = alloc_type_array(t_Internal_Test, m->info->testing_procedures.count);
+		Type *slice_type = alloc_type_slice(t_Internal_Test);
+		lbAddr all_tests_array_addr = lb_add_global_generated(p->module, array_type, {});
+		lbValue all_tests_array = lb_addr_get_ptr(p, all_tests_array_addr);
+
+		LLVMTypeRef lbt_Internal_Test = lb_type(m, t_Internal_Test);
+
+		LLVMValueRef indices[2] = {};
+		indices[0] = LLVMConstInt(lb_type(m, t_i32), 0, false);
+
+		for_array(i, m->info->testing_procedures) {
+			Entity *testing_proc = m->info->testing_procedures[i];
+			String name = testing_proc->token.string;
+			lbValue *found = map_get(&m->values, hash_entity(testing_proc));
+			GB_ASSERT(found != nullptr);
+
+			String pkg_name = {};
+			if (testing_proc->pkg != nullptr) {
+				pkg_name = testing_proc->pkg->name;
+			}
+			lbValue v_pkg  = lb_find_or_add_entity_string(m, pkg_name);
+			lbValue v_name = lb_find_or_add_entity_string(m, name);
+			lbValue v_proc = *found;
+
+			indices[1] = LLVMConstInt(lb_type(m, t_int), i, false);
+
+			LLVMValueRef vals[3] = {};
+			vals[0] = v_pkg.value;
+			vals[1] = v_name.value;
+			vals[2] = v_proc.value;
+			GB_ASSERT(LLVMIsConstant(vals[0]));
+			GB_ASSERT(LLVMIsConstant(vals[1]));
+			GB_ASSERT(LLVMIsConstant(vals[2]));
+
+			LLVMValueRef dst = LLVMConstInBoundsGEP(all_tests_array.value, indices, gb_count_of(indices));
+			LLVMValueRef src = llvm_const_named_struct(lbt_Internal_Test, vals, gb_count_of(vals));
+
+			LLVMBuildStore(p->builder, src, dst);
+		}
+
+		lbAddr all_tests_slice = lb_add_local_generated(p, slice_type, true);
+		lb_fill_slice(p, all_tests_slice,
+		              lb_array_elem(p, all_tests_array),
+		              lb_const_int(m, t_int, m->info->testing_procedures.count));
+
+
+		lbValue runner = lb_find_package_value(m, str_lit("testing"), str_lit("runner"));
+
+		auto args = array_make<lbValue>(heap_allocator(), 1);
+		args[0] = lb_addr_load(p, all_tests_slice);
+		lb_emit_call(p, runner, args);
+	} else {
+		lbValue *found = map_get(&m->values, hash_entity(m->info->entry_point));
+		GB_ASSERT(found != nullptr);
+		lb_emit_call(p, *found, {});
+	}
+
+	LLVMBuildRet(p->builder, LLVMConstInt(lb_type(m, t_i32), 0, false));
+
+	lb_end_procedure_body(p);
+
+	if (!m->debug_builder && LLVMVerifyFunction(p->value, LLVMReturnStatusAction)) {
+		gb_printf_err("LLVM CODE GEN FAILED FOR PROCEDURE: %s\n", "main");
+		LLVMDumpValue(p->value);
+		gb_printf_err("\n\n\n\n");
+		LLVMVerifyFunction(p->value, LLVMAbortProcessAction);
+	}
+
+	LLVMRunFunctionPassManager(default_function_pass_manager, p->value);
+	return p;
+}
+
+
 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)
 
 	TIME_SECTION("LLVM Initializtion");
 
-	lbModule *m = &gen->module;
-	LLVMModuleRef mod = gen->module.mod;
+	lbModule *m = &gen->default_module;
 	CheckerInfo *info = gen->info;
 
 	auto *min_dep_set = &info->minimum_dependency_set;
 
-
 	LLVMInitializeAllTargetInfos();
 	LLVMInitializeAllTargets();
 	LLVMInitializeAllTargetMCs();
@@ -13853,16 +14109,19 @@ void lb_generate_code(lbGenerator *gen) {
 	LLVMInitializeAllDisassemblers();
 	LLVMInitializeNativeTarget();
 
-
 	char const *target_triple = alloc_cstring(permanent_allocator(), build_context.metrics.target_triplet);
 	char const *target_data_layout = alloc_cstring(permanent_allocator(), build_context.metrics.target_data_layout);
-	LLVMSetTarget(mod, target_triple);
+	for_array(i, gen->modules.entries) {
+		LLVMSetTarget(gen->modules.entries[i].value->mod, target_triple);
+	}
 
 	LLVMTargetRef target = {};
 	char *llvm_error = nullptr;
 	LLVMGetTargetFromTriple(target_triple, &target, &llvm_error);
 	GB_ASSERT(target != nullptr);
 
+
+
 	TIME_SECTION("LLVM Create Target Machine");
 
 	LLVMCodeModel code_mode = LLVMCodeModelDefault;
@@ -13905,7 +14164,9 @@ void lb_generate_code(lbGenerator *gen) {
 	defer (LLVMDisposeTargetMachine(target_machine));
 
 
-	LLVMSetModuleDataLayout(mod, LLVMCreateTargetDataLayout(target_machine));
+	for_array(i, gen->modules.entries) {
+		LLVMSetModuleDataLayout(gen->modules.entries[i].value->mod, LLVMCreateTargetDataLayout(target_machine));
+	}
 
 	if (m->debug_builder) { // Debug Info
 		for_array(i, info->files.entries) {
@@ -13960,7 +14221,7 @@ void lb_generate_code(lbGenerator *gen) {
 			isize max_type_info_count = info->minimum_dependency_type_info_set.entries.count+1;
 			// gb_printf_err("max_type_info_count: %td\n", max_type_info_count);
 			Type *t = alloc_type_array(t_type_info, max_type_info_count);
-			LLVMValueRef g = LLVMAddGlobal(mod, lb_type(m, t), LB_TYPE_INFO_DATA_NAME);
+			LLVMValueRef g = LLVMAddGlobal(m->mod, lb_type(m, t), LB_TYPE_INFO_DATA_NAME);
 			LLVMSetInitializer(g, LLVMConstNull(lb_type(m, t)));
 			LLVMSetLinkage(g, LLVMInternalLinkage);
 
@@ -13998,7 +14259,7 @@ void lb_generate_code(lbGenerator *gen) {
 				{
 					char const *name = LB_TYPE_INFO_TYPES_NAME;
 					Type *t = alloc_type_array(t_type_info_ptr, count);
-					LLVMValueRef g = LLVMAddGlobal(mod, lb_type(m, t), name);
+					LLVMValueRef g = LLVMAddGlobal(m->mod, lb_type(m, t), name);
 					LLVMSetInitializer(g, LLVMConstNull(lb_type(m, t)));
 					LLVMSetLinkage(g, LLVMInternalLinkage);
 					lb_global_type_info_member_types = lb_addr({g, alloc_type_pointer(t)});
@@ -14007,7 +14268,7 @@ void lb_generate_code(lbGenerator *gen) {
 				{
 					char const *name = LB_TYPE_INFO_NAMES_NAME;
 					Type *t = alloc_type_array(t_string, count);
-					LLVMValueRef g = LLVMAddGlobal(mod, lb_type(m, t), name);
+					LLVMValueRef g = LLVMAddGlobal(m->mod, lb_type(m, t), name);
 					LLVMSetInitializer(g, LLVMConstNull(lb_type(m, t)));
 					LLVMSetLinkage(g, LLVMInternalLinkage);
 					lb_global_type_info_member_names = lb_addr({g, alloc_type_pointer(t)});
@@ -14015,7 +14276,7 @@ void lb_generate_code(lbGenerator *gen) {
 				{
 					char const *name = LB_TYPE_INFO_OFFSETS_NAME;
 					Type *t = alloc_type_array(t_uintptr, count);
-					LLVMValueRef g = LLVMAddGlobal(mod, lb_type(m, t), name);
+					LLVMValueRef g = LLVMAddGlobal(m->mod, lb_type(m, t), name);
 					LLVMSetInitializer(g, LLVMConstNull(lb_type(m, t)));
 					LLVMSetLinkage(g, LLVMInternalLinkage);
 					lb_global_type_info_member_offsets = lb_addr({g, alloc_type_pointer(t)});
@@ -14024,7 +14285,7 @@ void lb_generate_code(lbGenerator *gen) {
 				{
 					char const *name = LB_TYPE_INFO_USINGS_NAME;
 					Type *t = alloc_type_array(t_bool, count);
-					LLVMValueRef g = LLVMAddGlobal(mod, lb_type(m, t), name);
+					LLVMValueRef g = LLVMAddGlobal(m->mod, lb_type(m, t), name);
 					LLVMSetInitializer(g, LLVMConstNull(lb_type(m, t)));
 					LLVMSetLinkage(g, LLVMInternalLinkage);
 					lb_global_type_info_member_usings = lb_addr({g, alloc_type_pointer(t)});
@@ -14033,7 +14294,7 @@ void lb_generate_code(lbGenerator *gen) {
 				{
 					char const *name = LB_TYPE_INFO_TAGS_NAME;
 					Type *t = alloc_type_array(t_string, count);
-					LLVMValueRef g = LLVMAddGlobal(mod, lb_type(m, t), name);
+					LLVMValueRef g = LLVMAddGlobal(m->mod, lb_type(m, t), name);
 					LLVMSetInitializer(g, LLVMConstNull(lb_type(m, t)));
 					LLVMSetLinkage(g, LLVMInternalLinkage);
 					lb_global_type_info_member_tags = lb_addr({g, alloc_type_pointer(t)});
@@ -14073,13 +14334,8 @@ void lb_generate_code(lbGenerator *gen) {
 		}
 	}
 
-	struct GlobalVariable {
-		lbValue var;
-		lbValue init;
-		DeclInfo *decl;
-		bool is_initialized;
-	};
-	auto global_variables = array_make<GlobalVariable>(permanent_allocator(), 0, global_variable_max_count);
+
+	auto global_variables = array_make<lbGlobalVariable>(permanent_allocator(), 0, global_variable_max_count);
 
 	for_array(i, info->variable_init_order) {
 		DeclInfo *d = info->variable_init_order[i];
@@ -14141,7 +14397,7 @@ void lb_generate_code(lbGenerator *gen) {
 			LLVMSetLinkage(g.value, LLVMInternalLinkage);
 		}
 
-		GlobalVariable var = {};
+		lbGlobalVariable var = {};
 		var.var = g;
 		var.decl = decl;
 
@@ -14259,10 +14515,10 @@ void lb_generate_code(lbGenerator *gen) {
 
 	LLVMPassRegistryRef pass_registry = LLVMGetGlobalPassRegistry();
 
-	LLVMPassManagerRef default_function_pass_manager = LLVMCreateFunctionPassManagerForModule(mod);
-	LLVMPassManagerRef function_pass_manager_minimal = LLVMCreateFunctionPassManagerForModule(mod);
-	LLVMPassManagerRef function_pass_manager_size = LLVMCreateFunctionPassManagerForModule(mod);
-	LLVMPassManagerRef function_pass_manager_speed = LLVMCreateFunctionPassManagerForModule(mod);
+	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);
 	defer (LLVMDisposePassManager(default_function_pass_manager));
 	defer (LLVMDisposePassManager(function_pass_manager_minimal));
 	defer (LLVMDisposePassManager(function_pass_manager_size));
@@ -14284,142 +14540,18 @@ void lb_generate_code(lbGenerator *gen) {
 	LLVMFinalizeFunctionPassManager(function_pass_manager_speed);
 
 
-	LLVMPassManagerRef default_function_pass_manager_without_memcpy = LLVMCreateFunctionPassManagerForModule(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);
 	lb_populate_function_pass_manager(default_function_pass_manager_without_memcpy, true, build_context.optimization_level);
 	LLVMFinalizeFunctionPassManager(default_function_pass_manager_without_memcpy);
 
 	TIME_SECTION("LLVM Runtime Type Information Creation");
+	lbProcedure *startup_type_info = lb_create_startup_type_info(m);
 
-	lbProcedure *startup_type_info = nullptr;
-	lbProcedure *startup_runtime = nullptr;
-	{ // Startup Type Info
-		Type *params  = alloc_type_tuple();
-		Type *results = alloc_type_tuple();
-
-		Type *proc_type = alloc_type_proc(nullptr, nullptr, 0, nullptr, 0, false, ProcCC_CDecl);
-
-		lbProcedure *p = lb_create_dummy_procedure(m, str_lit(LB_STARTUP_TYPE_INFO_PROC_NAME), proc_type);
-		p->is_startup = true;
-		startup_type_info = p;
-
-		lb_begin_procedure_body(p);
-
-		lb_setup_type_info_data(p);
-
-		lb_end_procedure_body(p);
-
-		if (!m->debug_builder && LLVMVerifyFunction(p->value, LLVMReturnStatusAction)) {
-			gb_printf_err("LLVM CODE GEN FAILED FOR PROCEDURE: %s\n", "main");
-			LLVMDumpValue(p->value);
-			gb_printf_err("\n\n\n\n");
-			LLVMVerifyFunction(p->value, LLVMAbortProcessAction);
-		}
-
-		LLVMRunFunctionPassManager(default_function_pass_manager, p->value);
-	}
 	TIME_SECTION("LLVM Runtime Startup Creation (Global Variables)");
-	{ // Startup Runtime
-		Type *params  = alloc_type_tuple();
-		Type *results = alloc_type_tuple();
-
-		Type *proc_type = alloc_type_proc(nullptr, nullptr, 0, nullptr, 0, false, ProcCC_CDecl);
+	lbProcedure *startup_runtime = lb_create_startup_runtime(m, startup_type_info, global_variables);
 
-		lbProcedure *p = lb_create_dummy_procedure(m, str_lit(LB_STARTUP_RUNTIME_PROC_NAME), proc_type);
-		p->is_startup = true;
-		startup_runtime = p;
-
-		lb_begin_procedure_body(p);
-
-
-		LLVMBuildCall2(p->builder, LLVMGetElementType(lb_type(m, startup_type_info->type)), startup_type_info->value, nullptr, 0, "");
-
-		for_array(i, global_variables) {
-			auto *var = &global_variables[i];
-			if (var->is_initialized) {
-				continue;
-			}
-
-			Entity *e = var->decl->entity;
-			GB_ASSERT(e->kind == Entity_Variable);
-
-			if (var->decl->init_expr != nullptr)  {
-				// gb_printf_err("%s\n", expr_to_string(var->decl->init_expr));
-				lbValue init = lb_build_expr(p, var->decl->init_expr);
-				LLVMValueKind value_kind = LLVMGetValueKind(init.value);
-				// gb_printf_err("%s %d\n", LLVMPrintValueToString(init.value));
-
-				if (lb_is_const_or_global(init)) {
-					if (!var->is_initialized) {
-						LLVMSetInitializer(var->var.value, init.value);
-						var->is_initialized = true;
-						continue;
-					}
-				} else {
-					var->init = init;
-				}
-			}
-
-			if (var->init.value != nullptr) {
-				GB_ASSERT(!var->is_initialized);
-				Type *t = type_deref(var->var.type);
-
-				if (is_type_any(t)) {
-					// NOTE(bill): Edge case for 'any' type
-					Type *var_type = default_type(var->init.type);
-					lbAddr g = lb_add_global_generated(m, var_type, var->init);
-					lb_addr_store(p, g, var->init);
-					lbValue gp = lb_addr_get_ptr(p, g);
-
-					lbValue data = lb_emit_struct_ep(p, var->var, 0);
-					lbValue ti   = lb_emit_struct_ep(p, var->var, 1);
-					lb_emit_store(p, data, lb_emit_conv(p, gp, t_rawptr));
-					lb_emit_store(p, ti,   lb_type_info(m, var_type));
-				} else {
-					LLVMTypeRef pvt = LLVMTypeOf(var->var.value);
-					LLVMTypeRef vt = LLVMGetElementType(pvt);
-					lbValue src0 = lb_emit_conv(p, var->init, t);
-					LLVMValueRef src = OdinLLVMBuildTransmute(p, src0.value, vt);
-					LLVMValueRef dst = var->var.value;
-					LLVMBuildStore(p->builder, src, dst);
-				}
-
-				var->is_initialized = true;
-			}
-		}
-
-
-		lb_end_procedure_body(p);
-
-		if (!m->debug_builder && LLVMVerifyFunction(p->value, LLVMReturnStatusAction)) {
-			gb_printf_err("LLVM CODE GEN FAILED FOR PROCEDURE: %s\n", "main");
-			LLVMDumpValue(p->value);
-			gb_printf_err("\n\n\n\n");
-			LLVMVerifyFunction(p->value, LLVMAbortProcessAction);
-		}
-
-		LLVMRunFunctionPassManager(default_function_pass_manager, p->value);
-
-		/*{
-			LLVMValueRef last_instr = LLVMGetLastInstruction(p->decl_block->block);
-			for (LLVMValueRef instr = LLVMGetFirstInstruction(p->decl_block->block);
-			     instr != last_instr;
-			     instr = LLVMGetNextInstruction(instr)) {
-				if (LLVMIsAAllocaInst(instr)) {
-					LLVMTypeRef type = LLVMGetAllocatedType(instr);
-					LLVMValueRef sz_val = LLVMSizeOf(type);
-					GB_ASSERT(LLVMIsConstant(sz_val));
-					gb_printf_err(">> 0x%p\n", sz_val);
-					LLVMTypeRef sz_type = LLVMTypeOf(sz_val);
-					gb_printf_err(">> %s\n", LLVMPrintTypeToString(sz_type));
-					unsigned long long sz = LLVMConstIntGetZExtValue(sz_val);
-					// long long sz = LLVMConstIntGetSExtValue(sz_val);
-					gb_printf_err(">> %ll\n", sz);
-				}
-			}
-		}*/
-	}
 
 	String filepath_ll = concatenate_strings(permanent_allocator(), gen->output_base, STR_LIT(".ll"));
 
@@ -14453,7 +14585,7 @@ void lb_generate_code(lbGenerator *gen) {
 			gb_printf_err("LLVM CODE GEN FAILED FOR PROCEDURE: %.*s\n", LIT(p->name));
 			LLVMDumpValue(p->value);
 			gb_printf_err("\n\n\n\n");
-			if (LLVMPrintModuleToFile(mod, cast(char const *)filepath_ll.text, &llvm_error)) {
+			if (LLVMPrintModuleToFile(m->mod, cast(char const *)filepath_ll.text, &llvm_error)) {
 				gb_printf_err("LLVM Error: %s\n", llvm_error);
 			}
 			LLVMVerifyFunction(p->value, LLVMPrintMessageAction);
@@ -14463,117 +14595,8 @@ void lb_generate_code(lbGenerator *gen) {
 
 
 	if (!(build_context.build_mode == BuildMode_DynamicLibrary && !has_dll_main)) {
-		TIME_SECTION("LLVM DLL main");
-
-
-		Type *params  = alloc_type_tuple();
-		Type *results = alloc_type_tuple();
-
-		Type *t_ptr_cstring = alloc_type_pointer(t_cstring);
-
-		String name = str_lit("main");
-		if (build_context.metrics.os == TargetOs_windows && build_context.metrics.arch == TargetArch_386) {
-			name = str_lit("mainCRTStartup");
-		} else {
-			array_init(&params->Tuple.variables, permanent_allocator(), 2);
-			params->Tuple.variables[0] = alloc_entity_param(nullptr, make_token_ident("argc"), t_i32, false, true);
-			params->Tuple.variables[1] = alloc_entity_param(nullptr, make_token_ident("argv"), t_ptr_cstring, false, true);
-		}
-
-		array_init(&results->Tuple.variables, permanent_allocator(), 1);
-		results->Tuple.variables[0] = alloc_entity_param(nullptr, make_token_ident("_"),   t_i32, false, true);
-
-		Type *proc_type = alloc_type_proc(nullptr,
-			params, params->Tuple.variables.count,
-			results, results->Tuple.variables.count, false, ProcCC_CDecl);
-
-
-		lbProcedure *p = lb_create_dummy_procedure(m, name, proc_type);
-		p->is_startup = true;
-
-		lb_begin_procedure_body(p);
-
-		{ // initialize `runtime.args__`
-			lbValue argc = {LLVMGetParam(p->value, 0), t_i32};
-			argc = lb_emit_conv(p, argc, t_int);
-			lbValue argv = {LLVMGetParam(p->value, 1), t_ptr_cstring};
-			lbAddr args = lb_addr(lb_find_runtime_value(p->module, str_lit("args__")));
-			lb_fill_slice(p, args, argv, argc);
-		}
-
-		LLVMBuildCall2(p->builder, LLVMGetElementType(lb_type(m, startup_runtime->type)), startup_runtime->value, nullptr, 0, "");
-
-		if (build_context.command_kind == Command_test) {
-			Type *t_Internal_Test = find_type_in_pkg(m->info, str_lit("testing"), str_lit("Internal_Test"));
-			Type *array_type = alloc_type_array(t_Internal_Test, m->info->testing_procedures.count);
-			Type *slice_type = alloc_type_slice(t_Internal_Test);
-			lbAddr all_tests_array_addr = lb_add_global_generated(p->module, array_type, {});
-			lbValue all_tests_array = lb_addr_get_ptr(p, all_tests_array_addr);
-
-			LLVMTypeRef lbt_Internal_Test = lb_type(m, t_Internal_Test);
-
-			LLVMValueRef indices[2] = {};
-			indices[0] = LLVMConstInt(lb_type(m, t_i32), 0, false);
-
-			for_array(i, m->info->testing_procedures) {
-				Entity *testing_proc = m->info->testing_procedures[i];
-				String name = testing_proc->token.string;
-				lbValue *found = map_get(&m->values, hash_entity(testing_proc));
-				GB_ASSERT(found != nullptr);
-
-				String pkg_name = {};
-				if (testing_proc->pkg != nullptr) {
-					pkg_name = testing_proc->pkg->name;
-				}
-				lbValue v_pkg  = lb_find_or_add_entity_string(m, pkg_name);
-				lbValue v_name = lb_find_or_add_entity_string(m, name);
-				lbValue v_proc = *found;
-
-				indices[1] = LLVMConstInt(lb_type(m, t_int), i, false);
-
-				LLVMValueRef vals[3] = {};
-				vals[0] = v_pkg.value;
-				vals[1] = v_name.value;
-				vals[2] = v_proc.value;
-				GB_ASSERT(LLVMIsConstant(vals[0]));
-				GB_ASSERT(LLVMIsConstant(vals[1]));
-				GB_ASSERT(LLVMIsConstant(vals[2]));
-
-				LLVMValueRef dst = LLVMConstInBoundsGEP(all_tests_array.value, indices, gb_count_of(indices));
-				LLVMValueRef src = llvm_const_named_struct(lbt_Internal_Test, vals, gb_count_of(vals));
-
-				LLVMBuildStore(p->builder, src, dst);
-			}
-
-			lbAddr all_tests_slice = lb_add_local_generated(p, slice_type, true);
-			lb_fill_slice(p, all_tests_slice,
-			              lb_array_elem(p, all_tests_array),
-			              lb_const_int(m, t_int, m->info->testing_procedures.count));
-
-
-			lbValue runner = lb_find_package_value(m, str_lit("testing"), str_lit("runner"));
-
-			auto args = array_make<lbValue>(heap_allocator(), 1);
-			args[0] = lb_addr_load(p, all_tests_slice);
-			lb_emit_call(p, runner, args);
-		} else {
-			lbValue *found = map_get(&m->values, hash_entity(entry_point));
-			GB_ASSERT(found != nullptr);
-			lb_emit_call(p, *found, {});
-		}
-
-		LLVMBuildRet(p->builder, LLVMConstInt(lb_type(m, t_i32), 0, false));
-
-		lb_end_procedure_body(p);
-
-		if (!m->debug_builder && LLVMVerifyFunction(p->value, LLVMReturnStatusAction)) {
-			gb_printf_err("LLVM CODE GEN FAILED FOR PROCEDURE: %s\n", "main");
-			LLVMDumpValue(p->value);
-			gb_printf_err("\n\n\n\n");
-			LLVMVerifyFunction(p->value, LLVMAbortProcessAction);
-		}
-
-		LLVMRunFunctionPassManager(default_function_pass_manager, p->value);
+		TIME_SECTION("LLVM main");
+		lb_create_main_procedure(m, startup_runtime);
 	}
 
 
@@ -14583,7 +14606,7 @@ void lb_generate_code(lbGenerator *gen) {
 
 
 		TIME_SECTION("LLVM Print Module to File");
-		if (LLVMPrintModuleToFile(mod, cast(char const *)filepath_ll.text, &llvm_error)) {
+		if (LLVMPrintModuleToFile(m->mod, cast(char const *)filepath_ll.text, &llvm_error)) {
 			gb_printf_err("LLVM Error: %s\n", llvm_error);
 			gb_exit(1);
 			return;
@@ -14594,7 +14617,9 @@ void lb_generate_code(lbGenerator *gen) {
 
 
 	TIME_SECTION("LLVM Function Pass");
-	{
+	for_array(i, gen->modules.entries) {
+		lbModule *m = gen->modules.entries[i].value;
+
 		for_array(i, m->procedures_to_generate) {
 			lbProcedure *p = m->procedures_to_generate[i];
 			if (p->body != nullptr) { // Build Procedure
@@ -14640,7 +14665,10 @@ void lb_generate_code(lbGenerator *gen) {
 	defer (LLVMDisposePassManager(module_pass_manager));
 	lb_populate_module_pass_manager(target_machine, module_pass_manager, build_context.optimization_level);
 
-	LLVMRunPassManager(module_pass_manager, mod);
+	for_array(i, gen->modules.entries) {
+		lbModule *m = gen->modules.entries[i].value;
+		LLVMRunPassManager(module_pass_manager, m->mod);
+	}
 
 	llvm_error = nullptr;
 	defer (LLVMDisposeMessage(llvm_error));
@@ -14667,11 +14695,11 @@ void lb_generate_code(lbGenerator *gen) {
 		}
 	}
 
-	if (LLVMVerifyModule(mod, LLVMReturnStatusAction, &llvm_error)) {
+	if (LLVMVerifyModule(m->mod, LLVMReturnStatusAction, &llvm_error)) {
 		gb_printf_err("LLVM Error:\n%s\n", llvm_error);
 		if (build_context.keep_temp_files) {
 			TIME_SECTION("LLVM Print Module to File");
-			if (LLVMPrintModuleToFile(mod, cast(char const *)filepath_ll.text, &llvm_error)) {
+			if (LLVMPrintModuleToFile(m->mod, cast(char const *)filepath_ll.text, &llvm_error)) {
 				gb_printf_err("LLVM Error: %s\n", llvm_error);
 				gb_exit(1);
 				return;
@@ -14684,7 +14712,7 @@ void lb_generate_code(lbGenerator *gen) {
 	if (build_context.keep_temp_files ||
 	    build_context.build_mode == BuildMode_LLVM_IR) {
 		TIME_SECTION("LLVM Print Module to File");
-		if (LLVMPrintModuleToFile(mod, cast(char const *)filepath_ll.text, &llvm_error)) {
+		if (LLVMPrintModuleToFile(m->mod, cast(char const *)filepath_ll.text, &llvm_error)) {
 			gb_printf_err("LLVM Error: %s\n", llvm_error);
 			gb_exit(1);
 			return;
@@ -14697,7 +14725,7 @@ void lb_generate_code(lbGenerator *gen) {
 
 	TIME_SECTION("LLVM Object Generation");
 
-	if (LLVMTargetMachineEmitToFile(target_machine, mod, cast(char *)filepath_obj.text, code_gen_file_type, &llvm_error)) {
+	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;

+ 3 - 1
src/llvm_backend.hpp

@@ -86,6 +86,7 @@ struct lbModule {
 	LLVMContextRef ctx;
 
 	CheckerInfo *info;
+	AstPackage *pkg; // associated
 
 	gbMutex mutex;
 
@@ -124,12 +125,13 @@ struct lbModule {
 };
 
 struct lbGenerator {
-	lbModule module;
 	CheckerInfo *info;
 
 	Array<String> output_object_paths;
 	String   output_base;
 	String   output_name;
+	Map<lbModule *> modules; // Key: AstPackage *
+	lbModule default_module;
 };
 
 

+ 13 - 2
src/main.cpp

@@ -218,8 +218,19 @@ i32 linker_stage(lbGenerator *gen) {
 			add_path(find_result.vs_library_path);
 		}
 
-		for_array(i, gen->module.foreign_library_paths) {
-			String lib = gen->module.foreign_library_paths[i];
+		for_array(j, gen->modules.entries) {
+			lbModule *m = gen->modules.entries[j].value;
+			for_array(i, m->foreign_library_paths) {
+				String lib = m->foreign_library_paths[i];
+				GB_ASSERT(lib.len < gb_count_of(lib_str_buf)-1);
+				isize len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf),
+				                        " \"%.*s\"", LIT(lib));
+				lib_str = gb_string_appendc(lib_str, lib_str_buf);
+			}
+		}
+
+		for_array(i, gen->default_module.foreign_library_paths) {
+			String lib = gen->default_module.foreign_library_paths[i];
 			GB_ASSERT(lib.len < gb_count_of(lib_str_buf)-1);
 			isize len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf),
 			                        " \"%.*s\"", LIT(lib));