Browse Source

Basic functionality, except for `map` and correct nested typename mangling

gingerBill 5 years ago
parent
commit
f92334a769
5 changed files with 630 additions and 440 deletions
  1. 2 1
      build.bat
  2. 8 7
      examples/demo/demo.odin
  3. 352 166
      src/llvm_backend.cpp
  4. 4 2
      src/llvm_backend.hpp
  5. 264 264
      src/main.cpp

+ 2 - 1
build.bat

@@ -49,7 +49,8 @@ del *.ilk > NUL 2> NUL
 
 cl %compiler_settings% "src\main.cpp" ^
 	/link %linker_settings% -OUT:%exe_name% ^
-	&& odin build examples/llvm-demo/demo.odin -llvm-api -show-timings
+	&& odin build examples/demo/demo.odin -llvm-api -show-timings
+	rem && odin build examples/llvm-demo/demo.odin -llvm-api -show-timings
 if %errorlevel% neq 0 (
 	goto end_of_build
 )

+ 8 - 7
examples/demo/demo.odin

@@ -1245,7 +1245,7 @@ implicit_selector_expression :: proc() {
 
 	switch f {
 	case .A:
-		fmt.println("HERE");
+		fmt.println("HITHER");
 	case .B:
 		fmt.println("NEVER");
 	case .C:
@@ -1742,6 +1742,7 @@ range_statements_with_multiple_return_values :: proc() {
 	}
 }
 
+
 soa_struct_layout :: proc() {
 	// IMPORTANT NOTE(bill, 2019-11-03): This feature is subject to be changed/removed
 	// NOTE(bill): Most likely #soa [N]T
@@ -1933,22 +1934,22 @@ union_maybe :: proc() {
 main :: proc() {
 	when true {
 		the_basics();
-		control_flow();
+		// control_flow();
 		named_proc_return_parameters();
 		explicit_procedure_overloading();
 		struct_type();
 		union_type();
 		using_statement();
-		implicit_context_system();
+		// implicit_context_system();
 		parametric_polymorphism();
 		array_programming();
-		map_type();
-		implicit_selector_expression();
+		// map_type();
+		// implicit_selector_expression();
 		partial_switch();
 		cstring_example();
 		bit_set_type();
 		deferred_procedure_associations();
-		reflection();
+		// reflection();
 		quaternions();
 		inline_for_statement();
 		where_clauses();
@@ -1957,7 +1958,7 @@ main :: proc() {
 		deprecated_attribute();
 		range_statements_with_multiple_return_values();
 		threading_example();
-		soa_struct_layout();
+		// soa_struct_layout();
 		constant_literal_expressions();
 		union_maybe();
 	}

+ 352 - 166
src/llvm_backend.cpp

@@ -376,10 +376,17 @@ lbValue lb_emit_union_tag_ptr(lbProcedure *p, lbValue u) {
 	GB_ASSERT_MSG(is_type_pointer(t) &&
 	              is_type_union(type_deref(t)), "%s", type_to_string(t));
 	Type *ut = type_deref(t);
+
+	GB_ASSERT(!is_type_union_maybe_pointer_original_alignment(ut));
 	GB_ASSERT(!is_type_union_maybe_pointer(ut));
 	GB_ASSERT(type_size_of(ut) > 0);
+
 	Type *tag_type = union_tag_type(ut);
 
+	LLVMTypeRef uvt = LLVMGetElementType(LLVMTypeOf(u.value));
+	unsigned element_count = LLVMCountStructElementTypes(uvt);
+	GB_ASSERT_MSG(element_count == 3, "(%s) != (%s)", type_to_string(ut), LLVMPrintTypeToString(uvt));
+
 	lbValue tag_ptr = {};
 	tag_ptr.value = LLVMBuildStructGEP(p->builder, u.value, 2, "");
 	tag_ptr.type = alloc_type_pointer(tag_type);
@@ -455,6 +462,13 @@ String lb_mangle_name(lbModule *m, Entity *e) {
 
 	isize max_len = pkgn.len + 1 + name.len + 1;
 	bool require_suffix_id = is_type_polymorphic(e->type, true);
+
+	if ((e->scope->flags & (ScopeFlag_File | ScopeFlag_Pkg)) == 0) {
+		require_suffix_id = true;
+	} else {
+		require_suffix_id = true;
+	}
+
 	if (require_suffix_id) {
 		max_len += 21;
 	}
@@ -471,7 +485,7 @@ String lb_mangle_name(lbModule *m, Entity *e) {
 		new_name_len += extra-1;
 	}
 
-	return make_string((u8 *)new_name, new_name_len-1);
+	return make_string((u8 const *)new_name, new_name_len-1);
 }
 
 String lb_get_entity_name(lbModule *m, Entity *e, String default_name) {
@@ -727,9 +741,15 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
 			if (found) {
 				LLVMTypeKind kind = LLVMGetTypeKind(*found);
 				if (kind == LLVMStructTypeKind) {
-					LLVMTypeRef llvm_type = LLVMStructCreateNamed(ctx, alloc_cstring(heap_allocator(), lb_get_entity_name(m, type->Named.type_name)));
+					char const *name = alloc_cstring(heap_allocator(), lb_get_entity_name(m, type->Named.type_name));
+					LLVMTypeRef llvm_type = LLVMGetTypeByName(m->mod, name);
+					if (llvm_type != nullptr) {
+						return llvm_type;
+					}
+					llvm_type = LLVMStructCreateNamed(ctx, name);
 					map_set(&m->types, hash_type(type), llvm_type);
 					lb_clone_struct_type(llvm_type, *found);
+					return llvm_type;
 				}
 			}
 
@@ -738,7 +758,12 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
 			case Type_Union:
 			case Type_BitField:
 				{
-					LLVMTypeRef llvm_type = LLVMStructCreateNamed(ctx, alloc_cstring(heap_allocator(), lb_get_entity_name(m, type->Named.type_name)));
+					char const *name = alloc_cstring(heap_allocator(), lb_get_entity_name(m, type->Named.type_name));
+					LLVMTypeRef llvm_type = LLVMGetTypeByName(m->mod, name);
+					if (llvm_type != nullptr) {
+						return llvm_type;
+					}
+					llvm_type = LLVMStructCreateNamed(ctx, name);
 					map_set(&m->types, hash_type(type), llvm_type);
 					lb_clone_struct_type(llvm_type, lb_type(m, base));
 					return llvm_type;
@@ -1008,7 +1033,7 @@ LLVMAttributeRef lb_create_enum_attribute(LLVMContextRef ctx, char const *name,
 
 void lb_add_proc_attribute_at_index(lbProcedure *p, isize index, char const *name, u64 value) {
 	LLVMContextRef ctx = LLVMGetModuleContext(p->module->mod);
-	LLVMAddAttributeAtIndex(p->value, cast(unsigned)index, lb_create_enum_attribute(ctx, name, value));
+	// LLVMAddAttributeAtIndex(p->value, cast(unsigned)index, lb_create_enum_attribute(ctx, name, value));
 }
 
 void lb_add_proc_attribute_at_index(lbProcedure *p, isize index, char const *name) {
@@ -1633,7 +1658,7 @@ lbAddr lb_add_local(lbProcedure *p, Type *type, Entity *e, bool zero_init, i32 p
 
 	char const *name = "";
 	if (e != nullptr) {
-		name = alloc_cstring(heap_allocator(), e->token.string);
+		// name = alloc_cstring(heap_allocator(), e->token.string);
 	}
 
 	LLVMTypeRef llvm_type = lb_type(p->module, type);
@@ -1702,6 +1727,41 @@ void lb_build_nested_proc(lbProcedure *p, AstProcLit *pd, Entity *e) {
 	array_add(&m->procedures_to_generate, nested_proc);
 }
 
+
+void lb_add_foreign_library_path(lbModule *m, Entity *e) {
+	if (e == nullptr) {
+		return;
+	}
+	GB_ASSERT(e->kind == Entity_LibraryName);
+	GB_ASSERT(e->flags & EntityFlag_Used);
+
+	for_array(i, e->LibraryName.paths) {
+		String library_path = e->LibraryName.paths[i];
+		if (library_path.len == 0) {
+			continue;
+		}
+
+		bool ok = true;
+		for_array(path_index, m->foreign_library_paths) {
+			String path = m->foreign_library_paths[path_index];
+	#if defined(GB_SYSTEM_WINDOWS)
+			if (str_eq_ignore_case(path, library_path)) {
+	#else
+			if (str_eq(path, library_path)) {
+	#endif
+				ok = false;
+				break;
+			}
+		}
+
+		if (ok) {
+			array_add(&m->foreign_library_paths, library_path);
+		}
+	}
+}
+
+
+
 void lb_build_constant_value_decl(lbProcedure *p, AstValueDecl *vd) {
 	if (vd == nullptr || vd->is_mutable) {
 		return;
@@ -1709,104 +1769,109 @@ void lb_build_constant_value_decl(lbProcedure *p, AstValueDecl *vd) {
 
 	auto *min_dep_set = &p->module->info->minimum_dependency_set;
 
+	static i32 global_guid = 0;
 
 	for_array(i, vd->names) {
 		Ast *ident = vd->names[i];
 		GB_ASSERT(ident->kind == Ast_Ident);
 		Entity *e = entity_of_ident(ident);
 		GB_ASSERT(e != nullptr);
-		switch (e->kind) {
-		case Entity_TypeName:
-		case Entity_Procedure:
-			break;
-		default:
+		if (e->kind != Entity_TypeName) {
 			continue;
 		}
 
-		if (e->kind == Entity_TypeName) {
-			bool polymorphic_struct = false;
-			if (e->type != nullptr && e->kind == Entity_TypeName) {
-			Type *bt = base_type(e->type);
-				if (bt->kind == Type_Struct) {
-					polymorphic_struct = bt->Struct.is_polymorphic;
-				}
+		bool polymorphic_struct = false;
+		if (e->type != nullptr && e->kind == Entity_TypeName) {
+		Type *bt = base_type(e->type);
+			if (bt->kind == Type_Struct) {
+				polymorphic_struct = bt->Struct.is_polymorphic;
 			}
+		}
 
-			if (!polymorphic_struct && !ptr_set_exists(min_dep_set, e)) {
-				continue;
-			}
+		if (!polymorphic_struct && !ptr_set_exists(min_dep_set, e)) {
+			continue;
+		}
 
-			// NOTE(bill): Generate a new name
-			// parent_proc.name-guid
-			String ts_name = e->token.string;
-
-			lbModule *m = p->module;
-			isize name_len = p->name.len + 1 + ts_name.len + 1 + 10 + 1;
-			char *name_text = gb_alloc_array(heap_allocator(), char, name_len);
-			i32 guid = cast(i32)m->members.entries.count;
-			name_len = gb_snprintf(name_text, name_len, "%.*s.%.*s-%d", LIT(p->name), LIT(ts_name), guid);
-
-			String name = make_string(cast(u8 *)name_text, name_len-1);
-			e->TypeName.ir_mangled_name = name;
-
-			// lbValue value = ir_value_type_name(name, e->type);
-			// ir_add_entity_name(m, e, name);
-			// ir_gen_global_type_name(m, e, name);
-		} else if (e->kind == Entity_Procedure) {
-			CheckerInfo *info = p->module->info;
-			DeclInfo *decl = decl_info_of_entity(e);
-			ast_node(pl, ProcLit, decl->proc_lit);
-			if (pl->body != nullptr) {
-				auto *found = map_get(&info->gen_procs, hash_pointer(ident));
-				if (found) {
-					auto procs = *found;
-					for_array(i, procs) {
-						Entity *e = procs[i];
-						if (!ptr_set_exists(min_dep_set, e)) {
-							continue;
-						}
-						DeclInfo *d = decl_info_of_entity(e);
-						lb_build_nested_proc(p, &d->proc_lit->ProcLit, e);
+		// NOTE(bill): Generate a new name
+		// parent_proc.name-guid
+		String ts_name = e->token.string;
+
+		lbModule *m = p->module;
+		isize name_len = p->name.len + 1 + ts_name.len + 1 + 10 + 1;
+		char *name_text = gb_alloc_array(heap_allocator(), char, name_len);
+		u32 guid = ++p->module->nested_type_name_guid;
+		name_len = gb_snprintf(name_text, name_len, "%.*s.%.*s-%u", LIT(p->name), LIT(ts_name), guid);
+
+		String name = make_string(cast(u8 *)name_text, name_len-1);
+		e->TypeName.ir_mangled_name = name;
+
+		// lbValue value = ir_value_type_name(name, e->type);
+		// ir_add_entity_name(m, e, name);
+		// ir_gen_global_type_name(m, e, name);
+	}
+
+	for_array(i, vd->names) {
+		Ast *ident = vd->names[i];
+		GB_ASSERT(ident->kind == Ast_Ident);
+		Entity *e = entity_of_ident(ident);
+		GB_ASSERT(e != nullptr);
+		if (e->kind != Entity_Procedure) {
+			continue;
+		}
+
+		CheckerInfo *info = p->module->info;
+		DeclInfo *decl = decl_info_of_entity(e);
+		ast_node(pl, ProcLit, decl->proc_lit);
+		if (pl->body != nullptr) {
+			auto *found = map_get(&info->gen_procs, hash_pointer(ident));
+			if (found) {
+				auto procs = *found;
+				for_array(i, procs) {
+					Entity *e = procs[i];
+					if (!ptr_set_exists(min_dep_set, e)) {
+						continue;
 					}
-				} else {
-					lb_build_nested_proc(p, pl, e);
+					DeclInfo *d = decl_info_of_entity(e);
+					lb_build_nested_proc(p, &d->proc_lit->ProcLit, e);
 				}
 			} else {
+				lb_build_nested_proc(p, pl, e);
+			}
+		} else {
 
-				// FFI - Foreign function interace
-				String original_name = e->token.string;
-				String name = original_name;
+			// FFI - Foreign function interace
+			String original_name = e->token.string;
+			String name = original_name;
 
-				if (e->Procedure.is_foreign) {
-					// lb_add_foreign_library_path(p->module, e->Procedure.foreign_library);
-				}
+			if (e->Procedure.is_foreign) {
+				lb_add_foreign_library_path(p->module, e->Procedure.foreign_library);
+			}
 
-				if (e->Procedure.link_name.len > 0) {
-					name = e->Procedure.link_name;
-				}
+			if (e->Procedure.link_name.len > 0) {
+				name = e->Procedure.link_name;
+			}
 
-				HashKey key = hash_string(name);
-				lbValue *prev_value = map_get(&p->module->members, key);
-				if (prev_value != nullptr) {
-					// NOTE(bill): Don't do mutliple declarations in the IR
-					return;
-				}
+			HashKey key = hash_string(name);
+			lbValue *prev_value = map_get(&p->module->members, key);
+			if (prev_value != nullptr) {
+				// NOTE(bill): Don't do mutliple declarations in the IR
+				return;
+			}
 
-				set_procedure_abi_types(heap_allocator(), e->type);
-				e->Procedure.link_name = name;
+			set_procedure_abi_types(heap_allocator(), e->type);
+			e->Procedure.link_name = name;
 
-				lbProcedure *nested_proc = lb_create_procedure(p->module, e);
+			lbProcedure *nested_proc = lb_create_procedure(p->module, e);
 
-				lbValue value = {};
-				value.value = nested_proc->value;
-				value.type = nested_proc->type;
+			lbValue value = {};
+			value.value = nested_proc->value;
+			value.type = nested_proc->type;
 
-				array_add(&p->module->procedures_to_generate, nested_proc);
-				if (p != nullptr) {
-					array_add(&p->children, nested_proc);
-				} else {
-					map_set(&p->module->members, hash_string(name), value);
-				}
+			array_add(&p->module->procedures_to_generate, nested_proc);
+			if (p != nullptr) {
+				array_add(&p->children, nested_proc);
+			} else {
+				map_set(&p->module->members, hash_string(name), value);
 			}
 		}
 	}
@@ -2710,13 +2775,14 @@ void lb_build_type_switch_stmt(lbProcedure *p, AstTypeSwitchStmt *ss) {
 
 	lbValue parent_ptr = parent;
 	if (!is_parent_ptr) {
-		parent_ptr = lb_address_from_load_or_generate_local(p, parent_ptr);
+		parent_ptr = lb_address_from_load_or_generate_local(p, parent);
 	}
 
 	lbValue tag_index = {};
 	lbValue union_data = {};
 	if (switch_kind == TypeSwitch_Union) {
-		tag_index = lb_emit_load(p, lb_emit_union_tag_ptr(p, parent_ptr));
+		lbValue tag_ptr = lb_emit_union_tag_ptr(p, parent_ptr);
+		tag_index = lb_emit_load(p, tag_ptr);
 		union_data = lb_emit_conv(p, parent_ptr, t_rawptr);
 	}
 
@@ -3429,25 +3495,34 @@ lbValue lb_emit_clamp(lbProcedure *p, Type *t, lbValue x, lbValue min, lbValue m
 
 lbValue lb_find_or_add_entity_string(lbModule *m, String const &str) {
 	HashKey key = hash_string(str);
-	lbValue *found = map_get(&m->const_strings, key);
+	LLVMValueRef *found = map_get(&m->const_strings, key);
 	if (found != nullptr) {
-		return *found;
+		LLVMValueRef ptr = *found;
+		LLVMValueRef str_len = LLVMConstInt(lb_type(m, t_int), str.len, true);
+		LLVMValueRef values[2] = {ptr, str_len};
+
+		lbValue res = {};
+		res.value = LLVMConstNamedStruct(lb_type(m, t_string), values, 2);
+		res.type = t_string;
+		return res;
 	}
-	lbValue v = lb_const_value(m, t_string, exact_value_string(str));
-	map_set(&m->const_strings, key, v);
-	return v;
+	return lb_const_value(m, t_string, exact_value_string(str));
 }
 
 lbValue lb_find_or_add_entity_string_byte_slice(lbModule *m, String const &str) {
 	HashKey key = hash_string(str);
-	lbValue *found = map_get(&m->const_string_byte_slices, key);
+	LLVMValueRef *found = map_get(&m->const_strings, key);
 	if (found != nullptr) {
-		return *found;
+		LLVMValueRef ptr = *found;
+		LLVMValueRef len = LLVMConstInt(lb_type(m, t_int), str.len, true);
+		LLVMValueRef values[2] = {ptr, len};
+
+		lbValue res = {};
+		res.value = LLVMConstNamedStruct(lb_type(m, t_u8_slice), values, 2);
+		res.type = t_u8_slice;
+		return res;
 	}
-	Type *t = t_u8_slice;
-	lbValue v = lb_const_value(m, t, exact_value_string(str));
-	map_set(&m->const_string_byte_slices, key, v);
-	return v;
+	return lb_const_value(m, t_u8_slice, exact_value_string(str));
 }
 
 isize lb_type_info_index(CheckerInfo *info, Type *type, bool err_on_not_found=true) {
@@ -3659,10 +3734,20 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value) {
 	case ExactValue_String:
 		{
 			HashKey key = hash_string(value.value_string);
-			lbValue *found = map_get(&m->const_strings, key);
+			LLVMValueRef *found = map_get(&m->const_strings, key);
 			if (found != nullptr) {
-				res.value = found->value;
+				LLVMValueRef ptr = *found;
+				lbValue res = {};
 				res.type = default_type(original_type);
+				if (is_type_cstring(res.type)) {
+					res.value = ptr;
+				} else {
+					LLVMValueRef str_len = LLVMConstInt(lb_type(m, t_int), value.value_string.len, true);
+					LLVMValueRef values[2] = {ptr, str_len};
+
+					res.value = LLVMConstNamedStruct(lb_type(m, original_type), values, 2);
+				}
+
 				return res;
 			}
 
@@ -3695,7 +3780,7 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value) {
 			res.value = LLVMConstNamedStruct(lb_type(m, original_type), values, 2);
 			res.type = default_type(original_type);
 
-			map_set(&m->const_strings, key, res);
+			map_set(&m->const_strings, key, ptr);
 
 			return res;
 		}
@@ -3703,7 +3788,7 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value) {
 	case ExactValue_Integer:
 		if (is_type_pointer(type)) {
 			LLVMValueRef i = LLVMConstIntOfArbitraryPrecision(lb_type(m, t_uintptr), cast(unsigned)value.value_integer.len, big_int_ptr(&value.value_integer));
-			res.value = LLVMConstBitCast(i, lb_type(m, original_type));
+			res.value = LLVMConstIntToPtr(i, lb_type(m, original_type));
 		} else {
 			res.value = LLVMConstIntOfArbitraryPrecision(lb_type(m, original_type), cast(unsigned)value.value_integer.len, big_int_ptr(&value.value_integer));
 			if (value.value_integer.neg) {
@@ -3763,7 +3848,7 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value) {
 		break;
 
 	case ExactValue_Pointer:
-		res.value = LLVMConstBitCast(LLVMConstInt(lb_type(m, t_uintptr), value.value_pointer, false), lb_type(m, original_type));
+		res.value = LLVMConstIntToPtr(LLVMConstInt(lb_type(m, t_uintptr), value.value_pointer, false), lb_type(m, original_type));
 		return res;
 
 	case ExactValue_Compound:
@@ -4530,21 +4615,20 @@ lbValue lb_build_binary_expr(lbProcedure *p, Ast *expr) {
 			switch (rt->kind) {
 			case Type_Map:
 				{
-					GB_PANIC("map in/not_in");
-					// lbValue addr = lb_address_from_load_or_generate_local(p, right);
-					// lbValue h = lb_gen_map_header(p, addr, rt);
-					// lbValue key = ir_gen_map_key(p, left, rt->Map.key);
-
-					// auto args = array_make<lbValue>(heap_allocator(), 2);
-					// args[0] = h;
-					// args[1] = key;
-
-					// lbValue ptr = lb_emit_runtime_call(p, "__dynamic_map_get", args);
-					// if (be->op.kind == Token_in) {
-					// 	return lb_emit_conv(p, ir_emit_comp(p, Token_NotEq, ptr, v_raw_nil), t_bool);
-					// } else {
-					// 	return lb_emit_conv(p, ir_emit_comp(p, Token_CmpEq, ptr, v_raw_nil), t_bool);
-					// }
+					lbValue addr = lb_address_from_load_or_generate_local(p, right);
+					lbValue h = lb_gen_map_header(p, addr, rt);
+					lbValue key = lb_gen_map_key(p, left, rt->Map.key);
+
+					auto args = array_make<lbValue>(heap_allocator(), 2);
+					args[0] = h;
+					args[1] = key;
+
+					lbValue ptr = lb_emit_runtime_call(p, "__dynamic_map_get", args);
+					if (be->op.kind == Token_in) {
+						return lb_emit_conv(p, lb_emit_comp_against_nil(p, Token_NotEq, ptr), t_bool);
+					} else {
+						return lb_emit_conv(p, lb_emit_comp_against_nil(p, Token_CmpEq, ptr), t_bool);
+					}
 				}
 				break;
 			case Type_BitSet:
@@ -4628,8 +4712,6 @@ lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) {
 	Type *src = core_type(src_type);
 	Type *dst = core_type(t);
 
-
-	// if (is_type_untyped_nil(src) && type_has_nil(dst)) {
 	if (is_type_untyped_nil(src)) {
 		return lb_const_nil(m, t);
 	}
@@ -4653,12 +4735,10 @@ lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) {
 			return lb_addr_load(p, res);
 		} else if (dst->kind == Type_Basic) {
 			if (src->Basic.kind == Basic_string && dst->Basic.kind == Basic_cstring) {
-				// TODO(bill): This is kind of a hack
-				unsigned indices[1] = {0};
-				LLVMValueRef data = LLVMConstExtractValue(value.value, indices, gb_count_of(indices));
+				String str = lb_get_const_string(m, value);
 				lbValue res = {};
 				res.type = t;
-				res.value = data;
+				res.value = LLVMConstString(cast(char const *)str.text, cast(unsigned)str.len, false);
 				return res;
 			}
 			// if (is_type_float(dst)) {
@@ -5278,7 +5358,7 @@ lbValue lb_emit_struct_ep(lbProcedure *p, lbValue s, i32 index) {
 		}
 	} else if (is_type_map(t)) {
 		init_map_internal_types(t);
-		Type *itp = (t->Map.internal_type);
+		Type *itp = alloc_type_pointer(t->Map.internal_type);
 		s = lb_emit_transmute(p, s, itp);
 
 		Type *gst = t->Map.internal_type;
@@ -6355,13 +6435,19 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
 
 
 
-	#if 0
 	// "Intrinsics"
 	case BuiltinProc_atomic_fence:
+		LLVMBuildFence(p->builder, LLVMAtomicOrderingSequentiallyConsistent, false, "");
+		return {};
 	case BuiltinProc_atomic_fence_acq:
+		LLVMBuildFence(p->builder, LLVMAtomicOrderingAcquire, false, "");
+		return {};
 	case BuiltinProc_atomic_fence_rel:
+		LLVMBuildFence(p->builder, LLVMAtomicOrderingRelease, false, "");
+		return {};
 	case BuiltinProc_atomic_fence_acqrel:
-		return lb_emit(p, lb_instr_atomic_fence(p, id));
+		LLVMBuildFence(p->builder, LLVMAtomicOrderingAcquireRelease, false, "");
+		return {};
 
 	case BuiltinProc_atomic_store:
 	case BuiltinProc_atomic_store_rel:
@@ -6369,8 +6455,19 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
 	case BuiltinProc_atomic_store_unordered: {
 		lbValue dst = lb_build_expr(p, ce->args[0]);
 		lbValue val = lb_build_expr(p, ce->args[1]);
-		val = lb_emit_conv(p, val, type_deref(lb_type(dst)));
-		return lb_emit(p, lb_instr_atomic_store(p, dst, val, id));
+		val = lb_emit_conv(p, val, type_deref(dst.type));
+
+		LLVMValueRef instr = LLVMBuildStore(p->builder, val.value, dst.value);
+		switch (id) {
+		case BuiltinProc_atomic_store:           LLVMSetOrdering(instr, LLVMAtomicOrderingSequentiallyConsistent); break;
+		case BuiltinProc_atomic_store_rel:       LLVMSetOrdering(instr, LLVMAtomicOrderingRelease);                break;
+		case BuiltinProc_atomic_store_relaxed:   LLVMSetOrdering(instr, LLVMAtomicOrderingMonotonic);              break;
+		case BuiltinProc_atomic_store_unordered: LLVMSetOrdering(instr, LLVMAtomicOrderingUnordered);              break;
+		}
+
+		LLVMSetAlignment(instr, cast(unsigned)type_align_of(type_deref(dst.type)));
+
+		return {};
 	}
 
 	case BuiltinProc_atomic_load:
@@ -6378,7 +6475,20 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
 	case BuiltinProc_atomic_load_relaxed:
 	case BuiltinProc_atomic_load_unordered: {
 		lbValue dst = lb_build_expr(p, ce->args[0]);
-		return lb_emit(p, lb_instr_atomic_load(p, dst, id));
+
+		LLVMValueRef instr = LLVMBuildLoad(p->builder, dst.value, "");
+		switch (id) {
+		case BuiltinProc_atomic_load:           LLVMSetOrdering(instr, LLVMAtomicOrderingSequentiallyConsistent); break;
+		case BuiltinProc_atomic_load_acq:       LLVMSetOrdering(instr, LLVMAtomicOrderingAcquire);                break;
+		case BuiltinProc_atomic_load_relaxed:   LLVMSetOrdering(instr, LLVMAtomicOrderingMonotonic);              break;
+		case BuiltinProc_atomic_load_unordered: LLVMSetOrdering(instr, LLVMAtomicOrderingUnordered);              break;
+		}
+		LLVMSetAlignment(instr, cast(unsigned)type_align_of(type_deref(dst.type)));
+
+		lbValue res = {};
+		res.value = instr;
+		res.type = type_deref(dst.type);
+		return res;
 	}
 
 	case BuiltinProc_atomic_add:
@@ -6418,8 +6528,51 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
 	case BuiltinProc_atomic_xchg_relaxed: {
 		lbValue dst = lb_build_expr(p, ce->args[0]);
 		lbValue val = lb_build_expr(p, ce->args[1]);
-		val = lb_emit_conv(p, val, type_deref(ir_type(dst)));
-		return lb_emit(p, lb_instr_atomic_rmw(p, dst, val, id));
+		val = lb_emit_conv(p, val, type_deref(dst.type));
+
+		LLVMAtomicRMWBinOp op = {};
+		LLVMAtomicOrdering ordering = {};
+
+		switch (id) {
+		case BuiltinProc_atomic_add:          op = LLVMAtomicRMWBinOpAdd;  ordering = LLVMAtomicOrderingSequentiallyConsistent; break;
+		case BuiltinProc_atomic_add_acq:      op = LLVMAtomicRMWBinOpAdd;  ordering = LLVMAtomicOrderingAcquire; break;
+		case BuiltinProc_atomic_add_rel:      op = LLVMAtomicRMWBinOpAdd;  ordering = LLVMAtomicOrderingRelease; break;
+		case BuiltinProc_atomic_add_acqrel:   op = LLVMAtomicRMWBinOpAdd;  ordering = LLVMAtomicOrderingAcquireRelease; break;
+		case BuiltinProc_atomic_add_relaxed:  op = LLVMAtomicRMWBinOpAdd;  ordering = LLVMAtomicOrderingMonotonic; break;
+		case BuiltinProc_atomic_sub:          op = LLVMAtomicRMWBinOpSub;  ordering = LLVMAtomicOrderingSequentiallyConsistent; break;
+		case BuiltinProc_atomic_sub_acq:      op = LLVMAtomicRMWBinOpSub;  ordering = LLVMAtomicOrderingAcquire; break;
+		case BuiltinProc_atomic_sub_rel:      op = LLVMAtomicRMWBinOpSub;  ordering = LLVMAtomicOrderingRelease; break;
+		case BuiltinProc_atomic_sub_acqrel:   op = LLVMAtomicRMWBinOpSub;  ordering = LLVMAtomicOrderingAcquireRelease; break;
+		case BuiltinProc_atomic_sub_relaxed:  op = LLVMAtomicRMWBinOpSub;  ordering = LLVMAtomicOrderingMonotonic; break;
+		case BuiltinProc_atomic_and:          op = LLVMAtomicRMWBinOpAnd;  ordering = LLVMAtomicOrderingSequentiallyConsistent; break;
+		case BuiltinProc_atomic_and_acq:      op = LLVMAtomicRMWBinOpAnd;  ordering = LLVMAtomicOrderingAcquire; break;
+		case BuiltinProc_atomic_and_rel:      op = LLVMAtomicRMWBinOpAnd;  ordering = LLVMAtomicOrderingRelease; break;
+		case BuiltinProc_atomic_and_acqrel:   op = LLVMAtomicRMWBinOpAnd;  ordering = LLVMAtomicOrderingAcquireRelease; break;
+		case BuiltinProc_atomic_and_relaxed:  op = LLVMAtomicRMWBinOpAnd;  ordering = LLVMAtomicOrderingMonotonic; break;
+		case BuiltinProc_atomic_nand:         op = LLVMAtomicRMWBinOpNand; ordering = LLVMAtomicOrderingSequentiallyConsistent; break;
+		case BuiltinProc_atomic_nand_acq:     op = LLVMAtomicRMWBinOpNand; ordering = LLVMAtomicOrderingAcquire; break;
+		case BuiltinProc_atomic_nand_rel:     op = LLVMAtomicRMWBinOpNand; ordering = LLVMAtomicOrderingRelease; break;
+		case BuiltinProc_atomic_nand_acqrel:  op = LLVMAtomicRMWBinOpNand; ordering = LLVMAtomicOrderingAcquireRelease; break;
+		case BuiltinProc_atomic_nand_relaxed: op = LLVMAtomicRMWBinOpNand; ordering = LLVMAtomicOrderingMonotonic; break;
+		case BuiltinProc_atomic_or:           op = LLVMAtomicRMWBinOpOr;   ordering = LLVMAtomicOrderingSequentiallyConsistent; break;
+		case BuiltinProc_atomic_or_acq:       op = LLVMAtomicRMWBinOpOr;   ordering = LLVMAtomicOrderingAcquire; break;
+		case BuiltinProc_atomic_or_rel:       op = LLVMAtomicRMWBinOpOr;   ordering = LLVMAtomicOrderingRelease; break;
+		case BuiltinProc_atomic_or_acqrel:    op = LLVMAtomicRMWBinOpOr;   ordering = LLVMAtomicOrderingAcquireRelease; break;
+		case BuiltinProc_atomic_or_relaxed:   op = LLVMAtomicRMWBinOpOr;   ordering = LLVMAtomicOrderingMonotonic; break;
+		case BuiltinProc_atomic_xor:          op = LLVMAtomicRMWBinOpXor;  ordering = LLVMAtomicOrderingSequentiallyConsistent; break;
+		case BuiltinProc_atomic_xor_acq:      op = LLVMAtomicRMWBinOpXor;  ordering = LLVMAtomicOrderingAcquire; break;
+		case BuiltinProc_atomic_xor_rel:      op = LLVMAtomicRMWBinOpXor;  ordering = LLVMAtomicOrderingRelease; break;
+		case BuiltinProc_atomic_xor_acqrel:   op = LLVMAtomicRMWBinOpXor;  ordering = LLVMAtomicOrderingAcquireRelease; break;
+		case BuiltinProc_atomic_xor_relaxed:  op = LLVMAtomicRMWBinOpXor;  ordering = LLVMAtomicOrderingMonotonic; break;
+		case BuiltinProc_atomic_xchg:         op = LLVMAtomicRMWBinOpXchg; ordering = LLVMAtomicOrderingSequentiallyConsistent; break;
+		case BuiltinProc_atomic_xchg_acq:     op = LLVMAtomicRMWBinOpXchg; ordering = LLVMAtomicOrderingAcquire; break;
+		case BuiltinProc_atomic_xchg_rel:     op = LLVMAtomicRMWBinOpXchg; ordering = LLVMAtomicOrderingRelease; break;
+		case BuiltinProc_atomic_xchg_acqrel:  op = LLVMAtomicRMWBinOpXchg; ordering = LLVMAtomicOrderingAcquireRelease; break;
+		case BuiltinProc_atomic_xchg_relaxed: op = LLVMAtomicRMWBinOpXchg; ordering = LLVMAtomicOrderingMonotonic; break;
+		}
+
+		LLVMValueRef instr = LLVMBuildAtomicRMW(p->builder, op, dst.value, val.value, ordering, false);
+		return {};
 	}
 
 	case BuiltinProc_atomic_cxchg:
@@ -6443,20 +6596,53 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
 		Type *type = expr->tav.type;
 
 		lbValue address = lb_build_expr(p, ce->args[0]);
-		Type *elem = type_deref(ir_type(address));
+		Type *elem = type_deref(address.type);
 		lbValue old_value = lb_build_expr(p, ce->args[1]);
 		lbValue new_value = lb_build_expr(p, ce->args[2]);
 		old_value = lb_emit_conv(p, old_value, elem);
 		new_value = lb_emit_conv(p, new_value, elem);
 
-		return lb_emit(p, lb_instr_atomic_cxchg(p, type, address, old_value, new_value, id));
+		LLVMAtomicOrdering success_ordering = {};
+		LLVMAtomicOrdering failure_ordering = {};
+		LLVMBool weak = false;
+
+		switch (id) {
+		case BuiltinProc_atomic_cxchg:                        success_ordering = LLVMAtomicOrderingSequentiallyConsistent; failure_ordering = LLVMAtomicOrderingSequentiallyConsistent; weak = false; break;
+		case BuiltinProc_atomic_cxchg_acq:                    success_ordering = LLVMAtomicOrderingAcquire;                failure_ordering = LLVMAtomicOrderingSequentiallyConsistent; weak = false; break;
+		case BuiltinProc_atomic_cxchg_rel:                    success_ordering = LLVMAtomicOrderingRelease;                failure_ordering = LLVMAtomicOrderingSequentiallyConsistent; weak = false; break;
+		case BuiltinProc_atomic_cxchg_acqrel:                 success_ordering = LLVMAtomicOrderingAcquireRelease;         failure_ordering = LLVMAtomicOrderingSequentiallyConsistent; weak = false; break;
+		case BuiltinProc_atomic_cxchg_relaxed:                success_ordering = LLVMAtomicOrderingMonotonic;              failure_ordering = LLVMAtomicOrderingMonotonic;              weak = false; break;
+		case BuiltinProc_atomic_cxchg_failrelaxed:            success_ordering = LLVMAtomicOrderingSequentiallyConsistent; failure_ordering = LLVMAtomicOrderingMonotonic;              weak = false; break;
+		case BuiltinProc_atomic_cxchg_failacq:                success_ordering = LLVMAtomicOrderingSequentiallyConsistent; failure_ordering = LLVMAtomicOrderingAcquire;                weak = false; break;
+		case BuiltinProc_atomic_cxchg_acq_failrelaxed:        success_ordering = LLVMAtomicOrderingAcquire;                failure_ordering = LLVMAtomicOrderingMonotonic;              weak = false; break;
+		case BuiltinProc_atomic_cxchg_acqrel_failrelaxed:     success_ordering = LLVMAtomicOrderingAcquireRelease;         failure_ordering = LLVMAtomicOrderingMonotonic;              weak = false; break;
+		case BuiltinProc_atomic_cxchgweak:                    success_ordering = LLVMAtomicOrderingSequentiallyConsistent; failure_ordering = LLVMAtomicOrderingSequentiallyConsistent; weak = false; break;
+		case BuiltinProc_atomic_cxchgweak_acq:                success_ordering = LLVMAtomicOrderingAcquire;                failure_ordering = LLVMAtomicOrderingSequentiallyConsistent; weak = true;  break;
+		case BuiltinProc_atomic_cxchgweak_rel:                success_ordering = LLVMAtomicOrderingRelease;                failure_ordering = LLVMAtomicOrderingSequentiallyConsistent; weak = true;  break;
+		case BuiltinProc_atomic_cxchgweak_acqrel:             success_ordering = LLVMAtomicOrderingAcquireRelease;         failure_ordering = LLVMAtomicOrderingSequentiallyConsistent; weak = true;  break;
+		case BuiltinProc_atomic_cxchgweak_relaxed:            success_ordering = LLVMAtomicOrderingMonotonic;              failure_ordering = LLVMAtomicOrderingMonotonic;              weak = true;  break;
+		case BuiltinProc_atomic_cxchgweak_failrelaxed:        success_ordering = LLVMAtomicOrderingSequentiallyConsistent; failure_ordering = LLVMAtomicOrderingMonotonic;              weak = true;  break;
+		case BuiltinProc_atomic_cxchgweak_failacq:            success_ordering = LLVMAtomicOrderingSequentiallyConsistent; failure_ordering = LLVMAtomicOrderingAcquire;                weak = true;  break;
+		case BuiltinProc_atomic_cxchgweak_acq_failrelaxed:    success_ordering = LLVMAtomicOrderingAcquire;                failure_ordering = LLVMAtomicOrderingMonotonic;              weak = true;  break;
+		case BuiltinProc_atomic_cxchgweak_acqrel_failrelaxed: success_ordering = LLVMAtomicOrderingAcquireRelease;         failure_ordering = LLVMAtomicOrderingMonotonic;              weak = true;  break;
+		}
+
+		// TODO(bill): Figure out how to make it weak
+		LLVMBool single_threaded = !weak;
+
+		LLVMValueRef instr = LLVMBuildAtomicCmpXchg(p->builder, address.value,
+		                                            old_value.value, new_value.value,
+		                                            success_ordering,
+		                                            failure_ordering,
+		                                            single_threaded);
+
+		return {};
 	}
-	#endif
 
 
 	}
 
-	GB_PANIC("Unhandled built-in procedure");
+	GB_PANIC("Unhandled built-in procedure %.*s", LIT(builtin_procs[id].name));
 	return {};
 }
 
@@ -6804,8 +6990,8 @@ String lb_get_const_string(lbModule *m, lbValue value) {
 	Type *t = base_type(value.type);
 	GB_ASSERT(are_types_identical(t, t_string));
 
-	unsigned     ptr_indices[2] = {0, 0};
-	unsigned     len_indices[2] = {0, 1};
+	unsigned     ptr_indices[1] = {0};
+	unsigned     len_indices[1] = {1};
 	LLVMValueRef underlying_ptr = LLVMConstExtractValue(value.value, ptr_indices, gb_count_of(ptr_indices));
 	LLVMValueRef underlying_len = LLVMConstExtractValue(value.value, len_indices, gb_count_of(len_indices));
 
@@ -8161,7 +8347,6 @@ lbAddr lb_build_addr(lbProcedure *p, Ast *expr) {
 		t = base_type(type_deref(t));
 		if (is_type_soa_struct(t)) {
 			// SOA STRUCTURES!!!!
-			GB_PANIC("SOA STRUCTURES!!!!");
 			lbValue val = lb_build_addr_ptr(p, ie->expr);
 			if (deref) {
 				val = lb_emit_load(p, val);
@@ -8446,50 +8631,49 @@ lbAddr lb_build_addr(lbProcedure *p, Ast *expr) {
 				if (!no_indices) {
 					// lb_emit_slice_bounds_check(p, se->open, low, high, len, se->low != nullptr);
 				}
-				GB_PANIC("#soa struct slice");
-				#if 0
+				#if 1
 
 				lbAddr dst = lb_add_local_generated(p, type_of_expr(expr), true);
 				if (type->Struct.soa_kind == StructSoa_Fixed) {
 					i32 field_count = cast(i32)type->Struct.fields.count;
 					for (i32 i = 0; i < field_count; i++) {
-						lbValue field_dst = lb_emit_struct_ep(p, dst, i);
+						lbValue field_dst = lb_emit_struct_ep(p, dst.addr, i);
 						lbValue field_src = lb_emit_struct_ep(p, addr, i);
 						field_src = lb_emit_array_ep(p, field_src, low);
 						lb_emit_store(p, field_dst, field_src);
 					}
 
-					lbValue len_dst = lb_emit_struct_ep(p, dst, field_count);
+					lbValue len_dst = lb_emit_struct_ep(p, dst.addr, field_count);
 					lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int);
 					lb_emit_store(p, len_dst, new_len);
 				} else if (type->Struct.soa_kind == StructSoa_Slice) {
 					if (no_indices) {
-						lb_emit_store(p, dst, base);
+						lb_addr_store(p, dst, base);
 					} else {
 						i32 field_count = cast(i32)type->Struct.fields.count - 1;
 						for (i32 i = 0; i < field_count; i++) {
-							lbValue field_dst = lb_emit_struct_ep(p, dst, i);
+							lbValue field_dst = lb_emit_struct_ep(p, dst.addr, i);
 							lbValue field_src = lb_emit_struct_ev(p, base, i);
 							field_src = lb_emit_ptr_offset(p, field_src, low);
 							lb_emit_store(p, field_dst, field_src);
 						}
 
 
-						lbValue len_dst = lb_emit_struct_ep(p, dst, field_count);
+						lbValue len_dst = lb_emit_struct_ep(p, dst.addr, field_count);
 						lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int);
 						lb_emit_store(p, len_dst, new_len);
 					}
 				} else if (type->Struct.soa_kind == StructSoa_Dynamic) {
 					i32 field_count = cast(i32)type->Struct.fields.count - 3;
 					for (i32 i = 0; i < field_count; i++) {
-						lbValue field_dst = lb_emit_struct_ep(p, dst, i);
+						lbValue field_dst = lb_emit_struct_ep(p, dst.addr, i);
 						lbValue field_src = lb_emit_struct_ev(p, base, i);
 						field_src = lb_emit_ptr_offset(p, field_src, low);
 						lb_emit_store(p, field_dst, field_src);
 					}
 
 
-					lbValue len_dst = lb_emit_struct_ep(p, dst, field_count);
+					lbValue len_dst = lb_emit_struct_ep(p, dst.addr, field_count);
 					lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int);
 					lb_emit_store(p, len_dst, new_len);
 				}
@@ -9113,6 +9297,28 @@ lbAddr lb_build_addr(lbProcedure *p, Ast *expr) {
 	return {};
 }
 
+void lb_init_module(lbModule *m, Checker *c) {
+	m->info = &c->info;
+
+	m->ctx = LLVMGetGlobalContext();
+	m->mod = LLVMModuleCreateWithNameInContext("odin_module", m->ctx);
+	m->debug_builder = LLVMCreateDIBuilder(m->mod);
+
+	gb_mutex_init(&m->mutex);
+	gbAllocator a = heap_allocator();
+	map_init(&m->types, a);
+	map_init(&m->values, a);
+	map_init(&m->members, a);
+	map_init(&m->procedure_values, a);
+	map_init(&m->procedures, a);
+	map_init(&m->const_strings, a);
+	map_init(&m->anonymous_proc_lits, a);
+	array_init(&m->procedures_to_generate, a);
+	array_init(&m->foreign_library_paths, a);
+
+	map_init(&m->debug_values, a);
+
+}
 
 
 bool lb_init_generator(lbGenerator *gen, Checker *c) {
@@ -9148,29 +9354,9 @@ bool lb_init_generator(lbGenerator *gen, Checker *c) {
 	output_file_path = gb_string_appendc(output_file_path, ".obj");
 	defer (gb_string_free(output_file_path));
 
-
 	gen->info = &c->info;
-	gen->module.info = &c->info;
 
-	// gen->ctx = LLVMContextCreate();
-	gen->module.ctx = LLVMGetGlobalContext();
-	gen->module.mod = LLVMModuleCreateWithNameInContext("odin_module", gen->module.ctx);
-	gen->module.debug_builder = LLVMCreateDIBuilder(gen->module.mod);
-
-
-	gb_mutex_init(&gen->module.mutex);
-	gbAllocator a = heap_allocator();
-	map_init(&gen->module.types, a);
-	map_init(&gen->module.values, a);
-	map_init(&gen->module.members, a);
-	map_init(&gen->module.procedure_values, a);
-	map_init(&gen->module.procedures, a);
-	map_init(&gen->module.const_strings, a);
-	map_init(&gen->module.const_string_byte_slices, a);
-	map_init(&gen->module.anonymous_proc_lits, a);
-	array_init(&gen->module.procedures_to_generate, a);
-
-	map_init(&gen->module.debug_values, a);
+	lb_init_module(&gen->module, c);
 
 	return true;
 }
@@ -10173,7 +10359,7 @@ void lb_generate_code(lbGenerator *gen) {
 
 			if (e->Variable.is_foreign) {
 				Entity *fl = e->Procedure.foreign_library;
-				// lb_add_foreign_library_path(m, fl);
+				lb_add_foreign_library_path(m, fl);
 			}
 
 			if (e->flags & EntityFlag_Static) {
@@ -10276,10 +10462,10 @@ void lb_generate_code(lbGenerator *gen) {
 	defer (gb_free(heap_allocator(), filepath_obj.text));
 
 
+	LLVMBool failure = LLVMPrintModuleToFile(mod, cast(char const *)filepath_ll.text, &llvm_error);
 	LLVMDIBuilderFinalize(m->debug_builder);
 	LLVMVerifyModule(mod, LLVMAbortProcessAction, &llvm_error);
 	llvm_error = nullptr;
-	// LLVMBool failure = LLVMPrintModuleToFile(mod, cast(char const *)filepath_ll.text, &llvm_error);
 
 	LLVMInitializeAllTargetInfos();
 	LLVMInitializeAllTargets();

+ 4 - 2
src/llvm_backend.hpp

@@ -66,8 +66,7 @@ struct lbModule {
 	Map<lbProcedure *> procedures;  // Key: String
 	Map<Entity *> procedure_values; // Key: LLVMValueRef
 
-	Map<lbValue> const_strings; // Key: String
-	Map<lbValue> const_string_byte_slices; // Key: String
+	Map<LLVMValueRef> const_strings; // Key: String
 
 	Map<lbProcedure *> anonymous_proc_lits; // Key: Ast *
 
@@ -75,8 +74,11 @@ struct lbModule {
 
 	u32 global_array_index;
 	u32 global_generated_index;
+	u32 nested_type_name_guid;
 
 	Array<lbProcedure *> procedures_to_generate;
+	Array<String> foreign_library_paths;
+
 
 
 	LLVMDIBuilderRef debug_builder;

+ 264 - 264
src/main.cpp

@@ -1300,333 +1300,333 @@ int main(int arg_count, char const **arg_ptr) {
 			show_timings(&checker, timings);
 		}
 		return 0;
-	}
+	} else {
+		irGen ir_gen = {0};
+		if (!ir_gen_init(&ir_gen, &checker)) {
+			return 1;
+		}
+		// defer (ir_gen_destroy(&ir_gen));
 
-	irGen ir_gen = {0};
-	if (!ir_gen_init(&ir_gen, &checker)) {
-		return 1;
-	}
-	// defer (ir_gen_destroy(&ir_gen));
 
+		timings_start_section(timings, str_lit("llvm ir gen"));
+		ir_gen_tree(&ir_gen);
 
-	timings_start_section(timings, str_lit("llvm ir gen"));
-	ir_gen_tree(&ir_gen);
+		timings_start_section(timings, str_lit("llvm ir opt tree"));
+		ir_opt_tree(&ir_gen);
 
-	timings_start_section(timings, str_lit("llvm ir opt tree"));
-	ir_opt_tree(&ir_gen);
+		timings_start_section(timings, str_lit("llvm ir print"));
+		print_llvm_ir(&ir_gen);
 
-	timings_start_section(timings, str_lit("llvm ir print"));
-	print_llvm_ir(&ir_gen);
 
+		String output_name = ir_gen.output_name;
+		String output_base = ir_gen.output_base;
 
-	String output_name = ir_gen.output_name;
-	String output_base = ir_gen.output_base;
+		build_context.optimization_level = gb_clamp(build_context.optimization_level, 0, 3);
 
-	build_context.optimization_level = gb_clamp(build_context.optimization_level, 0, 3);
+		i32 exit_code = 0;
 
-	i32 exit_code = 0;
+		timings_start_section(timings, str_lit("llvm-opt"));
+		exit_code = exec_llvm_opt(output_base);
+		if (exit_code != 0) {
+			return exit_code;
+		}
 
-	timings_start_section(timings, str_lit("llvm-opt"));
-	exit_code = exec_llvm_opt(output_base);
-	if (exit_code != 0) {
-		return exit_code;
-	}
+		timings_start_section(timings, str_lit("llvm-llc"));
+		exit_code = exec_llvm_llc(output_base);
+		if (exit_code != 0) {
+			return exit_code;
+		}
 
-	timings_start_section(timings, str_lit("llvm-llc"));
-	exit_code = exec_llvm_llc(output_base);
-	if (exit_code != 0) {
-		return exit_code;
-	}
+		if (build_context.cross_compiling && selected_target_metrics->metrics == &target_essence_amd64) {
+	#ifdef GB_SYSTEM_UNIX
+			system_exec_command_line_app("linker", "x86_64-essence-gcc \"%.*s.o\" -o \"%.*s\" %.*s",
+					LIT(output_base), LIT(output_base), LIT(build_context.link_flags));
+	#else
+			gb_printf_err("Don't know how to cross compile to selected target.\n");
+	#endif
+		} else {
+		#if defined(GB_SYSTEM_WINDOWS)
+			timings_start_section(timings, str_lit("msvc-link"));
 
-	if (build_context.cross_compiling && selected_target_metrics->metrics == &target_essence_amd64) {
-#ifdef GB_SYSTEM_UNIX
-		system_exec_command_line_app("linker", "x86_64-essence-gcc \"%.*s.o\" -o \"%.*s\" %.*s",
-				LIT(output_base), LIT(output_base), LIT(build_context.link_flags));
-#else
-		gb_printf_err("Don't know how to cross compile to selected target.\n");
-#endif
-	} else {
-	#if defined(GB_SYSTEM_WINDOWS)
-		timings_start_section(timings, str_lit("msvc-link"));
+			gbString lib_str = gb_string_make(heap_allocator(), "");
+			defer (gb_string_free(lib_str));
+			char lib_str_buf[1024] = {0};
 
-		gbString lib_str = gb_string_make(heap_allocator(), "");
-		defer (gb_string_free(lib_str));
-		char lib_str_buf[1024] = {0};
+			char const *output_ext = "exe";
+			gbString link_settings = gb_string_make_reserve(heap_allocator(), 256);
+			defer (gb_string_free(link_settings));
 
-		char const *output_ext = "exe";
-		gbString link_settings = gb_string_make_reserve(heap_allocator(), 256);
-		defer (gb_string_free(link_settings));
 
+			// NOTE(ic): It would be nice to extend this so that we could specify the Visual Studio version that we want instead of defaulting to the latest.
+			Find_Result_Utf8 find_result = find_visual_studio_and_windows_sdk_utf8();
 
-		// NOTE(ic): It would be nice to extend this so that we could specify the Visual Studio version that we want instead of defaulting to the latest.
-		Find_Result_Utf8 find_result = find_visual_studio_and_windows_sdk_utf8();
+			if (find_result.windows_sdk_version == 0) {
+				gb_printf_err("Windows SDK not found.\n");
+				return 1;
+			}
 
-		if (find_result.windows_sdk_version == 0) {
-			gb_printf_err("Windows SDK not found.\n");
-			return 1;
-		}
+			// Add library search paths.
+			if (find_result.vs_library_path.len > 0) {
+				GB_ASSERT(find_result.windows_sdk_um_library_path.len > 0);
+				GB_ASSERT(find_result.windows_sdk_ucrt_library_path.len > 0);
 
-		// Add library search paths.
-		if (find_result.vs_library_path.len > 0) {
-			GB_ASSERT(find_result.windows_sdk_um_library_path.len > 0);
-			GB_ASSERT(find_result.windows_sdk_ucrt_library_path.len > 0);
+				String path = {};
+				auto add_path = [&](String path) {
+					if (path[path.len-1] == '\\') {
+						path.len -= 1;
+					}
+					link_settings = gb_string_append_fmt(link_settings, " /LIBPATH:\"%.*s\"", LIT(path));
+				};
+				add_path(find_result.windows_sdk_um_library_path);
+				add_path(find_result.windows_sdk_ucrt_library_path);
+				add_path(find_result.vs_library_path);
+			}
 
-			String path = {};
-			auto add_path = [&](String path) {
-				if (path[path.len-1] == '\\') {
-					path.len -= 1;
-				}
-				link_settings = gb_string_append_fmt(link_settings, " /LIBPATH:\"%.*s\"", LIT(path));
-			};
-			add_path(find_result.windows_sdk_um_library_path);
-			add_path(find_result.windows_sdk_ucrt_library_path);
-			add_path(find_result.vs_library_path);
-		}
+			for_array(i, ir_gen.module.foreign_library_paths) {
+				String lib = ir_gen.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));
+				lib_str = gb_string_appendc(lib_str, lib_str_buf);
+			}
 
-		for_array(i, ir_gen.module.foreign_library_paths) {
-			String lib = ir_gen.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));
-			lib_str = gb_string_appendc(lib_str, lib_str_buf);
-		}
 
 
+			if (build_context.is_dll) {
+				output_ext = "dll";
+				link_settings = gb_string_append_fmt(link_settings, "/DLL");
+			} else {
+				link_settings = gb_string_append_fmt(link_settings, "/ENTRY:mainCRTStartup");
+			}
 
-		if (build_context.is_dll) {
-			output_ext = "dll";
-			link_settings = gb_string_append_fmt(link_settings, "/DLL");
-		} else {
-			link_settings = gb_string_append_fmt(link_settings, "/ENTRY:mainCRTStartup");
-		}
+			if (build_context.pdb_filepath != "") {
+				link_settings = gb_string_append_fmt(link_settings, " /PDB:%.*s", LIT(build_context.pdb_filepath));
+			}
 
-		if (build_context.pdb_filepath != "") {
-			link_settings = gb_string_append_fmt(link_settings, " /PDB:%.*s", LIT(build_context.pdb_filepath));
-		}
+			if (build_context.no_crt) {
+				link_settings = gb_string_append_fmt(link_settings, " /nodefaultlib");
+			} else {
+				link_settings = gb_string_append_fmt(link_settings, " /defaultlib:libcmt");
+			}
 
-		if (build_context.no_crt) {
-			link_settings = gb_string_append_fmt(link_settings, " /nodefaultlib");
-		} else {
-			link_settings = gb_string_append_fmt(link_settings, " /defaultlib:libcmt");
-		}
+			if (ir_gen.module.generate_debug_info) {
+				link_settings = gb_string_append_fmt(link_settings, " /DEBUG");
+			}
 
-		if (ir_gen.module.generate_debug_info) {
-			link_settings = gb_string_append_fmt(link_settings, " /DEBUG");
-		}
 
+			char const *subsystem_str = build_context.use_subsystem_windows ? "WINDOWS" : "CONSOLE";
+			if (!build_context.use_lld) { // msvc
+				if (build_context.has_resource) {
+					exit_code = system_exec_command_line_app("msvc-link",
+						"\"%.*src.exe\" /nologo /fo \"%.*s.res\" \"%.*s.rc\"",
+						LIT(find_result.vs_exe_path),
+						LIT(output_base),
+						LIT(build_context.resource_filepath)
+					);
 
-		char const *subsystem_str = build_context.use_subsystem_windows ? "WINDOWS" : "CONSOLE";
-		if (!build_context.use_lld) { // msvc
-			if (build_context.has_resource) {
-				exit_code = system_exec_command_line_app("msvc-link",
-					"\"%.*src.exe\" /nologo /fo \"%.*s.res\" \"%.*s.rc\"",
-					LIT(find_result.vs_exe_path),
-					LIT(output_base),
-					LIT(build_context.resource_filepath)
-				);
+		            if (exit_code != 0) {
+						return exit_code;
+					}
 
-	            if (exit_code != 0) {
-					return exit_code;
+					exit_code = system_exec_command_line_app("msvc-link",
+						"\"%.*slink.exe\" \"%.*s.obj\" \"%.*s.res\" -OUT:\"%.*s.%s\" %s "
+						"/nologo /incremental:no /opt:ref /subsystem:%s "
+						" %.*s "
+						" %s "
+						"",
+						LIT(find_result.vs_exe_path), LIT(output_base), LIT(output_base), LIT(output_base), output_ext,
+						link_settings,
+						subsystem_str,
+						LIT(build_context.link_flags),
+						lib_str
+					);
+				} else {
+					exit_code = system_exec_command_line_app("msvc-link",
+						"\"%.*slink.exe\" \"%.*s.obj\" -OUT:\"%.*s.%s\" %s "
+						"/nologo /incremental:no /opt:ref /subsystem:%s "
+						" %.*s "
+						" %s "
+						"",
+						LIT(find_result.vs_exe_path), LIT(output_base), LIT(output_base), output_ext,
+						link_settings,
+						subsystem_str,
+						LIT(build_context.link_flags),
+						lib_str
+					);
 				}
-
+			} else { // lld
 				exit_code = system_exec_command_line_app("msvc-link",
-					"\"%.*slink.exe\" \"%.*s.obj\" \"%.*s.res\" -OUT:\"%.*s.%s\" %s "
+					"\"%.*s\\bin\\lld-link\" \"%.*s.obj\" -OUT:\"%.*s.%s\" %s "
 					"/nologo /incremental:no /opt:ref /subsystem:%s "
 					" %.*s "
 					" %s "
 					"",
-					LIT(find_result.vs_exe_path), LIT(output_base), LIT(output_base), LIT(output_base), output_ext,
-					link_settings,
-					subsystem_str,
-					LIT(build_context.link_flags),
-					lib_str
-				);
-			} else {
-				exit_code = system_exec_command_line_app("msvc-link",
-					"\"%.*slink.exe\" \"%.*s.obj\" -OUT:\"%.*s.%s\" %s "
-					"/nologo /incremental:no /opt:ref /subsystem:%s "
-					" %.*s "
-					" %s "
-					"",
-					LIT(find_result.vs_exe_path), LIT(output_base), LIT(output_base), output_ext,
+					LIT(build_context.ODIN_ROOT),
+					LIT(output_base), LIT(output_base), output_ext,
 					link_settings,
 					subsystem_str,
 					LIT(build_context.link_flags),
 					lib_str
 				);
 			}
-		} else { // lld
-			exit_code = system_exec_command_line_app("msvc-link",
-				"\"%.*s\\bin\\lld-link\" \"%.*s.obj\" -OUT:\"%.*s.%s\" %s "
-				"/nologo /incremental:no /opt:ref /subsystem:%s "
-				" %.*s "
-				" %s "
-				"",
-				LIT(build_context.ODIN_ROOT),
-				LIT(output_base), LIT(output_base), output_ext,
-				link_settings,
-				subsystem_str,
-				LIT(build_context.link_flags),
-				lib_str
-			);
-		}
-
-		if (exit_code != 0) {
-			return exit_code;
-		}
 
-		if (build_context.show_timings) {
-			show_timings(&checker, timings);
-		}
-
-		remove_temp_files(output_base);
+			if (exit_code != 0) {
+				return exit_code;
+			}
 
-		if (run_output) {
-			return system_exec_command_line_app("odin run", "%.*s.exe %.*s", LIT(output_base), LIT(run_args_string));
-		}
-	#else
-		timings_start_section(timings, str_lit("ld-link"));
+			if (build_context.show_timings) {
+				show_timings(&checker, timings);
+			}
 
-		// NOTE(vassvik): get cwd, for used for local shared libs linking, since those have to be relative to the exe
-		char cwd[256];
-		getcwd(&cwd[0], 256);
-		//printf("%s\n", cwd);
+			remove_temp_files(output_base);
 
-		// NOTE(vassvik): needs to add the root to the library search paths, so that the full filenames of the library
-		//                files can be passed with -l:
-		gbString lib_str = gb_string_make(heap_allocator(), "-L/");
-		defer (gb_string_free(lib_str));
+			if (run_output) {
+				return system_exec_command_line_app("odin run", "%.*s.exe %.*s", LIT(output_base), LIT(run_args_string));
+			}
+		#else
+			timings_start_section(timings, str_lit("ld-link"));
+
+			// NOTE(vassvik): get cwd, for used for local shared libs linking, since those have to be relative to the exe
+			char cwd[256];
+			getcwd(&cwd[0], 256);
+			//printf("%s\n", cwd);
+
+			// NOTE(vassvik): needs to add the root to the library search paths, so that the full filenames of the library
+			//                files can be passed with -l:
+			gbString lib_str = gb_string_make(heap_allocator(), "-L/");
+			defer (gb_string_free(lib_str));
+
+			for_array(i, ir_gen.module.foreign_library_paths) {
+				String lib = ir_gen.module.foreign_library_paths[i];
+
+				// NOTE(zangent): Sometimes, you have to use -framework on MacOS.
+				//   This allows you to specify '-f' in a #foreign_system_library,
+				//   without having to implement any new syntax specifically for MacOS.
+				#if defined(GB_SYSTEM_OSX)
+					if (string_ends_with(lib, str_lit(".framework"))) {
+						// framework thingie
+						String lib_name = lib;
+						lib_name = remove_extension_from_path(lib_name);
+						lib_str = gb_string_append_fmt(lib_str, " -framework %.*s ", LIT(lib_name));
+					} else if (string_ends_with(lib, str_lit(".a"))) {
+						// static libs, absolute full path relative to the file in which the lib was imported from
+						lib_str = gb_string_append_fmt(lib_str, " %.*s ", LIT(lib));
+					} else if (string_ends_with(lib, str_lit(".dylib"))) {
+						// dynamic lib
+						lib_str = gb_string_append_fmt(lib_str, " %.*s ", LIT(lib));
+					} else {
+						// dynamic or static system lib, just link regularly searching system library paths
+						lib_str = gb_string_append_fmt(lib_str, " -l%.*s ", LIT(lib));
+					}
+				#else
+					// NOTE(vassvik): static libraries (.a files) in linux can be linked to directly using the full path,
+					//                since those are statically linked to at link time. shared libraries (.so) has to be
+					//                available at runtime wherever the executable is run, so we make require those to be
+					//                local to the executable (unless the system collection is used, in which case we search
+					//                the system library paths for the library file).
+					if (string_ends_with(lib, str_lit(".a"))) {
+						// static libs, absolute full path relative to the file in which the lib was imported from
+						lib_str = gb_string_append_fmt(lib_str, " -l:\"%.*s\" ", LIT(lib));
+					} else if (string_ends_with(lib, str_lit(".so"))) {
+						// dynamic lib, relative path to executable
+						// NOTE(vassvik): it is the user's responsibility to make sure the shared library files are visible
+						//                at runtimeto the executable
+						lib_str = gb_string_append_fmt(lib_str, " -l:\"%s/%.*s\" ", cwd, LIT(lib));
+					} else {
+						// dynamic or static system lib, just link regularly searching system library paths
+						lib_str = gb_string_append_fmt(lib_str, " -l%.*s ", LIT(lib));
+					}
+				#endif
+			}
 
-		for_array(i, ir_gen.module.foreign_library_paths) {
-			String lib = ir_gen.module.foreign_library_paths[i];
+			// Unlike the Win32 linker code, the output_ext includes the dot, because
+			// typically executable files on *NIX systems don't have extensions.
+			String output_ext = {};
+			char const *link_settings = "";
+			char const *linker;
+			if (build_context.is_dll) {
+				// Shared libraries are .dylib on MacOS and .so on Linux.
+				#if defined(GB_SYSTEM_OSX)
+					output_ext = STR_LIT(".dylib");
+					link_settings = "-dylib -dynamic";
+				#else
+					output_ext = STR_LIT(".so");
+					link_settings = "-shared";
+				#endif
+			} else {
+				// TODO: Do I need anything here?
+				link_settings = "";
+			}
 
-			// NOTE(zangent): Sometimes, you have to use -framework on MacOS.
-			//   This allows you to specify '-f' in a #foreign_system_library,
-			//   without having to implement any new syntax specifically for MacOS.
-			#if defined(GB_SYSTEM_OSX)
-				if (string_ends_with(lib, str_lit(".framework"))) {
-					// framework thingie
-					String lib_name = lib;
-					lib_name = remove_extension_from_path(lib_name);
-					lib_str = gb_string_append_fmt(lib_str, " -framework %.*s ", LIT(lib_name));
-				} else if (string_ends_with(lib, str_lit(".a"))) {
-					// static libs, absolute full path relative to the file in which the lib was imported from
-					lib_str = gb_string_append_fmt(lib_str, " %.*s ", LIT(lib));
-				} else if (string_ends_with(lib, str_lit(".dylib"))) {
-					// dynamic lib
-					lib_str = gb_string_append_fmt(lib_str, " %.*s ", LIT(lib));
-				} else {
-					// dynamic or static system lib, just link regularly searching system library paths
-					lib_str = gb_string_append_fmt(lib_str, " -l%.*s ", LIT(lib));
+			if (build_context.out_filepath.len > 0) {
+				//NOTE(thebirk): We have a custom -out arguments, so we should use the extension from that
+				isize pos = string_extension_position(build_context.out_filepath);
+				if (pos > 0) {
+					output_ext = substring(build_context.out_filepath, pos, build_context.out_filepath.len);
 				}
-			#else
-				// NOTE(vassvik): static libraries (.a files) in linux can be linked to directly using the full path,
-				//                since those are statically linked to at link time. shared libraries (.so) has to be
-				//                available at runtime wherever the executable is run, so we make require those to be
-				//                local to the executable (unless the system collection is used, in which case we search
-				//                the system library paths for the library file).
-				if (string_ends_with(lib, str_lit(".a"))) {
-					// static libs, absolute full path relative to the file in which the lib was imported from
-					lib_str = gb_string_append_fmt(lib_str, " -l:\"%.*s\" ", LIT(lib));
-				} else if (string_ends_with(lib, str_lit(".so"))) {
-					// dynamic lib, relative path to executable
-					// NOTE(vassvik): it is the user's responsibility to make sure the shared library files are visible
-					//                at runtimeto the executable
-					lib_str = gb_string_append_fmt(lib_str, " -l:\"%s/%.*s\" ", cwd, LIT(lib));
-				} else {
-					// dynamic or static system lib, just link regularly searching system library paths
-					lib_str = gb_string_append_fmt(lib_str, " -l%.*s ", LIT(lib));
-				}
-			#endif
-		}
+			}
 
-		// Unlike the Win32 linker code, the output_ext includes the dot, because
-		// typically executable files on *NIX systems don't have extensions.
-		String output_ext = {};
-		char const *link_settings = "";
-		char const *linker;
-		if (build_context.is_dll) {
-			// Shared libraries are .dylib on MacOS and .so on Linux.
 			#if defined(GB_SYSTEM_OSX)
-				output_ext = STR_LIT(".dylib");
-				link_settings = "-dylib -dynamic";
+				linker = "ld";
 			#else
-				output_ext = STR_LIT(".so");
-				link_settings = "-shared";
+				// TODO(zangent): Figure out how to make ld work on Linux.
+				//   It probably has to do with including the entire CRT, but
+				//   that's quite a complicated issue to solve while remaining distro-agnostic.
+				//   Clang can figure out linker flags for us, and that's good enough _for now_.
+				linker = "clang -Wno-unused-command-line-argument";
 			#endif
-		} else {
-			// TODO: Do I need anything here?
-			link_settings = "";
-		}
 
-		if (build_context.out_filepath.len > 0) {
-			//NOTE(thebirk): We have a custom -out arguments, so we should use the extension from that
-			isize pos = string_extension_position(build_context.out_filepath);
-			if (pos > 0) {
-				output_ext = substring(build_context.out_filepath, pos, build_context.out_filepath.len);
+			exit_code = system_exec_command_line_app("ld-link",
+				"%s \"%.*s.o\" -o \"%.*s%.*s\" %s "
+				" %s "
+				" %.*s "
+				" %s "
+				#if defined(GB_SYSTEM_OSX)
+					// This sets a requirement of Mountain Lion and up, but the compiler doesn't work without this limit.
+					// NOTE: If you change this (although this minimum is as low as you can go with Odin working)
+					//       make sure to also change the 'mtriple' param passed to 'opt'
+					" -macosx_version_min 10.8.0 "
+					// This points the linker to where the entry point is
+					" -e _main "
+				#endif
+				, linker, LIT(output_base), LIT(output_base), LIT(output_ext),
+				lib_str,
+				"-lc -lm",
+				LIT(build_context.link_flags),
+				link_settings);
+			if (exit_code != 0) {
+				return exit_code;
 			}
-		}
 
 		#if defined(GB_SYSTEM_OSX)
-			linker = "ld";
-		#else
-			// TODO(zangent): Figure out how to make ld work on Linux.
-			//   It probably has to do with including the entire CRT, but
-			//   that's quite a complicated issue to solve while remaining distro-agnostic.
-			//   Clang can figure out linker flags for us, and that's good enough _for now_.
-			linker = "clang -Wno-unused-command-line-argument";
-		#endif
-
-		exit_code = system_exec_command_line_app("ld-link",
-			"%s \"%.*s.o\" -o \"%.*s%.*s\" %s "
-			" %s "
-			" %.*s "
-			" %s "
-			#if defined(GB_SYSTEM_OSX)
-				// This sets a requirement of Mountain Lion and up, but the compiler doesn't work without this limit.
-				// NOTE: If you change this (although this minimum is as low as you can go with Odin working)
-				//       make sure to also change the 'mtriple' param passed to 'opt'
-				" -macosx_version_min 10.8.0 "
-				// This points the linker to where the entry point is
-				" -e _main "
-			#endif
-			, linker, LIT(output_base), LIT(output_base), LIT(output_ext),
-			lib_str,
-			"-lc -lm",
-			LIT(build_context.link_flags),
-			link_settings);
-		if (exit_code != 0) {
-			return exit_code;
-		}
-
-	#if defined(GB_SYSTEM_OSX)
-		if (build_context.ODIN_DEBUG) {
-			// NOTE: macOS links DWARF symbols dynamically. Dsymutil will map the stubs in the exe
-			// to the symbols in the object file
-			exit_code = system_exec_command_line_app("dsymutil",
-				"dsymutil %.*s%.*s", LIT(output_base), LIT(output_ext)
-			);
+			if (build_context.ODIN_DEBUG) {
+				// NOTE: macOS links DWARF symbols dynamically. Dsymutil will map the stubs in the exe
+				// to the symbols in the object file
+				exit_code = system_exec_command_line_app("dsymutil",
+					"dsymutil %.*s%.*s", LIT(output_base), LIT(output_ext)
+				);
 
-			if (exit_code != 0) {
-				return exit_code;
+				if (exit_code != 0) {
+					return exit_code;
+				}
 			}
-		}
-	#endif
+		#endif
 
 
-		if (build_context.show_timings) {
-			show_timings(&checker, timings);
-		}
+			if (build_context.show_timings) {
+				show_timings(&checker, timings);
+			}
 
-		remove_temp_files(output_base);
+			remove_temp_files(output_base);
 
-		if (run_output) {
-			//NOTE(thebirk): This whole thing is a little leaky
-			String complete_path = concatenate_strings(heap_allocator(), output_base, output_ext);
-			complete_path = path_to_full_path(heap_allocator(), complete_path);
-			return system_exec_command_line_app("odin run", "\"%.*s\" %.*s", LIT(complete_path), LIT(run_args_string));
+			if (run_output) {
+				//NOTE(thebirk): This whole thing is a little leaky
+				String complete_path = concatenate_strings(heap_allocator(), output_base, output_ext);
+				complete_path = path_to_full_path(heap_allocator(), complete_path);
+				return system_exec_command_line_app("odin run", "\"%.*s\" %.*s", LIT(complete_path), LIT(run_args_string));
+			}
+		#endif
 		}
-	#endif
 	}
 
 	return 0;