Browse Source

Merge pull request #1526 from odin-lang/freestanding_amd64

Freestanding target for amd64
gingerBill 3 years ago
parent
commit
fc0291d745

+ 1 - 1
core/os/file_windows.odin

@@ -113,7 +113,7 @@ read_console :: proc(handle: win32.HANDLE, b: []byte) -> (n: int, err: Errno) {
 		if max_read == 0 {
 		if max_read == 0 {
 			break
 			break
 		}
 		}
-
+		
 		single_read_length: u32
 		single_read_length: u32
 		ok := win32.ReadConsoleW(handle, &buf16[0], max_read, &single_read_length, nil)
 		ok := win32.ReadConsoleW(handle, &buf16[0], max_read, &single_read_length, nil)
 		if !ok {
 		if !ok {

+ 12 - 10
core/runtime/core.odin

@@ -451,7 +451,7 @@ Odin_Endian_Type :: type_of(ODIN_ENDIAN)
 // This is probably only useful for freestanding targets
 // This is probably only useful for freestanding targets
 foreign {
 foreign {
 	@(link_name="__$startup_runtime")
 	@(link_name="__$startup_runtime")
-	_startup_runtime :: proc() ---
+	_startup_runtime :: proc "odin" () ---
 }
 }
 
 
 @(link_name="__$cleanup_runtime")
 @(link_name="__$cleanup_runtime")
@@ -513,16 +513,18 @@ __type_info_of :: proc "contextless" (id: typeid) -> ^Type_Info #no_bounds_check
 	return &type_table[n]
 	return &type_table[n]
 }
 }
 
 
-typeid_base :: proc "contextless" (id: typeid) -> typeid {
-	ti := type_info_of(id)
-	ti = type_info_base(ti)
-	return ti.id
-}
-typeid_core :: proc "contextless" (id: typeid) -> typeid {
-	ti := type_info_core(type_info_of(id))
-	return ti.id
+when !ODIN_DISALLOW_RTTI {
+	typeid_base :: proc "contextless" (id: typeid) -> typeid {
+		ti := type_info_of(id)
+		ti = type_info_base(ti)
+		return ti.id
+	}
+	typeid_core :: proc "contextless" (id: typeid) -> typeid {
+		ti := type_info_core(type_info_of(id))
+		return ti.id
+	}
+	typeid_base_without_enum :: typeid_core
 }
 }
-typeid_base_without_enum :: typeid_core
 
 
 
 
 
 

+ 89 - 53
core/runtime/error_checks.odin

@@ -21,6 +21,7 @@ bounds_check_error :: proc "contextless" (file: string, line, column: i32, index
 	if 0 <= index && index < count {
 	if 0 <= index && index < count {
 		return
 		return
 	}
 	}
+	@(cold)
 	handle_error :: proc "contextless" (file: string, line, column: i32, index, count: int) {
 	handle_error :: proc "contextless" (file: string, line, column: i32, index, count: int) {
 		print_caller_location(Source_Code_Location{file, line, column, ""})
 		print_caller_location(Source_Code_Location{file, line, column, ""})
 		print_string(" Index ")
 		print_string(" Index ")
@@ -81,6 +82,7 @@ dynamic_array_expr_error :: proc "contextless" (file: string, line, column: i32,
 	if 0 <= low && low <= high && high <= max {
 	if 0 <= low && low <= high && high <= max {
 		return
 		return
 	}
 	}
+	@(cold)
 	handle_error :: proc "contextless" (file: string, line, column: i32, low, high, max: int) {
 	handle_error :: proc "contextless" (file: string, line, column: i32, low, high, max: int) {
 		print_caller_location(Source_Code_Location{file, line, column, ""})
 		print_caller_location(Source_Code_Location{file, line, column, ""})
 		print_string(" Invalid dynamic array indices ")
 		print_string(" Invalid dynamic array indices ")
@@ -97,10 +99,11 @@ dynamic_array_expr_error :: proc "contextless" (file: string, line, column: i32,
 
 
 
 
 matrix_bounds_check_error :: proc "contextless" (file: string, line, column: i32, row_index, column_index, row_count, column_count: int) {
 matrix_bounds_check_error :: proc "contextless" (file: string, line, column: i32, row_index, column_index, row_count, column_count: int) {
-	if 0 <= row_index && row_index < row_count && 
+	if 0 <= row_index && row_index < row_count &&
 	   0 <= column_index && column_index < column_count {
 	   0 <= column_index && column_index < column_count {
 		return
 		return
 	}
 	}
+	@(cold)
 	handle_error :: proc "contextless" (file: string, line, column: i32, row_index, column_index, row_count, column_count: int) {
 	handle_error :: proc "contextless" (file: string, line, column: i32, row_index, column_index, row_count, column_count: int) {
 		print_caller_location(Source_Code_Location{file, line, column, ""})
 		print_caller_location(Source_Code_Location{file, line, column, ""})
 		print_string(" Matrix indices [")
 		print_string(" Matrix indices [")
@@ -119,71 +122,101 @@ matrix_bounds_check_error :: proc "contextless" (file: string, line, column: i32
 }
 }
 
 
 
 
-type_assertion_check :: proc "contextless" (ok: bool, file: string, line, column: i32, from, to: typeid) {
-	if ok {
-		return
-	}
-	handle_error :: proc "contextless" (file: string, line, column: i32, from, to: typeid) {
-		print_caller_location(Source_Code_Location{file, line, column, ""})
-		print_string(" Invalid type assertion from ")
-		print_typeid(from)
-		print_string(" to ")
-		print_typeid(to)
-		print_byte('\n')
-		type_assertion_trap()
+when ODIN_DISALLOW_RTTI {
+	type_assertion_check :: proc "contextless" (ok: bool, file: string, line, column: i32) {
+		if ok {
+			return
+		}
+		@(cold)
+		handle_error :: proc "contextless" (file: string, line, column: i32) {
+			print_caller_location(Source_Code_Location{file, line, column, ""})
+			print_string(" Invalid type assertion\n")
+			type_assertion_trap()
+		}
+		handle_error(file, line, column)
 	}
 	}
-	handle_error(file, line, column, from, to)
-}
 
 
-type_assertion_check2 :: proc "contextless" (ok: bool, file: string, line, column: i32, from, to: typeid, from_data: rawptr) {
-	if ok {
-		return
+	type_assertion_check2 :: proc "contextless" (ok: bool, file: string, line, column: i32) {
+		if ok {
+			return
+		}
+		@(cold)
+		handle_error :: proc "contextless" (file: string, line, column: i32) {
+			print_caller_location(Source_Code_Location{file, line, column, ""})
+			print_string(" Invalid type assertion\n")
+			type_assertion_trap()
+		}
+		handle_error(file, line, column)
+	}
+} else {
+	type_assertion_check :: proc "contextless" (ok: bool, file: string, line, column: i32, from, to: typeid) {
+		if ok {
+			return
+		}
+		@(cold)
+		handle_error :: proc "contextless" (file: string, line, column: i32, from, to: typeid) {
+			print_caller_location(Source_Code_Location{file, line, column, ""})
+			print_string(" Invalid type assertion from ")
+			print_typeid(from)
+			print_string(" to ")
+			print_typeid(to)
+			print_byte('\n')
+			type_assertion_trap()
+		}
+		handle_error(file, line, column, from, to)
 	}
 	}
 
 
-	variant_type :: proc "contextless" (id: typeid, data: rawptr) -> typeid {
-		if id == nil || data == nil {
-			return id
+	type_assertion_check2 :: proc "contextless" (ok: bool, file: string, line, column: i32, from, to: typeid, from_data: rawptr) {
+		if ok {
+			return
 		}
 		}
-		ti := type_info_base(type_info_of(id))
-		#partial switch v in ti.variant {
-		case Type_Info_Any:
-			return (^any)(data).id
-		case Type_Info_Union:
-			tag_ptr := uintptr(data) + v.tag_offset
-			idx := 0
-			switch v.tag_type.size {
-			case 1:  idx = int((^u8)(tag_ptr)^)   - 1
-			case 2:  idx = int((^u16)(tag_ptr)^)  - 1
-			case 4:  idx = int((^u32)(tag_ptr)^)  - 1
-			case 8:  idx = int((^u64)(tag_ptr)^)  - 1
-			case 16: idx = int((^u128)(tag_ptr)^) - 1
+
+		variant_type :: proc "contextless" (id: typeid, data: rawptr) -> typeid {
+			if id == nil || data == nil {
+				return id
 			}
 			}
-			if idx < 0 {
-				return nil
-			} else if idx < len(v.variants) {
-				return v.variants[idx].id
+			ti := type_info_base(type_info_of(id))
+			#partial switch v in ti.variant {
+			case Type_Info_Any:
+				return (^any)(data).id
+			case Type_Info_Union:
+				tag_ptr := uintptr(data) + v.tag_offset
+				idx := 0
+				switch v.tag_type.size {
+				case 1:  idx = int((^u8)(tag_ptr)^)   - 1
+				case 2:  idx = int((^u16)(tag_ptr)^)  - 1
+				case 4:  idx = int((^u32)(tag_ptr)^)  - 1
+				case 8:  idx = int((^u64)(tag_ptr)^)  - 1
+				case 16: idx = int((^u128)(tag_ptr)^) - 1
+				}
+				if idx < 0 {
+					return nil
+				} else if idx < len(v.variants) {
+					return v.variants[idx].id
+				}
 			}
 			}
+			return id
 		}
 		}
-		return id
-	}
 
 
-	handle_error :: proc "contextless" (file: string, line, column: i32, from, to: typeid, from_data: rawptr) {
+		@(cold)
+		handle_error :: proc "contextless" (file: string, line, column: i32, from, to: typeid, from_data: rawptr) {
 
 
-		actual := variant_type(from, from_data)
+			actual := variant_type(from, from_data)
 
 
-		print_caller_location(Source_Code_Location{file, line, column, ""})
-		print_string(" Invalid type assertion from ")
-		print_typeid(from)
-		print_string(" to ")
-		print_typeid(to)
-		if actual != from {
-			print_string(", actual type: ")
-			print_typeid(actual)
+			print_caller_location(Source_Code_Location{file, line, column, ""})
+			print_string(" Invalid type assertion from ")
+			print_typeid(from)
+			print_string(" to ")
+			print_typeid(to)
+			if actual != from {
+				print_string(", actual type: ")
+				print_typeid(actual)
+			}
+			print_byte('\n')
+			type_assertion_trap()
 		}
 		}
-		print_byte('\n')
-		type_assertion_trap()
+		handle_error(file, line, column, from, to, from_data)
 	}
 	}
-	handle_error(file, line, column, from, to, from_data)
 }
 }
 
 
 
 
@@ -191,6 +224,7 @@ make_slice_error_loc :: #force_inline proc "contextless" (loc := #caller_locatio
 	if 0 <= len {
 	if 0 <= len {
 		return
 		return
 	}
 	}
+	@(cold)
 	handle_error :: proc "contextless" (loc: Source_Code_Location, len: int) {
 	handle_error :: proc "contextless" (loc: Source_Code_Location, len: int) {
 		print_caller_location(loc)
 		print_caller_location(loc)
 		print_string(" Invalid slice length for make: ")
 		print_string(" Invalid slice length for make: ")
@@ -205,6 +239,7 @@ make_dynamic_array_error_loc :: #force_inline proc "contextless" (using loc := #
 	if 0 <= len && len <= cap {
 	if 0 <= len && len <= cap {
 		return
 		return
 	}
 	}
+	@(cold)
 	handle_error :: proc "contextless" (loc: Source_Code_Location, len, cap: int) {
 	handle_error :: proc "contextless" (loc: Source_Code_Location, len, cap: int) {
 		print_caller_location(loc)
 		print_caller_location(loc)
 		print_string(" Invalid dynamic array parameters for make: ")
 		print_string(" Invalid dynamic array parameters for make: ")
@@ -221,6 +256,7 @@ make_map_expr_error_loc :: #force_inline proc "contextless" (loc := #caller_loca
 	if 0 <= cap {
 	if 0 <= cap {
 		return
 		return
 	}
 	}
+	@(cold)
 	handle_error :: proc "contextless" (loc: Source_Code_Location, cap: int) {
 	handle_error :: proc "contextless" (loc: Source_Code_Location, cap: int) {
 		print_caller_location(loc)
 		print_caller_location(loc)
 		print_string(" Invalid map capacity for make: ")
 		print_string(" Invalid map capacity for make: ")

+ 12 - 4
core/runtime/print.odin

@@ -160,11 +160,19 @@ print_caller_location :: proc "contextless" (using loc: Source_Code_Location) {
 	}
 	}
 }
 }
 print_typeid :: proc "contextless" (id: typeid) {
 print_typeid :: proc "contextless" (id: typeid) {
-	if id == nil {
-		print_string("nil")
+	when ODIN_DISALLOW_RTTI {
+		if id == nil {
+			print_string("nil")
+		} else {
+			print_string("<unknown type>")
+		}
 	} else {
 	} else {
-		ti := type_info_of(id)
-		print_type(ti)
+		if id == nil {
+			print_string("nil")
+		} else {
+			ti := type_info_of(id)
+			print_type(ti)
+		}
 	}
 	}
 }
 }
 print_type :: proc "contextless" (ti: ^Type_Info) {
 print_type :: proc "contextless" (ti: ^Type_Info) {

+ 66 - 7
src/build_settings.cpp

@@ -8,7 +8,7 @@
 // #define DEFAULT_TO_THREADED_CHECKER
 // #define DEFAULT_TO_THREADED_CHECKER
 // #endif
 // #endif
 
 
-enum TargetOsKind {
+enum TargetOsKind : u16 {
 	TargetOs_Invalid,
 	TargetOs_Invalid,
 
 
 	TargetOs_windows,
 	TargetOs_windows,
@@ -26,7 +26,7 @@ enum TargetOsKind {
 	TargetOs_COUNT,
 	TargetOs_COUNT,
 };
 };
 
 
-enum TargetArchKind {
+enum TargetArchKind : u16 {
 	TargetArch_Invalid,
 	TargetArch_Invalid,
 
 
 	TargetArch_amd64,
 	TargetArch_amd64,
@@ -38,7 +38,7 @@ enum TargetArchKind {
 	TargetArch_COUNT,
 	TargetArch_COUNT,
 };
 };
 
 
-enum TargetEndianKind {
+enum TargetEndianKind : u8 {
 	TargetEndian_Invalid,
 	TargetEndian_Invalid,
 
 
 	TargetEndian_Little,
 	TargetEndian_Little,
@@ -47,6 +47,16 @@ enum TargetEndianKind {
 	TargetEndian_COUNT,
 	TargetEndian_COUNT,
 };
 };
 
 
+enum TargetABIKind : u16 {
+	TargetABI_Default,
+
+	TargetABI_Win64,
+	TargetABI_SysV,
+
+	TargetABI_COUNT,
+};
+
+
 String target_os_names[TargetOs_COUNT] = {
 String target_os_names[TargetOs_COUNT] = {
 	str_lit(""),
 	str_lit(""),
 	str_lit("windows"),
 	str_lit("windows"),
@@ -77,6 +87,12 @@ String target_endian_names[TargetEndian_COUNT] = {
 	str_lit("big"),
 	str_lit("big"),
 };
 };
 
 
+String target_abi_names[TargetABI_COUNT] = {
+	str_lit(""),
+	str_lit("win64"),
+	str_lit("sysv"),
+};
+
 TargetEndianKind target_endians[TargetArch_COUNT] = {
 TargetEndianKind target_endians[TargetArch_COUNT] = {
 	TargetEndian_Invalid,
 	TargetEndian_Invalid,
 	TargetEndian_Little,
 	TargetEndian_Little,
@@ -100,6 +116,7 @@ struct TargetMetrics {
 	isize          max_align;
 	isize          max_align;
 	String         target_triplet;
 	String         target_triplet;
 	String         target_data_layout;
 	String         target_data_layout;
+	TargetABIKind  abi;
 };
 };
 
 
 
 
@@ -174,6 +191,13 @@ enum ErrorPosStyle {
 	ErrorPosStyle_COUNT
 	ErrorPosStyle_COUNT
 };
 };
 
 
+enum RelocMode : u8 {
+	RelocMode_Default,
+	RelocMode_Static,
+	RelocMode_PIC,
+	RelocMode_DynamicNoPIC,
+};
+
 // This stores the information for the specify architecture of this build
 // This stores the information for the specify architecture of this build
 struct BuildContext {
 struct BuildContext {
 	// Constants
 	// Constants
@@ -185,6 +209,7 @@ struct BuildContext {
 	bool   ODIN_DEBUG;   // Odin in debug mode
 	bool   ODIN_DEBUG;   // Odin in debug mode
 	bool   ODIN_DISABLE_ASSERT; // Whether the default 'assert' et al is disabled in code or not
 	bool   ODIN_DISABLE_ASSERT; // Whether the default 'assert' et al is disabled in code or not
 	bool   ODIN_DEFAULT_TO_NIL_ALLOCATOR; // Whether the default allocator is a "nil" allocator or not (i.e. it does nothing)
 	bool   ODIN_DEFAULT_TO_NIL_ALLOCATOR; // Whether the default allocator is a "nil" allocator or not (i.e. it does nothing)
+	bool   ODIN_FOREIGN_ERROR_PROCEDURES;
 
 
 	ErrorPosStyle ODIN_ERROR_POS_STYLE;
 	ErrorPosStyle ODIN_ERROR_POS_STYLE;
 
 
@@ -209,6 +234,7 @@ struct BuildContext {
 	String extra_linker_flags;
 	String extra_linker_flags;
 	String extra_assembler_flags;
 	String extra_assembler_flags;
 	String microarch;
 	String microarch;
+	String target_features;
 	BuildModeKind build_mode;
 	BuildModeKind build_mode;
 	bool   generate_docs;
 	bool   generate_docs;
 	i32    optimization_level;
 	i32    optimization_level;
@@ -254,6 +280,12 @@ struct BuildContext {
 	
 	
 	bool copy_file_contents;
 	bool copy_file_contents;
 
 
+	bool disallow_rtti;
+
+	RelocMode reloc_mode;
+	bool disable_red_zone;
+
+
 	u32 cmd_doc_flags;
 	u32 cmd_doc_flags;
 	Array<String> extra_packages;
 	Array<String> extra_packages;
 
 
@@ -410,6 +442,16 @@ gb_global TargetMetrics target_wasi_wasm32 = {
 // 	str_lit(""),
 // 	str_lit(""),
 // };
 // };
 
 
+gb_global TargetMetrics target_freestanding_amd64_sysv = {
+	TargetOs_freestanding,
+	TargetArch_amd64,
+	8,
+	16,
+	str_lit("x86_64-pc-none-gnu"),
+	str_lit("e-m:w-i64:64-f80:128-n8:16:32:64-S128"),
+	TargetABI_SysV,
+};
+
 
 
 
 
 struct NamedTargetMetrics {
 struct NamedTargetMetrics {
@@ -432,7 +474,8 @@ gb_global NamedTargetMetrics named_targets[] = {
 	{ str_lit("freestanding_wasm32"), &target_freestanding_wasm32 },
 	{ str_lit("freestanding_wasm32"), &target_freestanding_wasm32 },
 	{ str_lit("wasi_wasm32"),         &target_wasi_wasm32 },
 	{ str_lit("wasi_wasm32"),         &target_wasi_wasm32 },
 	{ str_lit("js_wasm32"),           &target_js_wasm32 },
 	{ str_lit("js_wasm32"),           &target_js_wasm32 },
-	// { str_lit("freestanding_wasm64"), &target_freestanding_wasm64 },
+
+	{ str_lit("freestanding_amd64_sysv"), &target_freestanding_amd64_sysv },
 };
 };
 
 
 NamedTargetMetrics *selected_target_metrics;
 NamedTargetMetrics *selected_target_metrics;
@@ -946,7 +989,6 @@ void init_build_context(TargetMetrics *cross_target) {
 		}
 		}
 	}
 	}
 
 
-	
 	bc->copy_file_contents = true;
 	bc->copy_file_contents = true;
 
 
 	TargetMetrics *metrics = nullptr;
 	TargetMetrics *metrics = nullptr;
@@ -1005,6 +1047,21 @@ void init_build_context(TargetMetrics *cross_target) {
 	bc->threaded_checker = true;
 	bc->threaded_checker = true;
 	#endif
 	#endif
 
 
+	if (bc->disable_red_zone) {
+		if (!!is_arch_wasm() && bc->metrics.os == TargetOs_freestanding) {
+			gb_printf_err("-disable-red-zone is not support for this target");
+			gb_exit(1);
+		}
+	}
+
+	if (bc->metrics.os == TargetOs_freestanding) {
+		bc->no_entry_point = true;
+	} else {
+		if (bc->disallow_rtti) {
+			gb_printf_err("-disallow-rtti is only allowed on freestanding targets\n");
+			gb_exit(1);
+		}
+	}
 
 
 	// 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
@@ -1059,14 +1116,14 @@ void init_build_context(TargetMetrics *cross_target) {
 		if (bc->metrics.arch == TargetArch_wasm64) {
 		if (bc->metrics.arch == TargetArch_wasm64) {
 			link_flags = gb_string_appendc(link_flags, "-mwas64 ");
 			link_flags = gb_string_appendc(link_flags, "-mwas64 ");
 		}
 		}
-		if (bc->metrics.os == TargetOs_freestanding) {
+		if (bc->no_entry_point) {
 			link_flags = gb_string_appendc(link_flags, "--no-entry ");
 			link_flags = gb_string_appendc(link_flags, "--no-entry ");
 		}
 		}
 		
 		
 		bc->link_flags = make_string_c(link_flags);
 		bc->link_flags = make_string_c(link_flags);
 		
 		
 		// Disallow on wasm
 		// Disallow on wasm
-		build_context.use_separate_modules = false;
+		bc->use_separate_modules = false;
 	} else {
 	} else {
 		gb_printf_err("Compiler Error: Unsupported architecture\n");
 		gb_printf_err("Compiler Error: Unsupported architecture\n");
 		gb_exit(1);
 		gb_exit(1);
@@ -1074,6 +1131,8 @@ void init_build_context(TargetMetrics *cross_target) {
 
 
 	bc->optimization_level = gb_clamp(bc->optimization_level, 0, 3);
 	bc->optimization_level = gb_clamp(bc->optimization_level, 0, 3);
 
 
+
+
 	#undef LINK_FLAG_X64
 	#undef LINK_FLAG_X64
 	#undef LINK_FLAG_386
 	#undef LINK_FLAG_386
 }
 }

+ 13 - 5
src/check_builtin.cpp

@@ -1241,6 +1241,10 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
 		if (c->scope->flags&ScopeFlag_Global) {
 		if (c->scope->flags&ScopeFlag_Global) {
 			compiler_error("'type_info_of' Cannot be declared within the runtime package due to how the internals of the compiler works");
 			compiler_error("'type_info_of' Cannot be declared within the runtime package due to how the internals of the compiler works");
 		}
 		}
+		if (build_context.disallow_rtti) {
+			error(call, "'%.*s' has been disallowed", LIT(builtin_name));
+			return false;
+		}
 
 
 		// NOTE(bill): The type information may not be setup yet
 		// NOTE(bill): The type information may not be setup yet
 		init_core_type_info(c->checker);
 		init_core_type_info(c->checker);
@@ -1253,9 +1257,9 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
 		Type *t = o.type;
 		Type *t = o.type;
 		if (t == nullptr || t == t_invalid || is_type_asm_proc(o.type) || is_type_polymorphic(t)) {
 		if (t == nullptr || t == t_invalid || is_type_asm_proc(o.type) || is_type_polymorphic(t)) {
 			if (is_type_polymorphic(t)) {
 			if (is_type_polymorphic(t)) {
-				error(ce->args[0], "Invalid argument for 'type_info_of', unspecialized polymorphic type");
+				error(ce->args[0], "Invalid argument for '%.*s', unspecialized polymorphic type", LIT(builtin_name));
 			} else {
 			} else {
-				error(ce->args[0], "Invalid argument for 'type_info_of'");
+				error(ce->args[0], "Invalid argument for '%.*s'", LIT(builtin_name));
 			}
 			}
 			return false;
 			return false;
 		}
 		}
@@ -1266,7 +1270,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
 		if (is_operand_value(o) && is_type_typeid(t)) {
 		if (is_operand_value(o) && is_type_typeid(t)) {
 			add_package_dependency(c, "runtime", "__type_info_of");
 			add_package_dependency(c, "runtime", "__type_info_of");
 		} else if (o.mode != Addressing_Type) {
 		} else if (o.mode != Addressing_Type) {
-			error(expr, "Expected a type or typeid for 'type_info_of'");
+			error(expr, "Expected a type or typeid for '%.*s'", LIT(builtin_name));
 			return false;
 			return false;
 		}
 		}
 
 
@@ -1280,6 +1284,10 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
 		if (c->scope->flags&ScopeFlag_Global) {
 		if (c->scope->flags&ScopeFlag_Global) {
 			compiler_error("'typeid_of' Cannot be declared within the runtime package due to how the internals of the compiler works");
 			compiler_error("'typeid_of' Cannot be declared within the runtime package due to how the internals of the compiler works");
 		}
 		}
+		if (build_context.disallow_rtti) {
+			error(call, "'%.*s' has been disallowed", LIT(builtin_name));
+			return false;
+		}
 
 
 		// NOTE(bill): The type information may not be setup yet
 		// NOTE(bill): The type information may not be setup yet
 		init_core_type_info(c->checker);
 		init_core_type_info(c->checker);
@@ -1291,7 +1299,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
 		}
 		}
 		Type *t = o.type;
 		Type *t = o.type;
 		if (t == nullptr || t == t_invalid || is_type_asm_proc(o.type) || is_type_polymorphic(operand->type)) {
 		if (t == nullptr || t == t_invalid || is_type_asm_proc(o.type) || is_type_polymorphic(operand->type)) {
-			error(ce->args[0], "Invalid argument for 'typeid_of'");
+			error(ce->args[0], "Invalid argument for '%.*s'", LIT(builtin_name));
 			return false;
 			return false;
 		}
 		}
 		t = default_type(t);
 		t = default_type(t);
@@ -1299,7 +1307,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
 		add_type_info_type(c, t);
 		add_type_info_type(c, t);
 
 
 		if (o.mode != Addressing_Type) {
 		if (o.mode != Addressing_Type) {
-			error(expr, "Expected a type for 'typeid_of'");
+			error(expr, "Expected a type for '%.*s'", LIT(builtin_name));
 			return false;
 			return false;
 		}
 		}
 
 

+ 6 - 0
src/check_decl.cpp

@@ -1130,6 +1130,10 @@ void check_global_variable_decl(CheckerContext *ctx, Entity *&e, Ast *type_expr,
 	}
 	}
 	ac.link_name = handle_link_name(ctx, e->token, ac.link_name, ac.link_prefix);
 	ac.link_name = handle_link_name(ctx, e->token, ac.link_name, ac.link_prefix);
 
 
+	if (is_arch_wasm() && e->Variable.thread_local_model.len != 0) {
+		error(e->token, "@(thread_local) is not supported for this target platform");
+	}
+
 	String context_name = str_lit("variable declaration");
 	String context_name = str_lit("variable declaration");
 
 
 	if (type_expr != nullptr) {
 	if (type_expr != nullptr) {
@@ -1205,6 +1209,8 @@ void check_global_variable_decl(CheckerContext *ctx, Entity *&e, Ast *type_expr,
 	Operand o = {};
 	Operand o = {};
 	check_expr_with_type_hint(ctx, &o, init_expr, e->type);
 	check_expr_with_type_hint(ctx, &o, init_expr, e->type);
 	check_init_variable(ctx, e, &o, str_lit("variable declaration"));
 	check_init_variable(ctx, e, &o, str_lit("variable declaration"));
+
+	check_rtti_type_disallowed(e->token, e->type, "A variable declaration is using a type, %s, which has been disallowed");
 }
 }
 
 
 void check_proc_group_decl(CheckerContext *ctx, Entity *&pg_entity, DeclInfo *d) {
 void check_proc_group_decl(CheckerContext *ctx, Entity *&pg_entity, DeclInfo *d) {

+ 2 - 0
src/check_expr.cpp

@@ -9352,6 +9352,8 @@ ExprKind check_expr_base(CheckerContext *c, Operand *o, Ast *node, Type *type_hi
 	if (o->type != nullptr && is_type_untyped(o->type)) {
 	if (o->type != nullptr && is_type_untyped(o->type)) {
 		add_untyped(c, node, o->mode, o->type, o->value);
 		add_untyped(c, node, o->mode, o->type, o->value);
 	}
 	}
+	check_rtti_type_disallowed(node, o->type, "An expression is using a type, %s, which has been disallowed");
+
 	add_type_and_value(c->info, node, o->mode, o->type, o->value);
 	add_type_and_value(c->info, node, o->mode, o->type, o->value);
 	return kind;
 	return kind;
 }
 }

+ 4 - 1
src/check_stmt.cpp

@@ -2152,7 +2152,6 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
 					e->state = EntityState_Resolved;
 					e->state = EntityState_Resolved;
 				}
 				}
 				ac.link_name = handle_link_name(ctx, e->token, ac.link_name, ac.link_prefix);
 				ac.link_name = handle_link_name(ctx, e->token, ac.link_name, ac.link_prefix);
-				e->Variable.thread_local_model = ac.thread_local_model;
 
 
 				if (ac.link_name.len > 0) {
 				if (ac.link_name.len > 0) {
 					e->Variable.link_name = ac.link_name;
 					e->Variable.link_name = ac.link_name;
@@ -2182,6 +2181,10 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
 					}
 					}
 					e->Variable.thread_local_model = ac.thread_local_model;
 					e->Variable.thread_local_model = ac.thread_local_model;
 				}
 				}
+
+				if (is_arch_wasm() && e->Variable.thread_local_model.len != 0) {
+					error(e->token, "@(thread_local) is not supported for this target platform");
+				}
 				
 				
 
 
 				if (ac.is_static && ac.thread_local_model != "") {
 				if (ac.is_static && ac.thread_local_model != "") {

+ 9 - 3
src/check_type.cpp

@@ -2031,10 +2031,14 @@ bool check_procedure_type(CheckerContext *ctx, Type *type, Ast *proc_type_node,
 	if (param_count > 0) {
 	if (param_count > 0) {
 		Entity *end = params->Tuple.variables[param_count-1];
 		Entity *end = params->Tuple.variables[param_count-1];
 		if (end->flags&EntityFlag_CVarArg) {
 		if (end->flags&EntityFlag_CVarArg) {
-			if (cc == ProcCC_StdCall || cc == ProcCC_CDecl) {
+			switch (cc) {
+			default:
 				type->Proc.c_vararg = true;
 				type->Proc.c_vararg = true;
-			} else {
+				break;
+			case ProcCC_Odin:
+			case ProcCC_Contextless:
 				error(end->token, "Calling convention does not support #c_vararg");
 				error(end->token, "Calling convention does not support #c_vararg");
+				break;
 			}
 			}
 		}
 		}
 	}
 	}
@@ -2170,7 +2174,7 @@ void init_map_entry_type(Type *type) {
 
 
 	/*
 	/*
 	struct {
 	struct {
-		hash:  runtime.Map_Hash,
+		hash:  uintptr,
 		next:  int,
 		next:  int,
 		key:   Key,
 		key:   Key,
 		value: Value,
 		value: Value,
@@ -3027,5 +3031,7 @@ Type *check_type_expr(CheckerContext *ctx, Ast *e, Type *named_type) {
 	}
 	}
 	set_base_type(named_type, type);
 	set_base_type(named_type, type);
 
 
+	check_rtti_type_disallowed(e, type, "Use of a type, %s, which has been disallowed");
+
 	return type;
 	return type;
 }
 }

+ 66 - 35
src/checker.cpp

@@ -29,6 +29,23 @@ bool is_operand_undef(Operand o) {
 	return o.mode == Addressing_Value && o.type == t_untyped_undef;
 	return o.mode == Addressing_Value && o.type == t_untyped_undef;
 }
 }
 
 
+bool check_rtti_type_disallowed(Token const &token, Type *type, char const *format) {
+	if (build_context.disallow_rtti && type) {
+		if (is_type_any(type)) {
+			gbString t = type_to_string(type);
+			error(token, format, t);
+			gb_string_free(t);
+			return true;
+		}
+	}
+	return false;
+}
+
+bool check_rtti_type_disallowed(Ast *expr, Type *type, char const *format) {
+	GB_ASSERT(expr != nullptr);
+	return check_rtti_type_disallowed(ast_token(expr), type, format);
+}
+
 void scope_reset(Scope *scope) {
 void scope_reset(Scope *scope) {
 	if (scope == nullptr) return;
 	if (scope == nullptr) return;
 
 
@@ -875,7 +892,8 @@ void init_universal(void) {
 
 
 // Types
 // Types
 	for (isize i = 0; i < gb_count_of(basic_types); i++) {
 	for (isize i = 0; i < gb_count_of(basic_types); i++) {
-		add_global_type_entity(basic_types[i].Basic.name, &basic_types[i]);
+		String const &name = basic_types[i].Basic.name;
+		add_global_type_entity(name, &basic_types[i]);
 	}
 	}
 	add_global_type_entity(str_lit("byte"), &basic_types[Basic_u8]);
 	add_global_type_entity(str_lit("byte"), &basic_types[Basic_u8]);
 
 
@@ -977,6 +995,8 @@ void init_universal(void) {
 	add_global_bool_constant("ODIN_USE_SEPARATE_MODULES",     bc->use_separate_modules);
 	add_global_bool_constant("ODIN_USE_SEPARATE_MODULES",     bc->use_separate_modules);
 	add_global_bool_constant("ODIN_TEST",                     bc->command_kind == Command_test);
 	add_global_bool_constant("ODIN_TEST",                     bc->command_kind == Command_test);
 	add_global_bool_constant("ODIN_NO_ENTRY_POINT",           bc->no_entry_point);
 	add_global_bool_constant("ODIN_NO_ENTRY_POINT",           bc->no_entry_point);
+	add_global_bool_constant("ODIN_FOREIGN_ERROR_PROCEDURES", bc->ODIN_FOREIGN_ERROR_PROCEDURES);
+	add_global_bool_constant("ODIN_DISALLOW_RTTI",            bc->disallow_rtti);
 
 
 
 
 // Builtin Procedures
 // Builtin Procedures
@@ -1669,6 +1689,10 @@ void add_implicit_entity(CheckerContext *c, Ast *clause, Entity *e) {
 void add_type_info_type(CheckerContext *c, Type *t) {
 void add_type_info_type(CheckerContext *c, Type *t) {
 	void add_type_info_type_internal(CheckerContext *c, Type *t);
 	void add_type_info_type_internal(CheckerContext *c, Type *t);
 
 
+	if (build_context.disallow_rtti) {
+		return;
+	}
+
 	mutex_lock(&c->info->type_info_mutex);
 	mutex_lock(&c->info->type_info_mutex);
 	add_type_info_type_internal(c, t);
 	add_type_info_type_internal(c, t);
 	mutex_unlock(&c->info->type_info_mutex);
 	mutex_unlock(&c->info->type_info_mutex);
@@ -2181,21 +2205,25 @@ void generate_minimum_dependency_set(Checker *c, Entity *start) {
 	ptr_set_init(&c->info.minimum_dependency_set, heap_allocator(), min_dep_set_cap);
 	ptr_set_init(&c->info.minimum_dependency_set, heap_allocator(), min_dep_set_cap);
 	ptr_set_init(&c->info.minimum_dependency_type_info_set, heap_allocator());
 	ptr_set_init(&c->info.minimum_dependency_type_info_set, heap_allocator());
 
 
-	String required_runtime_entities[] = {
+#define FORCE_ADD_RUNTIME_ENTITIES(condition, ...) do {                                              \
+	if (condition) {                                                                             \
+		String entities[] = {__VA_ARGS__};                                                   \
+		for (isize i = 0; i < gb_count_of(entities); i++) {                                  \
+			force_add_dependency_entity(c, c->info.runtime_package->scope, entities[i]); \
+		}                                                                                    \
+	}                                                                                            \
+} while (0)
+
+	// required runtime entities
+	FORCE_ADD_RUNTIME_ENTITIES(true,
 		// Odin types
 		// Odin types
-		str_lit("Type_Info"),
 		str_lit("Source_Code_Location"),
 		str_lit("Source_Code_Location"),
 		str_lit("Context"),
 		str_lit("Context"),
 		str_lit("Allocator"),
 		str_lit("Allocator"),
 		str_lit("Logger"),
 		str_lit("Logger"),
 
 
-		// Global variables
-		str_lit("args__"),
-		str_lit("type_table"),
-
 		// Odin internal procedures
 		// Odin internal procedures
 		str_lit("__init_context"),
 		str_lit("__init_context"),
-		str_lit("__type_info_of"),
 		str_lit("cstring_to_string"),
 		str_lit("cstring_to_string"),
 		str_lit("_cleanup_runtime"),
 		str_lit("_cleanup_runtime"),
 
 
@@ -2228,35 +2256,36 @@ void generate_minimum_dependency_set(Checker *c, Entity *start) {
 		// WASM Specific
 		// WASM Specific
 		str_lit("__ashlti3"),
 		str_lit("__ashlti3"),
 		str_lit("__multi3"),
 		str_lit("__multi3"),
-	};
-	for (isize i = 0; i < gb_count_of(required_runtime_entities); i++) {
-		force_add_dependency_entity(c, c->info.runtime_package->scope, required_runtime_entities[i]);
-	}
+	);
 
 
-	if (build_context.no_crt) {
-		String required_no_crt_entities[] = {
-			// NOTE(bill): Only if these exist
-			str_lit("_tls_index"),
-			str_lit("_fltused"),
-		};
-		for (isize i = 0; i < gb_count_of(required_no_crt_entities); i++) {
-			force_add_dependency_entity(c, c->info.runtime_package->scope, required_no_crt_entities[i]);
-		}
-	}
+	FORCE_ADD_RUNTIME_ENTITIES(!build_context.disallow_rtti,
+		// Odin types
+		str_lit("Type_Info"),
 
 
-	if (!build_context.no_bounds_check) {
-		String bounds_check_entities[] = {
-			// Bounds checking related procedures
-			str_lit("bounds_check_error"),
-			str_lit("matrix_bounds_check_error"),
-			str_lit("slice_expr_error_hi"),
-			str_lit("slice_expr_error_lo_hi"),
-			str_lit("multi_pointer_slice_expr_error"),
-		};
-		for (isize i = 0; i < gb_count_of(bounds_check_entities); i++) {
-			force_add_dependency_entity(c, c->info.runtime_package->scope, bounds_check_entities[i]);
-		}
-	}
+		// Global variables
+		str_lit("type_table"),
+		str_lit("__type_info_of"),
+	);
+
+	FORCE_ADD_RUNTIME_ENTITIES(!build_context.no_entry_point,
+		// Global variables
+		str_lit("args__"),
+	);
+
+	FORCE_ADD_RUNTIME_ENTITIES((build_context.no_crt && !is_arch_wasm()),
+		// NOTE(bill): Only if these exist
+		str_lit("_tls_index"),
+		str_lit("_fltused"),
+	);
+
+	FORCE_ADD_RUNTIME_ENTITIES(!build_context.no_bounds_check,
+		// Bounds checking related procedures
+		str_lit("bounds_check_error"),
+		str_lit("matrix_bounds_check_error"),
+		str_lit("slice_expr_error_hi"),
+		str_lit("slice_expr_error_lo_hi"),
+		str_lit("multi_pointer_slice_expr_error"),
+	);
 
 
 	for_array(i, c->info.definitions) {
 	for_array(i, c->info.definitions) {
 		Entity *e = c->info.definitions[i];
 		Entity *e = c->info.definitions[i];
@@ -2378,6 +2407,8 @@ void generate_minimum_dependency_set(Checker *c, Entity *start) {
 		start->flags |= EntityFlag_Used;
 		start->flags |= EntityFlag_Used;
 		add_dependency_to_set(c, start);
 		add_dependency_to_set(c, start);
 	}
 	}
+
+#undef FORCE_ADD_RUNTIME_ENTITIES
 }
 }
 
 
 bool is_entity_a_dependency(Entity *e) {
 bool is_entity_a_dependency(Entity *e) {

+ 3 - 1
src/llvm_abi.cpp

@@ -1194,8 +1194,10 @@ LB_ABI_INFO(lb_get_abi_info) {
 
 
 	switch (build_context.metrics.arch) {
 	switch (build_context.metrics.arch) {
 	case TargetArch_amd64:
 	case TargetArch_amd64:
-		if (build_context.metrics.os == TargetOs_windows) {
+		if (build_context.metrics.os == TargetOs_windows || build_context.metrics.abi == TargetABI_Win64) {
 			return lbAbiAmd64Win64::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention);
 			return lbAbiAmd64Win64::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention);
+		} else if (build_context.metrics.abi == TargetABI_SysV) {
+			return lbAbiAmd64SysV::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention);
 		} else {
 		} else {
 			return lbAbiAmd64SysV::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention);
 			return lbAbiAmd64SysV::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention);
 		}
 		}

+ 46 - 5
src/llvm_backend.cpp

@@ -624,6 +624,9 @@ struct lbGlobalVariable {
 };
 };
 
 
 lbProcedure *lb_create_startup_type_info(lbModule *m) {
 lbProcedure *lb_create_startup_type_info(lbModule *m) {
+	if (build_context.disallow_rtti) {
+		return nullptr;
+	}
 	LLVMPassManagerRef default_function_pass_manager = LLVMCreateFunctionPassManagerForModule(m->mod);
 	LLVMPassManagerRef default_function_pass_manager = LLVMCreateFunctionPassManagerForModule(m->mod);
 	lb_populate_function_pass_manager(m, default_function_pass_manager, false, build_context.optimization_level);
 	lb_populate_function_pass_manager(m, default_function_pass_manager, false, build_context.optimization_level);
 	LLVMFinalizeFunctionPassManager(default_function_pass_manager);
 	LLVMFinalizeFunctionPassManager(default_function_pass_manager);
@@ -711,7 +714,9 @@ lbProcedure *lb_create_startup_runtime(lbModule *main_module, lbProcedure *start
 
 
 	lb_begin_procedure_body(p);
 	lb_begin_procedure_body(p);
 
 
-	LLVMBuildCall2(p->builder, LLVMGetElementType(lb_type(main_module, startup_type_info->type)), startup_type_info->value, nullptr, 0, "");
+	if (startup_type_info) {
+		LLVMBuildCall2(p->builder, LLVMGetElementType(lb_type(main_module, startup_type_info->type)), startup_type_info->value, nullptr, 0, "");
+	}
 
 
 	if (objc_names) {
 	if (objc_names) {
 		LLVMBuildCall2(p->builder, LLVMGetElementType(lb_type(main_module, objc_names->type)), objc_names->value, nullptr, 0, "");
 		LLVMBuildCall2(p->builder, LLVMGetElementType(lb_type(main_module, objc_names->type)), objc_names->value, nullptr, 0, "");
@@ -996,6 +1001,19 @@ String lb_filepath_obj_for_module(lbModule *m) {
 			case TargetOs_essence:
 			case TargetOs_essence:
 				ext = STR_LIT(".o");
 				ext = STR_LIT(".o");
 				break;
 				break;
+
+			case TargetOs_freestanding:
+				switch (build_context.metrics.abi) {
+				default:
+				case TargetABI_Default:
+				case TargetABI_SysV:
+					ext = STR_LIT(".o");
+					break;
+				case TargetABI_Win64:
+					ext = STR_LIT(".obj");
+					break;
+				}
+				break;
 			}
 			}
 		}
 		}
 	}
 	}
@@ -1248,6 +1266,8 @@ void lb_generate_code(lbGenerator *gen) {
 	LLVMCodeModel code_mode = LLVMCodeModelDefault;
 	LLVMCodeModel code_mode = LLVMCodeModelDefault;
 	if (is_arch_wasm()) {
 	if (is_arch_wasm()) {
 		code_mode = LLVMCodeModelJITDefault;
 		code_mode = LLVMCodeModelJITDefault;
+	} else if (build_context.metrics.os == TargetOs_freestanding) {
+		code_mode = LLVMCodeModelKernel;
 	}
 	}
 
 
 	char const *host_cpu_name = LLVMGetHostCPUName();
 	char const *host_cpu_name = LLVMGetHostCPUName();
@@ -1270,10 +1290,18 @@ void lb_generate_code(lbGenerator *gen) {
 		// x86-64-v3: (close to Haswell) AVX, AVX2, BMI1, BMI2, F16C, FMA, LZCNT, MOVBE, XSAVE
 		// x86-64-v3: (close to Haswell) AVX, AVX2, BMI1, BMI2, F16C, FMA, LZCNT, MOVBE, XSAVE
 		// x86-64-v4: AVX512F, AVX512BW, AVX512CD, AVX512DQ, AVX512VL
 		// x86-64-v4: AVX512F, AVX512BW, AVX512CD, AVX512DQ, AVX512VL
 		if (ODIN_LLVM_MINIMUM_VERSION_12) {
 		if (ODIN_LLVM_MINIMUM_VERSION_12) {
-			llvm_cpu = "x86-64-v2";
+			if (build_context.metrics.os == TargetOs_freestanding) {
+				llvm_cpu = "x86-64";
+			} else {
+				llvm_cpu = "x86-64-v2";
+			}
 		}
 		}
 	}
 	}
 
 
+	if (build_context.target_features.len != 0) {
+		llvm_features = alloc_cstring(permanent_allocator(), build_context.target_features);
+	}
+
 	// GB_ASSERT_MSG(LLVMTargetHasAsmBackend(target));
 	// GB_ASSERT_MSG(LLVMTargetHasAsmBackend(target));
 
 
 	LLVMCodeGenOptLevel code_gen_level = LLVMCodeGenLevelNone;
 	LLVMCodeGenOptLevel code_gen_level = LLVMCodeGenLevelNone;
@@ -1295,9 +1323,22 @@ void lb_generate_code(lbGenerator *gen) {
 		reloc_mode = LLVMRelocPIC;
 		reloc_mode = LLVMRelocPIC;
 	}
 	}
 
 
-	if (build_context.metrics.os == TargetOs_openbsd) {
-		// Always use PIC for OpenBSD: it defaults to PIE
+	switch (build_context.reloc_mode) {
+	case RelocMode_Default:
+		if (build_context.metrics.os == TargetOs_openbsd) {
+			// Always use PIC for OpenBSD: it defaults to PIE
+			reloc_mode = LLVMRelocPIC;
+		}
+		break;
+	case RelocMode_Static:
+		reloc_mode = LLVMRelocStatic;
+		break;
+	case RelocMode_PIC:
 		reloc_mode = LLVMRelocPIC;
 		reloc_mode = LLVMRelocPIC;
+		break;
+	case RelocMode_DynamicNoPIC:
+		reloc_mode = LLVMRelocDynamicNoPic;
+		break;
 	}
 	}
 
 
 	for_array(i, gen->modules.entries) {
 	for_array(i, gen->modules.entries) {
@@ -1366,7 +1407,7 @@ void lb_generate_code(lbGenerator *gen) {
 
 
 	TIME_SECTION("LLVM Global Variables");
 	TIME_SECTION("LLVM Global Variables");
 
 
-	{
+	if (!build_context.disallow_rtti) {
 		lbModule *m = default_module;
 		lbModule *m = default_module;
 
 
 		{ // Add type info data
 		{ // Add type info data

+ 14 - 3
src/llvm_backend_expr.cpp

@@ -2824,16 +2824,25 @@ lbValue lb_build_unary_and(lbProcedure *p, Ast *expr) {
 						src_tag = lb_emit_load(p, lb_emit_union_tag_ptr(p, v));
 						src_tag = lb_emit_load(p, lb_emit_union_tag_ptr(p, v));
 						dst_tag = lb_const_union_tag(p->module, src_type, dst_type);
 						dst_tag = lb_const_union_tag(p->module, src_type, dst_type);
 					}
 					}
+
+
+					isize arg_count = 6;
+					if (build_context.disallow_rtti) {
+						arg_count = 4;
+					}
+
 					lbValue ok = lb_emit_comp(p, Token_CmpEq, src_tag, dst_tag);
 					lbValue ok = lb_emit_comp(p, Token_CmpEq, src_tag, dst_tag);
-					auto args = array_make<lbValue>(permanent_allocator(), 6);
+					auto args = array_make<lbValue>(permanent_allocator(), arg_count);
 					args[0] = ok;
 					args[0] = ok;
 
 
 					args[1] = lb_find_or_add_entity_string(p->module, get_file_path_string(pos.file_id));
 					args[1] = lb_find_or_add_entity_string(p->module, get_file_path_string(pos.file_id));
 					args[2] = lb_const_int(p->module, t_i32, pos.line);
 					args[2] = lb_const_int(p->module, t_i32, pos.line);
 					args[3] = lb_const_int(p->module, t_i32, pos.column);
 					args[3] = lb_const_int(p->module, t_i32, pos.column);
 
 
-					args[4] = lb_typeid(p->module, src_type);
-					args[5] = lb_typeid(p->module, dst_type);
+					if (!build_context.disallow_rtti) {
+						args[4] = lb_typeid(p->module, src_type);
+						args[5] = lb_typeid(p->module, dst_type);
+					}
 					lb_emit_runtime_call(p, "type_assertion_check", args);
 					lb_emit_runtime_call(p, "type_assertion_check", args);
 				}
 				}
 
 
@@ -2846,6 +2855,8 @@ lbValue lb_build_unary_and(lbProcedure *p, Ast *expr) {
 				}
 				}
 				lbValue data_ptr = lb_emit_struct_ev(p, v, 0);
 				lbValue data_ptr = lb_emit_struct_ev(p, v, 0);
 				if ((p->state_flags & StateFlag_no_type_assert) == 0) {
 				if ((p->state_flags & StateFlag_no_type_assert) == 0) {
+					GB_ASSERT(!build_context.disallow_rtti);
+
 					lbValue any_id = lb_emit_struct_ev(p, v, 1);
 					lbValue any_id = lb_emit_struct_ev(p, v, 1);
 
 
 					lbValue id = lb_typeid(p->module, type);
 					lbValue id = lb_typeid(p->module, type);

+ 4 - 0
src/llvm_backend_proc.cpp

@@ -135,6 +135,10 @@ lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool ignore_body)
 		lb_add_attribute_to_proc(m, p->value, "naked");
 		lb_add_attribute_to_proc(m, p->value, "naked");
 	}
 	}
 
 
+	if (!entity->Procedure.is_foreign && build_context.disable_red_zone) {
+		lb_add_attribute_to_proc(m, p->value, "noredzone");
+	}
+
 	switch (p->inlining) {
 	switch (p->inlining) {
 	case ProcInlining_inline:
 	case ProcInlining_inline:
 		lb_add_attribute_to_proc(m, p->value, "alwaysinline");
 		lb_add_attribute_to_proc(m, p->value, "alwaysinline");

+ 10 - 0
src/llvm_backend_type.cpp

@@ -14,6 +14,8 @@ isize lb_type_info_index(CheckerInfo *info, Type *type, bool err_on_not_found=tr
 }
 }
 
 
 lbValue lb_typeid(lbModule *m, Type *type) {
 lbValue lb_typeid(lbModule *m, Type *type) {
+	GB_ASSERT(!build_context.disallow_rtti);
+
 	type = default_type(type);
 	type = default_type(type);
 
 
 	u64 id = cast(u64)lb_type_info_index(m->info, type);
 	u64 id = cast(u64)lb_type_info_index(m->info, type);
@@ -88,6 +90,8 @@ lbValue lb_typeid(lbModule *m, Type *type) {
 }
 }
 
 
 lbValue lb_type_info(lbModule *m, Type *type) {
 lbValue lb_type_info(lbModule *m, Type *type) {
+	GB_ASSERT(!build_context.disallow_rtti);
+
 	type = default_type(type);
 	type = default_type(type);
 
 
 	isize index = lb_type_info_index(m->info, type);
 	isize index = lb_type_info_index(m->info, type);
@@ -106,6 +110,8 @@ lbValue lb_type_info(lbModule *m, Type *type) {
 }
 }
 
 
 lbValue lb_get_type_info_ptr(lbModule *m, Type *type) {
 lbValue lb_get_type_info_ptr(lbModule *m, Type *type) {
+	GB_ASSERT(!build_context.disallow_rtti);
+
 	i32 index = cast(i32)lb_type_info_index(m->info, type);
 	i32 index = cast(i32)lb_type_info_index(m->info, type);
 	GB_ASSERT(index >= 0);
 	GB_ASSERT(index >= 0);
 	// gb_printf_err("%d %s\n", index, type_to_string(type));
 	// gb_printf_err("%d %s\n", index, type_to_string(type));
@@ -155,6 +161,10 @@ lbValue lb_type_info_member_tags_offset(lbProcedure *p, isize count) {
 
 
 
 
 void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info data
 void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info data
+	if (build_context.disallow_rtti) {
+		return;
+	}
+
 	lbModule *m = p->module;
 	lbModule *m = p->module;
 	CheckerInfo *info = m->info;
 	CheckerInfo *info = m->info;
 	
 	

+ 22 - 8
src/llvm_backend_utility.cpp

@@ -676,17 +676,24 @@ lbValue lb_emit_union_cast(lbProcedure *p, lbValue value, Type *type, TokenPos p
 		// NOTE(bill): Panic on invalid conversion
 		// NOTE(bill): Panic on invalid conversion
 		Type *dst_type = tuple->Tuple.variables[0]->type;
 		Type *dst_type = tuple->Tuple.variables[0]->type;
 
 
+		isize arg_count = 7;
+		if (build_context.disallow_rtti) {
+			arg_count = 4;
+		}
+
 		lbValue ok = lb_emit_load(p, lb_emit_struct_ep(p, v.addr, 1));
 		lbValue ok = lb_emit_load(p, lb_emit_struct_ep(p, v.addr, 1));
-		auto args = array_make<lbValue>(permanent_allocator(), 7);
+		auto args = array_make<lbValue>(permanent_allocator(), arg_count);
 		args[0] = ok;
 		args[0] = ok;
 
 
 		args[1] = lb_const_string(m, get_file_path_string(pos.file_id));
 		args[1] = lb_const_string(m, get_file_path_string(pos.file_id));
 		args[2] = lb_const_int(m, t_i32, pos.line);
 		args[2] = lb_const_int(m, t_i32, pos.line);
 		args[3] = lb_const_int(m, t_i32, pos.column);
 		args[3] = lb_const_int(m, t_i32, pos.column);
 
 
-		args[4] = lb_typeid(m, src_type);
-		args[5] = lb_typeid(m, dst_type);
-		args[6] = lb_emit_conv(p, value_, t_rawptr);
+		if (!build_context.disallow_rtti) {
+			args[4] = lb_typeid(m, src_type);
+			args[5] = lb_typeid(m, dst_type);
+			args[6] = lb_emit_conv(p, value_, t_rawptr);
+		}
 		lb_emit_runtime_call(p, "type_assertion_check2", args);
 		lb_emit_runtime_call(p, "type_assertion_check2", args);
 
 
 		return lb_emit_load(p, lb_emit_struct_ep(p, v.addr, 0));
 		return lb_emit_load(p, lb_emit_struct_ep(p, v.addr, 0));
@@ -744,16 +751,23 @@ lbAddr lb_emit_any_cast_addr(lbProcedure *p, lbValue value, Type *type, TokenPos
 	if (!is_tuple) {
 	if (!is_tuple) {
 		// NOTE(bill): Panic on invalid conversion
 		// NOTE(bill): Panic on invalid conversion
 		lbValue ok = lb_emit_load(p, lb_emit_struct_ep(p, v.addr, 1));
 		lbValue ok = lb_emit_load(p, lb_emit_struct_ep(p, v.addr, 1));
-		auto args = array_make<lbValue>(permanent_allocator(), 7);
+
+		isize arg_count = 7;
+		if (build_context.disallow_rtti) {
+			arg_count = 4;
+		}
+		auto args = array_make<lbValue>(permanent_allocator(), arg_count);
 		args[0] = ok;
 		args[0] = ok;
 
 
 		args[1] = lb_const_string(m, get_file_path_string(pos.file_id));
 		args[1] = lb_const_string(m, get_file_path_string(pos.file_id));
 		args[2] = lb_const_int(m, t_i32, pos.line);
 		args[2] = lb_const_int(m, t_i32, pos.line);
 		args[3] = lb_const_int(m, t_i32, pos.column);
 		args[3] = lb_const_int(m, t_i32, pos.column);
 
 
-		args[4] = any_typeid;
-		args[5] = dst_typeid;
-		args[6] = lb_emit_struct_ev(p, value, 0);;
+		if (!build_context.disallow_rtti) {
+			args[4] = any_typeid;
+			args[5] = dst_typeid;
+			args[6] = lb_emit_struct_ev(p, value, 0);
+		}
 		lb_emit_runtime_call(p, "type_assertion_check2", args);
 		lb_emit_runtime_call(p, "type_assertion_check2", args);
 
 
 		return lb_addr(lb_emit_struct_ep(p, v.addr, 0));
 		return lb_addr(lb_emit_struct_ep(p, v.addr, 0));

+ 71 - 1
src/main.cpp

@@ -632,6 +632,10 @@ enum BuildFlagKind {
 	BuildFlag_ExtraLinkerFlags,
 	BuildFlag_ExtraLinkerFlags,
 	BuildFlag_ExtraAssemblerFlags,
 	BuildFlag_ExtraAssemblerFlags,
 	BuildFlag_Microarch,
 	BuildFlag_Microarch,
+	BuildFlag_TargetFeatures,
+
+	BuildFlag_RelocMode,
+	BuildFlag_DisableRedZone,
 
 
 	BuildFlag_TestName,
 	BuildFlag_TestName,
 
 
@@ -640,6 +644,8 @@ enum BuildFlagKind {
 	BuildFlag_InsertSemicolon,
 	BuildFlag_InsertSemicolon,
 	BuildFlag_StrictStyle,
 	BuildFlag_StrictStyle,
 	BuildFlag_StrictStyleInitOnly,
 	BuildFlag_StrictStyleInitOnly,
+	BuildFlag_ForeignErrorProcedures,
+	BuildFlag_DisallowRTTI,
 
 
 	BuildFlag_Compact,
 	BuildFlag_Compact,
 	BuildFlag_GlobalDefinitions,
 	BuildFlag_GlobalDefinitions,
@@ -784,7 +790,11 @@ bool parse_build_flags(Array<String> args) {
 	add_flag(&build_flags, BuildFlag_IgnoreUnknownAttributes, str_lit("ignore-unknown-attributes"), BuildFlagParam_None, Command__does_check);
 	add_flag(&build_flags, BuildFlag_IgnoreUnknownAttributes, str_lit("ignore-unknown-attributes"), BuildFlagParam_None, Command__does_check);
 	add_flag(&build_flags, BuildFlag_ExtraLinkerFlags,    str_lit("extra-linker-flags"),            BuildFlagParam_String, Command__does_build);
 	add_flag(&build_flags, BuildFlag_ExtraLinkerFlags,    str_lit("extra-linker-flags"),            BuildFlagParam_String, Command__does_build);
 	add_flag(&build_flags, BuildFlag_ExtraAssemblerFlags, str_lit("extra-assembler-flags"),         BuildFlagParam_String, Command__does_build);
 	add_flag(&build_flags, BuildFlag_ExtraAssemblerFlags, str_lit("extra-assembler-flags"),         BuildFlagParam_String, Command__does_build);
-	add_flag(&build_flags, BuildFlag_Microarch,         str_lit("microarch"),                       BuildFlagParam_String, Command__does_build);
+	add_flag(&build_flags, BuildFlag_Microarch,           str_lit("microarch"),                       BuildFlagParam_String, Command__does_build);
+	add_flag(&build_flags, BuildFlag_TargetFeatures,      str_lit("target-features"),                 BuildFlagParam_String, Command__does_build);
+
+	add_flag(&build_flags, BuildFlag_RelocMode,        str_lit("reloc-mode"),                       BuildFlagParam_String, Command__does_build);
+	add_flag(&build_flags, BuildFlag_DisableRedZone,   str_lit("disable-red-zone"),                 BuildFlagParam_None, Command__does_build);
 
 
 	add_flag(&build_flags, BuildFlag_TestName,         str_lit("test-name"),                       BuildFlagParam_String, Command_test);
 	add_flag(&build_flags, BuildFlag_TestName,         str_lit("test-name"),                       BuildFlagParam_String, Command_test);
 
 
@@ -793,10 +803,16 @@ bool parse_build_flags(Array<String> args) {
 	add_flag(&build_flags, BuildFlag_InsertSemicolon,       str_lit("insert-semicolon"),         BuildFlagParam_None, Command__does_check);
 	add_flag(&build_flags, BuildFlag_InsertSemicolon,       str_lit("insert-semicolon"),         BuildFlagParam_None, Command__does_check);
 	add_flag(&build_flags, BuildFlag_StrictStyle,           str_lit("strict-style"),             BuildFlagParam_None, Command__does_check);
 	add_flag(&build_flags, BuildFlag_StrictStyle,           str_lit("strict-style"),             BuildFlagParam_None, Command__does_check);
 	add_flag(&build_flags, BuildFlag_StrictStyleInitOnly,   str_lit("strict-style-init-only"),   BuildFlagParam_None, Command__does_check);
 	add_flag(&build_flags, BuildFlag_StrictStyleInitOnly,   str_lit("strict-style-init-only"),   BuildFlagParam_None, Command__does_check);
+	add_flag(&build_flags, BuildFlag_ForeignErrorProcedures, str_lit("foreign-error-procedures"), BuildFlagParam_None, Command__does_check);
+
+	add_flag(&build_flags, BuildFlag_DisallowRTTI,            str_lit("disallow-rtti"),              BuildFlagParam_None, Command__does_check);
+
+
 	add_flag(&build_flags, BuildFlag_Compact,           str_lit("compact"),            BuildFlagParam_None, Command_query);
 	add_flag(&build_flags, BuildFlag_Compact,           str_lit("compact"),            BuildFlagParam_None, Command_query);
 	add_flag(&build_flags, BuildFlag_GlobalDefinitions, str_lit("global-definitions"), BuildFlagParam_None, Command_query);
 	add_flag(&build_flags, BuildFlag_GlobalDefinitions, str_lit("global-definitions"), BuildFlagParam_None, Command_query);
 	add_flag(&build_flags, BuildFlag_GoToDefinitions,   str_lit("go-to-definitions"),  BuildFlagParam_None, Command_query);
 	add_flag(&build_flags, BuildFlag_GoToDefinitions,   str_lit("go-to-definitions"),  BuildFlagParam_None, Command_query);
 
 
+
 	add_flag(&build_flags, BuildFlag_Short,         str_lit("short"),        BuildFlagParam_None, Command_doc);
 	add_flag(&build_flags, BuildFlag_Short,         str_lit("short"),        BuildFlagParam_None, Command_doc);
 	add_flag(&build_flags, BuildFlag_AllPackages,   str_lit("all-packages"), BuildFlagParam_None, Command_doc);
 	add_flag(&build_flags, BuildFlag_AllPackages,   str_lit("all-packages"), BuildFlagParam_None, Command_doc);
 	add_flag(&build_flags, BuildFlag_DocFormat,     str_lit("doc-format"),   BuildFlagParam_None, Command_doc);
 	add_flag(&build_flags, BuildFlag_DocFormat,     str_lit("doc-format"),   BuildFlagParam_None, Command_doc);
@@ -1343,6 +1359,37 @@ bool parse_build_flags(Array<String> args) {
 							string_to_lower(&build_context.microarch);
 							string_to_lower(&build_context.microarch);
 							break;
 							break;
 						}
 						}
+						case BuildFlag_TargetFeatures: {
+							GB_ASSERT(value.kind == ExactValue_String);
+							build_context.target_features = value.value_string;
+							string_to_lower(&build_context.target_features);
+							break;
+						}
+						case BuildFlag_RelocMode: {
+							GB_ASSERT(value.kind == ExactValue_String);
+							String v = value.value_string;
+							if (v == "default") {
+								build_context.reloc_mode = RelocMode_Default;
+							} else if (v == "static") {
+								build_context.reloc_mode = RelocMode_Static;
+							} else if (v == "pic") {
+								build_context.reloc_mode = RelocMode_PIC;
+							} else if (v == "dynamic-no-pic") {
+								build_context.reloc_mode = RelocMode_DynamicNoPIC;
+							} else {
+								gb_printf_err("-reloc-mode flag expected one of the following\n");
+								gb_printf_err("\tdefault\n");
+								gb_printf_err("\tstatic\n");
+								gb_printf_err("\tpic\n");
+								gb_printf_err("\tdynamic-no-pic\n");
+								bad_flags = true;
+							}
+
+							break;
+						}
+						case BuildFlag_DisableRedZone:
+							build_context.disable_red_zone = true;
+							break;
 						case BuildFlag_TestName: {
 						case BuildFlag_TestName: {
 							GB_ASSERT(value.kind == ExactValue_String);
 							GB_ASSERT(value.kind == ExactValue_String);
 							{
 							{
@@ -1361,9 +1408,15 @@ bool parse_build_flags(Array<String> args) {
 						case BuildFlag_DisallowDo:
 						case BuildFlag_DisallowDo:
 							build_context.disallow_do = true;
 							build_context.disallow_do = true;
 							break;
 							break;
+						case BuildFlag_DisallowRTTI:
+							build_context.disallow_rtti = true;
+							break;
 						case BuildFlag_DefaultToNilAllocator:
 						case BuildFlag_DefaultToNilAllocator:
 							build_context.ODIN_DEFAULT_TO_NIL_ALLOCATOR = true;
 							build_context.ODIN_DEFAULT_TO_NIL_ALLOCATOR = true;
 							break;
 							break;
+						case BuildFlag_ForeignErrorProcedures:
+							build_context.ODIN_FOREIGN_ERROR_PROCEDURES = true;
+							break;
 						case BuildFlag_InsertSemicolon: {
 						case BuildFlag_InsertSemicolon: {
 							gb_printf_err("-insert-semicolon flag is not required any more\n");
 							gb_printf_err("-insert-semicolon flag is not required any more\n");
 							bad_flags = true;
 							bad_flags = true;
@@ -2062,6 +2115,18 @@ void print_show_help(String const arg0, String const &command) {
 		print_usage_line(3, "-microarch:sandybridge");
 		print_usage_line(3, "-microarch:sandybridge");
 		print_usage_line(3, "-microarch:native");
 		print_usage_line(3, "-microarch:native");
 		print_usage_line(0, "");
 		print_usage_line(0, "");
+
+		print_usage_line(1, "-reloc-mode:<string>");
+		print_usage_line(2, "Specifies the reloc mode");
+		print_usage_line(2, "Options:");
+		print_usage_line(3, "default");
+		print_usage_line(3, "static");
+		print_usage_line(3, "pic");
+		print_usage_line(3, "dynamic-no-pic");
+		print_usage_line(0, "");
+
+		print_usage_line(1, "-disable-red-zone");
+		print_usage_line(2, "Disable red zone on a supported freestanding target");
 	}
 	}
 
 
 	if (check) {
 	if (check) {
@@ -2092,6 +2157,11 @@ void print_show_help(String const arg0, String const &command) {
 		print_usage_line(1, "-verbose-errors");
 		print_usage_line(1, "-verbose-errors");
 		print_usage_line(2, "Prints verbose error messages showing the code on that line and the location in that line");
 		print_usage_line(2, "Prints verbose error messages showing the code on that line and the location in that line");
 		print_usage_line(0, "");
 		print_usage_line(0, "");
+
+		print_usage_line(1, "-foreign-error-procedures");
+		print_usage_line(2, "States that the error procedues used in the runtime are defined in a separate translation unit");
+		print_usage_line(0, "");
+
 	}
 	}
 
 
 	if (run_or_build) {
 	if (run_or_build) {

+ 0 - 8
src/string.cpp

@@ -10,10 +10,6 @@ struct String {
 	u8 *  text;
 	u8 *  text;
 	isize len;
 	isize len;
 
 
-	// u8 &operator[](isize i) {
-	// 	GB_ASSERT_MSG(0 <= i && i < len, "[%td]", i);
-	// 	return text[i];
-	// }
 	u8 const &operator[](isize i) const {
 	u8 const &operator[](isize i) const {
 		GB_ASSERT_MSG(0 <= i && i < len, "[%td]", i);
 		GB_ASSERT_MSG(0 <= i && i < len, "[%td]", i);
 		return text[i];
 		return text[i];
@@ -33,10 +29,6 @@ struct String {
 struct String16 {
 struct String16 {
 	wchar_t *text;
 	wchar_t *text;
 	isize    len;
 	isize    len;
-	wchar_t &operator[](isize i) {
-		GB_ASSERT_MSG(0 <= i && i < len, "[%td]", i);
-		return text[i];
-	}
 	wchar_t const &operator[](isize i) const {
 	wchar_t const &operator[](isize i) const {
 		GB_ASSERT_MSG(0 <= i && i < len, "[%td]", i);
 		GB_ASSERT_MSG(0 <= i && i < len, "[%td]", i);
 		return text[i];
 		return text[i];