Browse Source

Begin work on making LLVM backend work with multiple modules for possible faster compilation

gingerBill 4 years ago
parent
commit
746e880eb5
4 changed files with 417 additions and 279 deletions
  1. 6 0
      src/build_settings.cpp
  2. 394 274
      src/llvm_backend.cpp
  3. 8 3
      src/llvm_backend.hpp
  4. 9 2
      src/main.cpp

+ 6 - 0
src/build_settings.cpp

@@ -207,6 +207,8 @@ struct BuildContext {
 	bool   ignore_microsoft_magic;
 	bool   ignore_microsoft_magic;
 	bool   linker_map_file;
 	bool   linker_map_file;
 
 
+	bool use_separate_modules;
+
 	u32 cmd_doc_flags;
 	u32 cmd_doc_flags;
 	Array<String> extra_packages;
 	Array<String> extra_packages;
 
 
@@ -807,6 +809,10 @@ void init_build_context(TargetMetrics *cross_target) {
 	bc->max_align   = metrics->max_align;
 	bc->max_align   = metrics->max_align;
 	bc->link_flags  = str_lit(" ");
 	bc->link_flags  = str_lit(" ");
 
 
+	if (bc->metrics.os == TargetOs_windows) {
+		// bc->use_separate_modules = bc->optimization_level == 0;
+	}
+
 
 
 	// NOTE(zangent): The linker flags to set the build architecture are different
 	// NOTE(zangent): The linker flags to set the build architecture are different
 	// across OSs. It doesn't make sense to allocate extra data on the heap
 	// across OSs. It doesn't make sense to allocate extra data on the heap

+ 394 - 274
src/llvm_backend.cpp

@@ -1,3 +1,7 @@
+#ifndef USE_SEPARTE_MODULES
+#define USE_SEPARTE_MODULES build_context.use_separate_modules
+#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"
@@ -74,6 +78,15 @@ bool lb_is_instr_terminating(LLVMValueRef instr) {
 
 
 
 
 
 
+lbModule *lb_pkg_module(lbGenerator *gen, AstPackage *pkg) {
+	auto *found = map_get(&gen->modules, hash_pointer(pkg));
+	if (found) {
+		return *found;
+	}
+	return &gen->default_module;
+}
+
+
 lbAddr lb_addr(lbValue addr) {
 lbAddr lb_addr(lbValue addr) {
 	lbAddr v = {lbAddr_Default, addr};
 	lbAddr v = {lbAddr_Default, addr};
 	if (addr.type != nullptr && is_type_relative_pointer(type_deref(addr.type))) {
 	if (addr.type != nullptr && is_type_relative_pointer(type_deref(addr.type))) {
@@ -2528,10 +2541,17 @@ void lb_ensure_abi_function_type(lbModule *m, lbProcedure *p) {
 	GB_ASSERT(p->abi_function_type != nullptr);
 	GB_ASSERT(p->abi_function_type != nullptr);
 }
 }
 
 
-lbProcedure *lb_create_procedure(lbModule *m, Entity *entity) {
+lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool ignore_body) {
 	GB_ASSERT(entity != nullptr);
 	GB_ASSERT(entity != nullptr);
 
 
-	String link_name = lb_get_entity_name(m, entity);
+	String link_name = {};
+
+	if (ignore_body) {
+		lbModule *other_module = lb_pkg_module(m->gen, entity->pkg);
+		link_name = lb_get_entity_name(other_module, entity);
+	} else {
+		link_name = lb_get_entity_name(m, entity);
+	}
 
 
 	{
 	{
 		StringHashKey key = string_hash_string(link_name);
 		StringHashKey key = string_hash_string(link_name);
@@ -2699,6 +2719,10 @@ lbProcedure *lb_create_procedure(lbModule *m, Entity *entity) {
 		}
 		}
 	}
 	}
 
 
+	if (ignore_body) {
+		p->body = nullptr;
+	}
+
 
 
 	if (m->debug_builder) { // Debug Information
 	if (m->debug_builder) { // Debug Information
 		Type *bt = base_type(p->type);
 		Type *bt = base_type(p->type);
@@ -5484,9 +5508,10 @@ LLVMValueRef lb_find_or_add_entity_string_ptr(lbModule *m, String const &str) {
 
 
 		isize max_len = 7+8+1;
 		isize max_len = 7+8+1;
 		char *name = gb_alloc_array(permanent_allocator(), char, max_len);
 		char *name = gb_alloc_array(permanent_allocator(), char, max_len);
-		isize len = gb_snprintf(name, max_len, "csbs$%x", m->global_array_index);
+
+		u32 id = cast(u32)gb_atomic32_fetch_add(&m->gen->global_array_index, 1);
+		isize len = gb_snprintf(name, max_len, "csbs$%x", id);
 		len -= 1;
 		len -= 1;
-		m->global_array_index++;
 
 
 		LLVMValueRef global_data = LLVMAddGlobal(m->mod, LLVMTypeOf(data), name);
 		LLVMValueRef global_data = LLVMAddGlobal(m->mod, LLVMTypeOf(data), name);
 		LLVMSetInitializer(global_data, data);
 		LLVMSetInitializer(global_data, data);
@@ -5526,9 +5551,9 @@ lbValue lb_find_or_add_entity_string_byte_slice(lbModule *m, String const &str)
 	{
 	{
 		isize max_len = 7+8+1;
 		isize max_len = 7+8+1;
 		name = gb_alloc_array(permanent_allocator(), char, max_len);
 		name = gb_alloc_array(permanent_allocator(), char, max_len);
-		isize len = gb_snprintf(name, max_len, "csbs$%x", m->global_array_index);
+		u32 id = cast(u32)gb_atomic32_fetch_add(&m->gen->global_array_index, 1);
+		isize len = gb_snprintf(name, max_len, "csbs$%x", id);
 		len -= 1;
 		len -= 1;
-		m->global_array_index++;
 	}
 	}
 	LLVMValueRef global_data = LLVMAddGlobal(m->mod, LLVMTypeOf(data), name);
 	LLVMValueRef global_data = LLVMAddGlobal(m->mod, LLVMTypeOf(data), name);
 	LLVMSetInitializer(global_data, data);
 	LLVMSetInitializer(global_data, data);
@@ -5684,6 +5709,7 @@ LLVMValueRef lb_build_constant_array_values(lbModule *m, Type *type, Type *elem_
 }
 }
 
 
 lbValue lb_find_procedure_value_from_entity(lbModule *m, Entity *e) {
 lbValue lb_find_procedure_value_from_entity(lbModule *m, Entity *e) {
+	GB_ASSERT(is_type_proc(e->type));
 	e = strip_entity_wrapping(e);
 	e = strip_entity_wrapping(e);
 	GB_ASSERT(e != nullptr);
 	GB_ASSERT(e != nullptr);
 	auto *found = map_get(&m->values, hash_entity(e));
 	auto *found = map_get(&m->values, hash_entity(e));
@@ -5691,8 +5717,14 @@ lbValue lb_find_procedure_value_from_entity(lbModule *m, Entity *e) {
 		return *found;
 		return *found;
 	}
 	}
 
 
-	// TODO(bill): this is
-	lbProcedure *missing_proc = lb_create_procedure(m, e);
+	bool ignore_body = false;
+
+	if (USE_SEPARTE_MODULES) {
+		lbModule *other_module = lb_pkg_module(m->gen, e->pkg);
+		ignore_body = other_module != m;
+	}
+
+	lbProcedure *missing_proc = lb_create_procedure(m, e, ignore_body);
 	found = map_get(&m->values, hash_entity(e));
 	found = map_get(&m->values, hash_entity(e));
 	if (found) {
 	if (found) {
 		return *found;
 		return *found;
@@ -5702,6 +5734,47 @@ lbValue lb_find_procedure_value_from_entity(lbModule *m, Entity *e) {
 	return {};
 	return {};
 }
 }
 
 
+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)) {
+		return lb_find_procedure_value_from_entity(m, e);
+	}
+
+	auto *found = map_get(&m->values, hash_entity(e));
+	if (found) {
+		return *found;
+	}
+
+	if (USE_SEPARTE_MODULES) {
+		lbModule *other_module = lb_pkg_module(m->gen, e->pkg);
+		bool is_external = other_module != m;
+		if (!is_external) {
+			other_module = e->code_gen_module;
+			is_external = other_module != m;
+		}
+
+		if (is_external) {
+			String name = lb_get_entity_name(other_module, e);
+
+			lbValue g = {};
+			g.value = LLVMAddGlobal(m->mod, lb_type(m, e->type), alloc_cstring(permanent_allocator(), name));
+			g.type = alloc_type_pointer(e->type);
+			LLVMSetExternallyInitialized(g.value, true);
+
+			lb_add_entity(m, e, g);
+			lb_add_member(m, name, g);
+			return g;
+		}
+	}
+
+	GB_PANIC("\n\tError in: %s, missing value %.*s\n", token_pos_to_string(e->token.pos), LIT(e->token.string));
+	return {};
+}
+
+
+
+
 
 
 lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_local) {
 lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_local) {
 	LLVMContextRef ctx = m->ctx;
 	LLVMContextRef ctx = m->ctx;
@@ -5777,8 +5850,8 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc
 			} else {
 			} else {
 				isize max_len = 7+8+1;
 				isize max_len = 7+8+1;
 				char *str = gb_alloc_array(permanent_allocator(), char, max_len);
 				char *str = gb_alloc_array(permanent_allocator(), char, max_len);
-				isize len = gb_snprintf(str, max_len, "csba$%x", m->global_array_index);
-				m->global_array_index++;
+				u32 id = cast(u32)gb_atomic32_fetch_add(&m->gen->global_array_index, 1);
+				isize len = gb_snprintf(str, max_len, "csba$%x", id);
 
 
 				String name = make_string(cast(u8 *)str, len-1);
 				String name = make_string(cast(u8 *)str, len-1);
 
 
@@ -8192,31 +8265,18 @@ lbValue lb_emit_call_internal(lbProcedure *p, lbValue value, lbValue return_ptr,
 	}
 	}
 }
 }
 
 
-lbValue lb_emit_runtime_call(lbProcedure *p, char const *c_name, Array<lbValue> const &args) {
-	// LLVMMetadataRef curr_loc = LLVMGetCurrentDebugLocation2(p->builder);
-	// LLVMSetCurrentDebugLocation2(p->builder, nullptr);
-	// defer (if (curr_loc) {
-	// 	LLVMSetCurrentDebugLocation2(p->builder, curr_loc);
-	// });
 
 
-	String name = make_string_c(c_name);
-
-
-	AstPackage *pkg = p->module->info->runtime_package;
+lbValue lb_lookup_runtime_procedure(lbModule *m, String const &name) {
+	AstPackage *pkg = m->info->runtime_package;
 	Entity *e = scope_lookup_current(pkg->scope, name);
 	Entity *e = scope_lookup_current(pkg->scope, name);
+	return lb_find_procedure_value_from_entity(m, e);
+}
 
 
-	lbValue *found = nullptr;
-	if (p->module != e->code_gen_module) {
-		gb_mutex_lock(&p->module->mutex);
-	}
-	GB_ASSERT(e->code_gen_module != nullptr);
-	found = map_get(&e->code_gen_module->values, hash_entity(e));
-	if (p->module != e->code_gen_module) {
-		gb_mutex_unlock(&p->module->mutex);
-	}
 
 
-	GB_ASSERT_MSG(found != nullptr, "%s", c_name);
-	return lb_emit_call(p, *found, args);
+lbValue lb_emit_runtime_call(lbProcedure *p, char const *c_name, Array<lbValue> const &args) {
+	String name = make_string_c(c_name);
+	lbValue proc = lb_lookup_runtime_procedure(p->module, name);
+	return lb_emit_call(p, proc, args);
 }
 }
 
 
 lbValue lb_emit_call(lbProcedure *p, lbValue value, Array<lbValue> const &args, ProcInlining inlining, bool use_return_ptr_hint) {
 lbValue lb_emit_call(lbProcedure *p, lbValue value, Array<lbValue> const &args, ProcInlining inlining, bool use_return_ptr_hint) {
@@ -9946,24 +10006,6 @@ void lb_emit_increment(lbProcedure *p, lbValue addr) {
 
 
 }
 }
 
 
-LLVMValueRef lb_lookup_runtime_procedure(lbModule *m, String const &name) {
-	AstPackage *pkg = m->info->runtime_package;
-	Entity *e = scope_lookup_current(pkg->scope, name);
-
-	lbValue *found = nullptr;
-	if (m != e->code_gen_module) {
-		gb_mutex_lock(&m->mutex);
-	}
-	GB_ASSERT(e->code_gen_module != nullptr);
-	found = map_get(&e->code_gen_module->values, hash_entity(e));
-	if (m != e->code_gen_module) {
-		gb_mutex_unlock(&m->mutex);
-	}
-	GB_ASSERT(found != nullptr);
-
-	return found->value;
-}
-
 lbValue lb_emit_byte_swap(lbProcedure *p, lbValue value, Type *end_type) {
 lbValue lb_emit_byte_swap(lbProcedure *p, lbValue value, Type *end_type) {
 	GB_ASSERT(type_size_of(value.type) == type_size_of(end_type));
 	GB_ASSERT(type_size_of(value.type) == type_size_of(end_type));
 
 
@@ -11122,6 +11164,44 @@ lbValue lb_emit_any_cast(lbProcedure *p, lbValue value, Type *type, TokenPos pos
 }
 }
 
 
 
 
+lbValue lb_find_ident(lbProcedure *p, lbModule *m, Entity *e, Ast *expr) {
+	auto *found = map_get(&m->values, hash_entity(e));
+	if (found) {
+		auto v = *found;
+		// NOTE(bill): This is because pointers are already pointers in LLVM
+		if (is_type_proc(v.type)) {
+			return v;
+		}
+		return lb_emit_load(p, v);
+	} else if (e != nullptr && e->kind == Entity_Variable) {
+		return lb_addr_load(p, lb_build_addr(p, expr));
+	}
+
+	if (USE_SEPARTE_MODULES) {
+		lbModule *other_module = lb_pkg_module(m->gen, e->pkg);
+		if (other_module != m) {
+			String name = lb_get_entity_name(other_module, e);
+
+			lbValue g = {};
+			g.value = LLVMAddGlobal(m->mod, lb_type(m, e->type), alloc_cstring(permanent_allocator(), name));
+			g.type = alloc_type_pointer(e->type);
+			LLVMSetExternallyInitialized(g.value, true);
+
+			lb_add_entity(m, e, g);
+			lb_add_member(m, name, g);
+			return lb_emit_load(p, g);
+		}
+	}
+
+	String pkg = {};
+	if (e->pkg) {
+		pkg = e->pkg->name;
+	}
+	gb_printf_err("Error in: %s\n", token_pos_to_string(ast_token(expr).pos));
+	GB_PANIC("nullptr value for expression from identifier: %.*s.%.*s (%p) : %s @ %p", LIT(pkg), LIT(e->token.string), e, type_to_string(e->type), expr);
+	return {};
+}
+
 lbValue lb_build_expr(lbProcedure *p, Ast *expr) {
 lbValue lb_build_expr(lbProcedure *p, Ast *expr) {
 	lbModule *m = p->module;
 	lbModule *m = p->module;
 
 
@@ -11211,24 +11291,7 @@ lbValue lb_build_expr(lbProcedure *p, Ast *expr) {
 		}
 		}
 		GB_ASSERT(e->kind != Entity_ProcGroup);
 		GB_ASSERT(e->kind != Entity_ProcGroup);
 
 
-		auto *found = map_get(&p->module->values, hash_entity(e));
-		if (found) {
-			auto v = *found;
-			// NOTE(bill): This is because pointers are already pointers in LLVM
-			if (is_type_proc(v.type)) {
-				return v;
-			}
-			return lb_emit_load(p, v);
-		} else if (e != nullptr && e->kind == Entity_Variable) {
-			return lb_addr_load(p, lb_build_addr(p, expr));
-		}
-		gb_printf_err("Error in: %s\n", token_pos_to_string(i->token.pos));
-		String pkg = {};
-		if (e->pkg) {
-			pkg = e->pkg->name;
-		}
-		GB_PANIC("nullptr value for expression from identifier: %.*s.%.*s (%p) : %s @ %p", LIT(pkg), LIT(e->token.string), e, type_to_string(e->type), expr);
-		return {};
+		return lb_find_ident(p, m, e, expr);
 	case_end;
 	case_end;
 
 
 	case_ast_node(de, DerefExpr, expr);
 	case_ast_node(de, DerefExpr, expr);
@@ -11609,11 +11672,14 @@ lbAddr lb_build_addr_from_entity(lbProcedure *p, Entity *e, Ast *expr) {
 		return lb_get_soa_variable_addr(p, e);
 		return lb_get_soa_variable_addr(p, e);
 	}
 	}
 
 
+
 	if (v.value == nullptr) {
 	if (v.value == nullptr) {
-		error(expr, "%.*s Unknown value: %.*s, entity: %p %.*s",
-		      LIT(p->name),
-		      LIT(e->token.string), e, LIT(entity_strings[e->kind]));
-		GB_PANIC("Unknown value");
+		return lb_addr(lb_find_value_from_entity(p->module, e));
+
+		// error(expr, "%.*s Unknown value: %.*s, entity: %p %.*s",
+		//       LIT(p->name),
+		//       LIT(e->token.string), e, LIT(entity_strings[e->kind]));
+		// GB_PANIC("Unknown value");
 	}
 	}
 
 
 	return lb_addr(v);
 	return lb_addr(v);
@@ -13031,18 +13097,31 @@ bool lb_init_generator(lbGenerator *gen, Checker *c) {
 	gen->info = &c->info;
 	gen->info = &c->info;
 
 
 	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);
 
 
-	for_array(i, gen->info->packages.entries) {
-		AstPackage *pkg = gen->info->packages.entries[i].value;
+	if (USE_SEPARTE_MODULES) {
+		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);
+			auto m = gb_alloc_item(permanent_allocator(), lbModule);
+			m->pkg = pkg;
+			m->gen = gen;
+			map_set(&gen->modules, hash_pointer(pkg), m);
+			lb_init_module(m, c);
+		}
 	}
 	}
+
+	gen->default_module.gen = gen;
 	map_set(&gen->modules, hash_pointer(nullptr), &gen->default_module);
 	map_set(&gen->modules, hash_pointer(nullptr), &gen->default_module);
 	lb_init_module(&gen->default_module, c);
 	lb_init_module(&gen->default_module, c);
 
 
+
+	for_array(i, gen->modules.entries) {
+		lbModule *m = gen->modules.entries[i].value;
+		LLVMContextRef ctx = LLVMGetModuleContext(m->mod);
+		map_set(&gen->modules_through_ctx, hash_pointer(ctx), m);
+	}
+
 	return true;
 	return true;
 }
 }
 
 
@@ -13052,8 +13131,10 @@ lbAddr lb_add_global_generated(lbModule *m, Type *type, lbValue value) {
 
 
 	isize max_len = 7+8+1;
 	isize max_len = 7+8+1;
 	u8 *str = cast(u8 *)gb_alloc_array(permanent_allocator(), u8, max_len);
 	u8 *str = cast(u8 *)gb_alloc_array(permanent_allocator(), u8, max_len);
-	isize len = gb_snprintf(cast(char *)str, max_len, "ggv$%x", m->global_generated_index);
-	m->global_generated_index++;
+
+	u32 id = cast(u32)gb_atomic32_fetch_add(&m->gen->global_generated_index, 1);
+
+	isize len = gb_snprintf(cast(char *)str, max_len, "ggv$%x", id);
 	String name = make_string(str, len-1);
 	String name = make_string(str, len-1);
 
 
 	Scope *scope = nullptr;
 	Scope *scope = nullptr;
@@ -13076,17 +13157,12 @@ lbAddr lb_add_global_generated(lbModule *m, Type *type, lbValue value) {
 lbValue lb_find_runtime_value(lbModule *m, String const &name) {
 lbValue lb_find_runtime_value(lbModule *m, String const &name) {
 	AstPackage *p = m->info->runtime_package;
 	AstPackage *p = m->info->runtime_package;
 	Entity *e = scope_lookup_current(p->scope, name);
 	Entity *e = scope_lookup_current(p->scope, name);
-	lbValue *found = map_get(&m->values, hash_entity(e));
-	GB_ASSERT_MSG(found != nullptr, "Unable to find runtime value '%.*s'", LIT(name));
-	lbValue value = *found;
-	return value;
+	return lb_find_value_from_entity(m, e);
 }
 }
 lbValue lb_find_package_value(lbModule *m, String const &pkg, String const &name) {
 lbValue lb_find_package_value(lbModule *m, String const &pkg, String const &name) {
 	Entity *e = find_entity_in_pkg(m->info, pkg, name);
 	Entity *e = find_entity_in_pkg(m->info, pkg, name);
 	lbValue *found = map_get(&m->values, hash_entity(e));
 	lbValue *found = map_get(&m->values, hash_entity(e));
-	GB_ASSERT_MSG(found != nullptr, "Unable to find value '%.*s.%.*s'", LIT(pkg), LIT(name));
-	lbValue value = *found;
-	return value;
+	return lb_find_value_from_entity(m, e);
 }
 }
 
 
 lbValue lb_get_type_info_ptr(lbModule *m, Type *type) {
 lbValue lb_get_type_info_ptr(lbModule *m, Type *type) {
@@ -13900,8 +13976,8 @@ lbProcedure *lb_create_startup_type_info(lbModule *m) {
 	return p;
 	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);
+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);
 	defer (LLVMDisposePassManager(default_function_pass_manager));
 	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);
@@ -13911,12 +13987,12 @@ lbProcedure *lb_create_startup_runtime(lbModule *m, lbProcedure *startup_type_in
 
 
 	Type *proc_type = alloc_type_proc(nullptr, nullptr, 0, nullptr, 0, false, ProcCC_CDecl);
 	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);
+	lbProcedure *p = lb_create_dummy_procedure(main_module, str_lit(LB_STARTUP_RUNTIME_PROC_NAME), proc_type);
 	p->is_startup = true;
 	p->is_startup = true;
 
 
 	lb_begin_procedure_body(p);
 	lb_begin_procedure_body(p);
 
 
-	LLVMBuildCall2(p->builder, LLVMGetElementType(lb_type(m, startup_type_info->type)), startup_type_info->value, nullptr, 0, "");
+	LLVMBuildCall2(p->builder, LLVMGetElementType(lb_type(main_module, startup_type_info->type)), startup_type_info->value, nullptr, 0, "");
 
 
 	for_array(i, global_variables) {
 	for_array(i, global_variables) {
 		auto *var = &global_variables[i];
 		auto *var = &global_variables[i];
@@ -13924,8 +14000,11 @@ lbProcedure *lb_create_startup_runtime(lbModule *m, lbProcedure *startup_type_in
 			continue;
 			continue;
 		}
 		}
 
 
+		lbModule *entity_module = main_module;
+
 		Entity *e = var->decl->entity;
 		Entity *e = var->decl->entity;
 		GB_ASSERT(e->kind == Entity_Variable);
 		GB_ASSERT(e->kind == Entity_Variable);
+		e->code_gen_module = entity_module;
 
 
 		if (var->decl->init_expr != nullptr)  {
 		if (var->decl->init_expr != nullptr)  {
 			// gb_printf_err("%s\n", expr_to_string(var->decl->init_expr));
 			// gb_printf_err("%s\n", expr_to_string(var->decl->init_expr));
@@ -13951,14 +14030,14 @@ lbProcedure *lb_create_startup_runtime(lbModule *m, lbProcedure *startup_type_in
 			if (is_type_any(t)) {
 			if (is_type_any(t)) {
 				// NOTE(bill): Edge case for 'any' type
 				// NOTE(bill): Edge case for 'any' type
 				Type *var_type = default_type(var->init.type);
 				Type *var_type = default_type(var->init.type);
-				lbAddr g = lb_add_global_generated(m, var_type, var->init);
+				lbAddr g = lb_add_global_generated(main_module, var_type, var->init);
 				lb_addr_store(p, g, var->init);
 				lb_addr_store(p, g, var->init);
 				lbValue gp = lb_addr_get_ptr(p, g);
 				lbValue gp = lb_addr_get_ptr(p, g);
 
 
 				lbValue data = lb_emit_struct_ep(p, var->var, 0);
 				lbValue data = lb_emit_struct_ep(p, var->var, 0);
 				lbValue ti   = lb_emit_struct_ep(p, var->var, 1);
 				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, data, lb_emit_conv(p, gp, t_rawptr));
-				lb_emit_store(p, ti,   lb_type_info(m, var_type));
+				lb_emit_store(p, ti,   lb_type_info(main_module, var_type));
 			} else {
 			} else {
 				LLVMTypeRef pvt = LLVMTypeOf(var->var.value);
 				LLVMTypeRef pvt = LLVMTypeOf(var->var.value);
 				LLVMTypeRef vt = LLVMGetElementType(pvt);
 				LLVMTypeRef vt = LLVMGetElementType(pvt);
@@ -13975,7 +14054,7 @@ lbProcedure *lb_create_startup_runtime(lbModule *m, lbProcedure *startup_type_in
 
 
 	lb_end_procedure_body(p);
 	lb_end_procedure_body(p);
 
 
-	if (!m->debug_builder && LLVMVerifyFunction(p->value, LLVMReturnStatusAction)) {
+	if (!main_module->debug_builder && LLVMVerifyFunction(p->value, LLVMReturnStatusAction)) {
 		gb_printf_err("LLVM CODE GEN FAILED FOR PROCEDURE: %s\n", "main");
 		gb_printf_err("LLVM CODE GEN FAILED FOR PROCEDURE: %s\n", "main");
 		LLVMDumpValue(p->value);
 		LLVMDumpValue(p->value);
 		gb_printf_err("\n\n\n\n");
 		gb_printf_err("\n\n\n\n");
@@ -14085,9 +14164,8 @@ lbProcedure *lb_create_main_procedure(lbModule *m, lbProcedure *startup_runtime)
 		args[0] = lb_addr_load(p, all_tests_slice);
 		args[0] = lb_addr_load(p, all_tests_slice);
 		lb_emit_call(p, runner, args);
 		lb_emit_call(p, runner, args);
 	} else {
 	} else {
-		lbValue *found = map_get(&m->values, hash_entity(m->info->entry_point));
-		GB_ASSERT(found != nullptr);
-		lb_emit_call(p, *found, {});
+		lbValue entry_point = lb_find_procedure_value_from_entity(m, m->info->entry_point);
+		lb_emit_call(p, entry_point, {});
 	}
 	}
 
 
 	LLVMBuildRet(p->builder, LLVMConstInt(lb_type(m, t_i32), 0, false));
 	LLVMBuildRet(p->builder, LLVMConstInt(lb_type(m, t_i32), 0, false));
@@ -14105,13 +14183,51 @@ lbProcedure *lb_create_main_procedure(lbModule *m, lbProcedure *startup_runtime)
 	return p;
 	return p;
 }
 }
 
 
+String lb_filepath_ll_for_module(lbModule *m) {
+	String path = m->gen->output_base;
+	if (m->pkg) {
+		path = concatenate3_strings(permanent_allocator(), path, STR_LIT("-"), m->pkg->name);
+	}
+	path = concatenate_strings(permanent_allocator(), path, STR_LIT(".ll"));
+
+	return path;
+}
+String lb_filepath_obj_for_module(lbModule *m) {
+	String path = m->gen->output_base;
+	if (m->pkg) {
+		path = concatenate3_strings(permanent_allocator(), path, STR_LIT("-"), m->pkg->name);
+	}
+
+	String ext = {};
+
+	if (build_context.build_mode == BuildMode_Assembly) {
+		ext = STR_LIT(".S");
+	} else {
+		switch (build_context.metrics.os) {
+		case TargetOs_windows:
+			ext = STR_LIT(".obj");
+			break;
+		case TargetOs_darwin:
+		case TargetOs_linux:
+		case TargetOs_essence:
+			ext = STR_LIT(".o");
+			break;
+		case TargetOs_js:
+			ext = STR_LIT(".wasm-obj");
+			break;
+		}
+	}
+
+	return concatenate_strings(permanent_allocator(), path, ext);
+}
+
 
 
 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)
 
 
 	TIME_SECTION("LLVM Initializtion");
 	TIME_SECTION("LLVM Initializtion");
 
 
-	lbModule *m = &gen->default_module;
+	lbModule *default_module = &gen->default_module;
 	CheckerInfo *info = gen->info;
 	CheckerInfo *info = gen->info;
 
 
 	auto *min_dep_set = &info->minimum_dependency_set;
 	auto *min_dep_set = &info->minimum_dependency_set;
@@ -14183,62 +14299,67 @@ void lb_generate_code(lbGenerator *gen) {
 		LLVMSetModuleDataLayout(gen->modules.entries[i].value->mod, LLVMCreateTargetDataLayout(target_machine));
 		LLVMSetModuleDataLayout(gen->modules.entries[i].value->mod, LLVMCreateTargetDataLayout(target_machine));
 	}
 	}
 
 
-	if (m->debug_builder) { // Debug Info
-		for_array(i, info->files.entries) {
-			AstFile *f = info->files.entries[i].value;
-			String fullpath = f->fullpath;
-			String filename = remove_directory_from_path(fullpath);
-			String directory = directory_from_path(fullpath);
-			LLVMMetadataRef res = LLVMDIBuilderCreateFile(m->debug_builder,
-				cast(char const *)filename.text, filename.len,
-				cast(char const *)directory.text, directory.len);
-			lb_set_llvm_metadata(m, f, res);
-		}
-
-		gbString producer = gb_string_make(heap_allocator(), "odin");
-		// producer = gb_string_append_fmt(producer, " version %.*s", LIT(ODIN_VERSION));
-		// #ifdef NIGHTLY
-		// producer = gb_string_appendc(producer, "-nightly");
-		// #endif
-		// #ifdef GIT_SHA
-		// producer = gb_string_append_fmt(producer, "-%s", GIT_SHA);
-		// #endif
-
-		gbString split_name = gb_string_make(heap_allocator(), "");
-
-		LLVMBool is_optimized = build_context.optimization_level > 0;
-		AstFile *init_file = m->info->init_package->files[0];
-		if (m->info->entry_point && m->info->entry_point->identifier && m->info->entry_point->identifier->file) {
-			init_file = m->info->entry_point->identifier->file;
-		}
-
-		LLVMBool split_debug_inlining = false;
-		LLVMBool debug_info_for_profiling = false;
-
-		m->debug_compile_unit = LLVMDIBuilderCreateCompileUnit(m->debug_builder, LLVMDWARFSourceLanguageC99,
-			lb_get_llvm_metadata(m, init_file),
-			producer, gb_string_length(producer),
-			is_optimized, "", 0,
-			1, split_name, gb_string_length(split_name),
-			LLVMDWARFEmissionFull,
-			0, split_debug_inlining,
-			debug_info_for_profiling,
-			"", 0, // sys_root
-			"", 0  // SDK
-		);
-		GB_ASSERT(m->debug_compile_unit != nullptr);
+	for_array(i, gen->modules.entries) {
+		lbModule *m = gen->modules.entries[i].value;
+		if (m->debug_builder) { // Debug Info
+			for_array(i, info->files.entries) {
+				AstFile *f = info->files.entries[i].value;
+				String fullpath = f->fullpath;
+				String filename = remove_directory_from_path(fullpath);
+				String directory = directory_from_path(fullpath);
+				LLVMMetadataRef res = LLVMDIBuilderCreateFile(m->debug_builder,
+					cast(char const *)filename.text, filename.len,
+					cast(char const *)directory.text, directory.len);
+				lb_set_llvm_metadata(m, f, res);
+			}
+
+			gbString producer = gb_string_make(heap_allocator(), "odin");
+			// producer = gb_string_append_fmt(producer, " version %.*s", LIT(ODIN_VERSION));
+			// #ifdef NIGHTLY
+			// producer = gb_string_appendc(producer, "-nightly");
+			// #endif
+			// #ifdef GIT_SHA
+			// producer = gb_string_append_fmt(producer, "-%s", GIT_SHA);
+			// #endif
+
+			gbString split_name = gb_string_make(heap_allocator(), "");
+
+			LLVMBool is_optimized = build_context.optimization_level > 0;
+			AstFile *init_file = m->info->init_package->files[0];
+			if (m->info->entry_point && m->info->entry_point->identifier && m->info->entry_point->identifier->file) {
+				init_file = m->info->entry_point->identifier->file;
+			}
+
+			LLVMBool split_debug_inlining = false;
+			LLVMBool debug_info_for_profiling = false;
+
+			m->debug_compile_unit = LLVMDIBuilderCreateCompileUnit(m->debug_builder, LLVMDWARFSourceLanguageC99,
+				lb_get_llvm_metadata(m, init_file),
+				producer, gb_string_length(producer),
+				is_optimized, "", 0,
+				1, split_name, gb_string_length(split_name),
+				LLVMDWARFEmissionFull,
+				0, split_debug_inlining,
+				debug_info_for_profiling,
+				"", 0, // sys_root
+				"", 0  // SDK
+			);
+			GB_ASSERT(m->debug_compile_unit != nullptr);
+		}
 	}
 	}
 
 
 	TIME_SECTION("LLVM Global Variables");
 	TIME_SECTION("LLVM Global Variables");
 
 
 	{
 	{
+		lbModule *m = default_module;
+
 		{ // Add type info data
 		{ // Add type info data
 			isize max_type_info_count = info->minimum_dependency_type_info_set.entries.count+1;
 			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);
 			// 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);
 			Type *t = alloc_type_array(t_type_info, max_type_info_count);
 			LLVMValueRef g = LLVMAddGlobal(m->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)));
 			LLVMSetInitializer(g, LLVMConstNull(lb_type(m, t)));
-			LLVMSetLinkage(g, LLVMInternalLinkage);
+			// LLVMSetLinkage(g, LLVMInternalLinkage);
 
 
 			lbValue value = {};
 			lbValue value = {};
 			value.value = g;
 			value.value = g;
@@ -14276,7 +14397,7 @@ void lb_generate_code(lbGenerator *gen) {
 					Type *t = alloc_type_array(t_type_info_ptr, count);
 					Type *t = alloc_type_array(t_type_info_ptr, count);
 					LLVMValueRef g = LLVMAddGlobal(m->mod, lb_type(m, t), name);
 					LLVMValueRef g = LLVMAddGlobal(m->mod, lb_type(m, t), name);
 					LLVMSetInitializer(g, LLVMConstNull(lb_type(m, t)));
 					LLVMSetInitializer(g, LLVMConstNull(lb_type(m, t)));
-					LLVMSetLinkage(g, LLVMInternalLinkage);
+					// LLVMSetLinkage(g, LLVMInternalLinkage);
 					lb_global_type_info_member_types = lb_addr({g, alloc_type_pointer(t)});
 					lb_global_type_info_member_types = lb_addr({g, alloc_type_pointer(t)});
 
 
 				}
 				}
@@ -14285,7 +14406,7 @@ void lb_generate_code(lbGenerator *gen) {
 					Type *t = alloc_type_array(t_string, count);
 					Type *t = alloc_type_array(t_string, count);
 					LLVMValueRef g = LLVMAddGlobal(m->mod, lb_type(m, t), name);
 					LLVMValueRef g = LLVMAddGlobal(m->mod, lb_type(m, t), name);
 					LLVMSetInitializer(g, LLVMConstNull(lb_type(m, t)));
 					LLVMSetInitializer(g, LLVMConstNull(lb_type(m, t)));
-					LLVMSetLinkage(g, LLVMInternalLinkage);
+					// LLVMSetLinkage(g, LLVMInternalLinkage);
 					lb_global_type_info_member_names = lb_addr({g, alloc_type_pointer(t)});
 					lb_global_type_info_member_names = lb_addr({g, alloc_type_pointer(t)});
 				}
 				}
 				{
 				{
@@ -14293,7 +14414,7 @@ void lb_generate_code(lbGenerator *gen) {
 					Type *t = alloc_type_array(t_uintptr, count);
 					Type *t = alloc_type_array(t_uintptr, count);
 					LLVMValueRef g = LLVMAddGlobal(m->mod, lb_type(m, t), name);
 					LLVMValueRef g = LLVMAddGlobal(m->mod, lb_type(m, t), name);
 					LLVMSetInitializer(g, LLVMConstNull(lb_type(m, t)));
 					LLVMSetInitializer(g, LLVMConstNull(lb_type(m, t)));
-					LLVMSetLinkage(g, LLVMInternalLinkage);
+					// LLVMSetLinkage(g, LLVMInternalLinkage);
 					lb_global_type_info_member_offsets = lb_addr({g, alloc_type_pointer(t)});
 					lb_global_type_info_member_offsets = lb_addr({g, alloc_type_pointer(t)});
 				}
 				}
 
 
@@ -14302,7 +14423,7 @@ void lb_generate_code(lbGenerator *gen) {
 					Type *t = alloc_type_array(t_bool, count);
 					Type *t = alloc_type_array(t_bool, count);
 					LLVMValueRef g = LLVMAddGlobal(m->mod, lb_type(m, t), name);
 					LLVMValueRef g = LLVMAddGlobal(m->mod, lb_type(m, t), name);
 					LLVMSetInitializer(g, LLVMConstNull(lb_type(m, t)));
 					LLVMSetInitializer(g, LLVMConstNull(lb_type(m, t)));
-					LLVMSetLinkage(g, LLVMInternalLinkage);
+					// LLVMSetLinkage(g, LLVMInternalLinkage);
 					lb_global_type_info_member_usings = lb_addr({g, alloc_type_pointer(t)});
 					lb_global_type_info_member_usings = lb_addr({g, alloc_type_pointer(t)});
 				}
 				}
 
 
@@ -14311,7 +14432,7 @@ void lb_generate_code(lbGenerator *gen) {
 					Type *t = alloc_type_array(t_string, count);
 					Type *t = alloc_type_array(t_string, count);
 					LLVMValueRef g = LLVMAddGlobal(m->mod, lb_type(m, t), name);
 					LLVMValueRef g = LLVMAddGlobal(m->mod, lb_type(m, t), name);
 					LLVMSetInitializer(g, LLVMConstNull(lb_type(m, t)));
 					LLVMSetInitializer(g, LLVMConstNull(lb_type(m, t)));
-					LLVMSetLinkage(g, LLVMInternalLinkage);
+					// LLVMSetLinkage(g, LLVMInternalLinkage);
 					lb_global_type_info_member_tags = lb_addr({g, alloc_type_pointer(t)});
 					lb_global_type_info_member_tags = lb_addr({g, alloc_type_pointer(t)});
 				}
 				}
 			}
 			}
@@ -14373,8 +14494,9 @@ void lb_generate_code(lbGenerator *gen) {
 		bool is_foreign = e->Variable.is_foreign;
 		bool is_foreign = e->Variable.is_foreign;
 		bool is_export  = e->Variable.is_export;
 		bool is_export  = e->Variable.is_export;
 
 
-		String name = lb_get_entity_name(m, e);
 
 
+		lbModule *m = &gen->default_module;
+		String name = lb_get_entity_name(m, e);
 
 
 		lbValue g = {};
 		lbValue g = {};
 		g.value = LLVMAddGlobal(m->mod, lb_type(m, e->type), alloc_cstring(permanent_allocator(), name));
 		g.value = LLVMAddGlobal(m->mod, lb_type(m, e->type), alloc_cstring(permanent_allocator(), name));
@@ -14409,7 +14531,7 @@ void lb_generate_code(lbGenerator *gen) {
 		}
 		}
 
 
 		if (e->flags & EntityFlag_Static) {
 		if (e->flags & EntityFlag_Static) {
-			LLVMSetLinkage(g.value, LLVMInternalLinkage);
+			// LLVMSetLinkage(g.value, LLVMInternalLinkage);
 		}
 		}
 
 
 		lbGlobalVariable var = {};
 		lbGlobalVariable var = {};
@@ -14439,6 +14561,7 @@ void lb_generate_code(lbGenerator *gen) {
 		lb_add_entity(m, e, g);
 		lb_add_entity(m, e, g);
 		lb_add_member(m, name, g);
 		lb_add_member(m, name, g);
 
 
+
 		if (m->debug_builder) {
 		if (m->debug_builder) {
 			String global_name = e->token.string;
 			String global_name = e->token.string;
 			if (global_name.len != 0 && global_name != "_") {
 			if (global_name.len != 0 && global_name != "_") {
@@ -14509,6 +14632,10 @@ void lb_generate_code(lbGenerator *gen) {
 			continue;
 			continue;
 		}
 		}
 
 
+		lbModule *m = &gen->default_module;
+		if (USE_SEPARTE_MODULES) {
+			m = lb_pkg_module(gen, e->pkg);
+		}
 
 
 		String mangled_name = lb_get_entity_name(m, e);
 		String mangled_name = lb_get_entity_name(m, e);
 
 
@@ -14526,108 +14653,70 @@ void lb_generate_code(lbGenerator *gen) {
 	}
 	}
 
 
 
 
-	TIME_SECTION("LLVM Registry Initializtion");
-
-	LLVMPassRegistryRef pass_registry = LLVMGetGlobalPassRegistry();
-
-	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));
-	defer (LLVMDisposePassManager(function_pass_manager_speed));
-
-	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);
-	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");
 	TIME_SECTION("LLVM Runtime Type Information Creation");
-	lbProcedure *startup_type_info = lb_create_startup_type_info(m);
+	lbProcedure *startup_type_info = lb_create_startup_type_info(default_module);
 
 
 	TIME_SECTION("LLVM Runtime Startup Creation (Global Variables)");
 	TIME_SECTION("LLVM Runtime Startup Creation (Global Variables)");
-	lbProcedure *startup_runtime = lb_create_startup_runtime(m, startup_type_info, global_variables);
-
+	lbProcedure *startup_runtime = lb_create_startup_runtime(default_module, startup_type_info, global_variables);
 
 
-	String filepath_ll = concatenate_strings(permanent_allocator(), gen->output_base, STR_LIT(".ll"));
 
 
 	TIME_SECTION("LLVM Procedure Generation");
 	TIME_SECTION("LLVM Procedure Generation");
-	for_array(i, m->procedures_to_generate) {
-		lbProcedure *p = m->procedures_to_generate[i];
-		if (p->is_done) {
-			continue;
-		}
-		if (p->body != nullptr) { // Build Procedure
-			m->curr_procedure = p;
-			lb_begin_procedure_body(p);
-			lb_build_stmt(p, p->body);
-			lb_end_procedure_body(p);
-			p->is_done = true;
-			m->curr_procedure = nullptr;
-		}
-		lb_end_procedure(p);
-
-		// Add Flags
-		if (p->body != nullptr) {
-			if (p->name == "memcpy" || p->name == "memmove" ||
-			    p->name == "runtime.mem_copy" || p->name == "mem_copy_non_overlapping" ||
-			    string_starts_with(p->name, str_lit("llvm.memcpy")) ||
-			    string_starts_with(p->name, str_lit("llvm.memmove"))) {
-				p->flags |= lbProcedureFlag_WithoutMemcpyPass;
+	for_array(j, gen->modules.entries) {
+		lbModule *m = gen->modules.entries[j].value;
+		for_array(i, m->procedures_to_generate) {
+			lbProcedure *p = m->procedures_to_generate[i];
+			if (p->is_done) {
+				continue;
 			}
 			}
-		}
-
-		if (!m->debug_builder && LLVMVerifyFunction(p->value, LLVMReturnStatusAction)) {
-			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(m->mod, cast(char const *)filepath_ll.text, &llvm_error)) {
-				gb_printf_err("LLVM Error: %s\n", llvm_error);
+			if (p->body != nullptr) { // Build Procedure
+				m->curr_procedure = p;
+				lb_begin_procedure_body(p);
+				lb_build_stmt(p, p->body);
+				lb_end_procedure_body(p);
+				p->is_done = true;
+				m->curr_procedure = nullptr;
+			}
+			lb_end_procedure(p);
+
+			// Add Flags
+			if (p->body != nullptr) {
+				if (p->name == "memcpy" || p->name == "memmove" ||
+				    p->name == "runtime.mem_copy" || p->name == "mem_copy_non_overlapping" ||
+				    string_starts_with(p->name, str_lit("llvm.memcpy")) ||
+				    string_starts_with(p->name, str_lit("llvm.memmove"))) {
+					p->flags |= lbProcedureFlag_WithoutMemcpyPass;
+				}
+			}
+
+			if (!m->debug_builder && LLVMVerifyFunction(p->value, LLVMReturnStatusAction)) {
+				gb_printf_err("LLVM CODE GEN FAILED FOR PROCEDURE: %.*s\n", LIT(p->name));
+				LLVMDumpValue(p->value);
+				gb_printf_err("\n\n\n\n");
+				String filepath_ll = lb_filepath_ll_for_module(m);
+				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);
+				gb_exit(1);
 			}
 			}
-			LLVMVerifyFunction(p->value, LLVMPrintMessageAction);
-			gb_exit(1);
 		}
 		}
 	}
 	}
 
 
 
 
 	if (!(build_context.build_mode == BuildMode_DynamicLibrary && !has_dll_main)) {
 	if (!(build_context.build_mode == BuildMode_DynamicLibrary && !has_dll_main)) {
 		TIME_SECTION("LLVM main");
 		TIME_SECTION("LLVM main");
-		lb_create_main_procedure(m, startup_runtime);
+		lb_create_main_procedure(default_module, startup_runtime);
 	}
 	}
 
 
-
-	if (m->debug_builder != nullptr) {
-		TIME_SECTION("LLVM Debug Info Complete Types");
-		lb_debug_complete_types(m);
-
-
-		TIME_SECTION("LLVM Print Module to File");
-		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;
+	if (build_context.ODIN_DEBUG) {
+		TIME_SECTION("LLVM Debug Info Complete Types and Finalize");
+		for_array(j, gen->modules.entries) {
+			lbModule *m = gen->modules.entries[j].value;
+			if (m->debug_builder != nullptr) {
+				lb_debug_complete_types(m);
+				LLVMDIBuilderFinalize(m->debug_builder);
+			}
 		}
 		}
-		TIME_SECTION("LLVM Debug Info Builder Finalize");
-		LLVMDIBuilderFinalize(m->debug_builder);
 	}
 	}
 
 
 
 
@@ -14635,6 +14724,38 @@ void lb_generate_code(lbGenerator *gen) {
 	for_array(i, gen->modules.entries) {
 	for_array(i, gen->modules.entries) {
 		lbModule *m = gen->modules.entries[i].value;
 		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);
+		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(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);
+		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);
+
+
 		for_array(i, m->procedures_to_generate) {
 		for_array(i, m->procedures_to_generate) {
 			lbProcedure *p = m->procedures_to_generate[i];
 			lbProcedure *p = m->procedures_to_generate[i];
 			if (p->body != nullptr) { // Build Procedure
 			if (p->body != nullptr) { // Build Procedure
@@ -14688,49 +14809,41 @@ void lb_generate_code(lbGenerator *gen) {
 	llvm_error = nullptr;
 	llvm_error = nullptr;
 	defer (LLVMDisposeMessage(llvm_error));
 	defer (LLVMDisposeMessage(llvm_error));
 
 
-	String filepath_obj = {};
 	LLVMCodeGenFileType code_gen_file_type = LLVMObjectFile;
 	LLVMCodeGenFileType code_gen_file_type = LLVMObjectFile;
-
 	if (build_context.build_mode == BuildMode_Assembly) {
 	if (build_context.build_mode == BuildMode_Assembly) {
-		filepath_obj = concatenate_strings(permanent_allocator(), gen->output_base, STR_LIT(".S"));
 		code_gen_file_type = LLVMAssemblyFile;
 		code_gen_file_type = LLVMAssemblyFile;
-	} else {
-		switch (build_context.metrics.os) {
-		case TargetOs_windows:
-			filepath_obj = concatenate_strings(permanent_allocator(), gen->output_base, STR_LIT(".obj"));
-			break;
-		case TargetOs_darwin:
-		case TargetOs_linux:
-		case TargetOs_essence:
-			filepath_obj = concatenate_strings(permanent_allocator(), gen->output_base, STR_LIT(".o"));
-			break;
-		case TargetOs_js:
-			filepath_obj = concatenate_strings(permanent_allocator(), gen->output_base, STR_LIT(".wasm-obj"));
-			break;
-		}
 	}
 	}
 
 
-	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(m->mod, cast(char const *)filepath_ll.text, &llvm_error)) {
-				gb_printf_err("LLVM Error: %s\n", llvm_error);
-				gb_exit(1);
-				return;
+	for_array(j, gen->modules.entries) {
+		lbModule *m = gen->modules.entries[j].value;
+		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");
+				String filepath_ll = lb_filepath_ll_for_module(m);
+				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;
+				}
 			}
 			}
+			gb_exit(1);
+			return;
 		}
 		}
-		gb_exit(1);
-		return;
 	}
 	}
 	llvm_error = nullptr;
 	llvm_error = nullptr;
 	if (build_context.keep_temp_files ||
 	if (build_context.keep_temp_files ||
 	    build_context.build_mode == BuildMode_LLVM_IR) {
 	    build_context.build_mode == BuildMode_LLVM_IR) {
 		TIME_SECTION("LLVM Print Module to File");
 		TIME_SECTION("LLVM Print Module to File");
-		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;
+
+		for_array(j, gen->modules.entries) {
+			lbModule *m = gen->modules.entries[j].value;
+			String filepath_ll = lb_filepath_ll_for_module(m);
+			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;
+			}
 		}
 		}
 		if (build_context.build_mode == BuildMode_LLVM_IR) {
 		if (build_context.build_mode == BuildMode_LLVM_IR) {
 			gb_exit(0);
 			gb_exit(0);
@@ -14740,18 +14853,25 @@ void lb_generate_code(lbGenerator *gen) {
 
 
 	TIME_SECTION("LLVM Object Generation");
 	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;
-	}
+	for_array(j, gen->modules.entries) {
+		lbModule *m = gen->modules.entries[j].value;
+		String filepath_obj = lb_filepath_obj_for_module(m);
 
 
-	array_add(&gen->output_object_paths, filepath_obj);
+		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;
+		}
 
 
-	for_array(i, m->info->required_foreign_imports_through_force) {
-		Entity *e = m->info->required_foreign_imports_through_force[i];
-		lb_add_foreign_library_path(m, e);
+		array_add(&gen->output_object_paths, filepath_obj);
+		for_array(i, m->info->required_foreign_imports_through_force) {
+			Entity *e = m->info->required_foreign_imports_through_force[i];
+			lb_add_foreign_library_path(m, e);
+		}
 	}
 	}
 
 
+
+
+
 #undef TIME_SECTION
 #undef TIME_SECTION
 }
 }

+ 8 - 3
src/llvm_backend.hpp

@@ -85,6 +85,8 @@ struct lbModule {
 	LLVMModuleRef mod;
 	LLVMModuleRef mod;
 	LLVMContextRef ctx;
 	LLVMContextRef ctx;
 
 
+	struct lbGenerator *gen;
+
 	CheckerInfo *info;
 	CheckerInfo *info;
 	AstPackage *pkg; // associated
 	AstPackage *pkg; // associated
 
 
@@ -108,8 +110,6 @@ struct lbModule {
 	Map<lbProcedure *> equal_procs; // Key: Type *
 	Map<lbProcedure *> equal_procs; // Key: Type *
 	Map<lbProcedure *> hasher_procs; // Key: Type *
 	Map<lbProcedure *> hasher_procs; // Key: Type *
 
 
-	u32 global_array_index;
-	u32 global_generated_index;
 	u32 nested_type_name_guid;
 	u32 nested_type_name_guid;
 
 
 	Array<lbProcedure *> procedures_to_generate;
 	Array<lbProcedure *> procedures_to_generate;
@@ -131,7 +131,11 @@ struct lbGenerator {
 	String   output_base;
 	String   output_base;
 	String   output_name;
 	String   output_name;
 	Map<lbModule *> modules; // Key: AstPackage *
 	Map<lbModule *> modules; // Key: AstPackage *
+	Map<lbModule *> modules_through_ctx; // Key: LLVMContextRef *
 	lbModule default_module;
 	lbModule default_module;
+
+	gbAtomic32 global_array_index;
+	gbAtomic32 global_generated_index;
 };
 };
 
 
 
 
@@ -271,7 +275,7 @@ String lb_get_entity_name(lbModule *m, Entity *e, String name = {});
 LLVMAttributeRef lb_create_enum_attribute(LLVMContextRef ctx, char const *name, u64 value=0);
 LLVMAttributeRef lb_create_enum_attribute(LLVMContextRef ctx, char const *name, u64 value=0);
 void lb_add_proc_attribute_at_index(lbProcedure *p, isize index, char const *name, u64 value);
 void lb_add_proc_attribute_at_index(lbProcedure *p, isize index, char const *name, u64 value);
 void lb_add_proc_attribute_at_index(lbProcedure *p, isize index, char const *name);
 void lb_add_proc_attribute_at_index(lbProcedure *p, isize index, char const *name);
-lbProcedure *lb_create_procedure(lbModule *module, Entity *entity);
+lbProcedure *lb_create_procedure(lbModule *module, Entity *entity, bool ignore_body=false);
 void lb_end_procedure(lbProcedure *p);
 void lb_end_procedure(lbProcedure *p);
 
 
 
 
@@ -383,6 +387,7 @@ lbValue lb_gen_map_hash(lbProcedure *p, lbValue key, Type *key_type);
 void    lb_insert_dynamic_map_key_and_value(lbProcedure *p, lbAddr addr, Type *map_type, lbValue map_key, lbValue map_value, Ast *node);
 void    lb_insert_dynamic_map_key_and_value(lbProcedure *p, lbAddr addr, Type *map_type, lbValue map_key, lbValue map_value, Ast *node);
 
 
 
 
+
 void lb_store_type_case_implicit(lbProcedure *p, Ast *clause, lbValue value);
 void lb_store_type_case_implicit(lbProcedure *p, Ast *clause, lbValue value);
 lbAddr lb_store_range_stmt_val(lbProcedure *p, Ast *stmt_val, lbValue value);
 lbAddr lb_store_range_stmt_val(lbProcedure *p, Ast *stmt_val, lbValue value);
 lbValue lb_emit_source_code_location(lbProcedure *p, String const &procedure, TokenPos const &pos);
 lbValue lb_emit_source_code_location(lbProcedure *p, String const &procedure, TokenPos const &pos);

+ 9 - 2
src/main.cpp

@@ -1542,12 +1542,19 @@ void show_timings(Checker *c, Timings *t) {
 	}
 	}
 }
 }
 
 
-void remove_temp_files(String output_base) {
+void remove_temp_files(lbGenerator *gen) {
 	if (build_context.keep_temp_files) return;
 	if (build_context.keep_temp_files) return;
 
 
+	String output_base = gen->output_base;
+
 	auto data = array_make<u8>(heap_allocator(), output_base.len + 30);
 	auto data = array_make<u8>(heap_allocator(), output_base.len + 30);
 	defer (array_free(&data));
 	defer (array_free(&data));
 
 
+	for_array(i, gen->output_object_paths) {
+		String path = gen->output_object_paths[i];
+		gb_file_remove(cast(char const *)path.text);
+	}
+
 	isize n = output_base.len;
 	isize n = output_base.len;
 	gb_memmove(data.data, output_base.text, n);
 	gb_memmove(data.data, output_base.text, n);
 #define EXT_REMOVE(s) do {                         \
 #define EXT_REMOVE(s) do {                         \
@@ -2183,7 +2190,7 @@ int main(int arg_count, char const **arg_ptr) {
 		show_timings(&checker, timings);
 		show_timings(&checker, timings);
 	}
 	}
 
 
-	remove_temp_files(gen.output_base);
+	remove_temp_files(&gen);
 
 
 	if (run_output) {
 	if (run_output) {
 	#if defined(GB_SYSTEM_WINDOWS)
 	#if defined(GB_SYSTEM_WINDOWS)