aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJeroen van Rijn <Kelimion@users.noreply.github.com>2025-06-27 01:20:37 +0200
committerGitHub <noreply@github.com>2025-06-27 01:20:37 +0200
commit2e83e221419b480160dbf11dd09edf8b5fa97f32 (patch)
treebc5e666006bf43931bc793ac921061b5630db4d4 /src
parentc51df72f1a8a21dd0064086dfc1186a3dd79e2ef (diff)
parentf72b2b153057e1d629c85af2ea7c54f7928198d5 (diff)
Merge branch 'master' into args-leak
Diffstat (limited to 'src')
-rw-r--r--src/big_int.cpp5
-rw-r--r--src/bug_report.cpp15
-rw-r--r--src/build_settings.cpp514
-rw-r--r--src/build_settings_microarch.cpp559
-rw-r--r--src/bundle_command.cpp212
-rw-r--r--src/check_builtin.cpp470
-rw-r--r--src/check_decl.cpp245
-rw-r--r--src/check_expr.cpp825
-rw-r--r--src/check_stmt.cpp87
-rw-r--r--src/check_type.cpp84
-rw-r--r--src/checker.cpp408
-rw-r--r--src/checker.hpp54
-rw-r--r--src/checker_builtin_procs.hpp31
-rw-r--r--src/common.cpp4
-rw-r--r--src/docs_writer.cpp85
-rw-r--r--src/entity.cpp8
-rw-r--r--src/error.cpp2
-rw-r--r--src/exact_value.cpp4
-rw-r--r--src/gb/gb.h45
-rw-r--r--src/linker.cpp304
-rw-r--r--src/llvm-c/Analysis.h4
-rw-r--r--src/llvm-c/BitReader.h4
-rw-r--r--src/llvm-c/BitWriter.h4
-rw-r--r--src/llvm-c/Comdat.h4
-rw-r--r--src/llvm-c/Config/llvm-config.h6
-rw-r--r--src/llvm-c/Core.h536
-rw-r--r--src/llvm-c/DebugInfo.h149
-rw-r--r--src/llvm-c/Disassembler.h8
-rw-r--r--src/llvm-c/DisassemblerTypes.h2
-rw-r--r--src/llvm-c/Error.h10
-rw-r--r--src/llvm-c/ErrorHandling.h2
-rw-r--r--src/llvm-c/ExecutionEngine.h8
-rw-r--r--src/llvm-c/IRReader.h4
-rw-r--r--src/llvm-c/LLJIT.h8
-rw-r--r--src/llvm-c/LLJITUtils.h2
-rw-r--r--src/llvm-c/Linker.h4
-rw-r--r--src/llvm-c/Object.h6
-rw-r--r--src/llvm-c/Orc.h63
-rw-r--r--src/llvm-c/OrcEE.h10
-rw-r--r--src/llvm-c/Remarks.h4
-rw-r--r--src/llvm-c/Support.h6
-rw-r--r--src/llvm-c/Target.h32
-rw-r--r--src/llvm-c/TargetMachine.h6
-rw-r--r--src/llvm-c/Transforms/PassBuilder.h24
-rw-r--r--src/llvm-c/Types.h9
-rw-r--r--src/llvm-c/lto.h2
-rw-r--r--src/llvm_abi.cpp207
-rw-r--r--src/llvm_backend.cpp1892
-rw-r--r--src/llvm_backend.hpp67
-rw-r--r--src/llvm_backend_const.cpp366
-rw-r--r--src/llvm_backend_debug.cpp223
-rw-r--r--src/llvm_backend_expr.cpp117
-rw-r--r--src/llvm_backend_general.cpp535
-rw-r--r--src/llvm_backend_opt.cpp4
-rw-r--r--src/llvm_backend_passes.cpp1195
-rw-r--r--src/llvm_backend_proc.cpp347
-rw-r--r--src/llvm_backend_stmt.cpp248
-rw-r--r--src/llvm_backend_type.cpp83
-rw-r--r--src/llvm_backend_utility.cpp185
-rw-r--r--src/main.cpp563
-rw-r--r--src/name_canonicalization.cpp787
-rw-r--r--src/name_canonicalization.hpp128
-rw-r--r--src/parser.cpp262
-rw-r--r--src/path.cpp76
-rw-r--r--src/ptr_map.cpp6
-rw-r--r--src/ptr_set.cpp10
-rw-r--r--src/string.cpp86
-rw-r--r--src/threading.cpp6
-rw-r--r--src/timings.cpp4
-rw-r--r--src/tokenizer.cpp1
-rw-r--r--src/types.cpp476
71 files changed, 9692 insertions, 3060 deletions
diff --git a/src/big_int.cpp b/src/big_int.cpp
index 8e476f090..0b0a9a400 100644
--- a/src/big_int.cpp
+++ b/src/big_int.cpp
@@ -251,7 +251,10 @@ gb_internal void big_int_from_string(BigInt *dst, String const &s, bool *success
exp *= 10;
exp += v;
}
- big_int_exp_u64(dst, &b, exp, success);
+ BigInt tmp = {};
+ mp_init(&tmp);
+ big_int_exp_u64(&tmp, &b, exp, success);
+ big_int_mul_eq(dst, &tmp);
}
if (is_negative) {
diff --git a/src/bug_report.cpp b/src/bug_report.cpp
index ca5d0a395..98a376895 100644
--- a/src/bug_report.cpp
+++ b/src/bug_report.cpp
@@ -527,19 +527,20 @@ gb_internal void report_os_info() {
#elif defined(GB_SYSTEM_OSX)
gbString sw_vers = gb_string_make(heap_allocator(), "");
- if (!system_exec_command_line_app_output("sw_vers --productVersion", &sw_vers)) {
+ if (!system_exec_command_line_app_output("sw_vers -productVersion", &sw_vers)) {
gb_printf("macOS Unknown\n");
return;
}
- uint32_t major, minor, patch;
+ uint32_t major, minor, patch = 0;
- if (sscanf(cast(const char *)sw_vers, "%u.%u.%u", &major, &minor, &patch) != 3) {
+ if (sscanf(cast(const char *)sw_vers, "%u.%u.%u", &major, &minor, &patch) < 1) {
gb_printf("macOS Unknown\n");
return;
}
switch (major) {
+ case 26: gb_printf("macOS Tahoe"); break;
case 15: gb_printf("macOS Sequoia"); break;
case 14: gb_printf("macOS Sonoma"); break;
case 13: gb_printf("macOS Ventura"); break;
@@ -667,8 +668,14 @@ gb_internal void print_bug_report_help() {
gb_printf("-nightly");
#endif
+ String version = {};
+
#ifdef GIT_SHA
- gb_printf(":%s", GIT_SHA);
+ version.text = cast(u8 *)GIT_SHA;
+ version.len = gb_strlen(GIT_SHA);
+ if (version != "") {
+ gb_printf(":%.*s", LIT(version));
+ }
#endif
gb_printf("\n");
diff --git a/src/build_settings.cpp b/src/build_settings.cpp
index 93168cf77..ebe57bf1e 100644
--- a/src/build_settings.cpp
+++ b/src/build_settings.cpp
@@ -31,6 +31,24 @@ enum TargetOsKind : u16 {
TargetOs_COUNT,
};
+gb_global String target_os_names[TargetOs_COUNT] = {
+ str_lit(""),
+ str_lit("windows"),
+ str_lit("darwin"),
+ str_lit("linux"),
+ str_lit("essence"),
+ str_lit("freebsd"),
+ str_lit("openbsd"),
+ str_lit("netbsd"),
+ str_lit("haiku"),
+
+ str_lit("wasi"),
+ str_lit("js"),
+ str_lit("orca"),
+
+ str_lit("freestanding"),
+};
+
enum TargetArchKind : u16 {
TargetArch_Invalid,
@@ -45,6 +63,17 @@ enum TargetArchKind : u16 {
TargetArch_COUNT,
};
+gb_global String target_arch_names[TargetArch_COUNT] = {
+ str_lit(""),
+ str_lit("amd64"),
+ str_lit("i386"),
+ str_lit("arm32"),
+ str_lit("arm64"),
+ str_lit("wasm32"),
+ str_lit("wasm64p32"),
+ str_lit("riscv64"),
+};
+
enum TargetEndianKind : u8 {
TargetEndian_Little,
TargetEndian_Big,
@@ -52,6 +81,11 @@ enum TargetEndianKind : u8 {
TargetEndian_COUNT,
};
+gb_global String target_endian_names[TargetEndian_COUNT] = {
+ str_lit("little"),
+ str_lit("big"),
+};
+
enum TargetABIKind : u16 {
TargetABI_Default,
@@ -61,7 +95,14 @@ enum TargetABIKind : u16 {
TargetABI_COUNT,
};
+gb_global String target_abi_names[TargetABI_COUNT] = {
+ str_lit(""),
+ str_lit("win64"),
+ str_lit("sysv"),
+};
+
enum Windows_Subsystem : u8 {
+ Windows_Subsystem_UNKNOWN,
Windows_Subsystem_BOOT_APPLICATION,
Windows_Subsystem_CONSOLE, // Default,
Windows_Subsystem_EFI_APPLICATION,
@@ -75,53 +116,32 @@ enum Windows_Subsystem : u8 {
Windows_Subsystem_COUNT,
};
-struct MicroarchFeatureList {
- String microarch;
- String features;
-};
-
-gb_global String target_os_names[TargetOs_COUNT] = {
+gb_global String windows_subsystem_names[Windows_Subsystem_COUNT] = {
str_lit(""),
- str_lit("windows"),
- str_lit("darwin"),
- str_lit("linux"),
- str_lit("essence"),
- str_lit("freebsd"),
- str_lit("openbsd"),
- str_lit("netbsd"),
- str_lit("haiku"),
-
- str_lit("wasi"),
- str_lit("js"),
- str_lit("orca"),
-
- str_lit("freestanding"),
+ str_lit("BOOT_APPLICATION"),
+ str_lit("CONSOLE"), // Default
+ str_lit("EFI_APPLICATION"),
+ str_lit("EFI_BOOT_SERVICE_DRIVER"),
+ str_lit("EFI_ROM"),
+ str_lit("EFI_RUNTIME_DRIVER"),
+ str_lit("NATIVE"),
+ str_lit("POSIX"),
+ str_lit("WINDOWS"),
+ str_lit("WINDOWSCE"),
};
-gb_global String target_arch_names[TargetArch_COUNT] = {
- str_lit(""),
- str_lit("amd64"),
- str_lit("i386"),
- str_lit("arm32"),
- str_lit("arm64"),
- str_lit("wasm32"),
- str_lit("wasm64p32"),
- str_lit("riscv64"),
+struct MicroarchFeatureList {
+ String microarch;
+ String features;
};
+#if defined(GB_SYSTEM_WINDOWS)
+ #include <llvm-c/Config/llvm-config.h>
+#else
+ #include <llvm/Config/llvm-config.h>
+#endif
#include "build_settings_microarch.cpp"
-gb_global String target_endian_names[TargetEndian_COUNT] = {
- str_lit("little"),
- str_lit("big"),
-};
-
-gb_global String target_abi_names[TargetABI_COUNT] = {
- str_lit(""),
- str_lit("win64"),
- str_lit("sysv"),
-};
-
gb_global TargetEndianKind target_endians[TargetArch_COUNT] = {
TargetEndian_Little,
TargetEndian_Little,
@@ -132,19 +152,6 @@ gb_global TargetEndianKind target_endians[TargetArch_COUNT] = {
TargetEndian_Little,
};
-gb_global String windows_subsystem_names[Windows_Subsystem_COUNT] = {
- str_lit("BOOT_APPLICATION"),
- str_lit("CONSOLE"), // Default
- str_lit("EFI_APPLICATION"),
- str_lit("EFI_BOOT_SERVICE_DRIVER"),
- str_lit("EFI_ROM"),
- str_lit("EFI_RUNTIME_DRIVER"),
- str_lit("NATIVE"),
- str_lit("POSIX"),
- str_lit("WINDOWS"),
- str_lit("WINDOWSCE"),
-};
-
#ifndef ODIN_VERSION_RAW
#define ODIN_VERSION_RAW "dev-unknown-unknown"
#endif
@@ -165,6 +172,7 @@ struct TargetMetrics {
enum Subtarget : u32 {
Subtarget_Default,
Subtarget_iOS,
+ Subtarget_Android,
Subtarget_COUNT,
};
@@ -172,6 +180,7 @@ enum Subtarget : u32 {
gb_global String subtarget_strings[Subtarget_COUNT] = {
str_lit(""),
str_lit("ios"),
+ str_lit("android"),
};
@@ -198,20 +207,25 @@ enum BuildModeKind {
BuildMode_COUNT,
};
-enum CommandKind : u32 {
+enum CommandKind : u64 {
Command_run = 1<<0,
Command_build = 1<<1,
- Command_check = 1<<3,
- Command_doc = 1<<5,
- Command_version = 1<<6,
- Command_test = 1<<7,
+ Command_check = 1<<2,
+ Command_doc = 1<<3,
+ Command_version = 1<<4,
+ Command_test = 1<<5,
- Command_strip_semicolon = 1<<8,
- Command_bug_report = 1<<9,
+ Command_strip_semicolon = 1<<6,
+ Command_bug_report = 1<<7,
+
+ Command_bundle_android = 1<<8,
+ Command_bundle_macos = 1<<9,
+ Command_bundle_ios = 1<<10,
+ Command_bundle_orca = 1<<11,
Command__does_check = Command_run|Command_build|Command_check|Command_doc|Command_test|Command_strip_semicolon,
Command__does_build = Command_run|Command_build|Command_test,
- Command_all = ~(u32)0,
+ Command_all = ~(CommandKind)0,
};
gb_global char const *odin_command_strings[32] = {
@@ -222,6 +236,11 @@ gb_global char const *odin_command_strings[32] = {
"version",
"test",
"strip-semicolon",
+ "",
+ "bundle android",
+ "bundle macos",
+ "bundle ios",
+ "bundle orca",
};
@@ -269,7 +288,7 @@ enum BuildPath : u8 {
BuildPath_VS_LIB, // vs_library_path
BuildPath_Output, // Output Path for .exe, .dll, .so, etc. Can be overridden with `-out:`.
- BuildPath_PDB, // Output Path for .pdb file, can be overridden with `-pdb-name:`.
+ BuildPath_Symbols, // Output Path for .pdb or .dSym file, can be overridden with `-pdb-name:`.
BuildPathCOUNT,
};
@@ -366,6 +385,13 @@ enum LinkerChoice : i32 {
Linker_COUNT,
};
+enum SourceCodeLocationInfo : u8 {
+ SourceCodeLocationInfo_Normal = 0,
+ SourceCodeLocationInfo_Obfuscated = 1,
+ SourceCodeLocationInfo_Filename = 2,
+ SourceCodeLocationInfo_None = 3,
+};
+
String linker_choices[Linker_COUNT] = {
str_lit("default"),
str_lit("lld"),
@@ -375,17 +401,17 @@ String linker_choices[Linker_COUNT] = {
// This stores the information for the specify architecture of this build
struct BuildContext {
// Constants
- String ODIN_OS; // Target operating system
- String ODIN_ARCH; // Target architecture
- String ODIN_VENDOR; // Compiler vendor
- String ODIN_VERSION; // Compiler version
- String ODIN_ROOT; // Odin ROOT
- String ODIN_BUILD_PROJECT_NAME; // Odin main/initial package's directory name
- String ODIN_WINDOWS_SUBSYSTEM; // Empty string for non-Windows targets
- 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_DEFAULT_TO_NIL_ALLOCATOR; // Whether the default allocator is a "nil" allocator or not (i.e. it does nothing)
- bool ODIN_DEFAULT_TO_PANIC_ALLOCATOR; // Whether the default allocator is a "panic" allocator or not (i.e. panics on any call to it)
+ String ODIN_OS; // Target operating system
+ String ODIN_ARCH; // Target architecture
+ String ODIN_VENDOR; // Compiler vendor
+ String ODIN_VERSION; // Compiler version
+ String ODIN_ROOT; // Odin ROOT
+ String ODIN_BUILD_PROJECT_NAME; // Odin main/initial package's directory name
+ Windows_Subsystem ODIN_WINDOWS_SUBSYSTEM; // .Console, .Windows
+ 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_DEFAULT_TO_NIL_ALLOCATOR; // Whether the default allocator is a "nil" allocator or not (i.e. it does nothing)
+ bool ODIN_DEFAULT_TO_PANIC_ALLOCATOR; // Whether the default allocator is a "panic" allocator or not (i.e. panics on any call to it)
bool ODIN_FOREIGN_ERROR_PROCEDURES;
bool ODIN_VALGRIND_SUPPORT;
@@ -423,6 +449,7 @@ struct BuildContext {
String extra_assembler_flags;
String microarch;
BuildModeKind build_mode;
+ bool keep_executable;
bool generate_docs;
bool custom_optimization_level;
i32 optimization_level;
@@ -441,6 +468,7 @@ struct BuildContext {
bool ignore_unknown_attributes;
bool no_bounds_check;
bool no_type_assert;
+ bool dynamic_literals; // Opt-in to `#+feature dynamic-literals` project-wide.
bool no_output_files;
bool no_crt;
bool no_rpath;
@@ -472,6 +500,7 @@ struct BuildContext {
bool ignore_microsoft_magic;
bool linker_map_file;
+ bool use_single_module;
bool use_separate_modules;
bool module_per_file;
bool cached;
@@ -490,7 +519,7 @@ struct BuildContext {
bool dynamic_map_calls;
- bool obfuscate_source_code_locations;
+ SourceCodeLocationInfo source_code_location_info;
bool min_link_libs;
@@ -520,6 +549,21 @@ struct BuildContext {
String minimum_os_version_string;
bool minimum_os_version_string_given;
+
+
+ int ODIN_ANDROID_API_LEVEL;
+
+ String ODIN_ANDROID_SDK;
+
+ String ODIN_ANDROID_NDK;
+ String ODIN_ANDROID_NDK_TOOLCHAIN;
+ String ODIN_ANDROID_NDK_TOOLCHAIN_LIB;
+ String ODIN_ANDROID_NDK_TOOLCHAIN_LIB_LEVEL;
+ String ODIN_ANDROID_NDK_TOOLCHAIN_SYSROOT;
+
+ String android_keystore;
+ String android_keystore_alias;
+ String android_keystore_password;
};
gb_global BuildContext build_context = {0};
@@ -543,12 +587,6 @@ gb_internal isize MAX_ERROR_COLLECTOR_COUNT(void) {
return build_context.max_error_count;
}
-#if defined(GB_SYSTEM_WINDOWS)
- #include <llvm-c/Config/llvm-config.h>
-#else
- #include <llvm/Config/llvm-config.h>
-#endif
-
// NOTE: AMD64 targets had their alignment on 128 bit ints bumped from 8 to 16 (undocumented of course).
#if LLVM_VERSION_MAJOR >= 18
#define AMD64_MAX_ALIGNMENT 16
@@ -819,13 +857,39 @@ gb_global NamedTargetMetrics *selected_target_metrics;
gb_global Subtarget selected_subtarget;
-gb_internal TargetOsKind get_target_os_from_string(String str) {
+gb_internal TargetOsKind get_target_os_from_string(String str, Subtarget *subtarget_ = nullptr) {
+ String os_name = str;
+ String subtarget = {};
+ auto part = string_partition(str, str_lit(":"));
+ if (part.match.len == 1) {
+ os_name = part.head;
+ subtarget = part.tail;
+ }
+
+ TargetOsKind kind = TargetOs_Invalid;
+
for (isize i = 0; i < TargetOs_COUNT; i++) {
- if (str_eq_ignore_case(target_os_names[i], str)) {
- return cast(TargetOsKind)i;
+ if (str_eq_ignore_case(target_os_names[i], os_name)) {
+ kind = cast(TargetOsKind)i;
+ break;
+ }
+ }
+ if (subtarget_) *subtarget_ = Subtarget_Default;
+
+ if (subtarget.len != 0) {
+ if (str_eq_ignore_case(subtarget, "generic") || str_eq_ignore_case(subtarget, "default")) {
+ if (subtarget_) *subtarget_ = Subtarget_Default;
+ } else {
+ for (isize i = 1; i < Subtarget_COUNT; i++) {
+ if (str_eq_ignore_case(subtarget_strings[i], subtarget)) {
+ if (subtarget_) *subtarget_ = cast(Subtarget)i;
+ break;
+ }
+ }
}
}
- return TargetOs_Invalid;
+
+ return kind;
}
gb_internal TargetArchKind get_target_arch_from_string(String str) {
@@ -945,6 +1009,14 @@ gb_internal bool is_arch_x86(void) {
gb_global String const WIN32_SEPARATOR_STRING = {cast(u8 *)"\\", 1};
gb_global String const NIX_SEPARATOR_STRING = {cast(u8 *)"/", 1};
+gb_global String const SEPARATOR_STRING =
+#if defined(GB_SYSTEM_WINDOWS)
+ WIN32_SEPARATOR_STRING;
+#else
+ NIX_SEPARATOR_STRING;
+#endif
+
+
gb_global String const WASM_MODULE_NAME_SEPARATOR = str_lit("..");
gb_internal String internal_odin_root_dir(void);
@@ -1460,6 +1532,94 @@ gb_internal bool has_ansi_terminal_colours(void) {
return build_context.has_ansi_terminal_colours && !json_errors();
}
+gb_internal void init_android_values(bool with_sdk) {
+ auto *bc = &build_context;
+ { // Android SDK/API Level
+ String default_level = str_lit("34");
+ if (!bc->minimum_os_version_string_given) {
+ bc->minimum_os_version_string = default_level;
+ }
+ BigInt level = {};
+ bool success = false;
+ big_int_from_string(&level, bc->minimum_os_version_string, &success);
+ if (!success) {
+ gb_printf_err("Warning: Invalid -minimum-os-version:%.*s for -subtarget:Android, defaulting to %.*s\n", LIT(bc->minimum_os_version_string), LIT(default_level));
+ bc->minimum_os_version_string = default_level;
+ big_int_from_string(&level, bc->minimum_os_version_string, &success);
+ GB_ASSERT(success);
+ }
+
+ i64 new_level = big_int_to_i64(&level);
+
+ if (new_level >= 21) {
+ bc->ODIN_ANDROID_API_LEVEL = cast(int)new_level;
+ } else {
+ gb_printf_err("Warning: Invalid -minimum-os-version:%.*s for -subtarget:Android, defaulting to %.*s\n", LIT(bc->minimum_os_version_string), LIT(default_level));
+ bc->ODIN_ANDROID_API_LEVEL = atoi(cast(char const *)default_level.text);
+ }
+ }
+ bc->ODIN_ANDROID_NDK = normalize_path(permanent_allocator(), make_string_c(gb_get_env("ODIN_ANDROID_NDK", permanent_allocator())), NIX_SEPARATOR_STRING);
+ bc->ODIN_ANDROID_NDK_TOOLCHAIN = normalize_path(permanent_allocator(), make_string_c(gb_get_env("ODIN_ANDROID_NDK_TOOLCHAIN", permanent_allocator())), NIX_SEPARATOR_STRING);
+ bc->ODIN_ANDROID_SDK = normalize_path(permanent_allocator(), make_string_c(gb_get_env("ODIN_ANDROID_SDK", permanent_allocator())), NIX_SEPARATOR_STRING);
+
+ #if defined(GB_SYSTEM_WINDOWS)
+ if (bc->ODIN_ANDROID_SDK.len == 0) {
+ bc->ODIN_ANDROID_SDK = normalize_path(permanent_allocator(),
+ path_to_fullpath(permanent_allocator(), str_lit("%LocalAppData%/Android/Sdk"), nullptr),
+ NIX_SEPARATOR_STRING);
+ }
+ #endif
+
+ if (bc->ODIN_ANDROID_NDK.len != 0 && bc->ODIN_ANDROID_NDK_TOOLCHAIN.len == 0) {
+ String arch = str_lit("x86_64");
+ #if defined (GB_CPU_ARM)
+ // TODO(bill): this is a complete guess
+ arch = str_lit("aarch64");
+ #endif
+ #if defined(GB_SYSTEM_WINDOWS)
+ bc->ODIN_ANDROID_NDK_TOOLCHAIN = concatenate4_strings(temporary_allocator(), bc->ODIN_ANDROID_NDK, str_lit("toolchains/llvm/prebuilt/"), str_lit("windows-"), arch);
+ #elif defined(GB_SYSTEM_OSX)
+ // TODO(bill): is this name even correct?
+ bc->ODIN_ANDROID_NDK_TOOLCHAIN = concatenate4_strings(temporary_allocator(), bc->ODIN_ANDROID_NDK, str_lit("toolchains/llvm/prebuilt/"), str_lit("darwin-"), arch);
+ #elif defined(GB_SYSTEM_LINUX)
+ bc->ODIN_ANDROID_NDK_TOOLCHAIN = concatenate4_strings(temporary_allocator(), bc->ODIN_ANDROID_NDK, str_lit("toolchains/llvm/prebuilt/"), str_lit("linux-"), arch);
+ #endif
+
+ bc->ODIN_ANDROID_NDK_TOOLCHAIN = normalize_path(permanent_allocator(), bc->ODIN_ANDROID_NDK_TOOLCHAIN, NIX_SEPARATOR_STRING);
+ }
+
+ if (bc->ODIN_ANDROID_NDK.len == 0 && !with_sdk) {
+ gb_printf_err("Error: ODIN_ANDROID_NDK not set");
+ gb_exit(1);
+
+ }
+
+ if (bc->ODIN_ANDROID_NDK_TOOLCHAIN.len == 0 && !with_sdk) {
+ gb_printf_err("Error: ODIN_ANDROID_NDK not set");
+ gb_exit(1);
+ }
+
+ bc->ODIN_ANDROID_NDK_TOOLCHAIN_LIB = concatenate_strings(permanent_allocator(), bc->ODIN_ANDROID_NDK_TOOLCHAIN, str_lit("sysroot/usr/lib/aarch64-linux-android/"));
+
+ char buf[32] = {};
+ gb_snprintf(buf, gb_size_of(buf), "%d/", bc->ODIN_ANDROID_API_LEVEL);
+ bc->ODIN_ANDROID_NDK_TOOLCHAIN_LIB_LEVEL = concatenate_strings(permanent_allocator(), bc->ODIN_ANDROID_NDK_TOOLCHAIN_LIB, make_string_c(buf));
+
+ bc->ODIN_ANDROID_NDK_TOOLCHAIN_SYSROOT = concatenate_strings(permanent_allocator(), bc->ODIN_ANDROID_NDK_TOOLCHAIN, str_lit("sysroot/"));
+
+
+ if (with_sdk) {
+ if (bc->ODIN_ANDROID_SDK.len == 0) {
+ gb_printf_err("Error: ODIN_ANDROID_SDK not set, which is required for -build-mode:executable for -subtarget:android");
+ gb_exit(1);
+ }
+ if (bc->android_keystore.len == 0) {
+ gb_printf_err("Error: -android-keystore:<string> has not been set\n");
+ gb_exit(1);
+ }
+ }
+}
+
gb_internal bool has_asm_extension(String const &path) {
String ext = path_extension(path);
if (ext == ".asm") {
@@ -1636,8 +1796,32 @@ gb_internal void init_build_context(TargetMetrics *cross_target, Subtarget subta
}
// Default to subsystem:CONSOLE on Windows targets
- if (bc->ODIN_WINDOWS_SUBSYSTEM == "" && bc->metrics.os == TargetOs_windows) {
- bc->ODIN_WINDOWS_SUBSYSTEM = windows_subsystem_names[Windows_Subsystem_CONSOLE];
+ if (bc->ODIN_WINDOWS_SUBSYSTEM == Windows_Subsystem_UNKNOWN && bc->metrics.os == TargetOs_windows) {
+ bc->ODIN_WINDOWS_SUBSYSTEM = Windows_Subsystem_CONSOLE;
+ }
+
+ if (subtarget == Subtarget_Android) {
+ switch (build_context.build_mode) {
+ case BuildMode_DynamicLibrary:
+ case BuildMode_Object:
+ case BuildMode_Assembly:
+ case BuildMode_LLVM_IR:
+ break;
+ default:
+ case BuildMode_Executable:
+ case BuildMode_StaticLibrary:
+ if ((build_context.command_kind & Command__does_build) != 0) {
+ gb_printf_err("Unsupported -build-mode for -subtarget:android\n");
+ gb_printf_err("\tCurrently only supporting: \n");
+ // gb_printf_err("\t\texe\n");
+ gb_printf_err("\t\tshared\n");
+ gb_printf_err("\t\tobject\n");
+ gb_printf_err("\t\tassembly\n");
+ gb_printf_err("\t\tllvm-ir\n");
+ gb_exit(1);
+ }
+ break;
+ }
}
if (metrics->os == TargetOs_darwin && subtarget == Subtarget_iOS) {
@@ -1651,6 +1835,15 @@ gb_internal void init_build_context(TargetMetrics *cross_target, Subtarget subta
default:
GB_PANIC("Unknown architecture for darwin");
}
+ } else if (metrics->os == TargetOs_linux && subtarget == Subtarget_Android) {
+ switch (metrics->arch) {
+ case TargetArch_arm64:
+ bc->metrics.target_triplet = str_lit("aarch64-none-linux-android");
+ bc->reloc_mode = RelocMode_PIC;
+ break;
+ default:
+ GB_PANIC("Unknown architecture for -subtarget:android");
+ }
}
if (bc->metrics.os == TargetOs_windows) {
@@ -1705,6 +1898,8 @@ gb_internal void init_build_context(TargetMetrics *cross_target, Subtarget subta
if (subtarget == Subtarget_Default) {
bc->metrics.target_triplet = concatenate_strings(permanent_allocator(), bc->metrics.target_triplet, bc->minimum_os_version_string);
}
+ } else if (selected_subtarget == Subtarget_Android) {
+ init_android_values(bc->build_mode == BuildMode_Executable && (bc->command_kind & Command__does_build) != 0);
}
if (!bc->custom_optimization_level) {
@@ -1719,21 +1914,17 @@ gb_internal void init_build_context(TargetMetrics *cross_target, Subtarget subta
bc->optimization_level = gb_clamp(bc->optimization_level, -1, 3);
-#if defined(GB_SYSTEM_WINDOWS)
if (bc->optimization_level <= 0) {
if (!is_arch_wasm()) {
bc->use_separate_modules = true;
}
}
-#endif
-
- // TODO: Static map calls are bugged on `amd64sysv` abi.
- if (bc->metrics.os != TargetOs_windows && bc->metrics.arch == TargetArch_amd64) {
- // ENFORCE DYNAMIC MAP CALLS
- bc->dynamic_map_calls = true;
+ if (build_context.use_single_module) {
+ bc->use_separate_modules = false;
}
+
bc->ODIN_VALGRIND_SUPPORT = false;
if (build_context.metrics.os != TargetOs_windows) {
switch (bc->metrics.arch) {
@@ -1839,6 +2030,39 @@ gb_internal bool check_target_feature_is_superset_of(String const &superset, Str
return true;
}
+gb_internal String infer_object_extension_from_build_context() {
+ String output_extension = {};
+ if (is_arch_wasm()) {
+ output_extension = STR_LIT("wasm.o");
+ } else {
+ switch (build_context.metrics.os) {
+ case TargetOs_windows:
+ output_extension = STR_LIT("obj");
+ break;
+ default:
+ case TargetOs_darwin:
+ case TargetOs_linux:
+ case TargetOs_essence:
+ output_extension = STR_LIT("o");
+ break;
+
+ case TargetOs_freestanding:
+ switch (build_context.metrics.abi) {
+ default:
+ case TargetABI_Default:
+ case TargetABI_SysV:
+ output_extension = STR_LIT("o");
+ break;
+ case TargetABI_Win64:
+ output_extension = STR_LIT("obj");
+ break;
+ }
+ break;
+ }
+ }
+ return output_extension;
+}
+
// NOTE(Jeroen): Set/create the output and other paths and report an error as appropriate.
// We've previously called `parse_build_flags`, so `out_filepath` should be set.
gb_internal bool init_build_paths(String init_filename) {
@@ -1882,10 +2106,6 @@ gb_internal bool init_build_paths(String init_filename) {
}
}
- if (bc->pdb_filepath.len > 0) {
- bc->build_paths[BuildPath_PDB] = path_from_string(ha, bc->pdb_filepath);
- }
-
if ((bc->command_kind & Command__does_build) && (!bc->ignore_microsoft_magic)) {
// 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 find_result = find_visual_studio_and_windows_sdk();
@@ -1944,7 +2164,10 @@ gb_internal bool init_build_paths(String init_filename) {
output_extension = make_string(nullptr, 0);
String const single_file_extension = str_lit(".odin");
- if (build_context.metrics.os == TargetOs_windows) {
+ if (selected_subtarget == Subtarget_Android) {
+ // NOTE(bill): It's always shared!
+ output_extension = STR_LIT("so");
+ } else if (build_context.metrics.os == TargetOs_windows) {
output_extension = STR_LIT("exe");
} else if (build_context.cross_compiling && selected_target_metrics->metrics == &target_essence_amd64) {
// Do nothing: we don't want the .bin extension
@@ -1972,13 +2195,8 @@ gb_internal bool init_build_paths(String init_filename) {
if (build_context.metrics.os == TargetOs_windows) {
output_extension = STR_LIT("lib");
}
- }else if (build_context.build_mode == BuildMode_Object) {
- // By default use a .o object extension.
- output_extension = STR_LIT("o");
-
- if (build_context.metrics.os == TargetOs_windows) {
- output_extension = STR_LIT("obj");
- }
+ } else if (build_context.build_mode == BuildMode_Object) {
+ output_extension = infer_object_extension_from_build_context();
} else if (build_context.build_mode == BuildMode_Assembly) {
// By default use a .S asm extension.
output_extension = STR_LIT("S");
@@ -1998,7 +2216,7 @@ gb_internal bool init_build_paths(String init_filename) {
return false;
} else if (bc->build_paths[BuildPath_Output].ext.len == 0) {
gb_printf_err("Output path %.*s must have an appropriate extension.\n", LIT(output_file));
- return false;
+ return false;
}
}
} else {
@@ -2024,11 +2242,34 @@ gb_internal bool init_build_paths(String init_filename) {
while (output_name.len > 0 && (output_name[output_name.len-1] == '/' || output_name[output_name.len-1] == '\\')) {
output_name.len -= 1;
}
+ // Only trim the extension if it's an Odin source file.
+ // This lets people build folders with extensions or files beginning with dots.
+ if (path_extension(output_name) == ".odin" && !path_is_directory(output_name)) {
+ output_name = remove_extension_from_path(output_name);
+ }
output_name = remove_directory_from_path(output_name);
- output_name = remove_extension_from_path(output_name);
output_name = copy_string(ha, string_trim_whitespace(output_name));
- output_path = path_from_string(ha, output_name);
-
+ // This is `path_from_string` without the extension trimming.
+ Path res = {};
+ if (output_name.len > 0) {
+ String fullpath = path_to_full_path(ha, output_name);
+ defer (gb_free(ha, fullpath.text));
+
+ res.basename = directory_from_path(fullpath);
+ res.basename = copy_string(ha, res.basename);
+
+ if (path_is_directory(fullpath)) {
+ if (res.basename.len > 0 && res.basename.text[res.basename.len - 1] == '/') {
+ res.basename.len--;
+ }
+ } else {
+ isize name_start = (res.basename.len > 0) ? res.basename.len + 1 : res.basename.len;
+ res.name = substring(fullpath, name_start, fullpath.len);
+ res.name = copy_string(ha, res.name);
+ }
+ }
+ output_path = res;
+
// Note(Dragos): This is a fix for empty filenames
// Turn the trailing folder into the file name
if (output_path.name.len == 0) {
@@ -2058,6 +2299,26 @@ gb_internal bool init_build_paths(String init_filename) {
bc->build_paths[BuildPath_Output] = output_path;
}
+ if (build_context.ODIN_DEBUG) {
+ if (build_context.metrics.os == TargetOs_windows) {
+ if (bc->pdb_filepath.len > 0) {
+ bc->build_paths[BuildPath_Symbols] = path_from_string(ha, bc->pdb_filepath);
+ } else {
+ Path symbol_path;
+ symbol_path.basename = copy_string(ha, bc->build_paths[BuildPath_Output].basename);
+ symbol_path.name = copy_string(ha, bc->build_paths[BuildPath_Output].name);
+ symbol_path.ext = copy_string(ha, STR_LIT("pdb"));
+ bc->build_paths[BuildPath_Symbols] = symbol_path;
+ }
+ } else if (build_context.metrics.os == TargetOs_darwin) {
+ Path symbol_path;
+ symbol_path.basename = copy_string(ha, bc->build_paths[BuildPath_Output].basename);
+ symbol_path.name = copy_string(ha, bc->build_paths[BuildPath_Output].name);
+ symbol_path.ext = copy_string(ha, STR_LIT("dSYM"));
+ bc->build_paths[BuildPath_Symbols] = symbol_path;
+ }
+ }
+
// Do we have an extension? We might not if the output filename was supplied.
if (bc->build_paths[BuildPath_Output].ext.len == 0) {
if (build_context.metrics.os == TargetOs_windows || is_arch_wasm() || build_context.build_mode != BuildMode_Executable) {
@@ -2093,9 +2354,10 @@ gb_internal bool init_build_paths(String init_filename) {
case TargetOs_windows:
case TargetOs_linux:
case TargetOs_darwin:
+ case TargetOs_freebsd:
break;
default:
- gb_printf_err("-sanitize:address is only supported on windows, linux, and darwin\n");
+ gb_printf_err("-sanitize:address is only supported on Windows, Linux, Darwin, and FreeBSD\n");
return false;
}
}
@@ -2103,12 +2365,10 @@ gb_internal bool init_build_paths(String init_filename) {
if (build_context.sanitizer_flags & SanitizerFlag_Memory) {
switch (build_context.metrics.os) {
case TargetOs_linux:
+ case TargetOs_freebsd:
break;
default:
- gb_printf_err("-sanitize:memory is only supported on linux\n");
- return false;
- }
- if (build_context.metrics.os != TargetOs_linux) {
+ gb_printf_err("-sanitize:memory is only supported on Linux and FreeBSD\n");
return false;
}
}
@@ -2117,13 +2377,15 @@ gb_internal bool init_build_paths(String init_filename) {
switch (build_context.metrics.os) {
case TargetOs_linux:
case TargetOs_darwin:
+ case TargetOs_freebsd:
break;
default:
- gb_printf_err("-sanitize:thread is only supported on linux and darwin\n");
+ gb_printf_err("-sanitize:thread is only supported on Linux, Darwin, and FreeBSD\n");
return false;
}
}
+ bool no_crt_checks_failed = false;
if (build_context.no_crt && !build_context.ODIN_DEFAULT_TO_NIL_ALLOCATOR && !build_context.ODIN_DEFAULT_TO_PANIC_ALLOCATOR) {
switch (build_context.metrics.os) {
case TargetOs_linux:
@@ -2133,11 +2395,29 @@ gb_internal bool init_build_paths(String init_filename) {
case TargetOs_openbsd:
case TargetOs_netbsd:
case TargetOs_haiku:
- gb_printf_err("-no-crt on unix systems requires either -default-to-nil-allocator or -default-to-panic-allocator to also be present because the default allocator requires crt\n");
- return false;
+ gb_printf_err("-no-crt on Unix systems requires either -default-to-nil-allocator or -default-to-panic-allocator to also be present, because the default allocator requires CRT\n");
+ no_crt_checks_failed = true;
}
}
+ if (build_context.no_crt && !build_context.no_thread_local) {
+ switch (build_context.metrics.os) {
+ case TargetOs_linux:
+ case TargetOs_darwin:
+ case TargetOs_essence:
+ case TargetOs_freebsd:
+ case TargetOs_openbsd:
+ case TargetOs_netbsd:
+ case TargetOs_haiku:
+ gb_printf_err("-no-crt on Unix systems requires the -no-thread-local flag to also be present, because the TLS is inaccessible without CRT\n");
+ no_crt_checks_failed = true;
+ }
+ }
+
+ if (no_crt_checks_failed) {
+ return false;
+ }
+
return true;
}
diff --git a/src/build_settings_microarch.cpp b/src/build_settings_microarch.cpp
index 8f64d4026..16fb2196f 100644
--- a/src/build_settings_microarch.cpp
+++ b/src/build_settings_microarch.cpp
@@ -1,3 +1,561 @@
+#ifndef LLVM_VERSION_MAJOR
+ #error "LLVM_VERSION_MAJOR is not defined!"
+#endif
+
+#if LLVM_VERSION_MAJOR >= 20
+// Generated with the featuregen script in `misc/featuregen`
+gb_global String target_microarch_list[TargetArch_COUNT] = {
+ // TargetArch_Invalid:
+ str_lit(""),
+ // TargetArch_amd64:
+ str_lit("alderlake,amdfam10,arrowlake,arrowlake-s,arrowlake_s,athlon,athlon-4,athlon-fx,athlon-mp,athlon-tbird,athlon-xp,athlon64,athlon64-sse3,atom,atom_sse4_2,atom_sse4_2_movbe,barcelona,bdver1,bdver2,bdver3,bdver4,bonnell,broadwell,btver1,btver2,c3,c3-2,cannonlake,cascadelake,clearwaterforest,cooperlake,core-avx-i,core-avx2,core2,core_2_duo_sse4_1,core_2_duo_ssse3,core_2nd_gen_avx,core_3rd_gen_avx,core_4th_gen_avx,core_4th_gen_avx_tsx,core_5th_gen_avx,core_5th_gen_avx_tsx,core_aes_pclmulqdq,core_i7_sse4_2,corei7,corei7-avx,diamondrapids,emeraldrapids,generic,geode,goldmont,goldmont-plus,goldmont_plus,gracemont,grandridge,graniterapids,graniterapids-d,graniterapids_d,haswell,i386,i486,i586,i686,icelake-client,icelake-server,icelake_client,icelake_server,ivybridge,k6,k6-2,k6-3,k8,k8-sse3,knl,knm,lakemont,lunarlake,meteorlake,mic_avx512,nehalem,nocona,opteron,opteron-sse3,pantherlake,penryn,pentium,pentium-m,pentium-mmx,pentium2,pentium3,pentium3m,pentium4,pentium4m,pentium_4,pentium_4_sse3,pentium_ii,pentium_iii,pentium_iii_no_xmm_regs,pentium_m,pentium_mmx,pentium_pro,pentiumpro,prescott,raptorlake,rocketlake,sandybridge,sapphirerapids,sierraforest,silvermont,skx,skylake,skylake-avx512,skylake_avx512,slm,tigerlake,tremont,westmere,winchip-c6,winchip2,x86-64,x86-64-v2,x86-64-v3,x86-64-v4,yonah,znver1,znver2,znver3,znver4,znver5"),
+ // TargetArch_i386:
+ str_lit("alderlake,amdfam10,arrowlake,arrowlake-s,arrowlake_s,athlon,athlon-4,athlon-fx,athlon-mp,athlon-tbird,athlon-xp,athlon64,athlon64-sse3,atom,atom_sse4_2,atom_sse4_2_movbe,barcelona,bdver1,bdver2,bdver3,bdver4,bonnell,broadwell,btver1,btver2,c3,c3-2,cannonlake,cascadelake,clearwaterforest,cooperlake,core-avx-i,core-avx2,core2,core_2_duo_sse4_1,core_2_duo_ssse3,core_2nd_gen_avx,core_3rd_gen_avx,core_4th_gen_avx,core_4th_gen_avx_tsx,core_5th_gen_avx,core_5th_gen_avx_tsx,core_aes_pclmulqdq,core_i7_sse4_2,corei7,corei7-avx,diamondrapids,emeraldrapids,generic,geode,goldmont,goldmont-plus,goldmont_plus,gracemont,grandridge,graniterapids,graniterapids-d,graniterapids_d,haswell,i386,i486,i586,i686,icelake-client,icelake-server,icelake_client,icelake_server,ivybridge,k6,k6-2,k6-3,k8,k8-sse3,knl,knm,lakemont,lunarlake,meteorlake,mic_avx512,nehalem,nocona,opteron,opteron-sse3,pantherlake,penryn,pentium,pentium-m,pentium-mmx,pentium2,pentium3,pentium3m,pentium4,pentium4m,pentium_4,pentium_4_sse3,pentium_ii,pentium_iii,pentium_iii_no_xmm_regs,pentium_m,pentium_mmx,pentium_pro,pentiumpro,prescott,raptorlake,rocketlake,sandybridge,sapphirerapids,sierraforest,silvermont,skx,skylake,skylake-avx512,skylake_avx512,slm,tigerlake,tremont,westmere,winchip-c6,winchip2,x86-64,x86-64-v2,x86-64-v3,x86-64-v4,yonah,znver1,znver2,znver3,znver4,znver5"),
+ // TargetArch_arm32:
+ str_lit("arm1020e,arm1020t,arm1022e,arm10e,arm10tdmi,arm1136j-s,arm1136jf-s,arm1156t2-s,arm1156t2f-s,arm1176jz-s,arm1176jzf-s,arm710t,arm720t,arm7tdmi,arm7tdmi-s,arm8,arm810,arm9,arm920,arm920t,arm922t,arm926ej-s,arm940t,arm946e-s,arm966e-s,arm968e-s,arm9e,arm9tdmi,cortex-a12,cortex-a15,cortex-a17,cortex-a32,cortex-a35,cortex-a5,cortex-a510,cortex-a53,cortex-a55,cortex-a57,cortex-a7,cortex-a710,cortex-a72,cortex-a73,cortex-a75,cortex-a76,cortex-a76ae,cortex-a77,cortex-a78,cortex-a78ae,cortex-a78c,cortex-a8,cortex-a9,cortex-m0,cortex-m0plus,cortex-m1,cortex-m23,cortex-m3,cortex-m33,cortex-m35p,cortex-m4,cortex-m52,cortex-m55,cortex-m7,cortex-m85,cortex-r4,cortex-r4f,cortex-r5,cortex-r52,cortex-r52plus,cortex-r7,cortex-r8,cortex-x1,cortex-x1c,cyclone,ep9312,exynos-m3,exynos-m4,exynos-m5,generic,iwmmxt,krait,kryo,mpcore,mpcorenovfp,neoverse-n1,neoverse-n2,neoverse-v1,sc000,sc300,star-mc1,strongarm,strongarm110,strongarm1100,strongarm1110,swift,xscale"),
+ // TargetArch_arm64:
+ str_lit("a64fx,ampere1,ampere1a,ampere1b,apple-a10,apple-a11,apple-a12,apple-a13,apple-a14,apple-a15,apple-a16,apple-a17,apple-a7,apple-a8,apple-a9,apple-m1,apple-m2,apple-m3,apple-m4,apple-s4,apple-s5,carmel,cobalt-100,cortex-a34,cortex-a35,cortex-a510,cortex-a520,cortex-a520ae,cortex-a53,cortex-a55,cortex-a57,cortex-a65,cortex-a65ae,cortex-a710,cortex-a715,cortex-a72,cortex-a720,cortex-a720ae,cortex-a725,cortex-a73,cortex-a75,cortex-a76,cortex-a76ae,cortex-a77,cortex-a78,cortex-a78ae,cortex-a78c,cortex-r82,cortex-r82ae,cortex-x1,cortex-x1c,cortex-x2,cortex-x3,cortex-x4,cortex-x925,cyclone,exynos-m3,exynos-m4,exynos-m5,falkor,fujitsu-monaka,generic,grace,kryo,neoverse-512tvb,neoverse-e1,neoverse-n1,neoverse-n2,neoverse-n3,neoverse-v1,neoverse-v2,neoverse-v3,neoverse-v3ae,oryon-1,saphira,thunderx,thunderx2t99,thunderx3t110,thunderxt81,thunderxt83,thunderxt88,tsv110"),
+ // TargetArch_wasm32:
+ str_lit("bleeding-edge,generic,lime1,mvp"),
+ // TargetArch_wasm64p32:
+ str_lit("bleeding-edge,generic,lime1,mvp"),
+ // TargetArch_riscv64:
+ str_lit("generic,generic-rv32,generic-rv64,mips-p8700,rocket,rocket-rv32,rocket-rv64,rp2350-hazard3,sifive-7-series,sifive-e20,sifive-e21,sifive-e24,sifive-e31,sifive-e34,sifive-e76,sifive-p450,sifive-p470,sifive-p550,sifive-p670,sifive-s21,sifive-s51,sifive-s54,sifive-s76,sifive-u54,sifive-u74,sifive-x280,spacemit-x60,syntacore-scr1-base,syntacore-scr1-max,syntacore-scr3-rv32,syntacore-scr3-rv64,syntacore-scr4-rv32,syntacore-scr4-rv64,syntacore-scr5-rv32,syntacore-scr5-rv64,syntacore-scr7,tt-ascalon-d8,veyron-v1,xiangshan-nanhu"),
+};
+
+// Generated with the featuregen script in `misc/featuregen`
+gb_global String target_features_list[TargetArch_COUNT] = {
+ // TargetArch_Invalid:
+ str_lit(""),
+ // TargetArch_amd64:
+ str_lit("16bit-mode,32bit-mode,64bit,64bit-mode,adx,aes,allow-light-256-bit,amx-avx512,amx-bf16,amx-complex,amx-fp16,amx-fp8,amx-int8,amx-movrs,amx-tf32,amx-tile,amx-transpose,avx,avx10.1-256,avx10.1-512,avx10.2-256,avx10.2-512,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vp2intersect,avx512vpopcntdq,avxifma,avxneconvert,avxvnni,avxvnniint16,avxvnniint8,bmi,bmi2,branch-hint,branchfusion,ccmp,cf,cldemote,clflushopt,clwb,clzero,cmov,cmpccxadd,crc32,cx16,cx8,egpr,enqcmd,ermsb,evex512,f16c,false-deps-getmant,false-deps-lzcnt-tzcnt,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-popcnt,false-deps-range,fast-11bytenop,fast-15bytenop,fast-7bytenop,fast-bextr,fast-dpwssd,fast-gather,fast-hops,fast-imm16,fast-lzcnt,fast-movbe,fast-scalar-fsqrt,fast-scalar-shift-masks,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fast-vector-shift-masks,faster-shift-than-shuffle,fma,fma4,fsgsbase,fsrm,fxsr,gfni,harden-sls-ijmp,harden-sls-ret,hreset,idivl-to-divb,idivq-to-divl,inline-asm-use-gpr32,invpcid,kl,lea-sp,lea-uses-ag,lvi-cfi,lvi-load-hardening,lwp,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,movrs,mwaitx,ndd,nf,no-bypass-delay,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pad-short-functions,pclmul,pconfig,pku,popcnt,ppx,prefer-128-bit,prefer-256-bit,prefer-mask-registers,prefer-movmsk-over-vtest,prefer-no-gather,prefer-no-scatter,prefetchi,prfchw,ptwrite,push2pop2,raoint,rdpid,rdpru,rdrnd,rdseed,retpoline,retpoline-external-thunk,retpoline-indirect-branches,retpoline-indirect-calls,rtm,sahf,sbb-dep-breaking,serialize,seses,sgx,sha,sha512,shstk,slow-3ops-lea,slow-incdec,slow-lea,slow-pmaddwd,slow-pmulld,slow-shld,slow-two-mem-ops,slow-unaligned-mem-16,slow-unaligned-mem-32,sm3,sm4,soft-float,sse,sse-unaligned-mem,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,tagged-globals,tbm,tsxldtrk,tuning-fast-imm-vector-shift,uintr,use-glm-div-sqrt-costs,use-slm-arith-costs,usermsr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,widekl,x87,xop,xsave,xsavec,xsaveopt,xsaves,zu"),
+ // TargetArch_i386:
+ str_lit("16bit-mode,32bit-mode,64bit,64bit-mode,adx,aes,allow-light-256-bit,amx-avx512,amx-bf16,amx-complex,amx-fp16,amx-fp8,amx-int8,amx-movrs,amx-tf32,amx-tile,amx-transpose,avx,avx10.1-256,avx10.1-512,avx10.2-256,avx10.2-512,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vp2intersect,avx512vpopcntdq,avxifma,avxneconvert,avxvnni,avxvnniint16,avxvnniint8,bmi,bmi2,branch-hint,branchfusion,ccmp,cf,cldemote,clflushopt,clwb,clzero,cmov,cmpccxadd,crc32,cx16,cx8,egpr,enqcmd,ermsb,evex512,f16c,false-deps-getmant,false-deps-lzcnt-tzcnt,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-popcnt,false-deps-range,fast-11bytenop,fast-15bytenop,fast-7bytenop,fast-bextr,fast-dpwssd,fast-gather,fast-hops,fast-imm16,fast-lzcnt,fast-movbe,fast-scalar-fsqrt,fast-scalar-shift-masks,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fast-vector-shift-masks,faster-shift-than-shuffle,fma,fma4,fsgsbase,fsrm,fxsr,gfni,harden-sls-ijmp,harden-sls-ret,hreset,idivl-to-divb,idivq-to-divl,inline-asm-use-gpr32,invpcid,kl,lea-sp,lea-uses-ag,lvi-cfi,lvi-load-hardening,lwp,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,movrs,mwaitx,ndd,nf,no-bypass-delay,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pad-short-functions,pclmul,pconfig,pku,popcnt,ppx,prefer-128-bit,prefer-256-bit,prefer-mask-registers,prefer-movmsk-over-vtest,prefer-no-gather,prefer-no-scatter,prefetchi,prfchw,ptwrite,push2pop2,raoint,rdpid,rdpru,rdrnd,rdseed,retpoline,retpoline-external-thunk,retpoline-indirect-branches,retpoline-indirect-calls,rtm,sahf,sbb-dep-breaking,serialize,seses,sgx,sha,sha512,shstk,slow-3ops-lea,slow-incdec,slow-lea,slow-pmaddwd,slow-pmulld,slow-shld,slow-two-mem-ops,slow-unaligned-mem-16,slow-unaligned-mem-32,sm3,sm4,soft-float,sse,sse-unaligned-mem,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,tagged-globals,tbm,tsxldtrk,tuning-fast-imm-vector-shift,uintr,use-glm-div-sqrt-costs,use-slm-arith-costs,usermsr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,widekl,x87,xop,xsave,xsavec,xsaveopt,xsaves,zu"),
+ // TargetArch_arm32:
+ str_lit("32bit,8msecext,a12,a15,a17,a32,a35,a5,a53,a55,a57,a7,a72,a73,a75,a76,a77,a78c,a8,a9,aapcs-frame-chain,aclass,acquire-release,aes,armv4,armv4t,armv5t,armv5te,armv5tej,armv6,armv6-m,armv6j,armv6k,armv6kz,armv6s-m,armv6t2,armv7-a,armv7-m,armv7-r,armv7e-m,armv7k,armv7s,armv7ve,armv8-a,armv8-m.base,armv8-m.main,armv8-r,armv8.1-a,armv8.1-m.main,armv8.2-a,armv8.3-a,armv8.4-a,armv8.5-a,armv8.6-a,armv8.7-a,armv8.8-a,armv8.9-a,armv9-a,armv9.1-a,armv9.2-a,armv9.3-a,armv9.4-a,armv9.5-a,armv9.6-a,atomics-32,avoid-movs-shop,avoid-muls,avoid-partial-cpsr,bf16,big-endian-instructions,branch-align-64,cde,cdecp0,cdecp1,cdecp2,cdecp3,cdecp4,cdecp5,cdecp6,cdecp7,cheap-predicable-cpsr,clrbhb,cortex-a510,cortex-a710,cortex-a78,cortex-a78ae,cortex-x1,cortex-x1c,crc,crypto,d32,db,dfb,disable-postra-scheduler,dont-widen-vmovs,dotprod,dsp,execute-only,expand-fp-mlx,exynos,fix-cmse-cve-2021-35465,fix-cortex-a57-aes-1742098,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp16fml,fp64,fpao,fpregs,fpregs16,fpregs64,fullfp16,fuse-aes,fuse-literals,harden-sls-blr,harden-sls-nocomdat,harden-sls-retbr,hwdiv,hwdiv-arm,i8mm,iwmmxt,iwmmxt2,krait,kryo,lob,long-calls,loop-align,m3,m55,m7,m85,mclass,mp,muxed-units,mve,mve.fp,mve1beat,mve2beat,mve4beat,nacl-trap,neon,neon-fpmovs,neonfp,neoverse-v1,no-branch-predictor,no-bti-at-return-twice,no-movt,no-neg-immediates,noarm,nonpipelined-vfp,pacbti,perfmon,prefer-ishst,prefer-vmovsr,prof-unpr,r4,r5,r52,r52plus,r7,ras,rclass,read-tp-tpidrprw,read-tp-tpidruro,read-tp-tpidrurw,reserve-r9,ret-addr-stack,sb,sha2,slow-fp-brcc,slow-load-D-subreg,slow-odd-reg,slow-vdup32,slow-vgetlni32,slowfpvfmx,slowfpvmlx,soft-float,splat-vfp-neon,strict-align,swift,thumb-mode,thumb2,trustzone,use-mipipeliner,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.1m.main,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8.8a,v8.9a,v8m,v8m.main,v9.1a,v9.2a,v9.3a,v9.4a,v9.5a,v9.6a,v9a,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization,vldn-align,vmlx-forwarding,vmlx-hazards,wide-stride-vfp,xscale,zcz"),
+ // TargetArch_arm64:
+ str_lit("CONTEXTIDREL2,a35,a510,a520,a520ae,a53,a55,a57,a64fx,a65,a710,a715,a72,a720,a720ae,a73,a75,a76,a77,a78,a78ae,a78c,addr-lsl-slow-14,aes,aggressive-fma,all,alternate-sextload-cvt-f32-pattern,altnzcv,alu-lsl-fast,am,ampere1,ampere1a,ampere1b,amvs,apple-a10,apple-a11,apple-a12,apple-a13,apple-a14,apple-a15,apple-a16,apple-a17,apple-a7,apple-m4,arith-bcc-fusion,arith-cbz-fusion,ascend-store-address,avoid-ldapur,balance-fp-ops,bf16,brbe,bti,call-saved-x10,call-saved-x11,call-saved-x12,call-saved-x13,call-saved-x14,call-saved-x15,call-saved-x18,call-saved-x8,call-saved-x9,carmel,ccdp,ccidx,ccpp,chk,clrbhb,cmp-bcc-fusion,cmpbr,complxnum,cortex-a725,cortex-r82,cortex-r82ae,cortex-x1,cortex-x2,cortex-x3,cortex-x4,cortex-x925,cpa,crc,crypto,cssc,d128,disable-latency-sched-heuristic,disable-ldp,disable-stp,dit,dotprod,ecv,el2vmsa,el3,enable-select-opt,ete,exynos-cheap-as-move,exynosm3,exynosm4,f32mm,f64mm,f8f16mm,f8f32mm,falkor,faminmax,fgt,fix-cortex-a53-835769,flagm,fmv,force-32bit-jump-tables,fp-armv8,fp16fml,fp8,fp8dot2,fp8dot4,fp8fma,fpac,fprcvt,fptoint,fujitsu-monaka,fullfp16,fuse-address,fuse-addsub-2reg-const1,fuse-adrp-add,fuse-aes,fuse-arith-logic,fuse-crypto-eor,fuse-csel,fuse-literals,gcs,harden-sls-blr,harden-sls-nocomdat,harden-sls-retbr,hbc,hcx,i8mm,ite,jsconv,kryo,ldp-aligned-only,lor,ls64,lse,lse128,lse2,lsfe,lsui,lut,mec,mops,mpam,mte,neon,neoverse512tvb,neoversee1,neoversen1,neoversen2,neoversen3,neoversev1,neoversev2,neoversev3,neoversev3AE,nmi,no-bti-at-return-twice,no-neg-immediates,no-sve-fp-ld1r,no-zcz-fp,nv,occmo,oryon-1,outline-atomics,pan,pan-rwv,pauth,pauth-lr,pcdphint,perfmon,pops,predictable-select-expensive,predres,prfm-slc-target,rand,ras,rasv2,rcpc,rcpc-immo,rcpc3,rdm,reserve-lr-for-ra,reserve-x1,reserve-x10,reserve-x11,reserve-x12,reserve-x13,reserve-x14,reserve-x15,reserve-x18,reserve-x2,reserve-x20,reserve-x21,reserve-x22,reserve-x23,reserve-x24,reserve-x25,reserve-x26,reserve-x27,reserve-x28,reserve-x3,reserve-x4,reserve-x5,reserve-x6,reserve-x7,reserve-x9,rme,saphira,sb,sel2,sha2,sha3,slow-misaligned-128store,slow-paired-128,slow-strqro-store,sm4,sme,sme-b16b16,sme-f16f16,sme-f64f64,sme-f8f16,sme-f8f32,sme-fa64,sme-i16i64,sme-lutv2,sme-mop4,sme-tmop,sme2,sme2p1,sme2p2,spe,spe-eef,specres2,specrestrict,ssbs,ssve-aes,ssve-bitperm,ssve-fp8dot2,ssve-fp8dot4,ssve-fp8fma,store-pair-suppress,stp-aligned-only,strict-align,sve,sve-aes,sve-aes2,sve-b16b16,sve-bfscale,sve-bitperm,sve-f16f32mm,sve2,sve2-aes,sve2-bitperm,sve2-sha3,sve2-sm4,sve2p1,sve2p2,tagged-globals,the,thunderx,thunderx2t99,thunderx3t110,thunderxt81,thunderxt83,thunderxt88,tlb-rmi,tlbiw,tme,tpidr-el1,tpidr-el2,tpidr-el3,tpidrro-el0,tracev8.4,trbe,tsv110,uaops,use-experimental-zeroing-pseudos,use-fixed-over-scalable-if-equal-cost,use-postra-scheduler,use-reciprocal-square-root,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8.8a,v8.9a,v8a,v8r,v9.1a,v9.2a,v9.3a,v9.4a,v9.5a,v9.6a,v9a,vh,wfxt,xs,zcm,zcz,zcz-fp-workaround,zcz-gp"),
+ // TargetArch_wasm32:
+ str_lit("atomics,bulk-memory,bulk-memory-opt,call-indirect-overlong,exception-handling,extended-const,fp16,multimemory,multivalue,mutable-globals,nontrapping-fptoint,reference-types,relaxed-simd,sign-ext,simd128,tail-call,wide-arithmetic"),
+ // TargetArch_wasm64p32:
+ str_lit("atomics,bulk-memory,bulk-memory-opt,call-indirect-overlong,exception-handling,extended-const,fp16,multimemory,multivalue,mutable-globals,nontrapping-fptoint,reference-types,relaxed-simd,sign-ext,simd128,tail-call,wide-arithmetic"),
+ // TargetArch_riscv64:
+ str_lit("32bit,64bit,a,auipc-addi-fusion,b,c,conditional-cmv-fusion,d,disable-latency-sched-heuristic,dlen-factor-2,e,experimental,experimental-rvm23u32,experimental-sdext,experimental-sdtrig,experimental-smctr,experimental-ssctr,experimental-svukte,experimental-xqcia,experimental-xqciac,experimental-xqcicli,experimental-xqcicm,experimental-xqcics,experimental-xqcicsr,experimental-xqciint,experimental-xqcilo,experimental-xqcilsm,experimental-xqcisls,experimental-zalasr,experimental-zicfilp,experimental-zicfiss,experimental-zvbc32e,experimental-zvkgs,f,forced-atomics,h,i,ld-add-fusion,lui-addi-fusion,m,mips-p8700,no-default-unroll,no-rvc-hints,no-sink-splat-operands,no-trailing-seq-cst-fence,optimized-nf2-segment-load-store,optimized-nf3-segment-load-store,optimized-nf4-segment-load-store,optimized-nf5-segment-load-store,optimized-nf6-segment-load-store,optimized-nf7-segment-load-store,optimized-nf8-segment-load-store,optimized-zero-stride-load,predictable-select-expensive,prefer-w-inst,relax,reserve-x1,reserve-x10,reserve-x11,reserve-x12,reserve-x13,reserve-x14,reserve-x15,reserve-x16,reserve-x17,reserve-x18,reserve-x19,reserve-x2,reserve-x20,reserve-x21,reserve-x22,reserve-x23,reserve-x24,reserve-x25,reserve-x26,reserve-x27,reserve-x28,reserve-x29,reserve-x3,reserve-x30,reserve-x31,reserve-x4,reserve-x5,reserve-x6,reserve-x7,reserve-x8,reserve-x9,rva20s64,rva20u64,rva22s64,rva22u64,rva23s64,rva23u64,rvb23s64,rvb23u64,rvi20u32,rvi20u64,save-restore,sha,shcounterenw,shgatpa,shifted-zextw-fusion,short-forward-branch-opt,shtvala,shvsatpa,shvstvala,shvstvecd,sifive7,smaia,smcdeleg,smcsrind,smdbltrp,smepmp,smmpm,smnpm,smrnmi,smstateen,ssaia,ssccfg,ssccptr,sscofpmf,sscounterenw,sscsrind,ssdbltrp,ssnpm,sspm,ssqosid,ssstateen,ssstrict,sstc,sstvala,sstvecd,ssu64xl,supm,svade,svadu,svbare,svinval,svnapot,svpbmt,svvptc,tagged-globals,unaligned-scalar-mem,unaligned-vector-mem,use-postra-scheduler,v,ventana-veyron,vxrm-pipeline-flush,xcvalu,xcvbi,xcvbitmanip,xcvelw,xcvmac,xcvmem,xcvsimd,xmipscmove,xmipslsp,xsfcease,xsfvcp,xsfvfnrclipxfqf,xsfvfwmaccqqq,xsfvqmaccdod,xsfvqmaccqoq,xsifivecdiscarddlone,xsifivecflushdlone,xtheadba,xtheadbb,xtheadbs,xtheadcmo,xtheadcondmov,xtheadfmemidx,xtheadmac,xtheadmemidx,xtheadmempair,xtheadsync,xtheadvdot,xventanacondops,xwchc,za128rs,za64rs,zaamo,zabha,zacas,zalrsc,zama16b,zawrs,zba,zbb,zbc,zbkb,zbkc,zbkx,zbs,zca,zcb,zcd,zce,zcf,zcmop,zcmp,zcmt,zdinx,zexth-fusion,zextw-fusion,zfa,zfbfmin,zfh,zfhmin,zfinx,zhinx,zhinxmin,zic64b,zicbom,zicbop,zicboz,ziccamoa,ziccif,zicclsm,ziccrse,zicntr,zicond,zicsr,zifencei,zihintntl,zihintpause,zihpm,zimop,zk,zkn,zknd,zkne,zknh,zkr,zks,zksed,zksh,zkt,zmmul,ztso,zvbb,zvbc,zve32f,zve32x,zve64d,zve64f,zve64x,zvfbfmin,zvfbfwma,zvfh,zvfhmin,zvkb,zvkg,zvkn,zvknc,zvkned,zvkng,zvknha,zvknhb,zvks,zvksc,zvksed,zvksg,zvksh,zvkt,zvl1024b,zvl128b,zvl16384b,zvl2048b,zvl256b,zvl32768b,zvl32b,zvl4096b,zvl512b,zvl64b,zvl65536b,zvl8192b"),
+};
+
+// Generated with the featuregen script in `misc/featuregen`
+gb_global int target_microarch_counts[TargetArch_COUNT] = {
+ // TargetArch_Invalid:
+ 0,
+ // TargetArch_amd64:
+ 129,
+ // TargetArch_i386:
+ 129,
+ // TargetArch_arm32:
+ 95,
+ // TargetArch_arm64:
+ 82,
+ // TargetArch_wasm32:
+ 4,
+ // TargetArch_wasm64p32:
+ 4,
+ // TargetArch_riscv64:
+ 39,
+};
+
+// Generated with the featuregen script in `misc/featuregen`
+gb_global MicroarchFeatureList microarch_features_list[] = {
+ // TargetArch_amd64:
+ { str_lit("alderlake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") },
+ { str_lit("amdfam10"), str_lit("64bit,64bit-mode,cmov,cx16,cx8,fast-scalar-shift-masks,fxsr,idivq-to-divl,lzcnt,nopl,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4a,vzeroupper,x87") },
+ { str_lit("arrowlake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint8,bmi,bmi2,cldemote,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") },
+ { str_lit("arrowlake-s"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint16,avxvnniint8,bmi,bmi2,cldemote,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,sha512,shstk,slow-3ops-lea,sm3,sm4,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") },
+ { str_lit("arrowlake_s"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint16,avxvnniint8,bmi,bmi2,cldemote,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,sha512,shstk,slow-3ops-lea,sm3,sm4,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") },
+ { str_lit("athlon"), str_lit("64bit-mode,cmov,cx8,mmx,nopl,prfchw,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") },
+ { str_lit("athlon-4"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,prfchw,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") },
+ { str_lit("athlon-fx"), str_lit("64bit,64bit-mode,cmov,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,prfchw,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") },
+ { str_lit("athlon-mp"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,prfchw,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") },
+ { str_lit("athlon-tbird"), str_lit("64bit-mode,cmov,cx8,mmx,nopl,prfchw,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") },
+ { str_lit("athlon-xp"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,prfchw,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") },
+ { str_lit("athlon64"), str_lit("64bit,64bit-mode,cmov,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,prfchw,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") },
+ { str_lit("athlon64-sse3"), str_lit("64bit,64bit-mode,cmov,cx16,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,prfchw,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") },
+ { str_lit("atom"), str_lit("64bit,64bit-mode,cmov,cx16,cx8,fast-imm16,fxsr,idivl-to-divb,idivq-to-divl,lea-sp,lea-uses-ag,mmx,movbe,no-bypass-delay,nopl,pad-short-functions,sahf,slow-two-mem-ops,slow-unaligned-mem-16,sse,sse2,sse3,ssse3,vzeroupper,x87") },
+ { str_lit("atom_sse4_2"), str_lit("64bit,64bit-mode,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-7bytenop,fast-imm16,fast-movbe,fxsr,idivq-to-divl,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,rdrnd,sahf,slow-incdec,slow-lea,slow-pmulld,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-slm-arith-costs,vzeroupper,x87") },
+ { str_lit("atom_sse4_2_movbe"), str_lit("64bit,64bit-mode,aes,clflushopt,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-7bytenop,fast-imm16,fast-movbe,fsgsbase,fxsr,idivq-to-divl,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,sha,slow-incdec,slow-lea,slow-pmulld,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-slm-arith-costs,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") },
+ { str_lit("barcelona"), str_lit("64bit,64bit-mode,cmov,cx16,cx8,fast-scalar-shift-masks,fxsr,idivq-to-divl,lzcnt,nopl,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4a,vzeroupper,x87") },
+ { str_lit("bdver1"), str_lit("64bit,64bit-mode,aes,avx,branchfusion,cmov,crc32,cx16,cx8,fast-11bytenop,fast-scalar-shift-masks,fma4,fxsr,idivq-to-divl,lwp,lzcnt,mmx,nopl,pclmul,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,vzeroupper,x87,xop,xsave") },
+ { str_lit("bdver2"), str_lit("64bit,64bit-mode,aes,avx,bmi,branchfusion,cmov,crc32,cx16,cx8,f16c,fast-11bytenop,fast-bextr,fast-movbe,fast-scalar-shift-masks,fma,fma4,fxsr,idivq-to-divl,lwp,lzcnt,mmx,nopl,pclmul,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,tbm,vzeroupper,x87,xop,xsave") },
+ { str_lit("bdver3"), str_lit("64bit,64bit-mode,aes,avx,bmi,branchfusion,cmov,crc32,cx16,cx8,f16c,fast-11bytenop,fast-bextr,fast-movbe,fast-scalar-shift-masks,fma,fma4,fsgsbase,fxsr,idivq-to-divl,lwp,lzcnt,mmx,nopl,pclmul,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,tbm,vzeroupper,x87,xop,xsave,xsaveopt") },
+ { str_lit("bdver4"), str_lit("64bit,64bit-mode,aes,avx,avx2,bmi,bmi2,branchfusion,cmov,crc32,cx16,cx8,f16c,fast-11bytenop,fast-bextr,fast-movbe,fast-scalar-shift-masks,fma,fma4,fsgsbase,fxsr,idivq-to-divl,lwp,lzcnt,mmx,movbe,mwaitx,nopl,pclmul,popcnt,prfchw,rdrnd,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,tbm,vzeroupper,x87,xop,xsave,xsaveopt") },
+ { str_lit("bonnell"), str_lit("64bit,64bit-mode,cmov,cx16,cx8,fast-imm16,fxsr,idivl-to-divb,idivq-to-divl,lea-sp,lea-uses-ag,mmx,movbe,no-bypass-delay,nopl,pad-short-functions,sahf,slow-two-mem-ops,slow-unaligned-mem-16,sse,sse2,sse3,ssse3,vzeroupper,x87") },
+ { str_lit("broadwell"), str_lit("64bit,64bit-mode,adx,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") },
+ { str_lit("btver1"), str_lit("64bit,64bit-mode,cmov,cx16,cx8,fast-15bytenop,fast-imm16,fast-scalar-shift-masks,fast-vector-shift-masks,fxsr,idivq-to-divl,lzcnt,mmx,nopl,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4a,ssse3,vzeroupper,x87") },
+ { str_lit("btver2"), str_lit("64bit,64bit-mode,aes,avx,bmi,cmov,crc32,cx16,cx8,f16c,fast-15bytenop,fast-bextr,fast-hops,fast-imm16,fast-lzcnt,fast-movbe,fast-scalar-shift-masks,fast-vector-shift-masks,fxsr,idivq-to-divl,lzcnt,mmx,movbe,nopl,pclmul,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,x87,xsave,xsaveopt") },
+ { str_lit("c3"), str_lit("64bit-mode,mmx,prfchw,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") },
+ { str_lit("c3-2"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") },
+ { str_lit("cannonlake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vl,bmi,bmi2,clflushopt,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,sha,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") },
+ { str_lit("cascadelake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,avx512vnni,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,faster-shift-than-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") },
+ { str_lit("clearwaterforest"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint16,avxvnniint8,bmi,bmi2,cldemote,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prefetchi,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,sha512,shstk,slow-3ops-lea,sm3,sm4,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,uintr,usermsr,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") },
+ { str_lit("cooperlake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bf16,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,avx512vnni,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,faster-shift-than-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") },
+ { str_lit("core-avx-i"), str_lit("64bit,64bit-mode,avx,cmov,crc32,cx16,cx8,f16c,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fsgsbase,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") },
+ { str_lit("core-avx2"), str_lit("64bit,64bit-mode,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") },
+ { str_lit("core2"), str_lit("64bit,64bit-mode,cmov,cx16,cx8,fxsr,macrofusion,mmx,nopl,sahf,slow-unaligned-mem-16,sse,sse2,sse3,ssse3,vzeroupper,x87") },
+ { str_lit("core_2_duo_sse4_1"), str_lit("64bit,64bit-mode,cmov,cx16,cx8,fxsr,macrofusion,mmx,nopl,sahf,slow-unaligned-mem-16,sse,sse2,sse3,sse4.1,ssse3,vzeroupper,x87") },
+ { str_lit("core_2_duo_ssse3"), str_lit("64bit,64bit-mode,cmov,cx16,cx8,fxsr,macrofusion,mmx,nopl,sahf,slow-unaligned-mem-16,sse,sse2,sse3,ssse3,vzeroupper,x87") },
+ { str_lit("core_2nd_gen_avx"), str_lit("64bit,64bit-mode,avx,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") },
+ { str_lit("core_3rd_gen_avx"), str_lit("64bit,64bit-mode,avx,cmov,crc32,cx16,cx8,f16c,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fsgsbase,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") },
+ { str_lit("core_4th_gen_avx"), str_lit("64bit,64bit-mode,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") },
+ { str_lit("core_4th_gen_avx_tsx"), str_lit("64bit,64bit-mode,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") },
+ { str_lit("core_5th_gen_avx"), str_lit("64bit,64bit-mode,adx,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") },
+ { str_lit("core_5th_gen_avx_tsx"), str_lit("64bit,64bit-mode,adx,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") },
+ { str_lit("core_aes_pclmulqdq"), str_lit("64bit,64bit-mode,cmov,crc32,cx16,cx8,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,sahf,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") },
+ { str_lit("core_i7_sse4_2"), str_lit("64bit,64bit-mode,cmov,crc32,cx16,cx8,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,popcnt,sahf,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") },
+ { str_lit("corei7"), str_lit("64bit,64bit-mode,cmov,crc32,cx16,cx8,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,popcnt,sahf,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") },
+ { str_lit("corei7-avx"), str_lit("64bit,64bit-mode,avx,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") },
+ { str_lit("diamondrapids"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,amx-avx512,amx-bf16,amx-complex,amx-fp16,amx-fp8,amx-int8,amx-movrs,amx-tf32,amx-tile,amx-transpose,avx,avx10.1-256,avx10.1-512,avx10.2-256,avx10.2-512,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avxifma,avxneconvert,avxvnni,avxvnniint16,avxvnniint8,bmi,bmi2,branch-hint,ccmp,cf,cldemote,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,egpr,enqcmd,ermsb,evex512,f16c,false-deps-getmant,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-range,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,movrs,ndd,nf,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,ppx,prefer-256-bit,prefetchi,prfchw,ptwrite,push2pop2,rdpid,rdrnd,rdseed,sahf,serialize,sha,sha512,shstk,sm3,sm4,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tsxldtrk,tuning-fast-imm-vector-shift,uintr,usermsr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves,zu") },
+ { str_lit("emeraldrapids"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,amx-bf16,amx-int8,amx-tile,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,enqcmd,ermsb,evex512,f16c,false-deps-getmant,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-range,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tsxldtrk,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") },
+ { str_lit("generic"), str_lit("64bit,64bit-mode,cx8,fast-15bytenop,fast-scalar-fsqrt,idivq-to-divl,macrofusion,slow-3ops-lea,sse,sse2,vzeroupper,x87") },
+ { str_lit("geode"), str_lit("64bit-mode,cx8,mmx,prfchw,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") },
+ { str_lit("goldmont"), str_lit("64bit,64bit-mode,aes,clflushopt,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-imm16,fast-movbe,fsgsbase,fxsr,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,sha,slow-incdec,slow-lea,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-glm-div-sqrt-costs,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") },
+ { str_lit("goldmont-plus"), str_lit("64bit,64bit-mode,aes,clflushopt,cmov,crc32,cx16,cx8,fast-imm16,fast-movbe,fsgsbase,fxsr,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,sha,slow-incdec,slow-lea,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-glm-div-sqrt-costs,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") },
+ { str_lit("goldmont_plus"), str_lit("64bit,64bit-mode,aes,clflushopt,cmov,crc32,cx16,cx8,fast-imm16,fast-movbe,fsgsbase,fxsr,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,sha,slow-incdec,slow-lea,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-glm-div-sqrt-costs,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") },
+ { str_lit("gracemont"), str_lit("64bit,64bit-mode,adx,aes,avx,avx2,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,f16c,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,nopl,pclmul,pconfig,pku,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") },
+ { str_lit("grandridge"), str_lit("64bit,64bit-mode,adx,aes,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint8,bmi,bmi2,cldemote,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,nopl,pclmul,pconfig,pku,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") },
+ { str_lit("graniterapids"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,amx-bf16,amx-fp16,amx-int8,amx-tile,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avxvnni,bmi,bmi2,branch-hint,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,enqcmd,ermsb,evex512,f16c,false-deps-getmant,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-range,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prefetchi,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tsxldtrk,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") },
+ { str_lit("graniterapids-d"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,amx-bf16,amx-complex,amx-fp16,amx-int8,amx-tile,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avxvnni,bmi,bmi2,branch-hint,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,enqcmd,ermsb,evex512,f16c,false-deps-getmant,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-range,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prefetchi,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tsxldtrk,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") },
+ { str_lit("graniterapids_d"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,amx-bf16,amx-complex,amx-fp16,amx-int8,amx-tile,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avxvnni,bmi,bmi2,branch-hint,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,enqcmd,ermsb,evex512,f16c,false-deps-getmant,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-range,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prefetchi,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tsxldtrk,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") },
+ { str_lit("haswell"), str_lit("64bit,64bit-mode,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") },
+ { str_lit("i386"), str_lit("64bit-mode,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") },
+ { str_lit("i486"), str_lit("64bit-mode,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") },
+ { str_lit("i586"), str_lit("64bit-mode,cx8,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") },
+ { str_lit("i686"), str_lit("64bit-mode,cmov,cx8,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") },
+ { str_lit("icelake-client"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,bmi,bmi2,clflushopt,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdpid,rdrnd,rdseed,sahf,sha,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") },
+ { str_lit("icelake-server"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prfchw,rdpid,rdrnd,rdseed,sahf,sha,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") },
+ { str_lit("icelake_client"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,bmi,bmi2,clflushopt,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdpid,rdrnd,rdseed,sahf,sha,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") },
+ { str_lit("icelake_server"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prfchw,rdpid,rdrnd,rdseed,sahf,sha,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") },
+ { str_lit("ivybridge"), str_lit("64bit,64bit-mode,avx,cmov,crc32,cx16,cx8,f16c,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fsgsbase,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") },
+ { str_lit("k6"), str_lit("64bit-mode,cx8,mmx,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") },
+ { str_lit("k6-2"), str_lit("64bit-mode,cx8,mmx,prfchw,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") },
+ { str_lit("k6-3"), str_lit("64bit-mode,cx8,mmx,prfchw,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") },
+ { str_lit("k8"), str_lit("64bit,64bit-mode,cmov,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,prfchw,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") },
+ { str_lit("k8-sse3"), str_lit("64bit,64bit-mode,cmov,cx16,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,prfchw,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") },
+ { str_lit("knl"), str_lit("64bit,64bit-mode,adx,aes,avx,avx2,avx512cd,avx512f,bmi,bmi2,cmov,crc32,cx16,cx8,evex512,f16c,fast-gather,fast-imm16,fast-movbe,fma,fsgsbase,fxsr,idivq-to-divl,lzcnt,mmx,movbe,nopl,pclmul,popcnt,prefer-mask-registers,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,slow-incdec,slow-pmaddwd,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,x87,xsave,xsaveopt") },
+ { str_lit("knm"), str_lit("64bit,64bit-mode,adx,aes,avx,avx2,avx512cd,avx512f,avx512vpopcntdq,bmi,bmi2,cmov,crc32,cx16,cx8,evex512,f16c,fast-gather,fast-imm16,fast-movbe,fma,fsgsbase,fxsr,idivq-to-divl,lzcnt,mmx,movbe,nopl,pclmul,popcnt,prefer-mask-registers,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,slow-incdec,slow-pmaddwd,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,x87,xsave,xsaveopt") },
+ { str_lit("lakemont"), str_lit("64bit-mode,cx8,slow-unaligned-mem-16,sse,sse2,vzeroupper") },
+ { str_lit("lunarlake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint16,avxvnniint8,bmi,bmi2,cldemote,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,sha512,shstk,slow-3ops-lea,sm3,sm4,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") },
+ { str_lit("meteorlake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") },
+ { str_lit("mic_avx512"), str_lit("64bit,64bit-mode,adx,aes,avx,avx2,avx512cd,avx512f,bmi,bmi2,cmov,crc32,cx16,cx8,evex512,f16c,fast-gather,fast-imm16,fast-movbe,fma,fsgsbase,fxsr,idivq-to-divl,lzcnt,mmx,movbe,nopl,pclmul,popcnt,prefer-mask-registers,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,slow-incdec,slow-pmaddwd,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,x87,xsave,xsaveopt") },
+ { str_lit("nehalem"), str_lit("64bit,64bit-mode,cmov,crc32,cx16,cx8,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,popcnt,sahf,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") },
+ { str_lit("nocona"), str_lit("64bit,64bit-mode,cmov,cx16,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") },
+ { str_lit("opteron"), str_lit("64bit,64bit-mode,cmov,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,prfchw,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") },
+ { str_lit("opteron-sse3"), str_lit("64bit,64bit-mode,cmov,cx16,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,prfchw,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") },
+ { str_lit("pantherlake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint16,avxvnniint8,bmi,bmi2,cldemote,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prefetchi,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,sha512,shstk,slow-3ops-lea,sm3,sm4,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") },
+ { str_lit("penryn"), str_lit("64bit,64bit-mode,cmov,cx16,cx8,fxsr,macrofusion,mmx,nopl,sahf,slow-unaligned-mem-16,sse,sse2,sse3,sse4.1,ssse3,vzeroupper,x87") },
+ { str_lit("pentium"), str_lit("64bit-mode,cx8,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") },
+ { str_lit("pentium-m"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") },
+ { str_lit("pentium-mmx"), str_lit("64bit-mode,cx8,mmx,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") },
+ { str_lit("pentium2"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") },
+ { str_lit("pentium3"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") },
+ { str_lit("pentium3m"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") },
+ { str_lit("pentium4"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") },
+ { str_lit("pentium4m"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") },
+ { str_lit("pentium_4"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") },
+ { str_lit("pentium_4_sse3"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") },
+ { str_lit("pentium_ii"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") },
+ { str_lit("pentium_iii"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") },
+ { str_lit("pentium_iii_no_xmm_regs"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") },
+ { str_lit("pentium_m"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") },
+ { str_lit("pentium_mmx"), str_lit("64bit-mode,cx8,mmx,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") },
+ { str_lit("pentium_pro"), str_lit("64bit-mode,cmov,cx8,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") },
+ { str_lit("pentiumpro"), str_lit("64bit-mode,cmov,cx8,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") },
+ { str_lit("prescott"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") },
+ { str_lit("raptorlake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") },
+ { str_lit("rocketlake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,bmi,bmi2,clflushopt,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdpid,rdrnd,rdseed,sahf,sha,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") },
+ { str_lit("sandybridge"), str_lit("64bit,64bit-mode,avx,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") },
+ { str_lit("sapphirerapids"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,amx-bf16,amx-int8,amx-tile,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,enqcmd,ermsb,evex512,f16c,false-deps-getmant,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-range,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tsxldtrk,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") },
+ { str_lit("sierraforest"), str_lit("64bit,64bit-mode,adx,aes,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint8,bmi,bmi2,cldemote,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,nopl,pclmul,pconfig,pku,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") },
+ { str_lit("silvermont"), str_lit("64bit,64bit-mode,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-7bytenop,fast-imm16,fast-movbe,fxsr,idivq-to-divl,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,rdrnd,sahf,slow-incdec,slow-lea,slow-pmulld,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-slm-arith-costs,vzeroupper,x87") },
+ { str_lit("skx"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,faster-shift-than-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") },
+ { str_lit("skylake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,bmi,bmi2,clflushopt,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") },
+ { str_lit("skylake-avx512"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,faster-shift-than-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") },
+ { str_lit("skylake_avx512"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,faster-shift-than-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") },
+ { str_lit("slm"), str_lit("64bit,64bit-mode,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-7bytenop,fast-imm16,fast-movbe,fxsr,idivq-to-divl,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,rdrnd,sahf,slow-incdec,slow-lea,slow-pmulld,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-slm-arith-costs,vzeroupper,x87") },
+ { str_lit("tigerlake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vp2intersect,avx512vpopcntdq,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdpid,rdrnd,rdseed,sahf,sha,shstk,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") },
+ { str_lit("tremont"), str_lit("64bit,64bit-mode,aes,clflushopt,clwb,cmov,crc32,cx16,cx8,fast-imm16,fast-movbe,fsgsbase,fxsr,gfni,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,sha,slow-incdec,slow-lea,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-glm-div-sqrt-costs,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") },
+ { str_lit("westmere"), str_lit("64bit,64bit-mode,cmov,crc32,cx16,cx8,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,sahf,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") },
+ { str_lit("winchip-c6"), str_lit("64bit-mode,mmx,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") },
+ { str_lit("winchip2"), str_lit("64bit-mode,mmx,prfchw,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") },
+ { str_lit("x86-64"), str_lit("64bit,64bit-mode,cmov,cx8,fxsr,idivq-to-divl,macrofusion,mmx,nopl,slow-3ops-lea,slow-incdec,sse,sse2,vzeroupper,x87") },
+ { str_lit("x86-64-v2"), str_lit("64bit,64bit-mode,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fxsr,idivq-to-divl,macrofusion,mmx,nopl,popcnt,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") },
+ { str_lit("x86-64-v3"), str_lit("64bit,64bit-mode,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fxsr,idivq-to-divl,lzcnt,macrofusion,mmx,movbe,nopl,popcnt,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave") },
+ { str_lit("x86-64-v4"), str_lit("64bit,64bit-mode,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,bmi,bmi2,cmov,crc32,cx16,cx8,evex512,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fxsr,idivq-to-divl,lzcnt,macrofusion,mmx,movbe,nopl,popcnt,prefer-256-bit,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave") },
+ { str_lit("yonah"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") },
+ { str_lit("znver1"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,bmi,bmi2,branchfusion,clflushopt,clzero,cmov,crc32,cx16,cx8,f16c,fast-15bytenop,fast-bextr,fast-imm16,fast-lzcnt,fast-movbe,fast-scalar-fsqrt,fast-scalar-shift-masks,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,idivq-to-divl,lzcnt,mmx,movbe,mwaitx,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,sbb-dep-breaking,sha,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") },
+ { str_lit("znver2"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,bmi,bmi2,branchfusion,clflushopt,clwb,clzero,cmov,crc32,cx16,cx8,f16c,fast-15bytenop,fast-bextr,fast-imm16,fast-lzcnt,fast-movbe,fast-scalar-fsqrt,fast-scalar-shift-masks,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,idivq-to-divl,lzcnt,mmx,movbe,mwaitx,nopl,pclmul,popcnt,prfchw,rdpid,rdpru,rdrnd,rdseed,sahf,sbb-dep-breaking,sha,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,vzeroupper,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") },
+ { str_lit("znver3"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,bmi,bmi2,branchfusion,clflushopt,clwb,clzero,cmov,crc32,cx16,cx8,f16c,fast-15bytenop,fast-bextr,fast-imm16,fast-lzcnt,fast-movbe,fast-scalar-fsqrt,fast-scalar-shift-masks,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,mwaitx,nopl,pclmul,pku,popcnt,prfchw,rdpid,rdpru,rdrnd,rdseed,sahf,sbb-dep-breaking,sha,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,vaes,vpclmulqdq,vzeroupper,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") },
+ { str_lit("znver4"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,bmi,bmi2,branchfusion,clflushopt,clwb,clzero,cmov,crc32,cx16,cx8,evex512,f16c,fast-15bytenop,fast-bextr,fast-dpwssd,fast-imm16,fast-lzcnt,fast-movbe,fast-scalar-fsqrt,fast-scalar-shift-masks,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,mwaitx,nopl,pclmul,pku,popcnt,prfchw,rdpid,rdpru,rdrnd,rdseed,sahf,sbb-dep-breaking,sha,shstk,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,vaes,vpclmulqdq,vzeroupper,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") },
+ { str_lit("znver5"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vp2intersect,avx512vpopcntdq,avxvnni,bmi,bmi2,branchfusion,clflushopt,clwb,clzero,cmov,crc32,cx16,cx8,evex512,f16c,fast-15bytenop,fast-bextr,fast-dpwssd,fast-imm16,fast-lzcnt,fast-movbe,fast-scalar-fsqrt,fast-scalar-shift-masks,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,mwaitx,nopl,pclmul,pku,popcnt,prefetchi,prfchw,rdpid,rdpru,rdrnd,rdseed,sahf,sbb-dep-breaking,sha,shstk,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,vaes,vpclmulqdq,vzeroupper,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") },
+ // TargetArch_i386:
+ { str_lit("alderlake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") },
+ { str_lit("amdfam10"), str_lit("32bit-mode,64bit,cmov,cx16,cx8,fast-scalar-shift-masks,fxsr,idivq-to-divl,lzcnt,nopl,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4a,vzeroupper,x87") },
+ { str_lit("arrowlake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint8,bmi,bmi2,cldemote,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") },
+ { str_lit("arrowlake-s"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint16,avxvnniint8,bmi,bmi2,cldemote,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,sha512,shstk,slow-3ops-lea,sm3,sm4,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") },
+ { str_lit("arrowlake_s"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint16,avxvnniint8,bmi,bmi2,cldemote,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,sha512,shstk,slow-3ops-lea,sm3,sm4,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") },
+ { str_lit("athlon"), str_lit("32bit-mode,cmov,cx8,mmx,nopl,prfchw,slow-shld,slow-unaligned-mem-16,vzeroupper,x87") },
+ { str_lit("athlon-4"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,prfchw,slow-shld,slow-unaligned-mem-16,sse,vzeroupper,x87") },
+ { str_lit("athlon-fx"), str_lit("32bit-mode,64bit,cmov,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,prfchw,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") },
+ { str_lit("athlon-mp"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,prfchw,slow-shld,slow-unaligned-mem-16,sse,vzeroupper,x87") },
+ { str_lit("athlon-tbird"), str_lit("32bit-mode,cmov,cx8,mmx,nopl,prfchw,slow-shld,slow-unaligned-mem-16,vzeroupper,x87") },
+ { str_lit("athlon-xp"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,prfchw,slow-shld,slow-unaligned-mem-16,sse,vzeroupper,x87") },
+ { str_lit("athlon64"), str_lit("32bit-mode,64bit,cmov,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,prfchw,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") },
+ { str_lit("athlon64-sse3"), str_lit("32bit-mode,64bit,cmov,cx16,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,prfchw,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") },
+ { str_lit("atom"), str_lit("32bit-mode,64bit,cmov,cx16,cx8,fast-imm16,fxsr,idivl-to-divb,idivq-to-divl,lea-sp,lea-uses-ag,mmx,movbe,no-bypass-delay,nopl,pad-short-functions,sahf,slow-two-mem-ops,slow-unaligned-mem-16,sse,sse2,sse3,ssse3,vzeroupper,x87") },
+ { str_lit("atom_sse4_2"), str_lit("32bit-mode,64bit,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-7bytenop,fast-imm16,fast-movbe,fxsr,idivq-to-divl,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,rdrnd,sahf,slow-incdec,slow-lea,slow-pmulld,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-slm-arith-costs,vzeroupper,x87") },
+ { str_lit("atom_sse4_2_movbe"), str_lit("32bit-mode,64bit,aes,clflushopt,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-7bytenop,fast-imm16,fast-movbe,fsgsbase,fxsr,idivq-to-divl,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,sha,slow-incdec,slow-lea,slow-pmulld,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-slm-arith-costs,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") },
+ { str_lit("barcelona"), str_lit("32bit-mode,64bit,cmov,cx16,cx8,fast-scalar-shift-masks,fxsr,idivq-to-divl,lzcnt,nopl,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4a,vzeroupper,x87") },
+ { str_lit("bdver1"), str_lit("32bit-mode,64bit,aes,avx,branchfusion,cmov,crc32,cx16,cx8,fast-11bytenop,fast-scalar-shift-masks,fma4,fxsr,idivq-to-divl,lwp,lzcnt,mmx,nopl,pclmul,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,vzeroupper,x87,xop,xsave") },
+ { str_lit("bdver2"), str_lit("32bit-mode,64bit,aes,avx,bmi,branchfusion,cmov,crc32,cx16,cx8,f16c,fast-11bytenop,fast-bextr,fast-movbe,fast-scalar-shift-masks,fma,fma4,fxsr,idivq-to-divl,lwp,lzcnt,mmx,nopl,pclmul,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,tbm,vzeroupper,x87,xop,xsave") },
+ { str_lit("bdver3"), str_lit("32bit-mode,64bit,aes,avx,bmi,branchfusion,cmov,crc32,cx16,cx8,f16c,fast-11bytenop,fast-bextr,fast-movbe,fast-scalar-shift-masks,fma,fma4,fsgsbase,fxsr,idivq-to-divl,lwp,lzcnt,mmx,nopl,pclmul,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,tbm,vzeroupper,x87,xop,xsave,xsaveopt") },
+ { str_lit("bdver4"), str_lit("32bit-mode,64bit,aes,avx,avx2,bmi,bmi2,branchfusion,cmov,crc32,cx16,cx8,f16c,fast-11bytenop,fast-bextr,fast-movbe,fast-scalar-shift-masks,fma,fma4,fsgsbase,fxsr,idivq-to-divl,lwp,lzcnt,mmx,movbe,mwaitx,nopl,pclmul,popcnt,prfchw,rdrnd,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,tbm,vzeroupper,x87,xop,xsave,xsaveopt") },
+ { str_lit("bonnell"), str_lit("32bit-mode,64bit,cmov,cx16,cx8,fast-imm16,fxsr,idivl-to-divb,idivq-to-divl,lea-sp,lea-uses-ag,mmx,movbe,no-bypass-delay,nopl,pad-short-functions,sahf,slow-two-mem-ops,slow-unaligned-mem-16,sse,sse2,sse3,ssse3,vzeroupper,x87") },
+ { str_lit("broadwell"), str_lit("32bit-mode,64bit,adx,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") },
+ { str_lit("btver1"), str_lit("32bit-mode,64bit,cmov,cx16,cx8,fast-15bytenop,fast-imm16,fast-scalar-shift-masks,fast-vector-shift-masks,fxsr,idivq-to-divl,lzcnt,mmx,nopl,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4a,ssse3,vzeroupper,x87") },
+ { str_lit("btver2"), str_lit("32bit-mode,64bit,aes,avx,bmi,cmov,crc32,cx16,cx8,f16c,fast-15bytenop,fast-bextr,fast-hops,fast-imm16,fast-lzcnt,fast-movbe,fast-scalar-shift-masks,fast-vector-shift-masks,fxsr,idivq-to-divl,lzcnt,mmx,movbe,nopl,pclmul,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,x87,xsave,xsaveopt") },
+ { str_lit("c3"), str_lit("32bit-mode,mmx,prfchw,slow-unaligned-mem-16,vzeroupper,x87") },
+ { str_lit("c3-2"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,slow-unaligned-mem-16,sse,vzeroupper,x87") },
+ { str_lit("cannonlake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vl,bmi,bmi2,clflushopt,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,sha,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") },
+ { str_lit("cascadelake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,avx512vnni,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,faster-shift-than-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") },
+ { str_lit("clearwaterforest"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint16,avxvnniint8,bmi,bmi2,cldemote,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prefetchi,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,sha512,shstk,slow-3ops-lea,sm3,sm4,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,uintr,usermsr,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") },
+ { str_lit("cooperlake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bf16,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,avx512vnni,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,faster-shift-than-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") },
+ { str_lit("core-avx-i"), str_lit("32bit-mode,64bit,avx,cmov,crc32,cx16,cx8,f16c,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fsgsbase,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") },
+ { str_lit("core-avx2"), str_lit("32bit-mode,64bit,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") },
+ { str_lit("core2"), str_lit("32bit-mode,64bit,cmov,cx16,cx8,fxsr,macrofusion,mmx,nopl,sahf,slow-unaligned-mem-16,sse,sse2,sse3,ssse3,vzeroupper,x87") },
+ { str_lit("core_2_duo_sse4_1"), str_lit("32bit-mode,64bit,cmov,cx16,cx8,fxsr,macrofusion,mmx,nopl,sahf,slow-unaligned-mem-16,sse,sse2,sse3,sse4.1,ssse3,vzeroupper,x87") },
+ { str_lit("core_2_duo_ssse3"), str_lit("32bit-mode,64bit,cmov,cx16,cx8,fxsr,macrofusion,mmx,nopl,sahf,slow-unaligned-mem-16,sse,sse2,sse3,ssse3,vzeroupper,x87") },
+ { str_lit("core_2nd_gen_avx"), str_lit("32bit-mode,64bit,avx,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") },
+ { str_lit("core_3rd_gen_avx"), str_lit("32bit-mode,64bit,avx,cmov,crc32,cx16,cx8,f16c,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fsgsbase,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") },
+ { str_lit("core_4th_gen_avx"), str_lit("32bit-mode,64bit,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") },
+ { str_lit("core_4th_gen_avx_tsx"), str_lit("32bit-mode,64bit,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") },
+ { str_lit("core_5th_gen_avx"), str_lit("32bit-mode,64bit,adx,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") },
+ { str_lit("core_5th_gen_avx_tsx"), str_lit("32bit-mode,64bit,adx,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") },
+ { str_lit("core_aes_pclmulqdq"), str_lit("32bit-mode,64bit,cmov,crc32,cx16,cx8,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,sahf,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") },
+ { str_lit("core_i7_sse4_2"), str_lit("32bit-mode,64bit,cmov,crc32,cx16,cx8,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,popcnt,sahf,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") },
+ { str_lit("corei7"), str_lit("32bit-mode,64bit,cmov,crc32,cx16,cx8,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,popcnt,sahf,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") },
+ { str_lit("corei7-avx"), str_lit("32bit-mode,64bit,avx,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") },
+ { str_lit("diamondrapids"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,amx-avx512,amx-bf16,amx-complex,amx-fp16,amx-fp8,amx-int8,amx-movrs,amx-tf32,amx-tile,amx-transpose,avx,avx10.1-256,avx10.1-512,avx10.2-256,avx10.2-512,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avxifma,avxneconvert,avxvnni,avxvnniint16,avxvnniint8,bmi,bmi2,branch-hint,ccmp,cf,cldemote,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,egpr,enqcmd,ermsb,evex512,f16c,false-deps-getmant,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-range,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,movrs,ndd,nf,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,ppx,prefer-256-bit,prefetchi,prfchw,ptwrite,push2pop2,rdpid,rdrnd,rdseed,sahf,serialize,sha,sha512,shstk,sm3,sm4,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tsxldtrk,tuning-fast-imm-vector-shift,uintr,usermsr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves,zu") },
+ { str_lit("emeraldrapids"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,amx-bf16,amx-int8,amx-tile,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,enqcmd,ermsb,evex512,f16c,false-deps-getmant,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-range,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tsxldtrk,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") },
+ { str_lit("generic"), str_lit("32bit-mode,64bit,cx8,fast-15bytenop,fast-scalar-fsqrt,idivq-to-divl,macrofusion,slow-3ops-lea,vzeroupper,x87") },
+ { str_lit("geode"), str_lit("32bit-mode,cx8,mmx,prfchw,slow-unaligned-mem-16,vzeroupper,x87") },
+ { str_lit("goldmont"), str_lit("32bit-mode,64bit,aes,clflushopt,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-imm16,fast-movbe,fsgsbase,fxsr,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,sha,slow-incdec,slow-lea,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-glm-div-sqrt-costs,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") },
+ { str_lit("goldmont-plus"), str_lit("32bit-mode,64bit,aes,clflushopt,cmov,crc32,cx16,cx8,fast-imm16,fast-movbe,fsgsbase,fxsr,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,sha,slow-incdec,slow-lea,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-glm-div-sqrt-costs,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") },
+ { str_lit("goldmont_plus"), str_lit("32bit-mode,64bit,aes,clflushopt,cmov,crc32,cx16,cx8,fast-imm16,fast-movbe,fsgsbase,fxsr,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,sha,slow-incdec,slow-lea,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-glm-div-sqrt-costs,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") },
+ { str_lit("gracemont"), str_lit("32bit-mode,64bit,adx,aes,avx,avx2,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,f16c,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,nopl,pclmul,pconfig,pku,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") },
+ { str_lit("grandridge"), str_lit("32bit-mode,64bit,adx,aes,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint8,bmi,bmi2,cldemote,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,nopl,pclmul,pconfig,pku,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") },
+ { str_lit("graniterapids"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,amx-bf16,amx-fp16,amx-int8,amx-tile,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avxvnni,bmi,bmi2,branch-hint,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,enqcmd,ermsb,evex512,f16c,false-deps-getmant,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-range,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prefetchi,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tsxldtrk,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") },
+ { str_lit("graniterapids-d"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,amx-bf16,amx-complex,amx-fp16,amx-int8,amx-tile,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avxvnni,bmi,bmi2,branch-hint,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,enqcmd,ermsb,evex512,f16c,false-deps-getmant,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-range,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prefetchi,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tsxldtrk,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") },
+ { str_lit("graniterapids_d"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,amx-bf16,amx-complex,amx-fp16,amx-int8,amx-tile,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avxvnni,bmi,bmi2,branch-hint,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,enqcmd,ermsb,evex512,f16c,false-deps-getmant,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-range,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prefetchi,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tsxldtrk,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") },
+ { str_lit("haswell"), str_lit("32bit-mode,64bit,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") },
+ { str_lit("i386"), str_lit("32bit-mode,slow-unaligned-mem-16,vzeroupper,x87") },
+ { str_lit("i486"), str_lit("32bit-mode,slow-unaligned-mem-16,vzeroupper,x87") },
+ { str_lit("i586"), str_lit("32bit-mode,cx8,slow-unaligned-mem-16,vzeroupper,x87") },
+ { str_lit("i686"), str_lit("32bit-mode,cmov,cx8,slow-unaligned-mem-16,vzeroupper,x87") },
+ { str_lit("icelake-client"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,bmi,bmi2,clflushopt,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdpid,rdrnd,rdseed,sahf,sha,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") },
+ { str_lit("icelake-server"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prfchw,rdpid,rdrnd,rdseed,sahf,sha,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") },
+ { str_lit("icelake_client"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,bmi,bmi2,clflushopt,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdpid,rdrnd,rdseed,sahf,sha,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") },
+ { str_lit("icelake_server"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prfchw,rdpid,rdrnd,rdseed,sahf,sha,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") },
+ { str_lit("ivybridge"), str_lit("32bit-mode,64bit,avx,cmov,crc32,cx16,cx8,f16c,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fsgsbase,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") },
+ { str_lit("k6"), str_lit("32bit-mode,cx8,mmx,slow-unaligned-mem-16,vzeroupper,x87") },
+ { str_lit("k6-2"), str_lit("32bit-mode,cx8,mmx,prfchw,slow-unaligned-mem-16,vzeroupper,x87") },
+ { str_lit("k6-3"), str_lit("32bit-mode,cx8,mmx,prfchw,slow-unaligned-mem-16,vzeroupper,x87") },
+ { str_lit("k8"), str_lit("32bit-mode,64bit,cmov,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,prfchw,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") },
+ { str_lit("k8-sse3"), str_lit("32bit-mode,64bit,cmov,cx16,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,prfchw,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") },
+ { str_lit("knl"), str_lit("32bit-mode,64bit,adx,aes,avx,avx2,avx512cd,avx512f,bmi,bmi2,cmov,crc32,cx16,cx8,evex512,f16c,fast-gather,fast-imm16,fast-movbe,fma,fsgsbase,fxsr,idivq-to-divl,lzcnt,mmx,movbe,nopl,pclmul,popcnt,prefer-mask-registers,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,slow-incdec,slow-pmaddwd,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,x87,xsave,xsaveopt") },
+ { str_lit("knm"), str_lit("32bit-mode,64bit,adx,aes,avx,avx2,avx512cd,avx512f,avx512vpopcntdq,bmi,bmi2,cmov,crc32,cx16,cx8,evex512,f16c,fast-gather,fast-imm16,fast-movbe,fma,fsgsbase,fxsr,idivq-to-divl,lzcnt,mmx,movbe,nopl,pclmul,popcnt,prefer-mask-registers,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,slow-incdec,slow-pmaddwd,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,x87,xsave,xsaveopt") },
+ { str_lit("lakemont"), str_lit("32bit-mode,cx8,slow-unaligned-mem-16,vzeroupper") },
+ { str_lit("lunarlake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint16,avxvnniint8,bmi,bmi2,cldemote,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,sha512,shstk,slow-3ops-lea,sm3,sm4,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") },
+ { str_lit("meteorlake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") },
+ { str_lit("mic_avx512"), str_lit("32bit-mode,64bit,adx,aes,avx,avx2,avx512cd,avx512f,bmi,bmi2,cmov,crc32,cx16,cx8,evex512,f16c,fast-gather,fast-imm16,fast-movbe,fma,fsgsbase,fxsr,idivq-to-divl,lzcnt,mmx,movbe,nopl,pclmul,popcnt,prefer-mask-registers,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,slow-incdec,slow-pmaddwd,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,x87,xsave,xsaveopt") },
+ { str_lit("nehalem"), str_lit("32bit-mode,64bit,cmov,crc32,cx16,cx8,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,popcnt,sahf,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") },
+ { str_lit("nocona"), str_lit("32bit-mode,64bit,cmov,cx16,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") },
+ { str_lit("opteron"), str_lit("32bit-mode,64bit,cmov,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,prfchw,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") },
+ { str_lit("opteron-sse3"), str_lit("32bit-mode,64bit,cmov,cx16,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,prfchw,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") },
+ { str_lit("pantherlake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint16,avxvnniint8,bmi,bmi2,cldemote,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prefetchi,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,sha512,shstk,slow-3ops-lea,sm3,sm4,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") },
+ { str_lit("penryn"), str_lit("32bit-mode,64bit,cmov,cx16,cx8,fxsr,macrofusion,mmx,nopl,sahf,slow-unaligned-mem-16,sse,sse2,sse3,sse4.1,ssse3,vzeroupper,x87") },
+ { str_lit("pentium"), str_lit("32bit-mode,cx8,slow-unaligned-mem-16,vzeroupper,x87") },
+ { str_lit("pentium-m"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") },
+ { str_lit("pentium-mmx"), str_lit("32bit-mode,cx8,mmx,slow-unaligned-mem-16,vzeroupper,x87") },
+ { str_lit("pentium2"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,vzeroupper,x87") },
+ { str_lit("pentium3"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,vzeroupper,x87") },
+ { str_lit("pentium3m"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,vzeroupper,x87") },
+ { str_lit("pentium4"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") },
+ { str_lit("pentium4m"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") },
+ { str_lit("pentium_4"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") },
+ { str_lit("pentium_4_sse3"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") },
+ { str_lit("pentium_ii"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,vzeroupper,x87") },
+ { str_lit("pentium_iii"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,vzeroupper,x87") },
+ { str_lit("pentium_iii_no_xmm_regs"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,vzeroupper,x87") },
+ { str_lit("pentium_m"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") },
+ { str_lit("pentium_mmx"), str_lit("32bit-mode,cx8,mmx,slow-unaligned-mem-16,vzeroupper,x87") },
+ { str_lit("pentium_pro"), str_lit("32bit-mode,cmov,cx8,nopl,slow-unaligned-mem-16,vzeroupper,x87") },
+ { str_lit("pentiumpro"), str_lit("32bit-mode,cmov,cx8,nopl,slow-unaligned-mem-16,vzeroupper,x87") },
+ { str_lit("prescott"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") },
+ { str_lit("raptorlake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") },
+ { str_lit("rocketlake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,bmi,bmi2,clflushopt,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdpid,rdrnd,rdseed,sahf,sha,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") },
+ { str_lit("sandybridge"), str_lit("32bit-mode,64bit,avx,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") },
+ { str_lit("sapphirerapids"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,amx-bf16,amx-int8,amx-tile,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,enqcmd,ermsb,evex512,f16c,false-deps-getmant,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-range,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tsxldtrk,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") },
+ { str_lit("sierraforest"), str_lit("32bit-mode,64bit,adx,aes,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint8,bmi,bmi2,cldemote,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,nopl,pclmul,pconfig,pku,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") },
+ { str_lit("silvermont"), str_lit("32bit-mode,64bit,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-7bytenop,fast-imm16,fast-movbe,fxsr,idivq-to-divl,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,rdrnd,sahf,slow-incdec,slow-lea,slow-pmulld,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-slm-arith-costs,vzeroupper,x87") },
+ { str_lit("skx"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,faster-shift-than-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") },
+ { str_lit("skylake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,bmi,bmi2,clflushopt,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") },
+ { str_lit("skylake-avx512"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,faster-shift-than-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") },
+ { str_lit("skylake_avx512"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,faster-shift-than-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") },
+ { str_lit("slm"), str_lit("32bit-mode,64bit,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-7bytenop,fast-imm16,fast-movbe,fxsr,idivq-to-divl,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,rdrnd,sahf,slow-incdec,slow-lea,slow-pmulld,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-slm-arith-costs,vzeroupper,x87") },
+ { str_lit("tigerlake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vp2intersect,avx512vpopcntdq,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdpid,rdrnd,rdseed,sahf,sha,shstk,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") },
+ { str_lit("tremont"), str_lit("32bit-mode,64bit,aes,clflushopt,clwb,cmov,crc32,cx16,cx8,fast-imm16,fast-movbe,fsgsbase,fxsr,gfni,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,sha,slow-incdec,slow-lea,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-glm-div-sqrt-costs,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") },
+ { str_lit("westmere"), str_lit("32bit-mode,64bit,cmov,crc32,cx16,cx8,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,sahf,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") },
+ { str_lit("winchip-c6"), str_lit("32bit-mode,mmx,slow-unaligned-mem-16,vzeroupper,x87") },
+ { str_lit("winchip2"), str_lit("32bit-mode,mmx,prfchw,slow-unaligned-mem-16,vzeroupper,x87") },
+ { str_lit("x86-64"), str_lit("32bit-mode,64bit,cmov,cx8,fxsr,idivq-to-divl,macrofusion,mmx,nopl,slow-3ops-lea,slow-incdec,sse,sse2,vzeroupper,x87") },
+ { str_lit("x86-64-v2"), str_lit("32bit-mode,64bit,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fxsr,idivq-to-divl,macrofusion,mmx,nopl,popcnt,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") },
+ { str_lit("x86-64-v3"), str_lit("32bit-mode,64bit,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fxsr,idivq-to-divl,lzcnt,macrofusion,mmx,movbe,nopl,popcnt,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave") },
+ { str_lit("x86-64-v4"), str_lit("32bit-mode,64bit,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,bmi,bmi2,cmov,crc32,cx16,cx8,evex512,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fxsr,idivq-to-divl,lzcnt,macrofusion,mmx,movbe,nopl,popcnt,prefer-256-bit,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave") },
+ { str_lit("yonah"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") },
+ { str_lit("znver1"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,bmi,bmi2,branchfusion,clflushopt,clzero,cmov,crc32,cx16,cx8,f16c,fast-15bytenop,fast-bextr,fast-imm16,fast-lzcnt,fast-movbe,fast-scalar-fsqrt,fast-scalar-shift-masks,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,idivq-to-divl,lzcnt,mmx,movbe,mwaitx,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,sbb-dep-breaking,sha,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") },
+ { str_lit("znver2"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,bmi,bmi2,branchfusion,clflushopt,clwb,clzero,cmov,crc32,cx16,cx8,f16c,fast-15bytenop,fast-bextr,fast-imm16,fast-lzcnt,fast-movbe,fast-scalar-fsqrt,fast-scalar-shift-masks,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,idivq-to-divl,lzcnt,mmx,movbe,mwaitx,nopl,pclmul,popcnt,prfchw,rdpid,rdpru,rdrnd,rdseed,sahf,sbb-dep-breaking,sha,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,vzeroupper,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") },
+ { str_lit("znver3"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,bmi,bmi2,branchfusion,clflushopt,clwb,clzero,cmov,crc32,cx16,cx8,f16c,fast-15bytenop,fast-bextr,fast-imm16,fast-lzcnt,fast-movbe,fast-scalar-fsqrt,fast-scalar-shift-masks,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,mwaitx,nopl,pclmul,pku,popcnt,prfchw,rdpid,rdpru,rdrnd,rdseed,sahf,sbb-dep-breaking,sha,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,vaes,vpclmulqdq,vzeroupper,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") },
+ { str_lit("znver4"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,bmi,bmi2,branchfusion,clflushopt,clwb,clzero,cmov,crc32,cx16,cx8,evex512,f16c,fast-15bytenop,fast-bextr,fast-dpwssd,fast-imm16,fast-lzcnt,fast-movbe,fast-scalar-fsqrt,fast-scalar-shift-masks,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,mwaitx,nopl,pclmul,pku,popcnt,prfchw,rdpid,rdpru,rdrnd,rdseed,sahf,sbb-dep-breaking,sha,shstk,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,vaes,vpclmulqdq,vzeroupper,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") },
+ { str_lit("znver5"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vp2intersect,avx512vpopcntdq,avxvnni,bmi,bmi2,branchfusion,clflushopt,clwb,clzero,cmov,crc32,cx16,cx8,evex512,f16c,fast-15bytenop,fast-bextr,fast-dpwssd,fast-imm16,fast-lzcnt,fast-movbe,fast-scalar-fsqrt,fast-scalar-shift-masks,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,mwaitx,nopl,pclmul,pku,popcnt,prefetchi,prfchw,rdpid,rdpru,rdrnd,rdseed,sahf,sbb-dep-breaking,sha,shstk,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,vaes,vpclmulqdq,vzeroupper,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") },
+ // TargetArch_arm32:
+ { str_lit("arm1020e"), str_lit("armv5te,v4t,v5t,v5te") },
+ { str_lit("arm1020t"), str_lit("armv5t,v4t,v5t") },
+ { str_lit("arm1022e"), str_lit("armv5te,v4t,v5t,v5te") },
+ { str_lit("arm10e"), str_lit("armv5te,v4t,v5t,v5te") },
+ { str_lit("arm10tdmi"), str_lit("armv5t,v4t,v5t") },
+ { str_lit("arm1136j-s"), str_lit("armv6,dsp,v4t,v5t,v5te,v6") },
+ { str_lit("arm1136jf-s"), str_lit("armv6,dsp,fp64,fpregs,fpregs64,slowfpvmlx,v4t,v5t,v5te,v6,vfp2,vfp2sp") },
+ { str_lit("arm1156t2-s"), str_lit("armv6t2,dsp,thumb2,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v8m") },
+ { str_lit("arm1156t2f-s"), str_lit("armv6t2,dsp,fp64,fpregs,fpregs64,slowfpvmlx,thumb2,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v8m,vfp2,vfp2sp") },
+ { str_lit("arm1176jz-s"), str_lit("armv6kz,trustzone,v4t,v5t,v5te,v6,v6k") },
+ { str_lit("arm1176jzf-s"), str_lit("armv6kz,fp64,fpregs,fpregs64,slowfpvmlx,trustzone,v4t,v5t,v5te,v6,v6k,vfp2,vfp2sp") },
+ { str_lit("arm710t"), str_lit("armv4t,v4t") },
+ { str_lit("arm720t"), str_lit("armv4t,v4t") },
+ { str_lit("arm7tdmi"), str_lit("armv4t,v4t") },
+ { str_lit("arm7tdmi-s"), str_lit("armv4t,v4t") },
+ { str_lit("arm8"), str_lit("armv4") },
+ { str_lit("arm810"), str_lit("armv4") },
+ { str_lit("arm9"), str_lit("armv4t,v4t") },
+ { str_lit("arm920"), str_lit("armv4t,v4t") },
+ { str_lit("arm920t"), str_lit("armv4t,v4t") },
+ { str_lit("arm922t"), str_lit("armv4t,v4t") },
+ { str_lit("arm926ej-s"), str_lit("armv5te,v4t,v5t,v5te") },
+ { str_lit("arm940t"), str_lit("armv4t,v4t") },
+ { str_lit("arm946e-s"), str_lit("armv5te,v4t,v5t,v5te") },
+ { str_lit("arm966e-s"), str_lit("armv5te,v4t,v5t,v5te") },
+ { str_lit("arm968e-s"), str_lit("armv5te,v4t,v5t,v5te") },
+ { str_lit("arm9e"), str_lit("armv5te,v4t,v5t,v5te") },
+ { str_lit("arm9tdmi"), str_lit("armv4t,v4t") },
+ { str_lit("cortex-a12"), str_lit("a12,aclass,armv7-a,avoid-partial-cpsr,d32,db,dsp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,ret-addr-stack,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization,vmlx-forwarding") },
+ { str_lit("cortex-a15"), str_lit("a15,aclass,armv7-a,avoid-partial-cpsr,d32,db,dont-widen-vmovs,dsp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,muxed-units,neon,perfmon,ret-addr-stack,splat-vfp-neon,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization,vldn-align") },
+ { str_lit("cortex-a17"), str_lit("a17,aclass,armv7-a,avoid-partial-cpsr,d32,db,dsp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,ret-addr-stack,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization,vmlx-forwarding") },
+ { str_lit("cortex-a32"), str_lit("aclass,acquire-release,aes,armv8-a,crc,crypto,d32,db,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") },
+ { str_lit("cortex-a35"), str_lit("a35,aclass,acquire-release,aes,armv8-a,crc,crypto,d32,db,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") },
+ { str_lit("cortex-a5"), str_lit("a5,aclass,armv7-a,d32,db,dsp,fp16,fp64,fpregs,fpregs64,mp,neon,perfmon,ret-addr-stack,slow-fp-brcc,slowfpvfmx,slowfpvmlx,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,vmlx-forwarding") },
+ { str_lit("cortex-a510"), str_lit("aclass,acquire-release,armv9-a,bf16,cortex-a710,crc,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp16fml,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,hwdiv-arm,i8mm,mp,neon,perfmon,ras,sb,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8m,v9a,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") },
+ { str_lit("cortex-a53"), str_lit("a53,aclass,acquire-release,aes,armv8-a,crc,crypto,d32,db,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpao,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") },
+ { str_lit("cortex-a55"), str_lit("a55,aclass,acquire-release,aes,armv8.2-a,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") },
+ { str_lit("cortex-a57"), str_lit("a57,aclass,acquire-release,aes,armv8-a,avoid-partial-cpsr,cheap-predicable-cpsr,crc,crypto,d32,db,dsp,fix-cortex-a57-aes-1742098,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpao,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") },
+ { str_lit("cortex-a7"), str_lit("a7,aclass,armv7-a,d32,db,dsp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,ret-addr-stack,slow-fp-brcc,slowfpvfmx,slowfpvmlx,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization,vmlx-forwarding,vmlx-hazards") },
+ { str_lit("cortex-a710"), str_lit("aclass,acquire-release,armv9-a,bf16,cortex-a710,crc,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp16fml,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,hwdiv-arm,i8mm,mp,neon,perfmon,ras,sb,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8m,v9a,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") },
+ { str_lit("cortex-a72"), str_lit("a72,aclass,acquire-release,aes,armv8-a,crc,crypto,d32,db,dsp,fix-cortex-a57-aes-1742098,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") },
+ { str_lit("cortex-a73"), str_lit("a73,aclass,acquire-release,aes,armv8-a,crc,crypto,d32,db,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") },
+ { str_lit("cortex-a75"), str_lit("a75,aclass,acquire-release,aes,armv8.2-a,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") },
+ { str_lit("cortex-a76"), str_lit("a76,aclass,acquire-release,aes,armv8.2-a,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,hwdiv-arm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") },
+ { str_lit("cortex-a76ae"), str_lit("a76,aclass,acquire-release,aes,armv8.2-a,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,hwdiv-arm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") },
+ { str_lit("cortex-a77"), str_lit("a77,aclass,acquire-release,aes,armv8.2-a,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,hwdiv-arm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") },
+ { str_lit("cortex-a78"), str_lit("aclass,acquire-release,aes,armv8.2-a,cortex-a78,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,hwdiv-arm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") },
+ { str_lit("cortex-a78ae"), str_lit("aclass,acquire-release,aes,armv8.2-a,cortex-a78ae,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,hwdiv-arm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") },
+ { str_lit("cortex-a78c"), str_lit("a78c,aclass,acquire-release,aes,armv8.2-a,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,hwdiv-arm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") },
+ { str_lit("cortex-a8"), str_lit("a8,aclass,armv7-a,d32,db,dsp,fp64,fpregs,fpregs64,neon,nonpipelined-vfp,perfmon,ret-addr-stack,slow-fp-brcc,slowfpvfmx,slowfpvmlx,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vmlx-forwarding,vmlx-hazards") },
+ { str_lit("cortex-a9"), str_lit("a9,aclass,armv7-a,avoid-partial-cpsr,d32,db,dsp,expand-fp-mlx,fp16,fp64,fpregs,fpregs64,mp,muxed-units,neon,neon-fpmovs,perfmon,prefer-vmovsr,ret-addr-stack,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vldn-align,vmlx-forwarding,vmlx-hazards") },
+ { str_lit("cortex-m0"), str_lit("armv6-m,db,mclass,no-branch-predictor,noarm,strict-align,thumb-mode,v4t,v5t,v5te,v6,v6m") },
+ { str_lit("cortex-m0plus"), str_lit("armv6-m,db,mclass,no-branch-predictor,noarm,strict-align,thumb-mode,v4t,v5t,v5te,v6,v6m") },
+ { str_lit("cortex-m1"), str_lit("armv6-m,db,mclass,no-branch-predictor,noarm,strict-align,thumb-mode,v4t,v5t,v5te,v6,v6m") },
+ { str_lit("cortex-m23"), str_lit("8msecext,acquire-release,armv8-m.base,db,hwdiv,mclass,no-branch-predictor,no-movt,noarm,strict-align,thumb-mode,v4t,v5t,v5te,v6,v6m,v7clrex,v8m") },
+ { str_lit("cortex-m3"), str_lit("armv7-m,db,hwdiv,loop-align,m3,mclass,no-branch-predictor,noarm,thumb-mode,thumb2,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m") },
+ { str_lit("cortex-m33"), str_lit("8msecext,acquire-release,armv8-m.main,avoid-muls,db,dsp,fix-cmse-cve-2021-35465,fp-armv8d16sp,fp16,fpregs,hwdiv,loop-align,mclass,no-branch-predictor,noarm,slowfpvfmx,slowfpvmlx,thumb-mode,thumb2,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,v8m.main,vfp2sp,vfp3d16sp,vfp4d16sp") },
+ { str_lit("cortex-m35p"), str_lit("8msecext,acquire-release,armv8-m.main,db,dsp,fix-cmse-cve-2021-35465,fp-armv8d16sp,fp16,fpregs,hwdiv,loop-align,mclass,no-branch-predictor,noarm,slowfpvfmx,slowfpvmlx,thumb-mode,thumb2,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,v8m.main,vfp2sp,vfp3d16sp,vfp4d16sp") },
+ { str_lit("cortex-m4"), str_lit("armv7e-m,db,dsp,fp16,fpregs,hwdiv,loop-align,mclass,no-branch-predictor,noarm,slowfpvfmx,slowfpvmlx,thumb-mode,thumb2,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2sp,vfp3d16sp,vfp4d16sp") },
+ { str_lit("cortex-m52"), str_lit("8msecext,acquire-release,armv8.1-m.main,db,dsp,fp-armv8d16,fp-armv8d16sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,lob,loop-align,mclass,mve,mve.fp,mve1beat,no-branch-predictor,noarm,pacbti,ras,slowfpvmlx,thumb-mode,thumb2,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8.1m.main,v8m,v8m.main,vfp2,vfp2sp,vfp3d16,vfp3d16sp,vfp4d16,vfp4d16sp") },
+ { str_lit("cortex-m55"), str_lit("8msecext,acquire-release,armv8.1-m.main,db,dsp,fix-cmse-cve-2021-35465,fp-armv8d16,fp-armv8d16sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,lob,loop-align,m55,mclass,mve,mve.fp,no-branch-predictor,noarm,ras,slowfpvmlx,thumb-mode,thumb2,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8.1m.main,v8m,v8m.main,vfp2,vfp2sp,vfp3d16,vfp3d16sp,vfp4d16,vfp4d16sp") },
+ { str_lit("cortex-m7"), str_lit("armv7e-m,branch-align-64,db,dsp,fp-armv8d16,fp-armv8d16sp,fp16,fp64,fpregs,fpregs64,hwdiv,m7,mclass,noarm,thumb-mode,thumb2,use-mipipeliner,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3d16,vfp3d16sp,vfp4d16,vfp4d16sp") },
+ { str_lit("cortex-m85"), str_lit("8msecext,acquire-release,armv8.1-m.main,branch-align-64,db,dsp,fp-armv8d16,fp-armv8d16sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,lob,m85,mclass,mve,mve.fp,noarm,pacbti,ras,thumb-mode,thumb2,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8.1m.main,v8m,v8m.main,vfp2,vfp2sp,vfp3d16,vfp3d16sp,vfp4d16,vfp4d16sp") },
+ { str_lit("cortex-r4"), str_lit("armv7-r,avoid-partial-cpsr,db,dsp,hwdiv,perfmon,r4,rclass,ret-addr-stack,thumb2,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m") },
+ { str_lit("cortex-r4f"), str_lit("armv7-r,avoid-partial-cpsr,db,dsp,fp64,fpregs,fpregs64,hwdiv,perfmon,r4,rclass,ret-addr-stack,slow-fp-brcc,slowfpvfmx,slowfpvmlx,thumb2,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3d16,vfp3d16sp") },
+ { str_lit("cortex-r5"), str_lit("armv7-r,avoid-partial-cpsr,db,dsp,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,perfmon,r5,rclass,ret-addr-stack,slow-fp-brcc,slowfpvfmx,slowfpvmlx,thumb2,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3d16,vfp3d16sp") },
+ { str_lit("cortex-r52"), str_lit("acquire-release,armv8-r,crc,d32,db,dfb,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpao,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,r52,rclass,thumb2,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") },
+ { str_lit("cortex-r52plus"), str_lit("acquire-release,armv8-r,crc,d32,db,dfb,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpao,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,r52plus,rclass,thumb2,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") },
+ { str_lit("cortex-r7"), str_lit("armv7-r,avoid-partial-cpsr,db,dsp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,perfmon,r7,rclass,ret-addr-stack,slow-fp-brcc,slowfpvfmx,slowfpvmlx,thumb2,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3d16,vfp3d16sp") },
+ { str_lit("cortex-r8"), str_lit("armv7-r,avoid-partial-cpsr,db,dsp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,perfmon,rclass,ret-addr-stack,slow-fp-brcc,slowfpvfmx,slowfpvmlx,thumb2,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3d16,vfp3d16sp") },
+ { str_lit("cortex-x1"), str_lit("aclass,acquire-release,aes,armv8.2-a,cortex-x1,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,hwdiv-arm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") },
+ { str_lit("cortex-x1c"), str_lit("aclass,acquire-release,aes,armv8.2-a,cortex-x1c,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,hwdiv-arm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") },
+ { str_lit("cyclone"), str_lit("aclass,acquire-release,aes,armv8-a,avoid-movs-shop,avoid-partial-cpsr,crc,crypto,d32,db,disable-postra-scheduler,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,neonfp,perfmon,ret-addr-stack,sha2,slowfpvfmx,slowfpvmlx,swift,thumb2,trustzone,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization,zcz") },
+ { str_lit("ep9312"), str_lit("armv4t,v4t") },
+ { str_lit("exynos-m3"), str_lit("aclass,acquire-release,aes,armv8-a,crc,crypto,d32,db,dont-widen-vmovs,dsp,expand-fp-mlx,exynos,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs64,fuse-aes,fuse-literals,hwdiv,hwdiv-arm,mp,neon,perfmon,prof-unpr,ret-addr-stack,sha2,slow-fp-brcc,slow-vdup32,slow-vgetlni32,slowfpvfmx,slowfpvmlx,splat-vfp-neon,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization,wide-stride-vfp,zcz") },
+ { str_lit("exynos-m4"), str_lit("aclass,acquire-release,aes,armv8.2-a,crc,crypto,d32,db,dont-widen-vmovs,dotprod,dsp,expand-fp-mlx,exynos,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,fuse-aes,fuse-literals,hwdiv,hwdiv-arm,mp,neon,perfmon,prof-unpr,ras,ret-addr-stack,sha2,slow-fp-brcc,slow-vdup32,slow-vgetlni32,slowfpvfmx,slowfpvmlx,splat-vfp-neon,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization,wide-stride-vfp,zcz") },
+ { str_lit("exynos-m5"), str_lit("aclass,acquire-release,aes,armv8.2-a,crc,crypto,d32,db,dont-widen-vmovs,dotprod,dsp,expand-fp-mlx,exynos,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,fuse-aes,fuse-literals,hwdiv,hwdiv-arm,mp,neon,perfmon,prof-unpr,ras,ret-addr-stack,sha2,slow-fp-brcc,slow-vdup32,slow-vgetlni32,slowfpvfmx,slowfpvmlx,splat-vfp-neon,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization,wide-stride-vfp,zcz") },
+ { str_lit("generic"), str_lit("") },
+ { str_lit("iwmmxt"), str_lit("armv5te,v4t,v5t,v5te") },
+ { str_lit("krait"), str_lit("aclass,armv7-a,avoid-partial-cpsr,d32,db,dsp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,krait,muxed-units,neon,perfmon,ret-addr-stack,thumb2,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,vldn-align,vmlx-forwarding") },
+ { str_lit("kryo"), str_lit("aclass,acquire-release,aes,armv8-a,crc,crypto,d32,db,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,kryo,mp,neon,perfmon,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") },
+ { str_lit("mpcore"), str_lit("armv6k,fp64,fpregs,fpregs64,slowfpvmlx,v4t,v5t,v5te,v6,v6k,vfp2,vfp2sp") },
+ { str_lit("mpcorenovfp"), str_lit("armv6k,v4t,v5t,v5te,v6,v6k") },
+ { str_lit("neoverse-n1"), str_lit("aclass,acquire-release,aes,armv8.2-a,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") },
+ { str_lit("neoverse-n2"), str_lit("aclass,acquire-release,armv9-a,bf16,crc,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp16fml,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,hwdiv-arm,i8mm,mp,neon,perfmon,ras,sb,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8m,v9a,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") },
+ { str_lit("neoverse-v1"), str_lit("aclass,acquire-release,aes,armv8.4-a,bf16,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,hwdiv-arm,i8mm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8.3a,v8.4a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") },
+ { str_lit("sc000"), str_lit("armv6-m,db,mclass,no-branch-predictor,noarm,strict-align,thumb-mode,v4t,v5t,v5te,v6,v6m") },
+ { str_lit("sc300"), str_lit("armv7-m,db,hwdiv,m3,mclass,no-branch-predictor,noarm,thumb-mode,thumb2,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m") },
+ { str_lit("star-mc1"), str_lit("8msecext,acquire-release,armv8-m.main,db,dsp,fix-cmse-cve-2021-35465,fp-armv8d16sp,fp16,fpregs,hwdiv,loop-align,mclass,no-branch-predictor,noarm,slowfpvfmx,slowfpvmlx,thumb-mode,thumb2,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,v8m.main,vfp2sp,vfp3d16sp,vfp4d16sp") },
+ { str_lit("strongarm"), str_lit("armv4") },
+ { str_lit("strongarm110"), str_lit("armv4") },
+ { str_lit("strongarm1100"), str_lit("armv4") },
+ { str_lit("strongarm1110"), str_lit("armv4") },
+ { str_lit("swift"), str_lit("aclass,armv7-a,avoid-movs-shop,avoid-partial-cpsr,d32,db,disable-postra-scheduler,dsp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,neonfp,perfmon,prefer-ishst,prof-unpr,ret-addr-stack,slow-load-D-subreg,slow-odd-reg,slow-vdup32,slow-vgetlni32,slowfpvfmx,slowfpvmlx,swift,thumb2,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,vmlx-hazards,wide-stride-vfp") },
+ { str_lit("xscale"), str_lit("armv5te,v4t,v5t,v5te") },
+ // TargetArch_arm64:
+ { str_lit("a64fx"), str_lit("CONTEXTIDREL2,a64fx,aes,aggressive-fma,arith-bcc-fusion,ccpp,complxnum,crc,el2vmsa,el3,fp-armv8,fullfp16,lor,lse,neon,pan,pan-rwv,perfmon,predictable-select-expensive,ras,rdm,sha2,store-pair-suppress,sve,uaops,use-postra-scheduler,v8.1a,v8.2a,v8a,vh") },
+ { str_lit("ampere1"), str_lit("CONTEXTIDREL2,aes,aggressive-fma,altnzcv,alu-lsl-fast,am,ampere1,amvs,arith-bcc-fusion,bf16,bti,ccdp,ccidx,ccpp,cmp-bcc-fusion,complxnum,crc,dit,dotprod,ecv,el2vmsa,el3,fgt,flagm,fp-armv8,fptoint,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,fuse-literals,i8mm,jsconv,ldp-aligned-only,lor,lse,lse2,mpam,neon,nv,pan,pan-rwv,pauth,perfmon,predres,rand,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,specrestrict,ssbs,store-pair-suppress,stp-aligned-only,tlb-rmi,tracev8.4,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8a,vh") },
+ { str_lit("ampere1a"), str_lit("CONTEXTIDREL2,aes,aggressive-fma,altnzcv,alu-lsl-fast,am,ampere1a,amvs,arith-bcc-fusion,bf16,bti,ccdp,ccidx,ccpp,cmp-bcc-fusion,complxnum,crc,dit,dotprod,ecv,el2vmsa,el3,fgt,flagm,fp-armv8,fptoint,fullfp16,fuse-address,fuse-addsub-2reg-const1,fuse-adrp-add,fuse-aes,fuse-literals,i8mm,jsconv,ldp-aligned-only,lor,lse,lse2,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predres,rand,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,sm4,specrestrict,ssbs,store-pair-suppress,stp-aligned-only,tlb-rmi,tracev8.4,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8a,vh") },
+ { str_lit("ampere1b"), str_lit("CONTEXTIDREL2,aes,aggressive-fma,altnzcv,alu-lsl-fast,am,ampere1b,amvs,arith-bcc-fusion,bf16,bti,ccdp,ccidx,ccpp,cmp-bcc-fusion,complxnum,crc,cssc,dit,dotprod,ecv,el2vmsa,el3,enable-select-opt,fgt,flagm,fp-armv8,fptoint,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,fuse-literals,hcx,i8mm,jsconv,ldp-aligned-only,lor,lse,lse2,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,rand,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,sm4,specrestrict,ssbs,store-pair-suppress,stp-aligned-only,tlb-rmi,tracev8.4,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8a,vh,wfxt,xs") },
+ { str_lit("apple-a10"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,apple-a10,arith-bcc-fusion,arith-cbz-fusion,crc,disable-latency-sched-heuristic,el2vmsa,el3,fp-armv8,fuse-aes,fuse-crypto-eor,lor,neon,pan,perfmon,rdm,sha2,store-pair-suppress,v8a,vh,zcm,zcz,zcz-gp") },
+ { str_lit("apple-a11"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,apple-a11,arith-bcc-fusion,arith-cbz-fusion,ccpp,crc,disable-latency-sched-heuristic,el2vmsa,el3,fp-armv8,fullfp16,fuse-aes,fuse-crypto-eor,lor,lse,neon,pan,pan-rwv,perfmon,ras,rdm,sha2,store-pair-suppress,uaops,v8.1a,v8.2a,v8a,vh,zcm,zcz,zcz-gp") },
+ { str_lit("apple-a12"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,apple-a12,arith-bcc-fusion,arith-cbz-fusion,ccpp,complxnum,crc,disable-latency-sched-heuristic,el2vmsa,el3,fp-armv8,fullfp16,fuse-aes,fuse-crypto-eor,jsconv,lor,lse,neon,pan,pan-rwv,pauth,perfmon,ras,rcpc,rdm,sha2,store-pair-suppress,uaops,v8.1a,v8.2a,v8.3a,v8a,vh,zcm,zcz,zcz-gp") },
+ { str_lit("apple-a13"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,am,apple-a13,arith-bcc-fusion,arith-cbz-fusion,ccpp,complxnum,crc,disable-latency-sched-heuristic,dit,dotprod,el2vmsa,el3,flagm,fp-armv8,fp16fml,fullfp16,fuse-aes,fuse-crypto-eor,jsconv,lor,lse,lse2,mpam,neon,nv,pan,pan-rwv,pauth,perfmon,ras,rcpc,rcpc-immo,rdm,sel2,sha2,sha3,store-pair-suppress,tlb-rmi,tracev8.4,uaops,v8.1a,v8.2a,v8.3a,v8.4a,v8a,vh,zcm,zcz,zcz-gp") },
+ { str_lit("apple-a14"), str_lit("CONTEXTIDREL2,aes,aggressive-fma,alternate-sextload-cvt-f32-pattern,altnzcv,am,apple-a14,arith-bcc-fusion,arith-cbz-fusion,ccdp,ccpp,complxnum,crc,disable-latency-sched-heuristic,dit,dotprod,el2vmsa,el3,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-address,fuse-aes,fuse-arith-logic,fuse-crypto-eor,fuse-csel,fuse-literals,jsconv,lor,lse,lse2,mpam,neon,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,specrestrict,ssbs,store-pair-suppress,tlb-rmi,tracev8.4,uaops,v8.1a,v8.2a,v8.3a,v8.4a,v8a,vh,zcm,zcz,zcz-gp") },
+ { str_lit("apple-a15"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,altnzcv,am,amvs,apple-a15,arith-bcc-fusion,arith-cbz-fusion,bf16,bti,ccdp,ccpp,complxnum,crc,disable-latency-sched-heuristic,dit,dotprod,ecv,el2vmsa,el3,fgt,flagm,fp-armv8,fp16fml,fpac,fptoint,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,fuse-arith-logic,fuse-crypto-eor,fuse-csel,fuse-literals,i8mm,jsconv,lor,lse,lse2,mpam,neon,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,specrestrict,ssbs,store-pair-suppress,tlb-rmi,tracev8.4,uaops,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8a,vh,zcm,zcz,zcz-gp") },
+ { str_lit("apple-a16"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,altnzcv,am,amvs,apple-a16,arith-bcc-fusion,arith-cbz-fusion,bf16,bti,ccdp,ccpp,complxnum,crc,disable-latency-sched-heuristic,dit,dotprod,ecv,el2vmsa,el3,fgt,flagm,fp-armv8,fp16fml,fpac,fptoint,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,fuse-arith-logic,fuse-crypto-eor,fuse-csel,fuse-literals,hcx,i8mm,jsconv,lor,lse,lse2,mpam,neon,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,specrestrict,ssbs,store-pair-suppress,tlb-rmi,tracev8.4,uaops,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8a,vh,zcm,zcz,zcz-gp") },
+ { str_lit("apple-a17"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,altnzcv,am,amvs,apple-a17,arith-bcc-fusion,arith-cbz-fusion,bf16,bti,ccdp,ccpp,complxnum,crc,disable-latency-sched-heuristic,dit,dotprod,ecv,el2vmsa,el3,fgt,flagm,fp-armv8,fp16fml,fpac,fptoint,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,fuse-arith-logic,fuse-crypto-eor,fuse-csel,fuse-literals,hcx,i8mm,jsconv,lor,lse,lse2,mpam,neon,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,specrestrict,ssbs,store-pair-suppress,tlb-rmi,tracev8.4,uaops,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8a,vh,zcm,zcz,zcz-gp") },
+ { str_lit("apple-a7"), str_lit("aes,alternate-sextload-cvt-f32-pattern,apple-a7,arith-bcc-fusion,arith-cbz-fusion,disable-latency-sched-heuristic,el2vmsa,el3,fp-armv8,fuse-aes,fuse-crypto-eor,neon,perfmon,sha2,store-pair-suppress,v8a,zcm,zcz,zcz-fp-workaround,zcz-gp") },
+ { str_lit("apple-a8"), str_lit("aes,alternate-sextload-cvt-f32-pattern,apple-a7,arith-bcc-fusion,arith-cbz-fusion,disable-latency-sched-heuristic,el2vmsa,el3,fp-armv8,fuse-aes,fuse-crypto-eor,neon,perfmon,sha2,store-pair-suppress,v8a,zcm,zcz,zcz-fp-workaround,zcz-gp") },
+ { str_lit("apple-a9"), str_lit("aes,alternate-sextload-cvt-f32-pattern,apple-a7,arith-bcc-fusion,arith-cbz-fusion,disable-latency-sched-heuristic,el2vmsa,el3,fp-armv8,fuse-aes,fuse-crypto-eor,neon,perfmon,sha2,store-pair-suppress,v8a,zcm,zcz,zcz-fp-workaround,zcz-gp") },
+ { str_lit("apple-m1"), str_lit("CONTEXTIDREL2,aes,aggressive-fma,alternate-sextload-cvt-f32-pattern,altnzcv,am,apple-a14,arith-bcc-fusion,arith-cbz-fusion,ccdp,ccpp,complxnum,crc,disable-latency-sched-heuristic,dit,dotprod,el2vmsa,el3,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-address,fuse-aes,fuse-arith-logic,fuse-crypto-eor,fuse-csel,fuse-literals,jsconv,lor,lse,lse2,mpam,neon,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,specrestrict,ssbs,store-pair-suppress,tlb-rmi,tracev8.4,uaops,v8.1a,v8.2a,v8.3a,v8.4a,v8a,vh,zcm,zcz,zcz-gp") },
+ { str_lit("apple-m2"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,altnzcv,am,amvs,apple-a15,arith-bcc-fusion,arith-cbz-fusion,bf16,bti,ccdp,ccpp,complxnum,crc,disable-latency-sched-heuristic,dit,dotprod,ecv,el2vmsa,el3,fgt,flagm,fp-armv8,fp16fml,fpac,fptoint,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,fuse-arith-logic,fuse-crypto-eor,fuse-csel,fuse-literals,i8mm,jsconv,lor,lse,lse2,mpam,neon,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,specrestrict,ssbs,store-pair-suppress,tlb-rmi,tracev8.4,uaops,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8a,vh,zcm,zcz,zcz-gp") },
+ { str_lit("apple-m3"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,altnzcv,am,amvs,apple-a16,arith-bcc-fusion,arith-cbz-fusion,bf16,bti,ccdp,ccpp,complxnum,crc,disable-latency-sched-heuristic,dit,dotprod,ecv,el2vmsa,el3,fgt,flagm,fp-armv8,fp16fml,fpac,fptoint,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,fuse-arith-logic,fuse-crypto-eor,fuse-csel,fuse-literals,hcx,i8mm,jsconv,lor,lse,lse2,mpam,neon,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,specrestrict,ssbs,store-pair-suppress,tlb-rmi,tracev8.4,uaops,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8a,vh,zcm,zcz,zcz-gp") },
+ { str_lit("apple-m4"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,altnzcv,am,amvs,apple-m4,arith-bcc-fusion,arith-cbz-fusion,bf16,bti,ccdp,ccpp,complxnum,crc,disable-latency-sched-heuristic,dit,dotprod,ecv,el2vmsa,el3,fgt,flagm,fp-armv8,fp16fml,fpac,fptoint,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,fuse-arith-logic,fuse-crypto-eor,fuse-csel,fuse-literals,hcx,i8mm,jsconv,lor,lse,lse2,mpam,neon,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,sme,sme-f64f64,sme-i16i64,sme2,specrestrict,tlb-rmi,tracev8.4,uaops,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8a,vh,wfxt,xs,zcm,zcz,zcz-gp") },
+ { str_lit("apple-s4"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,apple-a12,arith-bcc-fusion,arith-cbz-fusion,ccpp,complxnum,crc,disable-latency-sched-heuristic,el2vmsa,el3,fp-armv8,fullfp16,fuse-aes,fuse-crypto-eor,jsconv,lor,lse,neon,pan,pan-rwv,pauth,perfmon,ras,rcpc,rdm,sha2,store-pair-suppress,uaops,v8.1a,v8.2a,v8.3a,v8a,vh,zcm,zcz,zcz-gp") },
+ { str_lit("apple-s5"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,apple-a12,arith-bcc-fusion,arith-cbz-fusion,ccpp,complxnum,crc,disable-latency-sched-heuristic,el2vmsa,el3,fp-armv8,fullfp16,fuse-aes,fuse-crypto-eor,jsconv,lor,lse,neon,pan,pan-rwv,pauth,perfmon,ras,rcpc,rdm,sha2,store-pair-suppress,uaops,v8.1a,v8.2a,v8.3a,v8a,vh,zcm,zcz,zcz-gp") },
+ { str_lit("carmel"), str_lit("CONTEXTIDREL2,aes,carmel,ccpp,crc,el2vmsa,el3,fp-armv8,fullfp16,lor,lse,neon,pan,pan-rwv,ras,rdm,sha2,uaops,v8.1a,v8.2a,v8a,vh") },
+ { str_lit("cobalt-100"), str_lit("CONTEXTIDREL2,altnzcv,alu-lsl-fast,am,bf16,bti,ccdp,ccidx,ccpp,complxnum,crc,dit,dotprod,el2vmsa,el3,enable-select-opt,ete,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-adrp-add,fuse-aes,i8mm,jsconv,lor,lse,lse2,mpam,mte,neon,neoversen2,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,specrestrict,ssbs,sve,sve-bitperm,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8a,v9a,vh") },
+ { str_lit("cortex-a34"), str_lit("a35,aes,crc,el2vmsa,el3,fp-armv8,neon,perfmon,sha2,v8a") },
+ { str_lit("cortex-a35"), str_lit("a35,aes,crc,el2vmsa,el3,fp-armv8,neon,perfmon,sha2,v8a") },
+ { str_lit("cortex-a510"), str_lit("CONTEXTIDREL2,a510,altnzcv,am,bf16,bti,ccdp,ccidx,ccpp,complxnum,crc,dit,dotprod,el2vmsa,el3,ete,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-adrp-add,fuse-aes,i8mm,jsconv,lor,lse,lse2,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,specrestrict,ssbs,sve,sve-bitperm,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8a,v9a,vh") },
+ { str_lit("cortex-a520"), str_lit("CONTEXTIDREL2,a520,altnzcv,am,amvs,bf16,bti,ccdp,ccidx,ccpp,complxnum,crc,dit,dotprod,ecv,el2vmsa,el3,ete,fgt,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-adrp-add,fuse-aes,hcx,i8mm,jsconv,lor,lse,lse2,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,specrestrict,ssbs,sve,sve-bitperm,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8a,v9.1a,v9.2a,v9a,vh,wfxt,xs") },
+ { str_lit("cortex-a520ae"), str_lit("CONTEXTIDREL2,a520ae,altnzcv,am,amvs,bf16,bti,ccdp,ccidx,ccpp,complxnum,crc,dit,dotprod,ecv,el2vmsa,el3,ete,fgt,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-adrp-add,fuse-aes,hcx,i8mm,jsconv,lor,lse,lse2,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,specrestrict,ssbs,sve,sve-bitperm,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8a,v9.1a,v9.2a,v9a,vh,wfxt,xs") },
+ { str_lit("cortex-a53"), str_lit("a53,aes,balance-fp-ops,crc,el2vmsa,el3,fp-armv8,fuse-adrp-add,fuse-aes,neon,perfmon,sha2,use-postra-scheduler,v8a") },
+ { str_lit("cortex-a55"), str_lit("CONTEXTIDREL2,a55,aes,ccpp,crc,dotprod,el2vmsa,el3,fp-armv8,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,lor,lse,neon,pan,pan-rwv,perfmon,ras,rcpc,rdm,sha2,uaops,use-postra-scheduler,v8.1a,v8.2a,v8a,vh") },
+ { str_lit("cortex-a57"), str_lit("a57,addr-lsl-slow-14,aes,balance-fp-ops,crc,el2vmsa,el3,enable-select-opt,fp-armv8,fuse-adrp-add,fuse-aes,fuse-literals,neon,perfmon,predictable-select-expensive,sha2,use-postra-scheduler,v8a") },
+ { str_lit("cortex-a65"), str_lit("CONTEXTIDREL2,a65,aes,ccpp,crc,dotprod,el2vmsa,el3,enable-select-opt,fp-armv8,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,fuse-literals,lor,lse,neon,pan,pan-rwv,perfmon,predictable-select-expensive,ras,rcpc,rdm,sha2,ssbs,uaops,v8.1a,v8.2a,v8a,vh") },
+ { str_lit("cortex-a65ae"), str_lit("CONTEXTIDREL2,a65,aes,ccpp,crc,dotprod,el2vmsa,el3,enable-select-opt,fp-armv8,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,fuse-literals,lor,lse,neon,pan,pan-rwv,perfmon,predictable-select-expensive,ras,rcpc,rdm,sha2,ssbs,uaops,v8.1a,v8.2a,v8a,vh") },
+ { str_lit("cortex-a710"), str_lit("CONTEXTIDREL2,a710,altnzcv,alu-lsl-fast,am,bf16,bti,ccdp,ccidx,ccpp,cmp-bcc-fusion,complxnum,crc,dit,dotprod,el2vmsa,el3,enable-select-opt,ete,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-adrp-add,fuse-aes,i8mm,jsconv,lor,lse,lse2,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,specrestrict,ssbs,sve,sve-bitperm,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8a,v9a,vh") },
+ { str_lit("cortex-a715"), str_lit("CONTEXTIDREL2,a715,altnzcv,alu-lsl-fast,am,bf16,bti,ccdp,ccidx,ccpp,cmp-bcc-fusion,complxnum,crc,dit,dotprod,el2vmsa,el3,enable-select-opt,ete,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-adrp-add,fuse-aes,i8mm,jsconv,lor,lse,lse2,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,spe,specrestrict,ssbs,sve,sve-bitperm,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8a,v9a,vh") },
+ { str_lit("cortex-a72"), str_lit("a72,addr-lsl-slow-14,aes,crc,el2vmsa,el3,enable-select-opt,fp-armv8,fuse-adrp-add,fuse-aes,fuse-literals,neon,perfmon,predictable-select-expensive,sha2,v8a") },
+ { str_lit("cortex-a720"), str_lit("CONTEXTIDREL2,a720,altnzcv,alu-lsl-fast,am,amvs,bf16,bti,ccdp,ccidx,ccpp,cmp-bcc-fusion,complxnum,crc,dit,dotprod,ecv,el2vmsa,el3,enable-select-opt,ete,fgt,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-adrp-add,fuse-aes,hcx,i8mm,jsconv,lor,lse,lse2,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,spe,spe-eef,specrestrict,ssbs,sve,sve-bitperm,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8a,v9.1a,v9.2a,v9a,vh,wfxt,xs") },
+ { str_lit("cortex-a720ae"), str_lit("CONTEXTIDREL2,a720ae,altnzcv,alu-lsl-fast,am,amvs,bf16,bti,ccdp,ccidx,ccpp,cmp-bcc-fusion,complxnum,crc,dit,dotprod,ecv,el2vmsa,el3,enable-select-opt,ete,fgt,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-adrp-add,fuse-aes,hcx,i8mm,jsconv,lor,lse,lse2,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,spe,spe-eef,specrestrict,ssbs,sve,sve-bitperm,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8a,v9.1a,v9.2a,v9a,vh,wfxt,xs") },
+ { str_lit("cortex-a725"), str_lit("CONTEXTIDREL2,altnzcv,alu-lsl-fast,am,amvs,bf16,bti,ccdp,ccidx,ccpp,cmp-bcc-fusion,complxnum,cortex-a725,crc,dit,dotprod,ecv,el2vmsa,el3,enable-select-opt,ete,fgt,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-adrp-add,fuse-aes,hcx,i8mm,jsconv,lor,lse,lse2,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,spe,spe-eef,specrestrict,ssbs,sve,sve-bitperm,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8a,v9.1a,v9.2a,v9a,vh,wfxt,xs") },
+ { str_lit("cortex-a73"), str_lit("a73,addr-lsl-slow-14,aes,crc,el2vmsa,el3,enable-select-opt,fp-armv8,fuse-adrp-add,fuse-aes,neon,perfmon,predictable-select-expensive,sha2,v8a") },
+ { str_lit("cortex-a75"), str_lit("CONTEXTIDREL2,a75,addr-lsl-slow-14,aes,ccpp,crc,dotprod,el2vmsa,el3,enable-select-opt,fp-armv8,fullfp16,fuse-adrp-add,fuse-aes,lor,lse,neon,pan,pan-rwv,perfmon,predictable-select-expensive,ras,rcpc,rdm,sha2,uaops,v8.1a,v8.2a,v8a,vh") },
+ { str_lit("cortex-a76"), str_lit("CONTEXTIDREL2,a76,addr-lsl-slow-14,aes,alu-lsl-fast,ccpp,crc,dotprod,el2vmsa,el3,enable-select-opt,fp-armv8,fullfp16,fuse-adrp-add,fuse-aes,lor,lse,neon,pan,pan-rwv,perfmon,predictable-select-expensive,ras,rcpc,rdm,sha2,ssbs,uaops,v8.1a,v8.2a,v8a,vh") },
+ { str_lit("cortex-a76ae"), str_lit("CONTEXTIDREL2,a76,addr-lsl-slow-14,aes,alu-lsl-fast,ccpp,crc,dotprod,el2vmsa,el3,enable-select-opt,fp-armv8,fullfp16,fuse-adrp-add,fuse-aes,lor,lse,neon,pan,pan-rwv,perfmon,predictable-select-expensive,ras,rcpc,rdm,sha2,ssbs,uaops,v8.1a,v8.2a,v8a,vh") },
+ { str_lit("cortex-a77"), str_lit("CONTEXTIDREL2,a77,addr-lsl-slow-14,aes,alu-lsl-fast,ccpp,cmp-bcc-fusion,crc,dotprod,el2vmsa,el3,enable-select-opt,fp-armv8,fullfp16,fuse-adrp-add,fuse-aes,lor,lse,neon,pan,pan-rwv,perfmon,predictable-select-expensive,ras,rcpc,rdm,sha2,ssbs,uaops,v8.1a,v8.2a,v8a,vh") },
+ { str_lit("cortex-a78"), str_lit("CONTEXTIDREL2,a78,addr-lsl-slow-14,aes,alu-lsl-fast,ccpp,cmp-bcc-fusion,crc,dotprod,el2vmsa,el3,enable-select-opt,fp-armv8,fullfp16,fuse-adrp-add,fuse-aes,lor,lse,neon,pan,pan-rwv,perfmon,predictable-select-expensive,ras,rcpc,rdm,sha2,spe,ssbs,uaops,use-postra-scheduler,v8.1a,v8.2a,v8a,vh") },
+ { str_lit("cortex-a78ae"), str_lit("CONTEXTIDREL2,a78ae,addr-lsl-slow-14,aes,alu-lsl-fast,ccpp,cmp-bcc-fusion,crc,dotprod,el2vmsa,el3,enable-select-opt,fp-armv8,fullfp16,fuse-adrp-add,fuse-aes,lor,lse,neon,pan,pan-rwv,perfmon,predictable-select-expensive,ras,rcpc,rdm,sha2,spe,ssbs,uaops,use-postra-scheduler,v8.1a,v8.2a,v8a,vh") },
+ { str_lit("cortex-a78c"), str_lit("CONTEXTIDREL2,a78c,addr-lsl-slow-14,aes,alu-lsl-fast,ccpp,cmp-bcc-fusion,crc,dotprod,el2vmsa,el3,enable-select-opt,flagm,fp-armv8,fullfp16,fuse-adrp-add,fuse-aes,lor,lse,neon,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,ras,rcpc,rdm,sha2,spe,ssbs,uaops,use-postra-scheduler,v8.1a,v8.2a,v8a,vh") },
+ { str_lit("cortex-r82"), str_lit("CONTEXTIDREL2,ccdp,ccpp,complxnum,cortex-r82,crc,dit,dotprod,flagm,fp-armv8,fp16fml,fullfp16,jsconv,lse,neon,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,specrestrict,ssbs,tlb-rmi,tracev8.4,uaops,use-postra-scheduler,v8r") },
+ { str_lit("cortex-r82ae"), str_lit("CONTEXTIDREL2,ccdp,ccpp,complxnum,cortex-r82ae,crc,dit,dotprod,flagm,fp-armv8,fp16fml,fullfp16,jsconv,lse,neon,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,specrestrict,ssbs,tlb-rmi,tracev8.4,uaops,use-postra-scheduler,v8r") },
+ { str_lit("cortex-x1"), str_lit("CONTEXTIDREL2,addr-lsl-slow-14,aes,alu-lsl-fast,ccpp,cmp-bcc-fusion,cortex-x1,crc,dotprod,el2vmsa,el3,enable-select-opt,fp-armv8,fullfp16,fuse-adrp-add,fuse-aes,lor,lse,neon,pan,pan-rwv,perfmon,predictable-select-expensive,ras,rcpc,rdm,sha2,spe,ssbs,uaops,use-postra-scheduler,v8.1a,v8.2a,v8a,vh") },
+ { str_lit("cortex-x1c"), str_lit("CONTEXTIDREL2,addr-lsl-slow-14,aes,alu-lsl-fast,ccpp,cmp-bcc-fusion,cortex-x1,crc,dotprod,el2vmsa,el3,enable-select-opt,flagm,fp-armv8,fullfp16,fuse-adrp-add,fuse-aes,lor,lse,lse2,neon,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,ras,rcpc,rcpc-immo,rdm,sha2,spe,ssbs,uaops,use-postra-scheduler,v8.1a,v8.2a,v8a,vh") },
+ { str_lit("cortex-x2"), str_lit("CONTEXTIDREL2,altnzcv,alu-lsl-fast,am,bf16,bti,ccdp,ccidx,ccpp,cmp-bcc-fusion,complxnum,cortex-x2,crc,dit,dotprod,el2vmsa,el3,enable-select-opt,ete,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-adrp-add,fuse-aes,i8mm,jsconv,lor,lse,lse2,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,specrestrict,ssbs,sve,sve-bitperm,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-fixed-over-scalable-if-equal-cost,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8a,v9a,vh") },
+ { str_lit("cortex-x3"), str_lit("CONTEXTIDREL2,altnzcv,alu-lsl-fast,am,avoid-ldapur,bf16,bti,ccdp,ccidx,ccpp,complxnum,cortex-x3,crc,dit,dotprod,el2vmsa,el3,enable-select-opt,ete,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-adrp-add,fuse-aes,i8mm,jsconv,lor,lse,lse2,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,spe,specrestrict,ssbs,sve,sve-bitperm,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-fixed-over-scalable-if-equal-cost,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8a,v9a,vh") },
+ { str_lit("cortex-x4"), str_lit("CONTEXTIDREL2,altnzcv,alu-lsl-fast,am,amvs,avoid-ldapur,bf16,bti,ccdp,ccidx,ccpp,complxnum,cortex-x4,crc,dit,dotprod,ecv,el2vmsa,el3,enable-select-opt,ete,fgt,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-adrp-add,fuse-aes,hcx,i8mm,jsconv,lor,lse,lse2,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,spe,spe-eef,specrestrict,ssbs,sve,sve-bitperm,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-fixed-over-scalable-if-equal-cost,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8a,v9.1a,v9.2a,v9a,vh,wfxt,xs") },
+ { str_lit("cortex-x925"), str_lit("CONTEXTIDREL2,altnzcv,alu-lsl-fast,am,amvs,avoid-ldapur,bf16,bti,ccdp,ccidx,ccpp,complxnum,cortex-x925,crc,dit,dotprod,ecv,el2vmsa,el3,enable-select-opt,ete,fgt,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-adrp-add,fuse-aes,hcx,i8mm,jsconv,lor,lse,lse2,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,spe,spe-eef,specrestrict,ssbs,sve,sve-bitperm,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-fixed-over-scalable-if-equal-cost,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8a,v9.1a,v9.2a,v9a,vh,wfxt,xs") },
+ { str_lit("cyclone"), str_lit("aes,alternate-sextload-cvt-f32-pattern,apple-a7,arith-bcc-fusion,arith-cbz-fusion,disable-latency-sched-heuristic,el2vmsa,el3,fp-armv8,fuse-aes,fuse-crypto-eor,neon,perfmon,sha2,store-pair-suppress,v8a,zcm,zcz,zcz-fp-workaround,zcz-gp") },
+ { str_lit("exynos-m3"), str_lit("aes,alu-lsl-fast,crc,el2vmsa,el3,exynos-cheap-as-move,exynosm3,force-32bit-jump-tables,fp-armv8,fuse-address,fuse-adrp-add,fuse-aes,fuse-csel,fuse-literals,neon,perfmon,predictable-select-expensive,sha2,store-pair-suppress,use-postra-scheduler,v8a") },
+ { str_lit("exynos-m4"), str_lit("CONTEXTIDREL2,aes,alu-lsl-fast,arith-bcc-fusion,arith-cbz-fusion,ccpp,crc,dotprod,el2vmsa,el3,exynos-cheap-as-move,exynosm4,force-32bit-jump-tables,fp-armv8,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,fuse-arith-logic,fuse-csel,fuse-literals,lor,lse,neon,pan,pan-rwv,perfmon,ras,rdm,sha2,store-pair-suppress,uaops,use-postra-scheduler,v8.1a,v8.2a,v8a,vh,zcz,zcz-gp") },
+ { str_lit("exynos-m5"), str_lit("CONTEXTIDREL2,aes,alu-lsl-fast,arith-bcc-fusion,arith-cbz-fusion,ccpp,crc,dotprod,el2vmsa,el3,exynos-cheap-as-move,exynosm4,force-32bit-jump-tables,fp-armv8,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,fuse-arith-logic,fuse-csel,fuse-literals,lor,lse,neon,pan,pan-rwv,perfmon,ras,rdm,sha2,store-pair-suppress,uaops,use-postra-scheduler,v8.1a,v8.2a,v8a,vh,zcz,zcz-gp") },
+ { str_lit("falkor"), str_lit("aes,alu-lsl-fast,crc,el2vmsa,el3,falkor,fp-armv8,neon,perfmon,predictable-select-expensive,rdm,sha2,slow-strqro-store,store-pair-suppress,use-postra-scheduler,v8a,zcz,zcz-gp") },
+ { str_lit("fujitsu-monaka"), str_lit("CONTEXTIDREL2,aes,altnzcv,am,amvs,arith-bcc-fusion,bf16,bti,ccdp,ccidx,ccpp,clrbhb,complxnum,crc,dit,dotprod,ecv,el2vmsa,el3,enable-select-opt,ete,faminmax,fgt,flagm,fp-armv8,fp16fml,fp8,fp8dot2,fpac,fptoint,fujitsu-monaka,fullfp16,hbc,hcx,i8mm,jsconv,lor,ls64,lse,lse2,lut,mec,mops,mpam,neon,nmi,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,rand,ras,rcpc,rcpc-immo,rdm,rme,sb,sel2,sha2,sha3,sm4,specres2,specrestrict,ssbs,sve,sve-aes,sve-bitperm,sve2,sve2-sha3,sve2-sm4,tlb-rmi,tracev8.4,trbe,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8.8a,v8a,v9.1a,v9.2a,v9.3a,v9a,vh,wfxt,xs") },
+ { str_lit("generic"), str_lit("enable-select-opt,ete,fp-armv8,fuse-adrp-add,fuse-aes,neon,trbe,use-postra-scheduler") },
+ { str_lit("grace"), str_lit("CONTEXTIDREL2,altnzcv,alu-lsl-fast,am,avoid-ldapur,bf16,bti,ccdp,ccidx,ccpp,cmp-bcc-fusion,complxnum,crc,dit,dotprod,el2vmsa,el3,enable-select-opt,ete,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-adrp-add,fuse-aes,i8mm,jsconv,lor,lse,lse2,mpam,mte,neon,neoversev2,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,rand,ras,rcpc,rcpc-immo,rdm,sb,sel2,spe,specrestrict,ssbs,sve,sve-bitperm,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-fixed-over-scalable-if-equal-cost,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8a,v9a,vh") },
+ { str_lit("kryo"), str_lit("aes,alu-lsl-fast,crc,el2vmsa,el3,fp-armv8,kryo,neon,perfmon,predictable-select-expensive,sha2,store-pair-suppress,use-postra-scheduler,v8a,zcz,zcz-gp") },
+ { str_lit("neoverse-512tvb"), str_lit("CONTEXTIDREL2,aes,alu-lsl-fast,am,bf16,ccdp,ccidx,ccpp,complxnum,crc,dit,dotprod,el2vmsa,el3,enable-select-opt,flagm,fp-armv8,fp16fml,fullfp16,fuse-adrp-add,fuse-aes,i8mm,jsconv,lor,lse,lse2,mpam,neon,neoverse512tvb,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,rand,ras,rcpc,rcpc-immo,rdm,sel2,sha2,sha3,sm4,spe,ssbs,sve,tlb-rmi,tracev8.4,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8a,vh") },
+ { str_lit("neoverse-e1"), str_lit("CONTEXTIDREL2,aes,ccpp,crc,dotprod,el2vmsa,el3,fp-armv8,fullfp16,fuse-adrp-add,fuse-aes,lor,lse,neon,neoversee1,pan,pan-rwv,perfmon,ras,rcpc,rdm,sha2,ssbs,uaops,use-postra-scheduler,v8.1a,v8.2a,v8a,vh") },
+ { str_lit("neoverse-n1"), str_lit("CONTEXTIDREL2,addr-lsl-slow-14,aes,alu-lsl-fast,ccpp,crc,dotprod,el2vmsa,el3,enable-select-opt,fp-armv8,fullfp16,fuse-adrp-add,fuse-aes,lor,lse,neon,neoversen1,pan,pan-rwv,perfmon,predictable-select-expensive,ras,rcpc,rdm,sha2,spe,ssbs,uaops,use-postra-scheduler,v8.1a,v8.2a,v8a,vh") },
+ { str_lit("neoverse-n2"), str_lit("CONTEXTIDREL2,altnzcv,alu-lsl-fast,am,bf16,bti,ccdp,ccidx,ccpp,complxnum,crc,dit,dotprod,el2vmsa,el3,enable-select-opt,ete,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-adrp-add,fuse-aes,i8mm,jsconv,lor,lse,lse2,mpam,mte,neon,neoversen2,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,specrestrict,ssbs,sve,sve-bitperm,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8a,v9a,vh") },
+ { str_lit("neoverse-n3"), str_lit("CONTEXTIDREL2,altnzcv,alu-lsl-fast,am,amvs,bf16,bti,ccdp,ccidx,ccpp,complxnum,crc,dit,dotprod,ecv,el2vmsa,el3,enable-select-opt,ete,fgt,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-adrp-add,fuse-aes,hcx,i8mm,jsconv,lor,lse,lse2,mpam,mte,neon,neoversen3,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,rand,ras,rcpc,rcpc-immo,rdm,sb,sel2,spe,spe-eef,specrestrict,ssbs,sve,sve-bitperm,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8a,v9.1a,v9.2a,v9a,vh,wfxt,xs") },
+ { str_lit("neoverse-v1"), str_lit("CONTEXTIDREL2,addr-lsl-slow-14,aes,alu-lsl-fast,am,bf16,ccdp,ccidx,ccpp,complxnum,crc,dit,dotprod,el2vmsa,el3,enable-select-opt,flagm,fp-armv8,fp16fml,fullfp16,fuse-adrp-add,fuse-aes,i8mm,jsconv,lor,lse,lse2,mpam,neon,neoversev1,no-sve-fp-ld1r,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,rand,ras,rcpc,rcpc-immo,rdm,sel2,sha2,sha3,sm4,spe,ssbs,sve,tlb-rmi,tracev8.4,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8a,vh") },
+ { str_lit("neoverse-v2"), str_lit("CONTEXTIDREL2,altnzcv,alu-lsl-fast,am,avoid-ldapur,bf16,bti,ccdp,ccidx,ccpp,cmp-bcc-fusion,complxnum,crc,dit,dotprod,el2vmsa,el3,enable-select-opt,ete,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-adrp-add,fuse-aes,i8mm,jsconv,lor,lse,lse2,mpam,mte,neon,neoversev2,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,rand,ras,rcpc,rcpc-immo,rdm,sb,sel2,spe,specrestrict,ssbs,sve,sve-bitperm,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-fixed-over-scalable-if-equal-cost,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8a,v9a,vh") },
+ { str_lit("neoverse-v3"), str_lit("CONTEXTIDREL2,altnzcv,alu-lsl-fast,am,amvs,avoid-ldapur,bf16,brbe,bti,ccdp,ccidx,ccpp,complxnum,crc,dit,dotprod,ecv,el2vmsa,el3,enable-select-opt,ete,fgt,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-adrp-add,fuse-aes,hcx,i8mm,jsconv,lor,ls64,lse,lse2,mpam,mte,neon,neoversev3,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,rand,ras,rcpc,rcpc-immo,rdm,rme,sb,sel2,spe,spe-eef,specrestrict,ssbs,sve,sve-bitperm,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8a,v9.1a,v9.2a,v9a,vh,wfxt,xs") },
+ { str_lit("neoverse-v3ae"), str_lit("CONTEXTIDREL2,altnzcv,alu-lsl-fast,am,amvs,avoid-ldapur,bf16,brbe,bti,ccdp,ccidx,ccpp,complxnum,crc,dit,dotprod,ecv,el2vmsa,el3,enable-select-opt,ete,fgt,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-adrp-add,fuse-aes,hcx,i8mm,jsconv,lor,ls64,lse,lse2,mpam,mte,neon,neoversev3AE,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,rand,ras,rcpc,rcpc-immo,rdm,rme,sb,sel2,spe,spe-eef,specrestrict,ssbs,sve,sve-bitperm,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8a,v9.1a,v9.2a,v9a,vh,wfxt,xs") },
+ { str_lit("oryon-1"), str_lit("CONTEXTIDREL2,aes,altnzcv,am,amvs,bf16,bti,ccdp,ccidx,ccpp,complxnum,crc,dit,dotprod,ecv,el2vmsa,el3,enable-select-opt,fgt,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,fuse-crypto-eor,i8mm,jsconv,lor,lse,lse2,mpam,neon,nv,oryon-1,pan,pan-rwv,pauth,perfmon,predres,rand,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,sm4,spe,specrestrict,ssbs,tlb-rmi,tracev8.4,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8a,vh") },
+ { str_lit("saphira"), str_lit("CONTEXTIDREL2,aes,alu-lsl-fast,am,ccidx,ccpp,complxnum,crc,dit,dotprod,el2vmsa,el3,flagm,fp-armv8,jsconv,lor,lse,lse2,mpam,neon,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,ras,rcpc,rcpc-immo,rdm,saphira,sel2,sha2,spe,store-pair-suppress,tlb-rmi,tracev8.4,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8a,vh,zcz,zcz-gp") },
+ { str_lit("thunderx"), str_lit("aes,crc,el2vmsa,el3,fp-armv8,neon,perfmon,predictable-select-expensive,sha2,store-pair-suppress,thunderx,use-postra-scheduler,v8a") },
+ { str_lit("thunderx2t99"), str_lit("CONTEXTIDREL2,aes,aggressive-fma,arith-bcc-fusion,crc,el2vmsa,el3,fp-armv8,lor,lse,neon,pan,predictable-select-expensive,rdm,sha2,store-pair-suppress,thunderx2t99,use-postra-scheduler,v8.1a,v8a,vh") },
+ { str_lit("thunderx3t110"), str_lit("CONTEXTIDREL2,aes,aggressive-fma,arith-bcc-fusion,balance-fp-ops,ccidx,ccpp,complxnum,crc,el2vmsa,el3,fp-armv8,jsconv,lor,lse,neon,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,ras,rcpc,rdm,sha2,store-pair-suppress,strict-align,thunderx3t110,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8a,vh") },
+ { str_lit("thunderxt81"), str_lit("aes,crc,el2vmsa,el3,fp-armv8,neon,perfmon,predictable-select-expensive,sha2,store-pair-suppress,thunderxt81,use-postra-scheduler,v8a") },
+ { str_lit("thunderxt83"), str_lit("aes,crc,el2vmsa,el3,fp-armv8,neon,perfmon,predictable-select-expensive,sha2,store-pair-suppress,thunderxt83,use-postra-scheduler,v8a") },
+ { str_lit("thunderxt88"), str_lit("aes,crc,el2vmsa,el3,fp-armv8,neon,perfmon,predictable-select-expensive,sha2,store-pair-suppress,thunderxt88,use-postra-scheduler,v8a") },
+ { str_lit("tsv110"), str_lit("CONTEXTIDREL2,aes,ccpp,complxnum,crc,dotprod,el2vmsa,el3,fp-armv8,fp16fml,fullfp16,fuse-aes,jsconv,lor,lse,neon,pan,pan-rwv,perfmon,ras,rdm,sha2,spe,store-pair-suppress,tsv110,uaops,use-postra-scheduler,v8.1a,v8.2a,v8a,vh") },
+ // TargetArch_wasm32:
+ { str_lit("bleeding-edge"), str_lit("atomics,bulk-memory,bulk-memory-opt,call-indirect-overlong,exception-handling,extended-const,fp16,multimemory,multivalue,mutable-globals,nontrapping-fptoint,reference-types,relaxed-simd,sign-ext,simd128,tail-call") },
+ { str_lit("generic"), str_lit("bulk-memory,bulk-memory-opt,call-indirect-overlong,multivalue,mutable-globals,nontrapping-fptoint,reference-types,sign-ext") },
+ { str_lit("lime1"), str_lit("bulk-memory-opt,call-indirect-overlong,extended-const,multivalue,mutable-globals,nontrapping-fptoint,sign-ext") },
+ { str_lit("mvp"), str_lit("") },
+ // TargetArch_wasm64p32:
+ { str_lit("bleeding-edge"), str_lit("atomics,bulk-memory,bulk-memory-opt,call-indirect-overlong,exception-handling,extended-const,fp16,multimemory,multivalue,mutable-globals,nontrapping-fptoint,reference-types,relaxed-simd,sign-ext,simd128,tail-call") },
+ { str_lit("generic"), str_lit("bulk-memory,bulk-memory-opt,call-indirect-overlong,multivalue,mutable-globals,nontrapping-fptoint,reference-types,sign-ext") },
+ { str_lit("lime1"), str_lit("bulk-memory-opt,call-indirect-overlong,extended-const,multivalue,mutable-globals,nontrapping-fptoint,sign-ext") },
+ { str_lit("mvp"), str_lit("") },
+ // TargetArch_riscv64:
+ { str_lit("generic"), str_lit("64bit,i,optimized-nf2-segment-load-store") },
+ { str_lit("generic-rv32"), str_lit("32bit,i,optimized-nf2-segment-load-store") },
+ { str_lit("generic-rv64"), str_lit("64bit,i,optimized-nf2-segment-load-store") },
+ { str_lit("mips-p8700"), str_lit("64bit,a,c,d,f,i,m,mips-p8700,xmipscmove,xmipslsp,zaamo,zalrsc,zba,zbb,zicsr,zifencei,zmmul") },
+ { str_lit("rocket"), str_lit("") },
+ { str_lit("rocket-rv32"), str_lit("32bit,i,zicsr,zifencei") },
+ { str_lit("rocket-rv64"), str_lit("64bit,i,zicsr,zifencei") },
+ { str_lit("rp2350-hazard3"), str_lit("32bit,a,c,i,m,zaamo,zalrsc,zba,zbb,zbkb,zbs,zca,zcb,zcmp,zicsr,zifencei,zmmul") },
+ { str_lit("sifive-7-series"), str_lit("no-default-unroll,short-forward-branch-opt,sifive7,use-postra-scheduler") },
+ { str_lit("sifive-e20"), str_lit("32bit,c,i,m,zicsr,zifencei,zmmul") },
+ { str_lit("sifive-e21"), str_lit("32bit,a,c,i,m,zaamo,zalrsc,zicsr,zifencei,zmmul") },
+ { str_lit("sifive-e24"), str_lit("32bit,a,c,f,i,m,zaamo,zalrsc,zicsr,zifencei,zmmul") },
+ { str_lit("sifive-e31"), str_lit("32bit,a,c,i,m,zaamo,zalrsc,zicsr,zifencei,zmmul") },
+ { str_lit("sifive-e34"), str_lit("32bit,a,c,f,i,m,zaamo,zalrsc,zicsr,zifencei,zmmul") },
+ { str_lit("sifive-e76"), str_lit("32bit,a,c,f,i,m,no-default-unroll,short-forward-branch-opt,sifive7,use-postra-scheduler,zaamo,zalrsc,zicsr,zifencei,zmmul") },
+ { str_lit("sifive-p450"), str_lit("64bit,a,auipc-addi-fusion,b,c,conditional-cmv-fusion,d,f,i,lui-addi-fusion,m,no-default-unroll,unaligned-scalar-mem,unaligned-vector-mem,use-postra-scheduler,za64rs,zaamo,zalrsc,zba,zbb,zbs,zfhmin,zic64b,zicbom,zicbop,zicboz,ziccamoa,ziccif,zicclsm,ziccrse,zicntr,zicsr,zifencei,zihintntl,zihintpause,zihpm,zkt,zmmul") },
+ { str_lit("sifive-p470"), str_lit("64bit,a,auipc-addi-fusion,b,c,conditional-cmv-fusion,d,f,i,lui-addi-fusion,m,no-default-unroll,no-sink-splat-operands,unaligned-scalar-mem,unaligned-vector-mem,use-postra-scheduler,v,vxrm-pipeline-flush,xsifivecdiscarddlone,xsifivecflushdlone,za64rs,zaamo,zalrsc,zba,zbb,zbs,zfhmin,zic64b,zicbom,zicbop,zicboz,ziccamoa,ziccif,zicclsm,ziccrse,zicntr,zicsr,zifencei,zihintntl,zihintpause,zihpm,zkt,zmmul,zvbb,zvbc,zve32f,zve32x,zve64d,zve64f,zve64x,zvkb,zvkg,zvkn,zvknc,zvkned,zvkng,zvknhb,zvks,zvksc,zvksed,zvksg,zvksh,zvkt,zvl128b,zvl32b,zvl64b") },
+ { str_lit("sifive-p550"), str_lit("64bit,a,auipc-addi-fusion,c,conditional-cmv-fusion,d,f,i,lui-addi-fusion,m,no-default-unroll,use-postra-scheduler,zaamo,zalrsc,zba,zbb,zicsr,zifencei,zmmul") },
+ { str_lit("sifive-p670"), str_lit("64bit,a,auipc-addi-fusion,b,c,conditional-cmv-fusion,d,f,i,lui-addi-fusion,m,no-default-unroll,no-sink-splat-operands,unaligned-scalar-mem,unaligned-vector-mem,use-postra-scheduler,v,vxrm-pipeline-flush,za64rs,zaamo,zalrsc,zba,zbb,zbs,zfhmin,zic64b,zicbom,zicbop,zicboz,ziccamoa,ziccif,zicclsm,ziccrse,zicntr,zicsr,zifencei,zihintntl,zihintpause,zihpm,zkt,zmmul,zvbb,zvbc,zve32f,zve32x,zve64d,zve64f,zve64x,zvkb,zvkg,zvkn,zvknc,zvkned,zvkng,zvknhb,zvks,zvksc,zvksed,zvksg,zvksh,zvkt,zvl128b,zvl32b,zvl64b") },
+ { str_lit("sifive-s21"), str_lit("64bit,a,c,i,m,zaamo,zalrsc,zicsr,zifencei,zmmul") },
+ { str_lit("sifive-s51"), str_lit("64bit,a,c,i,m,zaamo,zalrsc,zicsr,zifencei,zmmul") },
+ { str_lit("sifive-s54"), str_lit("64bit,a,c,d,f,i,m,zaamo,zalrsc,zicsr,zifencei,zmmul") },
+ { str_lit("sifive-s76"), str_lit("64bit,a,c,d,f,i,m,no-default-unroll,short-forward-branch-opt,sifive7,use-postra-scheduler,zaamo,zalrsc,zicsr,zifencei,zihintpause,zmmul") },
+ { str_lit("sifive-u54"), str_lit("64bit,a,c,d,f,i,m,zaamo,zalrsc,zicsr,zifencei,zmmul") },
+ { str_lit("sifive-u74"), str_lit("64bit,a,c,d,f,i,m,no-default-unroll,short-forward-branch-opt,sifive7,use-postra-scheduler,zaamo,zalrsc,zicsr,zifencei,zmmul") },
+ { str_lit("sifive-x280"), str_lit("64bit,a,c,d,dlen-factor-2,f,i,m,no-default-unroll,optimized-nf2-segment-load-store,optimized-zero-stride-load,short-forward-branch-opt,sifive7,use-postra-scheduler,v,zaamo,zalrsc,zba,zbb,zfh,zfhmin,zicsr,zifencei,zmmul,zve32f,zve32x,zve64d,zve64f,zve64x,zvfh,zvfhmin,zvl128b,zvl256b,zvl32b,zvl512b,zvl64b") },
+ { str_lit("spacemit-x60"), str_lit("64bit,a,b,c,d,dlen-factor-2,f,i,m,optimized-nf2-segment-load-store,optimized-nf3-segment-load-store,optimized-nf4-segment-load-store,ssccptr,sscofpmf,sscounterenw,sstc,sstvala,sstvecd,svade,svbare,svinval,svnapot,svpbmt,unaligned-scalar-mem,v,vxrm-pipeline-flush,za64rs,zaamo,zalrsc,zba,zbb,zbc,zbkc,zbs,zfh,zfhmin,zic64b,zicbom,zicbop,zicboz,ziccamoa,ziccif,zicclsm,ziccrse,zicntr,zicond,zicsr,zifencei,zihintpause,zihpm,zkt,zmmul,zve32f,zve32x,zve64d,zve64f,zve64x,zvfh,zvfhmin,zvkt,zvl128b,zvl256b,zvl32b,zvl64b") },
+ { str_lit("syntacore-scr1-base"), str_lit("32bit,c,i,no-default-unroll,zicsr,zifencei") },
+ { str_lit("syntacore-scr1-max"), str_lit("32bit,c,i,m,no-default-unroll,zicsr,zifencei,zmmul") },
+ { str_lit("syntacore-scr3-rv32"), str_lit("32bit,c,i,m,no-default-unroll,use-postra-scheduler,zicsr,zifencei,zmmul") },
+ { str_lit("syntacore-scr3-rv64"), str_lit("64bit,a,c,i,m,no-default-unroll,use-postra-scheduler,zaamo,zalrsc,zicsr,zifencei,zmmul") },
+ { str_lit("syntacore-scr4-rv32"), str_lit("32bit,c,d,f,i,m,no-default-unroll,use-postra-scheduler,zicsr,zifencei,zmmul") },
+ { str_lit("syntacore-scr4-rv64"), str_lit("64bit,a,c,d,f,i,m,no-default-unroll,use-postra-scheduler,zaamo,zalrsc,zicsr,zifencei,zmmul") },
+ { str_lit("syntacore-scr5-rv32"), str_lit("32bit,a,c,d,f,i,m,no-default-unroll,use-postra-scheduler,zaamo,zalrsc,zicsr,zifencei,zmmul") },
+ { str_lit("syntacore-scr5-rv64"), str_lit("64bit,a,c,d,f,i,m,no-default-unroll,use-postra-scheduler,zaamo,zalrsc,zicsr,zifencei,zmmul") },
+ { str_lit("syntacore-scr7"), str_lit("64bit,a,c,d,f,i,m,no-default-unroll,use-postra-scheduler,v,zaamo,zalrsc,zba,zbb,zbc,zbkb,zbkc,zbkx,zbs,zicsr,zifencei,zkn,zknd,zkne,zknh,zmmul,zve32f,zve32x,zve64d,zve64f,zve64x,zvl128b,zvl32b,zvl64b") },
+ { str_lit("tt-ascalon-d8"), str_lit("64bit,a,b,c,d,f,h,i,m,no-default-unroll,optimized-zero-stride-load,sha,shcounterenw,shgatpa,shtvala,shvsatpa,shvstvala,shvstvecd,smaia,ssaia,ssccptr,sscofpmf,sscounterenw,ssnpm,ssstateen,ssstrict,sstc,sstvala,sstvecd,ssu64xl,supm,svade,svbare,svinval,svnapot,svpbmt,unaligned-scalar-mem,unaligned-vector-mem,use-postra-scheduler,v,za64rs,zaamo,zalrsc,zawrs,zba,zbb,zbs,zca,zcb,zcmop,zfa,zfbfmin,zfh,zfhmin,zic64b,zicbom,zicbop,zicboz,ziccamoa,ziccif,zicclsm,ziccrse,zicntr,zicond,zicsr,zifencei,zihintntl,zihintpause,zihpm,zimop,zkt,zmmul,zvbb,zvbc,zve32f,zve32x,zve64d,zve64f,zve64x,zvfbfmin,zvfbfwma,zvfh,zvfhmin,zvkb,zvkg,zvkn,zvkned,zvkng,zvknhb,zvkt,zvl128b,zvl256b,zvl32b,zvl64b") },
+ { str_lit("veyron-v1"), str_lit("64bit,a,auipc-addi-fusion,c,d,f,i,ld-add-fusion,lui-addi-fusion,m,shifted-zextw-fusion,ventana-veyron,xventanacondops,zaamo,zalrsc,zba,zbb,zbc,zbs,zexth-fusion,zextw-fusion,zicbom,zicbop,zicboz,zicntr,zicsr,zifencei,zihintpause,zihpm,zmmul") },
+ { str_lit("xiangshan-nanhu"), str_lit("64bit,a,c,d,f,i,m,no-default-unroll,shifted-zextw-fusion,svinval,zaamo,zalrsc,zba,zbb,zbc,zbkb,zbkc,zbkx,zbs,zexth-fusion,zextw-fusion,zicbom,zicboz,zicsr,zifencei,zkn,zknd,zkne,zknh,zksed,zksh,zmmul") },
+};
+#else
// Generated with the featuregen script in `misc/featuregen`
gb_global String target_microarch_list[TargetArch_COUNT] = {
// TargetArch_Invalid:
@@ -514,3 +1072,4 @@ gb_global MicroarchFeatureList microarch_features_list[] = {
{ str_lit("veyron-v1"), str_lit("64bit,a,auipc-addi-fusion,c,d,f,ld-add-fusion,lui-addi-fusion,m,shifted-zextw-fusion,ventana-veyron,xventanacondops,zba,zbb,zbc,zbs,zexth-fusion,zextw-fusion,zicbom,zicbop,zicboz,zicntr,zicsr,zifencei,zihintpause,zihpm") },
{ str_lit("xiangshan-nanhu"), str_lit("64bit,a,c,d,f,m,svinval,zba,zbb,zbc,zbkb,zbkc,zbkx,zbs,zicbom,zicboz,zicsr,zifencei,zkn,zknd,zkne,zknh,zksed,zksh") },
};
+#endif
diff --git a/src/bundle_command.cpp b/src/bundle_command.cpp
new file mode 100644
index 000000000..cd0cd589f
--- /dev/null
+++ b/src/bundle_command.cpp
@@ -0,0 +1,212 @@
+i32 bundle_android(String init_directory);
+
+i32 bundle(String init_directory) {
+ switch (build_context.command_kind) {
+ case Command_bundle_android:
+ return bundle_android(init_directory);
+ }
+ gb_printf_err("Unknown odin package <platform>\n");
+ return 1;
+}
+
+
+i32 bundle_android(String original_init_directory) {
+ TEMPORARY_ALLOCATOR_GUARD();
+
+ i32 result = 0;
+ init_android_values(/*with_sdk*/true);
+
+ bool init_directory_ok = false;
+ String init_directory = path_to_fullpath(temporary_allocator(), original_init_directory, &init_directory_ok);
+ if (!init_directory_ok) {
+ gb_printf_err("Error: '%.*s' is not a valid directory", LIT(original_init_directory));
+ return 1;
+ }
+ init_directory = normalize_path(temporary_allocator(), init_directory, NIX_SEPARATOR_STRING);
+
+ int const ODIN_ANDROID_API_LEVEL = build_context.ODIN_ANDROID_API_LEVEL;
+
+ String android_sdk_build_tools = concatenate3_strings(temporary_allocator(),
+ build_context.ODIN_ANDROID_SDK, str_lit("build-tools"), NIX_SEPARATOR_STRING);
+
+ Array<FileInfo> list = {};
+ ReadDirectoryError rd_err = read_directory(android_sdk_build_tools, &list);
+ defer (array_free(&list));
+
+ switch (rd_err) {
+ case ReadDirectory_InvalidPath:
+ gb_printf_err("Invalid path: %.*s\n", LIT(android_sdk_build_tools));
+ return 1;
+ case ReadDirectory_NotExists:
+ gb_printf_err("Path does not exist: %.*s\n", LIT(android_sdk_build_tools));
+ return 1;
+ case ReadDirectory_Permission:
+ gb_printf_err("Unknown error whilst reading path %.*s\n", LIT(android_sdk_build_tools));
+ return 1;
+ case ReadDirectory_NotDir:
+ gb_printf_err("Expected a directory for a package, got a file: %.*s\n", LIT(android_sdk_build_tools));
+ return 1;
+ case ReadDirectory_Empty:
+ gb_printf_err("Empty directory: %.*s\n", LIT(android_sdk_build_tools));
+ return 1;
+ case ReadDirectory_Unknown:
+ gb_printf_err("Unknown error whilst reading path %.*s\n", LIT(android_sdk_build_tools));
+ return 1;
+ }
+
+ auto possible_valid_dirs = array_make<FileInfo>(heap_allocator(), 0, list.count);
+ defer (array_free(&possible_valid_dirs));
+
+
+ for (FileInfo fi : list) if (fi.is_dir) {
+ bool all_numbers = true;
+ for (isize i = 0; i < fi.name.len; i++) {
+ u8 c = fi.name[i];
+ if ('0' <= c && c <= '9') {
+ // true
+ } else if (i == 0) {
+ all_numbers = false;
+ } else if (c == '.') {
+ break;
+ } else {
+ all_numbers = false;
+ }
+ }
+
+ if (all_numbers) {
+ array_add(&possible_valid_dirs, fi);
+ }
+ }
+
+ if (possible_valid_dirs.count == 0) {
+ gb_printf_err("Unable to find any Android SDK/API Level in %.*s\n", LIT(android_sdk_build_tools));
+ return 1;
+ }
+
+ int *dir_numbers = gb_alloc_array(temporary_allocator(), int, possible_valid_dirs.count);
+
+ char buf[1024] = {};
+ for_array(i, possible_valid_dirs) {
+ FileInfo fi = possible_valid_dirs[i];
+ isize n = gb_min(gb_size_of(buf)-1, fi.name.len);
+ memcpy(buf, fi.name.text, n);
+ buf[n] = 0;
+
+ dir_numbers[i] = atoi(buf);
+ }
+
+ isize closest_number_idx = -1;
+ for (isize i = 0; i < possible_valid_dirs.count; i++) {
+ if (dir_numbers[i] >= ODIN_ANDROID_API_LEVEL) {
+ if (closest_number_idx < 0) {
+ closest_number_idx = i;
+ } else if (dir_numbers[i] < dir_numbers[closest_number_idx]) {
+ closest_number_idx = i;
+ }
+ }
+ }
+
+ if (closest_number_idx < 0) {
+ gb_printf_err("Unable to find any Android SDK/API Level in %.*s meeting the minimum API level of %d\n", LIT(android_sdk_build_tools), ODIN_ANDROID_API_LEVEL);
+ return 1;
+ }
+
+ String api_number = possible_valid_dirs[closest_number_idx].name;
+
+ android_sdk_build_tools = concatenate_strings(temporary_allocator(), android_sdk_build_tools, api_number);
+ String android_sdk_platforms = concatenate_strings(temporary_allocator(),
+ build_context.ODIN_ANDROID_SDK,
+ make_string_c(gb_bprintf("platforms/android-%d/", dir_numbers[closest_number_idx]))
+ );
+
+ android_sdk_build_tools = normalize_path(temporary_allocator(), android_sdk_build_tools, NIX_SEPARATOR_STRING);
+ android_sdk_platforms = normalize_path(temporary_allocator(), android_sdk_platforms, NIX_SEPARATOR_STRING);
+
+ gbString cmd = gb_string_make(heap_allocator(), "");
+ defer (gb_string_free(cmd));
+
+
+ String output_filename = str_lit("test");
+ String output_apk = path_remove_extension(output_filename);
+
+ TIME_SECTION("Android aapt");
+ {
+ TEMPORARY_ALLOCATOR_GUARD();
+ gb_string_clear(cmd);
+
+ String manifest = concatenate_strings(temporary_allocator(), init_directory, str_lit("AndroidManifest.xml"));
+
+ cmd = gb_string_append_length(cmd, android_sdk_build_tools.text, android_sdk_build_tools.len);
+ cmd = gb_string_appendc(cmd, "aapt");
+ cmd = gb_string_appendc(cmd, " package -f");
+ cmd = gb_string_append_fmt(cmd, " -M \"%.*s\"", LIT(manifest));
+ cmd = gb_string_append_fmt(cmd, " -I \"%.*sandroid.jar\"", LIT(android_sdk_platforms));
+ cmd = gb_string_append_fmt(cmd, " -F \"%.*s.apk-build\"", LIT(output_apk));
+
+ String resources_dir = concatenate_strings(temporary_allocator(), init_directory, str_lit("res"));
+ if (gb_file_exists((const char *)resources_dir.text)) {
+ cmd = gb_string_append_fmt(cmd, " -S \"%.*s\"", LIT(resources_dir));
+ }
+
+ String assets_dir = concatenate_strings(temporary_allocator(), init_directory, str_lit("assets"));
+ if (gb_file_exists((const char *)assets_dir.text)) {
+ cmd = gb_string_append_fmt(cmd, " -A \"%.*s\"", LIT(assets_dir));
+ }
+
+ String lib_dir = concatenate_strings(temporary_allocator(), init_directory, str_lit("lib"));
+ if (gb_file_exists((const char *)lib_dir.text)) {
+ cmd = gb_string_append_fmt(cmd, " \"%.*s\"", LIT(lib_dir));
+ }
+
+ result = system_exec_command_line_app("android-aapt", cmd);
+ if (result) {
+ return result;
+ }
+ }
+
+ TIME_SECTION("Android zipalign");
+ {
+ TEMPORARY_ALLOCATOR_GUARD();
+ gb_string_clear(cmd);
+
+ cmd = gb_string_append_length(cmd, android_sdk_build_tools.text, android_sdk_build_tools.len);
+ cmd = gb_string_appendc(cmd, "zipalign");
+ cmd = gb_string_appendc(cmd, " -f 4");
+ cmd = gb_string_append_fmt(cmd, " \"%.*s.apk-build\" \"%.*s.apk\"", LIT(output_apk), LIT(output_apk));
+
+ result = system_exec_command_line_app("android-zipalign", cmd);
+ if (result) {
+ return result;
+ }
+ }
+
+ TIME_SECTION("Android apksigner");
+ {
+ TEMPORARY_ALLOCATOR_GUARD();
+ gb_string_clear(cmd);
+
+ cmd = gb_string_append_length(cmd, android_sdk_build_tools.text, android_sdk_build_tools.len);
+ cmd = gb_string_appendc(cmd, "apksigner");
+ cmd = gb_string_appendc(cmd, " sign");
+
+ String keystore = normalize_path(temporary_allocator(), build_context.android_keystore, NIX_SEPARATOR_STRING);
+ keystore = substring(keystore, 0, keystore.len - 1);
+ cmd = gb_string_append_fmt(cmd, " --ks \"%.*s\"", LIT(keystore));
+
+ if (build_context.android_keystore_alias.len != 0) {
+ cmd = gb_string_append_fmt(cmd, " --ks-key-alias \"%.*s\"", LIT(build_context.android_keystore_alias));
+ }
+ if (build_context.android_keystore_password.len != 0) {
+ cmd = gb_string_append_fmt(cmd, " --ks-pass pass:\"%.*s\"", LIT(build_context.android_keystore_password));
+ }
+
+ cmd = gb_string_append_fmt(cmd, " \"%.*s.apk\"", LIT(output_apk));
+
+ result = system_exec_command_line_app("android-apksigner", cmd);
+ if (result) {
+ return result;
+ }
+ }
+
+ return 0;
+}
diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp
index ea902387b..9f9787b61 100644
--- a/src/check_builtin.cpp
+++ b/src/check_builtin.cpp
@@ -41,6 +41,7 @@ gb_global BuiltinTypeIsProc *builtin_type_is_procs[BuiltinProc__type_simple_bool
is_type_enum,
is_type_proc,
is_type_bit_set,
+ is_type_bit_field,
is_type_simd_vector,
is_type_matrix,
@@ -147,6 +148,11 @@ gb_internal bool does_require_msgSend_stret(Type *return_type) {
if (return_type == nullptr) {
return false;
}
+
+ if (build_context.metrics.os != TargetOs_darwin) {
+ return false;
+ }
+
if (build_context.metrics.arch == TargetArch_i386 || build_context.metrics.arch == TargetArch_amd64) {
i64 struct_limit = type_size_of(t_uintptr) << 1;
return type_size_of(return_type) > struct_limit;
@@ -223,9 +229,9 @@ gb_internal void add_objc_proc_type(CheckerContext *c, Ast *call, Type *return_t
data.kind = kind;
data.proc_type = alloc_type_proc(scope, params, param_types.count, results, results->Tuple.variables.count, false, ProcCC_CDecl);
- mutex_lock(&c->info->objc_types_mutex);
+ mutex_lock(&c->info->objc_objc_msgSend_mutex);
map_set(&c->info->objc_msgSend_types, call, data);
- mutex_unlock(&c->info->objc_types_mutex);
+ mutex_unlock(&c->info->objc_objc_msgSend_mutex);
try_to_add_package_dependency(c, "runtime", "objc_msgSend");
try_to_add_package_dependency(c, "runtime", "objc_msgSend_fpret");
@@ -387,6 +393,59 @@ gb_internal bool check_builtin_objc_procedure(CheckerContext *c, Operand *operan
try_to_add_package_dependency(c, "runtime", "objc_allocateClassPair");
return true;
} break;
+
+ case BuiltinProc_objc_ivar_get:
+ {
+ Type *self_type = nullptr;
+
+ Operand self = {};
+ check_expr_or_type(c, &self, ce->args[0]);
+
+ if (!is_operand_value(self) || !check_is_assignable_to(c, &self, t_objc_id)) {
+ gbString e = expr_to_string(self.expr);
+ gbString t = type_to_string(self.type);
+ error(self.expr, "'%.*s' expected a type or value derived from intrinsics.objc_object, got '%s' of type %s", LIT(builtin_name), e, t);
+ gb_string_free(t);
+ gb_string_free(e);
+ return false;
+ } else if (!is_type_pointer(self.type)) {
+ gbString e = expr_to_string(self.expr);
+ gbString t = type_to_string(self.type);
+ error(self.expr, "'%.*s' expected a pointer of a value derived from intrinsics.objc_object, got '%s' of type %s", LIT(builtin_name), e, t);
+ gb_string_free(t);
+ gb_string_free(e);
+ return false;
+ }
+
+ self_type = type_deref(self.type);
+
+ if (!(self_type->kind == Type_Named &&
+ self_type->Named.type_name != nullptr &&
+ self_type->Named.type_name->TypeName.objc_class_name != "")) {
+ gbString t = type_to_string(self_type);
+ error(self.expr, "'%.*s' expected a named type with the attribute @(objc_class=<string>) , got type %s", LIT(builtin_name), t);
+ gb_string_free(t);
+ return false;
+ }
+
+ Type *ivar_type = self_type->Named.type_name->TypeName.objc_ivar;
+ if (ivar_type == nullptr) {
+ gbString t = type_to_string(self_type);
+ error(self.expr, "'%.*s' requires that type %s have the attribute @(objc_ivar=<ivar_type_name>).", LIT(builtin_name), t);
+ gb_string_free(t);
+ return false;
+ }
+
+ if (type_hint != nullptr && type_hint->kind == Type_Pointer && type_hint->Pointer.elem == ivar_type) {
+ operand->type = type_hint;
+ } else {
+ operand->type = alloc_type_pointer(ivar_type);
+ }
+
+ operand->mode = Addressing_Value;
+ return true;
+
+ } break;
}
}
@@ -645,6 +704,13 @@ gb_internal bool check_builtin_simd_operation(CheckerContext *c, Operand *operan
break;
}
+ if (!are_types_identical(x.type, y.type)) {
+ gbString tx = type_to_string(x.type);
+ gbString ty = type_to_string(y.type);
+ error(call, "Mismatched types to '%.*s', '%s' vs '%s'", LIT(builtin_name), tx, ty);
+ gb_string_free(ty);
+ gb_string_free(tx);
+ }
Type *vt = base_type(x.type);
GB_ASSERT(vt->kind == Type_SimdVector);
@@ -753,6 +819,36 @@ gb_internal bool check_builtin_simd_operation(CheckerContext *c, Operand *operan
return true;
}
+ case BuiltinProc_simd_indices:
+ {
+ Operand x = {};
+ check_expr_or_type(c, &x, ce->args[0], nullptr);
+ if (x.mode == Addressing_Invalid) return false;
+ if (x.mode != Addressing_Type) {
+ gbString s = expr_to_string(x.expr);
+ error(x.expr, "'%.*s' expected a simd vector type, got '%s'", LIT(builtin_name), s);
+ gb_string_free(s);
+ return false;
+ }
+ if (!is_type_simd_vector(x.type)) {
+ gbString s = type_to_string(x.type);
+ error(x.expr, "'%.*s' expected a simd vector type, got '%s'", LIT(builtin_name), s);
+ gb_string_free(s);
+ return false;
+ }
+
+ Type *elem = base_array_type(x.type);
+ if (!is_type_numeric(elem)) {
+ gbString s = type_to_string(x.type);
+ error(x.expr, "'%.*s' expected a simd vector type with a numeric element type, got '%s'", LIT(builtin_name), s);
+ gb_string_free(s);
+ }
+
+ operand->mode = Addressing_Value;
+ operand->type = x.type;
+ return true;
+ }
+
case BuiltinProc_simd_extract:
{
Operand x = {};
@@ -816,8 +912,12 @@ gb_internal bool check_builtin_simd_operation(CheckerContext *c, Operand *operan
}
break;
+ case BuiltinProc_simd_reduce_add_bisect:
+ case BuiltinProc_simd_reduce_mul_bisect:
case BuiltinProc_simd_reduce_add_ordered:
case BuiltinProc_simd_reduce_mul_ordered:
+ case BuiltinProc_simd_reduce_add_pairs:
+ case BuiltinProc_simd_reduce_mul_pairs:
case BuiltinProc_simd_reduce_min:
case BuiltinProc_simd_reduce_max:
{
@@ -888,6 +988,39 @@ gb_internal bool check_builtin_simd_operation(CheckerContext *c, Operand *operan
return true;
}
+ case BuiltinProc_simd_extract_lsbs:
+ case BuiltinProc_simd_extract_msbs:
+ {
+ Operand x = {};
+ check_expr(c, &x, ce->args[0]); if (x.mode == Addressing_Invalid) return false;
+
+ if (!is_type_simd_vector(x.type)) {
+ gbString xs = type_to_string(x.type);
+ error(x.expr, "'%.*s' expected a simd vector type, got '%s'", LIT(builtin_name), xs);
+ gb_string_free(xs);
+ return false;
+ }
+
+ Type *elem = base_array_type(x.type);
+ if (!is_type_integer_like(elem)) {
+ gbString xs = type_to_string(x.type);
+ error(x.expr, "'%.*s' expected a #simd type with integer or boolean elements, got '%s'", LIT(builtin_name), xs);
+ gb_string_free(xs);
+ return false;
+ }
+
+ i64 num_elems = get_array_type_count(x.type);
+
+ Type *result_type = alloc_type_bit_set();
+ result_type->BitSet.elem = t_int;
+ result_type->BitSet.lower = 0;
+ result_type->BitSet.upper = num_elems - 1;
+
+ operand->mode = Addressing_Value;
+ operand->type = result_type;
+ return true;
+ }
+
case BuiltinProc_simd_shuffle:
{
@@ -1642,12 +1775,16 @@ gb_internal bool check_builtin_procedure_directive(CheckerContext *c, Operand *o
}
if (ce->args.count > 0) {
Ast *arg = ce->args[0];
- Operand o = {};
- Entity *e = check_ident(c, &o, arg, nullptr, nullptr, true);
- if (e == nullptr || (e->flags & EntityFlag_Param) == 0) {
- error(ce->args[0], "'#caller_expression' expected a valid earlier parameter name");
+ if (arg->kind != Ast_Ident) {
+ error(arg, "'#caller_expression' expected an identifier");
+ } else {
+ Operand o = {};
+ Entity *e = check_ident(c, &o, arg, nullptr, nullptr, true);
+ if (e == nullptr || (e->flags & EntityFlag_Param) == 0) {
+ error(arg, "'#caller_expression' expected a valid earlier parameter name");
+ }
+ arg->Ident.entity = e;
}
- arg->Ident.entity = e;
}
operand->type = t_string;
@@ -2015,6 +2152,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
case BuiltinProc_atomic_type_is_lock_free:
case BuiltinProc_has_target_feature:
case BuiltinProc_procedure_of:
+ case BuiltinProc_simd_indices:
// NOTE(bill): The first arg may be a Type, this will be checked case by case
break;
@@ -2088,7 +2226,8 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
case BuiltinProc_objc_find_selector:
case BuiltinProc_objc_find_class:
case BuiltinProc_objc_register_selector:
- case BuiltinProc_objc_register_class:
+ case BuiltinProc_objc_register_class:
+ case BuiltinProc_objc_ivar_get:
return check_builtin_objc_procedure(c, operand, call, id, type_hint);
case BuiltinProc___entry_point:
@@ -2738,8 +2877,6 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
// quaternion :: proc(imag, jmag, kmag, real: float_type) -> complex_type
Operand xyzw[4] = {};
- u32 first_index = 0;
-
// NOTE(bill): Invalid will be the default till fixed
operand->type = t_invalid;
operand->mode = Addressing_Invalid;
@@ -2784,6 +2921,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
if (fields_set[*index]) {
error(field->field, "Previously assigned field: '%.*s'", LIT(name));
+ return false;
}
fields_set[*index] = style;
@@ -2800,7 +2938,6 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
if (!ok || index < 0) {
return false;
}
- first_index = cast(u32)index;
*refs[index] = o;
}
@@ -2825,12 +2962,17 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
}
- for (u32 i = 0; i < 4; i++ ){
- u32 j = (i + first_index) % 4;
- if (j == first_index) {
- convert_to_typed(c, &xyzw[j], xyzw[(first_index+1)%4].type); if (xyzw[j].mode == Addressing_Invalid) return false;
- } else {
- convert_to_typed(c, &xyzw[j], xyzw[first_index].type); if (xyzw[j].mode == Addressing_Invalid) return false;
+ // The first typed value found, if any exist, will dictate the type for all untyped values.
+ for (u32 i = 0; i < 4; i++) {
+ if (is_type_typed(xyzw[i].type)) {
+ for (u32 j = 0; j < 4; j++) {
+ // `convert_to_typed` should check if it is typed already.
+ convert_to_typed(c, &xyzw[j], xyzw[i].type);
+ if (xyzw[j].mode == Addressing_Invalid) {
+ return false;
+ }
+ }
+ break;
}
}
if (xyzw[0].mode == Addressing_Constant &&
@@ -2854,7 +2996,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
gbString ty = type_to_string(xyzw[1].type);
gbString tz = type_to_string(xyzw[2].type);
gbString tw = type_to_string(xyzw[3].type);
- error(call, "Mismatched types to 'quaternion', 'x=%s' vs 'y=%s' vs 'z=%s' vs 'w=%s'", tx, ty, tz, tw);
+ error(call, "Mismatched types to 'quaternion', 'w=%s' vs 'x=%s' vs 'y=%s' vs 'z=%s'", tw, tx, ty, tz);
gb_string_free(tw);
gb_string_free(tz);
gb_string_free(ty);
@@ -2890,7 +3032,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
operand->mode = Addressing_Constant;
}
- BasicKind kind = core_type(xyzw[first_index].type)->Basic.kind;
+ BasicKind kind = core_type(xyzw[0].type)->Basic.kind;
switch (kind) {
case Basic_f16: operand->type = t_quaternion64; break;
case Basic_f32: operand->type = t_quaternion128; break;
@@ -3110,6 +3252,194 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
break;
}
+ case BuiltinProc_compress_values: {
+ Operand *ops = gb_alloc_array(temporary_allocator(), Operand, ce->args.count);
+
+ isize value_count = 0;
+
+ for_array(i, ce->args) {
+ Ast *arg = ce->args[i];
+ Operand *op = &ops[i];
+ check_multi_expr(c, op, arg);
+ if (op->mode == Addressing_Invalid) {
+ return false;
+ }
+
+ if (op->type == nullptr || op->type == t_invalid) {
+ gbString s = expr_to_string(op->expr);
+ error(op->expr, "Invalid expression to '%.*s', got %s", LIT(builtin_name), s);
+ gb_string_free(s);
+ }
+ if (is_type_tuple(op->type)) {
+ value_count += op->type->Tuple.variables.count;
+ } else {
+ value_count += 1;
+ }
+ }
+
+ GB_ASSERT(value_count >= 1);
+
+ if (value_count == 1) {
+ *operand = ops[0];
+ break;
+ }
+
+ if (type_hint != nullptr) {
+ Type *th = base_type(type_hint);
+ if (th->kind == Type_Struct) {
+ if (value_count == th->Struct.fields.count) {
+ isize index = 0;
+ for_array(i, ce->args) {
+ Operand *op = &ops[i];
+ if (is_type_tuple(op->type)) {
+ for (Entity *v : op->type->Tuple.variables) {
+ Operand x = {};
+ x.mode = Addressing_Value;
+ x.type = v->type;
+ check_assignment(c, &x, th->Struct.fields[index++]->type, builtin_name);
+ if (x.mode == Addressing_Invalid) {
+ return false;
+ }
+ }
+ } else {
+ check_assignment(c, op, th->Struct.fields[index++]->type, builtin_name);
+ if (op->mode == Addressing_Invalid) {
+ return false;
+ }
+ }
+ }
+
+ operand->type = type_hint;
+ operand->mode = Addressing_Value;
+ break;
+ }
+ } else if (is_type_array_like(th)) {
+ if (cast(i64)value_count == get_array_type_count(th)) {
+ Type *elem = base_array_type(th);
+ for_array(i, ce->args) {
+ Operand *op = &ops[i];
+ if (is_type_tuple(op->type)) {
+ for (Entity *v : op->type->Tuple.variables) {
+ Operand x = {};
+ x.mode = Addressing_Value;
+ x.type = v->type;
+ check_assignment(c, &x, elem, builtin_name);
+ if (x.mode == Addressing_Invalid) {
+ return false;
+ }
+ }
+ } else {
+ check_assignment(c, op, elem, builtin_name);
+ if (op->mode == Addressing_Invalid) {
+ return false;
+ }
+ }
+ }
+
+ operand->type = type_hint;
+ operand->mode = Addressing_Value;
+ break;
+ }
+ }
+ }
+
+ bool all_types_the_same = true;
+ Type *last_type = nullptr;
+ for_array(i, ce->args) {
+ Operand *op = &ops[i];
+ if (is_type_tuple(op->type)) {
+ if (last_type == nullptr) {
+ op->type->Tuple.variables[0]->type;
+ }
+ for (Entity *v : op->type->Tuple.variables) {
+ if (!are_types_identical(last_type, v->type)) {
+ all_types_the_same = false;
+ break;
+ }
+ last_type = v->type;
+ }
+ } else {
+ if (last_type == nullptr) {
+ last_type = op->type;
+ } else {
+ if (!are_types_identical(last_type, op->type)) {
+ all_types_the_same = false;
+ break;
+ }
+ last_type = op->type;
+ }
+ }
+ }
+
+ if (all_types_the_same) {
+ Type *elem_type = default_type(last_type);
+ if (is_type_untyped(elem_type)) {
+ gbString s = expr_to_string(call);
+ error(call, "Invalid use of '%s' in '%.*s'", s, LIT(builtin_name));
+ gb_string_free(s);
+ return false;
+ }
+
+ operand->type = alloc_type_array(elem_type, value_count);
+ operand->mode = Addressing_Value;
+ } else {
+ Type *st = alloc_type_struct_complete();
+ st->Struct.fields = slice_make<Entity *>(permanent_allocator(), value_count);
+ st->Struct.tags = gb_alloc_array(permanent_allocator(), String, value_count);
+ st->Struct.offsets = gb_alloc_array(permanent_allocator(), i64, value_count);
+
+ Scope *scope = create_scope(c->info, nullptr);
+
+ Token token = {};
+ token.kind = Token_Ident;
+ token.pos = ast_token(call).pos;
+
+ isize index = 0;
+ for_array(i, ce->args) {
+ Operand *op = &ops[i];
+ if (is_type_tuple(op->type)) {
+ for (Entity *v : op->type->Tuple.variables) {
+ Type *t = default_type(v->type);
+ if (is_type_untyped(t)) {
+ gbString s = expr_to_string(op->expr);
+ error(op->expr, "Invalid use of '%s' in '%.*s'", s, LIT(builtin_name));
+ gb_string_free(s);
+ return false;
+ }
+
+ gbString s = gb_string_make_reserve(permanent_allocator(), 32);
+ s = gb_string_append_fmt(s, "v%lld", cast(long long)index);
+ token.string = make_string_c(s);
+ Entity *e = alloc_entity_field(scope, token, t, false, cast(i32)index, EntityState_Resolved);
+ st->Struct.fields[index++] = e;
+ }
+ } else {
+ Type *t = default_type(op->type);
+ if (is_type_untyped(t)) {
+ gbString s = expr_to_string(op->expr);
+ error(op->expr, "Invalid use of '%s' in '%.*s'", s, LIT(builtin_name));
+ gb_string_free(s);
+ return false;
+ }
+
+ gbString s = gb_string_make_reserve(permanent_allocator(), 32);
+ s = gb_string_append_fmt(s, "v%lld", cast(long long)index);
+ token.string = make_string_c(s);
+ Entity *e = alloc_entity_field(scope, token, t, false, cast(i32)index, EntityState_Resolved);
+ st->Struct.fields[index++] = e;
+ }
+ }
+
+
+ gb_unused(type_size_of(st));
+
+ operand->type = st;
+ operand->mode = Addressing_Value;
+ }
+ break;
+ }
+
+
case BuiltinProc_min: {
// min :: proc($T: typeid) -> ordered
// min :: proc(a: ..ordered) -> ordered
@@ -3488,9 +3818,12 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
case ExactValue_Integer:
mp_abs(&operand->value.value_integer, &operand->value.value_integer);
break;
- case ExactValue_Float:
- operand->value.value_float = gb_abs(operand->value.value_float);
+ case ExactValue_Float: {
+ u64 abs = bit_cast<u64>(operand->value.value_float);
+ abs &= 0x7FFFFFFFFFFFFFFF;
+ operand->value.value_float = bit_cast<f64>(abs);
break;
+ }
case ExactValue_Complex: {
f64 r = operand->value.value_complex->real;
f64 i = operand->value.value_complex->imag;
@@ -5265,7 +5598,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
}
if (sz >= 64) {
- if (is_type_unsigned(x.type)) {
+ if (is_type_unsigned(x.type) || is_type_unsigned(y.type)) {
add_package_dependency(c, "runtime", "umodti3", true);
add_package_dependency(c, "runtime", "udivti3", true);
} else {
@@ -5503,6 +5836,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
case Type_EnumeratedArray: operand->type = bt->EnumeratedArray.elem; break;
case Type_Slice: operand->type = bt->Slice.elem; break;
case Type_DynamicArray: operand->type = bt->DynamicArray.elem; break;
+ case Type_SimdVector: operand->type = bt->SimdVector.elem; break;
}
}
operand->mode = Addressing_Type;
@@ -5544,11 +5878,95 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
// NOTE(bill): Is this even correct?
new_type->Union.node = operand->expr;
new_type->Union.scope = bt->Union.scope;
+ if (bt->Union.kind == UnionType_no_nil) {
+ new_type->Union.kind = UnionType_no_nil;
+ }
operand->type = new_type;
}
operand->mode = Addressing_Type;
break;
+ case BuiltinProc_type_integer_to_unsigned:
+ if (operand->mode != Addressing_Type) {
+ error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name));
+ return false;
+ }
+
+ if (is_type_polymorphic(operand->type)) {
+ gbString t = type_to_string(operand->type);
+ error(operand->expr, "Expected a non-polymorphic type for '%.*s', got %s", LIT(builtin_name), t);
+ gb_string_free(t);
+ return false;
+ }
+
+ {
+ Type *bt = base_type(operand->type);
+
+ if (bt->kind != Type_Basic ||
+ (bt->Basic.flags & BasicFlag_Unsigned) != 0 ||
+ (bt->Basic.flags & BasicFlag_Integer) == 0) {
+ gbString t = type_to_string(operand->type);
+ error(operand->expr, "Expected a signed integer type for '%.*s', got %s", LIT(builtin_name), t);
+ gb_string_free(t);
+ return false;
+ }
+
+ if ((bt->Basic.flags & BasicFlag_Untyped) != 0) {
+ gbString t = type_to_string(operand->type);
+ error(operand->expr, "Expected a non-untyped integer type for '%.*s', got %s", LIT(builtin_name), t);
+ gb_string_free(t);
+ return false;
+ }
+
+ Type *u_type = &basic_types[bt->Basic.kind + 1];
+
+ operand->type = u_type;
+ }
+ break;
+ case BuiltinProc_type_integer_to_signed:
+ if (operand->mode != Addressing_Type) {
+ error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name));
+ return false;
+ }
+
+ if (is_type_polymorphic(operand->type)) {
+ gbString t = type_to_string(operand->type);
+ error(operand->expr, "Expected a non-polymorphic type for '%.*s', got %s", LIT(builtin_name), t);
+ gb_string_free(t);
+ return false;
+ }
+
+ {
+ Type *bt = base_type(operand->type);
+
+ if (bt->kind != Type_Basic ||
+ (bt->Basic.flags & BasicFlag_Unsigned) == 0 ||
+ (bt->Basic.flags & BasicFlag_Integer) == 0) {
+ gbString t = type_to_string(operand->type);
+ error(operand->expr, "Expected an unsigned integer type for '%.*s', got %s", LIT(builtin_name), t);
+ gb_string_free(t);
+ return false;
+ }
+
+ if ((bt->Basic.flags & BasicFlag_Untyped) != 0) {
+ gbString t = type_to_string(operand->type);
+ error(operand->expr, "Expected a non-untyped integer type for '%.*s', got %s", LIT(builtin_name), t);
+ gb_string_free(t);
+ return false;
+ }
+
+ if (bt->Basic.kind == Basic_uintptr) {
+ gbString t = type_to_string(operand->type);
+ error(operand->expr, "Type %s does not have a signed integer mapping for '%.*s'", t, LIT(builtin_name));
+ gb_string_free(t);
+ return false;
+ }
+
+ Type *u_type = &basic_types[bt->Basic.kind - 1];
+
+ operand->type = u_type;
+ }
+ break;
case BuiltinProc_type_merge:
{
operand->mode = Addressing_Type;
@@ -5669,6 +6087,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
case BuiltinProc_type_is_enum:
case BuiltinProc_type_is_proc:
case BuiltinProc_type_is_bit_set:
+ case BuiltinProc_type_is_bit_field:
case BuiltinProc_type_is_simd_vector:
case BuiltinProc_type_is_matrix:
case BuiltinProc_type_is_specialized_polymorphic_record:
@@ -5950,12 +6369,13 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
// NOTE(jakubtomsu): forces calculation of variant_block_size
type_size_of(u);
- i64 tag_offset = u->Union.variant_block_size;
- GB_ASSERT(tag_offset > 0);
+ // NOTE(Jeroen): A tag offset of zero is perfectly fine if all members of the union are empty structs.
+ // What matters is that the tag size is > 0.
+ GB_ASSERT(u->Union.tag_size > 0);
operand->mode = Addressing_Constant;
operand->type = t_untyped_integer;
- operand->value = exact_value_i64(tag_offset);
+ operand->value = exact_value_i64(u->Union.variant_block_size);
}
break;
diff --git a/src/check_decl.cpp b/src/check_decl.cpp
index 1d792dad8..3d0d95556 100644
--- a/src/check_decl.cpp
+++ b/src/check_decl.cpp
@@ -60,7 +60,7 @@ gb_internal Type *check_init_variable(CheckerContext *ctx, Entity *e, Operand *o
error(operand->expr, "Cannot assign a type '%s' to variable '%.*s'", t, LIT(e->token.string));
}
if (e->type == nullptr) {
- error_line("\tThe type of the variable '%.*s' cannot be inferred as a type does not have a default type\n", LIT(e->token.string));
+ error_line("\tThe type of the variable '%.*s' cannot be inferred as a type and does not have a default type\n", LIT(e->token.string));
}
e->type = operand->type;
return nullptr;
@@ -468,6 +468,10 @@ gb_internal void check_type_decl(CheckerContext *ctx, Entity *e, Ast *init_expr,
}
e->type = named;
+ if (!is_distinct) {
+ e->TypeName.is_type_alias = true;
+ }
+
check_type_path_push(ctx, e);
Type *bt = check_type_expr(ctx, te, named);
check_type_path_pop(ctx);
@@ -502,9 +506,9 @@ gb_internal void check_type_decl(CheckerContext *ctx, Entity *e, Ast *init_expr,
if (!is_distinct) {
e->type = bt;
named->Named.base = bt;
- e->TypeName.is_type_alias = true;
}
+ e->TypeName.is_type_alias = !is_distinct;
if (decl->type_expr != nullptr) {
Type *t = check_type(ctx, decl->type_expr);
@@ -520,12 +524,90 @@ gb_internal void check_type_decl(CheckerContext *ctx, Entity *e, Ast *init_expr,
if (decl != nullptr) {
AttributeContext ac = {};
check_decl_attributes(ctx, decl->attributes, type_decl_attribute, &ac);
+
if (e->kind == Entity_TypeName && ac.objc_class != "") {
+
e->TypeName.objc_class_name = ac.objc_class;
+ if (ac.objc_is_implementation) {
+ e->TypeName.objc_is_implementation = ac.objc_is_implementation;
+ e->TypeName.objc_superclass = ac.objc_superclass;
+ e->TypeName.objc_ivar = ac.objc_ivar;
+ e->TypeName.objc_context_provider = ac.objc_context_provider;
+
+ mutex_lock(&ctx->info->objc_class_name_mutex);
+ bool class_exists = string_set_update(&ctx->info->obcj_class_name_set, ac.objc_class);
+ mutex_unlock(&ctx->info->objc_class_name_mutex);
+ if (class_exists) {
+ error(e->token, "@(objc_class) name '%.*s' has already been used elsewhere", LIT(ac.objc_class));
+ }
+
+ mpsc_enqueue(&ctx->info->objc_class_implementations, e);
+
+ GB_ASSERT(e->TypeName.objc_ivar == nullptr || e->TypeName.objc_ivar->kind == Type_Named);
+
+ // Enqueue the contex_provider proc to be checked after it is resolved
+ if (e->TypeName.objc_context_provider != nullptr) {
+ mpsc_enqueue(&ctx->checker->procs_with_objc_context_provider_to_check, e);
+ }
+
+ // TODO(harold): I think there's a Check elsewhere in the checker for checking cycles.
+ // See about moving this to the right location.
+ // Ensure superclass hierarchy are all Objective-C classes and does not cycle
+
+ // NOTE(harold): We check for superclass unconditionally (before checking if super is null)
+ // because this should be the case 99.99% of the time. Not subclassing something that
+ // is, or is the child of, NSObject means the objc runtime messaging will not properly work on this type.
+ TypeSet super_set{};
+ type_set_init(&super_set, 8);
+ defer (type_set_destroy(&super_set));
+
+ type_set_update(&super_set, e->type);
+
+ Type *super = ac.objc_superclass;
+ while (super != nullptr) {
+ if (type_set_update(&super_set, super)) {
+ error(e->token, "@(objc_superclass) Superclass hierarchy cycle encountered");
+ break;
+ }
+
+ check_single_global_entity(ctx->checker, super->Named.type_name, super->Named.type_name->decl_info);
+
+ if (super->kind != Type_Named) {
+ error(e->token, "@(objc_superclass) Referenced type must be a named struct");
+ break;
+ }
+
+ Type* named_type = base_named_type(super);
+ GB_ASSERT(named_type->kind == Type_Named);
+
+ if (!is_type_objc_object(named_type)) {
+ error(e->token, "@(objc_superclass) Superclass '%.*s' must be an Objective-C class", LIT(named_type->Named.name));
+ break;
+ }
+
+ if (named_type->Named.type_name->TypeName.objc_class_name == "") {
+ error(e->token, "@(objc_superclass) Superclass '%.*s' must have a valid @(objc_class) attribute", LIT(named_type->Named.name));
+ break;
+ }
+
+ super = named_type->Named.type_name->TypeName.objc_superclass;
+ }
+ } else {
+ if (ac.objc_superclass != nullptr) {
+ error(e->token, "@(objc_superclass) may only be applied when the @(obj_implement) attribute is also applied");
+ } else if (ac.objc_ivar != nullptr) {
+ error(e->token, "@(objc_ivar) may only be applied when the @(obj_implement) attribute is also applied");
+ } else if (ac.objc_context_provider != nullptr) {
+ error(e->token, "@(objc_context_provider) may only be applied when the @(obj_implement) attribute is also applied");
+ }
+ }
+
if (type_size_of(e->type) > 0) {
error(e->token, "@(objc_class) marked type must be of zero size");
}
+ } else if (ac.objc_is_implementation) {
+ error(e->token, "@(objc_implement) may only be applied when the @(objc_class) attribute is also applied");
}
}
@@ -628,6 +710,10 @@ gb_internal void check_const_decl(CheckerContext *ctx, Entity *e, Ast *type_expr
Operand x = {};
x.type = entity->type;
x.mode = Addressing_Variable;
+ if (entity->kind == Entity_Constant) {
+ x.mode = Addressing_Constant;
+ x.value = entity->Constant.value;
+ }
if (!check_is_assignable_to(ctx, &x, e->type)) {
gbString expr_str = expr_to_string(init);
gbString op_type_str = type_to_string(entity->type);
@@ -857,6 +943,7 @@ gb_internal Entity *init_entity_foreign_library(CheckerContext *ctx, Entity *e)
} else {
String name = ident->Ident.token.string;
Entity *found = scope_lookup(ctx->scope, name);
+
if (found == nullptr) {
if (is_blank_ident(name)) {
// NOTE(bill): link against nothing
@@ -913,7 +1000,7 @@ gb_internal String handle_link_name(CheckerContext *ctx, Token token, String lin
}
-gb_internal void check_objc_methods(CheckerContext *ctx, Entity *e, AttributeContext const &ac) {
+gb_internal void check_objc_methods(CheckerContext *ctx, Entity *e, AttributeContext &ac) {
if (!(ac.objc_name.len || ac.objc_is_class_method || ac.objc_type)) {
return;
}
@@ -925,49 +1012,108 @@ gb_internal void check_objc_methods(CheckerContext *ctx, Entity *e, AttributeCon
error(e->token, "@(objc_name) is required with @(objc_type)");
} else {
Type *t = ac.objc_type;
- if (t->kind == Type_Named) {
- Entity *tn = t->Named.type_name;
- GB_ASSERT(tn->kind == Entity_TypeName);
+ GB_ASSERT(t->kind == Type_Named); // NOTE(harold): This is already checked for at the attribute resolution stage.
+ Entity *tn = t->Named.type_name;
- if (tn->scope != e->scope) {
- error(e->token, "@(objc_name) attribute may only be applied to procedures and types within the same scope");
- } else {
- mutex_lock(&global_type_name_objc_metadata_mutex);
- defer (mutex_unlock(&global_type_name_objc_metadata_mutex));
+ GB_ASSERT(tn->kind == Entity_TypeName);
- if (!tn->TypeName.objc_metadata) {
- tn->TypeName.objc_metadata = create_type_name_obj_c_metadata();
- }
- auto *md = tn->TypeName.objc_metadata;
- mutex_lock(md->mutex);
- defer (mutex_unlock(md->mutex));
-
- if (!ac.objc_is_class_method) {
- bool ok = true;
- for (TypeNameObjCMetadataEntry const &entry : md->value_entries) {
- if (entry.name == ac.objc_name) {
- error(e->token, "Previous declaration of @(objc_name=\"%.*s\")", LIT(ac.objc_name));
- ok = false;
- break;
- }
+ if (tn->scope != e->scope) {
+ error(e->token, "@(objc_name) attribute may only be applied to procedures and types within the same scope");
+ } else {
+
+ // Enable implementation by default if the class is an implementer too and
+ // @objc_implement was not set to false explicitly in this proc.
+ bool implement = tn->TypeName.objc_is_implementation;
+ if (ac.objc_is_disabled_implement) {
+ implement = false;
+ }
+
+ if (implement) {
+ GB_ASSERT(e->kind == Entity_Procedure);
+
+ auto &proc = e->type->Proc;
+ Type *first_param = proc.param_count > 0 ? proc.params->Tuple.variables[0]->type : t_untyped_nil;
+
+ if (!tn->TypeName.objc_is_implementation) {
+ error(e->token, "@(objc_is_implement) attribute may only be applied to procedures whose class also have @(objc_is_implement) applied");
+ } else if (!ac.objc_is_class_method && !(first_param->kind == Type_Pointer && internal_check_is_assignable_to(t, first_param->Pointer.elem))) {
+ error(e->token, "Objective-C instance methods implementations require the first parameter to be a pointer to the class type set by @(objc_type)");
+ } else if (proc.calling_convention == ProcCC_Odin && !tn->TypeName.objc_context_provider) {
+ error(e->token, "Objective-C methods with Odin calling convention can only be used with classes that have @(objc_context_provider) set");
+ } else if (ac.objc_is_class_method && proc.calling_convention != ProcCC_CDecl) {
+ error(e->token, "Objective-C class methods (objc_is_class_method=true) that have @objc_is_implementation can only use \"c\" calling convention");
+ } else if (proc.result_count > 1) {
+ error(e->token, "Objective-C method implementations may return at most 1 value");
+ } else {
+ // Always export unconditionally
+ // NOTE(harold): This means check_objc_methods() MUST be called before
+ // e->Procedure.is_export is set in check_proc_decl()!
+ if (ac.is_export) {
+ error(e->token, "Explicit export not allowed when @(objc_implement) is set. It set exported implicitly");
}
- if (ok) {
- array_add(&md->value_entries, TypeNameObjCMetadataEntry{ac.objc_name, e});
+ if (ac.link_name != "") {
+ error(e->token, "Explicit linkage not allowed when @(objc_implement) is set. It set to \"strong\" implicitly");
}
- } else {
- bool ok = true;
- for (TypeNameObjCMetadataEntry const &entry : md->type_entries) {
- if (entry.name == ac.objc_name) {
- error(e->token, "Previous declaration of @(objc_name=\"%.*s\")", LIT(ac.objc_name));
- ok = false;
- break;
- }
+
+ ac.is_export = true;
+ ac.linkage = STR_LIT("strong");
+
+ auto method = ObjcMethodData{ ac, e };
+ method.ac.objc_selector = ac.objc_selector != "" ? ac.objc_selector : ac.objc_name;
+
+ CheckerInfo *info = ctx->info;
+ mutex_lock(&info->objc_method_mutex);
+ defer (mutex_unlock(&info->objc_method_mutex));
+
+ Array<ObjcMethodData>* method_list = map_get(&info->objc_method_implementations, t);
+ if (method_list) {
+ array_add(method_list, method);
+ } else {
+ auto list = array_make<ObjcMethodData>(permanent_allocator(), 1, 8);
+ list[0] = method;
+
+ map_set(&info->objc_method_implementations, t, list);
}
- if (ok) {
- array_add(&md->type_entries, TypeNameObjCMetadataEntry{ac.objc_name, e});
+ }
+ } else if (ac.objc_selector != "") {
+ error(e->token, "@(objc_selector) may only be applied to procedures that are Objective-C implementations.");
+ }
+
+ mutex_lock(&global_type_name_objc_metadata_mutex);
+ defer (mutex_unlock(&global_type_name_objc_metadata_mutex));
+
+ if (!tn->TypeName.objc_metadata) {
+ tn->TypeName.objc_metadata = create_type_name_obj_c_metadata();
+ }
+ auto *md = tn->TypeName.objc_metadata;
+ mutex_lock(md->mutex);
+ defer (mutex_unlock(md->mutex));
+
+ if (!ac.objc_is_class_method) {
+ bool ok = true;
+ for (TypeNameObjCMetadataEntry const &entry : md->value_entries) {
+ if (entry.name == ac.objc_name) {
+ error(e->token, "Previous declaration of @(objc_name=\"%.*s\")", LIT(ac.objc_name));
+ ok = false;
+ break;
+ }
+ }
+ if (ok) {
+ array_add(&md->value_entries, TypeNameObjCMetadataEntry{ac.objc_name, e});
+ }
+ } else {
+ bool ok = true;
+ for (TypeNameObjCMetadataEntry const &entry : md->type_entries) {
+ if (entry.name == ac.objc_name) {
+ error(e->token, "Previous declaration of @(objc_name=\"%.*s\")", LIT(ac.objc_name));
+ ok = false;
+ break;
}
}
+ if (ok) {
+ array_add(&md->type_entries, TypeNameObjCMetadataEntry{ac.objc_name, e});
+ }
}
}
}
@@ -1136,6 +1282,9 @@ gb_internal void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
break;
}
+ // NOTE(harold): For Objective-C method implementations, this must happen after
+ // check_objc_methods() is called as it re-sets ac.is_export to true unconditionally.
+ // The same is true for the linkage, set below.
e->Procedure.entry_point_only = ac.entry_point_only;
e->Procedure.is_export = ac.is_export;
@@ -1185,12 +1334,16 @@ gb_internal void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
has_instrumentation = false;
e->flags |= EntityFlag_Require;
} else if (ac.instrumentation_enter) {
+ init_core_source_code_location(ctx->checker);
if (!is_valid_instrumentation_call(e->type)) {
init_core_source_code_location(ctx->checker);
gbString s = type_to_string(e->type);
error(e->token, "@(instrumentation_enter) procedures must have the type '%s', got %s", instrumentation_proc_type_str, s);
gb_string_free(s);
}
+ if ((e->scope->flags & (ScopeFlag_File|ScopeFlag_Pkg)) == 0) {
+ error(e->token, "@(instrumentation_enter) procedures must be declared at the file scope");
+ }
MUTEX_GUARD(&ctx->info->instrumentation_mutex);
if (ctx->info->instrumentation_enter_entity != nullptr) {
error(e->token, "@(instrumentation_enter) has already been set");
@@ -1207,6 +1360,9 @@ gb_internal void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
error(e->token, "@(instrumentation_exit) procedures must have the type '%s', got %s", instrumentation_proc_type_str, s);
gb_string_free(s);
}
+ if ((e->scope->flags & (ScopeFlag_File|ScopeFlag_Pkg)) == 0) {
+ error(e->token, "@(instrumentation_exit) procedures must be declared at the file scope");
+ }
MUTEX_GUARD(&ctx->info->instrumentation_mutex);
if (ctx->info->instrumentation_exit_entity != nullptr) {
error(e->token, "@(instrumentation_exit) has already been set");
@@ -1220,6 +1376,8 @@ gb_internal void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
e->Procedure.has_instrumentation = has_instrumentation;
+ e->Procedure.no_sanitize_address = ac.no_sanitize_address;
+ e->Procedure.no_sanitize_memory = ac.no_sanitize_memory;
e->deprecated_message = ac.deprecated_message;
e->warning_message = ac.warning_message;
@@ -1235,6 +1393,7 @@ gb_internal void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
}
}
+ // NOTE(harold): See export/linkage note above(where is_export is assigned) regarding Objective-C method implementations
bool is_foreign = e->Procedure.is_foreign;
bool is_export = e->Procedure.is_export;
@@ -1741,8 +1900,8 @@ gb_internal void add_deps_from_child_to_parent(DeclInfo *decl) {
rw_mutex_shared_lock(&decl->type_info_deps_mutex);
rw_mutex_lock(&decl->parent->type_info_deps_mutex);
- for (Type *t : decl->type_info_deps) {
- ptr_set_add(&decl->parent->type_info_deps, t);
+ for (auto const &tt : decl->type_info_deps) {
+ type_set_add(&decl->parent->type_info_deps, tt);
}
rw_mutex_unlock(&decl->parent->type_info_deps_mutex);
@@ -1783,6 +1942,10 @@ gb_internal bool check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *de
ctx->curr_proc_sig = type;
ctx->curr_proc_calling_convention = type->Proc.calling_convention;
+ if (decl->parent && decl->entity && decl->parent->entity) {
+ decl->entity->parent_proc_decl = decl->parent;
+ }
+
if (ctx->pkg->name != "runtime") {
switch (type->Proc.calling_convention) {
case ProcCC_None:
@@ -1872,6 +2035,8 @@ gb_internal bool check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *de
check_open_scope(ctx, body);
{
+ ctx->scope->decl_info = decl;
+
for (auto const &entry : using_entities) {
Entity *uvar = entry.uvar;
Entity *prev = scope_insert(ctx->scope, uvar);
diff --git a/src/check_expr.cpp b/src/check_expr.cpp
index 231ece2f4..aa9c8837d 100644
--- a/src/check_expr.cpp
+++ b/src/check_expr.cpp
@@ -263,6 +263,9 @@ gb_internal void check_did_you_mean_scope(String const &name, Scope *scope, char
gb_internal Entity *entity_from_expr(Ast *expr) {
expr = unparen_expr(expr);
+ if (expr == nullptr) {
+ return nullptr;
+ }
switch (expr->kind) {
case Ast_Ident:
return expr->Ident.entity;
@@ -345,7 +348,7 @@ gb_internal void check_scope_decls(CheckerContext *c, Slice<Ast *> const &nodes,
check_collect_entities(c, nodes);
for (auto const &entry : s->elements) {
- Entity *e = entry.value;
+ Entity *e = entry.value;\
switch (e->kind) {
case Entity_Constant:
case Entity_TypeName:
@@ -643,7 +646,7 @@ gb_internal bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, E
gb_internal bool check_polymorphic_procedure_assignment(CheckerContext *c, Operand *operand, Type *type, Ast *poly_def_node, PolyProcData *poly_proc_data) {
if (operand->expr == nullptr) return false;
- Entity *base_entity = entity_of_node(operand->expr);
+ Entity *base_entity = entity_from_expr(operand->expr);
if (base_entity == nullptr) return false;
return find_or_generate_polymorphic_procedure(c, base_entity, type, nullptr, poly_def_node, poly_proc_data);
}
@@ -863,6 +866,11 @@ gb_internal i64 check_distance_between_types(CheckerContext *c, Operand *operand
if (are_types_identical(vt, s)) {
return 1;
}
+ if (is_type_proc(vt)) {
+ if (are_types_identical(base_type(vt), src)) {
+ return 1;
+ }
+ }
}
if (dst->Union.variants.count == 1) {
@@ -990,14 +998,34 @@ gb_internal i64 assign_score_function(i64 distance, bool is_variadic=false) {
gb_internal bool check_is_assignable_to_with_score(CheckerContext *c, Operand *operand, Type *type, i64 *score_, bool is_variadic=false, bool allow_array_programming=true) {
- i64 score = 0;
- i64 distance = check_distance_between_types(c, operand, type, allow_array_programming);
- bool ok = distance >= 0;
- if (ok) {
- score = assign_score_function(distance, is_variadic);
+ if (c == nullptr) {
+ GB_ASSERT(operand->mode == Addressing_Value);
+ GB_ASSERT(is_type_typed(operand->type));
+ }
+ if (operand->mode == Addressing_Invalid || type == t_invalid) {
+ if (score_) *score_ = 0;
+ return false;
+ }
+
+ // Handle polymorphic procedure used as default parameter
+ if (operand->mode == Addressing_Value && is_type_proc(type) && is_type_proc(operand->type)) {
+ Entity *e = entity_from_expr(operand->expr);
+ if (e != nullptr && e->kind == Entity_Procedure && is_type_polymorphic(e->type) && !is_type_polymorphic(type)) {
+ // Special case: Allow a polymorphic procedure to be used as default value for concrete proc type
+ // during the initial check. It will be properly instantiated when actually used.
+ if (score_) *score_ = assign_score_function(1);
+ return true;
+ }
+ }
+
+ i64 score = check_distance_between_types(c, operand, type, allow_array_programming);
+ if (score >= 0) {
+ if (score_) *score_ = assign_score_function(score, is_variadic);
+ return true;
}
- if (score_) *score_ = score;
- return ok;
+
+ if (score_) *score_ = 0;
+ return false;
}
@@ -1044,7 +1072,7 @@ gb_internal AstPackage *get_package_of_type(Type *type) {
}
-// NOTE(bill): 'content_name' is for debugging and error messages
+// NOTE(bill): 'context_name' is for debugging and error messages
gb_internal void check_assignment(CheckerContext *c, Operand *operand, Type *type, String context_name) {
check_not_tuple(c, operand);
if (operand->mode == Addressing_Invalid) {
@@ -1849,7 +1877,10 @@ gb_internal Entity *check_ident(CheckerContext *c, Operand *o, Ast *n, Type *nam
o->type = t_invalid;
}
if (o->type != nullptr && o->type->kind == Type_Named && o->type->Named.type_name->TypeName.is_type_alias) {
- o->type = base_type(o->type);
+ Type *bt = base_type(o->type);
+ if (bt != nullptr) {
+ o->type = bt;
+ }
}
break;
@@ -1973,10 +2004,10 @@ gb_internal bool check_binary_op(CheckerContext *c, Operand *o, Token op) {
case Token_Quo:
case Token_QuoEq:
if (is_type_matrix(main_type)) {
- error(op, "Operator '%.*s' is only allowed with matrix types", LIT(op.string));
+ error(op, "Operator '%.*s' is not allowed with matrix types", LIT(op.string));
return false;
} else if (is_type_simd_vector(main_type) && is_type_integer(type)) {
- error(op, "Operator '%.*s' is only allowed with #simd types with integer elements", LIT(op.string));
+ error(op, "Operator '%.*s' is not allowed with #simd types with integer elements", LIT(op.string));
return false;
}
/*fallthrough*/
@@ -2023,14 +2054,14 @@ gb_internal bool check_binary_op(CheckerContext *c, Operand *o, Token op) {
case Token_ModEq:
case Token_ModModEq:
if (is_type_matrix(main_type)) {
- error(op, "Operator '%.*s' is only allowed with matrix types", LIT(op.string));
+ error(op, "Operator '%.*s' is not allowed with matrix types", LIT(op.string));
return false;
}
if (!is_type_integer(type)) {
error(op, "Operator '%.*s' is only allowed with integers", LIT(op.string));
return false;
} else if (is_type_simd_vector(main_type)) {
- error(op, "Operator '%.*s' is only allowed with #simd types with integer elements", LIT(op.string));
+ error(op, "Operator '%.*s' is not allowed with #simd types with integer elements", LIT(op.string));
return false;
}
break;
@@ -2393,27 +2424,27 @@ gb_internal void check_assignment_error_suggestion(CheckerContext *c, Operand *o
Type *s = src->Array.elem;
Type *d = dst->Slice.elem;
if (are_types_identical(s, d)) {
- error_line("\tSuggestion: the array expression may be sliced with %s[:]\n", a);
+ error_line("\tSuggestion: The array expression may be sliced with %s[:]\n", a);
}
} else if (is_type_dynamic_array(src) && is_type_slice(dst)) {
Type *s = src->DynamicArray.elem;
Type *d = dst->Slice.elem;
if (are_types_identical(s, d)) {
- error_line("\tSuggestion: the dynamic array expression may be sliced with %s[:]\n", a);
+ error_line("\tSuggestion: The dynamic array expression may be sliced with %s[:]\n", a);
}
}else if (are_types_identical(src, dst) && !are_types_identical(o->type, type)) {
- error_line("\tSuggestion: the expression may be directly casted to type %s\n", b);
+ error_line("\tSuggestion: The expression may be directly casted to type %s\n", b);
} else if (are_types_identical(src, t_string) && is_type_u8_slice(dst)) {
- error_line("\tSuggestion: a string may be transmuted to %s\n", b);
- error_line("\t This is an UNSAFE operation as string data is assumed to be immutable, \n");
+ error_line("\tSuggestion: A string may be transmuted to %s\n", b);
+ error_line("\t This is an UNSAFE operation as string data is assumed to be immutable,\n");
error_line("\t whereas slices in general are assumed to be mutable.\n");
} else if (is_type_u8_slice(src) && are_types_identical(dst, t_string) && o->mode != Addressing_Constant) {
- error_line("\tSuggestion: the expression may be casted to %s\n", b);
+ error_line("\tSuggestion: The expression may be casted to %s\n", b);
} else if (check_integer_exceed_suggestion(c, o, type, max_bit_size)) {
return;
} else if (is_expr_inferred_fixed_array(c->type_hint_expr) && is_type_array_like(type) && is_type_array_like(o->type)) {
gbString s = expr_to_string(c->type_hint_expr);
- error_line("\tSuggestion: make sure that `%s` is attached to the compound literal directly\n", s);
+ error_line("\tSuggestion: Make sure that `%s` is attached to the compound literal directly\n", s);
gb_string_free(s);
} else if (is_type_pointer(type) &&
o->mode == Addressing_Variable &&
@@ -2599,9 +2630,8 @@ gb_internal ExactValue exact_bit_set_all_set_mask(Type *type) {
continue;
}
- BigInt shift_amount = f->Constant.value.value_integer;
- big_int_sub_eq(&shift_amount, &b_lower_base);
-
+ BigInt shift_amount = {};
+ big_int_sub(&shift_amount, &f->Constant.value.value_integer, &b_lower_base);
BigInt value = {};
big_int_shl(&value, &one, &shift_amount);
@@ -2903,9 +2933,20 @@ gb_internal void check_comparison(CheckerContext *c, Ast *node, Operand *x, Oper
if (!defined) {
gbString xs = type_to_string(x->type, temporary_allocator());
gbString ys = type_to_string(y->type, temporary_allocator());
- err_str = gb_string_make(temporary_allocator(),
- gb_bprintf("operator '%.*s' not defined between the types '%s' and '%s'", LIT(token_strings[op]), xs, ys)
- );
+
+ if (!is_type_comparable(x->type)) {
+ err_str = gb_string_make(temporary_allocator(),
+ gb_bprintf("Type '%s' is not simply comparable, so operator '%.*s' is not defined for it", xs, LIT(token_strings[op]))
+ );
+ } else if (!is_type_comparable(y->type)) {
+ err_str = gb_string_make(temporary_allocator(),
+ gb_bprintf("Type '%s' is not simply comparable, so operator '%.*s' is not defined for it", ys, LIT(token_strings[op]))
+ );
+ } else {
+ err_str = gb_string_make(temporary_allocator(),
+ gb_bprintf("Operator '%.*s' not defined between the types '%s' and '%s'", LIT(token_strings[op]), xs, ys)
+ );
+ }
} else {
Type *comparison_type = x->type;
if (x->type == err_type && is_operand_nil(*x)) {
@@ -2926,11 +2967,11 @@ gb_internal void check_comparison(CheckerContext *c, Ast *node, Operand *x, Oper
} else {
yt = type_to_string(y->type);
}
- err_str = gb_string_make(temporary_allocator(), gb_bprintf("mismatched types '%s' and '%s'", xt, yt));
+ err_str = gb_string_make(temporary_allocator(), gb_bprintf("Mismatched types '%s' and '%s'", xt, yt));
}
if (err_str != nullptr) {
- error(node, "Cannot compare expression, %s", err_str);
+ error(node, "Cannot compare expression. %s.", err_str);
x->type = t_untyped_bool;
} else {
if (x->mode == Addressing_Constant &&
@@ -3045,126 +3086,106 @@ gb_internal void check_shift(CheckerContext *c, Operand *x, Operand *y, Ast *nod
GB_ASSERT(node->kind == Ast_BinaryExpr);
ast_node(be, BinaryExpr, node);
- ExactValue x_val = {};
- if (x->mode == Addressing_Constant) {
- x_val = exact_value_to_integer(x->value);
+ bool y_is_untyped = is_type_untyped(y->type);
+ if (y_is_untyped) {
+ convert_to_typed(c, y, t_untyped_integer);
+ if (y->mode == Addressing_Invalid) {
+ x->mode = Addressing_Invalid;
+ return;
+ }
+ } else if (!is_type_unsigned(y->type)) {
+ gbString y_str = expr_to_string(y->expr);
+ error(y->expr, "Shift amount '%s' must be an unsigned integer", y_str);
+ gb_string_free(y_str);
+ x->mode = Addressing_Invalid;
+ return;
}
bool x_is_untyped = is_type_untyped(x->type);
- if (!(is_type_integer(x->type) || (x_is_untyped && x_val.kind == ExactValue_Integer))) {
- gbString err_str = expr_to_string(x->expr);
- error(node, "Shifted operand '%s' must be an integer", err_str);
- gb_string_free(err_str);
+ if (!(x_is_untyped || is_type_integer(x->type))) {
+ gbString x_str = expr_to_string(x->expr);
+ error(x->expr, "Shifted operand '%s' must be an integer", x_str);
+ gb_string_free(x_str);
x->mode = Addressing_Invalid;
return;
}
- if (is_type_unsigned(y->type)) {
-
- } else if (is_type_untyped(y->type)) {
- convert_to_typed(c, y, t_untyped_integer);
- if (y->mode == Addressing_Invalid) {
+ if (y->mode == Addressing_Constant) {
+ if (big_int_is_neg(&y->value.value_integer)) {
+ gbString y_str = expr_to_string(y->expr);
+ error(y->expr, "Shift amount '%s' cannot be negative", y_str);
+ gb_string_free(y_str);
x->mode = Addressing_Invalid;
return;
}
- } else {
- gbString err_str = expr_to_string(y->expr);
- error(node, "Shift amount '%s' must be an unsigned integer", err_str);
- gb_string_free(err_str);
- x->mode = Addressing_Invalid;
- return;
- }
+ BigInt max_shift = {};
+ big_int_from_u64(&max_shift, MAX_BIG_INT_SHIFT);
- if (x->mode == Addressing_Constant) {
- if (y->mode == Addressing_Constant) {
- ExactValue y_val = exact_value_to_integer(y->value);
- if (y_val.kind != ExactValue_Integer) {
- gbString err_str = expr_to_string(y->expr);
- error(node, "Shift amount '%s' must be an unsigned integer", err_str);
- gb_string_free(err_str);
- x->mode = Addressing_Invalid;
- return;
- }
+ if (big_int_cmp(&y->value.value_integer, &max_shift) > 0) {
+ gbString y_str = expr_to_string(y->expr);
+ error(y->expr, "Shift amount '%s' must be <= %u", y_str, MAX_BIG_INT_SHIFT);
+ gb_string_free(y_str);
+ x->mode = Addressing_Invalid;
+ return;
+ }
- BigInt max_shift = {};
- big_int_from_u64(&max_shift, MAX_BIG_INT_SHIFT);
+ if (x->mode == Addressing_Constant) {
+ if (x_is_untyped) {
+ convert_to_typed(c, x, t_untyped_integer);
+ if (x->mode == Addressing_Invalid) {
+ return;
+ }
- if (big_int_cmp(&y_val.value_integer, &max_shift) > 0) {
- gbString err_str = expr_to_string(y->expr);
- error(node, "Shift amount too large: '%s'", err_str);
- gb_string_free(err_str);
- x->mode = Addressing_Invalid;
- return;
- }
+ x->expr = node;
+ x->value = exact_value_shift(be->op.kind, exact_value_to_integer(x->value), exact_value_to_integer(y->value));
- if (!is_type_integer(x->type)) {
- // NOTE(bill): It could be an untyped float but still representable
- // as an integer
- x->type = t_untyped_integer;
+ return;
}
x->expr = node;
- x->value = exact_value_shift(be->op.kind, x_val, y_val);
+ x->value = exact_value_shift(be->op.kind, x->value, y->value);
+ check_is_expressible(c, x, x->type);
- if (is_type_typed(x->type)) {
- check_is_expressible(c, x, x->type);
- }
return;
}
- TokenPos pos = ast_token(x->expr).pos;
+ if (y_is_untyped) {
+ convert_to_typed(c, y, t_uint);
+ }
+
+ return;
+ }
+
+ if (x->mode == Addressing_Constant) {
if (x_is_untyped) {
- if (x->expr != nullptr) {
- x->expr->tav.is_lhs = true;
- }
- x->mode = Addressing_Value;
if (type_hint) {
if (is_type_integer(type_hint)) {
convert_to_typed(c, x, type_hint);
+ } else if (is_type_any(type_hint)) {
+ convert_to_typed(c, x, default_type(t_untyped_integer));
} else {
gbString x_str = expr_to_string(x->expr);
- gbString to_type = type_to_string(type_hint);
- error(node, "Conversion of shifted operand '%s' to '%s' is not allowed", x_str, to_type);
+ gbString type_str = type_to_string(type_hint);
+ error(x->expr, "Shifted operand '%s' cannot convert to non-integer type '%s'", x_str, type_str);
gb_string_free(x_str);
- gb_string_free(to_type);
+ gb_string_free(type_str);
x->mode = Addressing_Invalid;
+ return;
}
- } else if (!is_type_integer(x->type)) {
- gbString x_str = expr_to_string(x->expr);
- error(node, "Non-integer shifted operand '%s' is not allowed", x_str);
- gb_string_free(x_str);
- x->mode = Addressing_Invalid;
+ } else {
+ check_is_expressible(c, x, default_type(t_untyped_integer));
+ }
+ if (x->mode == Addressing_Invalid) {
+ return;
}
- // x->value = x_val;
- return;
}
- }
-
- if (y->mode == Addressing_Constant && big_int_is_neg(&y->value.value_integer)) {
- gbString err_str = expr_to_string(y->expr);
- error(node, "Shift amount cannot be negative: '%s'", err_str);
- gb_string_free(err_str);
- }
-
- if (!is_type_integer(x->type)) {
- gbString err_str = expr_to_string(x->expr);
- error(node, "Shift operand '%s' must be an integer", err_str);
- gb_string_free(err_str);
- x->mode = Addressing_Invalid;
- return;
- }
- if (is_type_untyped(y->type)) {
- convert_to_typed(c, y, t_uint);
+ x->mode = Addressing_Value;
}
-
- x->mode = Addressing_Value;
}
-
-
gb_internal bool check_is_castable_to(CheckerContext *c, Operand *operand, Type *y) {
if (check_is_assignable_to(c, operand, y)) {
return true;
@@ -3649,7 +3670,8 @@ gb_internal bool check_transmute(CheckerContext *c, Ast *node, Operand *o, Type
gb_string_free(oper_str);
gb_string_free(to_type);
} else if (is_type_integer(src_t) && is_type_integer(dst_t) &&
- types_have_same_internal_endian(src_t, dst_t)) {
+ types_have_same_internal_endian(src_t, dst_t) &&
+ type_endian_kind_of(src_t) == type_endian_kind_of(dst_t)) {
gbString oper_type = type_to_string(src_t);
gbString to_type = type_to_string(dst_t);
error(o->expr, "Use of 'transmute' where 'cast' would be preferred since both are integers of the same endianness, from '%s' to '%s'", oper_type, to_type);
@@ -3665,6 +3687,11 @@ gb_internal bool check_transmute(CheckerContext *c, Ast *node, Operand *o, Type
}
gb_internal bool check_binary_array_expr(CheckerContext *c, Token op, Operand *x, Operand *y) {
+ if (is_type_array_like(x->type) || is_type_array_like(y->type)) {
+ if (op.kind == Token_CmpAnd || op.kind == Token_CmpOr) {
+ error(op, "Array programming is not allowed with the operator '%.*s'", LIT(op.string));
+ }
+ }
if (is_type_array(x->type) && !is_type_array(y->type)) {
if (check_is_assignable_to(c, y, x->type)) {
if (check_binary_op(c, x, op)) {
@@ -3840,6 +3867,59 @@ matrix_error:
}
+gb_internal void check_binary_expr_dependency(CheckerContext *c, Token op, Type *bt, bool REQUIRE) {
+ if (op.kind == Token_Mod || op.kind == Token_ModEq ||
+ op.kind == Token_ModMod || op.kind == Token_ModModEq) {
+ if (bt->kind == Type_Basic) switch (bt->Basic.kind) {
+ case Basic_u128: add_package_dependency(c, "runtime", "umodti3", REQUIRE); break;
+ case Basic_i128: add_package_dependency(c, "runtime", "modti3", REQUIRE); break;
+ }
+ } else if (op.kind == Token_Quo || op.kind == Token_QuoEq) {
+ if (bt->kind == Type_Basic) switch (bt->Basic.kind) {
+ case Basic_complex32: add_package_dependency(c, "runtime", "quo_complex32"); break;
+ case Basic_complex64: add_package_dependency(c, "runtime", "quo_complex64"); break;
+ case Basic_complex128: add_package_dependency(c, "runtime", "quo_complex128"); break;
+ case Basic_quaternion64: add_package_dependency(c, "runtime", "quo_quaternion64"); break;
+ case Basic_quaternion128: add_package_dependency(c, "runtime", "quo_quaternion128"); break;
+ case Basic_quaternion256: add_package_dependency(c, "runtime", "quo_quaternion256"); break;
+
+ case Basic_u128: add_package_dependency(c, "runtime", "udivti3", REQUIRE); break;
+ case Basic_i128: add_package_dependency(c, "runtime", "divti3", REQUIRE); break;
+ }
+ } else if (op.kind == Token_Mul || op.kind == Token_MulEq) {
+ if (bt->kind == Type_Basic) switch (bt->Basic.kind) {
+ case Basic_quaternion64: add_package_dependency(c, "runtime", "mul_quaternion64"); break;
+ case Basic_quaternion128: add_package_dependency(c, "runtime", "mul_quaternion128"); break;
+ case Basic_quaternion256: add_package_dependency(c, "runtime", "mul_quaternion256"); break;
+
+
+ case Basic_u128:
+ case Basic_i128:
+ if (is_arch_wasm()) {
+ add_package_dependency(c, "runtime", "__multi3", REQUIRE);
+ }
+ break;
+ }
+ } else if (op.kind == Token_Shl || op.kind == Token_ShlEq) {
+ if (bt->kind == Type_Basic) switch (bt->Basic.kind) {
+ case Basic_u128:
+ case Basic_i128:
+ if (is_arch_wasm()) {
+ add_package_dependency(c, "runtime", "__ashlti3", REQUIRE);
+ }
+ break;
+ }
+ } else if (op.kind == Token_Shr || op.kind == Token_ShrEq) {
+ if (bt->kind == Type_Basic) switch (bt->Basic.kind) {
+ case Basic_u128:
+ case Basic_i128:
+ if (is_arch_wasm()) {
+ add_package_dependency(c, "runtime", "__lshrti3", REQUIRE);
+ }
+ break;
+ }
+ }
+}
gb_internal void check_binary_expr(CheckerContext *c, Operand *x, Ast *node, Type *type_hint, bool use_lhs_as_type_hint=false) {
GB_ASSERT(node->kind == Ast_BinaryExpr);
@@ -4037,58 +4117,10 @@ gb_internal void check_binary_expr(CheckerContext *c, Operand *x, Ast *node, Typ
}
bool REQUIRE = true;
- Type *bt = base_type(x->type);
- if (op.kind == Token_Mod || op.kind == Token_ModEq ||
- op.kind == Token_ModMod || op.kind == Token_ModModEq) {
- if (bt->kind == Type_Basic) switch (bt->Basic.kind) {
- case Basic_u128: add_package_dependency(c, "runtime", "umodti3", REQUIRE); break;
- case Basic_i128: add_package_dependency(c, "runtime", "modti3", REQUIRE); break;
- }
- } else if (op.kind == Token_Quo || op.kind == Token_QuoEq) {
- if (bt->kind == Type_Basic) switch (bt->Basic.kind) {
- case Basic_complex32: add_package_dependency(c, "runtime", "quo_complex32"); break;
- case Basic_complex64: add_package_dependency(c, "runtime", "quo_complex64"); break;
- case Basic_complex128: add_package_dependency(c, "runtime", "quo_complex128"); break;
- case Basic_quaternion64: add_package_dependency(c, "runtime", "quo_quaternion64"); break;
- case Basic_quaternion128: add_package_dependency(c, "runtime", "quo_quaternion128"); break;
- case Basic_quaternion256: add_package_dependency(c, "runtime", "quo_quaternion256"); break;
-
- case Basic_u128: add_package_dependency(c, "runtime", "udivti3", REQUIRE); break;
- case Basic_i128: add_package_dependency(c, "runtime", "divti3", REQUIRE); break;
- }
- } else if (op.kind == Token_Mul || op.kind == Token_MulEq) {
- if (bt->kind == Type_Basic) switch (bt->Basic.kind) {
- case Basic_quaternion64: add_package_dependency(c, "runtime", "mul_quaternion64"); break;
- case Basic_quaternion128: add_package_dependency(c, "runtime", "mul_quaternion128"); break;
- case Basic_quaternion256: add_package_dependency(c, "runtime", "mul_quaternion256"); break;
-
-
- case Basic_u128:
- case Basic_i128:
- if (is_arch_wasm()) {
- add_package_dependency(c, "runtime", "__multi3", REQUIRE);
- }
- break;
- }
- } else if (op.kind == Token_Shl || op.kind == Token_ShlEq) {
- if (bt->kind == Type_Basic) switch (bt->Basic.kind) {
- case Basic_u128:
- case Basic_i128:
- if (is_arch_wasm()) {
- add_package_dependency(c, "runtime", "__ashlti3", REQUIRE);
- }
- break;
- }
- } else if (op.kind == Token_Shr || op.kind == Token_ShrEq) {
- if (bt->kind == Type_Basic) switch (bt->Basic.kind) {
- case Basic_u128:
- case Basic_i128:
- if (is_arch_wasm()) {
- add_package_dependency(c, "runtime", "__lshrti3", REQUIRE);
- }
- break;
- }
- }
+ Type *btx = base_type(x->type);
+ Type *bty = base_type(y->type);
+ check_binary_expr_dependency(c, op, btx, REQUIRE);
+ check_binary_expr_dependency(c, op, bty, REQUIRE);
if (token_is_shift(op.kind)) {
check_shift(c, x, y, node, type_hint);
@@ -4503,8 +4535,7 @@ gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *tar
} else {
switch (operand->type->Basic.kind) {
case Basic_UntypedBool:
- if (!is_type_boolean(target_type) &&
- !is_type_integer(target_type)) {
+ if (!is_type_boolean(target_type)) {
operand->mode = Addressing_Invalid;
convert_untyped_error(c, operand, target_type);
return;
@@ -5330,16 +5361,6 @@ gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *nod
return nullptr;
}
- check_entity_decl(c, entity, nullptr, nullptr);
- if (entity->kind == Entity_ProcGroup) {
- operand->mode = Addressing_ProcGroup;
- operand->proc_group = entity;
-
- add_type_and_value(c, operand->expr, operand->mode, operand->type, operand->value);
- return entity;
- }
- GB_ASSERT_MSG(entity->type != nullptr, "%.*s (%.*s)", LIT(entity->token.string), LIT(entity_strings[entity->kind]));
-
if (!is_entity_exported(entity, allow_builtin)) {
gbString sel_str = expr_to_string(selector);
error(node, "'%s' is not exported by '%.*s'", sel_str, LIT(import_name));
@@ -5350,36 +5371,15 @@ gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *nod
// return nullptr;
}
+ check_entity_decl(c, entity, nullptr, nullptr);
if (entity->kind == Entity_ProcGroup) {
- Array<Entity *> procs = entity->ProcGroup.entities;
- bool skip = false;
- for (Entity *p : procs) {
- Type *t = base_type(p->type);
- if (t == t_invalid) {
- continue;
- }
-
- Operand x = {};
- x.mode = Addressing_Value;
- x.type = t;
- if (type_hint != nullptr) {
- if (check_is_assignable_to(c, &x, type_hint)) {
- entity = p;
- skip = true;
- break;
- }
- }
- }
+ operand->mode = Addressing_ProcGroup;
+ operand->proc_group = entity;
- if (!skip) {
- GB_ASSERT(entity != nullptr);
- operand->mode = Addressing_ProcGroup;
- operand->type = t_invalid;
- operand->expr = node;
- operand->proc_group = entity;
- return entity;
- }
+ add_type_and_value(c, operand->expr, operand->mode, operand->type, operand->value);
+ return entity;
}
+ GB_ASSERT_MSG(entity->type != nullptr, "%.*s (%.*s)", LIT(entity->token.string), LIT(entity_strings[entity->kind]));
}
}
@@ -5418,8 +5418,18 @@ gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *nod
}
}
+ if (operand->type && is_type_simd_vector(type_deref(operand->type))) {
+ String field_name = selector->Ident.token.string;
+ if (field_name.len == 1) {
+ error(op_expr, "Extracting an element from a #simd array using .%.*s syntax is disallowed, prefer `simd.extract`", LIT(field_name));
+ } else {
+ error(op_expr, "Extracting elements from a #simd array using .%.*s syntax is disallowed, prefer `swizzle`", LIT(field_name));
+ }
+ return nullptr;
+ }
+
if (entity == nullptr && selector->kind == Ast_Ident && operand->type != nullptr &&
- (is_type_array(type_deref(operand->type)) || is_type_simd_vector(type_deref(operand->type)))) {
+ (is_type_array(type_deref(operand->type)))) {
String field_name = selector->Ident.token.string;
if (1 < field_name.len && field_name.len <= 4) {
u8 swizzles_xyzw[4] = {'x', 'y', 'z', 'w'};
@@ -5474,7 +5484,7 @@ gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *nod
Type *original_type = operand->type;
Type *array_type = base_type(type_deref(original_type));
- GB_ASSERT(array_type->kind == Type_Array || array_type->kind == Type_SimdVector);
+ GB_ASSERT(array_type->kind == Type_Array);
i64 array_count = get_array_type_count(array_type);
@@ -5508,10 +5518,11 @@ gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *nod
case Addressing_SwizzleVariable:
operand->mode = Addressing_SwizzleVariable;
break;
- }
-
- if (array_type->kind == Type_SimdVector) {
- operand->mode = Addressing_Value;
+ case Addressing_Value:
+ if (is_type_pointer(original_type)) {
+ operand->mode = Addressing_SwizzleVariable;
+ }
+ break;
}
Entity *swizzle_entity = alloc_entity_variable(nullptr, make_token_ident(field_name), operand->type, EntityState_Resolved);
@@ -5853,12 +5864,12 @@ typedef u32 UnpackFlags;
enum UnpackFlag : u32 {
UnpackFlag_None = 0,
UnpackFlag_AllowOk = 1<<0,
- UnpackFlag_IsVariadic = 1<<1,
- UnpackFlag_AllowUndef = 1<<2,
+ UnpackFlag_AllowUndef = 1<<1,
};
-gb_internal bool check_unpack_arguments(CheckerContext *ctx, Entity **lhs, isize lhs_count, Array<Operand> *operands, Slice<Ast *> const &rhs_arguments, UnpackFlags flags) {
+gb_internal bool check_unpack_arguments(CheckerContext *ctx, Entity **lhs, isize lhs_count, Array<Operand> *operands, Slice<Ast *> const &rhs_arguments, UnpackFlags flags,
+ isize variadic_index = -1) {
auto const &add_dependencies_from_unpacking = [](CheckerContext *c, Entity **lhs, isize lhs_count, isize tuple_index, isize tuple_count) -> isize {
if (lhs == nullptr || c->decl == nullptr) {
return tuple_count;
@@ -5883,11 +5894,14 @@ gb_internal bool check_unpack_arguments(CheckerContext *ctx, Entity **lhs, isize
return tuple_count;
};
-
bool allow_ok = (flags & UnpackFlag_AllowOk) != 0;
- bool is_variadic = (flags & UnpackFlag_IsVariadic) != 0;
bool allow_undef = (flags & UnpackFlag_AllowUndef) != 0;
+ bool is_variadic = variadic_index > -1;
+ if (!is_variadic) {
+ variadic_index = lhs_count;
+ }
+
bool optional_ok = false;
isize tuple_index = 0;
for (Ast *rhs : rhs_arguments) {
@@ -5903,26 +5917,18 @@ gb_internal bool check_unpack_arguments(CheckerContext *ctx, Entity **lhs, isize
Type *type_hint = nullptr;
-
- if (lhs != nullptr && tuple_index < lhs_count) {
- // NOTE(bill): override DeclInfo for dependency
- Entity *e = lhs[tuple_index];
- if (e != nullptr) {
- type_hint = e->type;
- if (e->flags & EntityFlag_Ellipsis) {
- GB_ASSERT(is_type_slice(e->type));
- GB_ASSERT(e->type->kind == Type_Slice);
- type_hint = e->type->Slice.elem;
+ if (lhs != nullptr) {
+ if (tuple_index < variadic_index) {
+ // NOTE(bill): override DeclInfo for dependency
+ Entity *e = lhs[tuple_index];
+ if (e != nullptr) {
+ type_hint = e->type;
}
- }
- } else if (lhs != nullptr && tuple_index >= lhs_count && is_variadic) {
- // NOTE(bill): override DeclInfo for dependency
- Entity *e = lhs[lhs_count-1];
- if (e != nullptr) {
- type_hint = e->type;
- if (e->flags & EntityFlag_Ellipsis) {
+ } else if (is_variadic) {
+ Entity *e = lhs[variadic_index];
+ if (e != nullptr) {
+ GB_ASSERT(e->flags & EntityFlag_Ellipsis);
GB_ASSERT(is_type_slice(e->type));
- GB_ASSERT(e->type->kind == Type_Slice);
type_hint = e->type->Slice.elem;
}
}
@@ -6462,17 +6468,16 @@ gb_internal bool is_call_expr_field_value(AstCallExpr *ce) {
return ce->args[0]->kind == Ast_FieldValue;
}
-gb_internal Entity **populate_proc_parameter_list(CheckerContext *c, Type *proc_type, isize *lhs_count_, bool *is_variadic) {
+gb_internal Entity **populate_proc_parameter_list(CheckerContext *c, Type *proc_type, isize *lhs_count_) {
Entity **lhs = nullptr;
isize lhs_count = -1;
- if (proc_type == nullptr) {
+ if (proc_type == nullptr || proc_type == t_invalid) {
return nullptr;
}
GB_ASSERT(is_type_proc(proc_type));
TypeProc *pt = &base_type(proc_type)->Proc;
- *is_variadic = pt->variadic;
if (!pt->is_polymorphic || pt->is_poly_specialized) {
if (pt->params != nullptr) {
@@ -6666,6 +6671,9 @@ gb_internal bool check_call_arguments_single(CheckerContext *c, Ast *call, Opera
GB_ASSERT(proc_type != nullptr);
proc_type = base_type(proc_type);
+ if (proc_type == t_invalid) {
+ return false;
+ }
GB_ASSERT(proc_type->kind == Type_Proc);
CallArgumentError err = check_call_arguments_internal(c, call, e, proc_type, positional_operands, named_operands, show_error_mode, data);
@@ -6799,7 +6807,7 @@ gb_internal CallArgumentData check_call_arguments_proc_group(CheckerContext *c,
Entity **lhs = nullptr;
isize lhs_count = -1;
- bool is_variadic = false;
+ i32 variadic_index = -1;
auto positional_operands = array_make<Operand>(heap_allocator(), 0, 0);
auto named_operands = array_make<Operand>(heap_allocator(), 0, 0);
@@ -6808,9 +6816,14 @@ gb_internal CallArgumentData check_call_arguments_proc_group(CheckerContext *c,
if (procs.count == 1) {
Entity *e = procs[0];
-
- lhs = populate_proc_parameter_list(c, e->type, &lhs_count, &is_variadic);
- check_unpack_arguments(c, lhs, lhs_count, &positional_operands, positional_args, is_variadic ? UnpackFlag_IsVariadic : UnpackFlag_None);
+ Type *pt = base_type(e->type);
+ if (pt != nullptr && is_type_proc(pt)) {
+ lhs = populate_proc_parameter_list(c, pt, &lhs_count);
+ if (pt->Proc.variadic) {
+ variadic_index = pt->Proc.variadic_index;
+ }
+ }
+ check_unpack_arguments(c, lhs, lhs_count, &positional_operands, positional_args, UnpackFlag_None, variadic_index);
if (check_named_arguments(c, e->type, named_args, &named_operands, true)) {
check_call_arguments_single(c, call, operand,
@@ -6870,11 +6883,30 @@ gb_internal CallArgumentData check_call_arguments_proc_group(CheckerContext *c,
}
lhs[param_index] = e;
}
+
+ for (Entity *p : procs) {
+ Type *pt = base_type(p->type);
+ if (!(pt != nullptr && is_type_proc(pt))) {
+ continue;
+ }
+
+ if (pt->Proc.is_polymorphic) {
+ if (variadic_index == -1) {
+ variadic_index = pt->Proc.variadic_index;
+ } else if (variadic_index != pt->Proc.variadic_index) {
+ variadic_index = -1;
+ break;
+ }
+ } else {
+ variadic_index = -1;
+ break;
+ }
+ }
}
}
}
- check_unpack_arguments(c, lhs, lhs_count, &positional_operands, positional_args, is_variadic ? UnpackFlag_IsVariadic : UnpackFlag_None);
+ check_unpack_arguments(c, lhs, lhs_count, &positional_operands, positional_args, UnpackFlag_None, variadic_index);
for_array(i, named_args) {
Ast *arg = named_args[i];
@@ -7312,13 +7344,16 @@ gb_internal CallArgumentData check_call_arguments(CheckerContext *c, Operand *op
defer (array_free(&named_operands));
if (positional_args.count > 0) {
- isize lhs_count = -1;
- bool is_variadic = false;
Entity **lhs = nullptr;
+ isize lhs_count = -1;
+ i32 variadic_index = -1;
if (pt != nullptr) {
- lhs = populate_proc_parameter_list(c, proc_type, &lhs_count, &is_variadic);
+ lhs = populate_proc_parameter_list(c, proc_type, &lhs_count);
+ if (pt->variadic) {
+ variadic_index = pt->variadic_index;
+ }
}
- check_unpack_arguments(c, lhs, lhs_count, &positional_operands, positional_args, is_variadic ? UnpackFlag_IsVariadic : UnpackFlag_None);
+ check_unpack_arguments(c, lhs, lhs_count, &positional_operands, positional_args, UnpackFlag_None, variadic_index);
}
if (named_args.count > 0) {
@@ -7906,7 +7941,27 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c
default:
{
gbString str = type_to_string(t);
- error(call, "Too many arguments in conversion to '%s'", str);
+ if (t->kind == Type_Basic) {
+ ERROR_BLOCK();
+ switch (t->Basic.kind) {
+ case Basic_complex32:
+ case Basic_complex64:
+ case Basic_complex128:
+ error(call, "Too many arguments in conversion to '%s'", str);
+ error_line("\tSuggestion: %s(1+2i) or construct with 'complex'\n", str);
+ break;
+ case Basic_quaternion64:
+ case Basic_quaternion128:
+ case Basic_quaternion256:
+ error(call, "Too many arguments in conversion to '%s'", str);
+ error_line("\tSuggestion: %s(1+2i+3j+4k) or construct with 'quaternion'\n", str);
+ break;
+ default:
+ error(call, "Too many arguments in conversion to '%s'", str);
+ }
+ } else {
+ error(call, "Too many arguments in conversion to '%s'", str);
+ }
gb_string_free(str);
} break;
case 1: {
@@ -8022,7 +8077,9 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c
if (pt->kind == Type_Proc && pt->Proc.calling_convention == ProcCC_Odin) {
if ((c->scope->flags & ScopeFlag_ContextDefined) == 0) {
+ ERROR_BLOCK();
error(call, "'context' has not been defined within this scope, but is required for this procedure call");
+ error_line("\tSuggestion: 'context = runtime.default_context()'");
}
}
@@ -8126,7 +8183,7 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c
type = pt;
}
type = base_type(type);
- if (type->kind == Type_Proc && type->Proc.optional_ok) {
+ if (type->kind == Type_Proc && type->Proc.optional_ok && type->Proc.result_count > 0) {
operand->mode = Addressing_OptionalOk;
operand->type = type->Proc.results->Tuple.variables[0]->type;
if (operand->expr != nullptr && operand->expr->kind == Ast_CallExpr) {
@@ -8703,23 +8760,52 @@ gb_internal ExprKind check_basic_directive_expr(CheckerContext *c, Operand *o, A
String name = bd->name.string;
if (name == "file") {
String file = get_file_path_string(bd->token.pos.file_id);
- if (build_context.obfuscate_source_code_locations) {
+ switch (build_context.source_code_location_info) {
+ case SourceCodeLocationInfo_Normal:
+ break;
+ case SourceCodeLocationInfo_Obfuscated:
file = obfuscate_string(file, "F");
+ break;
+ case SourceCodeLocationInfo_Filename:
+ file = last_path_element(file);
+ break;
+ case SourceCodeLocationInfo_None:
+ file = str_lit("");
+ break;
}
o->type = t_untyped_string;
o->value = exact_value_string(file);
} else if (name == "directory") {
String file = get_file_path_string(bd->token.pos.file_id);
String path = dir_from_path(file);
- if (build_context.obfuscate_source_code_locations) {
+ switch (build_context.source_code_location_info) {
+ case SourceCodeLocationInfo_Normal:
+ break;
+ case SourceCodeLocationInfo_Obfuscated:
path = obfuscate_string(path, "D");
+ break;
+ case SourceCodeLocationInfo_Filename:
+ path = last_path_element(path);
+ break;
+ case SourceCodeLocationInfo_None:
+ path = str_lit("");
+ break;
}
o->type = t_untyped_string;
o->value = exact_value_string(path);
} else if (name == "line") {
i32 line = bd->token.pos.line;
- if (build_context.obfuscate_source_code_locations) {
+ switch (build_context.source_code_location_info) {
+ case SourceCodeLocationInfo_Normal:
+ break;
+ case SourceCodeLocationInfo_Obfuscated:
line = obfuscate_i32(line);
+ break;
+ case SourceCodeLocationInfo_Filename:
+ break;
+ case SourceCodeLocationInfo_None:
+ line = 0;
+ break;
}
o->type = t_untyped_integer;
o->value = exact_value_i64(line);
@@ -8730,8 +8816,17 @@ gb_internal ExprKind check_basic_directive_expr(CheckerContext *c, Operand *o, A
o->value = exact_value_string(str_lit(""));
} else {
String p = c->proc_name;
- if (build_context.obfuscate_source_code_locations) {
+ switch (build_context.source_code_location_info) {
+ case SourceCodeLocationInfo_Normal:
+ break;
+ case SourceCodeLocationInfo_Obfuscated:
p = obfuscate_string(p, "P");
+ break;
+ case SourceCodeLocationInfo_Filename:
+ break;
+ case SourceCodeLocationInfo_None:
+ p = str_lit("");
+ break;
}
o->type = t_untyped_string;
o->value = exact_value_string(p);
@@ -8963,8 +9058,14 @@ gb_internal ExprKind check_or_else_expr(CheckerContext *c, Operand *o, Ast *node
o->expr = node;
return Expr_Expr;
}
+
+ Type *left_type = nullptr;
+ Type *right_type = nullptr;
+ check_or_else_split_types(c, &x, name, &left_type, &right_type);
+ add_type_and_value(c, arg, x.mode, x.type, x.value);
+
bool y_is_diverging = false;
- check_expr_base(c, &y, default_value, x.type);
+ check_expr_base(c, &y, default_value, left_type);
switch (y.mode) {
case Addressing_NoValue:
if (is_diverging_expr(y.expr)) {
@@ -8989,14 +9090,21 @@ gb_internal ExprKind check_or_else_expr(CheckerContext *c, Operand *o, Ast *node
return Expr_Expr;
}
- Type *left_type = nullptr;
- Type *right_type = nullptr;
- check_or_else_split_types(c, &x, name, &left_type, &right_type);
- add_type_and_value(c, arg, x.mode, x.type, x.value);
-
if (left_type != nullptr) {
if (!y_is_diverging) {
- check_assignment(c, &y, left_type, name);
+ if (is_type_tuple(left_type)) {
+ if (!is_type_tuple(y.type)) {
+ error(y.expr, "Found a single value where a %td-valued expression was expected", left_type->Tuple.variables.count);
+ } else if (!are_types_identical(left_type, y.type)) {
+ gbString xt = type_to_string(left_type);
+ gbString yt = type_to_string(y.type);
+ error(y.expr, "Mismatched types, expected (%s), got (%s)", xt, yt);
+ gb_string_free(yt);
+ gb_string_free(xt);
+ }
+ } else {
+ check_assignment(c, &y, left_type, name);
+ }
}
} else {
check_or_else_expr_no_value_error(c, name, x, type_hint);
@@ -9372,7 +9480,7 @@ gb_internal bool is_expr_inferred_fixed_array(Ast *type_expr) {
}
gb_internal bool check_for_dynamic_literals(CheckerContext *c, Ast *node, AstCompoundLit *cl) {
- if (cl->elems.count > 0 && (check_feature_flags(c, node) & OptInFeatureFlag_DynamicLiterals) == 0) {
+ if (cl->elems.count > 0 && (check_feature_flags(c, node) & OptInFeatureFlag_DynamicLiterals) == 0 && !build_context.dynamic_literals) {
ERROR_BLOCK();
error(node, "Compound literals of dynamic types are disabled by default");
error_line("\tSuggestion: If you want to enable them for this specific file, add '#+feature dynamic-literals' at the top of the file\n");
@@ -9398,6 +9506,7 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *
}
bool is_to_be_determined_array_count = false;
bool is_constant = true;
+ bool is_soa = false;
Ast *type_expr = cl->type;
@@ -9430,8 +9539,14 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *
GB_ASSERT(tag->kind == Ast_BasicDirective);
String name = tag->BasicDirective.name.string;
if (name == "soa") {
- error(node, "#soa arrays are not supported for compound literals");
- return kind;
+ is_soa = true;
+ if (count == nullptr) {
+ error(node, "#soa slices are not supported for compound literals");
+ return kind;
+ } else if (count->kind == Ast_UnaryExpr &&
+ count->UnaryExpr.op.kind == Token_Question) {
+ error(node, "#soa fixed length arrays must specify their length and cannot use ?");
+ }
}
}
}
@@ -9441,7 +9556,8 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *
GB_ASSERT(tag->kind == Ast_BasicDirective);
String name = tag->BasicDirective.name.string;
if (name == "soa") {
- error(node, "#soa arrays are not supported for compound literals");
+ is_soa = true;
+ error(node, "#soa dynamic arrays are not supported for compound literals");
return kind;
}
}
@@ -9470,101 +9586,101 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *
switch (t->kind) {
- case Type_Struct: {
+ case Type_Struct:
if (cl->elems.count == 0) {
break; // NOTE(bill): No need to init
}
- if (t->Struct.soa_kind != StructSoa_None) {
- error(node, "#soa arrays are not supported for compound literals");
- break;
- }
-
- if (t->Struct.is_raw_union) {
- if (cl->elems.count > 0) {
- // NOTE: unions cannot be constant
- is_constant = false;
+ if (t->Struct.soa_kind == StructSoa_None) {
+ if (t->Struct.is_raw_union) {
+ if (cl->elems.count > 0) {
+ // NOTE: unions cannot be constant
+ is_constant = false;
- if (cl->elems[0]->kind != Ast_FieldValue) {
- gbString type_str = type_to_string(type);
- error(node, "%s ('struct #raw_union') compound literals are only allowed to contain 'field = value' elements", type_str);
- gb_string_free(type_str);
- } else {
- if (cl->elems.count != 1) {
+ if (cl->elems[0]->kind != Ast_FieldValue) {
gbString type_str = type_to_string(type);
- error(node, "%s ('struct #raw_union') compound literals are only allowed to contain up to 1 'field = value' element, got %td", type_str, cl->elems.count);
+ error(node, "%s ('struct #raw_union') compound literals are only allowed to contain 'field = value' elements", type_str);
gb_string_free(type_str);
} else {
- check_compound_literal_field_values(c, cl->elems, o, type, is_constant);
+ if (cl->elems.count != 1) {
+ gbString type_str = type_to_string(type);
+ error(node, "%s ('struct #raw_union') compound literals are only allowed to contain up to 1 'field = value' element, got %td", type_str, cl->elems.count);
+ gb_string_free(type_str);
+ } else {
+ check_compound_literal_field_values(c, cl->elems, o, type, is_constant);
+ }
}
}
- }
- break;
- }
-
- wait_signal_until_available(&t->Struct.fields_wait_signal);
- isize field_count = t->Struct.fields.count;
- isize min_field_count = t->Struct.fields.count;
- for (isize i = min_field_count-1; i >= 0; i--) {
- Entity *e = t->Struct.fields[i];
- GB_ASSERT(e->kind == Entity_Variable);
- if (e->Variable.param_value.kind != ParameterValue_Invalid) {
- min_field_count--;
- } else {
break;
}
- }
-
- if (cl->elems[0]->kind == Ast_FieldValue) {
- check_compound_literal_field_values(c, cl->elems, o, type, is_constant);
- } else {
- bool seen_field_value = false;
- for_array(index, cl->elems) {
- Entity *field = nullptr;
- Ast *elem = cl->elems[index];
- if (elem->kind == Ast_FieldValue) {
- seen_field_value = true;
- error(elem, "Mixture of 'field = value' and value elements in a literal is not allowed");
- continue;
- } else if (seen_field_value) {
- error(elem, "Value elements cannot be used after a 'field = value'");
- continue;
- }
- if (index >= field_count) {
- error(elem, "Too many values in structure literal, expected %td, got %td", field_count, cl->elems.count);
+ wait_signal_until_available(&t->Struct.fields_wait_signal);
+ isize field_count = t->Struct.fields.count;
+ isize min_field_count = t->Struct.fields.count;
+ for (isize i = min_field_count-1; i >= 0; i--) {
+ Entity *e = t->Struct.fields[i];
+ GB_ASSERT(e->kind == Entity_Variable);
+ if (e->Variable.param_value.kind != ParameterValue_Invalid) {
+ min_field_count--;
+ } else {
break;
}
+ }
- if (field == nullptr) {
- field = t->Struct.fields[index];
- }
+ if (cl->elems[0]->kind == Ast_FieldValue) {
+ check_compound_literal_field_values(c, cl->elems, o, type, is_constant);
+ } else {
+ bool seen_field_value = false;
- Operand o = {};
- check_expr_or_type(c, &o, elem, field->type);
+ for_array(index, cl->elems) {
+ Entity *field = nullptr;
+ Ast *elem = cl->elems[index];
+ if (elem->kind == Ast_FieldValue) {
+ seen_field_value = true;
+ error(elem, "Mixture of 'field = value' and value elements in a literal is not allowed");
+ continue;
+ } else if (seen_field_value) {
+ error(elem, "Value elements cannot be used after a 'field = value'");
+ continue;
+ }
+ if (index >= field_count) {
+ error(elem, "Too many values in structure literal, expected %td, got %td", field_count, cl->elems.count);
+ break;
+ }
- if (is_type_any(field->type) || is_type_union(field->type) || is_type_raw_union(field->type) || is_type_typeid(field->type)) {
- is_constant = false;
- }
- if (is_constant) {
- is_constant = check_is_operand_compound_lit_constant(c, &o);
- }
+ if (field == nullptr) {
+ field = t->Struct.fields[index];
+ }
- check_assignment(c, &o, field->type, str_lit("structure literal"));
- }
- if (cl->elems.count < field_count) {
- if (min_field_count < field_count) {
- if (cl->elems.count < min_field_count) {
- error(cl->close, "Too few values in structure literal, expected at least %td, got %td", min_field_count, cl->elems.count);
- }
- } else {
- error(cl->close, "Too few values in structure literal, expected %td, got %td", field_count, cl->elems.count);
+ Operand o = {};
+ check_expr_or_type(c, &o, elem, field->type);
+
+ if (is_type_any(field->type) || is_type_union(field->type) || is_type_raw_union(field->type) || is_type_typeid(field->type)) {
+ is_constant = false;
+ }
+ if (is_constant) {
+ is_constant = check_is_operand_compound_lit_constant(c, &o);
+ }
+
+ check_assignment(c, &o, field->type, str_lit("structure literal"));
+ }
+ if (cl->elems.count < field_count) {
+ if (min_field_count < field_count) {
+ if (cl->elems.count < min_field_count) {
+ error(cl->close, "Too few values in structure literal, expected at least %td, got %td", min_field_count, cl->elems.count);
+ }
+ } else {
+ error(cl->close, "Too few values in structure literal, expected %td, got %td", field_count, cl->elems.count);
+ }
}
}
- }
- break;
- }
+ break;
+ } else if (t->Struct.soa_kind != StructSoa_Fixed) {
+ error(node, "#soa slices and dynamic arrays are not supported for compound literals");
+ break;
+ }
+ /*fallthrough*/
case Type_Slice:
case Type_Array:
@@ -9575,7 +9691,14 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *
Type *elem_type = nullptr;
String context_name = {};
i64 max_type_count = -1;
- if (t->kind == Type_Slice) {
+ if (t->kind == Type_Struct) {
+ GB_ASSERT(t->Struct.soa_kind == StructSoa_Fixed);
+ elem_type = t->Struct.soa_elem;
+ context_name = str_lit("#soa array literal");
+ if (!is_to_be_determined_array_count) {
+ max_type_count = t->Struct.soa_count;
+ }
+ } else if (t->kind == Type_Slice) {
elem_type = t->Slice.elem;
context_name = str_lit("slice literal");
} else if (t->kind == Type_Array) {
@@ -9584,6 +9707,12 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *
if (!is_to_be_determined_array_count) {
max_type_count = t->Array.count;
}
+ } else if (t->kind == Type_Array) {
+ elem_type = t->Array.elem;
+ context_name = str_lit("array literal");
+ if (!is_to_be_determined_array_count) {
+ max_type_count = t->Array.count;
+ }
} else if (t->kind == Type_DynamicArray) {
elem_type = t->DynamicArray.elem;
context_name = str_lit("dynamic array literal");
@@ -9751,6 +9880,15 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *
error(node, "Expected %lld values for this array literal, got %lld", cast(long long)t->Array.count, cast(long long)max);
}
}
+ } else if (t->kind == Type_Struct) {
+ GB_ASSERT(t->Struct.soa_kind == StructSoa_Fixed);
+ if (is_to_be_determined_array_count) {
+ t->Struct.soa_count = cast(i32)max;
+ } else if (cl->elems.count > 0 && cl->elems[0]->kind != Ast_FieldValue) {
+ if (0 < max && max < t->Struct.soa_count) {
+ error(node, "Expected %lld values for this #soa array literal, got %lld", cast(long long)t->Struct.soa_count, cast(long long)max);
+ }
+ }
}
@@ -10375,7 +10513,7 @@ gb_internal ExprKind check_type_assertion(CheckerContext *c, Operand *o, Ast *no
add_type_info_type(c, o->type);
o->type = type_hint;
o->mode = Addressing_OptionalOk;
- return kind;
+ goto end;
}
}
@@ -10440,6 +10578,8 @@ gb_internal ExprKind check_type_assertion(CheckerContext *c, Operand *o, Ast *no
}
}
+end:;
+
if ((c->state_flags & StateFlag_no_type_assert) == 0) {
add_package_dependency(c, "runtime", "type_assertion_check");
add_package_dependency(c, "runtime", "type_assertion_check2");
@@ -10953,7 +11093,7 @@ gb_internal ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast
return kind;
case_end;
- case_ast_node(i, Implicit, node)
+ case_ast_node(i, Implicit, node);
switch (i->kind) {
case Token_context:
{
@@ -10989,7 +11129,7 @@ gb_internal ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast
case_ast_node(u, Uninit, node);
o->mode = Addressing_Value;
o->type = t_untyped_uninit;
- error(node, "Use of --- outside of variable declaration");
+ error(node, "Global variables will always be zeroed if left unassigned, --- is disallowed");
case_end;
@@ -11224,6 +11364,13 @@ gb_internal ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast
o->mode = Addressing_Invalid;
o->expr = node;
return kind;
+ } else if (o->mode == Addressing_Type) {
+ gbString str = expr_to_string(o->expr);
+ error(o->expr, "Cannot dereference '%s' because it is a type", str);
+
+ o->mode = Addressing_Invalid;
+ o->expr = node;
+ return kind;
} else {
Type *t = base_type(o->type);
if (t->kind == Type_Pointer && !is_type_empty_union(t->Pointer.elem)) {
diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp
index 1708f7c81..07801b477 100644
--- a/src/check_stmt.cpp
+++ b/src/check_stmt.cpp
@@ -418,7 +418,7 @@ gb_internal bool check_is_terminating(Ast *node, String const &label) {
-gb_internal Type *check_assignment_variable(CheckerContext *ctx, Operand *lhs, Operand *rhs) {
+gb_internal Type *check_assignment_variable(CheckerContext *ctx, Operand *lhs, Operand *rhs, String context_name) {
if (rhs->mode == Addressing_Invalid) {
return nullptr;
}
@@ -430,7 +430,7 @@ gb_internal Type *check_assignment_variable(CheckerContext *ctx, Operand *lhs, O
Ast *node = unparen_expr(lhs->expr);
- check_no_copy_assignment(*rhs, str_lit("assignment"));
+ check_no_copy_assignment(*rhs, context_name);
// NOTE(bill): Ignore assignments to '_'
if (is_blank_ident(node)) {
@@ -630,7 +630,7 @@ gb_internal Type *check_assignment_variable(CheckerContext *ctx, Operand *lhs, O
ctx->bit_field_bit_size = lhs_e->Variable.bit_field_bit_size;
}
- check_assignment(ctx, rhs, assignment_type, str_lit("assignment"));
+ check_assignment(ctx, rhs, assignment_type, context_name);
ctx->bit_field_bit_size = prev_bit_field_bit_size;
@@ -1446,8 +1446,8 @@ gb_internal void check_type_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_
Ast *nil_seen = nullptr;
- PtrSet<Type *> seen = {};
- defer (ptr_set_destroy(&seen));
+ TypeSet seen = {};
+ defer (type_set_destroy(&seen));
for (Ast *stmt : bs->stmts) {
if (stmt->kind != Ast_CaseClause) {
@@ -1515,7 +1515,7 @@ gb_internal void check_type_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_
GB_PANIC("Unknown type to type switch statement");
}
- if (type_ptr_set_update(&seen, y.type)) {
+ if (type_set_update(&seen, y.type)) {
TokenPos pos = cc->token.pos;
gbString expr_str = expr_to_string(y.expr);
error(y.expr,
@@ -1569,7 +1569,7 @@ gb_internal void check_type_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_
auto unhandled = array_make<Type *>(temporary_allocator(), 0, variants.count);
for (Type *t : variants) {
- if (!type_ptr_set_exists(&seen, t)) {
+ if (!type_set_exists(&seen, t)) {
array_add(&unhandled, t);
}
}
@@ -1593,6 +1593,20 @@ gb_internal void check_type_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_
error_line("\tSuggestion: Was '#partial switch' wanted?\n");
}
}
+
+ if (build_context.strict_style) {
+ Token stok = ss->token;
+ for_array(i, bs->stmts) {
+ Ast *stmt = bs->stmts[i];
+ if (stmt->kind != Ast_CaseClause) {
+ continue;
+ }
+ Token ctok = stmt->CaseClause.token;
+ if (ctok.pos.column > stok.pos.column) {
+ error(ctok, "With '-strict-style', 'case' statements must share the same column as the 'switch' token");
+ }
+ }
+ }
}
gb_internal void check_block_stmt_for_errors(CheckerContext *ctx, Ast *body) {
@@ -2108,10 +2122,12 @@ gb_internal void check_value_decl_stmt(CheckerContext *ctx, Ast *node, u32 mod_f
if (init_type == nullptr) {
init_type = t_invalid;
} else if (is_type_polymorphic(base_type(init_type))) {
+ /* DISABLED: This error seems too aggressive for instantiated generic types.
gbString str = type_to_string(init_type);
error(vd->type, "Invalid use of a polymorphic type '%s' in variable declaration", str);
gb_string_free(str);
init_type = t_invalid;
+ */
}
if (init_type == t_invalid && entity_count == 1 && (mod_flags & (Stmt_BreakAllowed|Stmt_FallthroughAllowed))) {
Entity *e = entities[0];
@@ -2402,7 +2418,7 @@ gb_internal void check_assign_stmt(CheckerContext *ctx, Ast *node) {
isize lhs_count = as->lhs.count;
if (lhs_count == 0) {
- error(as->op, "Missing lhs in assignment statement");
+ error(as->op, "Missing LHS in assignment statement");
return;
}
@@ -2435,7 +2451,7 @@ gb_internal void check_assign_stmt(CheckerContext *ctx, Ast *node) {
if (lhs_to_ignore[i]) {
continue;
}
- check_assignment_variable(ctx, &lhs_operands[i], &rhs_operands[i]);
+ check_assignment_variable(ctx, &lhs_operands[i], &rhs_operands[i], str_lit("assignment"));
}
if (lhs_count != rhs_count) {
error(as->lhs[0], "Assignment count mismatch '%td' = '%td'", lhs_count, rhs_count);
@@ -2445,11 +2461,11 @@ gb_internal void check_assign_stmt(CheckerContext *ctx, Ast *node) {
// a += 1; // Single-sided
Token op = as->op;
if (as->lhs.count != 1 || as->rhs.count != 1) {
- error(op, "Assignment operation '%.*s' requires single-valued expressions", LIT(op.string));
+ error(op, "Assignment operator '%.*s' requires single-valued operands", LIT(op.string));
return;
}
if (!gb_is_between(op.kind, Token__AssignOpBegin+1, Token__AssignOpEnd-1)) {
- error(op, "Unknown Assignment operation '%.*s'", LIT(op.string));
+ error(op, "Unknown assignment operator '%.*s'", LIT(op.string));
return;
}
Operand lhs = {Addressing_Invalid};
@@ -2458,15 +2474,16 @@ gb_internal void check_assign_stmt(CheckerContext *ctx, Ast *node) {
ast_node(be, BinaryExpr, binary_expr);
be->op = op;
be->op.kind = cast(TokenKind)(cast(i32)be->op.kind - (Token_AddEq - Token_Add));
- // NOTE(bill): Only use the first one will be used
+ // NOTE(bill): Only use the first one will be used
be->left = as->lhs[0];
be->right = as->rhs[0];
check_expr(ctx, &lhs, as->lhs[0]);
check_binary_expr(ctx, &rhs, binary_expr, nullptr, true);
if (rhs.mode != Addressing_Invalid) {
- // NOTE(bill): Only use the first one will be used
- check_assignment_variable(ctx, &lhs, &rhs);
+ be->op.string = substring(be->op.string, 0, be->op.string.len - 1);
+ rhs.expr = binary_expr;
+ check_assignment_variable(ctx, &lhs, &rhs, str_lit("assignment operation"));
}
}
}
@@ -2755,6 +2772,47 @@ gb_internal void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags)
if (ctx->decl) {
ctx->decl->defer_used += 1;
}
+
+ // NOTE(bill): Handling errors/warnings
+
+ Ast *stmt = ds->stmt;
+ Ast *original_stmt = stmt;
+
+ bool is_singular = true;
+ while (is_singular && stmt->kind == Ast_BlockStmt) {
+ Ast *inner_stmt = nullptr;
+ for (Ast *s : stmt->BlockStmt.stmts) {
+ if (s->kind == Ast_EmptyStmt) {
+ continue;
+ }
+ if (inner_stmt != nullptr) {
+ is_singular = false;
+ break;
+ }
+ inner_stmt = s;
+ }
+
+ if (inner_stmt != nullptr) {
+ stmt = inner_stmt;
+ }
+ }
+ if (!is_singular) {
+ stmt = original_stmt;
+ }
+
+ switch (stmt->kind) {
+ case_ast_node(as, AssignStmt, stmt);
+ if (as->op.kind != Token_Eq) {
+ break;
+ }
+ for (Ast *lhs : as->lhs) {
+ Entity *e = entity_of_node(lhs);
+ if (e && e->flags & EntityFlag_Result) {
+ error(lhs, "Assignments to named return values within 'defer' will not affect the value that is returned");
+ }
+ }
+ case_end;
+ }
}
case_end;
@@ -2812,6 +2870,7 @@ gb_internal void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags)
case Ast_BlockStmt:
case Ast_IfStmt:
case Ast_SwitchStmt:
+ case Ast_TypeSwitchStmt:
if (token.kind != Token_break) {
error(bs->label, "Label '%.*s' can only be used with 'break'", LIT(e->token.string));
}
diff --git a/src/check_type.cpp b/src/check_type.cpp
index 44108ccbe..5f9540ee0 100644
--- a/src/check_type.cpp
+++ b/src/check_type.cpp
@@ -685,7 +685,8 @@ gb_internal void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast *
ST_ALIGN(min_field_align);
ST_ALIGN(max_field_align);
ST_ALIGN(align);
- if (struct_type->Struct.custom_align < struct_type->Struct.custom_min_field_align) {
+ if (struct_type->Struct.custom_align != 0 &&
+ struct_type->Struct.custom_align < struct_type->Struct.custom_min_field_align) {
error(st->align, "#align(%lld) is defined to be less than #min_field_align(%lld)",
cast(long long)struct_type->Struct.custom_align,
cast(long long)struct_type->Struct.custom_min_field_align);
@@ -1154,8 +1155,7 @@ gb_internal void check_bit_field_type(CheckerContext *ctx, Type *bit_field_type,
}
}
-
-
+ #if 0 // Reconsider at a later date
if (bit_sizes.count > 0 && is_type_integer(backing_type)) {
bool all_booleans = is_type_boolean(fields[0]->type);
bool all_ones = bit_sizes[0] == 1;
@@ -1181,7 +1181,7 @@ gb_internal void check_bit_field_type(CheckerContext *ctx, Type *bit_field_type,
}
}
}
-
+ #endif
bit_field_type->BitField.fields = slice_from_array(fields);
bit_field_type->BitField.bit_sizes = slice_from_array(bit_sizes);
@@ -1910,9 +1910,18 @@ gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_para
case ParameterValue_Location:
case ParameterValue_Expression:
case ParameterValue_Value:
+ // Special case for polymorphic procedures as default values
+ if (param_value.ast_value != nullptr) {
+ Entity *e = entity_from_expr(param_value.ast_value);
+ if (e != nullptr && e->kind == Entity_Procedure && is_type_polymorphic(e->type)) {
+ // Allow polymorphic procedures as default parameter values
+ // The type will be correctly determined at call site
+ break;
+ }
+ }
gbString str = type_to_string(type);
error(params[i], "A default value for a parameter must not be a polymorphic constant type, got %s", str);
- gb_string_free(str);
+ gb_string_free(str);
break;
}
}
@@ -2081,7 +2090,9 @@ gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_para
if (type != t_invalid && !check_is_assignable_to(ctx, &op, type, allow_array_programming)) {
bool ok = true;
if (p->flags&FieldFlag_any_int) {
- if ((!is_type_integer(op.type) && !is_type_enum(op.type)) || (!is_type_integer(type) && !is_type_enum(type))) {
+ if (op.type == nullptr) {
+ ok = false;
+ } else if ((!is_type_integer(op.type) && !is_type_enum(op.type)) || (!is_type_integer(type) && !is_type_enum(type))) {
ok = false;
} else if (!check_is_castable_to(ctx, &op, type)) {
ok = false;
@@ -2772,6 +2783,21 @@ gb_internal void add_map_key_type_dependencies(CheckerContext *ctx, Type *key) {
return;
}
+ if (key->kind == Type_Basic) {
+ if (key->Basic.flags & BasicFlag_Quaternion) {
+ add_package_dependency(ctx, "runtime", "default_hasher_f64");
+ add_package_dependency(ctx, "runtime", "default_hasher_quaternion256");
+ return;
+ } else if (key->Basic.flags & BasicFlag_Complex) {
+ add_package_dependency(ctx, "runtime", "default_hasher_f64");
+ add_package_dependency(ctx, "runtime", "default_hasher_complex128");
+ return;
+ } else if (key->Basic.flags & BasicFlag_Float) {
+ add_package_dependency(ctx, "runtime", "default_hasher_f64");
+ return;
+ }
+ }
+
if (key->kind == Type_Struct) {
add_package_dependency(ctx, "runtime", "default_hasher");
for_array(i, key->Struct.fields) {
@@ -2858,15 +2884,23 @@ gb_internal void check_matrix_type(CheckerContext *ctx, Type **type, Ast *node)
}
if (generic_row == nullptr && row_count < MATRIX_ELEMENT_COUNT_MIN) {
- gbString s = expr_to_string(row.expr);
- error(row.expr, "Invalid matrix row count, expected %d+ rows, got %s", MATRIX_ELEMENT_COUNT_MIN, s);
- gb_string_free(s);
+ if (row.expr == nullptr) {
+ error(node, "Invalid matrix row count, got nothing");
+ } else {
+ gbString s = expr_to_string(row.expr);
+ error(row.expr, "Invalid matrix row count, expected %d+ rows, got %s", MATRIX_ELEMENT_COUNT_MIN, s);
+ gb_string_free(s);
+ }
}
if (generic_column == nullptr && column_count < MATRIX_ELEMENT_COUNT_MIN) {
- gbString s = expr_to_string(column.expr);
- error(column.expr, "Invalid matrix column count, expected %d+ rows, got %s", MATRIX_ELEMENT_COUNT_MIN, s);
- gb_string_free(s);
+ if (column.expr == nullptr) {
+ error(node, "Invalid matrix column count, got nothing");
+ } else {
+ gbString s = expr_to_string(column.expr);
+ error(column.expr, "Invalid matrix column count, expected %d+ rows, got %s", MATRIX_ELEMENT_COUNT_MIN, s);
+ gb_string_free(s);
+ }
}
if ((generic_row == nullptr && generic_column == nullptr) && row_count*column_count > MATRIX_ELEMENT_COUNT_MAX) {
@@ -3250,7 +3284,7 @@ gb_internal void check_array_type_internal(CheckerContext *ctx, Ast *e, Type **t
}
if (count < 0) {
- error(at->count, "? can only be used in conjuction with compound literals");
+ error(at->count, "? can only be used in conjunction with compound literals");
count = 0;
}
@@ -3272,8 +3306,11 @@ gb_internal void check_array_type_internal(CheckerContext *ctx, Ast *e, Type **t
if (generic_type != nullptr) {
// Ignore
} else if (count < 1 || !is_power_of_two(count)) {
- error(at->count, "Invalid length for #simd, expected a power of two length, got '%lld'", cast(long long)count);
*type = alloc_type_array(elem, count, generic_type);
+ if (ctx->disallow_polymorphic_return_types && count == 0) {
+ return;
+ }
+ error(at->count, "Invalid length for #simd, expected a power of two length, got '%lld'", cast(long long)count);
return;
}
@@ -3493,6 +3530,17 @@ gb_internal bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, T
elem = o.type;
}
+ if (!ctx->in_polymorphic_specialization && ctx->disallow_polymorphic_return_types) {
+ Type *t = base_type(elem);
+ if (t != nullptr &&
+ unparen_expr(pt->type)->kind == Ast_Ident &&
+ is_type_polymorphic_record_unspecialized(t)) {
+ gbString err_str = expr_to_string(e);
+ error(e, "Invalid use of a non-specialized polymorphic type '%s'", err_str);
+ gb_string_free(err_str);
+ }
+ }
+
if (pt->tag != nullptr) {
GB_ASSERT(pt->tag->kind == Ast_BasicDirective);
@@ -3757,7 +3805,11 @@ gb_internal Type *check_type_expr(CheckerContext *ctx, Ast *e, Type *named_type)
#if 0
error(e, "Invalid type definition of '%.*s'", LIT(type->Named.name));
#endif
- type->Named.base = t_invalid;
+ if (type->Named.type_name->TypeName.is_type_alias) {
+ // NOTE(laytan): keep it null, type declaration is a mini "cycle" to be filled later.
+ } else {
+ type->Named.base = t_invalid;
+ }
}
if (is_type_polymorphic(type)) {
@@ -3775,7 +3827,7 @@ gb_internal Type *check_type_expr(CheckerContext *ctx, Ast *e, Type *named_type)
}
#endif
- if (is_type_typed(type)) {
+ if (type->kind == Type_Named && type->Named.base == nullptr || is_type_typed(type)) {
add_type_and_value(ctx, e, Addressing_Type, type, empty_exact_value);
} else {
gbString name = type_to_string(type);
diff --git a/src/checker.cpp b/src/checker.cpp
index 5d3263789..4ebabe004 100644
--- a/src/checker.cpp
+++ b/src/checker.cpp
@@ -3,7 +3,10 @@
#include "entity.cpp"
#include "types.cpp"
-String get_final_microarchitecture();
+
+gb_internal u64 type_hash_canonical_type(Type *type);
+
+gb_internal String get_final_microarchitecture();
gb_internal void check_expr(CheckerContext *c, Operand *operand, Ast *expression);
gb_internal void check_expr_or_type(CheckerContext *c, Operand *operand, Ast *expression, Type *type_hint=nullptr);
@@ -170,7 +173,7 @@ gb_internal void init_decl_info(DeclInfo *d, Scope *scope, DeclInfo *parent) {
d->parent = parent;
d->scope = scope;
ptr_set_init(&d->deps, 0);
- ptr_set_init(&d->type_info_deps, 0);
+ type_set_init(&d->type_info_deps, 0);
d->labels.allocator = heap_allocator();
d->variadic_reuses.allocator = heap_allocator();
d->variadic_reuse_max_bytes = 0;
@@ -355,6 +358,10 @@ gb_internal void check_open_scope(CheckerContext *c, Ast *node) {
scope->flags |= ScopeFlag_Type;
break;
}
+ if (c->decl && c->decl->proc_lit) {
+ // Number the scopes within a procedure body depth-first
+ scope->index = c->decl->scope_index++;
+ }
c->scope = scope;
c->state_flags |= StateFlag_bounds_check;
}
@@ -721,12 +728,17 @@ gb_internal void check_scope_usage_internal(Checker *c, Scope *scope, u64 vet_fl
bool is_unused = false;
if (vet_unused && check_vet_unused(c, e, &ve_unused)) {
is_unused = true;
- } else if (vet_unused_procedures &&
- e->kind == Entity_Procedure) {
+ } else if (vet_unused_procedures && e->kind == Entity_Procedure) {
if (e->flags&EntityFlag_Used) {
is_unused = false;
} else if (e->flags & EntityFlag_Require) {
is_unused = false;
+ } else if (e->flags & EntityFlag_Init) {
+ is_unused = false;
+ } else if (e->flags & EntityFlag_Fini) {
+ is_unused = false;
+ } else if (e->Procedure.is_export) {
+ is_unused = false;
} else if (e->pkg && e->pkg->kind == Package_Init && e->token.string == "main") {
is_unused = false;
} else {
@@ -744,14 +756,20 @@ gb_internal void check_scope_usage_internal(Checker *c, Scope *scope, u64 vet_fl
array_add(&vetted_entities, ve_unused);
} else if (is_shadowed) {
array_add(&vetted_entities, ve_shadowed);
- } else if (e->kind == Entity_Variable && (e->flags & (EntityFlag_Param|EntityFlag_Using|EntityFlag_Static)) == 0 && !e->Variable.is_global) {
+ } else if (e->kind == Entity_Variable && (e->flags & (EntityFlag_Param|EntityFlag_Using|EntityFlag_Static|EntityFlag_Field)) == 0 && !e->Variable.is_global) {
i64 sz = type_size_of(e->type);
// TODO(bill): When is a good size warn?
// Is >256 KiB good enough?
if (sz > 1ll<<18) {
- gbString type_str = type_to_string(e->type);
- warning(e->token, "Declaration of '%.*s' may cause a stack overflow due to its type '%s' having a size of %lld bytes", LIT(e->token.string), type_str, cast(long long)sz);
- gb_string_free(type_str);
+ bool is_ref = false;
+ if((e->flags & EntityFlag_ForValue) != 0) {
+ is_ref = type_deref(e->Variable.for_loop_parent_type) != NULL;
+ }
+ if(!is_ref) {
+ gbString type_str = type_to_string(e->type);
+ warning(e->token, "Declaration of '%.*s' may cause a stack overflow due to its type '%s' having a size of %lld bytes", LIT(e->token.string), type_str, cast(long long)sz);
+ gb_string_free(type_str);
+ }
}
}
}
@@ -819,11 +837,17 @@ gb_internal void add_dependency(CheckerInfo *info, DeclInfo *d, Entity *e) {
rw_mutex_unlock(&d->deps_mutex);
}
gb_internal void add_type_info_dependency(CheckerInfo *info, DeclInfo *d, Type *type) {
- if (d == nullptr) {
+ if (d == nullptr || type == nullptr) {
return;
}
+ if (type->kind == Type_Named) {
+ Entity *e = type->Named.type_name;
+ if (e->TypeName.is_type_alias) {
+ type = type->Named.base;
+ }
+ }
rw_mutex_lock(&d->type_info_deps_mutex);
- ptr_set_add(&d->type_info_deps, type);
+ type_set_add(&d->type_info_deps, type);
rw_mutex_unlock(&d->type_info_deps_mutex);
}
@@ -1054,11 +1078,30 @@ gb_internal void init_universal(void) {
add_global_bool_constant("true", true);
add_global_bool_constant("false", false);
- add_global_string_constant("ODIN_VENDOR", bc->ODIN_VENDOR);
- add_global_string_constant("ODIN_VERSION", bc->ODIN_VERSION);
- add_global_string_constant("ODIN_ROOT", bc->ODIN_ROOT);
- add_global_string_constant("ODIN_BUILD_PROJECT_NAME", bc->ODIN_BUILD_PROJECT_NAME);
- add_global_string_constant("ODIN_WINDOWS_SUBSYSTEM", bc->ODIN_WINDOWS_SUBSYSTEM);
+ add_global_string_constant("ODIN_VENDOR", bc->ODIN_VENDOR);
+ add_global_string_constant("ODIN_VERSION", bc->ODIN_VERSION);
+ add_global_string_constant("ODIN_ROOT", bc->ODIN_ROOT);
+ add_global_string_constant("ODIN_BUILD_PROJECT_NAME", bc->ODIN_BUILD_PROJECT_NAME);
+
+ {
+ GlobalEnumValue values[Windows_Subsystem_COUNT] = {
+ {"Unknown", Windows_Subsystem_UNKNOWN},
+ {"Boot_Application", Windows_Subsystem_BOOT_APPLICATION},
+ {"Console", Windows_Subsystem_CONSOLE},
+ {"EFI_Application", Windows_Subsystem_EFI_APPLICATION},
+ {"EFI_Boot_Service_Driver", Windows_Subsystem_EFI_BOOT_SERVICE_DRIVER},
+ {"EFI_Rom", Windows_Subsystem_EFI_ROM},
+ {"EFI_Runtime_Driver", Windows_Subsystem_EFI_RUNTIME_DRIVER},
+ {"Native", Windows_Subsystem_NATIVE},
+ {"Posix", Windows_Subsystem_POSIX},
+ {"Windows", Windows_Subsystem_WINDOWS},
+ {"Windows_CE", Windows_Subsystem_WINDOWSCE},
+ };
+
+ auto fields = add_global_enum_type(str_lit("Odin_Windows_Subsystem_Type"), values, gb_count_of(values));
+ add_global_enum_constant(fields, "ODIN_WINDOWS_SUBSYSTEM", bc->ODIN_WINDOWS_SUBSYSTEM);
+ add_global_string_constant("ODIN_WINDOWS_SUBSYSTEM_STRING", windows_subsystem_names[bc->ODIN_WINDOWS_SUBSYSTEM]);
+ }
{
GlobalEnumValue values[TargetOs_COUNT] = {
@@ -1078,7 +1121,7 @@ gb_internal void init_universal(void) {
};
auto fields = add_global_enum_type(str_lit("Odin_OS_Type"), values, gb_count_of(values));
- add_global_enum_constant(fields, "ODIN_OS", bc->metrics.os);
+ add_global_enum_constant(fields, "ODIN_OS", bc->metrics.os);
add_global_string_constant("ODIN_OS_STRING", target_os_names[bc->metrics.os]);
}
@@ -1130,6 +1173,7 @@ gb_internal void init_universal(void) {
GlobalEnumValue values[Subtarget_COUNT] = {
{"Default", Subtarget_Default},
{"iOS", Subtarget_iOS},
+ {"Android", Subtarget_Android},
};
auto fields = add_global_enum_type(str_lit("Odin_Platform_Subtarget_Type"), values, gb_count_of(values));
@@ -1331,10 +1375,12 @@ gb_internal void init_universal(void) {
t_objc_object = add_global_type_name(intrinsics_pkg->scope, str_lit("objc_object"), alloc_type_struct_complete());
t_objc_selector = add_global_type_name(intrinsics_pkg->scope, str_lit("objc_selector"), alloc_type_struct_complete());
t_objc_class = add_global_type_name(intrinsics_pkg->scope, str_lit("objc_class"), alloc_type_struct_complete());
+ t_objc_ivar = add_global_type_name(intrinsics_pkg->scope, str_lit("objc_ivar"), alloc_type_struct_complete());
t_objc_id = alloc_type_pointer(t_objc_object);
t_objc_SEL = alloc_type_pointer(t_objc_selector);
t_objc_Class = alloc_type_pointer(t_objc_class);
+ t_objc_Ivar = alloc_type_pointer(t_objc_ivar);
}
}
@@ -1352,8 +1398,11 @@ gb_internal void init_checker_info(CheckerInfo *i) {
string_map_init(&i->foreigns);
// map_init(&i->gen_procs);
map_init(&i->gen_types);
- array_init(&i->type_info_types, a);
- map_init(&i->type_info_map);
+
+ type_set_init(&i->min_dep_type_info_set);
+ map_init(&i->min_dep_type_info_index_map);
+
+ // map_init(&i->type_info_map);
string_map_init(&i->files);
string_map_init(&i->packages);
array_init(&i->variable_init_order, a);
@@ -1364,6 +1413,10 @@ gb_internal void init_checker_info(CheckerInfo *i) {
array_init(&i->defineables, a);
map_init(&i->objc_msgSend_types);
+ mpsc_init(&i->objc_class_implementations, a);
+ string_set_init(&i->obcj_class_name_set, 0);
+ map_init(&i->objc_method_implementations);
+
string_map_init(&i->load_file_cache);
array_init(&i->all_procedures, heap_allocator());
@@ -1386,8 +1439,10 @@ gb_internal void destroy_checker_info(CheckerInfo *i) {
string_map_destroy(&i->foreigns);
// map_destroy(&i->gen_procs);
map_destroy(&i->gen_types);
- array_free(&i->type_info_types);
- map_destroy(&i->type_info_map);
+
+ type_set_destroy(&i->min_dep_type_info_set);
+ map_destroy(&i->min_dep_type_info_index_map);
+
string_map_destroy(&i->files);
string_map_destroy(&i->packages);
array_free(&i->variable_init_order);
@@ -1472,6 +1527,8 @@ gb_internal void init_checker(Checker *c) {
TIME_SECTION("init proc queues");
mpsc_init(&c->procs_with_deferred_to_check, a); //, 1<<10);
+ mpsc_init(&c->procs_with_objc_context_provider_to_check, a);
+
// NOTE(bill): 1 Mi elements should be enough on average
array_init(&c->procs_to_check, heap_allocator(), 0, 1<<20);
@@ -1621,41 +1678,36 @@ gb_internal void check_remove_expr_info(CheckerContext *c, Ast *e) {
}
}
-
-gb_internal isize type_info_index(CheckerInfo *info, Type *type, bool error_on_failure) {
- type = default_type(type);
- if (type == t_llvm_bool) {
- type = t_bool;
- }
-
- mutex_lock(&info->type_info_mutex);
+gb_internal isize type_info_index(CheckerInfo *info, TypeInfoPair pair, bool error_on_failure) {
+ mutex_lock(&info->minimum_dependency_type_info_mutex);
isize entry_index = -1;
- isize *found_entry_index = map_get(&info->type_info_map, type);
+ u64 hash = pair.hash;
+ isize *found_entry_index = map_get(&info->min_dep_type_info_index_map, hash);
if (found_entry_index) {
entry_index = *found_entry_index;
}
- if (entry_index < 0) {
- // NOTE(bill): Do manual linear search
- for (auto const &e : info->type_info_map) {
- if (are_types_identical_unique_tuples(e.key, type)) {
- entry_index = e.value;
- // NOTE(bill): Add it to the search map
- map_set(&info->type_info_map, type, entry_index);
- break;
- }
- }
- }
-
- mutex_unlock(&info->type_info_mutex);
+ mutex_unlock(&info->minimum_dependency_type_info_mutex);
if (error_on_failure && entry_index < 0) {
- compiler_error("Type_Info for '%s' could not be found", type_to_string(type));
+ compiler_error("Type_Info for '%s' could not be found", type_to_string(pair.type));
}
return entry_index;
}
+gb_internal isize type_info_index(CheckerInfo *info, Type *type, bool error_on_failure) {
+ type = default_type(type);
+ if (type == t_llvm_bool) {
+ type = t_bool;
+ }
+
+ u64 hash = type_hash_canonical_type(type);
+ return type_info_index(info, {type, hash}, error_on_failure);
+}
+
+
+
gb_internal void add_untyped(CheckerContext *c, Ast *expr, AddressingMode mode, Type *type, ExactValue const &value) {
if (expr == nullptr) {
return;
@@ -2002,13 +2054,17 @@ gb_internal void add_type_info_type(CheckerContext *c, Type *t) {
}
gb_internal void add_type_info_type_internal(CheckerContext *c, Type *t) {
- if (t == nullptr) {
+ if (t == nullptr || c == nullptr) {
return;
}
add_type_info_dependency(c->info, c->decl, t);
-
+#if 0
MUTEX_GUARD_BLOCK(&c->info->type_info_mutex) {
+ if (type_set_update(&c->info->type_info_set, t)) {
+ // return;
+ }
+
auto found = map_get(&c->info->type_info_map, t);
if (found != nullptr) {
// Types have already been added
@@ -2031,7 +2087,8 @@ gb_internal void add_type_info_type_internal(CheckerContext *c, Type *t) {
// Unique entry
// NOTE(bill): map entries grow linearly and in order
ti_index = c->info->type_info_types.count;
- array_add(&c->info->type_info_types, t);
+ TypeInfoPair tt = {t, type_hash_canonical_type(t)};
+ array_add(&c->info->type_info_types, tt);
}
map_set(&c->checker->info.type_info_map, t, ti_index);
@@ -2226,6 +2283,7 @@ gb_internal void add_type_info_type_internal(CheckerContext *c, Type *t) {
GB_PANIC("Unhandled type: %*.s %d", LIT(type_strings[bt->kind]), bt->kind);
break;
}
+#endif
}
@@ -2283,19 +2341,7 @@ gb_internal void add_min_dep_type_info(Checker *c, Type *t) {
return;
}
- auto *set = &c->info.minimum_dependency_type_info_set;
-
- isize ti_index = type_info_index(&c->info, t, false);
- if (ti_index < 0) {
- add_type_info_type(&c->builtin_ctx, t); // Missing the type information
- ti_index = type_info_index(&c->info, t, false);
- }
- GB_ASSERT(ti_index >= 0);
- // IMPORTANT NOTE(bill): this must be copied as `map_set` takes a const ref
- // and effectively assigns the `+1` of the value
- isize const count = set->count;
- if (map_set_if_not_previously_exists(set, ti_index+1, count)) {
- // Type already exists;
+ if (type_set_update(&c->info.min_dep_type_info_set, t)) {
return;
}
@@ -2495,8 +2541,8 @@ gb_internal void add_dependency_to_set(Checker *c, Entity *entity) {
if (decl == nullptr) {
return;
}
- for (Type *t : decl->type_info_deps) {
- add_min_dep_type_info(c, t);
+ for (TypeInfoPair const tt : decl->type_info_deps) {
+ add_min_dep_type_info(c, tt.type);
}
for (Entity *e : decl->deps) {
@@ -2632,6 +2678,10 @@ gb_internal void generate_minimum_dependency_set_internal(Checker *c, Entity *st
is_init = false;
}
+ if (is_blank_ident(e->token)) {
+ error(e->token, "An @(init) procedure must not use a blank identifier as its name");
+ }
+
if (is_init) {
add_dependency_to_set(c, e);
array_add(&c->info.init_procedures, e);
@@ -2654,6 +2704,10 @@ gb_internal void generate_minimum_dependency_set_internal(Checker *c, Entity *st
is_fini = false;
}
+ if (is_blank_ident(e->token)) {
+ error(e->token, "An @(fini) procedure must not use a blank identifier as its name");
+ }
+
if (is_fini) {
add_dependency_to_set(c, e);
array_add(&c->info.fini_procedures, e);
@@ -2696,7 +2750,6 @@ gb_internal void generate_minimum_dependency_set(Checker *c, Entity *start) {
isize min_dep_set_cap = next_pow2_isize(entity_count*4); // empirically determined factor
ptr_set_init(&c->info.minimum_dependency_set, min_dep_set_cap);
- map_init(&c->info.minimum_dependency_type_info_set);
#define FORCE_ADD_RUNTIME_ENTITIES(condition, ...) do { \
if (condition) { \
@@ -3641,6 +3694,33 @@ gb_internal DECL_ATTRIBUTE_PROC(proc_decl_attribute) {
}
}
return true;
+ } else if (name == "objc_implement") {
+ ExactValue ev = check_decl_attribute_value(c, value);
+ if (ev.kind == ExactValue_Bool) {
+ ac->objc_is_implementation = ev.value_bool;
+
+ if (!ac->objc_is_implementation) {
+ ac->objc_is_disabled_implement = true;
+ }
+ } else if (ev.kind == ExactValue_Invalid) {
+ ac->objc_is_implementation = true;
+ } else {
+ error(elem, "Expected a boolean value, or no value, for '%.*s'", LIT(name));
+ }
+
+ return true;
+ } else if (name == "objc_selector") {
+ ExactValue ev = check_decl_attribute_value(c, value);
+ if (ev.kind == ExactValue_String) {
+ if (string_is_valid_identifier(ev.value_string)) {
+ ac->objc_selector = ev.value_string;
+ } else {
+ error(elem, "Invalid identifier for '%.*s', got '%.*s'", LIT(name), LIT(ev.value_string));
+ }
+ } else {
+ error(elem, "Expected a string value for '%.*s'", LIT(name));
+ }
+ return true;
} else if (name == "require_target_feature") {
ExactValue ev = check_decl_attribute_value(c, value);
if (ev.kind == ExactValue_String) {
@@ -3690,6 +3770,18 @@ gb_internal DECL_ATTRIBUTE_PROC(proc_decl_attribute) {
}
ac->instrumentation_exit = true;
return true;
+ } else if (name == "no_sanitize_address") {
+ if (value != nullptr) {
+ error(value, "'%.*s' expects no parameter", LIT(name));
+ }
+ ac->no_sanitize_address = true;
+ return true;
+ } else if (name == "no_sanitize_memory") {
+ if (value != nullptr) {
+ error(value, "'%.*s' expects no parameter", LIT(name));
+ }
+ ac->no_sanitize_memory = true;
+ return true;
}
return false;
}
@@ -3880,6 +3972,51 @@ gb_internal DECL_ATTRIBUTE_PROC(type_decl_attribute) {
ac->objc_class = ev.value_string;
}
return true;
+ } else if (name == "objc_implement") {
+ ExactValue ev = check_decl_attribute_value(c, value);
+ if (ev.kind == ExactValue_Bool) {
+ ac->objc_is_implementation = ev.value_bool;
+ } else if (ev.kind == ExactValue_Invalid) {
+ ac->objc_is_implementation = true;
+ } else {
+ error(elem, "Expected a boolean value, or no value, for '%.*s'", LIT(name));
+ }
+ return true;
+ } else if (name == "objc_superclass") {
+ Type *objc_superclass = check_type(c, value);
+
+ if (objc_superclass != nullptr) {
+ ac->objc_superclass = objc_superclass;
+ } else {
+ error(value, "'%.*s' expected a named type", LIT(name));
+ }
+ return true;
+ } else if (name == "objc_ivar") {
+ Type *objc_ivar = check_type(c, value);
+
+ if (objc_ivar != nullptr && objc_ivar->kind == Type_Named) {
+ ac->objc_ivar = objc_ivar;
+ } else {
+ error(value, "'%.*s' expected a named type", LIT(name));
+ }
+ return true;
+ } else if (name == "objc_context_provider") {
+ Operand o = {};
+ check_expr(c, &o, value);
+ Entity *e = entity_of_node(o.expr);
+
+ if (e != nullptr) {
+ if (ac->objc_context_provider != nullptr) {
+ error(elem, "Previous usage of a 'objc_context_provider' attribute");
+ }
+ if (e->kind != Entity_Procedure) {
+ error(elem, "'objc_context_provider' must refer to a procedure");
+ } else {
+ ac->objc_context_provider = e;
+ }
+
+ return true;
+ }
}
return false;
}
@@ -3888,6 +4025,7 @@ gb_internal DECL_ATTRIBUTE_PROC(type_decl_attribute) {
#include "check_expr.cpp"
#include "check_builtin.cpp"
#include "check_type.cpp"
+#include "name_canonicalization.cpp"
#include "check_decl.cpp"
#include "check_stmt.cpp"
@@ -5010,6 +5148,9 @@ gb_internal DECL_ATTRIBUTE_PROC(foreign_import_decl_attribute) {
error(elem, "Expected a string value for '%.*s'", LIT(name));
}
return true;
+ } else if (name == "export") {
+ ac->is_export = true;
+ return true;
} else if (name == "force" || name == "require") {
if (value != nullptr) {
error(elem, "Expected no parameter for '%.*s'", LIT(name));
@@ -5034,6 +5175,12 @@ gb_internal DECL_ATTRIBUTE_PROC(foreign_import_decl_attribute) {
ac->extra_linker_flags = ev.value_string;
}
return true;
+ } else if (name == "ignore_duplicates") {
+ if (value != nullptr) {
+ error(elem, "Expected no parameter for '%.*s'", LIT(name));
+ }
+ ac->ignore_duplicates = true;
+ return true;
}
return false;
}
@@ -5169,14 +5316,21 @@ gb_internal void check_add_foreign_import_decl(CheckerContext *ctx, Ast *decl) {
GB_ASSERT(fl->library_name.pos.line != 0);
fl->library_name.string = library_name;
+ AttributeContext ac = {};
+ check_decl_attributes(ctx, fl->attributes, foreign_import_decl_attribute, &ac);
+
+ Scope *scope = parent_scope;
+ if (ac.is_export) {
+ scope = parent_scope->parent;
+ }
+
Entity *e = alloc_entity_library_name(parent_scope, fl->library_name, t_invalid,
fl->fullpaths, library_name);
e->LibraryName.decl = decl;
add_entity_flags_from_file(ctx, e, parent_scope);
- add_entity(ctx, parent_scope, nullptr, e);
+ add_entity(ctx, scope, nullptr, e);
+
- AttributeContext ac = {};
- check_decl_attributes(ctx, fl->attributes, foreign_import_decl_attribute, &ac);
if (ac.require_declaration) {
mpsc_enqueue(&ctx->info->required_foreign_imports_through_force_queue, e);
add_entity_use(ctx, nullptr, e);
@@ -5184,6 +5338,9 @@ gb_internal void check_add_foreign_import_decl(CheckerContext *ctx, Ast *decl) {
if (ac.foreign_import_priority_index != 0) {
e->LibraryName.priority_index = ac.foreign_import_priority_index;
}
+ if (ac.ignore_duplicates) {
+ e->LibraryName.ignore_duplicates = true;
+ }
String extra_linker_flags = string_trim_whitespace(ac.extra_linker_flags);
if (extra_linker_flags.len != 0) {
e->LibraryName.extra_linker_flags = extra_linker_flags;
@@ -6193,6 +6350,12 @@ gb_internal void check_deferred_procedures(Checker *c) {
continue;
}
+ if (dst->flags & EntityFlag_Disabled) {
+ // Prevent procedures that have been disabled from acting as deferrals.
+ src->Procedure.deferred_procedure = {};
+ continue;
+ }
+
GB_ASSERT(is_type_proc(src->type));
GB_ASSERT(is_type_proc(dst->type));
Type *src_params = base_type(src->type)->Proc.params;
@@ -6294,6 +6457,10 @@ gb_internal void check_deferred_procedures(Checker *c) {
continue;
}
+ if (dst_params == nullptr) {
+ error(src->token, "Deferred procedure must have parameters for %s", attribute);
+ continue;
+ }
GB_ASSERT(dst_params->kind == Type_Tuple);
Type *tsrc = alloc_type_tuple();
@@ -6344,6 +6511,44 @@ gb_internal void check_deferred_procedures(Checker *c) {
}
+gb_internal void check_objc_context_provider_procedures(Checker *c) {
+ for (Entity *e = nullptr; mpsc_dequeue(&c->procs_with_objc_context_provider_to_check, &e); /**/) {
+ GB_ASSERT(e->kind == Entity_TypeName);
+
+ Entity *proc_entity = e->TypeName.objc_context_provider;
+ GB_ASSERT(proc_entity->kind == Entity_Procedure);
+
+ auto &proc = proc_entity->type->Proc;
+
+ Type *return_type = proc.result_count != 1 ? t_untyped_nil : base_named_type(proc.results->Tuple.variables[0]->type);
+ if (return_type != t_context) {
+ error(proc_entity->token, "The @(objc_context_provider) procedure must only return a context.");
+ }
+
+ const char *self_param_err = "The @(objc_context_provider) procedure must take as a parameter a single pointer to the @(objc_type) value.";
+ if (proc.param_count != 1) {
+ error(proc_entity->token, self_param_err);
+ }
+
+ Type *self_param = base_type(proc.params->Tuple.variables[0]->type);
+ if (self_param->kind != Type_Pointer) {
+ error(proc_entity->token, self_param_err);
+ }
+
+ Type *self_type = base_named_type(self_param->Pointer.elem);
+ if (!internal_check_is_assignable_to(self_type, e->type) &&
+ !(e->TypeName.objc_ivar && internal_check_is_assignable_to(self_type, e->TypeName.objc_ivar))) {
+ error(proc_entity->token, self_param_err);
+ }
+ if (proc.calling_convention != ProcCC_CDecl && proc.calling_convention != ProcCC_Contextless) {
+ error(e->token, self_param_err);
+ }
+ if (proc.is_polymorphic) {
+ error(e->token, self_param_err);
+ }
+ }
+}
+
gb_internal void check_unique_package_names(Checker *c) {
ERROR_BLOCK();
@@ -6378,6 +6583,19 @@ gb_internal void check_unique_package_names(Checker *c) {
"\tThere is no relation between a package name and the directory that contains it, so they can be completely different\n"
"\tA package name is required for link name prefixing to have a consistent ABI\n");
error_line("%s found at previous location\n", token_pos_to_string(ast_token(prev).pos));
+
+ // NOTE(Jeroen): Check if the conflicting imports are the same case-folded directory
+ // See https://github.com/odin-lang/Odin/issues/5080
+ #if defined(GB_SYSTEM_WINDOWS)
+ String dir_a = pkg->files[0]->directory;
+ String dir_b = (*found)->files[0]->directory;
+
+ if (str_eq_ignore_case(dir_a, dir_b)) {
+ error_line("\tRemember that Windows case-folds paths, and so %.*s and %.*s are the same directory.\n", LIT(dir_a), LIT(dir_b));
+ // Could also perform a FS lookup to check which of the two is the actual directory and suggest it, but this should be enough.
+ }
+ #endif
+
end_error_block();
}
}
@@ -6460,7 +6678,7 @@ gb_internal void check_sort_init_and_fini_procedures(Checker *c) {
gb_internal void add_type_info_for_type_definitions(Checker *c) {
for_array(i, c->info.definitions) {
Entity *e = c->info.definitions[i];
- if (e->kind == Entity_TypeName && e->type != nullptr) {
+ if (e->kind == Entity_TypeName && e->type != nullptr && is_type_typed(e->type)) {
i64 align = type_align_of(e->type);
if (align > 0 && ptr_set_exists(&c->info.minimum_dependency_set, e)) {
add_type_info_type(&c->builtin_ctx, e->type);
@@ -6491,6 +6709,7 @@ gb_internal void check_update_dependency_tree_for_procedures(Checker *c) {
}
}
+
gb_internal void check_parsed_files(Checker *c) {
TIME_SECTION("map full filepaths to scope");
add_type_info_type(&c->builtin_ctx, t_invalid);
@@ -6581,7 +6800,7 @@ gb_internal void check_parsed_files(Checker *c) {
// NOTE(bill): Check for illegal cyclic type declarations
for_array(i, c->info.definitions) {
Entity *e = c->info.definitions[i];
- if (e->kind == Entity_TypeName && e->type != nullptr) {
+ if (e->kind == Entity_TypeName && e->type != nullptr && is_type_typed(e->type)) {
(void)type_align_of(e->type);
} else if (e->kind == Entity_Procedure) {
DeclInfo *decl = e->decl_info;
@@ -6600,6 +6819,9 @@ gb_internal void check_parsed_files(Checker *c) {
TIME_SECTION("check deferred procedures");
check_deferred_procedures(c);
+ TIME_SECTION("check objc context provider procedures");
+ check_objc_context_provider_procedures(c);
+
TIME_SECTION("calculate global init order");
calculate_global_init_order(c);
@@ -6695,6 +6917,58 @@ gb_internal void check_parsed_files(Checker *c) {
add_type_and_value(&c->builtin_ctx, u.expr, u.info->mode, u.info->type, u.info->value);
}
+ TIME_SECTION("initialize and check for collisions in type info array");
+ {
+ Array<TypeInfoPair> type_info_types; // sorted after filled
+ array_init(&type_info_types, heap_allocator());
+ defer (array_free(&type_info_types));
+
+ for (auto const &tt : c->info.min_dep_type_info_set) {
+ array_add(&type_info_types, tt);
+ }
+ array_sort(type_info_types, type_info_pair_cmp);
+
+ array_init(&c->info.type_info_types_hash_map, heap_allocator(), type_info_types.count*2 + 1);
+ map_reserve(&c->info.min_dep_type_info_index_map, type_info_types.count);
+
+ isize hash_map_len = c->info.type_info_types_hash_map.count;
+ for (auto const &tt : type_info_types) {
+ isize index = tt.hash % hash_map_len;
+ // NOTE(bill): no need for a sanity check since there
+ // will always be enough space for the entries
+ for (;;) {
+ if (index == 0 || c->info.type_info_types_hash_map[index].hash != 0) {
+ index = (index+1) % hash_map_len;
+ continue;
+ }
+ break;
+ }
+ c->info.type_info_types_hash_map[index] = tt;
+
+ bool exists = map_set_if_not_previously_exists(&c->info.min_dep_type_info_index_map, tt.hash, index);
+ if (exists) {
+ for (auto const &entry : c->info.min_dep_type_info_index_map) {
+ if (entry.key != tt.hash) {
+ continue;
+ }
+ auto const &other = type_info_types[entry.value];
+ if (are_types_identical_unique_tuples(tt.type, other.type)) {
+ continue;
+ }
+ gbString t = temp_canonical_string(tt.type);
+ gbString o = temp_canonical_string(other.type);
+ GB_PANIC("%s (%s) %llu vs %s (%s) %llu",
+ type_to_string(tt.type, false), t, cast(unsigned long long)tt.hash,
+ type_to_string(other.type, false), o, cast(unsigned long long)other.hash);
+ }
+ }
+ }
+
+
+ GB_ASSERT(c->info.min_dep_type_info_index_map.count <= type_info_types.count);
+ }
+
+
TIME_SECTION("sort init and fini procedures");
check_sort_init_and_fini_procedures(c);
diff --git a/src/checker.hpp b/src/checker.hpp
index 3951fcefe..dabb7330a 100644
--- a/src/checker.hpp
+++ b/src/checker.hpp
@@ -139,7 +139,10 @@ struct AttributeContext {
bool entry_point_only : 1;
bool instrumentation_enter : 1;
bool instrumentation_exit : 1;
+ bool no_sanitize_address : 1;
+ bool no_sanitize_memory : 1;
bool rodata : 1;
+ bool ignore_duplicates : 1;
u32 optimization_mode; // ProcedureOptimizationMode
i64 foreign_import_priority_index;
String extra_linker_flags;
@@ -147,8 +150,14 @@ struct AttributeContext {
String objc_class;
String objc_name;
- bool objc_is_class_method;
+ String objc_selector;
Type * objc_type;
+ Type * objc_superclass;
+ Type * objc_ivar;
+ Entity *objc_context_provider;
+ bool objc_is_class_method;
+ bool objc_is_implementation; // This struct or proc provides a class/method implementation, not a binding to an existing type.
+ bool objc_is_disabled_implement; // This means the method explicitly set @objc_implement to false so it won't be inferred from the class' attribute.
String require_target_feature; // required by the target micro-architecture
String enable_target_feature; // will be enabled for the procedure only
@@ -166,6 +175,7 @@ typedef DECL_ATTRIBUTE_PROC(DeclAttributeProc);
gb_internal void check_decl_attributes(CheckerContext *c, Array<Ast *> const &attributes, DeclAttributeProc *proc, AttributeContext *ac);
+#include "name_canonicalization.hpp"
enum ProcCheckedState : u8 {
ProcCheckedState_Unchecked,
@@ -220,13 +230,15 @@ struct DeclInfo {
RwMutex deps_mutex;
PtrSet<Entity *> deps;
- RwMutex type_info_deps_mutex;
- PtrSet<Type *> type_info_deps;
+ RwMutex type_info_deps_mutex;
+ TypeSet type_info_deps;
BlockingMutex type_and_value_mutex;
Array<BlockLabel> labels;
+ i32 scope_index;
+
Array<VariadicReuseData> variadic_reuses;
i64 variadic_reuse_max_bytes;
i64 variadic_reuse_max_align;
@@ -271,10 +283,14 @@ struct Scope {
std::atomic<Scope *> next;
std::atomic<Scope *> head_child;
+ i32 index; // within a procedure
+
RwMutex mutex;
StringMap<Entity *> elements;
PtrSet<Scope *> imported;
+ DeclInfo *decl_info;
+
i32 flags; // ScopeFlag
union {
AstPackage *pkg;
@@ -357,6 +373,11 @@ struct ObjcMsgData {
Type *proc_type;
};
+struct ObjcMethodData {
+ AttributeContext ac;
+ Entity *proc_entity;
+};
+
enum LoadFileTier {
LoadFileTier_Invalid,
LoadFileTier_Exists,
@@ -420,8 +441,10 @@ struct CheckerInfo {
Scope * init_scope;
Entity * entry_point;
PtrSet<Entity *> minimum_dependency_set;
- PtrMap</*type info index*/isize, /*min dep index*/isize> minimum_dependency_type_info_set;
-
+ BlockingMutex minimum_dependency_type_info_mutex;
+ PtrMap</*type info hash*/u64, /*min dep index*/isize> min_dep_type_info_index_map;
+ TypeSet min_dep_type_info_set;
+ Array<TypeInfoPair> type_info_types_hash_map; // 2 * type_info_types.count
Array<Entity *> testing_procedures;
@@ -449,9 +472,10 @@ struct CheckerInfo {
BlockingMutex gen_types_mutex;
PtrMap<Type *, GenTypesData *> gen_types;
- BlockingMutex type_info_mutex; // NOT recursive
- Array<Type *> type_info_types;
- PtrMap<Type *, isize> type_info_map;
+ // BlockingMutex type_info_mutex; // NOT recursive
+ // Array<TypeInfoPair> type_info_types;
+ // PtrMap<Type *, isize> type_info_map;
+ // TypeSet type_info_set;
BlockingMutex foreign_mutex; // NOT recursive
StringMap<Entity *> foreigns;
@@ -465,9 +489,17 @@ struct CheckerInfo {
MPSCQueue<Ast *> intrinsics_entry_point_usage;
- BlockingMutex objc_types_mutex;
+ BlockingMutex objc_objc_msgSend_mutex;
PtrMap<Ast *, ObjcMsgData> objc_msgSend_types;
+ BlockingMutex objc_class_name_mutex;
+ StringSet obcj_class_name_set;
+ MPSCQueue<Entity *> objc_class_implementations;
+
+ BlockingMutex objc_method_mutex;
+ PtrMap<Type *, Array<ObjcMethodData>> objc_method_implementations;
+
+
BlockingMutex load_file_mutex;
StringMap<LoadFileCache *> load_file_cache;
@@ -544,6 +576,7 @@ struct Checker {
CheckerContext builtin_ctx;
MPSCQueue<Entity *> procs_with_deferred_to_check;
+ MPSCQueue<Entity *> procs_with_objc_context_provider_to_check;
Array<ProcInfo *> procs_to_check;
BlockingMutex nested_proc_lits_mutex;
@@ -570,6 +603,7 @@ gb_internal DeclInfo * decl_info_of_entity (Entity * e);
gb_internal AstFile * ast_file_of_filename (CheckerInfo *i, String filename);
// IMPORTANT: Only to use once checking is done
gb_internal isize type_info_index (CheckerInfo *i, Type *type, bool error_on_failure);
+gb_internal isize type_info_index (CheckerInfo *info, TypeInfoPair pair, bool error_on_failure);
// Will return nullptr if not found
gb_internal Entity *entity_of_node(Ast *expr);
@@ -617,4 +651,4 @@ gb_internal void add_untyped_expressions(CheckerInfo *cinfo, UntypedExprInfoMap
gb_internal GenTypesData *ensure_polymorphic_record_entity_has_gen_types(CheckerContext *ctx, Type *original_type);
-gb_internal void init_map_internal_types(Type *type); \ No newline at end of file
+gb_internal void init_map_internal_types(Type *type);
diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp
index 2dfd570e4..90652cb0b 100644
--- a/src/checker_builtin_procs.hpp
+++ b/src/checker_builtin_procs.hpp
@@ -26,6 +26,7 @@ enum BuiltinProcId {
BuiltinProc_conj,
BuiltinProc_expand_values,
+ BuiltinProc_compress_values,
BuiltinProc_min,
BuiltinProc_max,
@@ -170,8 +171,12 @@ BuiltinProc__simd_begin,
BuiltinProc_simd_extract,
BuiltinProc_simd_replace,
+ BuiltinProc_simd_reduce_add_bisect,
+ BuiltinProc_simd_reduce_mul_bisect,
BuiltinProc_simd_reduce_add_ordered,
BuiltinProc_simd_reduce_mul_ordered,
+ BuiltinProc_simd_reduce_add_pairs,
+ BuiltinProc_simd_reduce_mul_pairs,
BuiltinProc_simd_reduce_min,
BuiltinProc_simd_reduce_max,
BuiltinProc_simd_reduce_and,
@@ -181,6 +186,9 @@ BuiltinProc__simd_begin,
BuiltinProc_simd_reduce_any,
BuiltinProc_simd_reduce_all,
+ BuiltinProc_simd_extract_lsbs,
+ BuiltinProc_simd_extract_msbs,
+
BuiltinProc_simd_shuffle,
BuiltinProc_simd_select,
@@ -202,6 +210,9 @@ BuiltinProc__simd_begin,
BuiltinProc_simd_masked_expand_load,
BuiltinProc_simd_masked_compress_store,
+ BuiltinProc_simd_indices,
+
+
// Platform specific SIMD intrinsics
BuiltinProc_simd_x86__MM_SHUFFLE,
BuiltinProc__simd_end,
@@ -224,8 +235,12 @@ BuiltinProc__type_begin,
BuiltinProc_type_convert_variants_to_pointers,
BuiltinProc_type_merge,
+ BuiltinProc_type_integer_to_unsigned,
+ BuiltinProc_type_integer_to_signed,
+
BuiltinProc__type_simple_boolean_begin,
BuiltinProc_type_is_boolean,
+ BuiltinProc_type_is_bit_field,
BuiltinProc_type_is_integer,
BuiltinProc_type_is_rune,
BuiltinProc_type_is_float,
@@ -328,6 +343,7 @@ BuiltinProc__type_end,
BuiltinProc_objc_find_class,
BuiltinProc_objc_register_selector,
BuiltinProc_objc_register_class,
+ BuiltinProc_objc_ivar_get,
BuiltinProc_constant_utf16_cstring,
@@ -365,6 +381,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
{STR_LIT("conj"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
{STR_LIT("expand_values"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
+ {STR_LIT("compress_values"), 1, true, Expr_Expr, BuiltinProcPkg_builtin},
{STR_LIT("min"), 1, true, Expr_Expr, BuiltinProcPkg_builtin},
{STR_LIT("max"), 1, true, Expr_Expr, BuiltinProcPkg_builtin},
@@ -512,8 +529,12 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
{STR_LIT("simd_extract"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("simd_replace"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
+ {STR_LIT("simd_reduce_add_bisect"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
+ {STR_LIT("simd_reduce_mul_bisect"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("simd_reduce_add_ordered"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("simd_reduce_mul_ordered"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
+ {STR_LIT("simd_reduce_add_pairs"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
+ {STR_LIT("simd_reduce_mul_pairs"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("simd_reduce_min"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("simd_reduce_max"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("simd_reduce_and"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
@@ -523,6 +544,9 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
{STR_LIT("simd_reduce_any"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("simd_reduce_all"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
+ {STR_LIT("simd_extract_lsbs"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
+ {STR_LIT("simd_extract_msbs"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
+
{STR_LIT("simd_shuffle"), 2, true, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("simd_select"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
@@ -545,6 +569,8 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
{STR_LIT("simd_masked_expand_load"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("simd_masked_compress_store"), 3, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
+ {STR_LIT("simd_indices"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
+
{STR_LIT("simd_x86__MM_SHUFFLE"), 4, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT(""), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
@@ -563,6 +589,9 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
{STR_LIT("type_convert_variants_to_pointers"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("type_merge"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
+ {STR_LIT("type_integer_to_unsigned"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
+ {STR_LIT("type_integer_to_signed"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
+
{STR_LIT(""), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
{STR_LIT("type_is_boolean"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("type_is_integer"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
@@ -602,6 +631,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
{STR_LIT("type_is_enum"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("type_is_proc"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("type_is_bit_set"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
+ {STR_LIT("type_is_bit_field"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("type_is_simd_vector"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("type_is_matrix"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
@@ -667,6 +697,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
{STR_LIT("objc_find_class"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("objc_register_selector"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics, false, true},
{STR_LIT("objc_register_class"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics, false, true},
+ {STR_LIT("objc_ivar_get"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics, false, true},
{STR_LIT("constant_utf16_cstring"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
diff --git a/src/common.cpp b/src/common.cpp
index 0ef39bd10..ad1e5a851 100644
--- a/src/common.cpp
+++ b/src/common.cpp
@@ -134,9 +134,9 @@ gb_internal u32 fnv32a(void const *data, isize len) {
return h;
}
-gb_internal u64 fnv64a(void const *data, isize len) {
+gb_internal u64 fnv64a(void const *data, isize len, u64 seed=0xcbf29ce484222325ull) {
u8 const *bytes = cast(u8 const *)data;
- u64 h = 0xcbf29ce484222325ull;
+ u64 h = seed;
for (; len >= 8; len -= 8, bytes += 8) {
h = (h ^ bytes[0]) * 0x100000001b3ull;
diff --git a/src/docs_writer.cpp b/src/docs_writer.cpp
index 341b3fa6b..1f2325980 100644
--- a/src/docs_writer.cpp
+++ b/src/docs_writer.cpp
@@ -16,6 +16,8 @@ gb_global char const* OdinDocWriterState_strings[] {
"writing ",
};
+gb_global std::atomic<bool> g_in_doc_writer;
+
struct OdinDocWriter {
CheckerInfo *info;
OdinDocWriterState state;
@@ -26,11 +28,10 @@ struct OdinDocWriter {
StringMap<OdinDocString> string_cache;
- OrderedInsertPtrMap<AstFile *, OdinDocFileIndex> file_cache;
- OrderedInsertPtrMap<AstPackage *, OdinDocPkgIndex> pkg_cache;
- OrderedInsertPtrMap<Entity *, OdinDocEntityIndex> entity_cache;
- OrderedInsertPtrMap<Type *, OdinDocTypeIndex> type_cache;
- OrderedInsertPtrMap<Type *, Type *> stable_type_cache;
+ OrderedInsertPtrMap<AstFile *, OdinDocFileIndex> file_cache;
+ OrderedInsertPtrMap<AstPackage *, OdinDocPkgIndex> pkg_cache;
+ OrderedInsertPtrMap<Entity *, OdinDocEntityIndex> entity_cache;
+ OrderedInsertPtrMap<u64/*type hash*/, OdinDocTypeIndex> type_cache;
OdinDocWriterItemTracker<OdinDocFile> files;
OdinDocWriterItemTracker<OdinDocPkg> pkgs;
@@ -42,7 +43,7 @@ struct OdinDocWriter {
};
gb_internal OdinDocEntityIndex odin_doc_add_entity(OdinDocWriter *w, Entity *e);
-gb_internal OdinDocTypeIndex odin_doc_type(OdinDocWriter *w, Type *type);
+gb_internal OdinDocTypeIndex odin_doc_type(OdinDocWriter *w, Type *type, bool cache);
template <typename T>
gb_internal void odin_doc_writer_item_tracker_init(OdinDocWriterItemTracker<T> *t, isize size) {
@@ -61,7 +62,6 @@ gb_internal void odin_doc_writer_prepare(OdinDocWriter *w) {
map_init(&w->pkg_cache, 1<<10);
map_init(&w->entity_cache, 1<<18);
map_init(&w->type_cache, 1<<18);
- map_init(&w->stable_type_cache, 1<<18);
odin_doc_writer_item_tracker_init(&w->files, 1);
odin_doc_writer_item_tracker_init(&w->pkgs, 1);
@@ -81,7 +81,6 @@ gb_internal void odin_doc_writer_destroy(OdinDocWriter *w) {
map_destroy(&w->pkg_cache);
map_destroy(&w->entity_cache);
map_destroy(&w->type_cache);
- map_destroy(&w->stable_type_cache);
}
@@ -468,8 +467,8 @@ gb_internal OdinDocArray<OdinDocString> odin_doc_where_clauses(OdinDocWriter *w,
return odin_write_slice(w, clauses.data, clauses.count);
}
-gb_internal OdinDocArray<OdinDocTypeIndex> odin_doc_type_as_slice(OdinDocWriter *w, Type *type) {
- OdinDocTypeIndex index = odin_doc_type(w, type);
+gb_internal OdinDocArray<OdinDocTypeIndex> odin_doc_type_as_slice(OdinDocWriter *w, Type *type, bool cache=true) {
+ OdinDocTypeIndex index = odin_doc_type(w, type, cache);
return odin_write_item_as_slice(w, index);
}
@@ -480,7 +479,7 @@ gb_internal OdinDocArray<OdinDocEntityIndex> odin_doc_add_entity_as_slice(OdinDo
-gb_internal OdinDocTypeIndex odin_doc_type(OdinDocWriter *w, Type *type) {
+gb_internal OdinDocTypeIndex odin_doc_type(OdinDocWriter *w, Type *type, bool cache=true) {
if (type == nullptr) {
return 0;
}
@@ -492,46 +491,13 @@ gb_internal OdinDocTypeIndex odin_doc_type(OdinDocWriter *w, Type *type) {
}
}
- // Type **mapped_type = map_get(&w->stable_type_cache, type); // may map to itself
- // if (mapped_type && *mapped_type) {
- // type = *mapped_type;
- // }
-
- OdinDocTypeIndex *found = map_get(&w->type_cache, type);
- if (found) {
- return *found;
- }
- for (auto const &entry : w->type_cache) {
- // NOTE(bill): THIS IS SLOW
- Type *x = type;
- Type *y = entry.key;
-
- if (x == y) {
- goto do_set;
- }
-
- if (!x | !y) {
- continue;
- }
- if (y->kind == Type_Named) {
- Entity *e = y->Named.type_name;
- if (e->TypeName.is_type_alias) {
- y = y->Named.base;
- }
- }
- if (x->kind != y->kind) {
- continue;
+ u64 type_hash = {0};
+ if (cache) {
+ type_hash = type_hash_canonical_type(type);
+ OdinDocTypeIndex *found = map_get(&w->type_cache, type_hash);
+ if (found) {
+ return *found;
}
-
- if (!are_types_identical_internal(x, y, true)) {
- continue;
- }
-
- do_set:
- OdinDocTypeIndex index = entry.value;
- map_set(&w->type_cache, type, index);
- map_set(&w->stable_type_cache, type, entry.key);
- return index;
}
@@ -539,8 +505,9 @@ gb_internal OdinDocTypeIndex odin_doc_type(OdinDocWriter *w, Type *type) {
OdinDocType doc_type = {};
OdinDocTypeIndex type_index = 0;
type_index = odin_doc_write_item(w, &w->types, &doc_type, &dst);
- map_set(&w->type_cache, type, type_index);
- map_set(&w->stable_type_cache, type, type);
+ if (cache) {
+ map_set(&w->type_cache, type_hash, type_index);
+ }
switch (type->kind) {
case Type_Basic:
@@ -565,7 +532,10 @@ gb_internal OdinDocTypeIndex odin_doc_type(OdinDocWriter *w, Type *type) {
doc_type.kind = OdinDocType_Generic;
doc_type.name = odin_doc_write_string(w, name);
if (type->Generic.specialized) {
- doc_type.types = odin_doc_type_as_slice(w, type->Generic.specialized);
+ // NOTE(laytan): do not look at the cache for the specialization, it would resolve
+ // to the same entry as the type itself because `default_type` resolves to the
+ // specialization of a generic type.
+ doc_type.types = odin_doc_type_as_slice(w, type->Generic.specialized, cache=false);
}
}
break;
@@ -1177,6 +1147,8 @@ gb_internal void odin_doc_write_to_file(OdinDocWriter *w, char const *filename)
}
gb_internal void odin_doc_write(CheckerInfo *info, char const *filename) {
+ g_in_doc_writer.store(true);
+
OdinDocWriter w_ = {};
OdinDocWriter *w = &w_;
defer (odin_doc_writer_destroy(w));
@@ -1192,4 +1164,11 @@ gb_internal void odin_doc_write(CheckerInfo *info, char const *filename) {
odin_doc_writer_end_writing(w);
odin_doc_write_to_file(w, filename);
+
+ g_in_doc_writer.store(false);
+}
+
+
+gb_internal bool is_in_doc_writer(void) {
+ return g_in_doc_writer.load();
}
diff --git a/src/entity.cpp b/src/entity.cpp
index 802b381f9..6c0aa6ace 100644
--- a/src/entity.cpp
+++ b/src/entity.cpp
@@ -235,6 +235,10 @@ struct Entity {
Type * type_parameter_specialization;
String ir_mangled_name;
bool is_type_alias;
+ bool objc_is_implementation;
+ Type* objc_superclass;
+ Type* objc_ivar;
+ Entity*objc_context_provider;
String objc_class_name;
TypeNameObjCMetadata *objc_metadata;
} TypeName;
@@ -257,6 +261,9 @@ struct Entity {
bool has_instrumentation : 1;
bool is_memcpy_like : 1;
bool uses_branch_location : 1;
+ bool is_anonymous : 1;
+ bool no_sanitize_address : 1;
+ bool no_sanitize_memory : 1;
} Procedure;
struct {
Array<Entity *> entities;
@@ -274,6 +281,7 @@ struct Entity {
Slice<String> paths;
String name;
i64 priority_index;
+ bool ignore_duplicates;
String extra_linker_flags;
} LibraryName;
i32 Nil;
diff --git a/src/error.cpp b/src/error.cpp
index 1492b00c7..006d5ae8d 100644
--- a/src/error.cpp
+++ b/src/error.cpp
@@ -823,7 +823,7 @@ gb_internal int error_value_cmp(void const *a, void const *b) {
gb_global String error_article_table[][2] = {
{str_lit("a "), str_lit("bit_set literal")},
{str_lit("a "), str_lit("constant declaration")},
- {str_lit("a "), str_lit("dynamiic array literal")},
+ {str_lit("a "), str_lit("dynamic array literal")},
{str_lit("a "), str_lit("map index")},
{str_lit("a "), str_lit("map literal")},
{str_lit("a "), str_lit("matrix literal")},
diff --git a/src/exact_value.cpp b/src/exact_value.cpp
index ceaed84c1..37751c8f1 100644
--- a/src/exact_value.cpp
+++ b/src/exact_value.cpp
@@ -954,6 +954,10 @@ gb_internal bool compare_exact_values(TokenKind op, ExactValue x, ExactValue y)
case ExactValue_Float: {
f64 a = x.value_float;
f64 b = y.value_float;
+ if (isnan(a) || isnan(b)) {
+ return op == Token_NotEq;
+ }
+
switch (op) {
case Token_CmpEq: return cmp_f64(a, b) == 0;
case Token_NotEq: return cmp_f64(a, b) != 0;
diff --git a/src/gb/gb.h b/src/gb/gb.h
index f74026c7d..6ce8626c0 100644
--- a/src/gb/gb.h
+++ b/src/gb/gb.h
@@ -497,7 +497,11 @@ typedef i32 b32; // NOTE(bill): Prefer this!!!
#if !defined(gb_no_asan)
#if defined(_MSC_VER)
- #define gb_no_asan __declspec(no_sanitize_address)
+ #if _MSC_VER >= 1930
+ #define gb_no_asan __declspec(no_sanitize_address)
+ #else
+ #define gb_no_asan
+ #endif
#else
#define gb_no_asan __attribute__((disable_sanitizer_instrumentation))
#endif
@@ -5837,15 +5841,33 @@ gb_inline isize gb_printf_err_va(char const *fmt, va_list va) {
}
gb_inline isize gb_fprintf_va(struct gbFile *f, char const *fmt, va_list va) {
- gb_local_persist char buf[4096];
- isize len = gb_snprintf_va(buf, gb_size_of(buf), fmt, va);
- gb_file_write(f, buf, len-1); // NOTE(bill): prevent extra whitespace
+ char buf[4096];
+ va_list va_save;
+ va_copy(va_save, va);
+ isize len = gb_snprintf_va(buf, gb_size_of(buf), fmt, va_save);
+ va_end(va_save);
+ char *new_buf = NULL;
+ isize n = gb_size_of(buf);
+ while (len < 0) {
+ va_copy(va_save, va);
+ defer (va_end(va_save));
+ n <<= 1;
+ gb_free(gb_heap_allocator(), new_buf);
+ new_buf = gb_alloc_array(gb_heap_allocator(), char, n);;
+ len = gb_snprintf_va(new_buf, n, fmt, va_save);
+ }
+ if (new_buf != NULL) {
+ gb_file_write(f, new_buf, len-1); // NOTE(bill): prevent extra whitespace
+ gb_free(gb_heap_allocator(), new_buf);
+ } else {
+ gb_file_write(f, buf, len-1); // NOTE(bill): prevent extra whitespace
+ }
return len;
}
gb_inline char *gb_bprintf_va(char const *fmt, va_list va) {
- gb_local_persist char buffer[4096];
+ gb_thread_local gb_local_persist char buffer[4096];
gb_snprintf_va(buffer, gb_size_of(buffer), fmt, va);
return buffer;
}
@@ -5901,7 +5923,7 @@ gb_internal isize gb__print_string(char *text, isize max_len, gbprivFmtInfo *inf
len = info->precision < len ? info->precision : len;
}
- res += gb_strlcpy(text, str, len);
+ res += gb_strlcpy(text, str, gb_min(len, remaining));
if (info->width > res) {
isize padding = info->width - len;
@@ -5919,7 +5941,7 @@ gb_internal isize gb__print_string(char *text, isize max_len, gbprivFmtInfo *inf
}
}
- res += gb_strlcpy(text, str, len);
+ res += gb_strlcpy(text, str, gb_min(len, remaining));
}
@@ -6055,15 +6077,16 @@ gb_internal isize gb__print_f64(char *text, isize max_len, gbprivFmtInfo *info,
gb_no_inline isize gb_snprintf_va(char *text, isize max_len, char const *fmt, va_list va) {
char const *text_begin = text;
- isize remaining = max_len, res;
+ isize remaining = max_len - 1, res;
- while (*fmt) {
+ while (*fmt && remaining > 0) {
gbprivFmtInfo info = {0};
isize len = 0;
info.precision = -1;
- while (*fmt && *fmt != '%' && remaining) {
+ while (remaining > 0 && *fmt && *fmt != '%') {
*text++ = *fmt++;
+ remaining--;
}
if (*fmt == '%') {
@@ -6229,7 +6252,7 @@ gb_no_inline isize gb_snprintf_va(char *text, isize max_len, char const *fmt, va
text += len;
if (len >= remaining) {
- remaining = gb_min(remaining, 1);
+ remaining = 0;
} else {
remaining -= len;
}
diff --git a/src/linker.cpp b/src/linker.cpp
index 261d6e7a4..bf2ba6fe0 100644
--- a/src/linker.cpp
+++ b/src/linker.cpp
@@ -7,19 +7,15 @@ struct LinkerData {
Array<String> output_temp_paths;
String output_base;
String output_name;
-#if defined(GB_SYSTEM_OSX)
- b8 needs_system_library_linked;
-#endif
+ bool needs_system_library_linked;
};
gb_internal i32 system_exec_command_line_app(char const *name, char const *fmt, ...);
gb_internal bool system_exec_command_line_app_output(char const *command, gbString *output);
-#if defined(GB_SYSTEM_OSX)
gb_internal void linker_enable_system_library_linking(LinkerData *ld) {
- ld->needs_system_library_linked = 1;
+ ld->needs_system_library_linked = true;
}
-#endif
gb_internal void linker_data_init(LinkerData *ld, CheckerInfo *info, String const &init_fullpath) {
gbAllocator ha = heap_allocator();
@@ -28,9 +24,7 @@ gb_internal void linker_data_init(LinkerData *ld, CheckerInfo *info, String cons
array_init(&ld->foreign_libraries, ha, 0, 1024);
ptr_set_init(&ld->foreign_libraries_set, 1024);
-#if defined(GB_SYSTEM_OSX)
- ld->needs_system_library_linked = 0;
-#endif
+ ld->needs_system_library_linked = false;
if (build_context.out_filepath.len == 0) {
ld->output_name = remove_directory_from_path(init_fullpath);
@@ -136,6 +130,9 @@ gb_internal i32 linker_stage(LinkerData *gen) {
return result;
}
+ bool is_cross_linking = false;
+ bool is_android = false;
+
if (build_context.cross_compiling && selected_target_metrics->metrics == &target_essence_amd64) {
#if defined(GB_SYSTEM_UNIX)
result = system_exec_command_line_app("linker", "x86_64-essence-gcc \"%.*s.o\" -o \"%.*s\" %.*s %.*s",
@@ -146,23 +143,30 @@ gb_internal i32 linker_stage(LinkerData *gen) {
LIT(target_arch_names[build_context.metrics.arch])
);
#endif
- } else if (build_context.cross_compiling && build_context.different_os) {
- gb_printf_err("Linking for cross compilation for this platform is not yet supported (%.*s %.*s)\n",
- LIT(target_os_names[build_context.metrics.os]),
- LIT(target_arch_names[build_context.metrics.arch])
- );
- build_context.keep_object_files = true;
+ } else if (build_context.cross_compiling && (build_context.different_os || selected_subtarget != Subtarget_Default)) {
+ switch (selected_subtarget) {
+ case Subtarget_Android:
+ is_cross_linking = true;
+ is_android = true;
+ goto try_cross_linking;
+ default:
+ gb_printf_err("Linking for cross compilation for this platform is not yet supported (%.*s %.*s)\n",
+ LIT(target_os_names[build_context.metrics.os]),
+ LIT(target_arch_names[build_context.metrics.arch])
+ );
+ build_context.keep_object_files = true;
+ break;
+ }
} else {
+try_cross_linking:;
+
#if defined(GB_SYSTEM_WINDOWS)
- bool is_windows = true;
+ bool is_windows = build_context.metrics.os == TargetOs_windows;
#else
bool is_windows = false;
#endif
- #if defined(GB_SYSTEM_OSX)
- bool is_osx = true;
- #else
- bool is_osx = false;
- #endif
+
+ bool is_osx = build_context.metrics.os == TargetOs_darwin;
if (is_windows) {
@@ -273,13 +277,16 @@ gb_internal i32 linker_stage(LinkerData *gen) {
if (build_context.build_mode == BuildMode_DynamicLibrary) {
link_settings = gb_string_append_fmt(link_settings, " /DLL");
+ if (build_context.no_entry_point) {
+ link_settings = gb_string_append_fmt(link_settings, " /NOENTRY");
+ }
} else {
link_settings = gb_string_append_fmt(link_settings, " /ENTRY:mainCRTStartup");
}
- if (build_context.pdb_filepath != "") {
- String pdb_path = path_to_string(heap_allocator(), build_context.build_paths[BuildPath_PDB]);
- link_settings = gb_string_append_fmt(link_settings, " /PDB:\"%.*s\"", LIT(pdb_path));
+ if (build_context.build_paths[BuildPath_Symbols].name != "") {
+ String symbol_path = path_to_string(heap_allocator(), build_context.build_paths[BuildPath_Symbols]);
+ link_settings = gb_string_append_fmt(link_settings, " /PDB:\"%.*s\"", LIT(symbol_path));
}
if (build_context.build_mode != BuildMode_StaticLibrary) {
@@ -317,7 +324,7 @@ gb_internal i32 linker_stage(LinkerData *gen) {
"",
LIT(build_context.ODIN_ROOT), object_files, LIT(output_filename),
link_settings,
- LIT(build_context.ODIN_WINDOWS_SUBSYSTEM),
+ LIT(windows_subsystem_names[build_context.ODIN_WINDOWS_SUBSYSTEM]),
LIT(build_context.link_flags),
LIT(build_context.extra_linker_flags),
lib_str
@@ -337,7 +344,7 @@ gb_internal i32 linker_stage(LinkerData *gen) {
"",
LIT(build_context.ODIN_ROOT), object_files, LIT(output_filename),
link_settings,
- LIT(build_context.ODIN_WINDOWS_SUBSYSTEM),
+ LIT(windows_subsystem_names[build_context.ODIN_WINDOWS_SUBSYSTEM]),
LIT(build_context.link_flags),
LIT(build_context.extra_linker_flags),
lib_str
@@ -400,7 +407,7 @@ gb_internal i32 linker_stage(LinkerData *gen) {
"",
LIT(vs_exe_path), LIT(linker_name), object_files, LIT(res_path), LIT(output_filename),
link_settings,
- LIT(build_context.ODIN_WINDOWS_SUBSYSTEM),
+ LIT(windows_subsystem_names[build_context.ODIN_WINDOWS_SUBSYSTEM]),
LIT(build_context.link_flags),
LIT(build_context.extra_linker_flags),
lib_str
@@ -414,23 +421,27 @@ gb_internal i32 linker_stage(LinkerData *gen) {
} else {
timings_start_section(timings, str_lit("ld-link"));
+ int const ODIN_ANDROID_API_LEVEL = build_context.ODIN_ANDROID_API_LEVEL;
+
+ String ODIN_ANDROID_NDK = build_context.ODIN_ANDROID_NDK;
+ String ODIN_ANDROID_NDK_TOOLCHAIN = build_context.ODIN_ANDROID_NDK_TOOLCHAIN;
+ String ODIN_ANDROID_NDK_TOOLCHAIN_LIB = build_context.ODIN_ANDROID_NDK_TOOLCHAIN_LIB;
+ String ODIN_ANDROID_NDK_TOOLCHAIN_LIB_LEVEL = build_context.ODIN_ANDROID_NDK_TOOLCHAIN_LIB_LEVEL;
+ String ODIN_ANDROID_NDK_TOOLCHAIN_SYSROOT = build_context.ODIN_ANDROID_NDK_TOOLCHAIN_SYSROOT;
+
// Link using `clang`, unless overridden by `ODIN_CLANG_PATH` environment variable.
const char* clang_path = gb_get_env("ODIN_CLANG_PATH", permanent_allocator());
if (clang_path == NULL) {
clang_path = "clang";
}
- // NOTE(vassvik): get cwd, for used for local shared libs linking, since those have to be relative to the exe
- char cwd[256];
- #if !defined(GB_SYSTEM_WINDOWS)
- getcwd(&cwd[0], 256);
- #endif
- //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/");
+ gbString lib_str = gb_string_make(heap_allocator(), "");
defer (gb_string_free(lib_str));
+ #if !defined(GB_SYSTEM_WINDOWS)
+ lib_str = gb_string_appendc(lib_str, "-L/ ");
+ #endif
StringSet asm_files = {};
string_set_init(&asm_files, 64);
@@ -449,6 +460,26 @@ gb_internal i32 linker_stage(LinkerData *gen) {
if (extra_linker_flags.len != 0) {
lib_str = gb_string_append_fmt(lib_str, " %.*s", LIT(extra_linker_flags));
}
+
+ if (build_context.metrics.os == TargetOs_darwin) {
+ // Print frameworks first
+ for (String lib : e->LibraryName.paths) {
+ lib = string_trim_whitespace(lib);
+ if (lib.len == 0) {
+ continue;
+ }
+ if (string_ends_with(lib, str_lit(".framework"))) {
+ if (string_set_update(&min_libs_set, lib)) {
+ continue;
+ }
+
+ 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));
+ }
+ }
+ }
+
for (String lib : e->LibraryName.paths) {
lib = string_trim_whitespace(lib);
if (lib.len == 0) {
@@ -476,19 +507,20 @@ gb_internal i32 linker_stage(LinkerData *gen) {
}
String obj_format;
- #if defined(GB_ARCH_64_BIT)
- if (is_osx) {
- obj_format = str_lit("macho64");
- } else {
- obj_format = str_lit("elf64");
- }
- #elif defined(GB_ARCH_32_BIT)
- if (is_osx) {
- obj_format = str_lit("macho32");
+ if (build_context.metrics.ptr_size == 8) {
+ if (is_osx) {
+ obj_format = str_lit("macho64");
+ } else {
+ obj_format = str_lit("elf64");
+ }
} else {
- obj_format = str_lit("elf32");
+ GB_ASSERT(build_context.metrics.ptr_size == 4);
+ if (is_osx) {
+ obj_format = str_lit("macho32");
+ } else {
+ obj_format = str_lit("elf32");
+ }
}
- #endif // GB_ARCH_*_BIT
if (build_context.metrics.arch == TargetArch_riscv64) {
result = system_exec_command_line_app("clang",
@@ -536,7 +568,18 @@ gb_internal i32 linker_stage(LinkerData *gen) {
}
array_add(&gen->output_object_paths, obj_file);
} else {
- if (string_set_update(&min_libs_set, lib) && build_context.min_link_libs) {
+ bool short_circuit = false;
+ if (string_ends_with(lib, str_lit(".framework"))) {
+ short_circuit = true;
+ } else if (string_ends_with(lib, str_lit(".dylib"))) {
+ short_circuit = true;
+ } else if (string_ends_with(lib, str_lit(".so"))) {
+ short_circuit = true;
+ } else if (e->LibraryName.ignore_duplicates) {
+ short_circuit = true;
+ }
+
+ if (string_set_update(&min_libs_set, lib) && (build_context.min_link_libs || short_circuit)) {
continue;
}
@@ -563,7 +606,7 @@ gb_internal i32 linker_stage(LinkerData *gen) {
// object
// dynamic lib
// 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));
+ 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));
@@ -587,8 +630,86 @@ gb_internal i32 linker_stage(LinkerData *gen) {
gbString object_files = gb_string_make(heap_allocator(), "");
defer (gb_string_free(object_files));
+
+
+ if (is_android) { // NOTE(bill): glue code needed for Android
+ TIME_SECTION("Android Native App Glue Compile");
+
+ String android_glue_object = {};
+ String android_glue_static_lib = {};
+
+ char hash_buf[64] = {};
+ gb_snprintf(hash_buf, gb_size_of(hash_buf), "%p", &hash_buf);
+ String hash = make_string_c(hash_buf);
+
+ String temp_dir = normalize_path(temporary_allocator(), temporary_directory(temporary_allocator()), NIX_SEPARATOR_STRING);
+ android_glue_object = concatenate4_strings(temporary_allocator(), temp_dir, str_lit("android_native_app_glue-"), hash, str_lit(".o"));
+ android_glue_static_lib = concatenate4_strings(permanent_allocator(), temp_dir, str_lit("libandroid_native_app_glue-"), hash, str_lit(".a"));
+
+ gbString glue = gb_string_make_length(heap_allocator(), ODIN_ANDROID_NDK_TOOLCHAIN.text, ODIN_ANDROID_NDK_TOOLCHAIN.len);
+ defer (gb_string_free(glue));
+
+ glue = gb_string_append_fmt(glue, "bin/clang");
+ glue = gb_string_append_fmt(glue, " --target=aarch64-linux-android%d ", ODIN_ANDROID_API_LEVEL);
+ glue = gb_string_appendc(glue, "-c \"");
+ glue = gb_string_append_length(glue, ODIN_ANDROID_NDK.text, ODIN_ANDROID_NDK.len);
+ glue = gb_string_appendc(glue, "sources/android/native_app_glue/android_native_app_glue.c");
+ glue = gb_string_appendc(glue, "\" ");
+ glue = gb_string_appendc(glue, "-o \"");
+ glue = gb_string_append_length(glue, android_glue_object.text, android_glue_object.len);
+ glue = gb_string_appendc(glue, "\" ");
+
+ glue = gb_string_appendc(glue, "--sysroot \"");
+ glue = gb_string_append_length(glue, ODIN_ANDROID_NDK_TOOLCHAIN.text, ODIN_ANDROID_NDK_TOOLCHAIN.len);
+ glue = gb_string_appendc(glue, "sysroot");
+ glue = gb_string_appendc(glue, "\" ");
+
+ glue = gb_string_appendc(glue, "\"-I");
+ glue = gb_string_append_length(glue, ODIN_ANDROID_NDK_TOOLCHAIN.text, ODIN_ANDROID_NDK_TOOLCHAIN.len);
+ glue = gb_string_appendc(glue, "sysroot/usr/include/");
+ glue = gb_string_appendc(glue, "\" ");
+
+ glue = gb_string_appendc(glue, "\"-I");
+ glue = gb_string_append_length(glue, ODIN_ANDROID_NDK_TOOLCHAIN.text, ODIN_ANDROID_NDK_TOOLCHAIN.len);
+ glue = gb_string_appendc(glue, "sysroot/usr/include/aarch64-linux-android/");
+ glue = gb_string_appendc(glue, "\" ");
+
+
+ glue = gb_string_appendc(glue, "-Wno-macro-redefined ");
+
+ result = system_exec_command_line_app("android-native-app-glue-compile", glue);
+ if (result) {
+ return result;
+ }
+
+ TIME_SECTION("Android Native App Glue ar");
+
+ gbString ar = gb_string_make_length(heap_allocator(), ODIN_ANDROID_NDK_TOOLCHAIN.text, ODIN_ANDROID_NDK_TOOLCHAIN.len);
+ defer (gb_string_free(ar));
+
+ ar = gb_string_appendc(ar, "bin/llvm-ar");
+
+ ar = gb_string_appendc(ar, " rcs ");
+
+ ar = gb_string_appendc(ar, "\"");
+ ar = gb_string_append_length(ar, android_glue_static_lib.text, android_glue_static_lib.len);
+ ar = gb_string_appendc(ar, "\" ");
+
+ ar = gb_string_appendc(ar, "\"");
+ ar = gb_string_append_length(ar, android_glue_object.text, android_glue_object.len);
+ ar = gb_string_appendc(ar, "\" ");
+
+ result = system_exec_command_line_app("android-native-app-glue-ar", ar);
+ if (result) {
+ return result;
+ }
+
+ object_files = gb_string_append_fmt(object_files, "\'%.*s\' ", LIT(android_glue_static_lib));
+ }
+
+
for (String object_path : gen->output_object_paths) {
- object_files = gb_string_append_fmt(object_files, "\"%.*s\" ", LIT(object_path));
+ object_files = gb_string_append_fmt(object_files, "\'%.*s\' ", LIT(object_path));
}
gbString link_settings = gb_string_make_reserve(heap_allocator(), 32);
@@ -630,7 +751,9 @@ gb_internal i32 linker_stage(LinkerData *gen) {
link_settings = gb_string_appendc(link_settings, "-Wl,-init,'_odin_entry_point' ");
link_settings = gb_string_appendc(link_settings, "-Wl,-fini,'_odin_exit_point' ");
}
-
+ } else if (is_android) {
+ // Always shared even in android!
+ link_settings = gb_string_appendc(link_settings, "-shared ");
}
if (build_context.build_mode == BuildMode_Executable && build_context.reloc_mode == RelocMode_PIC) {
@@ -639,6 +762,7 @@ gb_internal i32 linker_stage(LinkerData *gen) {
if (build_context.metrics.os != TargetOs_openbsd
&& build_context.metrics.os != TargetOs_haiku
&& build_context.metrics.arch != TargetArch_riscv64
+ && !is_android
) {
// OpenBSD and Haiku default to PIE executable. do not pass -no-pie for it.
link_settings = gb_string_appendc(link_settings, "-no-pie ");
@@ -648,7 +772,17 @@ gb_internal i32 linker_stage(LinkerData *gen) {
gbString platform_lib_str = gb_string_make(heap_allocator(), "");
defer (gb_string_free(platform_lib_str));
if (build_context.metrics.os == TargetOs_darwin) {
- platform_lib_str = gb_string_appendc(platform_lib_str, "-Wl,-syslibroot /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk -L/usr/local/lib ");
+ // Get the MacOSX SDK path.
+ gbString darwin_sdk_path = gb_string_make(temporary_allocator(), "");
+ if (!system_exec_command_line_app_output("xcrun --sdk macosx --show-sdk-path", &darwin_sdk_path)) {
+ darwin_sdk_path = gb_string_set(darwin_sdk_path, "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk");
+ } else {
+ // Trim the trailing newline.
+ darwin_sdk_path = gb_string_trim_space(darwin_sdk_path);
+ }
+ platform_lib_str = gb_string_append_fmt(platform_lib_str, "--sysroot %s ", darwin_sdk_path);
+
+ platform_lib_str = gb_string_appendc(platform_lib_str, "-L/usr/local/lib ");
// Homebrew's default library path, checking if it exists to avoid linking warnings.
if (gb_file_exists("/opt/homebrew/lib")) {
@@ -670,6 +804,47 @@ gb_internal i32 linker_stage(LinkerData *gen) {
// This points the linker to where the entry point is
link_settings = gb_string_appendc(link_settings, "-e _main ");
}
+ } else if (build_context.metrics.os == TargetOs_freebsd) {
+ if (build_context.sanitizer_flags & (SanitizerFlag_Address | SanitizerFlag_Memory)) {
+ // It's imperative that `pthread` is linked before `libc`,
+ // otherwise ASan/MSan will be unable to call `pthread_key_create`
+ // because FreeBSD's `libthr` implementation of `pthread`
+ // needs to replace the relevant stubs first.
+ //
+ // (Presumably TSan implements its own `pthread` interface,
+ // which is why it isn't required.)
+ //
+ // See: https://reviews.llvm.org/D39254
+ platform_lib_str = gb_string_appendc(platform_lib_str, "-lpthread ");
+ }
+ // FreeBSD pkg installs third-party shared libraries in /usr/local/lib.
+ platform_lib_str = gb_string_appendc(platform_lib_str, "-Wl,-L/usr/local/lib ");
+ } else if (build_context.metrics.os == TargetOs_openbsd) {
+ // OpenBSD ports install shared libraries in /usr/local/lib. Also, we must explicitly link libpthread.
+ platform_lib_str = gb_string_appendc(platform_lib_str, "-lpthread -Wl,-L/usr/local/lib ");
+ // Until the LLVM back-end can be adapted to emit endbr64 instructions on amd64, we
+ // need to pass -z nobtcfi in order to allow the resulting program to run under
+ // OpenBSD 7.4 and newer. Once support is added at compile time, this can be dropped.
+ platform_lib_str = gb_string_appendc(platform_lib_str, "-Wl,-z,nobtcfi ");
+ }
+
+ if (is_android) {
+ GB_ASSERT(ODIN_ANDROID_NDK_TOOLCHAIN_LIB.len != 0);
+ GB_ASSERT(ODIN_ANDROID_NDK_TOOLCHAIN_LIB_LEVEL.len != 0);
+ GB_ASSERT(ODIN_ANDROID_NDK_TOOLCHAIN_SYSROOT.len != 0);
+
+ platform_lib_str = gb_string_appendc(platform_lib_str, "\"-L");
+ platform_lib_str = gb_string_append_length(platform_lib_str, ODIN_ANDROID_NDK_TOOLCHAIN_LIB_LEVEL.text, ODIN_ANDROID_NDK_TOOLCHAIN_LIB_LEVEL.len);
+ platform_lib_str = gb_string_appendc(platform_lib_str, "\" ");
+
+ platform_lib_str = gb_string_appendc(platform_lib_str, "-landroid ");
+ platform_lib_str = gb_string_appendc(platform_lib_str, "-llog ");
+
+ platform_lib_str = gb_string_appendc(platform_lib_str, "\"--sysroot=");
+ platform_lib_str = gb_string_append_length(platform_lib_str, ODIN_ANDROID_NDK_TOOLCHAIN_SYSROOT.text, ODIN_ANDROID_NDK_TOOLCHAIN_SYSROOT.len);
+ platform_lib_str = gb_string_appendc(platform_lib_str, "\" ");
+
+ link_settings = gb_string_appendc(link_settings, "-u ANativeActivity_onCreate ");
}
if (!build_context.no_rpath) {
@@ -678,24 +853,36 @@ gb_internal i32 linker_stage(LinkerData *gen) {
if (build_context.metrics.os == TargetOs_darwin) {
link_settings = gb_string_appendc(link_settings, "-Wl,-rpath,@loader_path ");
} else {
- link_settings = gb_string_appendc(link_settings, "-Wl,-rpath,\\$ORIGIN ");
+ if (is_android) {
+ // ignore
+ } else {
+ link_settings = gb_string_appendc(link_settings, "-Wl,-rpath,\\$ORIGIN ");
+ }
}
}
if (!build_context.no_crt) {
- platform_lib_str = gb_string_appendc(platform_lib_str, "-lm ");
+ lib_str = gb_string_appendc(lib_str, "-lm ");
if (build_context.metrics.os == TargetOs_darwin) {
// NOTE: adding this causes a warning about duplicate libraries, I think it is
// automatically assumed/added by clang when you don't do `-nostdlib`.
- // platform_lib_str = gb_string_appendc(platform_lib_str, "-lSystem ");
+ // lib_str = gb_string_appendc(lib_str, "-lSystem ");
} else {
- platform_lib_str = gb_string_appendc(platform_lib_str, "-lc ");
+ lib_str = gb_string_appendc(lib_str, "-lc ");
}
}
- gbString link_command_line = gb_string_make(heap_allocator(), clang_path);
+ gbString link_command_line = gb_string_make(heap_allocator(), "");
defer (gb_string_free(link_command_line));
+ if (is_android) {
+ gbString ndk_bin_directory = gb_string_make_length(temporary_allocator(), ODIN_ANDROID_NDK_TOOLCHAIN.text, ODIN_ANDROID_NDK_TOOLCHAIN.len);
+ link_command_line = gb_string_appendc(link_command_line, ndk_bin_directory);
+ link_command_line = gb_string_appendc(link_command_line, "bin/clang");
+ link_command_line = gb_string_append_fmt(link_command_line, " --target=aarch64-linux-android%d ", ODIN_ANDROID_API_LEVEL);
+ } else {
+ link_command_line = gb_string_appendc(link_command_line, clang_path);
+ }
link_command_line = gb_string_appendc(link_command_line, " -Wno-unused-command-line-argument ");
link_command_line = gb_string_appendc(link_command_line, object_files);
link_command_line = gb_string_append_fmt(link_command_line, " -o \"%.*s\" ", LIT(output_filename));
@@ -705,6 +892,11 @@ gb_internal i32 linker_stage(LinkerData *gen) {
link_command_line = gb_string_append_fmt(link_command_line, " %.*s ", LIT(build_context.extra_linker_flags));
link_command_line = gb_string_append_fmt(link_command_line, " %s ", link_settings);
+
+ if (is_android) {
+ TIME_SECTION("Linking");
+ }
+
if (build_context.linker_choice == Linker_lld) {
link_command_line = gb_string_append_fmt(link_command_line, " -fuse-ld=lld");
result = system_exec_command_line_app("lld-link", link_command_line);
diff --git a/src/llvm-c/Analysis.h b/src/llvm-c/Analysis.h
index 6b93b5c3d..270b145a4 100644
--- a/src/llvm-c/Analysis.h
+++ b/src/llvm-c/Analysis.h
@@ -19,8 +19,8 @@
#ifndef LLVM_C_ANALYSIS_H
#define LLVM_C_ANALYSIS_H
-#include "ExternC.h"
-#include "Types.h"
+#include "llvm-c/ExternC.h"
+#include "llvm-c/Types.h"
LLVM_C_EXTERN_C_BEGIN
diff --git a/src/llvm-c/BitReader.h b/src/llvm-c/BitReader.h
index 725f3fa84..088107468 100644
--- a/src/llvm-c/BitReader.h
+++ b/src/llvm-c/BitReader.h
@@ -19,8 +19,8 @@
#ifndef LLVM_C_BITREADER_H
#define LLVM_C_BITREADER_H
-#include "ExternC.h"
-#include "Types.h"
+#include "llvm-c/ExternC.h"
+#include "llvm-c/Types.h"
LLVM_C_EXTERN_C_BEGIN
diff --git a/src/llvm-c/BitWriter.h b/src/llvm-c/BitWriter.h
index ba4a61afc..ea84b6593 100644
--- a/src/llvm-c/BitWriter.h
+++ b/src/llvm-c/BitWriter.h
@@ -19,8 +19,8 @@
#ifndef LLVM_C_BITWRITER_H
#define LLVM_C_BITWRITER_H
-#include "ExternC.h"
-#include "Types.h"
+#include "llvm-c/ExternC.h"
+#include "llvm-c/Types.h"
LLVM_C_EXTERN_C_BEGIN
diff --git a/src/llvm-c/Comdat.h b/src/llvm-c/Comdat.h
index 30df20799..8002bc058 100644
--- a/src/llvm-c/Comdat.h
+++ b/src/llvm-c/Comdat.h
@@ -14,8 +14,8 @@
#ifndef LLVM_C_COMDAT_H
#define LLVM_C_COMDAT_H
-#include "ExternC.h"
-#include "Types.h"
+#include "llvm-c/ExternC.h"
+#include "llvm-c/Types.h"
LLVM_C_EXTERN_C_BEGIN
diff --git a/src/llvm-c/Config/llvm-config.h b/src/llvm-c/Config/llvm-config.h
index e4edb83c5..8b77597c9 100644
--- a/src/llvm-c/Config/llvm-config.h
+++ b/src/llvm-c/Config/llvm-config.h
@@ -142,16 +142,16 @@
#define LLVM_USE_PERF 0
/* Major version of the LLVM API */
-#define LLVM_VERSION_MAJOR 18
+#define LLVM_VERSION_MAJOR 20
/* Minor version of the LLVM API */
#define LLVM_VERSION_MINOR 1
/* Patch version of the LLVM API */
-#define LLVM_VERSION_PATCH 8
+#define LLVM_VERSION_PATCH 0
/* LLVM version string */
-#define LLVM_VERSION_STRING "18.1.8"
+#define LLVM_VERSION_STRING "20.1.0"
/* Whether LLVM records statistics for use with GetStatistics(),
* PrintStatistics() or PrintStatisticsJSON()
diff --git a/src/llvm-c/Core.h b/src/llvm-c/Core.h
index 25b8248fd..dc8ecf4fb 100644
--- a/src/llvm-c/Core.h
+++ b/src/llvm-c/Core.h
@@ -15,11 +15,11 @@
#ifndef LLVM_C_CORE_H
#define LLVM_C_CORE_H
-#include "Deprecated.h"
-#include "ErrorHandling.h"
-#include "ExternC.h"
+#include "llvm-c/Deprecated.h"
+#include "llvm-c/ErrorHandling.h"
+#include "llvm-c/ExternC.h"
-#include "Types.h"
+#include "llvm-c/Types.h"
LLVM_C_EXTERN_C_BEGIN
@@ -146,27 +146,27 @@ typedef enum {
} LLVMOpcode;
typedef enum {
- LLVMVoidTypeKind, /**< type with no size */
- LLVMHalfTypeKind, /**< 16 bit floating point type */
- LLVMFloatTypeKind, /**< 32 bit floating point type */
- LLVMDoubleTypeKind, /**< 64 bit floating point type */
- LLVMX86_FP80TypeKind, /**< 80 bit floating point type (X87) */
- LLVMFP128TypeKind, /**< 128 bit floating point type (112-bit mantissa)*/
- LLVMPPC_FP128TypeKind, /**< 128 bit floating point type (two 64-bits) */
- LLVMLabelTypeKind, /**< Labels */
- LLVMIntegerTypeKind, /**< Arbitrary bit width integers */
- LLVMFunctionTypeKind, /**< Functions */
- LLVMStructTypeKind, /**< Structures */
- LLVMArrayTypeKind, /**< Arrays */
- LLVMPointerTypeKind, /**< Pointers */
- LLVMVectorTypeKind, /**< Fixed width SIMD vector type */
- LLVMMetadataTypeKind, /**< Metadata */
- LLVMX86_MMXTypeKind, /**< X86 MMX */
- LLVMTokenTypeKind, /**< Tokens */
- LLVMScalableVectorTypeKind, /**< Scalable SIMD vector type */
- LLVMBFloatTypeKind, /**< 16 bit brain floating point type */
- LLVMX86_AMXTypeKind, /**< X86 AMX */
- LLVMTargetExtTypeKind, /**< Target extension type */
+ LLVMVoidTypeKind = 0, /**< type with no size */
+ LLVMHalfTypeKind = 1, /**< 16 bit floating point type */
+ LLVMFloatTypeKind = 2, /**< 32 bit floating point type */
+ LLVMDoubleTypeKind = 3, /**< 64 bit floating point type */
+ LLVMX86_FP80TypeKind = 4, /**< 80 bit floating point type (X87) */
+ LLVMFP128TypeKind = 5, /**< 128 bit floating point type (112-bit mantissa)*/
+ LLVMPPC_FP128TypeKind = 6, /**< 128 bit floating point type (two 64-bits) */
+ LLVMLabelTypeKind = 7, /**< Labels */
+ LLVMIntegerTypeKind = 8, /**< Arbitrary bit width integers */
+ LLVMFunctionTypeKind = 9, /**< Functions */
+ LLVMStructTypeKind = 10, /**< Structures */
+ LLVMArrayTypeKind = 11, /**< Arrays */
+ LLVMPointerTypeKind = 12, /**< Pointers */
+ LLVMVectorTypeKind = 13, /**< Fixed width SIMD vector type */
+ LLVMMetadataTypeKind = 14, /**< Metadata */
+ /* 15 previously used by LLVMX86_MMXTypeKind */
+ LLVMTokenTypeKind = 16, /**< Tokens */
+ LLVMScalableVectorTypeKind = 17, /**< Scalable SIMD vector type */
+ LLVMBFloatTypeKind = 18, /**< 16 bit brain floating point type */
+ LLVMX86_AMXTypeKind = 19, /**< X86 AMX */
+ LLVMTargetExtTypeKind = 20, /**< Target extension type */
} LLVMTypeKind;
typedef enum {
@@ -286,6 +286,7 @@ typedef enum {
LLVMInstructionValueKind,
LLVMPoisonValueValueKind,
LLVMConstantTargetNoneValueKind,
+ LLVMConstantPtrAuthValueKind,
} LLVMValueKind;
typedef enum {
@@ -361,35 +362,42 @@ typedef enum {
} LLVMAtomicOrdering;
typedef enum {
- LLVMAtomicRMWBinOpXchg, /**< Set the new value and return the one old */
- LLVMAtomicRMWBinOpAdd, /**< Add a value and return the old one */
- LLVMAtomicRMWBinOpSub, /**< Subtract a value and return the old one */
- LLVMAtomicRMWBinOpAnd, /**< And a value and return the old one */
- LLVMAtomicRMWBinOpNand, /**< Not-And a value and return the old one */
- LLVMAtomicRMWBinOpOr, /**< OR a value and return the old one */
- LLVMAtomicRMWBinOpXor, /**< Xor a value and return the old one */
- LLVMAtomicRMWBinOpMax, /**< Sets the value if it's greater than the
- original using a signed comparison and return
- the old one */
- LLVMAtomicRMWBinOpMin, /**< Sets the value if it's Smaller than the
- original using a signed comparison and return
- the old one */
- LLVMAtomicRMWBinOpUMax, /**< Sets the value if it's greater than the
- original using an unsigned comparison and return
- the old one */
- LLVMAtomicRMWBinOpUMin, /**< Sets the value if it's greater than the
- original using an unsigned comparison and return
- the old one */
- LLVMAtomicRMWBinOpFAdd, /**< Add a floating point value and return the
- old one */
- LLVMAtomicRMWBinOpFSub, /**< Subtract a floating point value and return the
+ LLVMAtomicRMWBinOpXchg, /**< Set the new value and return the one old */
+ LLVMAtomicRMWBinOpAdd, /**< Add a value and return the old one */
+ LLVMAtomicRMWBinOpSub, /**< Subtract a value and return the old one */
+ LLVMAtomicRMWBinOpAnd, /**< And a value and return the old one */
+ LLVMAtomicRMWBinOpNand, /**< Not-And a value and return the old one */
+ LLVMAtomicRMWBinOpOr, /**< OR a value and return the old one */
+ LLVMAtomicRMWBinOpXor, /**< Xor a value and return the old one */
+ LLVMAtomicRMWBinOpMax, /**< Sets the value if it's greater than the
+ original using a signed comparison and return
+ the old one */
+ LLVMAtomicRMWBinOpMin, /**< Sets the value if it's Smaller than the
+ original using a signed comparison and return
+ the old one */
+ LLVMAtomicRMWBinOpUMax, /**< Sets the value if it's greater than the
+ original using an unsigned comparison and return
+ the old one */
+ LLVMAtomicRMWBinOpUMin, /**< Sets the value if it's greater than the
+ original using an unsigned comparison and return
+ the old one */
+ LLVMAtomicRMWBinOpFAdd, /**< Add a floating point value and return the
old one */
- LLVMAtomicRMWBinOpFMax, /**< Sets the value if it's greater than the
- original using an floating point comparison and
- return the old one */
- LLVMAtomicRMWBinOpFMin, /**< Sets the value if it's smaller than the
- original using an floating point comparison and
- return the old one */
+ LLVMAtomicRMWBinOpFSub, /**< Subtract a floating point value and return the
+ old one */
+ LLVMAtomicRMWBinOpFMax, /**< Sets the value if it's greater than the
+ original using an floating point comparison and
+ return the old one */
+ LLVMAtomicRMWBinOpFMin, /**< Sets the value if it's smaller than the
+ original using an floating point comparison and
+ return the old one */
+ LLVMAtomicRMWBinOpUIncWrap, /**< Increments the value, wrapping back to zero
+ when incremented above input value */
+ LLVMAtomicRMWBinOpUDecWrap, /**< Decrements the value, wrapping back to
+ the input value when decremented below zero */
+ LLVMAtomicRMWBinOpUSubCond, /**<Subtracts the value only if no unsigned
+ overflow */
+ LLVMAtomicRMWBinOpUSubSat, /**<Subtracts the value, clamping to zero */
} LLVMAtomicRMWBinOp;
typedef enum {
@@ -467,6 +475,8 @@ enum {
LLVMAttributeFunctionIndex = -1,
};
+typedef unsigned LLVMAttributeIndex;
+
/**
* Tail call kind for LLVMSetTailCallKind and LLVMGetTailCallKind.
*
@@ -481,8 +491,6 @@ typedef enum {
LLVMTailCallKindNoTail = 3,
} LLVMTailCallKind;
-typedef unsigned LLVMAttributeIndex;
-
enum {
LLVMFastMathAllowReassoc = (1 << 0),
LLVMFastMathNoNaNs = (1 << 1),
@@ -506,6 +514,20 @@ enum {
*/
typedef unsigned LLVMFastMathFlags;
+enum {
+ LLVMGEPFlagInBounds = (1 << 0),
+ LLVMGEPFlagNUSW = (1 << 1),
+ LLVMGEPFlagNUW = (1 << 2),
+};
+
+/**
+ * Flags that constrain the allowed wrap semantics of a getelementptr
+ * instruction.
+ *
+ * See https://llvm.org/docs/LangRef.html#getelementptr-instruction
+ */
+typedef unsigned LLVMGEPNoWrapFlags;
+
/**
* @}
*/
@@ -628,6 +650,11 @@ unsigned LLVMGetMDKindIDInContext(LLVMContextRef C, const char *Name,
unsigned LLVMGetMDKindID(const char *Name, unsigned SLen);
/**
+ * Maps a synchronization scope name to a ID unique within this context.
+ */
+unsigned LLVMGetSyncScopeID(LLVMContextRef C, const char *Name, size_t SLen);
+
+/**
* Return an unique id given the name of a enum attribute,
* or 0 if no attribute by that name exists.
*
@@ -670,6 +697,18 @@ LLVMAttributeRef LLVMCreateTypeAttribute(LLVMContextRef C, unsigned KindID,
LLVMTypeRef LLVMGetTypeAttributeValue(LLVMAttributeRef A);
/**
+ * Create a ConstantRange attribute.
+ *
+ * LowerWords and UpperWords need to be NumBits divided by 64 rounded up
+ * elements long.
+ */
+LLVMAttributeRef LLVMCreateConstantRangeAttribute(LLVMContextRef C,
+ unsigned KindID,
+ unsigned NumBits,
+ const uint64_t LowerWords[],
+ const uint64_t UpperWords[]);
+
+/**
* Create a string attribute.
*/
LLVMAttributeRef LLVMCreateStringAttribute(LLVMContextRef C,
@@ -745,6 +784,24 @@ LLVMModuleRef LLVMCloneModule(LLVMModuleRef M);
void LLVMDisposeModule(LLVMModuleRef M);
/**
+ * Soon to be deprecated.
+ * See https://llvm.org/docs/RemoveDIsDebugInfo.html#c-api-changes
+ *
+ * Returns true if the module is in the new debug info mode which uses
+ * non-instruction debug records instead of debug intrinsics for variable
+ * location tracking.
+ */
+LLVMBool LLVMIsNewDbgInfoFormat(LLVMModuleRef M);
+
+/**
+ * Soon to be deprecated.
+ * See https://llvm.org/docs/RemoveDIsDebugInfo.html#c-api-changes
+ *
+ * Convert module into desired debug info format.
+ */
+void LLVMSetIsNewDbgInfoFormat(LLVMModuleRef M, LLVMBool UseNewFormat);
+
+/**
* Obtain the identifier of a module.
*
* @param M Module to obtain identifier of
@@ -1131,6 +1188,16 @@ LLVMValueRef LLVMAddFunction(LLVMModuleRef M, const char *Name,
LLVMValueRef LLVMGetNamedFunction(LLVMModuleRef M, const char *Name);
/**
+ * Obtain a Function value from a Module by its name.
+ *
+ * The returned value corresponds to a llvm::Function value.
+ *
+ * @see llvm::Module::getFunction()
+ */
+LLVMValueRef LLVMGetNamedFunctionWithLength(LLVMModuleRef M, const char *Name,
+ size_t Length);
+
+/**
* Obtain an iterator to the first Function in a Module.
*
* @see llvm::Module::begin()
@@ -1619,6 +1686,35 @@ LLVMTypeRef LLVMScalableVectorType(LLVMTypeRef ElementType,
unsigned LLVMGetVectorSize(LLVMTypeRef VectorTy);
/**
+ * Get the pointer value for the associated ConstantPtrAuth constant.
+ *
+ * @see llvm::ConstantPtrAuth::getPointer
+ */
+LLVMValueRef LLVMGetConstantPtrAuthPointer(LLVMValueRef PtrAuth);
+
+/**
+ * Get the key value for the associated ConstantPtrAuth constant.
+ *
+ * @see llvm::ConstantPtrAuth::getKey
+ */
+LLVMValueRef LLVMGetConstantPtrAuthKey(LLVMValueRef PtrAuth);
+
+/**
+ * Get the discriminator value for the associated ConstantPtrAuth constant.
+ *
+ * @see llvm::ConstantPtrAuth::getDiscriminator
+ */
+LLVMValueRef LLVMGetConstantPtrAuthDiscriminator(LLVMValueRef PtrAuth);
+
+/**
+ * Get the address discriminator value for the associated ConstantPtrAuth
+ * constant.
+ *
+ * @see llvm::ConstantPtrAuth::getAddrDiscriminator
+ */
+LLVMValueRef LLVMGetConstantPtrAuthAddrDiscriminator(LLVMValueRef PtrAuth);
+
+/**
* @}
*/
@@ -1639,11 +1735,6 @@ LLVMTypeRef LLVMVoidTypeInContext(LLVMContextRef C);
LLVMTypeRef LLVMLabelTypeInContext(LLVMContextRef C);
/**
- * Create a X86 MMX type in a context.
- */
-LLVMTypeRef LLVMX86MMXTypeInContext(LLVMContextRef C);
-
-/**
* Create a X86 AMX type in a context.
*/
LLVMTypeRef LLVMX86AMXTypeInContext(LLVMContextRef C);
@@ -1664,7 +1755,6 @@ LLVMTypeRef LLVMMetadataTypeInContext(LLVMContextRef C);
*/
LLVMTypeRef LLVMVoidType(void);
LLVMTypeRef LLVMLabelType(void);
-LLVMTypeRef LLVMX86MMXType(void);
LLVMTypeRef LLVMX86AMXType(void);
/**
@@ -1677,6 +1767,42 @@ LLVMTypeRef LLVMTargetExtTypeInContext(LLVMContextRef C, const char *Name,
unsigned IntParamCount);
/**
+ * Obtain the name for this target extension type.
+ *
+ * @see llvm::TargetExtType::getName()
+ */
+const char *LLVMGetTargetExtTypeName(LLVMTypeRef TargetExtTy);
+
+/**
+ * Obtain the number of type parameters for this target extension type.
+ *
+ * @see llvm::TargetExtType::getNumTypeParameters()
+ */
+unsigned LLVMGetTargetExtTypeNumTypeParams(LLVMTypeRef TargetExtTy);
+
+/**
+ * Get the type parameter at the given index for the target extension type.
+ *
+ * @see llvm::TargetExtType::getTypeParameter()
+ */
+LLVMTypeRef LLVMGetTargetExtTypeTypeParam(LLVMTypeRef TargetExtTy,
+ unsigned Idx);
+
+/**
+ * Obtain the number of int parameters for this target extension type.
+ *
+ * @see llvm::TargetExtType::getNumIntParameters()
+ */
+unsigned LLVMGetTargetExtTypeNumIntParams(LLVMTypeRef TargetExtTy);
+
+/**
+ * Get the int parameter at the given index for the target extension type.
+ *
+ * @see llvm::TargetExtType::getIntParameter()
+ */
+unsigned LLVMGetTargetExtTypeIntParam(LLVMTypeRef TargetExtTy, unsigned Idx);
+
+/**
* @}
*/
@@ -1705,6 +1831,10 @@ LLVMTypeRef LLVMTargetExtTypeInContext(LLVMContextRef C, const char *Name,
* @{
*/
+// Currently, clang-format tries to format the LLVM_FOR_EACH_VALUE_SUBCLASS
+// macro in a progressively-indented fashion, which is not desired
+// clang-format off
+
#define LLVM_FOR_EACH_VALUE_SUBCLASS(macro) \
macro(Argument) \
macro(BasicBlock) \
@@ -1724,6 +1854,7 @@ LLVMTypeRef LLVMTargetExtTypeInContext(LLVMContextRef C, const char *Name,
macro(ConstantStruct) \
macro(ConstantTokenNone) \
macro(ConstantVector) \
+ macro(ConstantPtrAuth) \
macro(GlobalValue) \
macro(GlobalAlias) \
macro(GlobalObject) \
@@ -1795,6 +1926,8 @@ LLVMTypeRef LLVMTargetExtTypeInContext(LLVMContextRef C, const char *Name,
macro(AtomicRMWInst) \
macro(FenceInst)
+// clang-format on
+
/**
* @defgroup LLVMCCoreValueGeneral General APIs
*
@@ -1849,6 +1982,21 @@ void LLVMDumpValue(LLVMValueRef Val);
char *LLVMPrintValueToString(LLVMValueRef Val);
/**
+ * Obtain the context to which this value is associated.
+ *
+ * @see llvm::Value::getContext()
+ */
+LLVMContextRef LLVMGetValueContext(LLVMValueRef Val);
+
+/**
+ * Return a string representation of the DbgRecord. Use
+ * LLVMDisposeMessage to free the string.
+ *
+ * @see llvm::DbgRecord::print()
+ */
+char *LLVMPrintDbgRecordToString(LLVMDbgRecordRef Record);
+
+/**
* Replace all uses of a value with another one.
*
* @see llvm::Value::replaceAllUsesWith()
@@ -2165,12 +2313,23 @@ double LLVMConstRealGetDouble(LLVMValueRef ConstantVal, LLVMBool *losesInfo);
/**
* Create a ConstantDataSequential and initialize it with a string.
*
+ * @deprecated LLVMConstStringInContext is deprecated in favor of the API
+ * accurate LLVMConstStringInContext2
* @see llvm::ConstantDataArray::getString()
*/
LLVMValueRef LLVMConstStringInContext(LLVMContextRef C, const char *Str,
unsigned Length, LLVMBool DontNullTerminate);
/**
+ * Create a ConstantDataSequential and initialize it with a string.
+ *
+ * @see llvm::ConstantDataArray::getString()
+ */
+LLVMValueRef LLVMConstStringInContext2(LLVMContextRef C, const char *Str,
+ size_t Length,
+ LLVMBool DontNullTerminate);
+
+/**
* Create a ConstantDataSequential with string content in the global context.
*
* This is the same as LLVMConstStringInContext except it operates on the
@@ -2270,6 +2429,14 @@ LLVM_ATTRIBUTE_C_DEPRECATED(
LLVMValueRef LLVMConstVector(LLVMValueRef *ScalarConstantVals, unsigned Size);
/**
+ * Create a ConstantPtrAuth constant with the given values.
+ *
+ * @see llvm::ConstantPtrAuth::get()
+ */
+LLVMValueRef LLVMConstantPtrAuth(LLVMValueRef Ptr, LLVMValueRef Key,
+ LLVMValueRef Disc, LLVMValueRef AddrDisc);
+
+/**
* @}
*/
@@ -2287,7 +2454,9 @@ LLVMValueRef LLVMAlignOf(LLVMTypeRef Ty);
LLVMValueRef LLVMSizeOf(LLVMTypeRef Ty);
LLVMValueRef LLVMConstNeg(LLVMValueRef ConstantVal);
LLVMValueRef LLVMConstNSWNeg(LLVMValueRef ConstantVal);
-LLVMValueRef LLVMConstNUWNeg(LLVMValueRef ConstantVal);
+LLVM_ATTRIBUTE_C_DEPRECATED(
+ LLVMValueRef LLVMConstNUWNeg(LLVMValueRef ConstantVal),
+ "Use LLVMConstNull instead.");
LLVMValueRef LLVMConstNot(LLVMValueRef ConstantVal);
LLVMValueRef LLVMConstAdd(LLVMValueRef LHSConstant, LLVMValueRef RHSConstant);
LLVMValueRef LLVMConstNSWAdd(LLVMValueRef LHSConstant, LLVMValueRef RHSConstant);
@@ -2299,16 +2468,22 @@ LLVMValueRef LLVMConstMul(LLVMValueRef LHSConstant, LLVMValueRef RHSConstant);
LLVMValueRef LLVMConstNSWMul(LLVMValueRef LHSConstant, LLVMValueRef RHSConstant);
LLVMValueRef LLVMConstNUWMul(LLVMValueRef LHSConstant, LLVMValueRef RHSConstant);
LLVMValueRef LLVMConstXor(LLVMValueRef LHSConstant, LLVMValueRef RHSConstant);
-LLVMValueRef LLVMConstICmp(LLVMIntPredicate Predicate,
- LLVMValueRef LHSConstant, LLVMValueRef RHSConstant);
-LLVMValueRef LLVMConstFCmp(LLVMRealPredicate Predicate,
- LLVMValueRef LHSConstant, LLVMValueRef RHSConstant);
-LLVMValueRef LLVMConstShl(LLVMValueRef LHSConstant, LLVMValueRef RHSConstant);
LLVMValueRef LLVMConstGEP2(LLVMTypeRef Ty, LLVMValueRef ConstantVal,
LLVMValueRef *ConstantIndices, unsigned NumIndices);
LLVMValueRef LLVMConstInBoundsGEP2(LLVMTypeRef Ty, LLVMValueRef ConstantVal,
LLVMValueRef *ConstantIndices,
unsigned NumIndices);
+/**
+ * Creates a constant GetElementPtr expression. Similar to LLVMConstGEP2, but
+ * allows specifying the no-wrap flags.
+ *
+ * @see llvm::ConstantExpr::getGetElementPtr()
+ */
+LLVMValueRef LLVMConstGEPWithNoWrapFlags(LLVMTypeRef Ty,
+ LLVMValueRef ConstantVal,
+ LLVMValueRef *ConstantIndices,
+ unsigned NumIndices,
+ LLVMGEPNoWrapFlags NoWrapFlags);
LLVMValueRef LLVMConstTrunc(LLVMValueRef ConstantVal, LLVMTypeRef ToType);
LLVMValueRef LLVMConstPtrToInt(LLVMValueRef ConstantVal, LLVMTypeRef ToType);
LLVMValueRef LLVMConstIntToPtr(LLVMValueRef ConstantVal, LLVMTypeRef ToType);
@@ -2328,6 +2503,16 @@ LLVMValueRef LLVMConstShuffleVector(LLVMValueRef VectorAConstant,
LLVMValueRef MaskConstant);
LLVMValueRef LLVMBlockAddress(LLVMValueRef F, LLVMBasicBlockRef BB);
+/**
+ * Gets the function associated with a given BlockAddress constant value.
+ */
+LLVMValueRef LLVMGetBlockAddressFunction(LLVMValueRef BlockAddr);
+
+/**
+ * Gets the basic block associated with a given BlockAddress constant value.
+ */
+LLVMBasicBlockRef LLVMGetBlockAddressBasicBlock(LLVMValueRef BlockAddr);
+
/** Deprecated: Use LLVMGetInlineAsm instead. */
LLVMValueRef LLVMConstInlineAsm(LLVMTypeRef Ty,
const char *AsmString, const char *Constraints,
@@ -2473,6 +2658,8 @@ LLVMValueRef LLVMAddGlobalInAddressSpace(LLVMModuleRef M, LLVMTypeRef Ty,
const char *Name,
unsigned AddressSpace);
LLVMValueRef LLVMGetNamedGlobal(LLVMModuleRef M, const char *Name);
+LLVMValueRef LLVMGetNamedGlobalWithLength(LLVMModuleRef M, const char *Name,
+ size_t Length);
LLVMValueRef LLVMGetFirstGlobal(LLVMModuleRef M);
LLVMValueRef LLVMGetLastGlobal(LLVMModuleRef M);
LLVMValueRef LLVMGetNextGlobal(LLVMValueRef GlobalVar);
@@ -2608,7 +2795,7 @@ void LLVMSetPersonalityFn(LLVMValueRef Fn, LLVMValueRef PersonalityFn);
/**
* Obtain the intrinsic ID number which matches the given function name.
*
- * @see llvm::Function::lookupIntrinsicID()
+ * @see llvm::Intrinsic::lookupIntrinsicID()
*/
unsigned LLVMLookupIntrinsicID(const char *Name, size_t NameLen);
@@ -2620,10 +2807,10 @@ unsigned LLVMLookupIntrinsicID(const char *Name, size_t NameLen);
unsigned LLVMGetIntrinsicID(LLVMValueRef Fn);
/**
- * Create or insert the declaration of an intrinsic. For overloaded intrinsics,
+ * Get or insert the declaration of an intrinsic. For overloaded intrinsics,
* parameter types must be provided to uniquely identify an overload.
*
- * @see llvm::Intrinsic::getDeclaration()
+ * @see llvm::Intrinsic::getOrInsertDeclaration()
*/
LLVMValueRef LLVMGetIntrinsicDeclaration(LLVMModuleRef Mod,
unsigned ID,
@@ -2647,10 +2834,8 @@ LLVMTypeRef LLVMIntrinsicGetType(LLVMContextRef Ctx, unsigned ID,
const char *LLVMIntrinsicGetName(unsigned ID, size_t *NameLength);
/** Deprecated: Use LLVMIntrinsicCopyOverloadedName2 instead. */
-const char *LLVMIntrinsicCopyOverloadedName(unsigned ID,
- LLVMTypeRef *ParamTypes,
- size_t ParamCount,
- size_t *NameLength);
+char *LLVMIntrinsicCopyOverloadedName(unsigned ID, LLVMTypeRef *ParamTypes,
+ size_t ParamCount, size_t *NameLength);
/**
* Copies the name of an overloaded intrinsic identified by a given list of
@@ -2663,10 +2848,9 @@ const char *LLVMIntrinsicCopyOverloadedName(unsigned ID,
*
* @see llvm::Intrinsic::getName()
*/
-const char *LLVMIntrinsicCopyOverloadedName2(LLVMModuleRef Mod, unsigned ID,
- LLVMTypeRef *ParamTypes,
- size_t ParamCount,
- size_t *NameLength);
+char *LLVMIntrinsicCopyOverloadedName2(LLVMModuleRef Mod, unsigned ID,
+ LLVMTypeRef *ParamTypes,
+ size_t ParamCount, size_t *NameLength);
/**
* Obtain if the intrinsic identified by the given ID is overloaded.
@@ -2710,6 +2894,44 @@ const char *LLVMGetGC(LLVMValueRef Fn);
void LLVMSetGC(LLVMValueRef Fn, const char *Name);
/**
+ * Gets the prefix data associated with a function. Only valid on functions, and
+ * only if LLVMHasPrefixData returns true.
+ * See https://llvm.org/docs/LangRef.html#prefix-data
+ */
+LLVMValueRef LLVMGetPrefixData(LLVMValueRef Fn);
+
+/**
+ * Check if a given function has prefix data. Only valid on functions.
+ * See https://llvm.org/docs/LangRef.html#prefix-data
+ */
+LLVMBool LLVMHasPrefixData(LLVMValueRef Fn);
+
+/**
+ * Sets the prefix data for the function. Only valid on functions.
+ * See https://llvm.org/docs/LangRef.html#prefix-data
+ */
+void LLVMSetPrefixData(LLVMValueRef Fn, LLVMValueRef prefixData);
+
+/**
+ * Gets the prologue data associated with a function. Only valid on functions,
+ * and only if LLVMHasPrologueData returns true.
+ * See https://llvm.org/docs/LangRef.html#prologue-data
+ */
+LLVMValueRef LLVMGetPrologueData(LLVMValueRef Fn);
+
+/**
+ * Check if a given function has prologue data. Only valid on functions.
+ * See https://llvm.org/docs/LangRef.html#prologue-data
+ */
+LLVMBool LLVMHasPrologueData(LLVMValueRef Fn);
+
+/**
+ * Sets the prologue data for the function. Only valid on functions.
+ * See https://llvm.org/docs/LangRef.html#prologue-data
+ */
+void LLVMSetPrologueData(LLVMValueRef Fn, LLVMValueRef prologueData);
+
+/**
* Add an attribute to a function.
*
* @see llvm::Function::addAttribute()
@@ -3426,8 +3648,7 @@ LLVMOpcode LLVMGetInstructionOpcode(LLVMValueRef Inst);
/**
* Obtain the predicate of an instruction.
*
- * This is only valid for instructions that correspond to llvm::ICmpInst
- * or llvm::ConstantExpr whose opcode is llvm::Instruction::ICmp.
+ * This is only valid for instructions that correspond to llvm::ICmpInst.
*
* @see llvm::ICmpInst::getPredicate()
*/
@@ -3436,8 +3657,7 @@ LLVMIntPredicate LLVMGetICmpPredicate(LLVMValueRef Inst);
/**
* Obtain the float predicate of an instruction.
*
- * This is only valid for instructions that correspond to llvm::FCmpInst
- * or llvm::ConstantExpr whose opcode is llvm::Instruction::FCmp.
+ * This is only valid for instructions that correspond to llvm::FCmpInst.
*
* @see llvm::FCmpInst::getPredicate()
*/
@@ -3463,6 +3683,41 @@ LLVMValueRef LLVMInstructionClone(LLVMValueRef Inst);
LLVMValueRef LLVMIsATerminatorInst(LLVMValueRef Inst);
/**
+ * Obtain the first debug record attached to an instruction.
+ *
+ * Use LLVMGetNextDbgRecord() and LLVMGetPreviousDbgRecord() to traverse the
+ * sequence of DbgRecords.
+ *
+ * Return the first DbgRecord attached to Inst or NULL if there are none.
+ *
+ * @see llvm::Instruction::getDbgRecordRange()
+ */
+LLVMDbgRecordRef LLVMGetFirstDbgRecord(LLVMValueRef Inst);
+
+/**
+ * Obtain the last debug record attached to an instruction.
+ *
+ * Return the last DbgRecord attached to Inst or NULL if there are none.
+ *
+ * @see llvm::Instruction::getDbgRecordRange()
+ */
+LLVMDbgRecordRef LLVMGetLastDbgRecord(LLVMValueRef Inst);
+
+/**
+ * Obtain the next DbgRecord in the sequence or NULL if there are no more.
+ *
+ * @see llvm::Instruction::getDbgRecordRange()
+ */
+LLVMDbgRecordRef LLVMGetNextDbgRecord(LLVMDbgRecordRef DbgRecord);
+
+/**
+ * Obtain the previous DbgRecord in the sequence or NULL if there are no more.
+ *
+ * @see llvm::Instruction::getDbgRecordRange()
+ */
+LLVMDbgRecordRef LLVMGetPreviousDbgRecord(LLVMDbgRecordRef DbgRecord);
+
+/**
* @defgroup LLVMCCoreValueInstructionCall Call Sites and Invocations
*
* Functions in this group apply to instructions that refer to call
@@ -3635,6 +3890,28 @@ void LLVMSetNormalDest(LLVMValueRef InvokeInst, LLVMBasicBlockRef B);
void LLVMSetUnwindDest(LLVMValueRef InvokeInst, LLVMBasicBlockRef B);
/**
+ * Get the default destination of a CallBr instruction.
+ *
+ * @see llvm::CallBrInst::getDefaultDest()
+ */
+LLVMBasicBlockRef LLVMGetCallBrDefaultDest(LLVMValueRef CallBr);
+
+/**
+ * Get the number of indirect destinations of a CallBr instruction.
+ *
+ * @see llvm::CallBrInst::getNumIndirectDests()
+
+ */
+unsigned LLVMGetCallBrNumIndirectDests(LLVMValueRef CallBr);
+
+/**
+ * Get the indirect destination of a CallBr instruction at the given index.
+ *
+ * @see llvm::CallBrInst::getIndirectDest()
+ */
+LLVMBasicBlockRef LLVMGetCallBrIndirectDest(LLVMValueRef CallBr, unsigned Idx);
+
+/**
* @}
*/
@@ -3751,6 +4028,20 @@ void LLVMSetIsInBounds(LLVMValueRef GEP, LLVMBool InBounds);
LLVMTypeRef LLVMGetGEPSourceElementType(LLVMValueRef GEP);
/**
+ * Get the no-wrap related flags for the given GEP instruction.
+ *
+ * @see llvm::GetElementPtrInst::getNoWrapFlags
+ */
+LLVMGEPNoWrapFlags LLVMGEPGetNoWrapFlags(LLVMValueRef GEP);
+
+/**
+ * Set the no-wrap related flags for the given GEP instruction.
+ *
+ * @see llvm::GetElementPtrInst::setNoWrapFlags
+ */
+void LLVMGEPSetNoWrapFlags(LLVMValueRef GEP, LLVMGEPNoWrapFlags NoWrapFlags);
+
+/**
* @}
*/
@@ -3832,9 +4123,28 @@ const unsigned *LLVMGetIndices(LLVMValueRef Inst);
LLVMBuilderRef LLVMCreateBuilderInContext(LLVMContextRef C);
LLVMBuilderRef LLVMCreateBuilder(void);
+/**
+ * Set the builder position before Instr but after any attached debug records,
+ * or if Instr is null set the position to the end of Block.
+ */
void LLVMPositionBuilder(LLVMBuilderRef Builder, LLVMBasicBlockRef Block,
LLVMValueRef Instr);
+/**
+ * Set the builder position before Instr and any attached debug records,
+ * or if Instr is null set the position to the end of Block.
+ */
+void LLVMPositionBuilderBeforeDbgRecords(LLVMBuilderRef Builder,
+ LLVMBasicBlockRef Block,
+ LLVMValueRef Inst);
+/**
+ * Set the builder position before Instr but after any attached debug records.
+ */
void LLVMPositionBuilderBefore(LLVMBuilderRef Builder, LLVMValueRef Instr);
+/**
+ * Set the builder position before Instr and any attached debug records.
+ */
+void LLVMPositionBuilderBeforeInstrAndDbgRecords(LLVMBuilderRef Builder,
+ LLVMValueRef Instr);
void LLVMPositionBuilderAtEnd(LLVMBuilderRef Builder, LLVMBasicBlockRef Block);
LLVMBasicBlockRef LLVMGetInsertBlock(LLVMBuilderRef Builder);
void LLVMClearInsertionPosition(LLVMBuilderRef Builder);
@@ -3898,6 +4208,13 @@ void LLVMBuilderSetDefaultFPMathTag(LLVMBuilderRef Builder,
LLVMMetadataRef FPMathTag);
/**
+ * Obtain the context to which this builder is associated.
+ *
+ * @see llvm::IRBuilder::getContext()
+ */
+LLVMContextRef LLVMGetBuilderContext(LLVMBuilderRef Builder);
+
+/**
* Deprecated: Passing the NULL location will crash.
* Use LLVMGetCurrentDebugLocation2 instead.
*/
@@ -3920,6 +4237,12 @@ LLVMValueRef LLVMBuildSwitch(LLVMBuilderRef, LLVMValueRef V,
LLVMBasicBlockRef Else, unsigned NumCases);
LLVMValueRef LLVMBuildIndirectBr(LLVMBuilderRef B, LLVMValueRef Addr,
unsigned NumDests);
+LLVMValueRef LLVMBuildCallBr(LLVMBuilderRef B, LLVMTypeRef Ty, LLVMValueRef Fn,
+ LLVMBasicBlockRef DefaultDest,
+ LLVMBasicBlockRef *IndirectDests,
+ unsigned NumIndirectDests, LLVMValueRef *Args,
+ unsigned NumArgs, LLVMOperandBundleRef *Bundles,
+ unsigned NumBundles, const char *Name);
LLVMValueRef LLVMBuildInvoke2(LLVMBuilderRef, LLVMTypeRef Ty, LLVMValueRef Fn,
LLVMValueRef *Args, unsigned NumArgs,
LLVMBasicBlockRef Then, LLVMBasicBlockRef Catch,
@@ -4075,8 +4398,10 @@ LLVMValueRef LLVMBuildBinOp(LLVMBuilderRef B, LLVMOpcode Op,
LLVMValueRef LLVMBuildNeg(LLVMBuilderRef, LLVMValueRef V, const char *Name);
LLVMValueRef LLVMBuildNSWNeg(LLVMBuilderRef B, LLVMValueRef V,
const char *Name);
-LLVMValueRef LLVMBuildNUWNeg(LLVMBuilderRef B, LLVMValueRef V,
- const char *Name);
+LLVM_ATTRIBUTE_C_DEPRECATED(LLVMValueRef LLVMBuildNUWNeg(LLVMBuilderRef B,
+ LLVMValueRef V,
+ const char *Name),
+ "Use LLVMBuildNeg + LLVMSetNUW instead.");
LLVMValueRef LLVMBuildFNeg(LLVMBuilderRef, LLVMValueRef V, const char *Name);
LLVMValueRef LLVMBuildNot(LLVMBuilderRef, LLVMValueRef V, const char *Name);
@@ -4182,11 +4507,25 @@ LLVMValueRef LLVMBuildGEP2(LLVMBuilderRef B, LLVMTypeRef Ty,
LLVMValueRef LLVMBuildInBoundsGEP2(LLVMBuilderRef B, LLVMTypeRef Ty,
LLVMValueRef Pointer, LLVMValueRef *Indices,
unsigned NumIndices, const char *Name);
+/**
+ * Creates a GetElementPtr instruction. Similar to LLVMBuildGEP2, but allows
+ * specifying the no-wrap flags.
+ *
+ * @see llvm::IRBuilder::CreateGEP()
+ */
+LLVMValueRef LLVMBuildGEPWithNoWrapFlags(LLVMBuilderRef B, LLVMTypeRef Ty,
+ LLVMValueRef Pointer,
+ LLVMValueRef *Indices,
+ unsigned NumIndices, const char *Name,
+ LLVMGEPNoWrapFlags NoWrapFlags);
LLVMValueRef LLVMBuildStructGEP2(LLVMBuilderRef B, LLVMTypeRef Ty,
LLVMValueRef Pointer, unsigned Idx,
const char *Name);
LLVMValueRef LLVMBuildGlobalString(LLVMBuilderRef B, const char *Str,
const char *Name);
+/**
+ * Deprecated: Use LLVMBuildGlobalString instead, which has identical behavior.
+ */
LLVMValueRef LLVMBuildGlobalStringPtr(LLVMBuilderRef B, const char *Str,
const char *Name);
LLVMBool LLVMGetVolatile(LLVMValueRef MemoryAccessInst);
@@ -4296,15 +4635,28 @@ LLVMValueRef LLVMBuildPtrDiff2(LLVMBuilderRef, LLVMTypeRef ElemTy,
const char *Name);
LLVMValueRef LLVMBuildFence(LLVMBuilderRef B, LLVMAtomicOrdering ordering,
LLVMBool singleThread, const char *Name);
+LLVMValueRef LLVMBuildFenceSyncScope(LLVMBuilderRef B,
+ LLVMAtomicOrdering ordering, unsigned SSID,
+ const char *Name);
LLVMValueRef LLVMBuildAtomicRMW(LLVMBuilderRef B, LLVMAtomicRMWBinOp op,
LLVMValueRef PTR, LLVMValueRef Val,
LLVMAtomicOrdering ordering,
LLVMBool singleThread);
+LLVMValueRef LLVMBuildAtomicRMWSyncScope(LLVMBuilderRef B,
+ LLVMAtomicRMWBinOp op,
+ LLVMValueRef PTR, LLVMValueRef Val,
+ LLVMAtomicOrdering ordering,
+ unsigned SSID);
LLVMValueRef LLVMBuildAtomicCmpXchg(LLVMBuilderRef B, LLVMValueRef Ptr,
LLVMValueRef Cmp, LLVMValueRef New,
LLVMAtomicOrdering SuccessOrdering,
LLVMAtomicOrdering FailureOrdering,
LLVMBool SingleThread);
+LLVMValueRef LLVMBuildAtomicCmpXchgSyncScope(LLVMBuilderRef B, LLVMValueRef Ptr,
+ LLVMValueRef Cmp, LLVMValueRef New,
+ LLVMAtomicOrdering SuccessOrdering,
+ LLVMAtomicOrdering FailureOrdering,
+ unsigned SSID);
/**
* Get the number of elements in the mask of a ShuffleVector instruction.
@@ -4329,6 +4681,22 @@ int LLVMGetMaskValue(LLVMValueRef ShuffleVectorInst, unsigned Elt);
LLVMBool LLVMIsAtomicSingleThread(LLVMValueRef AtomicInst);
void LLVMSetAtomicSingleThread(LLVMValueRef AtomicInst, LLVMBool SingleThread);
+/**
+ * Returns whether an instruction is an atomic instruction, e.g., atomicrmw,
+ * cmpxchg, fence, or loads and stores with atomic ordering.
+ */
+LLVMBool LLVMIsAtomic(LLVMValueRef Inst);
+
+/**
+ * Returns the synchronization scope ID of an atomic instruction.
+ */
+unsigned LLVMGetAtomicSyncScopeID(LLVMValueRef AtomicInst);
+
+/**
+ * Sets the synchronization scope ID of an atomic instruction.
+ */
+void LLVMSetAtomicSyncScopeID(LLVMValueRef AtomicInst, unsigned SSID);
+
LLVMAtomicOrdering LLVMGetCmpXchgSuccessOrdering(LLVMValueRef CmpXchgInst);
void LLVMSetCmpXchgSuccessOrdering(LLVMValueRef CmpXchgInst,
LLVMAtomicOrdering Ordering);
diff --git a/src/llvm-c/DebugInfo.h b/src/llvm-c/DebugInfo.h
index 93bd9e2ad..ac7ee5a7c 100644
--- a/src/llvm-c/DebugInfo.h
+++ b/src/llvm-c/DebugInfo.h
@@ -16,8 +16,8 @@
#ifndef LLVM_C_DEBUGINFO_H
#define LLVM_C_DEBUGINFO_H
-#include "ExternC.h"
-#include "Types.h"
+#include "llvm-c/ExternC.h"
+#include "llvm-c/Types.h"
LLVM_C_EXTERN_C_BEGIN
@@ -125,7 +125,21 @@ typedef enum {
LLVMDWARFSourceLanguageFortran18,
LLVMDWARFSourceLanguageAda2005,
LLVMDWARFSourceLanguageAda2012,
+ LLVMDWARFSourceLanguageHIP,
+ LLVMDWARFSourceLanguageAssembly,
+ LLVMDWARFSourceLanguageC_sharp,
LLVMDWARFSourceLanguageMojo,
+ LLVMDWARFSourceLanguageGLSL,
+ LLVMDWARFSourceLanguageGLSL_ES,
+ LLVMDWARFSourceLanguageHLSL,
+ LLVMDWARFSourceLanguageOpenCL_CPP,
+ LLVMDWARFSourceLanguageCPP_for_OpenCL,
+ LLVMDWARFSourceLanguageSYCL,
+ LLVMDWARFSourceLanguageRuby,
+ LLVMDWARFSourceLanguageMove,
+ LLVMDWARFSourceLanguageHylo,
+ LLVMDWARFSourceLanguageMetal,
+
// Vendor extensions:
LLVMDWARFSourceLanguageMips_Assembler,
LLVMDWARFSourceLanguageGOOGLE_RenderScript,
@@ -856,13 +870,16 @@ LLVMDIBuilderCreateObjCProperty(LLVMDIBuilderRef Builder,
LLVMMetadataRef Ty);
/**
- * Create a uniqued DIType* clone with FlagObjectPointer and FlagArtificial set.
+ * Create a uniqued DIType* clone with FlagObjectPointer. If \c Implicit
+ * is true, then also set FlagArtificial.
* \param Builder The DIBuilder.
* \param Type The underlying type to which this pointer points.
+ * \param Implicit Indicates whether this pointer was implicitly generated
+ * (i.e., not spelled out in source).
*/
-LLVMMetadataRef
-LLVMDIBuilderCreateObjectPointerType(LLVMDIBuilderRef Builder,
- LLVMMetadataRef Type);
+LLVMMetadataRef LLVMDIBuilderCreateObjectPointerType(LLVMDIBuilderRef Builder,
+ LLVMMetadataRef Type,
+ LLVMBool Implicit);
/**
* Create debugging information entry for a qualified
@@ -1249,66 +1266,84 @@ LLVMMetadataRef LLVMDIBuilderCreateTempGlobalVariableFwdDecl(
LLVMMetadataRef Decl, uint32_t AlignInBits);
/**
- * Insert a new llvm.dbg.declare intrinsic call before the given instruction.
+ * Only use in "new debug format" (LLVMIsNewDbgInfoFormat() is true).
+ * See https://llvm.org/docs/RemoveDIsDebugInfo.html#c-api-changes
+ *
+ * The debug format can be switched later after inserting the records using
+ * LLVMSetIsNewDbgInfoFormat, if needed for legacy or transitionary reasons.
+ *
+ * Insert a Declare DbgRecord before the given instruction.
* \param Builder The DIBuilder.
* \param Storage The storage of the variable to declare.
* \param VarInfo The variable's debug info descriptor.
* \param Expr A complex location expression for the variable.
* \param DebugLoc Debug info location.
- * \param Instr Instruction acting as a location for the new intrinsic.
+ * \param Instr Instruction acting as a location for the new record.
*/
-LLVMValueRef LLVMDIBuilderInsertDeclareBefore(
- LLVMDIBuilderRef Builder, LLVMValueRef Storage, LLVMMetadataRef VarInfo,
- LLVMMetadataRef Expr, LLVMMetadataRef DebugLoc, LLVMValueRef Instr);
+LLVMDbgRecordRef LLVMDIBuilderInsertDeclareRecordBefore(
+ LLVMDIBuilderRef Builder, LLVMValueRef Storage, LLVMMetadataRef VarInfo,
+ LLVMMetadataRef Expr, LLVMMetadataRef DebugLoc, LLVMValueRef Instr);
/**
- * Insert a new llvm.dbg.declare intrinsic call at the end of the given basic
- * block. If the basic block has a terminator instruction, the intrinsic is
- * inserted before that terminator instruction.
+ * Only use in "new debug format" (LLVMIsNewDbgInfoFormat() is true).
+ * See https://llvm.org/docs/RemoveDIsDebugInfo.html#c-api-changes
+ *
+ * The debug format can be switched later after inserting the records using
+ * LLVMSetIsNewDbgInfoFormat, if needed for legacy or transitionary reasons.
+ *
+ * Insert a Declare DbgRecord at the end of the given basic block. If the basic
+ * block has a terminator instruction, the record is inserted before that
+ * terminator instruction.
* \param Builder The DIBuilder.
* \param Storage The storage of the variable to declare.
* \param VarInfo The variable's debug info descriptor.
* \param Expr A complex location expression for the variable.
* \param DebugLoc Debug info location.
- * \param Block Basic block acting as a location for the new intrinsic.
+ * \param Block Basic block acting as a location for the new record.
*/
-LLVMValueRef LLVMDIBuilderInsertDeclareAtEnd(
+LLVMDbgRecordRef LLVMDIBuilderInsertDeclareRecordAtEnd(
LLVMDIBuilderRef Builder, LLVMValueRef Storage, LLVMMetadataRef VarInfo,
LLVMMetadataRef Expr, LLVMMetadataRef DebugLoc, LLVMBasicBlockRef Block);
/**
- * Insert a new llvm.dbg.value intrinsic call before the given instruction.
+ * Only use in "new debug format" (LLVMIsNewDbgInfoFormat() is true).
+ * See https://llvm.org/docs/RemoveDIsDebugInfo.html#c-api-changes
+ *
+ * The debug format can be switched later after inserting the records using
+ * LLVMSetIsNewDbgInfoFormat, if needed for legacy or transitionary reasons.
+ *
+ * Insert a new debug record before the given instruction.
* \param Builder The DIBuilder.
* \param Val The value of the variable.
* \param VarInfo The variable's debug info descriptor.
* \param Expr A complex location expression for the variable.
* \param DebugLoc Debug info location.
- * \param Instr Instruction acting as a location for the new intrinsic.
+ * \param Instr Instruction acting as a location for the new record.
*/
-LLVMValueRef LLVMDIBuilderInsertDbgValueBefore(LLVMDIBuilderRef Builder,
- LLVMValueRef Val,
- LLVMMetadataRef VarInfo,
- LLVMMetadataRef Expr,
- LLVMMetadataRef DebugLoc,
- LLVMValueRef Instr);
+LLVMDbgRecordRef LLVMDIBuilderInsertDbgValueRecordBefore(
+ LLVMDIBuilderRef Builder, LLVMValueRef Val, LLVMMetadataRef VarInfo,
+ LLVMMetadataRef Expr, LLVMMetadataRef DebugLoc, LLVMValueRef Instr);
/**
- * Insert a new llvm.dbg.value intrinsic call at the end of the given basic
- * block. If the basic block has a terminator instruction, the intrinsic is
- * inserted before that terminator instruction.
+ * Only use in "new debug format" (LLVMIsNewDbgInfoFormat() is true).
+ * See https://llvm.org/docs/RemoveDIsDebugInfo.html#c-api-changes
+ *
+ * The debug format can be switched later after inserting the records using
+ * LLVMSetIsNewDbgInfoFormat, if needed for legacy or transitionary reasons.
+ *
+ * Insert a new debug record at the end of the given basic block. If the
+ * basic block has a terminator instruction, the record is inserted before
+ * that terminator instruction.
* \param Builder The DIBuilder.
* \param Val The value of the variable.
* \param VarInfo The variable's debug info descriptor.
* \param Expr A complex location expression for the variable.
* \param DebugLoc Debug info location.
- * \param Block Basic block acting as a location for the new intrinsic.
+ * \param Block Basic block acting as a location for the new record.
*/
-LLVMValueRef LLVMDIBuilderInsertDbgValueAtEnd(LLVMDIBuilderRef Builder,
- LLVMValueRef Val,
- LLVMMetadataRef VarInfo,
- LLVMMetadataRef Expr,
- LLVMMetadataRef DebugLoc,
- LLVMBasicBlockRef Block);
+LLVMDbgRecordRef LLVMDIBuilderInsertDbgValueRecordAtEnd(
+ LLVMDIBuilderRef Builder, LLVMValueRef Val, LLVMMetadataRef VarInfo,
+ LLVMMetadataRef Expr, LLVMMetadataRef DebugLoc, LLVMBasicBlockRef Block);
/**
* Create a new descriptor for a local auto variable.
@@ -1385,6 +1420,52 @@ LLVMMetadataRef LLVMInstructionGetDebugLoc(LLVMValueRef Inst);
void LLVMInstructionSetDebugLoc(LLVMValueRef Inst, LLVMMetadataRef Loc);
/**
+ * Create a new descriptor for a label
+ *
+ * \param Builder The DIBuilder.
+ * \param Scope The scope to create the label in.
+ * \param Name Variable name.
+ * \param NameLen Length of variable name.
+ * \param File The file to create the label in.
+ * \param LineNo Line Number.
+ * \param AlwaysPreserve Preserve the label regardless of optimization.
+ *
+ * @see llvm::DIBuilder::createLabel()
+ */
+LLVMMetadataRef LLVMDIBuilderCreateLabel(
+ LLVMDIBuilderRef Builder,
+ LLVMMetadataRef Context, const char *Name, size_t NameLen,
+ LLVMMetadataRef File, unsigned LineNo, LLVMBool AlwaysPreserve);
+
+/**
+ * Insert a new llvm.dbg.label intrinsic call
+ *
+ * \param Builder The DIBuilder.
+ * \param LabelInfo The Label's debug info descriptor
+ * \param Location The debug info location
+ * \param InsertBefore Location for the new intrinsic.
+ *
+ * @see llvm::DIBuilder::insertLabel()
+ */
+LLVMDbgRecordRef LLVMDIBuilderInsertLabelBefore(
+ LLVMDIBuilderRef Builder, LLVMMetadataRef LabelInfo,
+ LLVMMetadataRef Location, LLVMValueRef InsertBefore);
+
+/**
+ * Insert a new llvm.dbg.label intrinsic call
+ *
+ * \param Builder The DIBuilder.
+ * \param LabelInfo The Label's debug info descriptor
+ * \param Location The debug info location
+ * \param InsertAtEnd Location for the new intrinsic.
+ *
+ * @see llvm::DIBuilder::insertLabel()
+ */
+LLVMDbgRecordRef LLVMDIBuilderInsertLabelAtEnd(
+ LLVMDIBuilderRef Builder, LLVMMetadataRef LabelInfo,
+ LLVMMetadataRef Location, LLVMBasicBlockRef InsertAtEnd);
+
+/**
* Obtain the enumerated type of a Metadata instance.
*
* @see llvm::Metadata::getMetadataID()
diff --git a/src/llvm-c/Disassembler.h b/src/llvm-c/Disassembler.h
index e6642f4ed..4bc6b04dd 100644
--- a/src/llvm-c/Disassembler.h
+++ b/src/llvm-c/Disassembler.h
@@ -15,8 +15,8 @@
#ifndef LLVM_C_DISASSEMBLER_H
#define LLVM_C_DISASSEMBLER_H
-#include "DisassemblerTypes.h"
-#include "ExternC.h"
+#include "llvm-c/DisassemblerTypes.h"
+#include "llvm-c/ExternC.h"
/**
* @defgroup LLVMCDisassembler Disassembler
@@ -79,8 +79,10 @@ int LLVMSetDisasmOptions(LLVMDisasmContextRef DC, uint64_t Options);
#define LLVMDisassembler_Option_AsmPrinterVariant 4
/* The option to set comment on instructions */
#define LLVMDisassembler_Option_SetInstrComments 8
- /* The option to print latency information alongside instructions */
+/* The option to print latency information alongside instructions */
#define LLVMDisassembler_Option_PrintLatency 16
+/* The option to print in color */
+#define LLVMDisassembler_Option_Color 32
/**
* Dispose of a disassembler context.
diff --git a/src/llvm-c/DisassemblerTypes.h b/src/llvm-c/DisassemblerTypes.h
index 6b7ad6104..6999a350e 100644
--- a/src/llvm-c/DisassemblerTypes.h
+++ b/src/llvm-c/DisassemblerTypes.h
@@ -10,7 +10,7 @@
#ifndef LLVM_C_DISASSEMBLERTYPES_H
#define LLVM_C_DISASSEMBLERTYPES_H
-#include "DataTypes.h"
+#include "llvm-c/DataTypes.h"
#ifdef __cplusplus
#include <cstddef>
#else
diff --git a/src/llvm-c/Error.h b/src/llvm-c/Error.h
index 00746c701..874bbcfe8 100644
--- a/src/llvm-c/Error.h
+++ b/src/llvm-c/Error.h
@@ -14,7 +14,7 @@
#ifndef LLVM_C_ERROR_H
#define LLVM_C_ERROR_H
-#include "ExternC.h"
+#include "llvm-c/ExternC.h"
LLVM_C_EXTERN_C_BEGIN
@@ -52,6 +52,14 @@ LLVMErrorTypeId LLVMGetErrorTypeId(LLVMErrorRef Err);
void LLVMConsumeError(LLVMErrorRef Err);
/**
+ * Report a fatal error if Err is a failure value.
+ *
+ * This function can be used to wrap calls to fallible functions ONLY when it is
+ * known that the Error will always be a success value.
+ */
+void LLVMCantFail(LLVMErrorRef Err);
+
+/**
* Returns the given string's error message. This operation consumes the error,
* and the given LLVMErrorRef value is not usable once this call returns.
* The caller is responsible for disposing of the string by calling
diff --git a/src/llvm-c/ErrorHandling.h b/src/llvm-c/ErrorHandling.h
index 7f9b50a95..d9b9f2275 100644
--- a/src/llvm-c/ErrorHandling.h
+++ b/src/llvm-c/ErrorHandling.h
@@ -14,7 +14,7 @@
#ifndef LLVM_C_ERRORHANDLING_H
#define LLVM_C_ERRORHANDLING_H
-#include "ExternC.h"
+#include "llvm-c/ExternC.h"
LLVM_C_EXTERN_C_BEGIN
diff --git a/src/llvm-c/ExecutionEngine.h b/src/llvm-c/ExecutionEngine.h
index 8e72faefd..c5fc9bdb4 100644
--- a/src/llvm-c/ExecutionEngine.h
+++ b/src/llvm-c/ExecutionEngine.h
@@ -19,10 +19,10 @@
#ifndef LLVM_C_EXECUTIONENGINE_H
#define LLVM_C_EXECUTIONENGINE_H
-#include "ExternC.h"
-#include "Target.h"
-#include "TargetMachine.h"
-#include "Types.h"
+#include "llvm-c/ExternC.h"
+#include "llvm-c/Target.h"
+#include "llvm-c/TargetMachine.h"
+#include "llvm-c/Types.h"
LLVM_C_EXTERN_C_BEGIN
diff --git a/src/llvm-c/IRReader.h b/src/llvm-c/IRReader.h
index ec1110c7a..905b84fa5 100644
--- a/src/llvm-c/IRReader.h
+++ b/src/llvm-c/IRReader.h
@@ -14,8 +14,8 @@
#ifndef LLVM_C_IRREADER_H
#define LLVM_C_IRREADER_H
-#include "ExternC.h"
-#include "Types.h"
+#include "llvm-c/ExternC.h"
+#include "llvm-c/Types.h"
LLVM_C_EXTERN_C_BEGIN
diff --git a/src/llvm-c/LLJIT.h b/src/llvm-c/LLJIT.h
index ee207e10e..a58c3b8bb 100644
--- a/src/llvm-c/LLJIT.h
+++ b/src/llvm-c/LLJIT.h
@@ -24,10 +24,10 @@
#ifndef LLVM_C_LLJIT_H
#define LLVM_C_LLJIT_H
-#include "Error.h"
-#include "Orc.h"
-#include "TargetMachine.h"
-#include "Types.h"
+#include "llvm-c/Error.h"
+#include "llvm-c/Orc.h"
+#include "llvm-c/TargetMachine.h"
+#include "llvm-c/Types.h"
LLVM_C_EXTERN_C_BEGIN
diff --git a/src/llvm-c/LLJITUtils.h b/src/llvm-c/LLJITUtils.h
index 57ffedff8..940097432 100644
--- a/src/llvm-c/LLJITUtils.h
+++ b/src/llvm-c/LLJITUtils.h
@@ -26,7 +26,7 @@
#ifndef LLVM_C_LLJITUTILS_H
#define LLVM_C_LLJITUTILS_H
-#include "LLJIT.h"
+#include "llvm-c/LLJIT.h"
LLVM_C_EXTERN_C_BEGIN
diff --git a/src/llvm-c/Linker.h b/src/llvm-c/Linker.h
index 463a2cff9..acff5d5e2 100644
--- a/src/llvm-c/Linker.h
+++ b/src/llvm-c/Linker.h
@@ -14,8 +14,8 @@
#ifndef LLVM_C_LINKER_H
#define LLVM_C_LINKER_H
-#include "ExternC.h"
-#include "Types.h"
+#include "llvm-c/ExternC.h"
+#include "llvm-c/Types.h"
LLVM_C_EXTERN_C_BEGIN
diff --git a/src/llvm-c/Object.h b/src/llvm-c/Object.h
index 1948c3c34..2f39179c1 100644
--- a/src/llvm-c/Object.h
+++ b/src/llvm-c/Object.h
@@ -19,9 +19,9 @@
#ifndef LLVM_C_OBJECT_H
#define LLVM_C_OBJECT_H
-#include "ExternC.h"
-#include "Types.h"
-#include "Config/llvm-config.h"
+#include "llvm-c/ExternC.h"
+#include "llvm-c/Types.h"
+#include "llvm-c/Config/llvm-config.h"
LLVM_C_EXTERN_C_BEGIN
diff --git a/src/llvm-c/Orc.h b/src/llvm-c/Orc.h
index ecd110b4d..8609a8a6d 100644
--- a/src/llvm-c/Orc.h
+++ b/src/llvm-c/Orc.h
@@ -27,9 +27,9 @@
#ifndef LLVM_C_ORC_H
#define LLVM_C_ORC_H
-#include "Error.h"
-#include "TargetMachine.h"
-#include "Types.h"
+#include "llvm-c/Error.h"
+#include "llvm-c/TargetMachine.h"
+#include "llvm-c/Types.h"
LLVM_C_EXTERN_C_BEGIN
@@ -182,6 +182,15 @@ typedef struct {
typedef LLVMOrcCDependenceMapPair *LLVMOrcCDependenceMapPairs;
/**
+ * A set of symbols that share dependencies.
+ */
+typedef struct {
+ LLVMOrcCSymbolsList Symbols;
+ LLVMOrcCDependenceMapPairs Dependencies;
+ size_t NumDependencies;
+} LLVMOrcCSymbolDependenceGroup;
+
+/**
* Lookup kind. This can be used by definition generators when deciding whether
* to produce a definition for a requested symbol.
*
@@ -808,6 +817,19 @@ LLVMErrorRef LLVMOrcMaterializationResponsibilityNotifyResolved(
* that all symbols covered by this MaterializationResponsibility instance
* have been emitted.
*
+ * This function takes ownership of the symbols in the Dependencies struct.
+ * This allows the following pattern...
+ *
+ * LLVMOrcSymbolStringPoolEntryRef Names[] = {...};
+ * LLVMOrcCDependenceMapPair Dependence = {JD, {Names, sizeof(Names)}}
+ * LLVMOrcMaterializationResponsibilityAddDependencies(JD, Name, &Dependence,
+ * 1);
+ *
+ * ... without requiring cleanup of the elements of the Names array afterwards.
+ *
+ * The client is still responsible for deleting the Dependencies.Names arrays,
+ * and the Dependencies array itself.
+ *
* This method will return an error if any symbols being resolved have been
* moved to the error state due to the failure of a dependency. If this
* method returns an error then clients should log it and call
@@ -817,7 +839,8 @@ LLVMErrorRef LLVMOrcMaterializationResponsibilityNotifyResolved(
* LLVMErrorSuccess.
*/
LLVMErrorRef LLVMOrcMaterializationResponsibilityNotifyEmitted(
- LLVMOrcMaterializationResponsibilityRef MR);
+ LLVMOrcMaterializationResponsibilityRef MR,
+ LLVMOrcCSymbolDependenceGroup *SymbolDepGroups, size_t NumSymbolDepGroups);
/**
* Attempt to claim responsibility for new definitions. This method can be
@@ -871,38 +894,6 @@ LLVMErrorRef LLVMOrcMaterializationResponsibilityDelegate(
LLVMOrcMaterializationResponsibilityRef *Result);
/**
- * Adds dependencies to a symbol that the MaterializationResponsibility is
- * responsible for.
- *
- * This function takes ownership of Dependencies struct. The Names
- * array have been retained for this function. This allows the following
- * pattern...
- *
- * LLVMOrcSymbolStringPoolEntryRef Names[] = {...};
- * LLVMOrcCDependenceMapPair Dependence = {JD, {Names, sizeof(Names)}}
- * LLVMOrcMaterializationResponsibilityAddDependencies(JD, Name, &Dependence,
- * 1);
- *
- * ... without requiring cleanup of the elements of the Names array afterwards.
- *
- * The client is still responsible for deleting the Dependencies.Names array
- * itself.
- */
-void LLVMOrcMaterializationResponsibilityAddDependencies(
- LLVMOrcMaterializationResponsibilityRef MR,
- LLVMOrcSymbolStringPoolEntryRef Name,
- LLVMOrcCDependenceMapPairs Dependencies, size_t NumPairs);
-
-/**
- * Adds dependencies to all symbols that the MaterializationResponsibility is
- * responsible for. See LLVMOrcMaterializationResponsibilityAddDependencies for
- * notes about memory responsibility.
- */
-void LLVMOrcMaterializationResponsibilityAddDependenciesForAll(
- LLVMOrcMaterializationResponsibilityRef MR,
- LLVMOrcCDependenceMapPairs Dependencies, size_t NumPairs);
-
-/**
* Create a "bare" JITDylib.
*
* The client is responsible for ensuring that the JITDylib's name is unique,
diff --git a/src/llvm-c/OrcEE.h b/src/llvm-c/OrcEE.h
index aef24c7aa..d451187aa 100644
--- a/src/llvm-c/OrcEE.h
+++ b/src/llvm-c/OrcEE.h
@@ -24,11 +24,11 @@
#ifndef LLVM_C_ORCEE_H
#define LLVM_C_ORCEE_H
-#include "Error.h"
-#include "ExecutionEngine.h"
-#include "Orc.h"
-#include "TargetMachine.h"
-#include "Types.h"
+#include "llvm-c/Error.h"
+#include "llvm-c/ExecutionEngine.h"
+#include "llvm-c/Orc.h"
+#include "llvm-c/TargetMachine.h"
+#include "llvm-c/Types.h"
LLVM_C_EXTERN_C_BEGIN
diff --git a/src/llvm-c/Remarks.h b/src/llvm-c/Remarks.h
index 548a4041a..ffe647a65 100644
--- a/src/llvm-c/Remarks.h
+++ b/src/llvm-c/Remarks.h
@@ -15,8 +15,8 @@
#ifndef LLVM_C_REMARKS_H
#define LLVM_C_REMARKS_H
-#include "ExternC.h"
-#include "Types.h"
+#include "llvm-c/ExternC.h"
+#include "llvm-c/Types.h"
#ifdef __cplusplus
#include <cstddef>
#else
diff --git a/src/llvm-c/Support.h b/src/llvm-c/Support.h
index 31a75354c..17657861b 100644
--- a/src/llvm-c/Support.h
+++ b/src/llvm-c/Support.h
@@ -14,9 +14,9 @@
#ifndef LLVM_C_SUPPORT_H
#define LLVM_C_SUPPORT_H
-#include "DataTypes.h"
-#include "ExternC.h"
-#include "Types.h"
+#include "llvm-c/DataTypes.h"
+#include "llvm-c/ExternC.h"
+#include "llvm-c/Types.h"
LLVM_C_EXTERN_C_BEGIN
diff --git a/src/llvm-c/Target.h b/src/llvm-c/Target.h
index 4d03741c4..54367a41b 100644
--- a/src/llvm-c/Target.h
+++ b/src/llvm-c/Target.h
@@ -19,9 +19,9 @@
#ifndef LLVM_C_TARGET_H
#define LLVM_C_TARGET_H
-#include "ExternC.h"
-#include "Types.h"
-#include "Config/llvm-config.h"
+#include "llvm-c/ExternC.h"
+#include "llvm-c/Types.h"
+#include "llvm-c/Config/llvm-config.h"
LLVM_C_EXTERN_C_BEGIN
@@ -40,34 +40,34 @@ typedef struct LLVMOpaqueTargetLibraryInfotData *LLVMTargetLibraryInfoRef;
/* Declare all of the target-initialization functions that are available. */
#define LLVM_TARGET(TargetName) \
void LLVMInitialize##TargetName##TargetInfo(void);
-#include "Config/Targets.def"
+#include "llvm-c/Config/Targets.def"
#undef LLVM_TARGET /* Explicit undef to make SWIG happier */
#define LLVM_TARGET(TargetName) void LLVMInitialize##TargetName##Target(void);
-#include "Config/Targets.def"
+#include "llvm-c/Config/Targets.def"
#undef LLVM_TARGET /* Explicit undef to make SWIG happier */
#define LLVM_TARGET(TargetName) \
void LLVMInitialize##TargetName##TargetMC(void);
-#include "Config/Targets.def"
+#include "llvm-c/Config/Targets.def"
#undef LLVM_TARGET /* Explicit undef to make SWIG happier */
/* Declare all of the available assembly printer initialization functions. */
#define LLVM_ASM_PRINTER(TargetName) \
void LLVMInitialize##TargetName##AsmPrinter(void);
-#include "Config/AsmPrinters.def"
+#include "llvm-c/Config/AsmPrinters.def"
#undef LLVM_ASM_PRINTER /* Explicit undef to make SWIG happier */
/* Declare all of the available assembly parser initialization functions. */
#define LLVM_ASM_PARSER(TargetName) \
void LLVMInitialize##TargetName##AsmParser(void);
-#include "Config/AsmParsers.def"
+#include "llvm-c/Config/AsmParsers.def"
#undef LLVM_ASM_PARSER /* Explicit undef to make SWIG happier */
/* Declare all of the available disassembler initialization functions. */
#define LLVM_DISASSEMBLER(TargetName) \
void LLVMInitialize##TargetName##Disassembler(void);
-#include "Config/Disassemblers.def"
+#include "llvm-c/Config/Disassemblers.def"
#undef LLVM_DISASSEMBLER /* Explicit undef to make SWIG happier */
/** LLVMInitializeAllTargetInfos - The main program should call this function if
@@ -75,7 +75,7 @@ typedef struct LLVMOpaqueTargetLibraryInfotData *LLVMTargetLibraryInfoRef;
support. */
static inline void LLVMInitializeAllTargetInfos(void) {
#define LLVM_TARGET(TargetName) LLVMInitialize##TargetName##TargetInfo();
-#include "Config/Targets.def"
+#include "llvm-c/Config/Targets.def"
#undef LLVM_TARGET /* Explicit undef to make SWIG happier */
}
@@ -84,7 +84,7 @@ static inline void LLVMInitializeAllTargetInfos(void) {
support. */
static inline void LLVMInitializeAllTargets(void) {
#define LLVM_TARGET(TargetName) LLVMInitialize##TargetName##Target();
-#include "Config/Targets.def"
+#include "llvm-c/Config/Targets.def"
#undef LLVM_TARGET /* Explicit undef to make SWIG happier */
}
@@ -93,7 +93,7 @@ static inline void LLVMInitializeAllTargets(void) {
support. */
static inline void LLVMInitializeAllTargetMCs(void) {
#define LLVM_TARGET(TargetName) LLVMInitialize##TargetName##TargetMC();
-#include "Config/Targets.def"
+#include "llvm-c/Config/Targets.def"
#undef LLVM_TARGET /* Explicit undef to make SWIG happier */
}
@@ -102,7 +102,7 @@ static inline void LLVMInitializeAllTargetMCs(void) {
available via the TargetRegistry. */
static inline void LLVMInitializeAllAsmPrinters(void) {
#define LLVM_ASM_PRINTER(TargetName) LLVMInitialize##TargetName##AsmPrinter();
-#include "Config/AsmPrinters.def"
+#include "llvm-c/Config/AsmPrinters.def"
#undef LLVM_ASM_PRINTER /* Explicit undef to make SWIG happier */
}
@@ -111,7 +111,7 @@ static inline void LLVMInitializeAllAsmPrinters(void) {
available via the TargetRegistry. */
static inline void LLVMInitializeAllAsmParsers(void) {
#define LLVM_ASM_PARSER(TargetName) LLVMInitialize##TargetName##AsmParser();
-#include "Config/AsmParsers.def"
+#include "llvm-c/Config/AsmParsers.def"
#undef LLVM_ASM_PARSER /* Explicit undef to make SWIG happier */
}
@@ -121,7 +121,7 @@ static inline void LLVMInitializeAllAsmParsers(void) {
static inline void LLVMInitializeAllDisassemblers(void) {
#define LLVM_DISASSEMBLER(TargetName) \
LLVMInitialize##TargetName##Disassembler();
-#include "Config/Disassemblers.def"
+#include "llvm-c/Config/Disassemblers.def"
#undef LLVM_DISASSEMBLER /* Explicit undef to make SWIG happier */
}
@@ -244,7 +244,7 @@ LLVMTypeRef LLVMIntPtrTypeInContext(LLVMContextRef C, LLVMTargetDataRef TD);
LLVMTypeRef LLVMIntPtrTypeForASInContext(LLVMContextRef C, LLVMTargetDataRef TD,
unsigned AS);
-/** Computes the size of a type in bytes for a target.
+/** Computes the size of a type in bits for a target.
See the method llvm::DataLayout::getTypeSizeInBits. */
unsigned long long LLVMSizeOfTypeInBits(LLVMTargetDataRef TD, LLVMTypeRef Ty);
diff --git a/src/llvm-c/TargetMachine.h b/src/llvm-c/TargetMachine.h
index aa628e216..cbe891380 100644
--- a/src/llvm-c/TargetMachine.h
+++ b/src/llvm-c/TargetMachine.h
@@ -19,9 +19,9 @@
#ifndef LLVM_C_TARGETMACHINE_H
#define LLVM_C_TARGETMACHINE_H
-#include "ExternC.h"
-#include "Target.h"
-#include "Types.h"
+#include "llvm-c/ExternC.h"
+#include "llvm-c/Target.h"
+#include "llvm-c/Types.h"
LLVM_C_EXTERN_C_BEGIN
diff --git a/src/llvm-c/Transforms/PassBuilder.h b/src/llvm-c/Transforms/PassBuilder.h
index 8ad2a9982..d297b57ca 100644
--- a/src/llvm-c/Transforms/PassBuilder.h
+++ b/src/llvm-c/Transforms/PassBuilder.h
@@ -14,9 +14,9 @@
#ifndef LLVM_C_TRANSFORMS_PASSBUILDER_H
#define LLVM_C_TRANSFORMS_PASSBUILDER_H
-#include "../Error.h"
-#include "../TargetMachine.h"
-#include "../Types.h"
+#include "llvm-c/Error.h"
+#include "llvm-c/TargetMachine.h"
+#include "llvm-c/Types.h"
/**
* @defgroup LLVMCCoreNewPM New Pass Manager
@@ -51,6 +51,16 @@ LLVMErrorRef LLVMRunPasses(LLVMModuleRef M, const char *Passes,
LLVMPassBuilderOptionsRef Options);
/**
+ * Construct and run a set of passes over a function.
+ *
+ * This function behaves the same as LLVMRunPasses, but operates on a single
+ * function instead of an entire module.
+ */
+LLVMErrorRef LLVMRunPassesOnFunction(LLVMValueRef F, const char *Passes,
+ LLVMTargetMachineRef TM,
+ LLVMPassBuilderOptionsRef Options);
+
+/**
* Create a new set of options for a PassBuilder
*
* Ownership of the returned instance is given to the client, and they are
@@ -72,6 +82,14 @@ void LLVMPassBuilderOptionsSetVerifyEach(LLVMPassBuilderOptionsRef Options,
void LLVMPassBuilderOptionsSetDebugLogging(LLVMPassBuilderOptionsRef Options,
LLVMBool DebugLogging);
+/**
+ * Specify a custom alias analysis pipeline for the PassBuilder to be used
+ * instead of the default one. The string argument is not copied; the caller
+ * is responsible for ensuring it outlives the PassBuilderOptions instance.
+ */
+void LLVMPassBuilderOptionsSetAAPipeline(LLVMPassBuilderOptionsRef Options,
+ const char *AAPipeline);
+
void LLVMPassBuilderOptionsSetLoopInterleaving(
LLVMPassBuilderOptionsRef Options, LLVMBool LoopInterleaving);
diff --git a/src/llvm-c/Types.h b/src/llvm-c/Types.h
index 77aa7c9b4..4681500ef 100644
--- a/src/llvm-c/Types.h
+++ b/src/llvm-c/Types.h
@@ -14,8 +14,8 @@
#ifndef LLVM_C_TYPES_H
#define LLVM_C_TYPES_H
-#include "DataTypes.h"
-#include "ExternC.h"
+#include "llvm-c/DataTypes.h"
+#include "llvm-c/ExternC.h"
LLVM_C_EXTERN_C_BEGIN
@@ -170,6 +170,11 @@ typedef struct LLVMOpaqueJITEventListener *LLVMJITEventListenerRef;
typedef struct LLVMOpaqueBinary *LLVMBinaryRef;
/**
+ * @see llvm::DbgRecord
+ */
+typedef struct LLVMOpaqueDbgRecord *LLVMDbgRecordRef;
+
+/**
* @}
*/
diff --git a/src/llvm-c/lto.h b/src/llvm-c/lto.h
index 89f76c695..5ceb02224 100644
--- a/src/llvm-c/lto.h
+++ b/src/llvm-c/lto.h
@@ -16,7 +16,7 @@
#ifndef LLVM_C_LTO_H
#define LLVM_C_LTO_H
-#include "ExternC.h"
+#include "llvm-c/ExternC.h"
#ifdef __cplusplus
#include <cstddef>
diff --git a/src/llvm_abi.cpp b/src/llvm_abi.cpp
index 0b2bb7956..e1cbe7558 100644
--- a/src/llvm_abi.cpp
+++ b/src/llvm_abi.cpp
@@ -256,8 +256,10 @@ gb_internal i64 lb_sizeof(LLVMTypeRef type) {
}
break;
+#if LLVM_VERSION_MAJOR < 20
case LLVMX86_MMXTypeKind:
return 8;
+#endif
case LLVMVectorTypeKind:
{
LLVMTypeRef elem = OdinLLVMGetVectorElementType(type);
@@ -310,8 +312,10 @@ gb_internal i64 lb_alignof(LLVMTypeRef type) {
case LLVMArrayTypeKind:
return lb_alignof(OdinLLVMGetArrayElementType(type));
+#if LLVM_VERSION_MAJOR < 20
case LLVMX86_MMXTypeKind:
return 8;
+#endif
case LLVMVectorTypeKind:
{
// TODO(bill): This appears to be correct but LLVM isn't necessarily "great" with regards to documentation
@@ -569,7 +573,9 @@ namespace lbAbiAmd64SysV {
gb_internal void classify_with(LLVMTypeRef t, Array<RegClass> *cls, i64 ix, i64 off);
gb_internal void fixup(LLVMTypeRef t, Array<RegClass> *cls);
- gb_internal lbArgType amd64_type(LLVMContextRef c, LLVMTypeRef type, Amd64TypeAttributeKind attribute_kind, ProcCallingConvention calling_convention);
+ gb_internal lbArgType amd64_type(LLVMContextRef c, LLVMTypeRef type, Amd64TypeAttributeKind attribute_kind, ProcCallingConvention calling_convention,
+ bool is_arg,
+ i32 *int_regs, i32 *sse_regs);
gb_internal Array<RegClass> classify(LLVMTypeRef t);
gb_internal LLVMTypeRef llreg(LLVMContextRef c, Array<RegClass> const &reg_classes, LLVMTypeRef type);
@@ -579,7 +585,9 @@ namespace lbAbiAmd64SysV {
}
LB_ABI_MODIFY_RETURN_IF_TUPLE_MACRO();
- return amd64_type(c, return_type, Amd64TypeAttribute_StructRect, ft->calling_convention);
+ return amd64_type(c, return_type, Amd64TypeAttribute_StructRect, ft->calling_convention,
+ false,
+ nullptr, nullptr);
}
gb_internal LB_ABI_INFO(abi_info) {
@@ -588,10 +596,16 @@ namespace lbAbiAmd64SysV {
ft->ctx = c;
ft->calling_convention = calling_convention;
+ i32 int_regs = 6; // rdi, rsi, rdx, rcx, r8, r9
+ i32 sse_regs = 8; // xmm0-xmm7
+
ft->args = array_make<lbArgType>(lb_function_type_args_allocator(), arg_count);
for (unsigned i = 0; i < arg_count; i++) {
- ft->args[i] = amd64_type(c, arg_types[i], Amd64TypeAttribute_ByVal, calling_convention);
+ ft->args[i] = amd64_type(c, arg_types[i], Amd64TypeAttribute_ByVal, calling_convention,
+ true,
+ &int_regs, &sse_regs);
}
+
ft->ret = compute_return_type(ft, c, return_type, return_is_defined, return_is_tuple);
return ft;
@@ -650,17 +664,79 @@ namespace lbAbiAmd64SysV {
}
- gb_internal lbArgType amd64_type(LLVMContextRef c, LLVMTypeRef type, Amd64TypeAttributeKind attribute_kind, ProcCallingConvention calling_convention) {
+
+ gb_internal bool is_aggregate(LLVMTypeRef type) {
+ LLVMTypeKind kind = LLVMGetTypeKind(type);
+ switch (kind) {
+ case LLVMStructTypeKind:
+ if (LLVMCountStructElementTypes(type) == 1) {
+ return is_aggregate(LLVMStructGetTypeAtIndex(type, 0));
+ }
+ return true;
+ case LLVMArrayTypeKind:
+ if (LLVMGetArrayLength(type) == 1) {
+ return is_aggregate(LLVMGetElementType(type));
+ }
+ return true;
+ }
+ return false;
+ };
+
+ gb_internal lbArgType amd64_type(LLVMContextRef c, LLVMTypeRef type, Amd64TypeAttributeKind attribute_kind, ProcCallingConvention calling_convention,
+ bool is_arg,
+ i32 *int_regs, i32 *sse_regs) {
+ auto cls = classify(type);
+ i32 needed_int = 0;
+ i32 needed_sse = 0;
+ for (auto c : cls) {
+ switch (c) {
+ case RegClass_Int:
+ needed_int += 1;
+ break;
+ case RegClass_SSEFs:
+ case RegClass_SSEFv:
+ case RegClass_SSEDs:
+ case RegClass_SSEDv:
+ case RegClass_SSEInt8:
+ case RegClass_SSEInt16:
+ case RegClass_SSEInt32:
+ case RegClass_SSEInt64:
+ case RegClass_SSEInt128:
+ case RegClass_SSEUp:
+ needed_sse += 1;
+ break;
+ }
+ }
+
+ bool ran_out_of_regs = false;
+ if (int_regs && sse_regs) {
+ *int_regs -= needed_int;
+ *sse_regs -= needed_sse;
+ bool int_ok = *int_regs >= 0;
+ bool sse_ok = *sse_regs >= 0;
+
+ *int_regs = gb_max(*int_regs, 0);
+ *sse_regs = gb_max(*sse_regs, 0);
+
+ if ((!int_ok || !sse_ok) && is_aggregate(type)) {
+ ran_out_of_regs = true;
+ }
+ }
+
if (is_register(type)) {
LLVMAttributeRef attribute = nullptr;
if (type == LLVMInt1TypeInContext(c)) {
attribute = lb_create_enum_attribute(c, "zeroext");
}
return lb_arg_type_direct(type, nullptr, nullptr, attribute);
- }
-
- auto cls = classify(type);
- if (is_mem_cls(cls, attribute_kind)) {
+ } else if (ran_out_of_regs) {
+ if (is_arg) {
+ return lb_arg_type_indirect_byval(c, type);
+ } else {
+ LLVMAttributeRef attribute = lb_create_enum_attribute_with_type(c, "sret", type);
+ return lb_arg_type_indirect(type, attribute);
+ }
+ } else if (is_mem_cls(cls, attribute_kind)) {
LLVMAttributeRef attribute = nullptr;
if (attribute_kind == Amd64TypeAttribute_ByVal) {
if (is_calling_convention_odin(calling_convention)) {
@@ -901,7 +977,7 @@ namespace lbAbiAmd64SysV {
return types[0];
}
- return LLVMStructTypeInContext(c, types.data, cast(unsigned)types.count, sz == 0);
+ return LLVMStructTypeInContext(c, types.data, cast(unsigned)types.count, false);
}
gb_internal void classify_with(LLVMTypeRef t, Array<RegClass> *cls, i64 ix, i64 off) {
@@ -1155,38 +1231,24 @@ namespace lbAbiArm64 {
}
} else {
i64 size = lb_sizeof(return_type);
- if (size <= 16) {
- LLVMTypeRef cast_type = nullptr;
-
- if (size == 0) {
- cast_type = LLVMStructTypeInContext(c, nullptr, 0, false);
- } else if (size <= 8) {
- cast_type = LLVMIntTypeInContext(c, cast(unsigned)(size*8));
- } else {
- unsigned count = cast(unsigned)((size+7)/8);
-
- LLVMTypeRef llvm_i64 = LLVMIntTypeInContext(c, 64);
- LLVMTypeRef *types = gb_alloc_array(temporary_allocator(), LLVMTypeRef, count);
-
- i64 size_copy = size;
- for (unsigned i = 0; i < count; i++) {
- if (size_copy >= 8) {
- types[i] = llvm_i64;
- } else {
- types[i] = LLVMIntTypeInContext(c, 8*cast(unsigned)size_copy);
- }
- size_copy -= 8;
- }
- GB_ASSERT(size_copy <= 0);
- cast_type = LLVMStructTypeInContext(c, types, count, true);
- }
- return lb_arg_type_direct(return_type, cast_type, nullptr, nullptr);
- } else {
+ if (size > 16) {
LB_ABI_MODIFY_RETURN_IF_TUPLE_MACRO();
LLVMAttributeRef attr = lb_create_enum_attribute_with_type(c, "sret", return_type);
return lb_arg_type_indirect(return_type, attr);
}
+
+ GB_ASSERT(size <= 16);
+ LLVMTypeRef cast_type = nullptr;
+ if (size == 0) {
+ cast_type = LLVMStructTypeInContext(c, nullptr, 0, false);
+ } else if (size <= 8) {
+ cast_type = LLVMIntTypeInContext(c, cast(unsigned)(size*8));
+ } else {
+ LLVMTypeRef llvm_i64 = LLVMIntTypeInContext(c, 64);
+ cast_type = llvm_array_type(llvm_i64, 2);
+ }
+ return lb_arg_type_direct(return_type, cast_type, nullptr, nullptr);
}
}
@@ -1251,7 +1313,7 @@ namespace lbAbiWasm {
registers/arguments if possible rather than by pointer.
*/
gb_internal Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count, ProcCallingConvention calling_convention, Type *original_type);
- gb_internal LB_ABI_COMPUTE_RETURN_TYPE(compute_return_type);
+ gb_internal lbArgType compute_return_type(lbFunctionType *ft, LLVMContextRef c, LLVMTypeRef return_type, bool return_is_defined, bool return_is_tuple, Type* original_type);
enum {MAX_DIRECT_STRUCT_SIZE = 32};
@@ -1261,7 +1323,9 @@ namespace lbAbiWasm {
ft->ctx = c;
ft->calling_convention = calling_convention;
ft->args = compute_arg_types(c, arg_types, arg_count, calling_convention, original_type);
- ft->ret = compute_return_type(ft, c, return_type, return_is_defined, return_is_tuple);
+
+ GB_ASSERT(original_type->kind == Type_Proc);
+ ft->ret = compute_return_type(ft, c, return_type, return_is_defined, return_is_tuple, original_type->Proc.results);
return ft;
}
@@ -1297,7 +1361,7 @@ namespace lbAbiWasm {
return false;
}
- gb_internal bool type_can_be_direct(LLVMTypeRef type, ProcCallingConvention calling_convention) {
+ gb_internal bool type_can_be_direct(LLVMTypeRef type, Type *original_type, ProcCallingConvention calling_convention) {
LLVMTypeKind kind = LLVMGetTypeKind(type);
i64 sz = lb_sizeof(type);
if (sz == 0) {
@@ -1310,9 +1374,21 @@ namespace lbAbiWasm {
return false;
} else if (kind == LLVMStructTypeKind) {
unsigned count = LLVMCountStructElementTypes(type);
+
+ // NOTE(laytan): raw unions are always structs with 1 field in LLVM, need to check our own def.
+ Type *bt = base_type(original_type);
+ if (bt->kind == Type_Struct && bt->Struct.is_raw_union) {
+ count = cast(unsigned)bt->Struct.fields.count;
+ }
+
if (count == 1) {
- return type_can_be_direct(LLVMStructGetTypeAtIndex(type, 0), calling_convention);
+ return type_can_be_direct(
+ LLVMStructGetTypeAtIndex(type, 0),
+ type_internal_index(original_type, 0),
+ calling_convention
+ );
}
+
} else if (is_basic_register_type(type)) {
return true;
}
@@ -1336,7 +1412,7 @@ namespace lbAbiWasm {
return false;
}
- gb_internal lbArgType is_struct(LLVMContextRef c, LLVMTypeRef type, ProcCallingConvention calling_convention) {
+ gb_internal lbArgType is_struct(LLVMContextRef c, LLVMTypeRef type, Type *original_type, ProcCallingConvention calling_convention) {
LLVMTypeKind kind = LLVMGetTypeKind(type);
GB_ASSERT(kind == LLVMArrayTypeKind || kind == LLVMStructTypeKind);
@@ -1344,15 +1420,15 @@ namespace lbAbiWasm {
if (sz == 0) {
return lb_arg_type_ignore(type);
}
- if (type_can_be_direct(type, calling_convention)) {
+ if (type_can_be_direct(type, original_type, calling_convention)) {
return lb_arg_type_direct(type);
}
return lb_arg_type_indirect(type, nullptr);
}
- gb_internal lbArgType pseudo_slice(LLVMContextRef c, LLVMTypeRef type, ProcCallingConvention calling_convention) {
+ gb_internal lbArgType pseudo_slice(LLVMContextRef c, LLVMTypeRef type, Type *original_type, ProcCallingConvention calling_convention) {
if (build_context.metrics.ptr_size < build_context.metrics.int_size &&
- type_can_be_direct(type, calling_convention)) {
+ type_can_be_direct(type, original_type, calling_convention)) {
LLVMTypeRef types[2] = {
LLVMStructGetTypeAtIndex(type, 0),
// ignore padding
@@ -1361,7 +1437,7 @@ namespace lbAbiWasm {
LLVMTypeRef new_type = LLVMStructTypeInContext(c, types, gb_count_of(types), false);
return lb_arg_type_direct(type, new_type, nullptr, nullptr);
} else {
- return is_struct(c, type, calling_convention);
+ return is_struct(c, type, original_type, calling_convention);
}
}
@@ -1382,9 +1458,9 @@ namespace lbAbiWasm {
LLVMTypeKind kind = LLVMGetTypeKind(t);
if (kind == LLVMStructTypeKind || kind == LLVMArrayTypeKind) {
if (is_type_slice(ptype) || is_type_string(ptype)) {
- args[i] = pseudo_slice(c, t, calling_convention);
+ args[i] = pseudo_slice(c, t, ptype, calling_convention);
} else {
- args[i] = is_struct(c, t, calling_convention);
+ args[i] = is_struct(c, t, ptype, calling_convention);
}
} else {
args[i] = non_struct(c, t, false);
@@ -1393,11 +1469,11 @@ namespace lbAbiWasm {
return args;
}
- gb_internal LB_ABI_COMPUTE_RETURN_TYPE(compute_return_type) {
+ gb_internal lbArgType compute_return_type(lbFunctionType *ft, LLVMContextRef c, LLVMTypeRef return_type, bool return_is_defined, bool return_is_tuple, Type* original_type) {
if (!return_is_defined) {
return lb_arg_type_direct(LLVMVoidTypeInContext(c));
} else if (lb_is_type_kind(return_type, LLVMStructTypeKind) || lb_is_type_kind(return_type, LLVMArrayTypeKind)) {
- if (type_can_be_direct(return_type, ft->calling_convention)) {
+ if (type_can_be_direct(return_type, original_type, ft->calling_convention)) {
return lb_arg_type_direct(return_type);
} else if (ft->calling_convention != ProcCC_CDecl) {
i64 sz = lb_sizeof(return_type);
@@ -1409,7 +1485,35 @@ namespace lbAbiWasm {
}
}
- LB_ABI_MODIFY_RETURN_IF_TUPLE_MACRO();
+ // Multiple returns.
+ if (return_is_tuple) { \
+ lbArgType return_arg = {};
+ if (lb_is_type_kind(return_type, LLVMStructTypeKind)) {
+ unsigned field_count = LLVMCountStructElementTypes(return_type);
+ if (field_count > 1) {
+ ft->original_arg_count = ft->args.count;
+ ft->multiple_return_original_type = return_type;
+
+ for (unsigned i = 0; i < field_count-1; i++) {
+ LLVMTypeRef field_type = LLVMStructGetTypeAtIndex(return_type, i);
+ LLVMTypeRef field_pointer_type = LLVMPointerType(field_type, 0);
+ lbArgType ret_partial = lb_arg_type_direct(field_pointer_type);
+ array_add(&ft->args, ret_partial);
+ }
+
+ return_arg = compute_return_type(
+ ft,
+ c,
+ LLVMStructGetTypeAtIndex(return_type, field_count-1),
+ true, false,
+ type_internal_index(original_type, field_count-1)
+ );
+ }
+ }
+ if (return_arg.type != nullptr) {
+ return return_arg;
+ }
+ }
LLVMAttributeRef attr = lb_create_enum_attribute_with_type(c, "sret", return_type);
return lb_arg_type_indirect(return_type, attr);
@@ -1814,7 +1918,8 @@ gb_internal LB_ABI_INFO(lb_get_abi_info) {
return_type, return_is_defined,
ALLOW_SPLIT_MULTI_RETURNS && return_is_tuple && is_calling_convention_odin(calling_convention),
calling_convention,
- base_type(original_type));
+ base_type(original_type)
+ );
// NOTE(bill): this is handled here rather than when developing the type in `lb_type_internal_for_procedures_raw`
diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp
index 696ced0df..3cf77256b 100644
--- a/src/llvm_backend.cpp
+++ b/src/llvm_backend.cpp
@@ -24,7 +24,7 @@
#include "llvm_backend_stmt.cpp"
#include "llvm_backend_proc.cpp"
-String get_default_microarchitecture() {
+gb_internal String get_default_microarchitecture() {
String default_march = str_lit("generic");
if (build_context.metrics.arch == TargetArch_amd64) {
// NOTE(bill): x86-64-v2 is more than enough for everyone
@@ -47,7 +47,7 @@ String get_default_microarchitecture() {
return default_march;
}
-String get_final_microarchitecture() {
+gb_internal String get_final_microarchitecture() {
BuildContext *bc = &build_context;
String microarch = bc->microarch;
@@ -169,11 +169,17 @@ gb_internal void lb_correct_entity_linkage(lbGenerator *gen) {
other_global = LLVMGetNamedGlobal(ec.other_module->mod, ec.cname);
if (other_global) {
LLVMSetLinkage(other_global, LLVMWeakAnyLinkage);
+ if (!ec.e->Variable.is_export && !ec.e->Variable.is_foreign) {
+ LLVMSetVisibility(other_global, LLVMHiddenVisibility);
+ }
}
} else if (ec.e->kind == Entity_Procedure) {
other_global = LLVMGetNamedFunction(ec.other_module->mod, ec.cname);
if (other_global) {
LLVMSetLinkage(other_global, LLVMWeakAnyLinkage);
+ if (!ec.e->Procedure.is_export && !ec.e->Procedure.is_foreign) {
+ LLVMSetVisibility(other_global, LLVMHiddenVisibility);
+ }
}
}
}
@@ -227,6 +233,16 @@ gb_internal lbContextData *lb_push_context_onto_stack(lbProcedure *p, lbAddr ctx
}
+gb_internal String lb_internal_gen_name_from_type(char const *prefix, Type *type) {
+ gbString str = gb_string_make(permanent_allocator(), prefix);
+ u64 hash = type_hash_canonical_type(type);
+ str = gb_string_appendc(str, "-");
+ str = gb_string_append_fmt(str, "%llu", cast(unsigned long long)hash);
+ String proc_name = make_string(cast(u8 const *)str, gb_string_length(str));
+ return proc_name;
+}
+
+
gb_internal lbValue lb_equal_proc_for_type(lbModule *m, Type *type) {
type = base_type(type);
GB_ASSERT(is_type_comparable(type));
@@ -234,7 +250,8 @@ gb_internal lbValue lb_equal_proc_for_type(lbModule *m, Type *type) {
Type *pt = alloc_type_pointer(type);
LLVMTypeRef ptr_type = lb_type(m, pt);
- lbProcedure **found = map_get(&m->equal_procs, type);
+ String proc_name = lb_internal_gen_name_from_type("__$equal", type);
+ lbProcedure **found = string_map_get(&m->gen_procs, proc_name);
lbProcedure *compare_proc = nullptr;
if (found) {
compare_proc = *found;
@@ -242,17 +259,12 @@ gb_internal lbValue lb_equal_proc_for_type(lbModule *m, Type *type) {
return {compare_proc->value, compare_proc->type};
}
- static std::atomic<u32> proc_index;
-
- char buf[32] = {};
- isize n = gb_snprintf(buf, 32, "__$equal%u", 1+proc_index.fetch_add(1));
- char *str = gb_alloc_str_len(permanent_allocator(), buf, n-1);
- String proc_name = make_string_c(str);
lbProcedure *p = lb_create_dummy_procedure(m, proc_name, t_equal_proc);
- map_set(&m->equal_procs, type, p);
+ string_map_set(&m->gen_procs, proc_name, p);
lb_begin_procedure_body(p);
+ LLVMSetLinkage(p->value, LLVMInternalLinkage);
// lb_add_attribute_to_proc(m, p->value, "readonly");
lb_add_attribute_to_proc(m, p->value, "nounwind");
@@ -404,24 +416,19 @@ gb_internal lbValue lb_hasher_proc_for_type(lbModule *m, Type *type) {
Type *pt = alloc_type_pointer(type);
- lbProcedure **found = map_get(&m->hasher_procs, type);
+ String proc_name = lb_internal_gen_name_from_type("__$hasher", type);
+ lbProcedure **found = string_map_get(&m->gen_procs, proc_name);
if (found) {
GB_ASSERT(*found != nullptr);
return {(*found)->value, (*found)->type};
}
- static std::atomic<u32> proc_index;
-
- char buf[32] = {};
- isize n = gb_snprintf(buf, 32, "__$hasher%u", 1+proc_index.fetch_add(1));
- char *str = gb_alloc_str_len(permanent_allocator(), buf, n-1);
- String proc_name = make_string_c(str);
-
lbProcedure *p = lb_create_dummy_procedure(m, proc_name, t_hasher_proc);
- map_set(&m->hasher_procs, type, p);
+ string_map_set(&m->gen_procs, proc_name, p);
lb_begin_procedure_body(p);
defer (lb_end_procedure_body(p));
+ LLVMSetLinkage(p->value, LLVMInternalLinkage);
// lb_add_attribute_to_proc(m, p->value, "readonly");
lb_add_attribute_to_proc(m, p->value, "nounwind");
@@ -556,6 +563,53 @@ gb_internal lbValue lb_hasher_proc_for_type(lbModule *m, Type *type) {
lbValue res = lb_emit_runtime_call(p, "default_hasher_string", args);
lb_add_callsite_force_inline(p, res);
LLVMBuildRet(p->builder, res.value);
+ } else if (is_type_float(type)) {
+ lbValue ptr = lb_emit_conv(p, data, pt);
+ lbValue v = lb_emit_load(p, ptr);
+ v = lb_emit_conv(p, v, t_f64);
+
+ auto args = array_make<lbValue>(temporary_allocator(), 2);
+ args[0] = v;
+ args[1] = seed;
+ lbValue res = lb_emit_runtime_call(p, "default_hasher_f64", args);
+ lb_add_callsite_force_inline(p, res);
+ LLVMBuildRet(p->builder, res.value);
+ } else if (is_type_complex(type)) {
+ lbValue ptr = lb_emit_conv(p, data, pt);
+ lbValue xp = lb_emit_struct_ep(p, ptr, 0);
+ lbValue yp = lb_emit_struct_ep(p, ptr, 1);
+
+ lbValue x = lb_emit_conv(p, lb_emit_load(p, xp), t_f64);
+ lbValue y = lb_emit_conv(p, lb_emit_load(p, yp), t_f64);
+
+ auto args = array_make<lbValue>(temporary_allocator(), 3);
+ args[0] = x;
+ args[1] = y;
+ args[2] = seed;
+ lbValue res = lb_emit_runtime_call(p, "default_hasher_complex128", args);
+ lb_add_callsite_force_inline(p, res);
+ LLVMBuildRet(p->builder, res.value);
+ } else if (is_type_quaternion(type)) {
+ lbValue ptr = lb_emit_conv(p, data, pt);
+ lbValue xp = lb_emit_struct_ep(p, ptr, 0);
+ lbValue yp = lb_emit_struct_ep(p, ptr, 1);
+ lbValue zp = lb_emit_struct_ep(p, ptr, 2);
+ lbValue wp = lb_emit_struct_ep(p, ptr, 3);
+
+ lbValue x = lb_emit_conv(p, lb_emit_load(p, xp), t_f64);
+ lbValue y = lb_emit_conv(p, lb_emit_load(p, yp), t_f64);
+ lbValue z = lb_emit_conv(p, lb_emit_load(p, zp), t_f64);
+ lbValue w = lb_emit_conv(p, lb_emit_load(p, wp), t_f64);
+
+ auto args = array_make<lbValue>(temporary_allocator(), 5);
+ args[0] = x;
+ args[1] = y;
+ args[2] = z;
+ args[3] = w;
+ args[4] = seed;
+ lbValue res = lb_emit_runtime_call(p, "default_hasher_quaternion256", args);
+ lb_add_callsite_force_inline(p, res);
+ LLVMBuildRet(p->builder, res.value);
} else {
GB_PANIC("Unhandled type for hasher: %s", type_to_string(type));
}
@@ -571,21 +625,15 @@ gb_internal lbValue lb_map_get_proc_for_type(lbModule *m, Type *type) {
type = base_type(type);
GB_ASSERT(type->kind == Type_Map);
-
- lbProcedure **found = map_get(&m->map_get_procs, type);
+ String proc_name = lb_internal_gen_name_from_type("__$map_get", type);
+ lbProcedure **found = string_map_get(&m->gen_procs, proc_name);
if (found) {
GB_ASSERT(*found != nullptr);
return {(*found)->value, (*found)->type};
}
- static std::atomic<u32> proc_index;
-
- char buf[32] = {};
- isize n = gb_snprintf(buf, 32, "__$map_get-%u", 1+proc_index.fetch_add(1));
- char *str = gb_alloc_str_len(permanent_allocator(), buf, n-1);
- String proc_name = make_string_c(str);
lbProcedure *p = lb_create_dummy_procedure(m, proc_name, t_map_get_proc);
- map_set(&m->map_get_procs, type, p);
+ string_map_set(&m->gen_procs, proc_name, p);
lb_begin_procedure_body(p);
defer (lb_end_procedure_body(p));
@@ -752,21 +800,15 @@ gb_internal lbValue lb_map_set_proc_for_type(lbModule *m, Type *type) {
type = base_type(type);
GB_ASSERT(type->kind == Type_Map);
-
- lbProcedure **found = map_get(&m->map_set_procs, type);
+ String proc_name = lb_internal_gen_name_from_type("__$map_set", type);
+ lbProcedure **found = string_map_get(&m->gen_procs, proc_name);
if (found) {
GB_ASSERT(*found != nullptr);
return {(*found)->value, (*found)->type};
}
- static std::atomic<u32> proc_index;
-
- char buf[32] = {};
- isize n = gb_snprintf(buf, 32, "__$map_set-%u", 1+proc_index.fetch_add(1));
- char *str = gb_alloc_str_len(permanent_allocator(), buf, n-1);
- String proc_name = make_string_c(str);
lbProcedure *p = lb_create_dummy_procedure(m, proc_name, t_map_set_proc);
- map_set(&m->map_set_procs, type, p);
+ string_map_set(&m->gen_procs, proc_name, p);
lb_begin_procedure_body(p);
defer (lb_end_procedure_body(p));
@@ -911,7 +953,7 @@ gb_internal lbValue lb_gen_map_cell_info_ptr(lbModule *m, Type *type) {
LLVMValueRef llvm_res = llvm_const_named_struct(m, t_map_cell_info, const_values, gb_count_of(const_values));
lbValue res = {llvm_res, t_map_cell_info};
- lbAddr addr = lb_add_global_generated(m, t_map_cell_info, res, nullptr);
+ lbAddr addr = lb_add_global_generated_with_name(m, t_map_cell_info, res, lb_internal_gen_name_from_type("ggv$map_cell_info", type));
lb_make_global_private_const(addr);
map_set(&m->map_cell_info_map, type, addr);
@@ -942,7 +984,7 @@ gb_internal lbValue lb_gen_map_info_ptr(lbModule *m, Type *map_type) {
LLVMValueRef llvm_res = llvm_const_named_struct(m, t_map_info, const_values, gb_count_of(const_values));
lbValue res = {llvm_res, t_map_info};
- lbAddr addr = lb_add_global_generated(m, t_map_info, res, nullptr);
+ lbAddr addr = lb_add_global_generated_with_name(m, t_map_info, res, lb_internal_gen_name_from_type("ggv$map_info", map_type));
lb_make_global_private_const(addr);
map_set(&m->map_info_map, map_type, addr);
@@ -1131,30 +1173,680 @@ gb_internal lbProcedure *lb_create_objc_names(lbModule *main_module) {
return p;
}
-gb_internal void lb_finalize_objc_names(lbProcedure *p) {
+String lb_get_objc_type_encoding(Type *t, isize pointer_depth = 0) {
+ // NOTE(harold): See https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html#//apple_ref/doc/uid/TP40008048-CH100
+
+ // NOTE(harold): Darwin targets are always 64-bit. Should we drop this and assume "q" always?
+ #define INT_SIZE_ENCODING (build_context.metrics.int_size == 4 ? "i" : "q")
+ switch (t->kind) {
+ case Type_Basic: {
+ switch (t->Basic.kind) {
+ case Basic_Invalid:
+ return str_lit("?");
+
+ case Basic_llvm_bool:
+ case Basic_bool:
+ case Basic_b8:
+ return str_lit("B");
+
+ case Basic_b16:
+ return str_lit("C");
+ case Basic_b32:
+ return str_lit("I");
+ case Basic_b64:
+ return str_lit("q");
+ case Basic_i8:
+ return str_lit("c");
+ case Basic_u8:
+ return str_lit("C");
+ case Basic_i16:
+ case Basic_i16le:
+ case Basic_i16be:
+ return str_lit("s");
+ case Basic_u16:
+ case Basic_u16le:
+ case Basic_u16be:
+ return str_lit("S");
+ case Basic_i32:
+ case Basic_i32le:
+ case Basic_i32be:
+ return str_lit("i");
+ case Basic_u32le:
+ case Basic_u32:
+ case Basic_u32be:
+ return str_lit("I");
+ case Basic_i64:
+ case Basic_i64le:
+ case Basic_i64be:
+ return str_lit("q");
+ case Basic_u64:
+ case Basic_u64le:
+ case Basic_u64be:
+ return str_lit("Q");
+ case Basic_i128:
+ case Basic_i128le:
+ case Basic_i128be:
+ return str_lit("t");
+ case Basic_u128:
+ case Basic_u128le:
+ case Basic_u128be:
+ return str_lit("T");
+ case Basic_rune:
+ return str_lit("I");
+ case Basic_f16:
+ case Basic_f16le:
+ case Basic_f16be:
+ return str_lit("s"); // @harold: Closest we've got?
+ case Basic_f32:
+ case Basic_f32le:
+ case Basic_f32be:
+ return str_lit("f");
+ case Basic_f64:
+ case Basic_f64le:
+ case Basic_f64be:
+ return str_lit("d");
+
+ case Basic_complex32: return str_lit("{complex32=ss}"); // No f16 encoding, so fallback to i16, as above in Basic_f16*
+ case Basic_complex64: return str_lit("{complex64=ff}");
+ case Basic_complex128: return str_lit("{complex128=dd}");
+ case Basic_quaternion64: return str_lit("{quaternion64=ssss}");
+ case Basic_quaternion128: return str_lit("{quaternion128=ffff}");
+ case Basic_quaternion256: return str_lit("{quaternion256=dddd}");
+
+ case Basic_int:
+ return str_lit(INT_SIZE_ENCODING);
+ case Basic_uint:
+ return build_context.metrics.int_size == 4 ? str_lit("I") : str_lit("Q");
+ case Basic_uintptr:
+ case Basic_rawptr:
+ return str_lit("^v");
+
+ case Basic_string:
+ return build_context.metrics.int_size == 4 ? str_lit("{string=*i}") : str_lit("{string=*q}");
+
+ case Basic_cstring: return str_lit("*");
+ case Basic_any: return str_lit("{any=^v^v}"); // rawptr + ^Type_Info
+
+ case Basic_typeid:
+ GB_ASSERT(t->Basic.size == 8);
+ return str_lit("q");
+
+ // Untyped types
+ case Basic_UntypedBool:
+ case Basic_UntypedInteger:
+ case Basic_UntypedFloat:
+ case Basic_UntypedComplex:
+ case Basic_UntypedQuaternion:
+ case Basic_UntypedString:
+ case Basic_UntypedRune:
+ case Basic_UntypedNil:
+ case Basic_UntypedUninit:
+ GB_PANIC("Untyped types cannot be @encoded()");
+ return str_lit("?");
+ }
+ break;
+ }
+
+ case Type_Named:
+ case Type_Struct:
+ case Type_Union: {
+ Type* base = t;
+ if (base->kind == Type_Named) {
+ base = base_type(base);
+ if(base->kind != Type_Struct && base->kind != Type_Union) {
+ return lb_get_objc_type_encoding(base, pointer_depth);
+ }
+ }
+
+ const bool is_union = base->kind == Type_Union;
+ if (!is_union) {
+ // Check for objc_SEL
+ if (internal_check_is_assignable_to(base, t_objc_SEL)) {
+ return str_lit(":");
+ }
+
+ // Check for objc_Class
+ if (internal_check_is_assignable_to(base, t_objc_SEL)) {
+ return str_lit("#");
+ }
+
+ // Treat struct as an Objective-C Class?
+ if (has_type_got_objc_class_attribute(base) && pointer_depth == 0) {
+ return str_lit("#");
+ }
+ }
+
+ if (is_type_objc_object(base)) {
+ return str_lit("@");
+ }
+
+
+ gbString s = gb_string_make_reserve(temporary_allocator(), 16);
+ s = gb_string_append_length(s, is_union ? "(" :"{", 1);
+ if (t->kind == Type_Named) {
+ s = gb_string_append_length(s, t->Named.name.text, t->Named.name.len);
+ }
+
+ // Write fields
+ if (pointer_depth < 2) {
+ s = gb_string_append_length(s, "=", 1);
+
+ if (!is_union) {
+ for( auto& f : base->Struct.fields ) {
+ String field_type = lb_get_objc_type_encoding(f->type, pointer_depth);
+ s = gb_string_append_length(s, field_type.text, field_type.len);
+ }
+ } else {
+ for( auto& v : base->Union.variants ) {
+ String variant_type = lb_get_objc_type_encoding(v, pointer_depth);
+ s = gb_string_append_length(s, variant_type.text, variant_type.len);
+ }
+ }
+ }
+
+ s = gb_string_append_length(s, is_union ? ")" :"}", 1);
+
+ return make_string_c(s);
+ }
+
+ case Type_Generic:
+ GB_PANIC("Generic types cannot be @encoded()");
+ return str_lit("?");
+
+ case Type_Pointer: {
+ String pointee = lb_get_objc_type_encoding(t->Pointer.elem, pointer_depth +1);
+ // Special case for Objective-C Objects
+ if (pointer_depth == 0 && pointee == "@") {
+ return pointee;
+ }
+
+ return concatenate_strings(temporary_allocator(), str_lit("^"), pointee);
+ }
+
+ case Type_MultiPointer:
+ return concatenate_strings(temporary_allocator(), str_lit("^"), lb_get_objc_type_encoding(t->Pointer.elem, pointer_depth +1));
+
+ case Type_Array: {
+ String type_str = lb_get_objc_type_encoding(t->Array.elem, pointer_depth);
+
+ gbString s = gb_string_make_reserve(temporary_allocator(), type_str.len + 8);
+ s = gb_string_append_fmt(s, "[%lld%.*s]", t->Array.count, LIT(type_str));
+ return make_string_c(s);
+ }
+
+ case Type_EnumeratedArray: {
+ String type_str = lb_get_objc_type_encoding(t->EnumeratedArray.elem, pointer_depth);
+
+ gbString s = gb_string_make_reserve(temporary_allocator(), type_str.len + 8);
+ s = gb_string_append_fmt(s, "[%lld%.*s]", t->EnumeratedArray.count, LIT(type_str));
+ return make_string_c(s);
+ }
+
+ case Type_Slice: {
+ String type_str = lb_get_objc_type_encoding(t->Slice.elem, pointer_depth);
+ gbString s = gb_string_make_reserve(temporary_allocator(), type_str.len + 8);
+ s = gb_string_append_fmt(s, "{slice=^%.*s%s}", LIT(type_str), INT_SIZE_ENCODING);
+ return make_string_c(s);
+ }
+
+ case Type_DynamicArray: {
+ String type_str = lb_get_objc_type_encoding(t->DynamicArray.elem, pointer_depth);
+ gbString s = gb_string_make_reserve(temporary_allocator(), type_str.len + 8);
+ s = gb_string_append_fmt(s, "{dynamic=^%.*s%s%sAllocator={?^v}}", LIT(type_str), INT_SIZE_ENCODING, INT_SIZE_ENCODING);
+ return make_string_c(s);
+ }
+
+ case Type_Map:
+ return str_lit("{^v^v{Allocator=?^v}}");
+ case Type_Enum:
+ return lb_get_objc_type_encoding(t->Enum.base_type, pointer_depth);
+ case Type_Tuple:
+ // NOTE(harold): Is this type allowed here?
+ return str_lit("?");
+ case Type_Proc:
+ return str_lit("?");
+ case Type_BitSet:
+ return lb_get_objc_type_encoding(t->BitSet.underlying, pointer_depth);
+
+ case Type_SimdVector: {
+ String type_str = lb_get_objc_type_encoding(t->SimdVector.elem, pointer_depth);
+ gbString s = gb_string_make_reserve(temporary_allocator(), type_str.len + 5);
+ gb_string_append_fmt(s, "[%lld%.*s]", t->SimdVector.count, LIT(type_str));
+ return make_string_c(s);
+ }
+
+ case Type_Matrix: {
+ String type_str = lb_get_objc_type_encoding(t->Matrix.elem, pointer_depth);
+ gbString s = gb_string_make_reserve(temporary_allocator(), type_str.len + 5);
+ i64 element_count = t->Matrix.column_count * t->Matrix.row_count;
+ gb_string_append_fmt(s, "[%lld%.*s]", element_count, LIT(type_str));
+ return make_string_c(s);
+ }
+
+ case Type_BitField:
+ return lb_get_objc_type_encoding(t->BitField.backing_type, pointer_depth);
+ case Type_SoaPointer: {
+ gbString s = gb_string_make_reserve(temporary_allocator(), 8);
+ s = gb_string_append_fmt(s, "{=^v%s}", INT_SIZE_ENCODING);
+ return make_string_c(s);
+ }
+
+ } // End switch t->kind
+ #undef INT_SIZE_ENCODING
+
+ GB_PANIC("Unreachable");
+ return str_lit("");
+}
+
+struct lbObjCGlobalClass {
+ lbObjCGlobal g;
+ lbValue class_value; // Local registered class value
+};
+
+gb_internal void lb_register_objc_thing(
+ StringSet &handled,
+ lbModule *m,
+ Array<lbValue> &args,
+ Array<lbObjCGlobalClass> &class_impls,
+ StringMap<lbObjCGlobalClass> &class_map,
+ lbProcedure *p,
+ lbObjCGlobal const &g,
+ char const *call
+) {
+ if (string_set_update(&handled, g.name)) {
+ return;
+ }
+
+ lbAddr addr = {};
+ lbValue *found = string_map_get(&m->members, g.global_name);
+ if (found) {
+ addr = lb_addr(*found);
+ } else {
+ lbValue v = {};
+ LLVMTypeRef t = lb_type(m, g.type);
+ v.value = LLVMAddGlobal(m->mod, t, g.global_name);
+ v.type = alloc_type_pointer(g.type);
+ addr = lb_addr(v);
+ LLVMSetInitializer(v.value, LLVMConstNull(t));
+ }
+
+ lbValue class_ptr = {};
+ lbValue class_name = lb_const_value(m, t_cstring, exact_value_string(g.name));
+
+ // If this class requires an implementation, save it for registration below.
+ if (g.class_impl_type != nullptr) {
+
+ // Make sure the superclass has been initialized before us
+ lbValue superclass_value = lb_const_nil(m, t_objc_Class);
+
+ auto &tn = g.class_impl_type->Named.type_name->TypeName;
+ Type *superclass = tn.objc_superclass;
+ if (superclass != nullptr) {
+ auto& superclass_global = string_map_must_get(&class_map, superclass->Named.type_name->TypeName.objc_class_name);
+ lb_register_objc_thing(handled, m, args, class_impls, class_map, p, superclass_global.g, call);
+ GB_ASSERT(superclass_global.class_value.value);
+
+ superclass_value = superclass_global.class_value;
+ }
+
+ args.count = 3;
+ args[0] = superclass_value;
+ args[1] = class_name;
+ args[2] = lb_const_int(m, t_uint, 0);
+ class_ptr = lb_emit_runtime_call(p, "objc_allocateClassPair", args);
+
+ array_add(&class_impls, lbObjCGlobalClass{g, class_ptr});
+ }
+ else {
+ args.count = 1;
+ args[0] = class_name;
+ class_ptr = lb_emit_runtime_call(p, call, args);
+ }
+
+ lb_addr_store(p, addr, class_ptr);
+
+ lbObjCGlobalClass* class_global = string_map_get(&class_map, g.name);
+ if (class_global != nullptr) {
+ class_global->class_value = class_ptr;
+ }
+}
+
+gb_internal void lb_finalize_objc_names(lbGenerator *gen, lbProcedure *p) {
if (p == nullptr) {
return;
}
lbModule *m = p->module;
+ GB_ASSERT(m == &p->module->gen->default_module);
TEMPORARY_ALLOCATOR_GUARD();
- auto args = array_make<lbValue>(temporary_allocator(), 1);
+ StringSet handled = {};
+ string_set_init(&handled);
+ defer (string_set_destroy(&handled));
+
+ auto args = array_make<lbValue>(temporary_allocator(), 3, 8);
+ auto class_impls = array_make<lbObjCGlobalClass>(temporary_allocator(), 0, 16);
+
+ // Register all class implementations unconditionally, even if not statically referenced
+ for (Entity *e = {}; mpsc_dequeue(&gen->info->objc_class_implementations, &e); /**/) {
+ GB_ASSERT(e->kind == Entity_TypeName && e->TypeName.objc_is_implementation);
+ lb_handle_objc_find_or_register_class(p, e->TypeName.objc_class_name, e->type);
+ }
+
+ // Ensure classes that have been implicitly referenced through
+ // the objc_superclass attribute have a global variable available for them.
+ TypeSet class_set{};
+ type_set_init(&class_set, gen->objc_classes.count+16);
+ defer (type_set_destroy(&class_set));
+
+ auto referenced_classes = array_make<lbObjCGlobal>(temporary_allocator());
+ for (lbObjCGlobal g = {}; mpsc_dequeue(&gen->objc_classes, &g); /**/) {
+ array_add(&referenced_classes, g);
+
+ Type *cls = g.class_impl_type;
+ while (cls) {
+ if (type_set_update(&class_set, cls)) {
+ break;
+ }
+ GB_ASSERT(cls->kind == Type_Named);
+
+ cls = cls->Named.type_name->TypeName.objc_superclass;
+ }
+ }
+
+ for (auto pair : class_set) {
+ auto& tn = pair.type->Named.type_name->TypeName;
+ Type *class_impl = !tn.objc_is_implementation ? nullptr : pair.type;
+ lb_handle_objc_find_or_register_class(p, tn.objc_class_name, class_impl);
+ }
+ for (lbObjCGlobal g = {}; mpsc_dequeue(&gen->objc_classes, &g); /**/) {
+ array_add( &referenced_classes, g );
+ }
+
+ // Add all class globals to a map so that we can look them up dynamically
+ // in order to resolve out-of-order because classes that are being implemented
+ // require their superclasses to be registered before them.
+ StringMap<lbObjCGlobalClass> global_class_map{};
+ string_map_init(&global_class_map, (usize)gen->objc_classes.count);
+ defer (string_map_destroy(&global_class_map));
+
+ for (lbObjCGlobal g :referenced_classes) {
+ string_map_set(&global_class_map, g.name, lbObjCGlobalClass{g});
+ }
LLVMSetLinkage(p->value, LLVMInternalLinkage);
lb_begin_procedure_body(p);
- for (auto const &entry : m->objc_classes) {
- String name = entry.key;
- args[0] = lb_const_value(m, t_cstring, exact_value_string(name));
- lbValue ptr = lb_emit_runtime_call(p, "objc_lookUpClass", args);
- lb_addr_store(p, entry.value, ptr);
+
+ // Register class globals, gathering classes that must be implemented
+ for (auto& kv : global_class_map) {
+ lb_register_objc_thing(handled, m, args, class_impls, global_class_map, p, kv.value.g, "objc_lookUpClass");
+ }
+
+ // Prefetch selectors for implemented methods so that they can also be registered.
+ for (const auto& cd : class_impls) {
+ auto& g = cd.g;
+ Type *class_type = g.class_impl_type;
+
+ Array<ObjcMethodData>* methods = map_get(&m->info->objc_method_implementations, class_type);
+ if (!methods) {
+ continue;
+ }
+
+ for (const ObjcMethodData& md : *methods) {
+ lb_handle_objc_find_or_register_selector(p, md.ac.objc_selector);
+ }
}
- for (auto const &entry : m->objc_selectors) {
- String name = entry.key;
- args[0] = lb_const_value(m, t_cstring, exact_value_string(name));
- lbValue ptr = lb_emit_runtime_call(p, "sel_registerName", args);
- lb_addr_store(p, entry.value, ptr);
+ // Now we can register all referenced selectors
+ for (lbObjCGlobal g = {}; mpsc_dequeue(&gen->objc_selectors, &g); /**/) {
+ lb_register_objc_thing(handled, m, args, class_impls, global_class_map, p, g, "sel_registerName");
+ }
+
+
+ // Emit method wrapper implementations and registration
+ auto wrapper_args = array_make<Type *>(temporary_allocator(), 2, 8);
+ auto get_context_args = array_make<lbValue>(temporary_allocator(), 1);
+
+
+ PtrMap<Type *, lbObjCGlobal> ivar_map{};
+ map_init(&ivar_map, gen->objc_ivars.count);
+
+ for (lbObjCGlobal g = {}; mpsc_dequeue(&gen->objc_ivars, &g); /**/) {
+ map_set(&ivar_map, g.class_impl_type, g);
+ }
+
+ for (const auto &cd : class_impls) {
+ auto &g = cd.g;
+ Type *class_type = g.class_impl_type;
+ Type *class_ptr_type = alloc_type_pointer(class_type);
+ lbValue class_value = cd.class_value;
+
+ Type *ivar_type = class_type->Named.type_name->TypeName.objc_ivar;
+
+ Entity *context_provider = class_type->Named.type_name->TypeName.objc_context_provider;
+ Type *contex_provider_self_ptr_type = nullptr;
+ Type *contex_provider_self_named_type = nullptr;
+ bool is_context_provider_ivar = false;
+ lbValue context_provider_proc_value{};
+
+ if (context_provider) {
+ context_provider_proc_value = lb_find_procedure_value_from_entity(m, context_provider);
+
+ contex_provider_self_ptr_type = base_type(context_provider->type->Proc.params->Tuple.variables[0]->type);
+ GB_ASSERT(contex_provider_self_ptr_type->kind == Type_Pointer);
+ contex_provider_self_named_type = base_named_type(type_deref(contex_provider_self_ptr_type));
+
+ is_context_provider_ivar = ivar_type != nullptr && internal_check_is_assignable_to(contex_provider_self_named_type, ivar_type);
+ }
+
+
+ Array<ObjcMethodData> *methods = map_get(&m->info->objc_method_implementations, class_type);
+ if (!methods) {
+ continue;
+ }
+
+ for (const ObjcMethodData &md : *methods) {
+ GB_ASSERT( md.proc_entity->kind == Entity_Procedure);
+ Type *method_type = md.proc_entity->type;
+
+ String proc_name = make_string_c("__$objc_method::");
+ proc_name = concatenate_strings(temporary_allocator(), proc_name, g.name);
+ proc_name = concatenate_strings(temporary_allocator(), proc_name, str_lit("::"));
+ proc_name = concatenate_strings( permanent_allocator(), proc_name, md.ac.objc_name);
+
+ wrapper_args.count = 2;
+ wrapper_args[0] = md.ac.objc_is_class_method ? t_objc_Class : class_ptr_type;
+ wrapper_args[1] = t_objc_SEL;
+
+ isize method_param_count = method_type->Proc.param_count;
+ isize method_param_offset = 0;
+
+ if (!md.ac.objc_is_class_method) {
+ GB_ASSERT(method_param_count >= 1);
+ method_param_count -= 1;
+ method_param_offset = 1;
+ }
+
+ for (isize i = 0; i < method_param_count; i++) {
+ array_add(&wrapper_args, method_type->Proc.params->Tuple.variables[method_param_offset+i]->type);
+ }
+
+ Type *wrapper_args_tuple = alloc_type_tuple_from_field_types(wrapper_args.data, wrapper_args.count, false, true);
+ Type *wrapper_results_tuple = nullptr;
+
+ if (method_type->Proc.result_count > 0) {
+ GB_ASSERT(method_type->Proc.result_count == 1);
+ wrapper_results_tuple = alloc_type_tuple_from_field_types(&method_type->Proc.results->Tuple.variables[0]->type, 1, false, true);
+ }
+
+ Type *wrapper_proc_type = alloc_type_proc(nullptr, wrapper_args_tuple, wrapper_args_tuple->Tuple.variables.count,
+ wrapper_results_tuple, method_type->Proc.result_count, false, ProcCC_CDecl);
+
+ lbProcedure *wrapper_proc = lb_create_dummy_procedure(m, proc_name, wrapper_proc_type);
+ lb_add_attribute_to_proc(wrapper_proc->module, wrapper_proc->value, "nounwind");
+
+ // Emit the wrapper
+ LLVMSetLinkage(wrapper_proc->value, LLVMExternalLinkage);
+ lb_begin_procedure_body(wrapper_proc);
+ {
+ if (method_type->Proc.calling_convention == ProcCC_Odin) {
+ GB_ASSERT(context_provider);
+
+ // Emit the get odin context call
+
+ get_context_args[0] = lbValue {
+ wrapper_proc->raw_input_parameters[0],
+ contex_provider_self_ptr_type,
+ };
+
+ if (is_context_provider_ivar) {
+ // The context provider takes the ivar's type.
+ // Emit an objc_ivar_get call and use that pointer for 'self' instead.
+ lbValue real_self {
+ wrapper_proc->raw_input_parameters[0],
+ class_ptr_type
+ };
+ get_context_args[0] = lb_handle_objc_ivar_for_objc_object_pointer(wrapper_proc, real_self);
+ }
+
+ lbValue context = lb_emit_call(wrapper_proc, context_provider_proc_value, get_context_args);
+ lbAddr context_addr = lb_addr(lb_address_from_load_or_generate_local(wrapper_proc, context));
+ lb_push_context_onto_stack(wrapper_proc, context_addr);
+ }
+
+
+ auto method_call_args = array_make<lbValue>(temporary_allocator(), method_param_count + method_param_offset);
+
+ if (!md.ac.objc_is_class_method) {
+ method_call_args[0] = lbValue {
+ wrapper_proc->raw_input_parameters[0],
+ class_ptr_type,
+ };
+ }
+
+ for (isize i = 0; i < method_param_count; i++) {
+ method_call_args[i+method_param_offset] = lbValue {
+ wrapper_proc->raw_input_parameters[i+2],
+ method_type->Proc.params->Tuple.variables[i+method_param_offset]->type,
+ };
+ }
+ lbValue method_proc_value = lb_find_procedure_value_from_entity(m, md.proc_entity);
+
+ // Call real procedure for method from here, passing the parameters expected, if any.
+ lbValue return_value = lb_emit_call(wrapper_proc, method_proc_value, method_call_args);
+
+ if (wrapper_results_tuple != nullptr) {
+ auto &result_var = method_type->Proc.results->Tuple.variables[0];
+ return_value = lb_emit_conv(wrapper_proc, return_value, result_var->type);
+ lb_build_return_stmt_internal(wrapper_proc, return_value, result_var->token.pos);
+ }
+ }
+ lb_end_procedure_body(wrapper_proc);
+
+
+ // Add the method to the class
+ String method_encoding = str_lit("v");
+ // TODO (harold): Checker must ensure that objc_methods have a single return value or none!
+ GB_ASSERT(method_type->Proc.result_count <= 1);
+ if (method_type->Proc.result_count != 0) {
+ method_encoding = lb_get_objc_type_encoding(method_type->Proc.results->Tuple.variables[0]->type);
+ }
+
+ if (!md.ac.objc_is_class_method) {
+ method_encoding = concatenate_strings(temporary_allocator(), method_encoding, str_lit("@:"));
+ } else {
+ method_encoding = concatenate_strings(temporary_allocator(), method_encoding, str_lit("#:"));
+ }
+
+ for (isize i = method_param_offset; i < method_param_count; i++) {
+ Type *param_type = method_type->Proc.params->Tuple.variables[i]->type;
+ String param_encoding = lb_get_objc_type_encoding(param_type);
+
+ method_encoding = concatenate_strings(temporary_allocator(), method_encoding, param_encoding);
+ }
+
+ // Emit method registration
+ lbAddr* sel_address = string_map_get(&m->objc_selectors, md.ac.objc_selector);
+ GB_ASSERT(sel_address);
+ lbValue selector_value = lb_addr_load(p, *sel_address);
+
+ args.count = 4;
+ args[0] = class_value; // Class
+ args[1] = selector_value; // SEL
+ args[2] = lbValue { wrapper_proc->value, wrapper_proc->type };
+ args[3] = lb_const_value(m, t_cstring, exact_value_string(method_encoding));
+
+ // TODO(harold): Emit check BOOL result and panic if false.
+ lb_emit_runtime_call(p, "class_addMethod", args);
+
+ } // End methods
+
+ // Add ivar if we have one
+ if (ivar_type != nullptr) {
+ // Register a single ivar for this class
+ Type *ivar_base = ivar_type->Named.base;
+
+ // @note(harold): The alignment is supposed to be passed as log2(alignment): https://developer.apple.com/documentation/objectivec/class_addivar(_:_:_:_:_:)?language=objc
+ const i64 size = type_size_of(ivar_base);
+ const i64 alignment = (i64)floor_log2((u64)type_align_of(ivar_base));
+
+ // NOTE(harold): I've opted to not emit the type encoding for ivars in order to keep the data private.
+ // If there is desire in the future to emit the type encoding for introspection through the Obj-C runtime,
+ // then perhaps an option can be added for it then.
+ // Should we pass the actual type encoding? Might not be ideal for obfuscation.
+ String ivar_name = str_lit("__$ivar");
+ String ivar_types = str_lit("{= }"); //lb_get_objc_type_encoding(ivar_type);
+ args.count = 5;
+ args[0] = class_value;
+ args[1] = lb_const_value(m, t_cstring, exact_value_string(ivar_name));
+ args[2] = lb_const_value(m, t_uint, exact_value_u64((u64)size));
+ args[3] = lb_const_value(m, t_u8, exact_value_u64((u64)alignment));
+ args[4] = lb_const_value(m, t_cstring, exact_value_string(ivar_types));
+ lb_emit_runtime_call(p, "class_addIvar", args);
+ }
+
+ // Complete the class registration
+ args.count = 1;
+ args[0] = class_value;
+ lb_emit_runtime_call(p, "objc_registerClassPair", args);
+ }
+
+ // Register ivar offsets for any `objc_ivar_get` expressions emitted.
+ for (auto const& kv : ivar_map) {
+ lbObjCGlobal const& g = kv.value;
+ lbAddr ivar_addr = {};
+ lbValue *found = string_map_get(&m->members, g.global_name);
+
+ if (found) {
+ ivar_addr = lb_addr(*found);
+ GB_ASSERT(ivar_addr.addr.type == t_int_ptr);
+ } else {
+ // Defined in an external package, define it now in the main package
+ LLVMTypeRef t = lb_type(m, t_int);
+
+ lbValue global{};
+ global.value = LLVMAddGlobal(m->mod, t, g.global_name);
+ global.type = t_int_ptr;
+
+ LLVMSetInitializer(global.value, LLVMConstInt(t, 0, true));
+
+ ivar_addr = lb_addr(global);
+ }
+
+ String class_name = g.class_impl_type->Named.type_name->TypeName.objc_class_name;
+ lbValue class_value = string_map_must_get(&global_class_map, class_name).class_value;
+
+ args.count = 2;
+ args[0] = class_value;
+ args[1] = lb_const_value(m, t_cstring, exact_value_string(str_lit("__$ivar")));
+ lbValue ivar = lb_emit_runtime_call(p, "class_getInstanceVariable", args);
+
+ args.count = 1;
+ args[0] = ivar;
+ lbValue ivar_offset = lb_emit_runtime_call(p, "ivar_getOffset", args);
+ lbValue ivar_offset_int = lb_emit_conv(p, ivar_offset, t_int);
+
+ lb_addr_store(p, ivar_addr, ivar_offset_int);
}
lb_end_procedure_body(p);
@@ -1215,6 +1907,10 @@ gb_internal lbProcedure *lb_create_startup_runtime(lbModule *main_module, lbProc
lb_add_attribute_to_proc(p->module, p->value, "optnone");
lb_add_attribute_to_proc(p->module, p->value, "noinline");
+ // Make sure shared libraries call their own runtime startup on Linux.
+ LLVMSetVisibility(p->value, LLVMHiddenVisibility);
+ LLVMSetLinkage(p->value, LLVMWeakAnyLinkage);
+
lb_begin_procedure_body(p);
lb_setup_type_info_data(main_module);
@@ -1278,14 +1974,17 @@ gb_internal lbProcedure *lb_create_startup_runtime(lbModule *main_module, lbProc
if (is_type_any(t)) {
// NOTE(bill): Edge case for 'any' type
Type *var_type = default_type(var.init.type);
- lbAddr g = lb_add_global_generated(main_module, var_type, var.init);
+ gbString var_name = gb_string_make(permanent_allocator(), "__$global_any::");
+ gbString e_str = string_canonical_entity_name(temporary_allocator(), e);
+ var_name = gb_string_append_length(var_name, e_str, gb_strlen(e_str));
+ lbAddr g = lb_add_global_generated_with_name(main_module, var_type, {}, make_string_c(var_name));
lb_addr_store(p, g, var.init);
lbValue gp = lb_addr_get_ptr(p, g);
lbValue data = lb_emit_struct_ep(p, var.var, 0);
lbValue ti = lb_emit_struct_ep(p, var.var, 1);
lb_emit_store(p, data, lb_emit_conv(p, gp, t_rawptr));
- lb_emit_store(p, ti, lb_type_info(p, var_type));
+ lb_emit_store(p, ti, lb_typeid(p->module, var_type));
} else {
LLVMTypeRef vt = llvm_addr_type(p->module, var.var);
lbValue src0 = lb_emit_conv(p, var.init, t);
@@ -1321,6 +2020,10 @@ gb_internal lbProcedure *lb_create_cleanup_runtime(lbModule *main_module) { // C
lb_add_attribute_to_proc(p->module, p->value, "optnone");
lb_add_attribute_to_proc(p->module, p->value, "noinline");
+ // Make sure shared libraries call their own runtime cleanup on Linux.
+ LLVMSetVisibility(p->value, LLVMHiddenVisibility);
+ LLVMSetLinkage(p->value, LLVMWeakAnyLinkage);
+
lb_begin_procedure_body(p);
CheckerInfo *info = main_module->gen->info;
@@ -1395,7 +2098,7 @@ gb_internal void lb_create_global_procedures_and_types(lbGenerator *gen, Checker
break;
case Entity_Constant:
if (build_context.ODIN_DEBUG) {
- add_debug_info_for_global_constant_from_entity(gen, e);
+ lb_add_debug_info_for_global_constant_from_entity(gen, e);
}
break;
}
@@ -1557,21 +2260,13 @@ gb_internal WORKER_TASK_PROC(lb_llvm_function_pass_per_module) {
}
}
- for (auto const &entry : m->equal_procs) {
- lbProcedure *p = entry.value;
- lb_llvm_function_pass_per_function_internal(m, p);
- }
- for (auto const &entry : m->hasher_procs) {
- lbProcedure *p = entry.value;
- lb_llvm_function_pass_per_function_internal(m, p);
- }
- for (auto const &entry : m->map_get_procs) {
+ for (auto const &entry : m->gen_procs) {
lbProcedure *p = entry.value;
- lb_llvm_function_pass_per_function_internal(m, p, lbFunctionPassManager_none);
- }
- for (auto const &entry : m->map_set_procs) {
- lbProcedure *p = entry.value;
- lb_llvm_function_pass_per_function_internal(m, p, lbFunctionPassManager_none);
+ if (string_starts_with(p->name, str_lit("__$map"))) {
+ lb_llvm_function_pass_per_function_internal(m, p, lbFunctionPassManager_none);
+ } else {
+ lb_llvm_function_pass_per_function_internal(m, p);
+ }
}
return 0;
@@ -1601,797 +2296,7 @@ gb_internal WORKER_TASK_PROC(lb_llvm_module_pass_worker_proc) {
LLVMPassBuilderOptionsRef pb_options = LLVMCreatePassBuilderOptions();
defer (LLVMDisposePassBuilderOptions(pb_options));
- switch (build_context.optimization_level) {
- case -1:
- array_add(&passes, "function(annotation-remarks)");
- break;
- case 0:
- array_add(&passes, "always-inline");
- array_add(&passes, "function(annotation-remarks)");
- break;
- case 1:
-// default<Os>
-// Passes removed: coro, openmp, sroa
-#if LLVM_VERSION_MAJOR == 17
- array_add(&passes, u8R"(
-annotation2metadata,
-forceattrs,
-inferattrs,
-function<eager-inv>(
- lower-expect,
- simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;no-switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,
- early-cse<>
-),
-ipsccp,
-called-value-propagation,
-globalopt,
-function<eager-inv>(
- mem2reg,
- instcombine<max-iterations=1000;no-use-loop-info>,
- simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>
-),
-require<globals-aa>,
-function(
- invalidate<aa>
-),
-require<profile-summary>,
-cgscc(
- devirt<4>(
- inline<only-mandatory>,
- inline,
- function-attrs<skip-non-recursive>,
- function<eager-inv;no-rerun>(
- early-cse<memssa>,
- speculative-execution,
- jump-threading,
- correlated-propagation,
- simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,
- instcombine<max-iterations=1000;no-use-loop-info>,
- aggressive-instcombine,
- constraint-elimination,
- tailcallelim,
- simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,
- reassociate,
- loop-mssa(
- loop-instsimplify,
- loop-simplifycfg,
- licm<no-allowspeculation>,
- loop-rotate<header-duplication;no-prepare-for-lto>,
- licm<allowspeculation>,
- simple-loop-unswitch<no-nontrivial;trivial>
- ),
- simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,
- instcombine<max-iterations=1000;no-use-loop-info>,
- loop(
- loop-idiom,
- indvars,
- loop-deletion,
- loop-unroll-full
- ),
- vector-combine,
- mldst-motion<no-split-footer-bb>,
- gvn<>,
- sccp,
- bdce,
- instcombine<max-iterations=1000;no-use-loop-info>,
- jump-threading,
- correlated-propagation,
- adce,
- memcpyopt,
- dse,
- move-auto-init,
- loop-mssa(
- licm<allowspeculation>
- ),
- simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;hoist-common-insts;sink-common-insts;speculate-blocks;simplify-cond-branch>,
- instcombine<max-iterations=1000;no-use-loop-info>
- ),
- function-attrs,
- function(
- require<should-not-run-function-passes>
- )
- )
-),
-deadargelim,
-globalopt,
-globaldce,
-elim-avail-extern,
-rpo-function-attrs,
-recompute-globalsaa,
-function<eager-inv>(
- float2int,
- lower-constant-intrinsics,
- loop(
- loop-rotate<header-duplication;no-prepare-for-lto>,
- loop-deletion
- ),
- loop-distribute,
- inject-tli-mappings,
- loop-vectorize<no-interleave-forced-only;no-vectorize-forced-only;>,
- loop-load-elim,
- instcombine<max-iterations=1000;no-use-loop-info>,
- simplifycfg<bonus-inst-threshold=1;forward-switch-cond;switch-range-to-icmp;switch-to-lookup;no-keep-loops;hoist-common-insts;sink-common-insts;speculate-blocks;simplify-cond-branch>,
- slp-vectorizer,
- vector-combine,
- instcombine<max-iterations=1000;no-use-loop-info>,
- loop-unroll<O2>,
- transform-warning,
- instcombine<max-iterations=1000;no-use-loop-info>,
- loop-mssa(
- licm<allowspeculation>
- ),
- alignment-from-assumptions,
- loop-sink,
- instsimplify,
- div-rem-pairs,
- tailcallelim,
- simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>
-),
-globaldce,
-constmerge,
-cg-profile,
-rel-lookup-table-converter,
-function(
- annotation-remarks
-),
-verify
-)");
-#else
- array_add(&passes, u8R"(
-annotation2metadata,
-forceattrs,
-inferattrs,
-function<eager-inv>(
- lower-expect,
- simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;no-switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,
- sroa<modify-cfg>,
- early-cse<>
-),
-ipsccp,
-called-value-propagation,
-globalopt,
-function<eager-inv>(
- mem2reg,
- instcombine<max-iterations=1;no-use-loop-info;no-verify-fixpoint>,
- simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>
-),
-always-inline,
-require<globals-aa>,
-function(
- invalidate<aa>
-),
-require<profile-summary>,
-cgscc(
- devirt<4>(
- inline,
- function-attrs<skip-non-recursive-function-attrs>,
- function<eager-inv;no-rerun>(
- sroa<modify-cfg>,
- early-cse<memssa>,
- speculative-execution<only-if-divergent-target>,
- jump-threading,
- correlated-propagation,
- simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,
- instcombine<max-iterations=1;no-use-loop-info;no-verify-fixpoint>,
- aggressive-instcombine,
- tailcallelim,
- simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,
- reassociate,
- constraint-elimination,
- loop-mssa(
- loop-instsimplify,
- loop-simplifycfg,
- licm<no-allowspeculation>,
- loop-rotate<header-duplication;no-prepare-for-lto>,
- licm<allowspeculation>,
- simple-loop-unswitch<no-nontrivial;trivial>
- ),
- simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,
- instcombine<max-iterations=1;no-use-loop-info;no-verify-fixpoint>,
- loop(
- loop-idiom,
- indvars,
- loop-deletion,
- loop-unroll-full
- ),
- sroa<modify-cfg>,
- vector-combine,
- mldst-motion<no-split-footer-bb>,
- gvn<>,
- sccp,
- bdce,
- instcombine<max-iterations=1;no-use-loop-info;no-verify-fixpoint>,
- jump-threading,
- correlated-propagation,
- adce,
- memcpyopt,
- dse,
- move-auto-init,
- loop-mssa(
- licm<allowspeculation>
- ),
- simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;hoist-common-insts;sink-common-insts;speculate-blocks;simplify-cond-branch>,
- instcombine<max-iterations=1;no-use-loop-info;no-verify-fixpoint>
- ),
- function-attrs,
- function(
- require<should-not-run-function-passes>
- )
- )
-),
-deadargelim,
-globalopt,
-globaldce,
-elim-avail-extern,
-rpo-function-attrs,
-recompute-globalsaa,
-function<eager-inv>(
- float2int,
- lower-constant-intrinsics,
- loop(
- loop-rotate<header-duplication;no-prepare-for-lto>,
- loop-deletion
- ),
- loop-distribute,
- inject-tli-mappings,
- loop-vectorize<no-interleave-forced-only;no-vectorize-forced-only;>,
- infer-alignment,
- loop-load-elim,
- instcombine<max-iterations=1;no-use-loop-info;no-verify-fixpoint>,
- simplifycfg<bonus-inst-threshold=1;forward-switch-cond;switch-range-to-icmp;switch-to-lookup;no-keep-loops;hoist-common-insts;sink-common-insts;speculate-blocks;simplify-cond-branch>,
- slp-vectorizer,
- vector-combine,
- instcombine<max-iterations=1;no-use-loop-info;no-verify-fixpoint>,
- loop-unroll<O2>,
- transform-warning,
- sroa<preserve-cfg>,
- infer-alignment,
- instcombine<max-iterations=1;no-use-loop-info;no-verify-fixpoint>,
- loop-mssa(
- licm<allowspeculation>
- ),
- alignment-from-assumptions,
- loop-sink,
- instsimplify,
- div-rem-pairs,
- tailcallelim,
- simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>
-),
-globaldce,
-constmerge,
-cg-profile,
-rel-lookup-table-converter,
-function(
- annotation-remarks
-),
-verify
-)");
-#endif
- break;
-// default<O2>
-// Passes removed: coro, openmp, sroa
- case 2:
-#if LLVM_VERSION_MAJOR == 17
- array_add(&passes, u8R"(
-annotation2metadata,
-forceattrs,
-inferattrs,
-function<eager-inv>(
- lower-expect,
- simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;no-switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,
- early-cse<>
-),
-ipsccp,
-called-value-propagation,
-globalopt,
-function<eager-inv>(
- mem2reg,
- instcombine<max-iterations=1000;no-use-loop-info>,
- simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>
-),
-require<globals-aa>,
-function(
- invalidate<aa>
-),
-require<profile-summary>,
-cgscc(
- devirt<4>(
- inline<only-mandatory>,
- inline,
- function-attrs<skip-non-recursive>,
- function<eager-inv;no-rerun>(
- early-cse<memssa>,
- speculative-execution,
- jump-threading,
- correlated-propagation,
- simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,
- instcombine<max-iterations=1000;no-use-loop-info>,
- aggressive-instcombine,
- constraint-elimination,
- libcalls-shrinkwrap,
- tailcallelim,
- simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,
- reassociate,
- loop-mssa(
- loop-instsimplify,
- loop-simplifycfg,
- licm<no-allowspeculation>,
- loop-rotate<header-duplication;no-prepare-for-lto>,
- licm<allowspeculation>,
- simple-loop-unswitch<no-nontrivial;trivial>
- ),
- simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,
- instcombine<max-iterations=1000;no-use-loop-info>,
- loop(
- loop-idiom,
- indvars,
- loop-deletion,
- loop-unroll-full
- ),
- vector-combine,
- mldst-motion<no-split-footer-bb>,
- gvn<>,
- sccp,
- bdce,
- instcombine<max-iterations=1000;no-use-loop-info>,
- jump-threading,
- correlated-propagation,
- adce,
- memcpyopt,
- dse,
- move-auto-init,
- loop-mssa(
- licm<allowspeculation>
- ),
- simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;hoist-common-insts;sink-common-insts;speculate-blocks;simplify-cond-branch>,
- instcombine<max-iterations=1000;no-use-loop-info>
- ),
- function-attrs,
- function(
- require<should-not-run-function-passes>
- )
- )
-),
-deadargelim,
-globalopt,
-globaldce,
-elim-avail-extern,
-rpo-function-attrs,
-recompute-globalsaa,
-function<eager-inv>(
- float2int,
- lower-constant-intrinsics,
- loop(
- loop-rotate<header-duplication;no-prepare-for-lto>,
- loop-deletion
- ),
- loop-distribute,
- inject-tli-mappings,
- loop-vectorize<no-interleave-forced-only;no-vectorize-forced-only;>,
- loop-load-elim,
- instcombine<max-iterations=1000;no-use-loop-info>,
- simplifycfg<bonus-inst-threshold=1;forward-switch-cond;switch-range-to-icmp;switch-to-lookup;no-keep-loops;hoist-common-insts;sink-common-insts;speculate-blocks;simplify-cond-branch>,
- slp-vectorizer,
- vector-combine,
- instcombine<max-iterations=1000;no-use-loop-info>,
- loop-unroll<O2>,
- transform-warning,
- instcombine<max-iterations=1000;no-use-loop-info>,
- loop-mssa(
- licm<allowspeculation>
- ),
- alignment-from-assumptions,
- loop-sink,
- instsimplify,
- div-rem-pairs,
- tailcallelim,
- simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>
-),
-globaldce,
-constmerge,
-cg-profile,
-rel-lookup-table-converter,
-function(
- annotation-remarks
-),
-verify
-)");
-#else
- array_add(&passes, u8R"(
-annotation2metadata,
-forceattrs,
-inferattrs,
-function<eager-inv>(
- lower-expect,
- simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;no-switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,
- sroa<modify-cfg>,
- early-cse<>
-),
-ipsccp,
-called-value-propagation,
-globalopt,
-function<eager-inv>(
- mem2reg,
- instcombine<max-iterations=1;no-use-loop-info;no-verify-fixpoint>,
- simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>
-),
-always-inline,
-require<globals-aa>,
-function(
- invalidate<aa>
-),
-require<profile-summary>,
-cgscc(
- devirt<4>(
- inline,
- function-attrs<skip-non-recursive-function-attrs>,
- function<eager-inv;no-rerun>(
- sroa<modify-cfg>,
- early-cse<memssa>,
- speculative-execution<only-if-divergent-target>,
- jump-threading,
- correlated-propagation,
- simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,
- instcombine<max-iterations=1;no-use-loop-info;no-verify-fixpoint>,
- aggressive-instcombine,
- libcalls-shrinkwrap,
- tailcallelim,
- simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,
- reassociate,
- constraint-elimination,
- loop-mssa(
- loop-instsimplify,
- loop-simplifycfg,
- licm<no-allowspeculation>,
- loop-rotate<header-duplication;no-prepare-for-lto>,
- licm<allowspeculation>,
- simple-loop-unswitch<no-nontrivial;trivial>
- ),
- simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,
- instcombine<max-iterations=1;no-use-loop-info;no-verify-fixpoint>,
- loop(
- loop-idiom,
- indvars,
- loop-deletion,
- loop-unroll-full
- ),
- sroa<modify-cfg>,
- vector-combine,
- mldst-motion<no-split-footer-bb>,
- gvn<>,
- sccp,
- bdce,
- instcombine<max-iterations=1;no-use-loop-info;no-verify-fixpoint>,
- jump-threading,
- correlated-propagation,
- adce,
- memcpyopt,
- dse,
- move-auto-init,
- loop-mssa(
- licm<allowspeculation>
- ),
- simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;hoist-common-insts;sink-common-insts;speculate-blocks;simplify-cond-branch>,
- instcombine<max-iterations=1;no-use-loop-info;no-verify-fixpoint>
- ),
- function-attrs,
- function(
- require<should-not-run-function-passes>
- )
- )
-),
-deadargelim,
-globalopt,
-globaldce,
-elim-avail-extern,
-rpo-function-attrs,
-recompute-globalsaa,
-function<eager-inv>(
- float2int,
- lower-constant-intrinsics,
- loop(
- loop-rotate<header-duplication;no-prepare-for-lto>,
- loop-deletion
- ),
- loop-distribute,
- inject-tli-mappings,
- loop-vectorize<no-interleave-forced-only;no-vectorize-forced-only;>,
- infer-alignment,
- loop-load-elim,
- instcombine<max-iterations=1;no-use-loop-info;no-verify-fixpoint>,
- simplifycfg<bonus-inst-threshold=1;forward-switch-cond;switch-range-to-icmp;switch-to-lookup;no-keep-loops;hoist-common-insts;sink-common-insts;speculate-blocks;simplify-cond-branch>,
- slp-vectorizer,
- vector-combine,
- instcombine<max-iterations=1;no-use-loop-info;no-verify-fixpoint>,
- loop-unroll<O2>,
- transform-warning,
- sroa<modify-cfg>,
- infer-alignment,
- instcombine<max-iterations=1;no-use-loop-info;no-verify-fixpoint>,
- loop-mssa(
- licm<allowspeculation>
- ),
- alignment-from-assumptions,
- loop-sink,
- instsimplify,
- div-rem-pairs,
- tailcallelim,
- simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>
-),
-globaldce,
-constmerge,
-cg-profile,
-rel-lookup-table-converter,
-function(
- annotation-remarks
-),
-verify
-)");
-#endif
- break;
-
- case 3:
-// default<O3>
-// Passes removed: coro, openmp, sroa
-#if LLVM_VERSION_MAJOR == 17
- array_add(&passes, u8R"(
-annotation2metadata,
-forceattrs,
-inferattrs,
-function<eager-inv>(
- lower-expect,
- simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;no-switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,
- early-cse<>,
- callsite-splitting
-),
-ipsccp,
-called-value-propagation,
-globalopt,
-function<eager-inv>(
- mem2reg,
- instcombine<max-iterations=1000;no-use-loop-info>,
- simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>
-),
-require<globals-aa>,
-function(
- invalidate<aa>
-),
-require<profile-summary>,
-cgscc(
- devirt<4>(
- inline<only-mandatory>,
- inline,
- function-attrs<skip-non-recursive>,
- argpromotion,
- function<eager-inv;no-rerun>(
- early-cse<memssa>,
- speculative-execution,
- jump-threading,
- correlated-propagation,
- simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,
- instcombine<max-iterations=1000;no-use-loop-info>,
- aggressive-instcombine,
- constraint-elimination,
- libcalls-shrinkwrap,
- tailcallelim,
- simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,
- reassociate,
- loop-mssa(
- loop-instsimplify,
- loop-simplifycfg,
- licm<no-allowspeculation>,
- loop-rotate<header-duplication;no-prepare-for-lto>,
- licm<allowspeculation>,
- simple-loop-unswitch<nontrivial;trivial>
- ),
- simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,
- instcombine<max-iterations=1000;no-use-loop-info>,
- loop(
- loop-idiom,
- indvars,
- loop-deletion,
- loop-unroll-full
- ),
- vector-combine,
- mldst-motion<no-split-footer-bb>,
- gvn<>,
- sccp,
- bdce,
- instcombine<max-iterations=1000;no-use-loop-info>,
- jump-threading,
- correlated-propagation,
- adce,
- memcpyopt,
- dse,
- move-auto-init,
- loop-mssa(
- licm<allowspeculation>
- ),
- simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;hoist-common-insts;sink-common-insts;speculate-blocks;simplify-cond-branch>,
- instcombine<max-iterations=1000;no-use-loop-info>
- ),
- function-attrs,
- function(
- require<should-not-run-function-passes>
- )
- )
-),
-deadargelim,
-globalopt,
-globaldce,
-elim-avail-extern,
-rpo-function-attrs,
-recompute-globalsaa,
-function<eager-inv>(
- float2int,
- lower-constant-intrinsics,
- chr,
- loop(
- loop-rotate<header-duplication;no-prepare-for-lto>,
- loop-deletion
- ),
- loop-distribute,
- inject-tli-mappings,
- loop-vectorize<no-interleave-forced-only;no-vectorize-forced-only;>,
- loop-load-elim,
- instcombine<max-iterations=1000;no-use-loop-info>,
- simplifycfg<bonus-inst-threshold=1;forward-switch-cond;switch-range-to-icmp;switch-to-lookup;no-keep-loops;hoist-common-insts;sink-common-insts;speculate-blocks;simplify-cond-branch>,
- slp-vectorizer,
- vector-combine,
- instcombine<max-iterations=1000;no-use-loop-info>,
- loop-unroll<O3>,
- transform-warning,
- instcombine<max-iterations=1000;no-use-loop-info>,
- loop-mssa(
- licm<allowspeculation>
- ),
- alignment-from-assumptions,
- loop-sink,
- instsimplify,
- div-rem-pairs,
- tailcallelim,
- simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>
-),
-globaldce,
-constmerge,
-cg-profile,
-rel-lookup-table-converter,
-function(
- annotation-remarks
-),
-verify
-)");
-#else
- array_add(&passes, u8R"(
-annotation2metadata,
-forceattrs,
-inferattrs,
-function<eager-inv>(
- lower-expect,
- simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;no-switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,
- sroa<modify-cfg>,
- early-cse<>,
- callsite-splitting
-),
-ipsccp,
-called-value-propagation,
-globalopt,
-function<eager-inv>(
- mem2reg,
- instcombine<max-iterations=1;no-use-loop-info;no-verify-fixpoint>,
- simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>
-),
-always-inline,
-require<globals-aa>,
-function(invalidate<aa>),
-require<profile-summary>,
-cgscc(
- devirt<4>(
- inline,
- function-attrs<skip-non-recursive-function-attrs>,
- argpromotion,
- function<eager-inv;no-rerun>(
- sroa<modify-cfg>,
- early-cse<memssa>,
- speculative-execution<only-if-divergent-target>,
- jump-threading,
- correlated-propagation,
- simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,
- instcombine<max-iterations=1;no-use-loop-info;no-verify-fixpoint>,
- aggressive-instcombine,
- libcalls-shrinkwrap,
- tailcallelim,
- simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,
- reassociate,
- constraint-elimination,
- loop-mssa(
- loop-instsimplify,
- loop-simplifycfg,
- licm<no-allowspeculation>,
- loop-rotate<header-duplication;no-prepare-for-lto>,
- licm<allowspeculation>,
- simple-loop-unswitch<nontrivial;trivial>
- ),
- simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,
- instcombine<max-iterations=1;no-use-loop-info;no-verify-fixpoint>,
- loop(
- loop-idiom,
- indvars,
- loop-deletion,
- loop-unroll-full
- ),
- sroa<modify-cfg>,
- vector-combine,
- mldst-motion<no-split-footer-bb>,
- gvn<>,
- sccp,
- bdce,
- instcombine<max-iterations=1;no-use-loop-info;no-verify-fixpoint>,
- jump-threading,
- correlated-propagation,
- adce,
- memcpyopt,
- dse,
- move-auto-init,
- loop-mssa(licm<allowspeculation>),
- simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;hoist-common-insts;sink-common-insts;speculate-blocks;simplify-cond-branch>,
- instcombine<max-iterations=1;no-use-loop-info;no-verify-fixpoint>
- ),
- function-attrs,
- function(
- require<should-not-run-function-passes>
- )
- )
-),
-deadargelim,
-globalopt,
-globaldce,
-elim-avail-extern,
-rpo-function-attrs,
-recompute-globalsaa,
-function<eager-inv>(
- float2int,
- lower-constant-intrinsics,
- chr,
- loop(
- loop-rotate<header-duplication;no-prepare-for-lto>,
- loop-deletion
- ),
- loop-distribute,
- inject-tli-mappings,
- loop-vectorize<no-interleave-forced-only;no-vectorize-forced-only;>,
- infer-alignment,
- loop-load-elim,
- instcombine<max-iterations=1;no-use-loop-info;no-verify-fixpoint>,
- simplifycfg<bonus-inst-threshold=1;forward-switch-cond;switch-range-to-icmp;switch-to-lookup;no-keep-loops;hoist-common-insts;sink-common-insts;speculate-blocks;simplify-cond-branch>,
- slp-vectorizer,
- vector-combine,
- instcombine<max-iterations=1;no-use-loop-info;no-verify-fixpoint>,
- loop-unroll<O3>,
- transform-warning,
- sroa<preserve-cfg>,
- infer-alignment,
- instcombine<max-iterations=1;no-use-loop-info;no-verify-fixpoint>,
- loop-mssa(licm<allowspeculation>),
- alignment-from-assumptions,
- loop-sink,
- instsimplify,
- div-rem-pairs,
- tailcallelim,
- simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>
-),
-globaldce,
-constmerge,
-cg-profile,
-rel-lookup-table-converter,
-function(
- annotation-remarks
-),
-verify
-)");
-#endif
- break;
- }
+ #include "llvm_backend_passes.cpp"
// asan - Linux, Darwin, Windows
// msan - linux
@@ -2569,17 +2474,16 @@ gb_internal String lb_filepath_ll_for_module(lbModule *m) {
build_context.build_paths[BuildPath_Output].name
);
- if (m->file) {
- char buf[32] = {};
- isize n = gb_snprintf(buf, gb_size_of(buf), "-%u", m->file->id);
- String suffix = make_string((u8 *)buf, n-1);
- path = concatenate_strings(permanent_allocator(), path, suffix);
- } else if (m->pkg) {
- path = concatenate3_strings(permanent_allocator(), path, STR_LIT("-"), m->pkg->name);
- } else if (USE_SEPARATE_MODULES) {
- path = concatenate_strings(permanent_allocator(), path, STR_LIT("-builtin"));
+ GB_ASSERT(m->module_name != nullptr);
+ String s = make_string_c(m->module_name);
+ String prefix = str_lit("odin_package-");
+ if (string_starts_with(s, prefix)) {
+ s.text += prefix.len;
+ s.len -= prefix.len;
}
- path = concatenate_strings(permanent_allocator(), path, STR_LIT(".ll"));
+
+ path = concatenate_strings(permanent_allocator(), path, s);
+ path = concatenate_strings(permanent_allocator(), s, STR_LIT(".ll"));
return path;
}
@@ -2600,57 +2504,38 @@ gb_internal String lb_filepath_obj_for_module(lbModule *m) {
gbString path = gb_string_make_length(heap_allocator(), basename.text, basename.len);
path = gb_string_appendc(path, "/");
- path = gb_string_append_length(path, name.text, name.len);
- if (m->file) {
- char buf[32] = {};
- isize n = gb_snprintf(buf, gb_size_of(buf), "-%u", m->file->id);
- String suffix = make_string((u8 *)buf, n-1);
- path = gb_string_append_length(path, suffix.text, suffix.len);
- } else if (m->pkg) {
- path = gb_string_appendc(path, "-");
- path = gb_string_append_length(path, m->pkg->name.text, m->pkg->name.len);
+ if (USE_SEPARATE_MODULES) {
+ GB_ASSERT(m->module_name != nullptr);
+ String s = make_string_c(m->module_name);
+ String prefix = str_lit("odin_package");
+ if (string_starts_with(s, prefix)) {
+ s.text += prefix.len;
+ s.len -= prefix.len;
+ }
+
+ path = gb_string_append_length(path, s.text, s.len);
+ } else {
+ path = gb_string_append_length(path, name.text, name.len);
}
if (use_temporary_directory) {
+ // NOTE(bill): this must be suffixed to ensure it is not conflicting with anything else in the temporary directory
path = gb_string_append_fmt(path, "-%p", m);
}
String ext = {};
if (build_context.build_mode == BuildMode_Assembly) {
- ext = STR_LIT(".S");
+ ext = STR_LIT("S");
+ } else if (build_context.build_mode == BuildMode_Object) {
+ // Allow a user override for the object extension.
+ ext = build_context.build_paths[BuildPath_Output].ext;
} else {
- if (is_arch_wasm()) {
- ext = STR_LIT(".wasm.o");
- } else {
- switch (build_context.metrics.os) {
- case TargetOs_windows:
- ext = STR_LIT(".obj");
- break;
- default:
- case TargetOs_darwin:
- case TargetOs_linux:
- case TargetOs_essence:
- ext = STR_LIT(".o");
- 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;
- }
- }
+ ext = infer_object_extension_from_build_context();
}
+ path = gb_string_append_length(path, ".", 1);
path = gb_string_append_length(path, ext.text, ext.len);
return make_string(cast(u8 *)path, gb_string_length(path));
@@ -2819,7 +2704,7 @@ gb_internal lbProcedure *lb_create_main_procedure(lbModule *m, lbProcedure *star
Type *t_Internal_Test = find_type_in_pkg(m->info, str_lit("testing"), str_lit("Internal_Test"));
Type *array_type = alloc_type_array(t_Internal_Test, m->info->testing_procedures.count);
Type *slice_type = alloc_type_slice(t_Internal_Test);
- lbAddr all_tests_array_addr = lb_add_global_generated(p->module, array_type, {});
+ lbAddr all_tests_array_addr = lb_add_global_generated_with_name(p->module, array_type, {}, str_lit("__$all_tests_array"));
lbValue all_tests_array = lb_addr_get_ptr(p, all_tests_array_addr);
LLVMValueRef indices[2] = {};
@@ -2833,8 +2718,8 @@ gb_internal lbProcedure *lb_create_main_procedure(lbModule *m, lbProcedure *star
if (testing_proc->pkg != nullptr) {
pkg_name = testing_proc->pkg->name;
}
- lbValue v_pkg = lb_find_or_add_entity_string(m, pkg_name);
- lbValue v_name = lb_find_or_add_entity_string(m, name);
+ lbValue v_pkg = lb_find_or_add_entity_string(m, pkg_name, false);
+ lbValue v_name = lb_find_or_add_entity_string(m, name, false);
lbValue v_proc = lb_find_procedure_value_from_entity(m, testing_proc);
indices[1] = LLVMConstInt(lb_type(m, t_int), testing_proc_index++, false);
@@ -2915,7 +2800,6 @@ gb_internal void lb_generate_procedure(lbModule *m, lbProcedure *p) {
p->is_done = true;
m->curr_procedure = nullptr;
}
- lb_end_procedure(p);
// Add Flags
if (p->entity && p->entity->kind == Entity_Procedure && p->entity->Procedure.is_memcpy_like) {
@@ -2966,13 +2850,24 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
LLVMInitializeWebAssemblyAsmParser();
LLVMInitializeWebAssemblyDisassembler();
break;
+ case TargetArch_riscv64:
+ LLVMInitializeRISCVTargetInfo();
+ LLVMInitializeRISCVTarget();
+ LLVMInitializeRISCVTargetMC();
+ LLVMInitializeRISCVAsmPrinter();
+ LLVMInitializeRISCVAsmParser();
+ LLVMInitializeRISCVDisassembler();
+ break;
+ case TargetArch_arm32:
+ LLVMInitializeARMTargetInfo();
+ LLVMInitializeARMTarget();
+ LLVMInitializeARMTargetMC();
+ LLVMInitializeARMAsmPrinter();
+ LLVMInitializeARMAsmParser();
+ LLVMInitializeARMDisassembler();
+ break;
default:
- LLVMInitializeAllTargetInfos();
- LLVMInitializeAllTargets();
- LLVMInitializeAllTargetMCs();
- LLVMInitializeAllAsmPrinters();
- LLVMInitializeAllAsmParsers();
- LLVMInitializeAllDisassemblers();
+ GB_PANIC("Unimplemented LLVM target initialization");
break;
}
@@ -3148,7 +3043,10 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
lbModule *m = default_module;
{ // Add type info data
- isize max_type_info_count = info->minimum_dependency_type_info_set.count+1;
+ // GB_ASSERT_MSG(info->minimum_dependency_type_info_index_map.count == info->type_info_types.count, "%tu vs %tu", info->minimum_dependency_type_info_index_map.count, info->type_info_types.count);
+
+ // isize max_type_info_count = info->minimum_dependency_type_info_index_map.count+1;
+ isize max_type_info_count = info->type_info_types_hash_map.count;
Type *t = alloc_type_array(t_type_info_ptr, max_type_info_count);
// IMPORTANT NOTE(bill): As LLVM does not have a union type, an array of unions cannot be initialized
@@ -3160,7 +3058,7 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
LLVMValueRef g = LLVMAddGlobal(m->mod, internal_llvm_type, LB_TYPE_INFO_DATA_NAME);
LLVMSetInitializer(g, LLVMConstNull(internal_llvm_type));
LLVMSetLinkage(g, USE_SEPARATE_MODULES ? LLVMExternalLinkage : LLVMInternalLinkage);
- LLVMSetUnnamedAddress(g, LLVMGlobalUnnamedAddr);
+ // LLVMSetUnnamedAddress(g, LLVMGlobalUnnamedAddr);
LLVMSetGlobalConstant(g, true);
lbValue value = {};
@@ -3176,7 +3074,11 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
isize count = 0;
isize offsets_extra = 0;
- for (Type *t : m->info->type_info_types) {
+ for (auto const &tt : m->info->type_info_types_hash_map) {
+ Type *t = tt.type;
+ if (t == nullptr) {
+ continue;
+ }
isize index = lb_type_info_index(m->info, t, false);
if (index < 0) {
continue;
@@ -3206,6 +3108,7 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
LLVMSetInitializer(g, LLVMConstNull(lb_type(m, t)));
LLVMSetLinkage(g, LLVMInternalLinkage);
lb_make_global_private_const(g);
+ lb_set_odin_rtti_section(g);
return lb_addr({g, alloc_type_pointer(t)});
};
@@ -3277,24 +3180,9 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
lbValue g = {};
g.value = LLVMAddGlobal(m->mod, lb_type(m, e->type), alloc_cstring(permanent_allocator(), name));
g.type = alloc_type_pointer(e->type);
- if (e->Variable.thread_local_model != "") {
- LLVMSetThreadLocal(g.value, true);
-
- String m = e->Variable.thread_local_model;
- LLVMThreadLocalMode mode = LLVMGeneralDynamicTLSModel;
- if (m == "default") {
- mode = LLVMGeneralDynamicTLSModel;
- } else if (m == "localdynamic") {
- mode = LLVMLocalDynamicTLSModel;
- } else if (m == "initialexec") {
- mode = LLVMInitialExecTLSModel;
- } else if (m == "localexec") {
- mode = LLVMLocalExecTLSModel;
- } else {
- GB_PANIC("Unhandled thread local mode %.*s", LIT(m));
- }
- LLVMSetThreadLocalMode(g.value, mode);
- }
+
+ lb_apply_thread_local_model(g.value, e->Variable.thread_local_model);
+
if (is_foreign) {
LLVMSetLinkage(g.value, LLVMExternalLinkage);
LLVMSetDLLStorageClass(g.value, LLVMDLLImportStorageClass);
@@ -3310,6 +3198,7 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
LLVMSetLinkage(g.value, USE_SEPARATE_MODULES ? LLVMWeakAnyLinkage : LLVMInternalLinkage);
}
lb_set_linkage_from_entity_flags(m, g.value, e->flags);
+ LLVMSetAlignment(g.value, cast(u32)type_align_of(e->type));
if (e->Variable.link_section.len > 0) {
LLVMSetSection(g.value, alloc_cstring(permanent_allocator(), e->Variable.link_section));
@@ -3324,12 +3213,16 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
if (!is_type_any(e->type) && !is_type_union(e->type)) {
if (tav.mode != Addressing_Invalid) {
if (tav.value.kind != ExactValue_Invalid) {
- bool is_rodata = e->kind == Entity_Variable && e->Variable.is_rodata;
+ auto cc = LB_CONST_CONTEXT_DEFAULT;
+ cc.is_rodata = e->kind == Entity_Variable && e->Variable.is_rodata;
+ cc.allow_local = false;
+ cc.link_section = e->Variable.link_section;
+
ExactValue v = tav.value;
- lbValue init = lb_const_value(m, tav.type, v, false, is_rodata);
+ lbValue init = lb_const_value(m, tav.type, v, cc);
LLVMSetInitializer(g.value, init.value);
var.is_initialized = true;
- if (is_rodata) {
+ if (cc.is_rodata) {
LLVMSetGlobalConstant(g.value, true);
}
}
@@ -3344,6 +3237,11 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
} else if (e->kind == Entity_Variable && e->Variable.is_rodata) {
LLVMSetGlobalConstant(g.value, true);
}
+
+ if (e->flags & EntityFlag_Require) {
+ lb_append_to_compiler_used(m, g.value);
+ }
+
array_add(&global_variables, var);
lb_add_entity(m, e, g);
@@ -3380,6 +3278,28 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
}
}
+ if (build_context.ODIN_DEBUG) {
+ // Custom `.raddbg` section for its debugger
+ if (build_context.metrics.os == TargetOs_windows) {
+ lbModule *m = default_module;
+ LLVMModuleRef mod = m->mod;
+ LLVMContextRef ctx = m->ctx;
+
+ {
+ LLVMTypeRef type = LLVMArrayType(LLVMInt8TypeInContext(ctx), 1);
+ LLVMValueRef global = LLVMAddGlobal(mod, type, "raddbg_is_attached_byte_marker");
+ LLVMSetInitializer(global, LLVMConstNull(type));
+ LLVMSetSection(global, ".raddbg");
+ }
+
+ if (gen->info->entry_point) {
+ String mangled_name = lb_get_entity_name(m, gen->info->entry_point);
+ char const *str = alloc_cstring(temporary_allocator(), mangled_name);
+ lb_add_raddbg_string(m, "entry_point: \"", str, "\"");
+ }
+ }
+ }
+
TIME_SECTION("LLVM Runtime Objective-C Names Creation");
gen->objc_names = lb_create_objc_names(default_module);
@@ -3393,7 +3313,7 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
if (build_context.ODIN_DEBUG) {
for (auto const &entry : builtin_pkg->scope->elements) {
Entity *e = entry.value;
- add_debug_info_for_global_constant_from_entity(gen, e);
+ lb_add_debug_info_for_global_constant_from_entity(gen, e);
}
}
@@ -3417,12 +3337,78 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
if (gen->objc_names) {
TIME_SECTION("Finalize objc names");
- lb_finalize_objc_names(gen->objc_names);
+ lb_finalize_objc_names(gen, gen->objc_names);
}
if (build_context.ODIN_DEBUG) {
TIME_SECTION("LLVM Debug Info Complete Types and Finalize");
lb_debug_info_complete_types_and_finalize(gen);
+
+ // Custom `.raddbg` section for its debugger
+ if (build_context.metrics.os == TargetOs_windows) {
+ lbModule *m = default_module;
+ LLVMModuleRef mod = m->mod;
+ LLVMContextRef ctx = m->ctx;
+
+ lb_add_raddbg_string(m, "type_view: {type: \"[]?\", expr: \"array(data, len)\"}");
+ lb_add_raddbg_string(m, "type_view: {type: \"string\", expr: \"array(data, len)\"}");
+
+ // column major matrices
+ lb_add_raddbg_string(m, "type_view: {type: \"matrix[1, ?]?\", expr: \"columns($.data, $[0])\"}");
+ lb_add_raddbg_string(m, "type_view: {type: \"matrix[2, ?]?\", expr: \"columns($.data, $[0], $[1])\"}");
+ lb_add_raddbg_string(m, "type_view: {type: \"matrix[3, ?]?\", expr: \"columns($.data, $[0], $[1], $[2])\"}");
+ lb_add_raddbg_string(m, "type_view: {type: \"matrix[4, ?]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3])\"}");
+ lb_add_raddbg_string(m, "type_view: {type: \"matrix[5, ?]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4])\"}");
+ lb_add_raddbg_string(m, "type_view: {type: \"matrix[6, ?]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5])\"}");
+ lb_add_raddbg_string(m, "type_view: {type: \"matrix[7, ?]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6])\"}");
+ lb_add_raddbg_string(m, "type_view: {type: \"matrix[8, ?]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7])\"}");
+ lb_add_raddbg_string(m, "type_view: {type: \"matrix[9, ?]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7], $[8])\"}");
+ lb_add_raddbg_string(m, "type_view: {type: \"matrix[10, ?]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7], $[8], $[9])\"}");
+ lb_add_raddbg_string(m, "type_view: {type: \"matrix[11, ?]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7], $[8], $[9], $[10])\"}");
+ lb_add_raddbg_string(m, "type_view: {type: \"matrix[12, ?]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7], $[8], $[9], $[10], $[11])\"}");
+ lb_add_raddbg_string(m, "type_view: {type: \"matrix[13, ?]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7], $[8], $[9], $[10], $[11], $[12])\"}");
+ lb_add_raddbg_string(m, "type_view: {type: \"matrix[14, ?]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7], $[8], $[9], $[10], $[11], $[12], $[13])\"}");
+ lb_add_raddbg_string(m, "type_view: {type: \"matrix[15, ?]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7], $[8], $[9], $[10], $[11], $[12], $[13], $[14])\"}");
+ lb_add_raddbg_string(m, "type_view: {type: \"matrix[16, ?]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7], $[8], $[9], $[10], $[11], $[12], $[13], $[14], $[15])\"}");
+
+ // row major matrices
+ lb_add_raddbg_string(m, "type_view: {type: \"#row_major matrix[?, 1]?\", expr: \"columns($.data, $[0])\"}");
+ lb_add_raddbg_string(m, "type_view: {type: \"#row_major matrix[?, 2]?\", expr: \"columns($.data, $[0], $[1])\"}");
+ lb_add_raddbg_string(m, "type_view: {type: \"#row_major matrix[?, 3]?\", expr: \"columns($.data, $[0], $[1], $[2])\"}");
+ lb_add_raddbg_string(m, "type_view: {type: \"#row_major matrix[?, 4]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3])\"}");
+ lb_add_raddbg_string(m, "type_view: {type: \"#row_major matrix[?, 5]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4])\"}");
+ lb_add_raddbg_string(m, "type_view: {type: \"#row_major matrix[?, 6]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5])\"}");
+ lb_add_raddbg_string(m, "type_view: {type: \"#row_major matrix[?, 7]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6])\"}");
+ lb_add_raddbg_string(m, "type_view: {type: \"#row_major matrix[?, 8]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7])\"}");
+ lb_add_raddbg_string(m, "type_view: {type: \"#row_major matrix[?, 9]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7], $[8])\"}");
+ lb_add_raddbg_string(m, "type_view: {type: \"#row_major matrix[?, 10]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7], $[8], $[9])\"}");
+ lb_add_raddbg_string(m, "type_view: {type: \"#row_major matrix[?, 11]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7], $[8], $[9], $[10])\"}");
+ lb_add_raddbg_string(m, "type_view: {type: \"#row_major matrix[?, 12]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7], $[8], $[9], $[10], $[11])\"}");
+ lb_add_raddbg_string(m, "type_view: {type: \"#row_major matrix[?, 13]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7], $[8], $[9], $[10], $[11], $[12])\"}");
+ lb_add_raddbg_string(m, "type_view: {type: \"#row_major matrix[?, 14]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7], $[8], $[9], $[10], $[11], $[12], $[13])\"}");
+ lb_add_raddbg_string(m, "type_view: {type: \"#row_major matrix[?, 15]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7], $[8], $[9], $[10], $[11], $[12], $[13], $[14])\"}");
+ lb_add_raddbg_string(m, "type_view: {type: \"#row_major matrix[?, 16]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7], $[8], $[9], $[10], $[11], $[12], $[13], $[14], $[15])\"}");
+
+
+ TEMPORARY_ALLOCATOR_GUARD();
+
+ u32 global_name_index = 0;
+ for (String str = {}; mpsc_dequeue(&gen->raddebug_section_strings, &str); /**/) {
+ LLVMValueRef data = LLVMConstStringInContext(ctx, cast(char const *)str.text, cast(unsigned)str.len, false);
+ LLVMTypeRef type = LLVMTypeOf(data);
+
+ gbString global_name = gb_string_make(temporary_allocator(), "raddbg_data__");
+ global_name = gb_string_append_fmt(global_name, "%u", global_name_index);
+ global_name_index += 1;
+
+ LLVMValueRef global = LLVMAddGlobal(mod, type, global_name);
+
+ LLVMSetInitializer(global, data);
+ LLVMSetAlignment(global, 1);
+
+ LLVMSetSection(global, ".raddbg");
+ }
+ }
}
if (do_threading) {
@@ -3505,36 +3491,48 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
if (build_context.sanitizer_flags & SanitizerFlag_Address) {
- if (build_context.metrics.os == TargetOs_windows) {
+ switch (build_context.metrics.os) {
+ case TargetOs_windows: {
auto paths = array_make<String>(heap_allocator(), 0, 1);
String path = concatenate_strings(permanent_allocator(), build_context.ODIN_ROOT, str_lit("\\bin\\llvm\\windows\\clang_rt.asan-x86_64.lib"));
array_add(&paths, path);
Entity *lib = alloc_entity_library_name(nullptr, make_token_ident("asan_lib"), nullptr, slice_from_array(paths), str_lit("asan_lib"));
array_add(&gen->foreign_libraries, lib);
- } else if (build_context.metrics.os == TargetOs_darwin || build_context.metrics.os == TargetOs_linux) {
+ } break;
+ case TargetOs_darwin:
+ case TargetOs_linux:
+ case TargetOs_freebsd:
if (!build_context.extra_linker_flags.text) {
build_context.extra_linker_flags = str_lit("-fsanitize=address");
} else {
build_context.extra_linker_flags = concatenate_strings(permanent_allocator(), build_context.extra_linker_flags, str_lit(" -fsanitize=address"));
}
+ break;
}
}
if (build_context.sanitizer_flags & SanitizerFlag_Memory) {
- if (build_context.metrics.os == TargetOs_darwin || build_context.metrics.os == TargetOs_linux) {
+ switch (build_context.metrics.os) {
+ case TargetOs_linux:
+ case TargetOs_freebsd:
if (!build_context.extra_linker_flags.text) {
build_context.extra_linker_flags = str_lit("-fsanitize=memory");
} else {
build_context.extra_linker_flags = concatenate_strings(permanent_allocator(), build_context.extra_linker_flags, str_lit(" -fsanitize=memory"));
}
+ break;
}
}
if (build_context.sanitizer_flags & SanitizerFlag_Thread) {
- if (build_context.metrics.os == TargetOs_darwin || build_context.metrics.os == TargetOs_linux) {
+ switch (build_context.metrics.os) {
+ case TargetOs_darwin:
+ case TargetOs_linux:
+ case TargetOs_freebsd:
if (!build_context.extra_linker_flags.text) {
build_context.extra_linker_flags = str_lit("-fsanitize=thread");
} else {
build_context.extra_linker_flags = concatenate_strings(permanent_allocator(), build_context.extra_linker_flags, str_lit(" -fsanitize=thread"));
}
+ break;
}
}
diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp
index 42d283a1e..fd6f50dcd 100644
--- a/src/llvm_backend.hpp
+++ b/src/llvm_backend.hpp
@@ -155,15 +155,17 @@ struct lbModule {
AstFile *file; // possibly associated
char const *module_name;
- PtrMap<Type *, LLVMTypeRef> types; // mutex: types_mutex
+ PtrMap<u64/*type hash*/, LLVMTypeRef> types; // mutex: types_mutex
PtrMap<void *, lbStructFieldRemapping> struct_field_remapping; // Key: LLVMTypeRef or Type *, mutex: types_mutex
- PtrMap<Type *, LLVMTypeRef> func_raw_types; // mutex: func_raw_types_mutex
- RecursiveMutex types_mutex;
- RecursiveMutex func_raw_types_mutex;
+ PtrMap<u64/*type hash*/, LLVMTypeRef> func_raw_types; // mutex: func_raw_types_mutex
+ RecursiveMutex types_mutex;
+ RecursiveMutex func_raw_types_mutex;
i32 internal_type_level;
RwMutex values_mutex;
+ std::atomic<u32> global_array_index;
+
PtrMap<Entity *, lbValue> values;
PtrMap<Entity *, lbAddr> soa_values;
StringMap<lbValue> members;
@@ -173,14 +175,9 @@ struct lbModule {
StringMap<LLVMValueRef> const_strings;
- PtrMap<Type *, struct lbFunctionType *> function_type_map;
+ PtrMap<u64/*type hash*/, struct lbFunctionType *> function_type_map;
- PtrMap<Type *, lbProcedure *> equal_procs;
- PtrMap<Type *, lbProcedure *> hasher_procs;
- PtrMap<Type *, lbProcedure *> map_get_procs;
- PtrMap<Type *, lbProcedure *> map_set_procs;
-
- std::atomic<u32> nested_type_name_guid;
+ StringMap<lbProcedure *> gen_procs; // key is the canonicalized name
Array<lbProcedure *> procedures_to_generate;
Array<Entity *> global_procedures_to_create;
@@ -196,11 +193,13 @@ struct lbModule {
RecursiveMutex debug_values_mutex;
PtrMap<void *, LLVMMetadataRef> debug_values;
+
StringMap<lbAddr> objc_classes;
StringMap<lbAddr> objc_selectors;
+ StringMap<lbAddr> objc_ivars;
- PtrMap<Type *, lbAddr> map_cell_info_map; // address of runtime.Map_Info
- PtrMap<Type *, lbAddr> map_info_map; // address of runtime.Map_Cell_Info
+ PtrMap<u64/*type hash*/, lbAddr> map_cell_info_map; // address of runtime.Map_Info
+ PtrMap<u64/*type hash*/, lbAddr> map_info_map; // address of runtime.Map_Cell_Info
PtrMap<Ast *, lbAddr> exact_value_compound_literal_addr_map; // Key: Ast_CompoundLit
@@ -216,6 +215,14 @@ struct lbEntityCorrection {
char const *cname;
};
+struct lbObjCGlobal {
+ lbModule *module;
+ gbString global_name;
+ String name;
+ Type * type;
+ Type * class_impl_type; // This is set when the class has the objc_implement attribute set to true.
+};
+
struct lbGenerator : LinkerData {
CheckerInfo *info;
@@ -226,9 +233,6 @@ struct lbGenerator : LinkerData {
RecursiveMutex anonymous_proc_lits_mutex;
PtrMap<Ast *, lbProcedure *> anonymous_proc_lits;
- std::atomic<u32> global_array_index;
- std::atomic<u32> global_generated_index;
-
isize used_module_count;
lbProcedure *startup_runtime;
@@ -236,6 +240,10 @@ struct lbGenerator : LinkerData {
lbProcedure *objc_names;
MPSCQueue<lbEntityCorrection> entities_to_correct_linkage;
+ MPSCQueue<lbObjCGlobal> objc_selectors;
+ MPSCQueue<lbObjCGlobal> objc_classes;
+ MPSCQueue<lbObjCGlobal> objc_ivars;
+ MPSCQueue<String> raddebug_section_strings;
};
@@ -359,6 +367,8 @@ struct lbProcedure {
bool in_multi_assignment;
Array<LLVMValueRef> raw_input_parameters;
+ u32 global_generated_index;
+
bool uses_branch_location;
TokenPos branch_location_pos;
TokenPos curr_token_pos;
@@ -377,6 +387,8 @@ struct lbProcedure {
PtrMap<Ast *, lbValue> selector_values;
PtrMap<Ast *, lbAddr> selector_addr;
PtrMap<LLVMValueRef, lbTupleFix> tuple_fix_map;
+
+ Array<lbValue> asan_stack_locals;
};
@@ -394,14 +406,13 @@ struct lbProcedure {
gb_internal bool lb_init_generator(lbGenerator *gen, Checker *c);
gb_internal String lb_mangle_name(Entity *e);
-gb_internal String lb_get_entity_name(lbModule *m, Entity *e, String name = {});
+gb_internal String lb_get_entity_name(lbModule *m, Entity *e);
gb_internal LLVMAttributeRef lb_create_enum_attribute(LLVMContextRef ctx, char const *name, u64 value=0);
gb_internal LLVMAttributeRef lb_create_enum_attribute_with_type(LLVMContextRef ctx, char const *name, LLVMTypeRef type);
gb_internal void lb_add_proc_attribute_at_index(lbProcedure *p, isize index, char const *name, u64 value);
gb_internal void lb_add_proc_attribute_at_index(lbProcedure *p, isize index, char const *name);
gb_internal lbProcedure *lb_create_procedure(lbModule *module, Entity *entity, bool ignore_body=false);
-gb_internal void lb_end_procedure(lbProcedure *p);
gb_internal LLVMTypeRef lb_type(lbModule *m, Type *type);
@@ -409,9 +420,19 @@ gb_internal LLVMTypeRef llvm_get_element_type(LLVMTypeRef type);
gb_internal lbBlock *lb_create_block(lbProcedure *p, char const *name, bool append=false);
+struct lbConstContext {
+ bool allow_local;
+ bool is_rodata;
+ String link_section;
+};
+
+static lbConstContext const LB_CONST_CONTEXT_DEFAULT = {true, false, {}};
+static lbConstContext const LB_CONST_CONTEXT_DEFAULT_ALLOW_LOCAL = {true, false, {}};
+static lbConstContext const LB_CONST_CONTEXT_DEFAULT_NO_LOCAL = {false, false, {}};
+
gb_internal lbValue lb_const_nil(lbModule *m, Type *type);
gb_internal lbValue lb_const_undef(lbModule *m, Type *type);
-gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_local=true, bool is_rodata=false);
+gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lbConstContext cc = LB_CONST_CONTEXT_DEFAULT);
gb_internal lbValue lb_const_bool(lbModule *m, Type *type, bool value);
gb_internal lbValue lb_const_int(lbModule *m, Type *type, u64 value);
@@ -468,7 +489,8 @@ gb_internal lbContextData *lb_push_context_onto_stack(lbProcedure *p, lbAddr ctx
gb_internal lbContextData *lb_push_context_onto_stack_from_implicit_parameter(lbProcedure *p);
-gb_internal lbAddr lb_add_global_generated(lbModule *m, Type *type, lbValue value={}, Entity **entity_=nullptr);
+gb_internal lbAddr lb_add_global_generated_from_procedure(lbProcedure *p, Type *type, lbValue value={});
+gb_internal lbAddr lb_add_global_generated_with_name(lbModule *m, Type *type, lbValue value, String name, Entity **entity_=nullptr);
gb_internal lbAddr lb_add_local(lbProcedure *p, Type *type, Entity *e=nullptr, bool zero_init=true, bool force_no_init=false);
gb_internal void lb_add_foreign_library_path(lbModule *m, Entity *e);
@@ -507,7 +529,7 @@ gb_internal void lb_fill_slice(lbProcedure *p, lbAddr const &slice, lbValue base
gb_internal lbValue lb_type_info(lbProcedure *p, Type *type);
-gb_internal lbValue lb_find_or_add_entity_string(lbModule *m, String const &str);
+gb_internal lbValue lb_find_or_add_entity_string(lbModule *m, String const &str, bool custom_link_section);
gb_internal lbValue lb_generate_anonymous_proc_lit(lbModule *m, String const &prefix_name, Ast *expr, lbProcedure *parent = nullptr);
gb_internal bool lb_is_const(lbValue value);
@@ -605,6 +627,9 @@ gb_internal LLVMTypeRef llvm_array_type(LLVMTypeRef ElementType, uint64_t Elemen
}
+gb_internal String lb_internal_gen_name_from_type(char const *prefix, Type *type);
+
+
gb_internal void lb_set_metadata_custom_u64(lbModule *m, LLVMValueRef v_ref, String name, u64 value);
gb_internal u64 lb_get_metadata_custom_u64(lbModule *m, LLVMValueRef v_ref, String name);
diff --git a/src/llvm_backend_const.cpp b/src/llvm_backend_const.cpp
index 754bbfca2..c3112934e 100644
--- a/src/llvm_backend_const.cpp
+++ b/src/llvm_backend_const.cpp
@@ -33,7 +33,7 @@ gb_internal bool lb_is_elem_const(Ast *elem, Type *elem_type) {
gb_internal bool lb_is_const_nil(lbValue value) {
LLVMValueRef v = value.value;
- if (LLVMIsConstant(v)) {
+ if (v != nullptr && LLVMIsConstant(v)) {
if (LLVMIsAConstantAggregateZero(v)) {
return true;
} else if (LLVMIsAConstantPointerNull(v)) {
@@ -292,19 +292,33 @@ gb_internal lbValue lb_const_source_code_location_const(lbModule *m, String cons
i32 line = pos.line;
i32 column = pos.column;
- if (build_context.obfuscate_source_code_locations) {
+ switch (build_context.source_code_location_info) {
+ case SourceCodeLocationInfo_Normal:
+ break;
+ case SourceCodeLocationInfo_Obfuscated:
file = obfuscate_string(file, "F");
procedure = obfuscate_string(procedure, "P");
- line = obfuscate_i32(line);
- column = obfuscate_i32(column);
+ line = obfuscate_i32(line);
+ column = obfuscate_i32(column);
+ break;
+ case SourceCodeLocationInfo_Filename:
+ file = last_path_element(file);
+ break;
+ case SourceCodeLocationInfo_None:
+ file = str_lit("");
+ procedure = str_lit("");
+
+ line = 0;
+ column = 0;
+ break;
}
LLVMValueRef fields[4] = {};
- fields[0]/*file*/ = lb_find_or_add_entity_string(m, file).value;
+ fields[0]/*file*/ = lb_find_or_add_entity_string(m, file, false).value;
fields[1]/*line*/ = lb_const_int(m, t_i32, line).value;
fields[2]/*column*/ = lb_const_int(m, t_i32, column).value;
- fields[3]/*procedure*/ = lb_find_or_add_entity_string(m, procedure).value;
+ fields[3]/*procedure*/ = lb_find_or_add_entity_string(m, procedure, false).value;
lbValue res = {};
res.value = llvm_const_named_struct(m, t_source_code_location, fields, gb_count_of(fields));
@@ -330,31 +344,57 @@ gb_internal lbValue lb_emit_source_code_location_const(lbProcedure *p, Ast *node
return lb_emit_source_code_location_const(p, proc_name, pos);
}
+gb_internal String lb_source_code_location_gen_name(String const &procedure, TokenPos const &pos) {
+ gbString s = gb_string_make(permanent_allocator(), "scl$[");
+
+ s = gb_string_append_length(s, procedure.text, procedure.len);
+ if (pos.offset != 0) {
+ s = gb_string_append_fmt(s, "%d", pos.offset);
+ } else {
+ s = gb_string_append_fmt(s, "%d_%d", pos.line, pos.column);
+ }
+ s = gb_string_appendc(s, "]");
+
+ return make_string(cast(u8 const *)s, gb_string_length(s));
+}
+
+gb_internal String lb_source_code_location_gen_name(lbProcedure *p, Ast *node) {
+ String proc_name = {};
+ if (p->entity) {
+ proc_name = p->entity->token.string;
+ }
+ TokenPos pos = {};
+ if (node) {
+ pos = ast_token(node).pos;
+ }
+ return lb_source_code_location_gen_name(proc_name, pos);
+}
+
+
gb_internal lbValue lb_emit_source_code_location_as_global_ptr(lbProcedure *p, String const &procedure, TokenPos const &pos) {
lbValue loc = lb_emit_source_code_location_const(p, procedure, pos);
- lbAddr addr = lb_add_global_generated(p->module, loc.type, loc, nullptr);
+ lbAddr addr = lb_add_global_generated_with_name(p->module, loc.type, loc, lb_source_code_location_gen_name(procedure, pos));
lb_make_global_private_const(addr);
return addr.addr;
}
gb_internal lbValue lb_const_source_code_location_as_global_ptr(lbModule *m, String const &procedure, TokenPos const &pos) {
lbValue loc = lb_const_source_code_location_const(m, procedure, pos);
- lbAddr addr = lb_add_global_generated(m, loc.type, loc, nullptr);
+ lbAddr addr = lb_add_global_generated_with_name(m, loc.type, loc, lb_source_code_location_gen_name(procedure, pos));
lb_make_global_private_const(addr);
return addr.addr;
}
-
-
-
gb_internal lbValue lb_emit_source_code_location_as_global_ptr(lbProcedure *p, Ast *node) {
lbValue loc = lb_emit_source_code_location_const(p, node);
- lbAddr addr = lb_add_global_generated(p->module, loc.type, loc, nullptr);
+ lbAddr addr = lb_add_global_generated_with_name(p->module, loc.type, loc, lb_source_code_location_gen_name(p, node));
lb_make_global_private_const(addr);
return addr.addr;
}
+
+
gb_internal lbValue lb_emit_source_code_location_as_global(lbProcedure *p, String const &procedure, TokenPos const &pos) {
return lb_emit_load(p, lb_emit_source_code_location_as_global_ptr(p, procedure, pos));
}
@@ -365,12 +405,12 @@ gb_internal lbValue lb_emit_source_code_location_as_global(lbProcedure *p, Ast *
-gb_internal LLVMValueRef lb_build_constant_array_values(lbModule *m, Type *type, Type *elem_type, isize count, LLVMValueRef *values, bool allow_local, bool is_rodata) {
- if (allow_local) {
- is_rodata = false;
+gb_internal LLVMValueRef lb_build_constant_array_values(lbModule *m, Type *type, Type *elem_type, isize count, LLVMValueRef *values, lbConstContext cc) {
+ if (cc.allow_local) {
+ cc.is_rodata = false;
}
- bool is_local = allow_local && m->curr_procedure != nullptr;
+ bool is_local = cc.allow_local && m->curr_procedure != nullptr;
bool is_const = true;
if (is_local) {
for (isize i = 0; i < count; i++) {
@@ -474,9 +514,9 @@ gb_internal bool lb_is_nested_possibly_constant(Type *ft, Selection const &sel,
return lb_is_elem_const(elem, ft);
}
-gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_local, bool is_rodata) {
- if (allow_local) {
- is_rodata = false;
+gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lbConstContext cc) {
+ if (cc.allow_local) {
+ cc.is_rodata = false;
}
LLVMContextRef ctx = m->ctx;
@@ -507,7 +547,10 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo
Entity *e = entity_from_expr(expr);
res = lb_find_procedure_value_from_entity(m, e);
}
- GB_ASSERT(res.value != nullptr);
+ if (res.value == nullptr) {
+ // This is an unspecialized polymorphic procedure, return nil or dummy value
+ return lb_const_nil(m, original_type);
+ }
GB_ASSERT(LLVMGetValueKind(res.value) == LLVMFunctionValueKind);
if (LLVMGetIntrinsicID(res.value) == 0) {
@@ -517,7 +560,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo
return res;
}
- bool is_local = allow_local && m->curr_procedure != nullptr;
+ bool is_local = cc.allow_local && m->curr_procedure != nullptr;
// GB_ASSERT_MSG(is_type_typed(type), "%s", type_to_string(type));
@@ -536,7 +579,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo
count = gb_max(cast(isize)cl->max_count, count);
Type *elem = base_type(type)->Slice.elem;
Type *t = alloc_type_array(elem, count);
- lbValue backing_array = lb_const_value(m, t, value, allow_local, is_rodata);
+ lbValue backing_array = lb_const_value(m, t, value, cc);
LLVMValueRef array_data = nullptr;
@@ -562,18 +605,21 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo
return lb_addr_load(p, slice);
}
} else {
- isize max_len = 7+8+1;
- char *str = gb_alloc_array(permanent_allocator(), char, max_len);
- u32 id = m->gen->global_array_index.fetch_add(1);
- isize len = gb_snprintf(str, max_len, "csba$%x", id);
+ u32 id = m->global_array_index.fetch_add(1);
+ gbString str = gb_string_make(temporary_allocator(), "csba$");
+ str = gb_string_appendc(str, m->module_name);
+ str = gb_string_append_fmt(str, "$%x", id);
- String name = make_string(cast(u8 *)str, len-1);
+ String name = make_string(cast(u8 const *)str, gb_string_length(str));
Entity *e = alloc_entity_constant(nullptr, make_token_ident(name), t, value);
array_data = LLVMAddGlobal(m->mod, lb_type(m, t), str);
LLVMSetInitializer(array_data, backing_array.value);
- if (is_rodata) {
+ if (cc.link_section.len > 0) {
+ LLVMSetSection(array_data, alloc_cstring(permanent_allocator(), cc.link_section));
+ }
+ if (cc.is_rodata) {
LLVMSetGlobalConstant(array_data, true);
}
@@ -624,7 +670,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo
}
// NOTE(bill, 2021-10-07): Allow for array programming value constants
Type *core_elem = core_array_type(type);
- return lb_const_value(m, core_elem, value, allow_local, is_rodata);
+ return lb_const_value(m, core_elem, value, cc);
} else if (is_type_u8_array(type) && value.kind == ExactValue_String) {
GB_ASSERT(type->Array.count == value.value_string.len);
LLVMValueRef data = LLVMConstStringInContext(ctx,
@@ -642,7 +688,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo
Type *elem = type->Array.elem;
- lbValue single_elem = lb_const_value(m, elem, value, allow_local, is_rodata);
+ lbValue single_elem = lb_const_value(m, elem, value, cc);
LLVMValueRef *elems = gb_alloc_array(permanent_allocator(), LLVMValueRef, cast(isize)count);
for (i64 i = 0; i < count; i++) {
@@ -660,7 +706,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo
Type *elem = type->Matrix.elem;
- lbValue single_elem = lb_const_value(m, elem, value, allow_local, is_rodata);
+ lbValue single_elem = lb_const_value(m, elem, value, cc);
single_elem.value = llvm_const_cast(single_elem.value, lb_type(m, elem));
i64 total_elem_count = matrix_type_total_internal_elems(type);
@@ -682,7 +728,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo
i64 count = type->SimdVector.count;
Type *elem = type->SimdVector.elem;
- lbValue single_elem = lb_const_value(m, elem, value, allow_local, is_rodata);
+ lbValue single_elem = lb_const_value(m, elem, value, cc);
single_elem.value = llvm_const_cast(single_elem.value, lb_type(m, elem));
LLVMValueRef *elems = gb_alloc_array(permanent_allocator(), LLVMValueRef, count);
@@ -703,9 +749,16 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo
return res;
case ExactValue_String:
{
- LLVMValueRef ptr = lb_find_or_add_entity_string_ptr(m, value.value_string);
+ bool custom_link_section = cc.link_section.len > 0;
+
+ LLVMValueRef ptr = lb_find_or_add_entity_string_ptr(m, value.value_string, custom_link_section);
lbValue res = {};
res.type = default_type(original_type);
+
+ if (custom_link_section) {
+ LLVMSetSection(ptr, alloc_cstring(permanent_allocator(), cc.link_section));
+ }
+
if (is_type_cstring(res.type)) {
res.value = ptr;
} else {
@@ -811,7 +864,149 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo
case ExactValue_Compound:
if (is_type_slice(type)) {
- return lb_const_value(m, type, value, allow_local, is_rodata);
+ return lb_const_value(m, type, value, cc);
+ } else if (is_type_soa_struct(type)) {
+ GB_ASSERT(type->kind == Type_Struct);
+ GB_ASSERT(type->Struct.soa_kind == StructSoa_Fixed);
+ ast_node(cl, CompoundLit, value.value_compound);
+ Type *elem_type = type->Struct.soa_elem;
+ isize elem_count = cl->elems.count;
+ if (elem_count == 0 || !elem_type_can_be_constant(elem_type)) {
+ return lb_const_nil(m, original_type);
+ }
+ if (cl->elems[0]->kind == Ast_FieldValue) {
+ TEMPORARY_ALLOCATOR_GUARD();
+
+ // TODO(bill): This is O(N*M) and will be quite slow; it should probably be sorted before hand
+
+ isize elem_count = cast(isize)type->Struct.soa_count;
+
+ LLVMValueRef *aos_values = gb_alloc_array(temporary_allocator(), LLVMValueRef, elem_count);
+
+ isize value_index = 0;
+ for (i64 i = 0; i < elem_count; i++) {
+ bool found = false;
+
+ for (isize j = 0; j < elem_count; j++) {
+ Ast *elem = cl->elems[j];
+ ast_node(fv, FieldValue, elem);
+ if (is_ast_range(fv->field)) {
+ ast_node(ie, BinaryExpr, fv->field);
+ TypeAndValue lo_tav = ie->left->tav;
+ TypeAndValue hi_tav = ie->right->tav;
+ GB_ASSERT(lo_tav.mode == Addressing_Constant);
+ GB_ASSERT(hi_tav.mode == Addressing_Constant);
+
+ TokenKind op = ie->op.kind;
+ i64 lo = exact_value_to_i64(lo_tav.value);
+ i64 hi = exact_value_to_i64(hi_tav.value);
+ if (op != Token_RangeHalf) {
+ hi += 1;
+ }
+ if (lo == i) {
+ TypeAndValue tav = fv->value->tav;
+ LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc).value;
+ for (i64 k = lo; k < hi; k++) {
+ aos_values[value_index++] = val;
+ }
+
+ found = true;
+ i += (hi-lo-1);
+ break;
+ }
+ } else {
+ TypeAndValue index_tav = fv->field->tav;
+ GB_ASSERT(index_tav.mode == Addressing_Constant);
+ i64 index = exact_value_to_i64(index_tav.value);
+ if (index == i) {
+ TypeAndValue tav = fv->value->tav;
+ LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc).value;
+ aos_values[value_index++] = val;
+ found = true;
+ break;
+ }
+ }
+ }
+
+ if (!found) {
+ aos_values[value_index++] = nullptr;
+ }
+ }
+
+
+ isize field_count = type->Struct.fields.count;
+ LLVMValueRef *soa_values = gb_alloc_array(temporary_allocator(), LLVMValueRef, field_count);
+
+ for (isize i = 0; i < field_count; i++) {
+ TEMPORARY_ALLOCATOR_GUARD();
+
+ LLVMValueRef *values = gb_alloc_array(temporary_allocator(), LLVMValueRef, elem_count);
+
+ Entity *f = type->Struct.fields[i];
+ Type *array_type = f->type;
+ GB_ASSERT(array_type->kind == Type_Array);
+ Type *field_type = array_type->Array.elem;
+
+ for (isize j = 0; j < elem_count; j++) {
+ LLVMValueRef v = aos_values[j];
+ if (v != nullptr) {
+ values[j] = llvm_const_extract_value(m, v, cast(unsigned)i);
+ } else {
+ values[j] = LLVMConstNull(lb_type(m, field_type));
+ }
+ }
+
+ soa_values[i] = lb_build_constant_array_values(m, array_type, field_type, elem_count, values, cc);
+ }
+
+ res.value = llvm_const_named_struct(m, type, soa_values, field_count);
+ return res;
+ } else {
+ GB_ASSERT_MSG(elem_count == type->Struct.soa_count, "%td != %td", elem_count, type->Struct.soa_count);
+
+ TEMPORARY_ALLOCATOR_GUARD();
+
+ isize elem_count = cast(isize)type->Struct.soa_count;
+
+ LLVMValueRef *aos_values = gb_alloc_array(temporary_allocator(), LLVMValueRef, elem_count);
+
+ for (isize i = 0; i < elem_count; i++) {
+ TypeAndValue tav = cl->elems[i]->tav;
+ GB_ASSERT(tav.mode != Addressing_Invalid);
+ aos_values[i] = lb_const_value(m, elem_type, tav.value, cc).value;
+ }
+ for (isize i = elem_count; i < type->Struct.soa_count; i++) {
+ aos_values[i] = nullptr;
+ }
+
+ isize field_count = type->Struct.fields.count;
+ LLVMValueRef *soa_values = gb_alloc_array(temporary_allocator(), LLVMValueRef, field_count);
+
+ for (isize i = 0; i < field_count; i++) {
+ TEMPORARY_ALLOCATOR_GUARD();
+
+ LLVMValueRef *values = gb_alloc_array(temporary_allocator(), LLVMValueRef, elem_count);
+
+ Entity *f = type->Struct.fields[i];
+ Type *array_type = f->type;
+ GB_ASSERT(array_type->kind == Type_Array);
+ Type *field_type = array_type->Array.elem;
+
+ for (isize j = 0; j < elem_count; j++) {
+ LLVMValueRef v = aos_values[j];
+ if (v != nullptr) {
+ values[j] = llvm_const_extract_value(m, v, cast(unsigned)i);
+ } else {
+ values[j] = LLVMConstNull(lb_type(m, field_type));
+ }
+ }
+
+ soa_values[i] = lb_build_constant_array_values(m, array_type, field_type, elem_count, values, cc);
+ }
+
+ res.value = llvm_const_named_struct(m, type, soa_values, field_count);
+ return res;
+ }
} else if (is_type_array(type)) {
ast_node(cl, CompoundLit, value.value_compound);
Type *elem_type = type->Array.elem;
@@ -845,7 +1040,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo
}
if (lo == i) {
TypeAndValue tav = fv->value->tav;
- LLVMValueRef val = lb_const_value(m, elem_type, tav.value, allow_local, is_rodata).value;
+ LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc).value;
for (i64 k = lo; k < hi; k++) {
values[value_index++] = val;
}
@@ -860,7 +1055,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo
i64 index = exact_value_to_i64(index_tav.value);
if (index == i) {
TypeAndValue tav = fv->value->tav;
- LLVMValueRef val = lb_const_value(m, elem_type, tav.value, allow_local, is_rodata).value;
+ LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc).value;
values[value_index++] = val;
found = true;
break;
@@ -873,9 +1068,20 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo
}
}
- res.value = lb_build_constant_array_values(m, type, elem_type, cast(isize)type->Array.count, values, allow_local, is_rodata);
+ res.value = lb_build_constant_array_values(m, type, elem_type, cast(isize)type->Array.count, values, cc);
+ return res;
+ } else if (value.value_compound->tav.type == elem_type) {
+ // Compound is of array item type; expand its value to all items in array.
+ LLVMValueRef* values = gb_alloc_array(temporary_allocator(), LLVMValueRef, cast(isize)type->Array.count);
+
+ for (isize i = 0; i < type->Array.count; i++) {
+ values[i] = lb_const_value(m, elem_type, value, cc).value;
+ }
+
+ res.value = lb_build_constant_array_values(m, type, elem_type, cast(isize)type->Array.count, values, cc);
return res;
} else {
+ // Assume that compound value is an array literal
GB_ASSERT_MSG(elem_count == type->Array.count, "%td != %td", elem_count, type->Array.count);
LLVMValueRef *values = gb_alloc_array(temporary_allocator(), LLVMValueRef, cast(isize)type->Array.count);
@@ -883,13 +1089,13 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo
for (isize i = 0; i < elem_count; i++) {
TypeAndValue tav = cl->elems[i]->tav;
GB_ASSERT(tav.mode != Addressing_Invalid);
- values[i] = lb_const_value(m, elem_type, tav.value, allow_local, is_rodata).value;
+ values[i] = lb_const_value(m, elem_type, tav.value, cc).value;
}
for (isize i = elem_count; i < type->Array.count; i++) {
values[i] = LLVMConstNull(lb_type(m, elem_type));
}
- res.value = lb_build_constant_array_values(m, type, elem_type, cast(isize)type->Array.count, values, allow_local, is_rodata);
+ res.value = lb_build_constant_array_values(m, type, elem_type, cast(isize)type->Array.count, values, cc);
return res;
}
} else if (is_type_enumerated_array(type)) {
@@ -929,7 +1135,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo
}
if (lo == i) {
TypeAndValue tav = fv->value->tav;
- LLVMValueRef val = lb_const_value(m, elem_type, tav.value, allow_local, is_rodata).value;
+ LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc).value;
for (i64 k = lo; k < hi; k++) {
values[value_index++] = val;
}
@@ -944,7 +1150,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo
i64 index = exact_value_to_i64(index_tav.value);
if (index == i) {
TypeAndValue tav = fv->value->tav;
- LLVMValueRef val = lb_const_value(m, elem_type, tav.value, allow_local, is_rodata).value;
+ LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc).value;
values[value_index++] = val;
found = true;
break;
@@ -957,7 +1163,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo
}
}
- res.value = lb_build_constant_array_values(m, type, elem_type, cast(isize)type->EnumeratedArray.count, values, allow_local, is_rodata);
+ res.value = lb_build_constant_array_values(m, type, elem_type, cast(isize)type->EnumeratedArray.count, values, cc);
return res;
} else {
GB_ASSERT_MSG(elem_count == type->EnumeratedArray.count, "%td != %td", elem_count, type->EnumeratedArray.count);
@@ -967,13 +1173,13 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo
for (isize i = 0; i < elem_count; i++) {
TypeAndValue tav = cl->elems[i]->tav;
GB_ASSERT(tav.mode != Addressing_Invalid);
- values[i] = lb_const_value(m, elem_type, tav.value, allow_local, is_rodata).value;
+ values[i] = lb_const_value(m, elem_type, tav.value, cc).value;
}
for (isize i = elem_count; i < type->EnumeratedArray.count; i++) {
values[i] = LLVMConstNull(lb_type(m, elem_type));
}
- res.value = lb_build_constant_array_values(m, type, elem_type, cast(isize)type->EnumeratedArray.count, values, allow_local, is_rodata);
+ res.value = lb_build_constant_array_values(m, type, elem_type, cast(isize)type->EnumeratedArray.count, values, cc);
return res;
}
} else if (is_type_simd_vector(type)) {
@@ -1012,7 +1218,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo
}
if (lo == i) {
TypeAndValue tav = fv->value->tav;
- LLVMValueRef val = lb_const_value(m, elem_type, tav.value, allow_local, is_rodata).value;
+ LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc).value;
for (i64 k = lo; k < hi; k++) {
values[value_index++] = val;
}
@@ -1027,7 +1233,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo
i64 index = exact_value_to_i64(index_tav.value);
if (index == i) {
TypeAndValue tav = fv->value->tav;
- LLVMValueRef val = lb_const_value(m, elem_type, tav.value, allow_local, is_rodata).value;
+ LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc).value;
values[value_index++] = val;
found = true;
break;
@@ -1046,7 +1252,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo
for (isize i = 0; i < elem_count; i++) {
TypeAndValue tav = cl->elems[i]->tav;
GB_ASSERT(tav.mode != Addressing_Invalid);
- values[i] = lb_const_value(m, elem_type, tav.value, allow_local, is_rodata).value;
+ values[i] = lb_const_value(m, elem_type, tav.value, cc).value;
}
LLVMTypeRef et = lb_type(m, elem_type);
@@ -1095,14 +1301,17 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo
i32 index = field_remapping[f->Variable.field_index];
if (elem_type_can_be_constant(f->type)) {
if (sel.index.count == 1) {
- values[index] = lb_const_value(m, f->type, tav.value, allow_local, is_rodata).value;
+ values[index] = lb_const_value(m, f->type, tav.value, cc).value;
visited[index] = true;
} else {
if (!visited[index]) {
- values[index] = lb_const_value(m, f->type, {}, false).value;
+ auto new_cc = cc;
+ new_cc.allow_local = false;
+ values[index] = lb_const_value(m, f->type, {}, new_cc).value;
visited[index] = true;
}
+
unsigned idx_list_len = cast(unsigned)sel.index.count-1;
unsigned *idx_list = gb_alloc_array(temporary_allocator(), unsigned, idx_list_len);
@@ -1113,6 +1322,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo
i32 index = sel.index[j];
Type *cvt = base_type(cv_type);
+
if (cvt->kind == Type_Struct) {
if (cvt->Struct.is_raw_union) {
// sanity check which should have been caught by `lb_is_nested_possibly_constant`
@@ -1137,9 +1347,41 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo
}
}
if (is_constant) {
- LLVMValueRef elem_value = lb_const_value(m, tav.type, tav.value, allow_local, is_rodata).value;
- if (LLVMIsConstant(elem_value)) {
+ LLVMValueRef elem_value = lb_const_value(m, tav.type, tav.value, cc).value;
+ if (LLVMIsConstant(elem_value) && LLVMIsConstant(values[index])) {
values[index] = llvm_const_insert_value(m, values[index], elem_value, idx_list, idx_list_len);
+ } else if (is_local) {
+ #if 1
+ lbProcedure *p = m->curr_procedure;
+ GB_ASSERT(p != nullptr);
+ if (LLVMIsConstant(values[index])) {
+ lbAddr addr = lb_add_local_generated(p, f->type, false);
+ lb_addr_store(p, addr, lbValue{values[index], f->type});
+ values[index] = lb_addr_load(p, addr).value;
+ }
+
+ GB_ASSERT(LLVMIsALoadInst(values[index]));
+
+ LLVMValueRef ptr = LLVMGetOperand(values[index], 0);
+
+ LLVMValueRef *indices = gb_alloc_array(temporary_allocator(), LLVMValueRef, idx_list_len);
+ LLVMTypeRef lt_u32 = lb_type(m, t_u32);
+ for (unsigned i = 0; i < idx_list_len; i++) {
+ indices[i] = LLVMConstInt(lt_u32, idx_list[i], false);
+ }
+
+ ptr = LLVMBuildGEP2(p->builder, lb_type(m, f->type), ptr, indices, idx_list_len, "");
+ ptr = LLVMBuildPointerCast(p->builder, ptr, lb_type(m, alloc_type_pointer(tav.type)), "");
+
+ if (LLVMIsALoadInst(elem_value)) {
+ i64 sz = type_size_of(tav.type);
+ LLVMValueRef src = LLVMGetOperand(elem_value, 0);
+ lb_mem_copy_non_overlapping(p, {ptr, t_rawptr}, {src, t_rawptr}, lb_const_int(m, t_int, sz), false);
+ } else {
+ LLVMBuildStore(p->builder, elem_value, ptr);
+ }
+ #endif
+ is_constant = false;
} else {
is_constant = false;
}
@@ -1159,7 +1401,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo
i32 index = field_remapping[f->Variable.field_index];
if (elem_type_can_be_constant(f->type)) {
- values[index] = lb_const_value(m, f->type, val, allow_local, is_rodata).value;
+ values[index] = lb_const_value(m, f->type, val, cc).value;
visited[index] = true;
}
}
@@ -1179,7 +1421,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo
LLVMValueRef val = values[i];
if (!LLVMIsConstant(val)) {
GB_ASSERT(is_local);
- GB_ASSERT(LLVMGetInstructionOpcode(val) == LLVMLoad);
+ GB_ASSERT(LLVMIsALoadInst(val));
is_constant = false;
}
}
@@ -1211,7 +1453,15 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo
LLVMValueRef val = old_values[i];
if (!LLVMIsConstant(val)) {
LLVMValueRef dst = LLVMBuildStructGEP2(p->builder, llvm_addr_type(p->module, v.addr), v.addr.value, cast(unsigned)i, "");
+ // if (LLVMIsALoadInst(val)) {
+ // Type *ptr_type = v.addr.type;
+ // i64 sz = type_size_of(type_deref(ptr_type));
+
+ // LLVMValueRef src = LLVMGetOperand(val, 0);
+ // lb_mem_copy_non_overlapping(p, {dst, ptr_type}, {src, ptr_type}, lb_const_int(m, t_int, sz), false);
+ // } else {
LLVMBuildStore(p->builder, val, dst);
+ // }
}
}
return lb_addr_load(p, v);
@@ -1285,7 +1535,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo
TypeAndValue tav = fv->value->tav;
- LLVMValueRef val = lb_const_value(m, elem_type, tav.value, allow_local, is_rodata).value;
+ LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc).value;
for (i64 k = lo; k < hi; k++) {
i64 offset = matrix_row_major_index_to_offset(type, k);
GB_ASSERT(values[offset] == nullptr);
@@ -1297,7 +1547,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo
i64 index = exact_value_to_i64(index_tav.value);
GB_ASSERT(index < max_count);
TypeAndValue tav = fv->value->tav;
- LLVMValueRef val = lb_const_value(m, elem_type, tav.value, allow_local, is_rodata).value;
+ LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc).value;
i64 offset = matrix_row_major_index_to_offset(type, index);
GB_ASSERT(values[offset] == nullptr);
values[offset] = val;
@@ -1310,7 +1560,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo
}
}
- res.value = lb_build_constant_array_values(m, type, elem_type, cast(isize)total_count, values, allow_local, is_rodata);
+ res.value = lb_build_constant_array_values(m, type, elem_type, cast(isize)total_count, values, cc);
return res;
} else {
GB_ASSERT_MSG(elem_count == max_count, "%td != %td", elem_count, max_count);
@@ -1321,7 +1571,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo
GB_ASSERT(tav.mode != Addressing_Invalid);
i64 offset = 0;
offset = matrix_row_major_index_to_offset(type, i);
- values[offset] = lb_const_value(m, elem_type, tav.value, allow_local, is_rodata).value;
+ values[offset] = lb_const_value(m, elem_type, tav.value, cc).value;
}
for (isize i = 0; i < total_count; i++) {
if (values[i] == nullptr) {
@@ -1329,7 +1579,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo
}
}
- res.value = lb_build_constant_array_values(m, type, elem_type, cast(isize)total_count, values, allow_local, is_rodata);
+ res.value = lb_build_constant_array_values(m, type, elem_type, cast(isize)total_count, values, cc);
return res;
}
} else {
diff --git a/src/llvm_backend_debug.cpp b/src/llvm_backend_debug.cpp
index fbb25960a..024c5564e 100644
--- a/src/llvm_backend_debug.cpp
+++ b/src/llvm_backend_debug.cpp
@@ -18,6 +18,25 @@ gb_internal void lb_set_llvm_metadata(lbModule *m, void *key, LLVMMetadataRef va
}
}
+gb_internal void lb_add_raddbg_string(lbModule *m, String const &str) {
+ mpsc_enqueue(&m->gen->raddebug_section_strings, copy_string(permanent_allocator(), str));
+}
+
+gb_internal void lb_add_raddbg_string(lbModule *m, char const *cstr) {
+ mpsc_enqueue(&m->gen->raddebug_section_strings, copy_string(permanent_allocator(), make_string_c(cstr)));
+}
+
+gb_internal void lb_add_raddbg_string(lbModule *m, char const *a, char const *b) {
+ String str = concatenate_strings(permanent_allocator(), make_string_c(a), make_string_c(b));
+ mpsc_enqueue(&m->gen->raddebug_section_strings, str);
+}
+
+gb_internal void lb_add_raddbg_string(lbModule *m, char const *a, char const *b, char const *c) {
+ String str = concatenate3_strings(permanent_allocator(), make_string_c(a), make_string_c(b), make_string_c(c));
+ mpsc_enqueue(&m->gen->raddebug_section_strings, str);
+}
+
+
gb_internal LLVMMetadataRef lb_get_current_debug_scope(lbProcedure *p) {
GB_ASSERT_MSG(p->debug_info != nullptr, "missing debug information for %.*s", LIT(p->name));
@@ -564,22 +583,21 @@ gb_internal LLVMMetadataRef lb_debug_bitfield(lbModule *m, Type *type, String na
u64 size_in_bits = 8*type_size_of(bt);
u32 align_in_bits = 8*cast(u32)type_align_of(bt);
- unsigned element_count = cast(unsigned)bt->BitField.fields.count;
- LLVMMetadataRef *elements = gb_alloc_array(permanent_allocator(), LLVMMetadataRef, element_count);
-
- u64 offset_in_bits = 0;
- for (unsigned i = 0; i < element_count; i++) {
- Entity *f = bt->BitField.fields[i];
- u8 bit_size = bt->BitField.bit_sizes[i];
- GB_ASSERT(f->kind == Entity_Variable);
- String name = f->token.string;
- elements[i] = LLVMDIBuilderCreateBitFieldMemberType(m->debug_builder, scope, cast(char const *)name.text, name.len, file, line,
- bit_size, offset_in_bits, 0,
- LLVMDIFlagZero, lb_debug_type(m, f->type)
- );
+ unsigned element_count = cast(unsigned)bt->BitField.fields.count;
+ LLVMMetadataRef *elements = gb_alloc_array(permanent_allocator(), LLVMMetadataRef, element_count);
- offset_in_bits += bit_size;
- }
+ u64 offset_in_bits = 0;
+ for (unsigned i = 0; i < element_count; i++) {
+ Entity *f = bt->BitField.fields[i];
+ u8 bit_size = bt->BitField.bit_sizes[i];
+ GB_ASSERT(f->kind == Entity_Variable);
+ String name = f->token.string;
+ elements[i] = LLVMDIBuilderCreateBitFieldMemberType(m->debug_builder, scope, cast(char const *)name.text, name.len, file, line,
+ bit_size, offset_in_bits, 0,
+ LLVMDIFlagZero, lb_debug_type(m, f->type)
+ );
+ offset_in_bits += bit_size;
+ }
LLVMMetadataRef final_decl = LLVMDIBuilderCreateStructType(
m->debug_builder, scope,
@@ -843,7 +861,7 @@ gb_internal LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) {
8*cast(unsigned)type_align_of(type),
lb_debug_type(m, type->EnumeratedArray.elem),
subscripts, gb_count_of(subscripts));
- gbString name = type_to_string(type, temporary_allocator());
+ gbString name = temp_canonical_string(type);
return LLVMDIBuilderCreateTypedef(m->debug_builder, array_type, name, gb_string_length(name), nullptr, 0, nullptr, cast(u32)(8*type_align_of(type)));
}
@@ -852,16 +870,16 @@ gb_internal LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) {
Type *bt = base_type(type->Map.debug_metadata_type);
GB_ASSERT(bt->kind == Type_Struct);
- return lb_debug_struct(m, type, bt, make_string_c(type_to_string(type, temporary_allocator())), nullptr, nullptr, 0);
+ return lb_debug_struct(m, type, bt, type_to_canonical_string(temporary_allocator(), type), nullptr, nullptr, 0);
}
- case Type_Struct: return lb_debug_struct( m, type, type, make_string_c(type_to_string(type, temporary_allocator())), nullptr, nullptr, 0);
- case Type_Slice: return lb_debug_slice( m, type, make_string_c(type_to_string(type, temporary_allocator())), nullptr, nullptr, 0);
- case Type_DynamicArray: return lb_debug_dynamic_array(m, type, make_string_c(type_to_string(type, temporary_allocator())), nullptr, nullptr, 0);
- case Type_Union: return lb_debug_union( m, type, make_string_c(type_to_string(type, temporary_allocator())), nullptr, nullptr, 0);
- case Type_BitSet: return lb_debug_bitset( m, type, make_string_c(type_to_string(type, temporary_allocator())), nullptr, nullptr, 0);
- case Type_Enum: return lb_debug_enum( m, type, make_string_c(type_to_string(type, temporary_allocator())), nullptr, nullptr, 0);
- case Type_BitField: return lb_debug_bitfield( m, type, make_string_c(type_to_string(type, temporary_allocator())), nullptr, nullptr, 0);
+ case Type_Struct: return lb_debug_struct( m, type, type, type_to_canonical_string(temporary_allocator(), type), nullptr, nullptr, 0);
+ case Type_Slice: return lb_debug_slice( m, type, type_to_canonical_string(temporary_allocator(), type), nullptr, nullptr, 0);
+ case Type_DynamicArray: return lb_debug_dynamic_array(m, type, type_to_canonical_string(temporary_allocator(), type), nullptr, nullptr, 0);
+ case Type_Union: return lb_debug_union( m, type, type_to_canonical_string(temporary_allocator(), type), nullptr, nullptr, 0);
+ case Type_BitSet: return lb_debug_bitset( m, type, type_to_canonical_string(temporary_allocator(), type), nullptr, nullptr, 0);
+ case Type_Enum: return lb_debug_enum( m, type, type_to_canonical_string(temporary_allocator(), type), nullptr, nullptr, 0);
+ case Type_BitField: return lb_debug_bitfield( m, type, type_to_canonical_string(temporary_allocator(), type), nullptr, nullptr, 0);
case Type_Tuple:
if (type->Tuple.variables.count == 1) {
@@ -904,7 +922,7 @@ gb_internal LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) {
{
LLVMMetadataRef proc_underlying_type = lb_debug_type_internal_proc(m, type);
LLVMMetadataRef pointer_type = LLVMDIBuilderCreatePointerType(m->debug_builder, proc_underlying_type, ptr_bits, ptr_bits, 0, nullptr, 0);
- gbString name = type_to_string(type, temporary_allocator());
+ gbString name = temp_canonical_string(type);
return LLVMDIBuilderCreateTypedef(m->debug_builder, pointer_type, name, gb_string_length(name), nullptr, 0, nullptr, cast(u32)(8*type_align_of(type)));
}
break;
@@ -924,6 +942,7 @@ gb_internal LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) {
}
case Type_Matrix: {
+ #if 0
LLVMMetadataRef subscripts[1] = {};
subscripts[0] = LLVMDIBuilderGetOrCreateSubrange(m->debug_builder,
0ll,
@@ -935,6 +954,66 @@ gb_internal LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) {
8*cast(unsigned)type_align_of(type),
lb_debug_type(m, type->Matrix.elem),
subscripts, gb_count_of(subscripts));
+ #else
+ LLVMMetadataRef subscripts[2] = {};
+ subscripts[0] = LLVMDIBuilderGetOrCreateSubrange(m->debug_builder, 0ll, type->Matrix.row_count);
+ subscripts[1] = LLVMDIBuilderGetOrCreateSubrange(m->debug_builder, 0ll, type->Matrix.column_count);
+
+ LLVMMetadataRef scope = nullptr;
+ LLVMMetadataRef array_type = nullptr;
+
+ uint64_t size_in_bits = 8*cast(uint64_t)(type_size_of(type));
+ unsigned align_in_bits = 8*cast(unsigned)(type_align_of(type));
+
+ if (type->Matrix.is_row_major) {
+ LLVMMetadataRef base = LLVMDIBuilderCreateArrayType(m->debug_builder,
+ 8*cast(uint64_t)(type_size_of(type->Matrix.elem) * type->Matrix.column_count),
+ 8*cast(unsigned)type_align_of(type->Matrix.elem),
+ lb_debug_type(m, type->Matrix.elem),
+ subscripts+1, 1);
+ array_type = LLVMDIBuilderCreateArrayType(m->debug_builder,
+ size_in_bits,
+ align_in_bits,
+ base,
+ subscripts+0, 1);
+ } else {
+ LLVMMetadataRef base = LLVMDIBuilderCreateArrayType(m->debug_builder,
+ 8*cast(uint64_t)(type_size_of(type->Matrix.elem) * type->Matrix.row_count),
+ 8*cast(unsigned)type_align_of(type->Matrix.elem),
+ lb_debug_type(m, type->Matrix.elem),
+ subscripts+0, 1);
+ array_type = LLVMDIBuilderCreateArrayType(m->debug_builder,
+ size_in_bits,
+ align_in_bits,
+ base,
+ subscripts+1, 1);
+ }
+
+ LLVMMetadataRef elements[1] = {};
+ elements[0] = LLVMDIBuilderCreateMemberType(m->debug_builder, scope,
+ "data", 4,
+ nullptr, 0,
+ size_in_bits, align_in_bits, 0, LLVMDIFlagZero,
+ array_type
+ );
+
+ gbString name = temp_canonical_string(type);
+
+ LLVMMetadataRef final_decl = LLVMDIBuilderCreateStructType(
+ m->debug_builder, scope,
+ name, gb_string_length(name),
+ nullptr, 0,
+ size_in_bits, align_in_bits,
+ LLVMDIFlagZero,
+ nullptr,
+ elements, 1,
+ 0,
+ nullptr,
+ "", 0
+ );
+
+ return final_decl;
+ #endif
}
}
@@ -987,10 +1066,7 @@ gb_internal LLVMMetadataRef lb_debug_type(lbModule *m, Type *type) {
line = cast(unsigned)e->token.pos.line;
}
- String name = type->Named.name;
- if (type->Named.type_name && type->Named.type_name->pkg && type->Named.type_name->pkg->name.len != 0) {
- name = concatenate3_strings(temporary_allocator(), type->Named.type_name->pkg->name, str_lit("."), type->Named.name);
- }
+ String name = type_to_canonical_string(temporary_allocator(), type);
Type *bt = base_type(type->Named.base);
@@ -1088,7 +1164,12 @@ gb_internal void lb_add_debug_local_variable(lbProcedure *p, LLVMValueRef ptr, T
LLVMMetadataRef llvm_debug_loc = lb_debug_location_from_token_pos(p, token.pos);
LLVMMetadataRef llvm_expr = LLVMDIBuilderCreateExpression(m->debug_builder, nullptr, 0);
lb_set_llvm_metadata(m, ptr, llvm_expr);
+
+#if LLVM_VERSION_MAJOR <= 18
LLVMDIBuilderInsertDeclareAtEnd(m->debug_builder, storage, var_info, llvm_expr, llvm_debug_loc, block);
+#else
+ LLVMDIBuilderInsertDeclareRecordAtEnd(m->debug_builder, storage, var_info, llvm_expr, llvm_debug_loc, block);
+#endif
}
gb_internal void lb_add_debug_param_variable(lbProcedure *p, LLVMValueRef ptr, Type *type, Token const &token, unsigned arg_number, lbBlock *block) {
@@ -1184,17 +1265,17 @@ gb_internal void lb_add_debug_context_variable(lbProcedure *p, lbAddr const &ctx
}
-gb_internal String debug_info_mangle_constant_name(Entity *e, gbAllocator const &allocator, bool *did_allocate_) {
+gb_internal String lb_debug_info_mangle_constant_name(Entity *e, gbAllocator const &allocator, bool *did_allocate_) {
String name = e->token.string;
if (e->pkg && e->pkg->name.len > 0) {
- // NOTE(bill): C++ NONSENSE FOR DEBUG SHITE!
- name = concatenate3_strings(allocator, e->pkg->name, str_lit("::"), name);
+ gbString s = string_canonical_entity_name(allocator, e);
+ name = make_string(cast(u8 const *)s, gb_string_length(s));
if (did_allocate_) *did_allocate_ = true;
}
return name;
}
-gb_internal void add_debug_info_global_variable_expr(lbModule *m, String const &name, LLVMMetadataRef dtype, LLVMMetadataRef expr) {
+gb_internal void lb_add_debug_info_global_variable_expr(lbModule *m, String const &name, LLVMMetadataRef dtype, LLVMMetadataRef expr) {
LLVMMetadataRef scope = nullptr;
LLVMMetadataRef file = nullptr;
unsigned line = 0;
@@ -1210,20 +1291,20 @@ gb_internal void add_debug_info_global_variable_expr(lbModule *m, String const &
expr, decl, 8/*AlignInBits*/);
}
-gb_internal void add_debug_info_for_global_constant_internal_i64(lbModule *m, Entity *e, LLVMMetadataRef dtype, i64 v) {
+gb_internal void lb_add_debug_info_for_global_constant_internal_i64(lbModule *m, Entity *e, LLVMMetadataRef dtype, i64 v) {
LLVMMetadataRef expr = LLVMDIBuilderCreateConstantValueExpression(m->debug_builder, v);
TEMPORARY_ALLOCATOR_GUARD();
- String name = debug_info_mangle_constant_name(e, temporary_allocator(), nullptr);
+ String name = lb_debug_info_mangle_constant_name(e, temporary_allocator(), nullptr);
- add_debug_info_global_variable_expr(m, name, dtype, expr);
+ lb_add_debug_info_global_variable_expr(m, name, dtype, expr);
if ((e->pkg && e->pkg->kind == Package_Init) ||
(e->scope && (e->scope->flags & ScopeFlag_Global))) {
- add_debug_info_global_variable_expr(m, e->token.string, dtype, expr);
+ lb_add_debug_info_global_variable_expr(m, e->token.string, dtype, expr);
}
}
-gb_internal void add_debug_info_for_global_constant_from_entity(lbGenerator *gen, Entity *e) {
+gb_internal void lb_add_debug_info_for_global_constant_from_entity(lbGenerator *gen, Entity *e) {
if (e == nullptr || e->kind != Entity_Constant) {
return;
}
@@ -1254,14 +1335,14 @@ gb_internal void add_debug_info_for_global_constant_from_entity(lbGenerator *gen
dtype = lb_debug_type(m, e->type);
}
- add_debug_info_for_global_constant_internal_i64(m, e, dtype, v);
+ lb_add_debug_info_for_global_constant_internal_i64(m, e, dtype, v);
}
} else if (is_type_rune(e->type)) {
ExactValue const &value = e->Constant.value;
if (value.kind == ExactValue_Integer) {
LLVMMetadataRef dtype = lb_debug_type(m, t_rune);
i64 v = exact_value_to_i64(value);
- add_debug_info_for_global_constant_internal_i64(m, e, dtype, v);
+ lb_add_debug_info_for_global_constant_internal_i64(m, e, dtype, v);
}
} else if (is_type_boolean(e->type)) {
ExactValue const &value = e->Constant.value;
@@ -1269,7 +1350,7 @@ gb_internal void add_debug_info_for_global_constant_from_entity(lbGenerator *gen
LLVMMetadataRef dtype = lb_debug_type(m, default_type(e->type));
i64 v = cast(i64)value.value_bool;
- add_debug_info_for_global_constant_internal_i64(m, e, dtype, v);
+ lb_add_debug_info_for_global_constant_internal_i64(m, e, dtype, v);
}
} else if (is_type_enum(e->type)) {
ExactValue const &value = e->Constant.value;
@@ -1282,14 +1363,70 @@ gb_internal void add_debug_info_for_global_constant_from_entity(lbGenerator *gen
v = cast(i64)exact_value_to_u64(value);
}
- add_debug_info_for_global_constant_internal_i64(m, e, dtype, v);
+ lb_add_debug_info_for_global_constant_internal_i64(m, e, dtype, v);
}
} else if (is_type_pointer(e->type)) {
ExactValue const &value = e->Constant.value;
if (value.kind == ExactValue_Integer) {
LLVMMetadataRef dtype = lb_debug_type(m, default_type(e->type));
i64 v = cast(i64)exact_value_to_u64(value);
- add_debug_info_for_global_constant_internal_i64(m, e, dtype, v);
+ lb_add_debug_info_for_global_constant_internal_i64(m, e, dtype, v);
}
}
}
+
+gb_internal void lb_add_debug_label(lbProcedure *p, Ast *label, lbBlock *target) {
+// NOTE(tf2spi): LLVM-C DILabel API used only existed for major versions 20+
+#if LLVM_VERSION_MAJOR >= 20
+ if (p == nullptr || p->debug_info == nullptr) {
+ return;
+ }
+ if (target == nullptr || label == nullptr || label->kind != Ast_Label) {
+ return;
+ }
+ Token label_token = label->Label.token;
+ if (is_blank_ident(label_token.string)) {
+ return;
+ }
+ lbModule *m = p->module;
+ if (m == nullptr) {
+ return;
+ }
+
+ AstFile *file = label->file();
+ LLVMMetadataRef llvm_file = lb_get_llvm_metadata(m, file);
+ if (llvm_file == nullptr) {
+ debugf("llvm file not found for label\n");
+ return;
+ }
+ LLVMMetadataRef llvm_scope = p->debug_info;
+ if(llvm_scope == nullptr) {
+ debugf("llvm scope not found for label\n");
+ return;
+ }
+ LLVMMetadataRef llvm_debug_loc = lb_debug_location_from_token_pos(p, label_token.pos);
+ LLVMBasicBlockRef llvm_block = target->block;
+ if (llvm_block == nullptr || llvm_debug_loc == nullptr) {
+ return;
+ }
+ LLVMMetadataRef llvm_label = LLVMDIBuilderCreateLabel(
+ m->debug_builder,
+ llvm_scope,
+ (const char *)label_token.string.text,
+ (size_t)label_token.string.len,
+ llvm_file,
+ label_token.pos.line,
+
+ // NOTE(tf2spi): Defaults to false in LLVM API, but I'd rather not take chances
+ // Always preserve the label no matter what when debugging
+ true
+ );
+ GB_ASSERT(llvm_label != nullptr);
+ (void)LLVMDIBuilderInsertLabelAtEnd(
+ m->debug_builder,
+ llvm_label,
+ llvm_debug_loc,
+ llvm_block
+ );
+#endif
+}
diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp
index df9dca801..74aea82f1 100644
--- a/src/llvm_backend_expr.cpp
+++ b/src/llvm_backend_expr.cpp
@@ -222,6 +222,7 @@ gb_internal lbValue lb_emit_unary_arith(lbProcedure *p, TokenKind op, lbValue x,
return lb_emit_byte_swap(p, res, type);
}
+ Type* bt = base_type(type);
lbValue res = {};
switch (op) {
@@ -233,6 +234,8 @@ gb_internal lbValue lb_emit_unary_arith(lbProcedure *p, TokenKind op, lbValue x,
case Token_Sub: // Number negation
if (is_type_integer(x.type)) {
res.value = LLVMBuildNeg(p->builder, x.value, "");
+ } else if (bt->kind == Type_Enum && is_type_integer(bt->Enum.base_type)) {
+ res.value = LLVMBuildNeg(p->builder, x.value, "");
} else if (is_type_float(x.type)) {
res.value = LLVMBuildFNeg(p->builder, x.value, "");
} else if (is_type_complex(x.type)) {
@@ -1554,7 +1557,7 @@ gb_internal lbValue lb_build_binary_expr(lbProcedure *p, Ast *expr) {
lbValue cmp = lb_emit_comp_against_nil(p, be->op.kind, right);
Type *type = default_type(tv.type);
return lb_emit_conv(p, cmp, type);
- } else if (lb_is_empty_string_constant(be->right)) {
+ } else if (lb_is_empty_string_constant(be->right) && !is_type_union(be->left->tav.type)) {
// `x == ""` or `x != ""`
lbValue s = lb_build_expr(p, be->left);
s = lb_emit_conv(p, s, t_string);
@@ -1562,7 +1565,7 @@ gb_internal lbValue lb_build_binary_expr(lbProcedure *p, Ast *expr) {
lbValue cmp = lb_emit_comp(p, be->op.kind, len, lb_const_int(p->module, t_int, 0));
Type *type = default_type(tv.type);
return lb_emit_conv(p, cmp, type);
- } else if (lb_is_empty_string_constant(be->left)) {
+ } else if (lb_is_empty_string_constant(be->left) && !is_type_union(be->right->tav.type)) {
// `"" == x` or `"" != x`
lbValue s = lb_build_expr(p, be->right);
s = lb_emit_conv(p, s, t_string);
@@ -2145,6 +2148,12 @@ gb_internal lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) {
}
}
for (Type *vt : dst->Union.variants) {
+ if (src_type == t_llvm_bool && is_type_boolean(vt)) {
+ value = lb_emit_conv(p, value, vt);
+ lbAddr parent = lb_add_local_generated(p, t, true);
+ lb_emit_store_union_variant(p, parent.addr, value, vt);
+ return lb_addr_load(p, parent);
+ }
if (are_types_identical(src_type, vt)) {
lbAddr parent = lb_add_local_generated(p, t, true);
lb_emit_store_union_variant(p, parent.addr, value, vt);
@@ -2312,9 +2321,9 @@ gb_internal lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) {
lbValue array_const_value = {};
array_const_value.type = t;
array_const_value.value = LLVMConstArray(lb_type(m, elem), values, cast(unsigned)index_count);
- v = lb_add_global_generated(m, t, array_const_value);
+ v = lb_add_global_generated_from_procedure(p, t, array_const_value);
} else {
- v = lb_add_global_generated(m, t);
+ v = lb_add_global_generated_from_procedure(p, t);
}
lb_make_global_private_const(v);
@@ -2346,7 +2355,7 @@ gb_internal lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) {
Type *elem = base_array_type(dst);
lbValue e = lb_emit_conv(p, value, elem);
lbAddr v = lb_add_local_generated(p, t, false);
- lbValue zero = lb_const_value(p->module, elem, exact_value_i64(0), true);
+ lbValue zero = lb_const_value(p->module, elem, exact_value_i64(0), LB_CONST_CONTEXT_DEFAULT_ALLOW_LOCAL);
for (i64 j = 0; j < dst->Matrix.column_count; j++) {
for (i64 i = 0; i < dst->Matrix.row_count; i++) {
lbValue ptr = lb_emit_matrix_epi(p, v.addr, i, j);
@@ -2383,7 +2392,7 @@ gb_internal lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) {
lb_emit_store(p, d, s);
} else if (i == j) {
lbValue d = lb_emit_matrix_epi(p, v.addr, i, j);
- lbValue s = lb_const_value(p->module, dst->Matrix.elem, exact_value_i64(1), true);
+ lbValue s = lb_const_value(p->module, dst->Matrix.elem, exact_value_i64(1), LB_CONST_CONTEXT_DEFAULT_ALLOW_LOCAL);
lb_emit_store(p, d, s);
}
}
@@ -2508,7 +2517,7 @@ gb_internal lbValue lb_emit_c_vararg(lbProcedure *p, lbValue arg, Type *type) {
}
gb_internal lbValue lb_compare_records(lbProcedure *p, TokenKind op_kind, lbValue left, lbValue right, Type *type) {
- GB_ASSERT((is_type_struct(type) || is_type_union(type)) && is_type_comparable(type));
+ GB_ASSERT((is_type_struct(type) || is_type_soa_pointer(type) || is_type_union(type)) && is_type_comparable(type));
lbValue left_ptr = lb_address_from_load_or_generate_local(p, left);
lbValue right_ptr = lb_address_from_load_or_generate_local(p, right);
lbValue res = {};
@@ -2893,6 +2902,7 @@ gb_internal lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left
is_type_proc(a) ||
is_type_enum(a)) {
LLVMIntPredicate pred = {};
+
if (is_type_unsigned(left.type)) {
switch (op_kind) {
case Token_Gt: pred = LLVMIntUGT; break;
@@ -2935,7 +2945,7 @@ gb_internal lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left
case Token_GtEq: pred = LLVMRealOGE; break;
case Token_Lt: pred = LLVMRealOLT; break;
case Token_LtEq: pred = LLVMRealOLE; break;
- case Token_NotEq: pred = LLVMRealONE; break;
+ case Token_NotEq: pred = LLVMRealUNE; break;
}
if (is_type_different_to_arch_endianness(left.type)) {
@@ -2963,7 +2973,7 @@ gb_internal lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left
LLVMRealPredicate pred = {};
switch (op_kind) {
case Token_CmpEq: pred = LLVMRealOEQ; break;
- case Token_NotEq: pred = LLVMRealONE; break;
+ case Token_NotEq: pred = LLVMRealUNE; break;
}
mask = LLVMBuildFCmp(p->builder, pred, left.value, right.value, "");
} else {
@@ -3004,9 +3014,21 @@ gb_internal lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left
LLVMTypeRef mask_int_type = LLVMIntTypeInContext(p->module->ctx, cast(unsigned)(8*type_size_of(a)));
LLVMValueRef mask_int = LLVMBuildBitCast(p->builder, mask, mask_int_type, "");
- res.value = LLVMBuildICmp(p->builder, LLVMIntNE, mask_int, LLVMConstNull(LLVMTypeOf(mask_int)), "");
+
+ switch (op_kind) {
+ case Token_CmpEq:
+ res.value = LLVMBuildICmp(p->builder, LLVMIntEQ, mask_int, LLVMConstInt(mask_int_type, U64_MAX, true), "");
+ break;
+ case Token_NotEq:
+ res.value = LLVMBuildICmp(p->builder, LLVMIntNE, mask_int, LLVMConstNull(mask_int_type), "");
+ break;
+ }
+
return res;
+ } else if (is_type_soa_pointer(a)) {
+ // NOTE(Jeroen): Compare data pointer and index tag as if it were a simple struct.
+ return lb_compare_records(p, op_kind, left, right, a);
} else {
GB_PANIC("Unhandled comparison kind %s (%s) %.*s %s (%s)", type_to_string(left.type), type_to_string(base_type(left.type)), LIT(token_strings[op_kind]), type_to_string(right.type), type_to_string(base_type(right.type)));
}
@@ -3128,6 +3150,18 @@ gb_internal lbValue lb_emit_comp_against_nil(lbProcedure *p, TokenKind op_kind,
}
}
break;
+
+ case Type_SoaPointer:
+ {
+ // NOTE(bill): An SoaPointer is essentially just a pointer for nil comparison
+ lbValue ptr = lb_emit_struct_ev(p, x, 0); // Extract the base pointer component (field 0)
+ if (op_kind == Token_CmpEq) {
+ res.value = LLVMBuildIsNull(p->builder, ptr.value, "");
+ } else if (op_kind == Token_NotEq) {
+ res.value = LLVMBuildIsNotNull(p->builder, ptr.value, "");
+ }
+ return res;
+ }
case Type_Union:
{
@@ -3255,7 +3289,7 @@ gb_internal lbValue lb_build_unary_and(lbProcedure *p, Ast *expr) {
Type *type = v.type;
lbAddr addr = {};
if (p->is_startup) {
- addr = lb_add_global_generated(p->module, type, v);
+ addr = lb_add_global_generated_from_procedure(p, type, v);
} else {
addr = lb_add_local_generated(p, type, false);
}
@@ -3364,9 +3398,7 @@ gb_internal lbValue lb_build_unary_and(lbProcedure *p, Ast *expr) {
auto args = array_make<lbValue>(permanent_allocator(), arg_count);
args[0] = ok;
- 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[3] = lb_const_int(p->module, t_i32, pos.column);
+ lb_set_file_line_col(p, array_slice(args, 1, args.count), pos);
if (!build_context.no_rtti) {
args[4] = lb_typeid(p->module, src_type);
@@ -3393,9 +3425,7 @@ gb_internal lbValue lb_build_unary_and(lbProcedure *p, Ast *expr) {
auto args = array_make<lbValue>(permanent_allocator(), 6);
args[0] = ok;
- 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[3] = lb_const_int(p->module, t_i32, pos.column);
+ lb_set_file_line_col(p, array_slice(args, 1, args.count), pos);
args[4] = any_id;
args[5] = id;
@@ -3482,7 +3512,7 @@ gb_internal lbValue lb_build_expr_internal(lbProcedure *p, Ast *expr) {
if (tv.value.kind != ExactValue_Invalid) {
// NOTE(bill): Short on constant values
- return lb_const_value(p->module, type, tv.value);
+ return lb_const_value(p->module, type, tv.value, LB_CONST_CONTEXT_DEFAULT_ALLOW_LOCAL);
} else if (tv.mode == Addressing_Type) {
// NOTE(bill, 2023-01-16): is this correct? I hope so at least
return lb_typeid(m, tv.type);
@@ -3846,7 +3876,7 @@ gb_internal lbAddr lb_build_addr_from_entity(lbProcedure *p, Entity *e, Ast *exp
Type *t = default_type(type_of_expr(expr));
lbValue v = lb_const_value(p->module, t, e->Constant.value);
if (LLVMIsConstant(v.value)) {
- lbAddr g = lb_add_global_generated(p->module, t, v);
+ lbAddr g = lb_add_global_generated_from_procedure(p, t, v);
return g;
}
GB_ASSERT(LLVMIsALoadInst(v.value));
@@ -4294,6 +4324,17 @@ gb_internal lbAddr lb_build_addr_index_expr(lbProcedure *p, Ast *expr) {
gb_internal lbAddr lb_build_addr_slice_expr(lbProcedure *p, Ast *expr) {
ast_node(se, SliceExpr, expr);
+ lbAddr addr = lb_build_addr(p, se->expr);
+ lbValue base = lb_addr_load(p, addr);
+ Type *type = base_type(base.type);
+
+ if (is_type_pointer(type)) {
+ type = base_type(type_deref(type));
+ addr = lb_addr(base);
+ base = lb_addr_load(p, addr);
+ }
+
+
lbValue low = lb_const_int(p->module, t_int, 0);
lbValue high = {};
@@ -4306,16 +4347,6 @@ gb_internal lbAddr lb_build_addr_slice_expr(lbProcedure *p, Ast *expr) {
bool no_indices = se->low == nullptr && se->high == nullptr;
- lbAddr addr = lb_build_addr(p, se->expr);
- lbValue base = lb_addr_load(p, addr);
- Type *type = base_type(base.type);
-
- if (is_type_pointer(type)) {
- type = base_type(type_deref(type));
- addr = lb_addr(base);
- base = lb_addr_load(p, addr);
- }
-
switch (type->kind) {
case Type_Slice: {
Type *slice_type = type;
@@ -4813,7 +4844,7 @@ gb_internal lbAddr lb_build_addr_compound_lit(lbProcedure *p, Ast *expr) {
if (cl->elems.count == 0) {
break;
}
- GB_ASSERT(expr->file()->feature_flags & OptInFeatureFlag_DynamicLiterals);
+ GB_ASSERT(expr->file()->feature_flags & OptInFeatureFlag_DynamicLiterals || build_context.dynamic_literals);
lbValue err = lb_dynamic_map_reserve(p, v.addr, 2*cl->elems.count, pos);
gb_unused(err);
@@ -4902,7 +4933,7 @@ gb_internal lbAddr lb_build_addr_compound_lit(lbProcedure *p, Ast *expr) {
if (cl->elems.count == 0) {
break;
}
- GB_ASSERT(expr->file()->feature_flags & OptInFeatureFlag_DynamicLiterals);
+ GB_ASSERT(expr->file()->feature_flags & OptInFeatureFlag_DynamicLiterals || build_context.dynamic_literals);
Type *et = bt->DynamicArray.elem;
lbValue size = lb_const_int(p->module, t_int, type_size_of(et));
@@ -5123,8 +5154,6 @@ gb_internal lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) {
return lb_build_addr(p, unparen_expr(se->selector));
}
-
- Type *type = base_type(tav.type);
if (tav.mode == Addressing_Type) { // Addressing_Type
Selection sel = lookup_field(tav.type, selector, true);
if (sel.pseudo_field) {
@@ -5159,18 +5188,29 @@ gb_internal lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) {
return lb_addr_swizzle(a, type, swizzle_count, swizzle_indices);
}
- Selection sel = lookup_field(type, selector, false);
+ Selection sel = lookup_field(tav.type, selector, false);
GB_ASSERT(sel.entity != nullptr);
- if (sel.pseudo_field) {
- GB_ASSERT(sel.entity->kind == Entity_Procedure || sel.entity->kind == Entity_ProcGroup);
+ if (sel.pseudo_field && (sel.entity->kind == Entity_Procedure || sel.entity->kind == Entity_ProcGroup)) {
Entity *e = entity_of_node(sel_node);
GB_ASSERT(e->kind == Entity_Procedure);
return lb_addr(lb_find_value_from_entity(p->module, e));
}
- if (sel.is_bit_field) {
- lbAddr addr = lb_build_addr(p, se->expr);
+ lbAddr addr = lb_build_addr(p, se->expr);
+
+ // NOTE(harold): Only allow ivar pseudo field access on indirect selectors.
+ // It is incoherent otherwise as Objective-C objects are zero-sized.
+ Type *deref_type = type_deref(tav.type);
+ if (tav.type->kind == Type_Pointer && deref_type->kind == Type_Named && deref_type->Named.type_name->TypeName.objc_ivar) {
+ // NOTE(harold): We need to load the ivar from the current address and
+ // replace addr with the loaded ivar addr to apply the selector load properly.
+ addr = lb_addr(lb_emit_load(p, addr.addr));
+ lbValue ivar_ptr = lb_handle_objc_ivar_for_objc_object_pointer(p, addr.addr);
+ addr = lb_addr(ivar_ptr);
+ }
+
+ if (sel.is_bit_field) {
Selection sub_sel = sel;
sub_sel.index.count -= 1;
@@ -5196,7 +5236,6 @@ gb_internal lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) {
}
{
- lbAddr addr = lb_build_addr(p, se->expr);
if (addr.kind == lbAddr_Map) {
lbValue v = lb_addr_load(p, addr);
lbValue a = lb_address_from_load_or_generate_local(p, v);
diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp
index 762256258..aaa9ffd4d 100644
--- a/src/llvm_backend_general.cpp
+++ b/src/llvm_backend_general.cpp
@@ -15,21 +15,39 @@ gb_global isize lb_global_type_info_member_offsets_index = 0;
gb_global isize lb_global_type_info_member_usings_index = 0;
gb_global isize lb_global_type_info_member_tags_index = 0;
-
gb_internal void lb_init_module(lbModule *m, Checker *c) {
m->info = &c->info;
- gbString module_name = gb_string_make(heap_allocator(), "odin_package");
- if (m->file) {
- module_name = gb_string_append_fmt(module_name, "-%u", m->file->id+1);
+
+ String name = build_context.build_paths[BuildPath_Output].name;
+ gbString module_name = gb_string_make(heap_allocator(), "");
+ module_name = gb_string_append_length(module_name, name.text, name.len);
+
+ if (!USE_SEPARATE_MODULES) {
+ // ignore suffixes
+ } else if (m->file) {
+ if (gb_string_length(module_name)) {
+ module_name = gb_string_appendc(module_name, "-");
+ }
+ if (m->pkg) {
+ module_name = gb_string_append_length(module_name, m->pkg->name.text, m->pkg->name.len);
+ module_name = gb_string_appendc(module_name, "-");
+ }
+ String filename = filename_from_path(m->file->filename);
+ module_name = gb_string_append_length(module_name, filename.text, filename.len);
} else if (m->pkg) {
- module_name = gb_string_appendc(module_name, "-");
+ if (gb_string_length(module_name)) {
+ module_name = gb_string_appendc(module_name, "-");
+ }
module_name = gb_string_append_length(module_name, m->pkg->name.text, m->pkg->name.len);
- } else if (USE_SEPARATE_MODULES) {
- module_name = gb_string_appendc(module_name, "-builtin");
+ } else {
+ if (gb_string_length(module_name)) {
+ module_name = gb_string_appendc(module_name, "-");
+ }
+ module_name = gb_string_appendc(module_name, "builtin");
}
- m->module_name = module_name ? module_name : "odin_package";
+ m->module_name = module_name;
m->ctx = LLVMContextCreate();
m->mod = LLVMModuleCreateWithNameInContext(m->module_name, m->ctx);
// m->debug_builder = nullptr;
@@ -68,10 +86,7 @@ gb_internal void lb_init_module(lbModule *m, Checker *c) {
string_map_init(&m->procedures);
string_map_init(&m->const_strings);
map_init(&m->function_type_map);
- map_init(&m->equal_procs);
- map_init(&m->hasher_procs);
- map_init(&m->map_get_procs);
- map_init(&m->map_set_procs);
+ string_map_init(&m->gen_procs);
if (USE_SEPARATE_MODULES) {
array_init(&m->procedures_to_generate, a, 0, 1<<10);
map_init(&m->procedure_values, 1<<11);
@@ -86,6 +101,7 @@ gb_internal void lb_init_module(lbModule *m, Checker *c) {
string_map_init(&m->objc_classes);
string_map_init(&m->objc_selectors);
+ string_map_init(&m->objc_ivars);
map_init(&m->map_info_map, 0);
map_init(&m->map_cell_info_map, 0);
@@ -156,7 +172,11 @@ gb_internal bool lb_init_generator(lbGenerator *gen, Checker *c) {
}
mpsc_init(&gen->entities_to_correct_linkage, heap_allocator());
-
+ mpsc_init(&gen->objc_selectors, heap_allocator());
+ mpsc_init(&gen->objc_classes, heap_allocator());
+ mpsc_init(&gen->objc_ivars, heap_allocator());
+ mpsc_init(&gen->raddebug_section_strings, heap_allocator());
+
return true;
}
@@ -219,7 +239,7 @@ gb_internal void lb_loop_end(lbProcedure *p, lbLoopData const &data) {
gb_internal void lb_make_global_private_const(LLVMValueRef global_data) {
LLVMSetLinkage(global_data, LLVMLinkerPrivateLinkage);
- LLVMSetUnnamedAddress(global_data, LLVMGlobalUnnamedAddr);
+ // LLVMSetUnnamedAddress(global_data, LLVMGlobalUnnamedAddr);
LLVMSetGlobalConstant(global_data, true);
}
gb_internal void lb_make_global_private_const(lbAddr const &addr) {
@@ -339,7 +359,7 @@ gb_internal LLVMValueRef llvm_const_insert_value(lbModule *m, LLVMValueRef agg,
gb_internal LLVMValueRef llvm_cstring(lbModule *m, String const &str) {
- lbValue v = lb_find_or_add_entity_string(m, str);
+ lbValue v = lb_find_or_add_entity_string(m, str, false);
unsigned indices[1] = {0};
return llvm_const_extract_value(m, v.value, indices, gb_count_of(indices));
}
@@ -526,8 +546,11 @@ gb_internal lbValue lb_addr_get_ptr(lbProcedure *p, lbAddr const &addr) {
break;
case lbAddr_Swizzle:
+ GB_PANIC("lbAddr_Swizzle should be handled elsewhere");
+ break;
+
case lbAddr_SwizzleLarge:
- // TOOD(bill): is this good enough logic?
+ GB_PANIC("lbAddr_SwizzleLarge should be handled elsewhere");
break;
}
@@ -540,6 +563,34 @@ gb_internal lbValue lb_build_addr_ptr(lbProcedure *p, Ast *expr) {
return lb_addr_get_ptr(p, addr);
}
+gb_internal void lb_set_file_line_col(lbProcedure *p, Array<lbValue> arr, TokenPos pos) {
+ String file = get_file_path_string(pos.file_id);
+ i32 line = pos.line;
+ i32 col = pos.column;
+
+ switch (build_context.source_code_location_info) {
+ case SourceCodeLocationInfo_Normal:
+ break;
+ case SourceCodeLocationInfo_Obfuscated:
+ file = obfuscate_string(file, "F");
+ line = obfuscate_i32(line);
+ col = obfuscate_i32(col);
+ break;
+ case SourceCodeLocationInfo_Filename:
+ file = last_path_element(file);
+ break;
+ case SourceCodeLocationInfo_None:
+ file = str_lit("");
+ line = 0;
+ col = 0;
+ break;
+ }
+
+ arr[0] = lb_find_or_add_entity_string(p->module, file, false);
+ arr[1] = lb_const_int(p->module, t_i32, line);
+ arr[2] = lb_const_int(p->module, t_i32, col);
+}
+
gb_internal void lb_emit_bounds_check(lbProcedure *p, Token token, lbValue index, lbValue len) {
if (build_context.no_bounds_check) {
return;
@@ -553,14 +604,8 @@ gb_internal void lb_emit_bounds_check(lbProcedure *p, Token token, lbValue index
index = lb_emit_conv(p, index, t_int);
len = lb_emit_conv(p, len, t_int);
- lbValue file = lb_find_or_add_entity_string(p->module, get_file_path_string(token.pos.file_id));
- lbValue line = lb_const_int(p->module, t_i32, token.pos.line);
- lbValue column = lb_const_int(p->module, t_i32, token.pos.column);
-
auto args = array_make<lbValue>(temporary_allocator(), 5);
- args[0] = file;
- args[1] = line;
- args[2] = column;
+ lb_set_file_line_col(p, args, token.pos);
args[3] = index;
args[4] = len;
@@ -582,14 +627,8 @@ gb_internal void lb_emit_matrix_bounds_check(lbProcedure *p, Token token, lbValu
row_count = lb_emit_conv(p, row_count, t_int);
column_count = lb_emit_conv(p, column_count, t_int);
- lbValue file = lb_find_or_add_entity_string(p->module, get_file_path_string(token.pos.file_id));
- lbValue line = lb_const_int(p->module, t_i32, token.pos.line);
- lbValue column = lb_const_int(p->module, t_i32, token.pos.column);
-
auto args = array_make<lbValue>(temporary_allocator(), 7);
- args[0] = file;
- args[1] = line;
- args[2] = column;
+ lb_set_file_line_col(p, args, token.pos);
args[3] = row_index;
args[4] = column_index;
args[5] = row_count;
@@ -610,14 +649,8 @@ gb_internal void lb_emit_multi_pointer_slice_bounds_check(lbProcedure *p, Token
low = lb_emit_conv(p, low, t_int);
high = lb_emit_conv(p, high, t_int);
- lbValue file = lb_find_or_add_entity_string(p->module, get_file_path_string(token.pos.file_id));
- lbValue line = lb_const_int(p->module, t_i32, token.pos.line);
- lbValue column = lb_const_int(p->module, t_i32, token.pos.column);
-
auto args = array_make<lbValue>(permanent_allocator(), 5);
- args[0] = file;
- args[1] = line;
- args[2] = column;
+ lb_set_file_line_col(p, args, token.pos);
args[3] = low;
args[4] = high;
@@ -632,16 +665,11 @@ gb_internal void lb_emit_slice_bounds_check(lbProcedure *p, Token token, lbValue
return;
}
- lbValue file = lb_find_or_add_entity_string(p->module, get_file_path_string(token.pos.file_id));
- lbValue line = lb_const_int(p->module, t_i32, token.pos.line);
- lbValue column = lb_const_int(p->module, t_i32, token.pos.column);
high = lb_emit_conv(p, high, t_int);
if (!lower_value_used) {
auto args = array_make<lbValue>(permanent_allocator(), 5);
- args[0] = file;
- args[1] = line;
- args[2] = column;
+ lb_set_file_line_col(p, args, token.pos);
args[3] = high;
args[4] = len;
@@ -651,9 +679,7 @@ gb_internal void lb_emit_slice_bounds_check(lbProcedure *p, Token token, lbValue
low = lb_emit_conv(p, low, t_int);
auto args = array_make<lbValue>(permanent_allocator(), 6);
- args[0] = file;
- args[1] = line;
- args[2] = column;
+ lb_set_file_line_col(p, args, token.pos);
args[3] = low;
args[4] = high;
args[5] = len;
@@ -877,8 +903,8 @@ gb_internal void lb_addr_store(lbProcedure *p, lbAddr addr, lbValue value) {
Type *t = base_type(type_deref(addr.addr.type));
GB_ASSERT(t->kind == Type_Struct && t->Struct.soa_kind != StructSoa_None);
lbValue len = lb_soa_struct_len(p, addr.addr);
- if (addr.soa.index_expr != nullptr) {
- lb_emit_bounds_check(p, ast_token(addr.soa.index_expr), index, len);
+ if (addr.soa.index_expr != nullptr && (!lb_is_const(addr.soa.index) || t->Struct.soa_kind != StructSoa_Fixed)) {
+ lb_emit_bounds_check(p, ast_token(addr.soa.index_expr), addr.soa.index, len);
}
}
@@ -911,7 +937,7 @@ gb_internal void lb_addr_store(lbProcedure *p, lbAddr addr, lbValue value) {
GB_ASSERT(value.value != nullptr);
value = lb_emit_conv(p, value, lb_addr_type(addr));
- lbValue dst = lb_addr_get_ptr(p, addr);
+ lbValue dst = addr.addr;
lbValue src = lb_address_from_load_or_generate_local(p, value);
{
lbValue src_ptrs[4] = {};
@@ -937,7 +963,7 @@ gb_internal void lb_addr_store(lbProcedure *p, lbAddr addr, lbValue value) {
GB_ASSERT(value.value != nullptr);
value = lb_emit_conv(p, value, lb_addr_type(addr));
- lbValue dst = lb_addr_get_ptr(p, addr);
+ lbValue dst = addr.addr;
lbValue src = lb_address_from_load_or_generate_local(p, value);
for_array(i, addr.swizzle_large.indices) {
lbValue src_ptr = lb_emit_array_epi(p, src, i);
@@ -1020,7 +1046,7 @@ gb_internal void lb_emit_store(lbProcedure *p, lbValue ptr, lbValue value) {
LLVMConstInt(LLVMInt64TypeInContext(p->module->ctx), lb_sizeof(LLVMTypeOf(value.value)), false));
return;
} else if (LLVMIsConstant(value.value)) {
- lbAddr addr = lb_add_global_generated(p->module, value.type, value, nullptr);
+ lbAddr addr = lb_add_global_generated_from_procedure(p, value.type, value);
lb_make_global_private_const(addr);
LLVMValueRef dst_ptr = ptr.value;
@@ -1453,148 +1479,30 @@ gb_internal void lb_clone_struct_type(LLVMTypeRef dst, LLVMTypeRef src) {
LLVMStructSetBody(dst, fields, field_count, LLVMIsPackedStruct(src));
}
-gb_internal String lb_mangle_name(Entity *e) {
- String name = e->token.string;
-
- AstPackage *pkg = e->pkg;
- GB_ASSERT_MSG(pkg != nullptr, "Missing package for '%.*s'", LIT(name));
- String pkgn = pkg->name;
- GB_ASSERT(!rune_is_digit(pkgn[0]));
- if (pkgn == "llvm") {
- pkgn = str_lit("llvm$");
- }
-
- 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 if (is_blank_ident(e->token)) {
- require_suffix_id = true;
- }if (e->flags & EntityFlag_NotExported) {
- require_suffix_id = true;
- }
-
- if (require_suffix_id) {
- max_len += 21;
- }
-
- char *new_name = gb_alloc_array(permanent_allocator(), char, max_len);
- isize new_name_len = gb_snprintf(
- new_name, max_len,
- "%.*s" ABI_PKG_NAME_SEPARATOR "%.*s", LIT(pkgn), LIT(name)
- );
- if (require_suffix_id) {
- char *str = new_name + new_name_len-1;
- isize len = max_len-new_name_len;
- isize extra = gb_snprintf(str, len, "-%llu", cast(unsigned long long)e->id);
- new_name_len += extra-1;
- }
-
- String mangled_name = make_string((u8 const *)new_name, new_name_len-1);
- return mangled_name;
-}
-
-gb_internal String lb_set_nested_type_name_ir_mangled_name(Entity *e, lbProcedure *p, lbModule *module) {
- // NOTE(bill, 2020-03-08): A polymorphic procedure may take a nested type declaration
- // and as a result, the declaration does not have time to determine what it should be
-
- GB_ASSERT(e != nullptr && e->kind == Entity_TypeName);
- if (e->TypeName.ir_mangled_name.len != 0) {
- return e->TypeName.ir_mangled_name;
- }
- GB_ASSERT((e->scope->flags & ScopeFlag_File) == 0);
-
- if (p == nullptr) {
- Entity *proc = nullptr;
- if (e->parent_proc_decl != nullptr) {
- proc = e->parent_proc_decl->entity;
- } else {
- Scope *scope = e->scope;
- while (scope != nullptr && (scope->flags & ScopeFlag_Proc) == 0) {
- scope = scope->parent;
- }
- GB_ASSERT(scope != nullptr);
- GB_ASSERT(scope->flags & ScopeFlag_Proc);
- proc = scope->procedure_entity;
- }
- if (proc != nullptr) {
- GB_ASSERT(proc->kind == Entity_Procedure);
- if (proc->code_gen_procedure != nullptr) {
- p = proc->code_gen_procedure;
- }
- }
- }
-
- // NOTE(bill): Generate a new name
- // parent_proc.name-guid
- String ts_name = e->token.string;
-
- if (p != nullptr) {
- isize name_len = p->name.len + 1 + ts_name.len + 1 + 10 + 1;
- char *name_text = gb_alloc_array(permanent_allocator(), char, name_len);
- u32 guid = 1+p->module->nested_type_name_guid.fetch_add(1);
- name_len = gb_snprintf(name_text, name_len, "%.*s" ABI_PKG_NAME_SEPARATOR "%.*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;
- return name;
- } else {
- // NOTE(bill): a nested type be required before its parameter procedure exists. Just give it a temp name for now
- isize name_len = 9 + 1 + ts_name.len + 1 + 10 + 1;
- char *name_text = gb_alloc_array(permanent_allocator(), char, name_len);
- static std::atomic<u32> guid;
- name_len = gb_snprintf(name_text, name_len, "_internal" ABI_PKG_NAME_SEPARATOR "%.*s-%u", LIT(ts_name), 1+guid.fetch_add(1));
-
- String name = make_string(cast(u8 *)name_text, name_len-1);
- e->TypeName.ir_mangled_name = name;
- return name;
- }
-}
-
-gb_internal String lb_get_entity_name(lbModule *m, Entity *e, String default_name) {
+gb_internal String lb_get_entity_name(lbModule *m, Entity *e) {
GB_ASSERT(m != nullptr);
- if (e != nullptr && e->kind == Entity_TypeName && e->TypeName.ir_mangled_name.len != 0) {
+ GB_ASSERT(e != nullptr);
+ if (e->kind == Entity_TypeName && e->TypeName.ir_mangled_name.len != 0) {
return e->TypeName.ir_mangled_name;
+ } else if (e->kind == Entity_Procedure && e->Procedure.link_name.len != 0) {
+ return e->Procedure.link_name;
}
- GB_ASSERT(e != nullptr);
if (e->pkg == nullptr) {
return e->token.string;
}
- if (e->kind == Entity_TypeName && (e->scope->flags & ScopeFlag_File) == 0) {
- return lb_set_nested_type_name_ir_mangled_name(e, nullptr, m);
- }
-
- String name = {};
+ gbString w = string_canonical_entity_name(heap_allocator(), e);
+ defer (gb_string_free(w));
- bool no_name_mangle = false;
-
- if (e->kind == Entity_Variable) {
- bool is_foreign = e->Variable.is_foreign;
- bool is_export = e->Variable.is_export;
- no_name_mangle = e->Variable.link_name.len > 0 || is_foreign || is_export;
- if (e->Variable.link_name.len > 0) {
- return e->Variable.link_name;
- }
- } else if (e->kind == Entity_Procedure && e->Procedure.link_name.len > 0) {
- return e->Procedure.link_name;
- } else if (e->kind == Entity_Procedure && e->Procedure.is_export) {
- no_name_mangle = true;
- }
-
- if (!no_name_mangle) {
- name = lb_mangle_name(e);
- }
- if (name.len == 0) {
- name = e->token.string;
- }
+ String name = copy_string(permanent_allocator(), make_string(cast(u8 const *)w, gb_string_length(w)));
if (e->kind == Entity_TypeName) {
e->TypeName.ir_mangled_name = name;
} else if (e->kind == Entity_Procedure) {
e->Procedure.link_name = name;
+ } else if (e->kind == Entity_Variable) {
+ e->Variable.link_name = name;
}
return name;
@@ -1912,15 +1820,24 @@ gb_internal LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
return type;
}
type = LLVMStructCreateNamed(ctx, name);
- LLVMTypeRef fields[2] = {
- lb_type(m, t_rawptr),
- lb_type(m, t_typeid),
- };
- LLVMStructSetBody(type, fields, 2, false);
+ if (build_context.ptr_size == 4) {
+ LLVMTypeRef fields[3] = {
+ lb_type(m, t_rawptr),
+ lb_type_padding_filler(m, build_context.ptr_size, build_context.ptr_size), // padding
+ lb_type(m, t_typeid),
+ };
+ LLVMStructSetBody(type, fields, 3, false);
+ } else {
+ LLVMTypeRef fields[2] = {
+ lb_type(m, t_rawptr),
+ lb_type(m, t_typeid),
+ };
+ LLVMStructSetBody(type, fields, 2, false);
+ }
return type;
}
- case Basic_typeid: return LLVMIntTypeInContext(m->ctx, 8*cast(unsigned)build_context.ptr_size);
+ case Basic_typeid: return LLVMIntTypeInContext(m->ctx, 64);
// Endian Specific Types
case Basic_i16le: return LLVMInt16TypeInContext(ctx);
@@ -2098,26 +2015,26 @@ gb_internal LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
case Type_Struct:
{
type_set_offsets(type);
-
+
i64 full_type_size = type_size_of(type);
i64 full_type_align = type_align_of(type);
GB_ASSERT(full_type_size % full_type_align == 0);
-
+
if (type->Struct.is_raw_union) {
-
+
lbStructFieldRemapping field_remapping = {};
slice_init(&field_remapping, permanent_allocator(), 1);
-
+
LLVMTypeRef fields[1] = {};
fields[0] = lb_type_padding_filler(m, full_type_size, full_type_align);
field_remapping[0] = 0;
-
+
LLVMTypeRef struct_type = LLVMStructTypeInContext(ctx, fields, gb_count_of(fields), false);
map_set(&m->struct_field_remapping, cast(void *)struct_type, field_remapping);
map_set(&m->struct_field_remapping, cast(void *)type, field_remapping);
return struct_type;
}
-
+
lbStructFieldRemapping field_remapping = {};
slice_init(&field_remapping, permanent_allocator(), type->Struct.fields.count);
@@ -2130,7 +2047,7 @@ gb_internal LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
LLVMTypeRef padding_type = lb_type_padding_filler(m, 0, type_align_of(type));
array_add(&fields, padding_type);
}
-
+
i64 prev_offset = 0;
bool requires_packing = type->Struct.is_packed;
for (i32 field_index : struct_fields_index_by_increasing_offset(temporary_allocator(), type)) {
@@ -2161,7 +2078,7 @@ gb_internal LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
prev_offset = offset + type_size_of(field->type);
}
-
+
i64 end_padding = full_type_size-prev_offset;
if (end_padding > 0) {
array_add(&fields, lb_type_padding_filler(m, end_padding, 1));
@@ -2170,14 +2087,14 @@ gb_internal LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
for_array(i, fields) {
GB_ASSERT(fields[i] != nullptr);
}
-
+
LLVMTypeRef struct_type = LLVMStructTypeInContext(ctx, fields.data, cast(unsigned)fields.count, requires_packing);
map_set(&m->struct_field_remapping, cast(void *)struct_type, field_remapping);
- map_set(&m->struct_field_remapping, cast(void *)type, field_remapping);
+ map_set(&m->struct_field_remapping, cast(void *)type, field_remapping);
#if 0
- GB_ASSERT_MSG(lb_sizeof(struct_type) == full_type_size,
- "(%lld) %s vs (%lld) %s",
- cast(long long)lb_sizeof(struct_type), LLVMPrintTypeToString(struct_type),
+ GB_ASSERT_MSG(lb_sizeof(struct_type) == full_type_size,
+ "(%lld) %s vs (%lld) %s",
+ cast(long long)lb_sizeof(struct_type), LLVMPrintTypeToString(struct_type),
cast(long long)full_type_size, type_to_string(type));
#endif
return struct_type;
@@ -2206,8 +2123,22 @@ gb_internal LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
LLVMTypeRef variant = lb_type(m, type->Union.variants[0]);
array_add(&fields, variant);
} else {
- LLVMTypeRef block_type = lb_type_padding_filler(m, block_size, align);
- LLVMTypeRef tag_type = lb_type(m, union_tag_type(type));
+ LLVMTypeRef block_type = nullptr;
+
+ bool all_pointers = align == build_context.ptr_size;
+ for (isize i = 0; all_pointers && i < type->Union.variants.count; i++) {
+ Type *t = type->Union.variants[i];
+ if (!is_type_internally_pointer_like(t)) {
+ all_pointers = false;
+ }
+ }
+ if (all_pointers) {
+ block_type = lb_type(m, t_rawptr);
+ } else {
+ block_type = lb_type_padding_filler(m, block_size, align);
+ }
+
+ LLVMTypeRef tag_type = lb_type(m, union_tag_type(type));
array_add(&fields, block_type);
array_add(&fields, tag_type);
i64 used_size = lb_sizeof(block_type) + lb_sizeof(tag_type);
@@ -2287,7 +2218,7 @@ gb_internal LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
field_count = 3;
}
LLVMTypeRef *fields = gb_alloc_array(permanent_allocator(), LLVMTypeRef, field_count);
- fields[0] = LLVMPointerType(lb_type(m, type->Pointer.elem), 0);
+ fields[0] = LLVMPointerType(lb_type(m, type->SoaPointer.elem), 0);
if (bigger_int) {
fields[1] = lb_type_padding_filler(m, build_context.ptr_size, build_context.ptr_size);
fields[2] = LLVMIntTypeInContext(ctx, 8*cast(unsigned)build_context.int_size);
@@ -2299,6 +2230,14 @@ gb_internal LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
case Type_BitField:
return lb_type_internal(m, type->BitField.backing_type);
+
+ case Type_Generic:
+ if (type->Generic.specialized) {
+ return lb_type_internal(m, type->Generic.specialized);
+ } else {
+ // For unspecialized generics, use a pointer type as a placeholder
+ return LLVMPointerType(LLVMInt8TypeInContext(m->ctx), 0);
+ }
}
GB_PANIC("Invalid type %s", type_to_string(type));
@@ -2464,6 +2403,29 @@ gb_internal void lb_add_attribute_to_proc_with_string(lbModule *m, LLVMValueRef
}
+gb_internal bool lb_apply_thread_local_model(LLVMValueRef value, String model) {
+ if (model != "") {
+ LLVMSetThreadLocal(value, true);
+
+ LLVMThreadLocalMode mode = LLVMGeneralDynamicTLSModel;
+ if (model == "default") {
+ mode = LLVMGeneralDynamicTLSModel;
+ } else if (model == "localdynamic") {
+ mode = LLVMLocalDynamicTLSModel;
+ } else if (model == "initialexec") {
+ mode = LLVMInitialExecTLSModel;
+ } else if (model == "localexec") {
+ mode = LLVMLocalExecTLSModel;
+ } else {
+ GB_PANIC("Unhandled thread local mode %.*s", LIT(model));
+ }
+ LLVMSetThreadLocalMode(value, mode);
+ return true;
+ }
+
+ return false;
+}
+
gb_internal void lb_add_edge(lbBlock *from, lbBlock *to) {
LLVMValueRef instr = LLVMGetLastInstruction(from->block);
@@ -2602,10 +2564,13 @@ general_end:;
}
}
- src_size = align_formula(src_size, src_align);
- dst_size = align_formula(dst_size, dst_align);
+ // NOTE(laytan): even though this logic seems sound, the Address Sanitizer does not
+ // want you to load/store the space of a value that is there for alignment.
+#if 0
+ i64 aligned_src_size = align_formula(src_size, src_align);
+ i64 aligned_dst_size = align_formula(dst_size, dst_align);
- if (LLVMIsALoadInst(val) && (src_size >= dst_size && src_align >= dst_align)) {
+ if (LLVMIsALoadInst(val) && (aligned_src_size >= aligned_dst_size && src_align >= dst_align)) {
LLVMValueRef val_ptr = LLVMGetOperand(val, 0);
val_ptr = LLVMBuildPointerCast(p->builder, val_ptr, LLVMPointerType(dst_type, 0), "");
LLVMValueRef loaded_val = OdinLLVMBuildLoad(p, dst_type, val_ptr);
@@ -2613,8 +2578,57 @@ general_end:;
// LLVMSetAlignment(loaded_val, gb_min(src_align, dst_align));
return loaded_val;
+ }
+#endif
+
+ if (src_size > dst_size) {
+ GB_ASSERT(p->decl_block != p->curr_block);
+ // NOTE(laytan): src is bigger than dst, need to memcpy the part of src we want.
+
+ LLVMValueRef val_ptr;
+ if (LLVMIsALoadInst(val)) {
+ val_ptr = LLVMGetOperand(val, 0);
+ } else if (LLVMIsAAllocaInst(val)) {
+ val_ptr = LLVMBuildPointerCast(p->builder, val, LLVMPointerType(src_type, 0), "");
+ } else {
+ // NOTE(laytan): we need a pointer to memcpy from.
+ LLVMValueRef val_copy = llvm_alloca(p, src_type, src_align);
+ val_ptr = LLVMBuildPointerCast(p->builder, val_copy, LLVMPointerType(src_type, 0), "");
+ LLVMBuildStore(p->builder, val, val_ptr);
+ }
+
+ i64 max_align = gb_max(lb_alignof(src_type), lb_alignof(dst_type));
+ max_align = gb_max(max_align, 16);
+
+ LLVMValueRef ptr = llvm_alloca(p, dst_type, max_align);
+ LLVMValueRef nptr = LLVMBuildPointerCast(p->builder, ptr, LLVMPointerType(dst_type, 0), "");
+
+ LLVMTypeRef types[3] = {
+ lb_type(p->module, t_rawptr),
+ lb_type(p->module, t_rawptr),
+ lb_type(p->module, t_int)
+ };
+
+ LLVMValueRef args[4] = {
+ nptr,
+ val_ptr,
+ LLVMConstInt(LLVMIntTypeInContext(p->module->ctx, 8*cast(unsigned)build_context.int_size), dst_size, 0),
+ LLVMConstInt(LLVMInt1TypeInContext(p->module->ctx), 0, 0),
+ };
+
+ lb_call_intrinsic(
+ p,
+ "llvm.memcpy.inline",
+ args,
+ gb_count_of(args),
+ types,
+ gb_count_of(types)
+ );
+
+ return OdinLLVMBuildLoad(p, dst_type, ptr);
} else {
GB_ASSERT(p->decl_block != p->curr_block);
+ GB_ASSERT(dst_size >= src_size);
i64 max_align = gb_max(lb_alignof(src_type), lb_alignof(dst_type));
max_align = gb_max(max_align, 16);
@@ -2630,9 +2644,14 @@ general_end:;
-gb_internal LLVMValueRef lb_find_or_add_entity_string_ptr(lbModule *m, String const &str) {
- StringHashKey key = string_hash_string(str);
- LLVMValueRef *found = string_map_get(&m->const_strings, key);
+gb_internal LLVMValueRef lb_find_or_add_entity_string_ptr(lbModule *m, String const &str, bool custom_link_section) {
+ StringHashKey key = {};
+ LLVMValueRef *found = nullptr;
+
+ if (!custom_link_section) {
+ key = string_hash_string(str);
+ found = string_map_get(&m->const_strings, key);
+ }
if (found != nullptr) {
return *found;
} else {
@@ -2643,12 +2662,10 @@ gb_internal LLVMValueRef lb_find_or_add_entity_string_ptr(lbModule *m, String co
false);
- isize max_len = 7+8+1;
- char *name = gb_alloc_array(permanent_allocator(), char, max_len);
-
- u32 id = m->gen->global_array_index.fetch_add(1);
- isize len = gb_snprintf(name, max_len, "csbs$%x", id);
- len -= 1;
+ u32 id = m->global_array_index.fetch_add(1);
+ gbString name = gb_string_make(temporary_allocator(), "csbs$");
+ name = gb_string_appendc(name, m->module_name);
+ name = gb_string_append_fmt(name, "$%x", id);
LLVMTypeRef type = LLVMTypeOf(data);
LLVMValueRef global_data = LLVMAddGlobal(m->mod, type, name);
@@ -2657,15 +2674,17 @@ gb_internal LLVMValueRef lb_find_or_add_entity_string_ptr(lbModule *m, String co
LLVMSetAlignment(global_data, 1);
LLVMValueRef ptr = LLVMConstInBoundsGEP2(type, global_data, indices, 2);
- string_map_set(&m->const_strings, key, ptr);
+ if (!custom_link_section) {
+ string_map_set(&m->const_strings, key, ptr);
+ }
return ptr;
}
}
-gb_internal lbValue lb_find_or_add_entity_string(lbModule *m, String const &str) {
+gb_internal lbValue lb_find_or_add_entity_string(lbModule *m, String const &str, bool custom_link_section) {
LLVMValueRef ptr = nullptr;
if (str.len != 0) {
- ptr = lb_find_or_add_entity_string_ptr(m, str);
+ ptr = lb_find_or_add_entity_string_ptr(m, str, custom_link_section);
} else {
ptr = LLVMConstNull(lb_type(m, t_u8_ptr));
}
@@ -2686,14 +2705,11 @@ gb_internal lbValue lb_find_or_add_entity_string_byte_slice_with_type(lbModule *
false);
- char *name = nullptr;
- {
- isize max_len = 7+8+1;
- name = gb_alloc_array(permanent_allocator(), char, max_len);
- u32 id = m->gen->global_array_index.fetch_add(1);
- isize len = gb_snprintf(name, max_len, "csbs$%x", id);
- len -= 1;
- }
+ u32 id = m->global_array_index.fetch_add(1);
+ gbString name = gb_string_make(temporary_allocator(), "csba$");
+ name = gb_string_appendc(name, m->module_name);
+ name = gb_string_append_fmt(name, "$%x", id);
+
LLVMTypeRef type = LLVMTypeOf(data);
LLVMValueRef global_data = LLVMAddGlobal(m->mod, type, name);
LLVMSetInitializer(global_data, data);
@@ -2813,6 +2829,14 @@ gb_internal lbValue lb_find_procedure_value_from_entity(lbModule *m, Entity *e)
ignore_body = other_module != m;
lbProcedure *missing_proc = lb_create_procedure(m, e, ignore_body);
+ if (missing_proc == nullptr) {
+ // This is an unspecialized polymorphic procedure, which should not be codegen'd
+ lbValue dummy = {};
+ dummy.value = nullptr;
+ dummy.type = nullptr;
+ return dummy;
+ }
+
if (ignore_body) {
mutex_lock(&gen->anonymous_proc_lits_mutex);
defer (mutex_unlock(&gen->anonymous_proc_lits_mutex));
@@ -2879,6 +2903,8 @@ gb_internal lbValue lb_generate_anonymous_proc_lit(lbModule *m, String const &pr
pl->decl->code_gen_module = m;
e->decl_info = pl->decl;
pl->decl->entity = e;
+ e->parent_proc_decl = pl->decl->parent;
+ e->Procedure.is_anonymous = true;
e->flags |= EntityFlag_ProcBodyChecked;
lbProcedure *p = lb_create_procedure(m, e);
@@ -2899,23 +2925,16 @@ gb_internal lbValue lb_generate_anonymous_proc_lit(lbModule *m, String const &pr
}
-gb_internal lbAddr lb_add_global_generated(lbModule *m, Type *type, lbValue value, Entity **entity_) {
+gb_internal lbAddr lb_add_global_generated_with_name(lbModule *m, Type *type, lbValue value, String name, Entity **entity_) {
+ GB_ASSERT(name.len != 0);
GB_ASSERT(type != nullptr);
type = default_type(type);
- isize max_len = 7+8+1;
- u8 *str = cast(u8 *)gb_alloc_array(permanent_allocator(), u8, max_len);
-
- u32 id = m->gen->global_generated_index.fetch_add(1);
-
- isize len = gb_snprintf(cast(char *)str, max_len, "ggv$%x", id);
- String name = make_string(str, len-1);
-
Scope *scope = nullptr;
Entity *e = alloc_entity_variable(scope, make_token_ident(name), type);
lbValue g = {};
g.type = alloc_type_pointer(type);
- g.value = LLVMAddGlobal(m->mod, lb_type(m, type), cast(char const *)str);
+ g.value = LLVMAddGlobal(m->mod, lb_type(m, type), alloc_cstring(temporary_allocator(), name));
if (value.value != nullptr) {
GB_ASSERT_MSG(LLVMIsConstant(value.value), LLVMPrintValueToString(value.value));
LLVMSetInitializer(g.value, value.value);
@@ -2931,6 +2950,25 @@ gb_internal lbAddr lb_add_global_generated(lbModule *m, Type *type, lbValue valu
return lb_addr(g);
}
+
+gb_internal lbAddr lb_add_global_generated_from_procedure(lbProcedure *p, Type *type, lbValue value) {
+ GB_ASSERT(type != nullptr);
+ type = default_type(type);
+
+ u32 index = ++p->global_generated_index;
+
+ gbString s = gb_string_make(temporary_allocator(), "ggv$");
+ // s = gb_string_appendc(s, p->module->module_name);
+ // s = gb_string_appendc(s, "$");
+ s = gb_string_append_length(s, p->name.text, p->name.len);
+ s = gb_string_append_fmt(s, "$%u", index);
+
+ String name = make_string(cast(u8 const *)s, gb_string_length(s));
+ return lb_add_global_generated_with_name(p->module, type, value, name);
+}
+
+
+
gb_internal lbValue lb_find_runtime_value(lbModule *m, String const &name) {
AstPackage *p = m->info->runtime_package;
Entity *e = scope_lookup_current(p->scope, name);
@@ -2991,25 +3029,7 @@ gb_internal lbValue lb_find_value_from_entity(lbModule *m, Entity *e) {
lb_set_entity_from_other_modules_linkage_correctly(other_module, e, name);
- if (e->Variable.thread_local_model != "") {
- LLVMSetThreadLocal(g.value, true);
-
- String m = e->Variable.thread_local_model;
- LLVMThreadLocalMode mode = LLVMGeneralDynamicTLSModel;
- if (m == "default") {
- mode = LLVMGeneralDynamicTLSModel;
- } else if (m == "localdynamic") {
- mode = LLVMLocalDynamicTLSModel;
- } else if (m == "initialexec") {
- mode = LLVMInitialExecTLSModel;
- } else if (m == "localexec") {
- mode = LLVMLocalExecTLSModel;
- } else {
- GB_PANIC("Unhandled thread local mode %.*s", LIT(m));
- }
- LLVMSetThreadLocalMode(g.value, mode);
- }
-
+ lb_apply_thread_local_model(g.value, e->Variable.thread_local_model);
return g;
}
@@ -3038,7 +3058,7 @@ gb_internal lbValue lb_generate_global_array(lbModule *m, Type *elem_type, i64 c
g.type = alloc_type_pointer(t);
LLVMSetInitializer(g.value, LLVMConstNull(lb_type(m, t)));
LLVMSetLinkage(g.value, LLVMPrivateLinkage);
- LLVMSetUnnamedAddress(g.value, LLVMGlobalUnnamedAddr);
+ // LLVMSetUnnamedAddress(g.value, LLVMGlobalUnnamedAddr);
string_map_set(&m->members, s, g);
return g;
}
@@ -3141,6 +3161,13 @@ gb_internal lbAddr lb_add_local(lbProcedure *p, Type *type, Entity *e, bool zero
if (e != nullptr) {
lb_add_entity(p->module, e, val);
lb_add_debug_local_variable(p, ptr, type, e->token);
+
+ // NOTE(lucas): In LLVM 20 and below we do not have the option to have asan cleanup poisoned stack
+ // locals ourselves. So we need to manually track and unpoison these locals on proc return.
+ // LLVM 21 adds the 'use-after-scope' asan option which does this for us.
+ if (build_context.sanitizer_flags & SanitizerFlag_Address && !p->entity->Procedure.no_sanitize_address) {
+ array_add(&p->asan_stack_locals, val);
+ }
}
if (zero_init) {
diff --git a/src/llvm_backend_opt.cpp b/src/llvm_backend_opt.cpp
index 7fe1359b4..8d5cfcb70 100644
--- a/src/llvm_backend_opt.cpp
+++ b/src/llvm_backend_opt.cpp
@@ -516,7 +516,7 @@ gb_internal void llvm_delete_function(LLVMValueRef func) {
LLVMDeleteFunction(func);
}
-gb_internal void lb_append_to_compiler_used(lbModule *m, LLVMValueRef func) {
+gb_internal void lb_append_to_compiler_used(lbModule *m, LLVMValueRef value) {
LLVMValueRef global = LLVMGetNamedGlobal(m->mod, "llvm.compiler.used");
LLVMValueRef *constants;
@@ -544,7 +544,7 @@ gb_internal void lb_append_to_compiler_used(lbModule *m, LLVMValueRef func) {
LLVMTypeRef Int8PtrTy = LLVMPointerType(LLVMInt8TypeInContext(m->ctx), 0);
LLVMTypeRef ATy = llvm_array_type(Int8PtrTy, operands);
- constants[operands - 1] = LLVMConstBitCast(func, Int8PtrTy);
+ constants[operands - 1] = LLVMConstBitCast(value, Int8PtrTy);
LLVMValueRef initializer = LLVMConstArray(Int8PtrTy, constants, operands);
global = LLVMAddGlobal(m->mod, ATy, "llvm.compiler.used");
diff --git a/src/llvm_backend_passes.cpp b/src/llvm_backend_passes.cpp
new file mode 100644
index 000000000..bea95ce8e
--- /dev/null
+++ b/src/llvm_backend_passes.cpp
@@ -0,0 +1,1195 @@
+ switch (build_context.optimization_level) {
+ case -1:
+ array_add(&passes, "function(annotation-remarks)");
+ break;
+ case 0:
+ array_add(&passes, "always-inline");
+ array_add(&passes, "function(annotation-remarks)");
+ break;
+ case 1:
+// default<Os>
+// Passes removed: coro, openmp, sroa
+#if LLVM_VERSION_MAJOR == 17
+ array_add(&passes, u8R"(
+annotation2metadata,
+forceattrs,
+inferattrs,
+function<eager-inv>(
+ lower-expect,
+ simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;no-switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,
+ early-cse<>
+),
+ipsccp,
+called-value-propagation,
+globalopt,
+function<eager-inv>(
+ mem2reg,
+ instcombine<max-iterations=1000;no-use-loop-info>,
+ simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>
+),
+require<globals-aa>,
+function(
+ invalidate<aa>
+),
+require<profile-summary>,
+cgscc(
+ devirt<4>(
+ inline<only-mandatory>,
+ inline,
+ function-attrs<skip-non-recursive>,
+ function<eager-inv;no-rerun>(
+ early-cse<memssa>,
+ speculative-execution,
+ jump-threading,
+ correlated-propagation,
+ simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,
+ instcombine<max-iterations=1000;no-use-loop-info>,
+ aggressive-instcombine,
+ constraint-elimination,
+ tailcallelim,
+ simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,
+ reassociate,
+ loop-mssa(
+ loop-instsimplify,
+ loop-simplifycfg,
+ licm<no-allowspeculation>,
+ loop-rotate<header-duplication;no-prepare-for-lto>,
+ licm<allowspeculation>,
+ simple-loop-unswitch<no-nontrivial;trivial>
+ ),
+ simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,
+ instcombine<max-iterations=1000;no-use-loop-info>,
+ loop(
+ loop-idiom,
+ indvars,
+ loop-deletion,
+ loop-unroll-full
+ ),
+ vector-combine,
+ mldst-motion<no-split-footer-bb>,
+ gvn<>,
+ sccp,
+ bdce,
+ instcombine<max-iterations=1000;no-use-loop-info>,
+ jump-threading,
+ correlated-propagation,
+ adce,
+ memcpyopt,
+ dse,
+ move-auto-init,
+ loop-mssa(
+ licm<allowspeculation>
+ ),
+ simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;hoist-common-insts;sink-common-insts;speculate-blocks;simplify-cond-branch>,
+ instcombine<max-iterations=1000;no-use-loop-info>
+ ),
+ function-attrs,
+ function(
+ require<should-not-run-function-passes>
+ )
+ )
+),
+deadargelim,
+globalopt,
+globaldce,
+elim-avail-extern,
+rpo-function-attrs,
+recompute-globalsaa,
+function<eager-inv>(
+ float2int,
+ lower-constant-intrinsics,
+ loop(
+ loop-rotate<header-duplication;no-prepare-for-lto>,
+ loop-deletion
+ ),
+ loop-distribute,
+ inject-tli-mappings,
+ loop-vectorize<no-interleave-forced-only;no-vectorize-forced-only;>,
+ loop-load-elim,
+ instcombine<max-iterations=1000;no-use-loop-info>,
+ simplifycfg<bonus-inst-threshold=1;forward-switch-cond;switch-range-to-icmp;switch-to-lookup;no-keep-loops;hoist-common-insts;sink-common-insts;speculate-blocks;simplify-cond-branch>,
+ slp-vectorizer,
+ vector-combine,
+ instcombine<max-iterations=1000;no-use-loop-info>,
+ loop-unroll<O2>,
+ transform-warning,
+ instcombine<max-iterations=1000;no-use-loop-info>,
+ loop-mssa(
+ licm<allowspeculation>
+ ),
+ alignment-from-assumptions,
+ loop-sink,
+ instsimplify,
+ div-rem-pairs,
+ tailcallelim,
+ simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>
+),
+globaldce,
+constmerge,
+cg-profile,
+rel-lookup-table-converter,
+function(
+ annotation-remarks
+),
+verify
+)");
+#elif LLVM_VERSION_MAJOR < 20
+ array_add(&passes, u8R"(
+annotation2metadata,
+forceattrs,
+inferattrs,
+function<eager-inv>(
+ lower-expect,
+ simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;no-switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,
+ sroa<modify-cfg>,
+ early-cse<>
+),
+ipsccp,
+called-value-propagation,
+globalopt,
+function<eager-inv>(
+ mem2reg,
+ instcombine<max-iterations=1;no-use-loop-info;no-verify-fixpoint>,
+ simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>
+),
+always-inline,
+require<globals-aa>,
+function(
+ invalidate<aa>
+),
+require<profile-summary>,
+cgscc(
+ devirt<4>(
+ inline,
+ function-attrs<skip-non-recursive-function-attrs>,
+ function<eager-inv;no-rerun>(
+ sroa<modify-cfg>,
+ early-cse<memssa>,
+ speculative-execution<only-if-divergent-target>,
+ jump-threading,
+ correlated-propagation,
+ simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,
+ instcombine<max-iterations=1;no-use-loop-info;no-verify-fixpoint>,
+ aggressive-instcombine,
+ tailcallelim,
+ simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,
+ reassociate,
+ constraint-elimination,
+ loop-mssa(
+ loop-instsimplify,
+ loop-simplifycfg,
+ licm<no-allowspeculation>,
+ loop-rotate<header-duplication;no-prepare-for-lto>,
+ licm<allowspeculation>,
+ simple-loop-unswitch<no-nontrivial;trivial>
+ ),
+ simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,
+ instcombine<max-iterations=1;no-use-loop-info;no-verify-fixpoint>,
+ loop(
+ loop-idiom,
+ indvars,
+ loop-deletion,
+ loop-unroll-full
+ ),
+ sroa<modify-cfg>,
+ vector-combine,
+ mldst-motion<no-split-footer-bb>,
+ gvn<>,
+ sccp,
+ bdce,
+ instcombine<max-iterations=1;no-use-loop-info;no-verify-fixpoint>,
+ jump-threading,
+ correlated-propagation,
+ adce,
+ memcpyopt,
+ dse,
+ move-auto-init,
+ loop-mssa(
+ licm<allowspeculation>
+ ),
+ simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;hoist-common-insts;sink-common-insts;speculate-blocks;simplify-cond-branch>,
+ instcombine<max-iterations=1;no-use-loop-info;no-verify-fixpoint>
+ ),
+ function-attrs,
+ function(
+ require<should-not-run-function-passes>
+ )
+ )
+),
+deadargelim,
+globalopt,
+globaldce,
+elim-avail-extern,
+rpo-function-attrs,
+recompute-globalsaa,
+function<eager-inv>(
+ float2int,
+ lower-constant-intrinsics,
+ loop(
+ loop-rotate<header-duplication;no-prepare-for-lto>,
+ loop-deletion
+ ),
+ loop-distribute,
+ inject-tli-mappings,
+ loop-vectorize<no-interleave-forced-only;no-vectorize-forced-only;>,
+ infer-alignment,
+ loop-load-elim,
+ instcombine<max-iterations=1;no-use-loop-info;no-verify-fixpoint>,
+ simplifycfg<bonus-inst-threshold=1;forward-switch-cond;switch-range-to-icmp;switch-to-lookup;no-keep-loops;hoist-common-insts;sink-common-insts;speculate-blocks;simplify-cond-branch>,
+ slp-vectorizer,
+ vector-combine,
+ instcombine<max-iterations=1;no-use-loop-info;no-verify-fixpoint>,
+ loop-unroll<O2>,
+ transform-warning,
+ sroa<preserve-cfg>,
+ infer-alignment,
+ instcombine<max-iterations=1;no-use-loop-info;no-verify-fixpoint>,
+ loop-mssa(
+ licm<allowspeculation>
+ ),
+ alignment-from-assumptions,
+ loop-sink,
+ instsimplify,
+ div-rem-pairs,
+ tailcallelim,
+ simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>
+),
+globaldce,
+constmerge,
+cg-profile,
+rel-lookup-table-converter,
+function(
+ annotation-remarks
+),
+verify
+)");
+#else
+ array_add(&passes, u8R"(
+annotation2metadata,
+forceattrs,
+inferattrs,
+function<eager-inv>(
+ ee-instrument<>,
+ lower-expect,
+ simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;no-switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-hoist-loads-stores-with-cond-faulting;no-sink-common-insts;speculate-blocks;simplify-cond-branch;no-speculate-unpredictables>,
+ sroa<modify-cfg>,
+ early-cse<>
+),
+ipsccp,
+called-value-propagation,
+globalopt,
+function<eager-inv>(
+ mem2reg,
+ instcombine<max-iterations=1;no-verify-fixpoint>,
+ simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-hoist-loads-stores-with-cond-faulting;no-sink-common-insts;speculate-blocks;simplify-cond-branch;no-speculate-unpredictables>
+),
+always-inline,
+require<globals-aa>,
+function(
+ invalidate<aa>
+),
+require<profile-summary>,
+cgscc(
+ devirt<4>(
+ inline,
+ function-attrs<skip-non-recursive-function-attrs>,
+ function<eager-inv;no-rerun>(
+ sroa<modify-cfg>,
+ early-cse<memssa>,
+ speculative-execution<only-if-divergent-target>,
+ jump-threading,
+ correlated-propagation,
+ simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-hoist-loads-stores-with-cond-faulting;no-sink-common-insts;speculate-blocks;simplify-cond-branch;no-speculate-unpredictables>,
+ instcombine<max-iterations=1;no-verify-fixpoint>,
+ aggressive-instcombine,
+ tailcallelim,
+ simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-hoist-loads-stores-with-cond-faulting;no-sink-common-insts;speculate-blocks;simplify-cond-branch;no-speculate-unpredictables>,
+ reassociate,
+ constraint-elimination,
+ loop-mssa(
+ loop-instsimplify,
+ loop-simplifycfg,
+ licm<no-allowspeculation>,
+ loop-rotate<header-duplication;no-prepare-for-lto>,
+ licm<allowspeculation>,
+ simple-loop-unswitch<no-nontrivial;trivial>
+ ),
+ simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-hoist-loads-stores-with-cond-faulting;no-sink-common-insts;speculate-blocks;simplify-cond-branch;no-speculate-unpredictables>,
+ instcombine<max-iterations=1;no-verify-fixpoint>,
+ loop(
+ loop-idiom,
+ indvars,
+ extra-simple-loop-unswitch-passes,
+ loop-deletion,loop-unroll-full
+ ),
+ sroa<modify-cfg>,
+ vector-combine,
+ mldst-motion<no-split-footer-bb>,
+ gvn<>,
+ sccp,
+ bdce,
+ instcombine<max-iterations=1;no-verify-fixpoint>,
+ jump-threading,
+ correlated-propagation,
+ adce,
+ memcpyopt,
+ dse,
+ move-auto-init,
+ loop-mssa(
+ licm<allowspeculation>
+ ),
+ simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;hoist-common-insts;no-hoist-loads-stores-with-cond-faulting;sink-common-insts;speculate-blocks;simplify-cond-branch;no-speculate-unpredictables>,
+ instcombine<max-iterations=1;no-verify-fixpoint>
+ ),
+ function-attrs,
+ function(
+ require<should-not-run-function-passes>
+ )
+ )
+),
+deadargelim,
+globalopt,
+globaldce,
+elim-avail-extern,
+rpo-function-attrs,
+recompute-globalsaa,
+function<eager-inv>(
+ float2int,
+ lower-constant-intrinsics,
+ loop(
+ loop-rotate<header-duplication;no-prepare-for-lto>,
+ loop-deletion
+ ),
+ loop-distribute,
+ inject-tli-mappings,
+ loop-vectorize<no-interleave-forced-only;no-vectorize-forced-only;>,
+ infer-alignment,
+ loop-load-elim,
+ instcombine<max-iterations=1;no-verify-fixpoint>,
+ simplifycfg<bonus-inst-threshold=1;forward-switch-cond;switch-range-to-icmp;switch-to-lookup;no-keep-loops;hoist-common-insts;no-hoist-loads-stores-with-cond-faulting;sink-common-insts;speculate-blocks;simplify-cond-branch;no-speculate-unpredictables>,
+ slp-vectorizer,
+ vector-combine,
+ instcombine<max-iterations=1;no-verify-fixpoint>,
+ loop-unroll<O2>,
+ transform-warning,
+ sroa<preserve-cfg>,
+ infer-alignment,
+ instcombine<max-iterations=1;no-verify-fixpoint>,
+ loop-mssa(
+ licm<allowspeculation>
+ ),
+ alignment-from-assumptions,
+ loop-sink,
+ instsimplify,
+ div-rem-pairs,
+ tailcallelim,
+ simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;hoist-loads-stores-with-cond-faulting;no-sink-common-insts;speculate-blocks;simplify-cond-branch;speculate-unpredictables>
+),
+globaldce,
+constmerge,
+cg-profile,
+rel-lookup-table-converter,
+function(
+ annotation-remarks
+),
+verify
+)");
+
+#endif
+ break;
+// default<O2>
+// Passes removed: coro, openmp, sroa
+ case 2:
+#if LLVM_VERSION_MAJOR == 17
+ array_add(&passes, u8R"(
+annotation2metadata,
+forceattrs,
+inferattrs,
+function<eager-inv>(
+ lower-expect,
+ simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;no-switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,
+ early-cse<>
+),
+ipsccp,
+called-value-propagation,
+globalopt,
+function<eager-inv>(
+ mem2reg,
+ instcombine<max-iterations=1000;no-use-loop-info>,
+ simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>
+),
+require<globals-aa>,
+function(
+ invalidate<aa>
+),
+require<profile-summary>,
+cgscc(
+ devirt<4>(
+ inline<only-mandatory>,
+ inline,
+ function-attrs<skip-non-recursive>,
+ function<eager-inv;no-rerun>(
+ early-cse<memssa>,
+ speculative-execution,
+ jump-threading,
+ correlated-propagation,
+ simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,
+ instcombine<max-iterations=1000;no-use-loop-info>,
+ aggressive-instcombine,
+ constraint-elimination,
+ libcalls-shrinkwrap,
+ tailcallelim,
+ simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,
+ reassociate,
+ loop-mssa(
+ loop-instsimplify,
+ loop-simplifycfg,
+ licm<no-allowspeculation>,
+ loop-rotate<header-duplication;no-prepare-for-lto>,
+ licm<allowspeculation>,
+ simple-loop-unswitch<no-nontrivial;trivial>
+ ),
+ simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,
+ instcombine<max-iterations=1000;no-use-loop-info>,
+ loop(
+ loop-idiom,
+ indvars,
+ loop-deletion,
+ loop-unroll-full
+ ),
+ vector-combine,
+ mldst-motion<no-split-footer-bb>,
+ gvn<>,
+ sccp,
+ bdce,
+ instcombine<max-iterations=1000;no-use-loop-info>,
+ jump-threading,
+ correlated-propagation,
+ adce,
+ memcpyopt,
+ dse,
+ move-auto-init,
+ loop-mssa(
+ licm<allowspeculation>
+ ),
+ simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;hoist-common-insts;sink-common-insts;speculate-blocks;simplify-cond-branch>,
+ instcombine<max-iterations=1000;no-use-loop-info>
+ ),
+ function-attrs,
+ function(
+ require<should-not-run-function-passes>
+ )
+ )
+),
+deadargelim,
+globalopt,
+globaldce,
+elim-avail-extern,
+rpo-function-attrs,
+recompute-globalsaa,
+function<eager-inv>(
+ float2int,
+ lower-constant-intrinsics,
+ loop(
+ loop-rotate<header-duplication;no-prepare-for-lto>,
+ loop-deletion
+ ),
+ loop-distribute,
+ inject-tli-mappings,
+ loop-vectorize<no-interleave-forced-only;no-vectorize-forced-only;>,
+ loop-load-elim,
+ instcombine<max-iterations=1000;no-use-loop-info>,
+ simplifycfg<bonus-inst-threshold=1;forward-switch-cond;switch-range-to-icmp;switch-to-lookup;no-keep-loops;hoist-common-insts;sink-common-insts;speculate-blocks;simplify-cond-branch>,
+ slp-vectorizer,
+ vector-combine,
+ instcombine<max-iterations=1000;no-use-loop-info>,
+ loop-unroll<O2>,
+ transform-warning,
+ instcombine<max-iterations=1000;no-use-loop-info>,
+ loop-mssa(
+ licm<allowspeculation>
+ ),
+ alignment-from-assumptions,
+ loop-sink,
+ instsimplify,
+ div-rem-pairs,
+ tailcallelim,
+ simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>
+),
+globaldce,
+constmerge,
+cg-profile,
+rel-lookup-table-converter,
+function(
+ annotation-remarks
+),
+verify
+)");
+#elif LLVM_VERSION_MAJOR < 20
+ array_add(&passes, u8R"(
+annotation2metadata,
+forceattrs,
+inferattrs,
+function<eager-inv>(
+ lower-expect,
+ simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;no-switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,
+ sroa<modify-cfg>,
+ early-cse<>
+),
+ipsccp,
+called-value-propagation,
+globalopt,
+function<eager-inv>(
+ mem2reg,
+ instcombine<max-iterations=1;no-use-loop-info;no-verify-fixpoint>,
+ simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>
+),
+always-inline,
+require<globals-aa>,
+function(
+ invalidate<aa>
+),
+require<profile-summary>,
+cgscc(
+ devirt<4>(
+ inline,
+ function-attrs<skip-non-recursive-function-attrs>,
+ function<eager-inv;no-rerun>(
+ sroa<modify-cfg>,
+ early-cse<memssa>,
+ speculative-execution<only-if-divergent-target>,
+ jump-threading,
+ correlated-propagation,
+ simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,
+ instcombine<max-iterations=1;no-use-loop-info;no-verify-fixpoint>,
+ aggressive-instcombine,
+ libcalls-shrinkwrap,
+ tailcallelim,
+ simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,
+ reassociate,
+ constraint-elimination,
+ loop-mssa(
+ loop-instsimplify,
+ loop-simplifycfg,
+ licm<no-allowspeculation>,
+ loop-rotate<header-duplication;no-prepare-for-lto>,
+ licm<allowspeculation>,
+ simple-loop-unswitch<no-nontrivial;trivial>
+ ),
+ simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,
+ instcombine<max-iterations=1;no-use-loop-info;no-verify-fixpoint>,
+ loop(
+ loop-idiom,
+ indvars,
+ loop-deletion,
+ loop-unroll-full
+ ),
+ sroa<modify-cfg>,
+ vector-combine,
+ mldst-motion<no-split-footer-bb>,
+ gvn<>,
+ sccp,
+ bdce,
+ instcombine<max-iterations=1;no-use-loop-info;no-verify-fixpoint>,
+ jump-threading,
+ correlated-propagation,
+ adce,
+ memcpyopt,
+ dse,
+ move-auto-init,
+ loop-mssa(
+ licm<allowspeculation>
+ ),
+ simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;hoist-common-insts;sink-common-insts;speculate-blocks;simplify-cond-branch>,
+ instcombine<max-iterations=1;no-use-loop-info;no-verify-fixpoint>
+ ),
+ function-attrs,
+ function(
+ require<should-not-run-function-passes>
+ )
+ )
+),
+deadargelim,
+globalopt,
+globaldce,
+elim-avail-extern,
+rpo-function-attrs,
+recompute-globalsaa,
+function<eager-inv>(
+ float2int,
+ lower-constant-intrinsics,
+ loop(
+ loop-rotate<header-duplication;no-prepare-for-lto>,
+ loop-deletion
+ ),
+ loop-distribute,
+ inject-tli-mappings,
+ loop-vectorize<no-interleave-forced-only;no-vectorize-forced-only;>,
+ infer-alignment,
+ loop-load-elim,
+ instcombine<max-iterations=1;no-use-loop-info;no-verify-fixpoint>,
+ simplifycfg<bonus-inst-threshold=1;forward-switch-cond;switch-range-to-icmp;switch-to-lookup;no-keep-loops;hoist-common-insts;sink-common-insts;speculate-blocks;simplify-cond-branch>,
+ slp-vectorizer,
+ vector-combine,
+ instcombine<max-iterations=1;no-use-loop-info;no-verify-fixpoint>,
+ loop-unroll<O2>,
+ transform-warning,
+ sroa<modify-cfg>,
+ infer-alignment,
+ instcombine<max-iterations=1;no-use-loop-info;no-verify-fixpoint>,
+ loop-mssa(
+ licm<allowspeculation>
+ ),
+ alignment-from-assumptions,
+ loop-sink,
+ instsimplify,
+ div-rem-pairs,
+ tailcallelim,
+ simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>
+),
+globaldce,
+constmerge,
+cg-profile,
+rel-lookup-table-converter,
+function(
+ annotation-remarks
+),
+verify
+)");
+#else
+ array_add(&passes, u8R"(
+annotation2metadata,
+forceattrs,
+inferattrs,
+function<eager-inv>(
+ ee-instrument<>,
+ lower-expect,
+ simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;no-switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-hoist-loads-stores-with-cond-faulting;no-sink-common-insts;speculate-blocks;simplify-cond-branch;no-speculate-unpredictables>,
+ sroa<modify-cfg>,
+ early-cse<>
+),
+ipsccp,
+called-value-propagation,
+globalopt,
+function<eager-inv>(
+ mem2reg,
+ instcombine<max-iterations=1;no-verify-fixpoint>,
+ simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-hoist-loads-stores-with-cond-faulting;no-sink-common-insts;speculate-blocks;simplify-cond-branch;no-speculate-unpredictables>
+),
+always-inline,
+require<globals-aa>,
+function(
+ invalidate<aa>
+),
+require<profile-summary>,
+cgscc(
+ devirt<4>(
+ inline,
+ function-attrs<skip-non-recursive-function-attrs>,
+ function<eager-inv;no-rerun>(
+ sroa<modify-cfg>,
+ early-cse<memssa>,
+ speculative-execution<only-if-divergent-target>,
+ jump-threading,
+ correlated-propagation,
+ simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-hoist-loads-stores-with-cond-faulting;no-sink-common-insts;speculate-blocks;simplify-cond-branch;no-speculate-unpredictables>,
+ instcombine<max-iterations=1;no-verify-fixpoint>,
+ aggressive-instcombine,
+ libcalls-shrinkwrap,
+ tailcallelim,
+ simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-hoist-loads-stores-with-cond-faulting;no-sink-common-insts;speculate-blocks;simplify-cond-branch;no-speculate-unpredictables>,
+ reassociate,
+ constraint-elimination,
+ loop-mssa(
+ loop-instsimplify,
+ loop-simplifycfg,
+ licm<no-allowspeculation>,
+ loop-rotate<header-duplication;no-prepare-for-lto>,
+ licm<allowspeculation>,
+ simple-loop-unswitch<no-nontrivial;trivial>
+ ),
+ simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-hoist-loads-stores-with-cond-faulting;no-sink-common-insts;speculate-blocks;simplify-cond-branch;no-speculate-unpredictables>,
+ instcombine<max-iterations=1;no-verify-fixpoint>,
+ loop(
+ loop-idiom,
+ indvars,
+ extra-simple-loop-unswitch-passes,
+ loop-deletion,
+ loop-unroll-full
+ ),
+ sroa<modify-cfg>,
+ vector-combine,
+ mldst-motion<no-split-footer-bb>,
+ gvn<>,
+ sccp,
+ bdce,
+ instcombine<max-iterations=1;no-verify-fixpoint>,
+ jump-threading,
+ correlated-propagation,
+ adce,
+ memcpyopt,
+ dse,
+ move-auto-init,
+ loop-mssa(
+ licm<allowspeculation>
+ ),
+ simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;hoist-common-insts;no-hoist-loads-stores-with-cond-faulting;sink-common-insts;speculate-blocks;simplify-cond-branch;no-speculate-unpredictables>,
+ instcombine<max-iterations=1;no-verify-fixpoint>
+ ),
+ function-attrs,
+ function(
+ require<should-not-run-function-passes>
+ )
+ )
+),
+deadargelim,
+globalopt,
+globaldce,
+elim-avail-extern,
+rpo-function-attrs,
+recompute-globalsaa,
+function<eager-inv>(
+ float2int,
+ lower-constant-intrinsics,
+ loop(
+ loop-rotate<header-duplication;no-prepare-for-lto>,
+ loop-deletion
+ ),
+ loop-distribute,
+ inject-tli-mappings,
+ loop-vectorize<no-interleave-forced-only;no-vectorize-forced-only;>,
+ infer-alignment,
+ loop-load-elim,
+ instcombine<max-iterations=1;no-verify-fixpoint>,
+ simplifycfg<bonus-inst-threshold=1;forward-switch-cond;switch-range-to-icmp;switch-to-lookup;no-keep-loops;hoist-common-insts;no-hoist-loads-stores-with-cond-faulting;sink-common-insts;speculate-blocks;simplify-cond-branch;no-speculate-unpredictables>,
+ slp-vectorizer,
+ vector-combine,
+ instcombine<max-iterations=1;no-verify-fixpoint>,
+ loop-unroll<O2>,
+ transform-warning,
+ sroa<preserve-cfg>,
+ infer-alignment,
+ instcombine<max-iterations=1;no-verify-fixpoint>,
+ loop-mssa(
+ licm<allowspeculation>
+ ),
+ alignment-from-assumptions,
+ loop-sink,
+ instsimplify,
+ div-rem-pairs,
+ tailcallelim,
+ simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;hoist-loads-stores-with-cond-faulting;no-sink-common-insts;speculate-blocks;simplify-cond-branch;speculate-unpredictables>
+),
+globaldce,
+constmerge,
+cg-profile,
+rel-lookup-table-converter,
+function(
+ annotation-remarks
+),
+verify
+)");
+#endif
+ break;
+
+ case 3:
+// default<O3>
+// Passes removed: coro, openmp, sroa
+#if LLVM_VERSION_MAJOR == 17
+ array_add(&passes, u8R"(
+annotation2metadata,
+forceattrs,
+inferattrs,
+function<eager-inv>(
+ lower-expect,
+ simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;no-switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,
+ early-cse<>,
+ callsite-splitting
+),
+ipsccp,
+called-value-propagation,
+globalopt,
+function<eager-inv>(
+ mem2reg,
+ instcombine<max-iterations=1000;no-use-loop-info>,
+ simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>
+),
+require<globals-aa>,
+function(
+ invalidate<aa>
+),
+require<profile-summary>,
+cgscc(
+ devirt<4>(
+ inline<only-mandatory>,
+ inline,
+ function-attrs<skip-non-recursive>,
+ argpromotion,
+ function<eager-inv;no-rerun>(
+ early-cse<memssa>,
+ speculative-execution,
+ jump-threading,
+ correlated-propagation,
+ simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,
+ instcombine<max-iterations=1000;no-use-loop-info>,
+ aggressive-instcombine,
+ constraint-elimination,
+ libcalls-shrinkwrap,
+ tailcallelim,
+ simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,
+ reassociate,
+ loop-mssa(
+ loop-instsimplify,
+ loop-simplifycfg,
+ licm<no-allowspeculation>,
+ loop-rotate<header-duplication;no-prepare-for-lto>,
+ licm<allowspeculation>,
+ simple-loop-unswitch<nontrivial;trivial>
+ ),
+ simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,
+ instcombine<max-iterations=1000;no-use-loop-info>,
+ loop(
+ loop-idiom,
+ indvars,
+ loop-deletion,
+ loop-unroll-full
+ ),
+ vector-combine,
+ mldst-motion<no-split-footer-bb>,
+ gvn<>,
+ sccp,
+ bdce,
+ instcombine<max-iterations=1000;no-use-loop-info>,
+ jump-threading,
+ correlated-propagation,
+ adce,
+ memcpyopt,
+ dse,
+ move-auto-init,
+ loop-mssa(
+ licm<allowspeculation>
+ ),
+ simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;hoist-common-insts;sink-common-insts;speculate-blocks;simplify-cond-branch>,
+ instcombine<max-iterations=1000;no-use-loop-info>
+ ),
+ function-attrs,
+ function(
+ require<should-not-run-function-passes>
+ )
+ )
+),
+deadargelim,
+globalopt,
+globaldce,
+elim-avail-extern,
+rpo-function-attrs,
+recompute-globalsaa,
+function<eager-inv>(
+ float2int,
+ lower-constant-intrinsics,
+ chr,
+ loop(
+ loop-rotate<header-duplication;no-prepare-for-lto>,
+ loop-deletion
+ ),
+ loop-distribute,
+ inject-tli-mappings,
+ loop-vectorize<no-interleave-forced-only;no-vectorize-forced-only;>,
+ loop-load-elim,
+ instcombine<max-iterations=1000;no-use-loop-info>,
+ simplifycfg<bonus-inst-threshold=1;forward-switch-cond;switch-range-to-icmp;switch-to-lookup;no-keep-loops;hoist-common-insts;sink-common-insts;speculate-blocks;simplify-cond-branch>,
+ slp-vectorizer,
+ vector-combine,
+ instcombine<max-iterations=1000;no-use-loop-info>,
+ loop-unroll<O3>,
+ transform-warning,
+ instcombine<max-iterations=1000;no-use-loop-info>,
+ loop-mssa(
+ licm<allowspeculation>
+ ),
+ alignment-from-assumptions,
+ loop-sink,
+ instsimplify,
+ div-rem-pairs,
+ tailcallelim,
+ simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>
+),
+globaldce,
+constmerge,
+cg-profile,
+rel-lookup-table-converter,
+function(
+ annotation-remarks
+),
+verify
+)");
+
+#elif LLVM_VERSION_MAJOR < 20
+ array_add(&passes, u8R"(
+annotation2metadata,
+forceattrs,
+inferattrs,
+function<eager-inv>(
+ lower-expect,
+ simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;no-switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,
+ sroa<modify-cfg>,
+ early-cse<>,
+ callsite-splitting
+),
+ipsccp,
+called-value-propagation,
+globalopt,
+function<eager-inv>(
+ mem2reg,
+ instcombine<max-iterations=1;no-use-loop-info;no-verify-fixpoint>,
+ simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>
+),
+always-inline,
+require<globals-aa>,
+function(invalidate<aa>),
+require<profile-summary>,
+cgscc(
+ devirt<4>(
+ inline,
+ function-attrs<skip-non-recursive-function-attrs>,
+ argpromotion,
+ function<eager-inv;no-rerun>(
+ sroa<modify-cfg>,
+ early-cse<memssa>,
+ speculative-execution<only-if-divergent-target>,
+ jump-threading,
+ correlated-propagation,
+ simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,
+ instcombine<max-iterations=1;no-use-loop-info;no-verify-fixpoint>,
+ aggressive-instcombine,
+ libcalls-shrinkwrap,
+ tailcallelim,
+ simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,
+ reassociate,
+ constraint-elimination,
+ loop-mssa(
+ loop-instsimplify,
+ loop-simplifycfg,
+ licm<no-allowspeculation>,
+ loop-rotate<header-duplication;no-prepare-for-lto>,
+ licm<allowspeculation>,
+ simple-loop-unswitch<nontrivial;trivial>
+ ),
+ simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>,
+ instcombine<max-iterations=1;no-use-loop-info;no-verify-fixpoint>,
+ loop(
+ loop-idiom,
+ indvars,
+ loop-deletion,
+ loop-unroll-full
+ ),
+ sroa<modify-cfg>,
+ vector-combine,
+ mldst-motion<no-split-footer-bb>,
+ gvn<>,
+ sccp,
+ bdce,
+ instcombine<max-iterations=1;no-use-loop-info;no-verify-fixpoint>,
+ jump-threading,
+ correlated-propagation,
+ adce,
+ memcpyopt,
+ dse,
+ move-auto-init,
+ loop-mssa(licm<allowspeculation>),
+ simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;hoist-common-insts;sink-common-insts;speculate-blocks;simplify-cond-branch>,
+ instcombine<max-iterations=1;no-use-loop-info;no-verify-fixpoint>
+ ),
+ function-attrs,
+ function(
+ require<should-not-run-function-passes>
+ )
+ )
+),
+deadargelim,
+globalopt,
+globaldce,
+elim-avail-extern,
+rpo-function-attrs,
+recompute-globalsaa,
+function<eager-inv>(
+ float2int,
+ lower-constant-intrinsics,
+ chr,
+ loop(
+ loop-rotate<header-duplication;no-prepare-for-lto>,
+ loop-deletion
+ ),
+ loop-distribute,
+ inject-tli-mappings,
+ loop-vectorize<no-interleave-forced-only;no-vectorize-forced-only;>,
+ infer-alignment,
+ loop-load-elim,
+ instcombine<max-iterations=1;no-use-loop-info;no-verify-fixpoint>,
+ simplifycfg<bonus-inst-threshold=1;forward-switch-cond;switch-range-to-icmp;switch-to-lookup;no-keep-loops;hoist-common-insts;sink-common-insts;speculate-blocks;simplify-cond-branch>,
+ slp-vectorizer,
+ vector-combine,
+ instcombine<max-iterations=1;no-use-loop-info;no-verify-fixpoint>,
+ loop-unroll<O3>,
+ transform-warning,
+ sroa<preserve-cfg>,
+ infer-alignment,
+ instcombine<max-iterations=1;no-use-loop-info;no-verify-fixpoint>,
+ loop-mssa(licm<allowspeculation>),
+ alignment-from-assumptions,
+ loop-sink,
+ instsimplify,
+ div-rem-pairs,
+ tailcallelim,
+ simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>
+),
+globaldce,
+constmerge,
+cg-profile,
+rel-lookup-table-converter,
+function(
+ annotation-remarks
+),
+verify
+)");
+#else
+ array_add(&passes, u8R"(
+annotation2metadata,
+forceattrs,
+inferattrs,
+function<eager-inv>(
+ ee-instrument<>,
+ lower-expect,
+ simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;no-switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-hoist-loads-stores-with-cond-faulting;no-sink-common-insts;speculate-blocks;simplify-cond-branch;no-speculate-unpredictables>,
+ sroa<modify-cfg>,
+ early-cse<>,
+ callsite-splitting
+),
+ipsccp,
+called-value-propagation,
+globalopt,
+function<eager-inv>(
+ mem2reg,
+ instcombine<max-iterations=1;no-verify-fixpoint>,
+ simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-hoist-loads-stores-with-cond-faulting;no-sink-common-insts;speculate-blocks;simplify-cond-branch;no-speculate-unpredictables>
+),
+always-inline,
+require<globals-aa>,
+function(
+ invalidate<aa>
+),
+require<profile-summary>,
+cgscc(
+ devirt<4>(
+ inline,
+ function-attrs<skip-non-recursive-function-attrs>,
+ argpromotion,
+ function<eager-inv;no-rerun>(
+ sroa<modify-cfg>,
+ early-cse<memssa>,
+ speculative-execution<only-if-divergent-target>,
+ jump-threading,
+ correlated-propagation,
+ simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-hoist-loads-stores-with-cond-faulting;no-sink-common-insts;speculate-blocks;simplify-cond-branch;no-speculate-unpredictables>,
+ instcombine<max-iterations=1;no-verify-fixpoint>,
+ aggressive-instcombine,
+ libcalls-shrinkwrap,
+ tailcallelim,
+ simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-hoist-loads-stores-with-cond-faulting;no-sink-common-insts;speculate-blocks;simplify-cond-branch;no-speculate-unpredictables>,
+ reassociate,
+ constraint-elimination,
+ loop-mssa(
+ loop-instsimplify,
+ loop-simplifycfg,
+ licm<no-allowspeculation>,
+ loop-rotate<header-duplication;no-prepare-for-lto>,
+ licm<allowspeculation>,
+ simple-loop-unswitch<nontrivial;trivial>
+ ),
+ simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-hoist-loads-stores-with-cond-faulting;no-sink-common-insts;speculate-blocks;simplify-cond-branch;no-speculate-unpredictables>,
+ instcombine<max-iterations=1;no-verify-fixpoint>,
+ loop(
+ loop-idiom,
+ indvars,
+ extra-simple-loop-unswitch-passes,
+ loop-deletion,
+ loop-unroll-full
+ ),
+ sroa<modify-cfg>,
+ vector-combine,
+ mldst-motion<no-split-footer-bb>,
+ gvn<>,
+ sccp,
+ bdce,
+ instcombine<max-iterations=1;no-verify-fixpoint>,
+ jump-threading,
+ correlated-propagation,
+ adce,
+ memcpyopt,
+ dse,
+ move-auto-init,
+ loop-mssa(
+ licm<allowspeculation>
+ ),
+ simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;hoist-common-insts;no-hoist-loads-stores-with-cond-faulting;sink-common-insts;speculate-blocks;simplify-cond-branch;no-speculate-unpredictables>,
+ instcombine<max-iterations=1;no-verify-fixpoint>
+ ),
+ function-attrs,
+ function(
+ require<should-not-run-function-passes>
+ )
+ )
+),
+deadargelim,
+globalopt,
+globaldce,
+elim-avail-extern,
+rpo-function-attrs,
+recompute-globalsaa,
+function<eager-inv>(
+ float2int,
+ lower-constant-intrinsics,
+ chr,
+ loop(
+ loop-rotate<header-duplication;no-prepare-for-lto>,
+ loop-deletion
+ ),
+ loop-distribute,
+ inject-tli-mappings,
+ loop-vectorize<no-interleave-forced-only;no-vectorize-forced-only;>,
+ infer-alignment,
+ loop-load-elim,
+ instcombine<max-iterations=1;no-verify-fixpoint>,
+ simplifycfg<bonus-inst-threshold=1;forward-switch-cond;switch-range-to-icmp;switch-to-lookup;no-keep-loops;hoist-common-insts;no-hoist-loads-stores-with-cond-faulting;sink-common-insts;speculate-blocks;simplify-cond-branch;no-speculate-unpredictables>,
+ slp-vectorizer,
+ vector-combine,
+ instcombine<max-iterations=1;no-verify-fixpoint>,
+ loop-unroll<O3>,
+ transform-warning,
+ sroa<preserve-cfg>,
+ infer-alignment,
+ instcombine<max-iterations=1;no-verify-fixpoint>,
+ loop-mssa(
+ licm<allowspeculation>
+ ),
+ alignment-from-assumptions,
+ loop-sink,
+ instsimplify,
+ div-rem-pairs,
+ tailcallelim,
+ simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;hoist-loads-stores-with-cond-faulting;no-sink-common-insts;speculate-blocks;simplify-cond-branch;speculate-unpredictables>
+),
+globaldce,
+constmerge,
+cg-profile,
+rel-lookup-table-converter,
+function(
+ annotation-remarks
+),
+verify
+
+)");
+
+#endif
+ break;
+ } \ No newline at end of file
diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp
index 7e44a0046..9f6a1d653 100644
--- a/src/llvm_backend_proc.cpp
+++ b/src/llvm_backend_proc.cpp
@@ -67,6 +67,14 @@ gb_internal void lb_mem_copy_non_overlapping(lbProcedure *p, lbValue dst, lbValu
gb_internal lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool ignore_body) {
GB_ASSERT(entity != nullptr);
GB_ASSERT(entity->kind == Entity_Procedure);
+ // Skip codegen for unspecialized polymorphic procedures
+ if (is_type_polymorphic(entity->type) && !entity->Procedure.is_foreign) {
+ Type *bt = base_type(entity->type);
+ if (bt->kind == Type_Proc && bt->Proc.is_polymorphic && !bt->Proc.is_poly_specialized) {
+ // Do not generate code for unspecialized polymorphic procedures
+ return nullptr;
+ }
+ }
if (!entity->Procedure.is_foreign) {
if ((entity->flags & EntityFlag_ProcBodyChecked) == 0) {
GB_PANIC("%.*s :: %s (was parapoly: %d %d)", LIT(entity->token.string), type_to_string(entity->type), is_type_polymorphic(entity->type, true), is_type_polymorphic(entity->type, false));
@@ -115,12 +123,13 @@ gb_internal lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool i
p->is_entry_point = false;
gbAllocator a = heap_allocator();
- p->children.allocator = a;
- p->defer_stmts.allocator = a;
- p->blocks.allocator = a;
- p->branch_blocks.allocator = a;
- p->context_stack.allocator = a;
- p->scope_stack.allocator = a;
+ p->children.allocator = a;
+ p->defer_stmts.allocator = a;
+ p->blocks.allocator = a;
+ p->branch_blocks.allocator = a;
+ p->context_stack.allocator = a;
+ p->scope_stack.allocator = a;
+ p->asan_stack_locals.allocator = a;
// map_init(&p->selector_values, 0);
// map_init(&p->selector_addr, 0);
// map_init(&p->tuple_fix_map, 0);
@@ -333,10 +342,10 @@ gb_internal lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool i
}
if (p->body && entity->pkg && ((entity->pkg->kind == Package_Normal) || (entity->pkg->kind == Package_Init))) {
- if (build_context.sanitizer_flags & SanitizerFlag_Address) {
+ if (build_context.sanitizer_flags & SanitizerFlag_Address && !entity->Procedure.no_sanitize_address) {
lb_add_attribute_to_proc(m, p->value, "sanitize_address");
}
- if (build_context.sanitizer_flags & SanitizerFlag_Memory) {
+ if (build_context.sanitizer_flags & SanitizerFlag_Memory && !entity->Procedure.no_sanitize_memory) {
lb_add_attribute_to_proc(m, p->value, "sanitize_memory");
}
if (build_context.sanitizer_flags & SanitizerFlag_Thread) {
@@ -385,11 +394,12 @@ gb_internal lbProcedure *lb_create_dummy_procedure(lbModule *m, String link_name
p->is_entry_point = false;
gbAllocator a = permanent_allocator();
- p->children.allocator = a;
- p->defer_stmts.allocator = a;
- p->blocks.allocator = a;
- p->branch_blocks.allocator = a;
- p->context_stack.allocator = a;
+ p->children.allocator = a;
+ p->defer_stmts.allocator = a;
+ p->blocks.allocator = a;
+ p->branch_blocks.allocator = a;
+ p->context_stack.allocator = a;
+ p->asan_stack_locals.allocator = a;
map_init(&p->tuple_fix_map, 0);
@@ -536,6 +546,9 @@ gb_internal void lb_begin_procedure_body(lbProcedure *p) {
GB_ASSERT(p->type != nullptr);
lb_ensure_abi_function_type(p->module, p);
+ if (p->type->Proc.calling_convention == ProcCC_Odin) {
+ lb_push_context_onto_stack_from_implicit_parameter(p);
+ }
{
lbFunctionType *ft = p->abi_function_type;
@@ -733,9 +746,6 @@ gb_internal void lb_begin_procedure_body(lbProcedure *p) {
}
}
- if (p->type->Proc.calling_convention == ProcCC_Odin) {
- lb_push_context_onto_stack_from_implicit_parameter(p);
- }
lb_set_debug_position_to_procedure_begin(p);
if (p->debug_info != nullptr) {
@@ -781,8 +791,7 @@ gb_internal void lb_end_procedure_body(lbProcedure *p) {
p->curr_block = nullptr;
p->state_flags = 0;
-}
-gb_internal void lb_end_procedure(lbProcedure *p) {
+
LLVMDisposeBuilder(p->builder);
}
@@ -815,6 +824,10 @@ gb_internal void lb_build_nested_proc(lbProcedure *p, AstProcLit *pd, Entity *e)
e->Procedure.link_name = name;
lbProcedure *nested_proc = lb_create_procedure(p->module, e);
+ if (nested_proc == nullptr) {
+ // This is an unspecialized polymorphic procedure, skip codegen
+ return;
+ }
e->code_gen_procedure = nested_proc;
lbValue value = {};
@@ -1119,7 +1132,7 @@ gb_internal lbValue lb_emit_call(lbProcedure *p, lbValue value, Array<lbValue> c
if (LLVMIsConstant(x.value)) {
// NOTE(bill): if the value is already constant, then just it as a global variable
// and pass it by pointer
- lbAddr addr = lb_add_global_generated(p->module, original_type, x);
+ lbAddr addr = lb_add_global_generated_from_procedure(p, original_type, x);
lb_make_global_private_const(addr);
ptr = addr.addr;
} else {
@@ -1293,6 +1306,23 @@ gb_internal lbValue lb_build_builtin_simd_proc(lbProcedure *p, Ast *expr, TypeAn
lbValue res = {};
res.type = tv.type;
+ switch (builtin_id) {
+ case BuiltinProc_simd_indices: {
+ Type *type = base_type(res.type);
+ GB_ASSERT(type->kind == Type_SimdVector);
+ Type *elem = type->SimdVector.elem;
+
+ i64 count = type->SimdVector.count;
+ LLVMValueRef *scalars = gb_alloc_array(temporary_allocator(), LLVMValueRef, count);
+ for (i64 i = 0; i < count; i++) {
+ scalars[i] = lb_const_value(m, elem, exact_value_i64(i)).value;
+ }
+
+ res.value = LLVMConstVector(scalars, cast(unsigned)count);
+ return res;
+ }
+ }
+
lbValue arg0 = {}; if (ce->args.count > 0) arg0 = lb_build_expr(p, ce->args[0]);
lbValue arg1 = {}; if (ce->args.count > 1) arg1 = lb_build_expr(p, ce->args[1]);
lbValue arg2 = {}; if (ce->args.count > 2) arg2 = lb_build_expr(p, ce->args[2]);
@@ -1442,7 +1472,7 @@ gb_internal lbValue lb_build_builtin_simd_proc(lbProcedure *p, Ast *expr, TypeAn
LLVMRealPredicate pred = cast(LLVMRealPredicate)0;
switch (builtin_id) {
case BuiltinProc_simd_lanes_eq: pred = LLVMRealOEQ; break;
- case BuiltinProc_simd_lanes_ne: pred = LLVMRealONE; break;
+ case BuiltinProc_simd_lanes_ne: pred = LLVMRealUNE; break;
case BuiltinProc_simd_lanes_lt: pred = LLVMRealOLT; break;
case BuiltinProc_simd_lanes_le: pred = LLVMRealOLE; break;
case BuiltinProc_simd_lanes_gt: pred = LLVMRealOGT; break;
@@ -1478,6 +1508,38 @@ gb_internal lbValue lb_build_builtin_simd_proc(lbProcedure *p, Ast *expr, TypeAn
res.value = LLVMBuildInsertElement(p->builder, arg0.value, arg2.value, arg1.value, "");
return res;
+ case BuiltinProc_simd_reduce_add_bisect:
+ case BuiltinProc_simd_reduce_mul_bisect:
+ {
+ GB_ASSERT(arg0.type->kind == Type_SimdVector);
+ i64 num_elems = arg0.type->SimdVector.count;
+
+ LLVMValueRef *indices = gb_alloc_array(temporary_allocator(), LLVMValueRef, num_elems);
+ for (i64 i = 0; i < num_elems; i++) {
+ indices[i] = lb_const_int(m, t_uint, cast(u64)i).value;
+ }
+
+ switch (builtin_id) {
+ case BuiltinProc_simd_reduce_add_bisect: op_code = is_float ? LLVMFAdd : LLVMAdd; break;
+ case BuiltinProc_simd_reduce_mul_bisect: op_code = is_float ? LLVMFMul : LLVMMul; break;
+ }
+
+ LLVMValueRef remaining = arg0.value;
+ i64 num_remaining = num_elems;
+
+ while (num_remaining > 1) {
+ num_remaining /= 2;
+ LLVMValueRef left_indices = LLVMConstVector(&indices[0], cast(unsigned)num_remaining);
+ LLVMValueRef left_value = LLVMBuildShuffleVector(p->builder, remaining, remaining, left_indices, "");
+ LLVMValueRef right_indices = LLVMConstVector(&indices[num_remaining], cast(unsigned)num_remaining);
+ LLVMValueRef right_value = LLVMBuildShuffleVector(p->builder, remaining, remaining, right_indices, "");
+ remaining = LLVMBuildBinOp(p->builder, op_code, left_value, right_value, "");
+ }
+
+ res.value = LLVMBuildExtractElement(p->builder, remaining, indices[0], "");
+ return res;
+ }
+
case BuiltinProc_simd_reduce_add_ordered:
case BuiltinProc_simd_reduce_mul_ordered:
{
@@ -1510,6 +1572,40 @@ gb_internal lbValue lb_build_builtin_simd_proc(lbProcedure *p, Ast *expr, TypeAn
res.value = lb_call_intrinsic(p, name, args, cast(unsigned)args_count, types, gb_count_of(types));
return res;
}
+
+ case BuiltinProc_simd_reduce_add_pairs:
+ case BuiltinProc_simd_reduce_mul_pairs:
+ {
+ GB_ASSERT(arg0.type->kind == Type_SimdVector);
+ i64 num_elems = arg0.type->SimdVector.count;
+
+ LLVMValueRef *indices = gb_alloc_array(temporary_allocator(), LLVMValueRef, num_elems);
+ for (i64 i = 0; i < num_elems/2; i++) {
+ indices[i] = lb_const_int(m, t_uint, cast(u64)(2*i)).value;
+ indices[i+num_elems/2] = lb_const_int(m, t_uint, cast(u64)(2*i+1)).value;
+ }
+
+ switch (builtin_id) {
+ case BuiltinProc_simd_reduce_add_pairs: op_code = is_float ? LLVMFAdd : LLVMAdd; break;
+ case BuiltinProc_simd_reduce_mul_pairs: op_code = is_float ? LLVMFMul : LLVMMul; break;
+ }
+
+ LLVMValueRef remaining = arg0.value;
+ i64 num_remaining = num_elems;
+
+ while (num_remaining > 1) {
+ num_remaining /= 2;
+ LLVMValueRef left_indices = LLVMConstVector(&indices[0], cast(unsigned)num_remaining);
+ LLVMValueRef left_value = LLVMBuildShuffleVector(p->builder, remaining, remaining, left_indices, "");
+ LLVMValueRef right_indices = LLVMConstVector(&indices[num_elems/2], cast(unsigned)num_remaining);
+ LLVMValueRef right_value = LLVMBuildShuffleVector(p->builder, remaining, remaining, right_indices, "");
+ remaining = LLVMBuildBinOp(p->builder, op_code, left_value, right_value, "");
+ }
+
+ res.value = LLVMBuildExtractElement(p->builder, remaining, indices[0], "");
+ return res;
+ }
+
case BuiltinProc_simd_reduce_min:
case BuiltinProc_simd_reduce_max:
case BuiltinProc_simd_reduce_and:
@@ -1564,6 +1660,34 @@ gb_internal lbValue lb_build_builtin_simd_proc(lbProcedure *p, Ast *expr, TypeAn
return res;
}
+ case BuiltinProc_simd_extract_lsbs:
+ case BuiltinProc_simd_extract_msbs:
+ {
+ Type *vt = arg0.type;
+ GB_ASSERT(vt->kind == Type_SimdVector);
+
+ i64 elem_bits = 8*type_size_of(elem);
+ i64 num_elems = get_array_type_count(vt);
+
+ LLVMValueRef broadcast_value = arg0.value;
+ if (builtin_id == BuiltinProc_simd_extract_msbs) {
+ LLVMTypeRef word_type = lb_type(m, elem);
+ LLVMValueRef shift_value = llvm_splat_int(num_elems, word_type, elem_bits - 1);
+ broadcast_value = LLVMBuildAShr(p->builder, broadcast_value, shift_value, "");
+ }
+
+ LLVMTypeRef bitvec_type = LLVMVectorType(LLVMInt1TypeInContext(m->ctx), (unsigned)num_elems);
+ LLVMValueRef bitvec_value = LLVMBuildTrunc(p->builder, broadcast_value, bitvec_type, "");
+
+ LLVMTypeRef mask_type = LLVMIntTypeInContext(m->ctx, (unsigned)num_elems);
+ LLVMValueRef mask_value = LLVMBuildBitCast(p->builder, bitvec_value, mask_type, "");
+
+ LLVMTypeRef result_type = lb_type(m, res.type);
+ res.value = LLVMBuildZExtOrBitCast(p->builder, mask_value, result_type, "");
+
+ return res;
+ }
+
case BuiltinProc_simd_shuffle:
{
@@ -1846,7 +1970,7 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu
LLVMValueRef backing_array = llvm_const_array(lb_type(m, t_load_directory_file), elements, count);
Type *array_type = alloc_type_array(t_load_directory_file, count);
- lbAddr backing_array_addr = lb_add_global_generated(m, array_type, {backing_array, array_type}, nullptr);
+ lbAddr backing_array_addr = lb_add_global_generated_from_procedure(p, array_type, {backing_array, array_type});
lb_make_global_private_const(backing_array_addr);
LLVMValueRef backing_array_ptr = backing_array_addr.addr.value;
@@ -1854,7 +1978,7 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu
LLVMValueRef const_slice = llvm_const_slice_internal(m, backing_array_ptr, LLVMConstInt(lb_type(m, t_int), count, false));
- lbAddr addr = lb_add_global_generated(p->module, tv.type, {const_slice, t_load_directory_file_slice}, nullptr);
+ lbAddr addr = lb_add_global_generated_from_procedure(p, tv.type, {const_slice, t_load_directory_file_slice});
lb_make_global_private_const(addr);
return lb_addr_load(p, addr);
@@ -2122,6 +2246,68 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu
return lb_emit_load(p, tuple);
}
+ case BuiltinProc_compress_values: {
+ isize value_count = 0;
+ for (Ast *arg : ce->args) {
+ Type *t = arg->tav.type;
+ if (is_type_tuple(t)) {
+ value_count += t->Tuple.variables.count;
+ } else {
+ value_count += 1;
+ }
+ }
+
+ if (value_count == 1) {
+ lbValue x = lb_build_expr(p, ce->args[0]);
+ x = lb_emit_conv(p, x, tv.type);
+ return x;
+ }
+
+ Type *dt = base_type(tv.type);
+ lbAddr addr = lb_add_local_generated(p, tv.type, true);
+ if (is_type_struct(dt) || is_type_tuple(dt)) {
+ i32 index = 0;
+ for (Ast *arg : ce->args) {
+ lbValue x = lb_build_expr(p, arg);
+ if (is_type_tuple(x.type)) {
+ for (isize i = 0; i < x.type->Tuple.variables.count; i++) {
+ lbValue y = lb_emit_tuple_ev(p, x, cast(i32)i);
+ lbValue ptr = lb_emit_struct_ep(p, addr.addr, index++);
+ y = lb_emit_conv(p, y, type_deref(ptr.type));
+ lb_emit_store(p, ptr, y);
+ }
+ } else {
+ lbValue ptr = lb_emit_struct_ep(p, addr.addr, index++);
+ x = lb_emit_conv(p, x, type_deref(ptr.type));
+ lb_emit_store(p, ptr, x);
+ }
+ }
+ GB_ASSERT(index == value_count);
+ } else if (is_type_array_like(dt)) {
+ i32 index = 0;
+ for (Ast *arg : ce->args) {
+ lbValue x = lb_build_expr(p, arg);
+ if (is_type_tuple(x.type)) {
+ for (isize i = 0; i < x.type->Tuple.variables.count; i++) {
+ lbValue y = lb_emit_tuple_ev(p, x, cast(i32)i);
+ lbValue ptr = lb_emit_array_epi(p, addr.addr, index++);
+ y = lb_emit_conv(p, y, type_deref(ptr.type));
+ lb_emit_store(p, ptr, y);
+ }
+ } else {
+ lbValue ptr = lb_emit_array_epi(p, addr.addr, index++);
+ x = lb_emit_conv(p, x, type_deref(ptr.type));
+ lb_emit_store(p, ptr, x);
+ }
+ }
+ GB_ASSERT(index == value_count);
+ } else {
+ GB_PANIC("TODO(bill): compress_values -> %s", type_to_string(tv.type));
+ }
+
+ return lb_addr_load(p, addr);
+ }
+
case BuiltinProc_min: {
Type *t = type_of_expr(expr);
if (ce->args.count == 2) {
@@ -2174,7 +2360,32 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu
case 128: return lb_emit_runtime_call(p, "abs_complex128", args);
}
GB_PANIC("Unknown complex type");
+ } else if (is_type_float(t)) {
+ bool little = is_type_endian_little(t) || (is_type_endian_platform(t) && build_context.endian_kind == TargetEndian_Little);
+ Type *t_unsigned = nullptr;
+ lbValue mask = {0};
+ switch (type_size_of(t)) {
+ case 2:
+ t_unsigned = t_u16;
+ mask = lb_const_int(p->module, t_unsigned, little ? 0x7FFF : 0xFF7F);
+ break;
+ case 4:
+ t_unsigned = t_u32;
+ mask = lb_const_int(p->module, t_unsigned, little ? 0x7FFFFFFF : 0xFFFFFF7F);
+ break;
+ case 8:
+ t_unsigned = t_u64;
+ mask = lb_const_int(p->module, t_unsigned, little ? 0x7FFFFFFFFFFFFFFF : 0xFFFFFFFFFFFFFF7F);
+ break;
+ default:
+ GB_PANIC("abs: unhandled float size");
+ }
+
+ lbValue as_unsigned = lb_emit_transmute(p, x, t_unsigned);
+ lbValue abs = lb_emit_arith(p, Token_And, as_unsigned, mask, t_unsigned);
+ return lb_emit_transmute(p, abs, t);
}
+
lbValue zero = lb_const_nil(p->module, t);
lbValue cond = lb_emit_comp(p, Token_Lt, x, zero);
lbValue neg = lb_emit_unary_arith(p, Token_Sub, x, t);
@@ -2523,8 +2734,8 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu
}
case BuiltinProc_ptr_sub:
{
- Type *elem0 = type_deref(type_of_expr(ce->args[0]));
- Type *elem1 = type_deref(type_of_expr(ce->args[1]));
+ Type *elem0 = type_deref(type_of_expr(ce->args[0]), true);
+ Type *elem1 = type_deref(type_of_expr(ce->args[1]), true);
GB_ASSERT(are_types_identical(elem0, elem1));
Type *elem = elem0;
@@ -2563,15 +2774,18 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu
LLVMSetMetadata(instr, kind_id, LLVMMetadataAsValue(p->module->ctx, node));
}
break;
- case BuiltinProc_volatile_store: LLVMSetVolatile(instr, true); break;
- case BuiltinProc_atomic_store: LLVMSetOrdering(instr, LLVMAtomicOrderingSequentiallyConsistent); break;
+ case BuiltinProc_volatile_store:
+ LLVMSetVolatile(instr, true);
+ break;
+ case BuiltinProc_atomic_store:
+ LLVMSetOrdering(instr, LLVMAtomicOrderingSequentiallyConsistent);
+ LLVMSetVolatile(instr, true);
+ break;
case BuiltinProc_atomic_store_explicit:
{
auto ordering = llvm_atomic_ordering_from_odin(ce->args[2]);
LLVMSetOrdering(instr, ordering);
- if (ordering == LLVMAtomicOrderingUnordered) {
- LLVMSetVolatile(instr, true);
- }
+ LLVMSetVolatile(instr, true);
}
break;
}
@@ -2597,15 +2811,18 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu
}
break;
break;
- case BuiltinProc_volatile_load: LLVMSetVolatile(instr, true); break;
- case BuiltinProc_atomic_load: LLVMSetOrdering(instr, LLVMAtomicOrderingSequentiallyConsistent); break;
+ case BuiltinProc_volatile_load:
+ LLVMSetVolatile(instr, true);
+ break;
+ case BuiltinProc_atomic_load:
+ LLVMSetOrdering(instr, LLVMAtomicOrderingSequentiallyConsistent);
+ LLVMSetVolatile(instr, true);
+ break;
case BuiltinProc_atomic_load_explicit:
{
auto ordering = llvm_atomic_ordering_from_odin(ce->args[1]);
LLVMSetOrdering(instr, ordering);
- if (ordering == LLVMAtomicOrderingUnordered) {
- LLVMSetVolatile(instr, true);
- }
+ LLVMSetVolatile(instr, true);
}
break;
}
@@ -2690,9 +2907,7 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu
lbValue res = {};
res.value = LLVMBuildAtomicRMW(p->builder, op, dst.value, val.value, ordering, false);
res.type = tv.type;
- if (ordering == LLVMAtomicOrderingUnordered) {
- LLVMSetVolatile(res.value, true);
- }
+ LLVMSetVolatile(res.value, true);
return res;
}
@@ -2728,9 +2943,7 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu
single_threaded
);
LLVMSetWeak(value, weak);
- if (success_ordering == LLVMAtomicOrderingUnordered || failure_ordering == LLVMAtomicOrderingUnordered) {
- LLVMSetVolatile(value, true);
- }
+ LLVMSetVolatile(value, true);
if (is_type_tuple(tv.type)) {
Type *fix_typed = alloc_type_tuple();
@@ -2919,6 +3132,8 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu
constraints = gb_string_appendc(constraints, "}");
}
+ constraints = gb_string_appendc(constraints, ",~{memory}");
+
inline_asm = llvm_get_inline_asm(func_type, make_string_c(asm_string), make_string_c(constraints));
}
break;
@@ -2981,6 +3196,8 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu
constraints = gb_string_appendc(constraints, "}");
}
+ constraints = gb_string_appendc(constraints, ",~{memory}");
+
inline_asm = llvm_get_inline_asm(func_type, make_string_c(asm_string), make_string_c(constraints));
}
break;
@@ -3006,6 +3223,8 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu
constraints = gb_string_appendc(constraints, "}");
}
+ constraints = gb_string_appendc(constraints, ",~{memory}");
+
inline_asm = llvm_get_inline_asm(func_type, make_string_c(asm_string), make_string_c(constraints));
} else {
char asm_string[] = "svc #0";
@@ -3025,6 +3244,8 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu
constraints = gb_string_appendc(constraints, "}");
}
+ constraints = gb_string_appendc(constraints, ",~{memory}");
+
inline_asm = llvm_get_inline_asm(func_type, make_string_c(asm_string), make_string_c(constraints));
}
}
@@ -3051,6 +3272,8 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu
constraints = gb_string_appendc(constraints, "}");
}
+ constraints = gb_string_appendc(constraints, ",~{memory}");
+
inline_asm = llvm_get_inline_asm(func_type, make_string_c(asm_string), make_string_c(constraints));
}
break;
@@ -3163,11 +3386,28 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu
{
GB_ASSERT(arg_count <= 7);
- char asm_string[] = "svc #0; cset x8, cc";
- gbString constraints = gb_string_make(heap_allocator(), "={x0},={x8}");
- for (unsigned i = 0; i < arg_count; i++) {
- constraints = gb_string_appendc(constraints, ",{");
- static char const *regs[] = {
+ char const *asm_string;
+ char const **regs;
+ gbString constraints;
+
+ if (build_context.metrics.os == TargetOs_netbsd) {
+ asm_string = "svc #0; cset x17, cc";
+ constraints = gb_string_make(heap_allocator(), "={x0},={x17}");
+ static char const *_regs[] = {
+ "x17",
+ "x0",
+ "x1",
+ "x2",
+ "x3",
+ "x4",
+ "x5",
+ };
+ regs = _regs;
+ } else {
+ // FreeBSD (tested), OpenBSD (untested).
+ asm_string = "svc #0; cset x8, cc";
+ constraints = gb_string_make(heap_allocator(), "={x0},={x8}");
+ static char const *_regs[] = {
"x8",
"x0",
"x1",
@@ -3176,13 +3416,19 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu
"x4",
"x5",
};
+ regs = _regs;
+
+ // FreeBSD clobbered x1 on a call to sysctl.
+ constraints = gb_string_appendc(constraints, ",~{x1}");
+ }
+
+ for (unsigned i = 0; i < arg_count; i++) {
+ constraints = gb_string_appendc(constraints, ",{");
constraints = gb_string_appendc(constraints, regs[i]);
constraints = gb_string_appendc(constraints, "}");
}
- // FreeBSD clobbered x1 on a call to sysctl.
- constraints = gb_string_appendc(constraints, ",~{x1},~{cc},~{memory}");
-
+ constraints = gb_string_appendc(constraints, ",~{cc},~{memory}");
inline_asm = llvm_get_inline_asm(func_type, make_string_c(asm_string), make_string_c(constraints));
}
break;
@@ -3204,6 +3450,7 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu
case BuiltinProc_objc_find_class: return lb_handle_objc_find_class(p, expr);
case BuiltinProc_objc_register_selector: return lb_handle_objc_register_selector(p, expr);
case BuiltinProc_objc_register_class: return lb_handle_objc_register_class(p, expr);
+ case BuiltinProc_objc_ivar_get: return lb_handle_objc_ivar_get(p, expr);
case BuiltinProc_constant_utf16_cstring:
@@ -3255,13 +3502,14 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu
{
isize max_len = 7+8+1;
name = gb_alloc_array(permanent_allocator(), char, max_len);
- u32 id = m->gen->global_array_index.fetch_add(1);
+ u32 id = m->global_array_index.fetch_add(1);
isize len = gb_snprintf(name, max_len, "csbs$%x", id);
len -= 1;
}
LLVMTypeRef type = LLVMTypeOf(array);
LLVMValueRef global_data = LLVMAddGlobal(m->mod, type, name);
LLVMSetInitializer(global_data, array);
+ LLVMSetUnnamedAddress(global_data, LLVMGlobalUnnamedAddr);
LLVMSetLinkage(global_data, LLVMInternalLinkage);
@@ -3567,6 +3815,7 @@ gb_internal lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr) {
GB_ASSERT(ce->args.count == 1);
lbValue x = lb_build_expr(p, ce->args[0]);
lbValue y = lb_emit_conv(p, x, tv.type);
+ y.type = tv.type;
return y;
}
diff --git a/src/llvm_backend_stmt.cpp b/src/llvm_backend_stmt.cpp
index b05df0b46..027837f3f 100644
--- a/src/llvm_backend_stmt.cpp
+++ b/src/llvm_backend_stmt.cpp
@@ -5,8 +5,6 @@ gb_internal 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 (Ast *ident : vd->names) {
GB_ASSERT(ident->kind == Ast_Ident);
Entity *e = entity_of_node(ident);
@@ -32,7 +30,8 @@ gb_internal void lb_build_constant_value_decl(lbProcedure *p, AstValueDecl *vd)
continue;
}
- lb_set_nested_type_name_ir_mangled_name(e, p, p->module);
+ String name = lb_get_entity_name(p->module, e);
+ gb_unused(name);
}
for_array(i, vd->names) {
@@ -137,7 +136,6 @@ gb_internal lbBranchBlocks lb_lookup_branch_blocks(lbProcedure *p, Ast *ident) {
return empty;
}
-
gb_internal lbTargetList *lb_push_target_list(lbProcedure *p, Ast *label, lbBlock *break_, lbBlock *continue_, lbBlock *fallthrough_) {
lbTargetList *tl = gb_alloc_item(permanent_allocator(), lbTargetList);
tl->prev = p->target_list;
@@ -689,6 +687,18 @@ gb_internal void lb_build_range_interval(lbProcedure *p, AstBinaryExpr *node,
lbBlock *body = lb_create_block(p, "for.interval.body");
lbBlock *done = lb_create_block(p, "for.interval.done");
+ // TODO(tf2spi): This is inlined in more than several places.
+ // Putting this in a function might be preferred.
+ // LLVMSetCurrentDebugLocation2 has side effects,
+ // so I didn't want to hide that before it got reviewed.
+ if (rs->label != nullptr && p->debug_info != nullptr) {
+ lbBlock *label = lb_create_block(p, "for.interval.label");
+ lb_emit_jump(p, label);
+ lb_start_block(p, label);
+
+ LLVMSetCurrentDebugLocation2(p->builder, lb_debug_location_from_ast(p, rs->label));
+ lb_add_debug_label(p, rs->label, label);
+ }
lb_emit_jump(p, loop);
lb_start_block(p, loop);
@@ -894,6 +904,14 @@ gb_internal void lb_build_range_stmt_struct_soa(lbProcedure *p, AstRangeStmt *rs
lbAddr index = lb_add_local_generated(p, t_int, false);
+ if (rs->label != nullptr && p->debug_info != nullptr) {
+ lbBlock *label = lb_create_block(p, "for.soa.label");
+ lb_emit_jump(p, label);
+ lb_start_block(p, label);
+
+ LLVMSetCurrentDebugLocation2(p->builder, lb_debug_location_from_ast(p, rs->label));
+ lb_add_debug_label(p, rs->label, label);
+ }
if (!is_reverse) {
/*
for x, i in array {
@@ -971,7 +989,6 @@ gb_internal void lb_build_range_stmt_struct_soa(lbProcedure *p, AstRangeStmt *rs
lb_store_range_stmt_val(p, val1, lb_addr_load(p, index));
}
-
lb_push_target_list(p, rs->label, done, loop, nullptr);
lb_build_stmt(p, rs->body);
@@ -1030,6 +1047,15 @@ gb_internal void lb_build_range_stmt(lbProcedure *p, AstRangeStmt *rs, Scope *sc
lbBlock *done = nullptr;
bool is_map = false;
+ if (rs->label != nullptr && p->debug_info != nullptr) {
+ lbBlock *label = lb_create_block(p, "for.range.label");
+ lb_emit_jump(p, label);
+ lb_start_block(p, label);
+
+ LLVMSetCurrentDebugLocation2(p->builder, lb_debug_location_from_ast(p, rs->label));
+ lb_add_debug_label(p, rs->label, label);
+ }
+
if (tav.mode == Addressing_Type) {
lb_build_range_enum(p, type_deref(tav.type), val0_type, &val, &key, &loop, &done);
} else {
@@ -1046,10 +1072,22 @@ gb_internal void lb_build_range_stmt(lbProcedure *p, AstRangeStmt *rs, Scope *sc
break;
}
case Type_Array: {
- lbValue array = lb_build_addr_ptr(p, expr);
- if (is_type_pointer(type_deref(array.type))) {
- array = lb_emit_load(p, array);
+ lbValue array;
+ lbAddr addr = lb_build_addr(p, expr);
+ switch (addr.kind) {
+ case lbAddr_Swizzle:
+ case lbAddr_SwizzleLarge:
+ // NOTE(laytan): apply the swizzle.
+ array = lb_address_from_load(p, lb_addr_load(p, addr));
+ break;
+ default:
+ array = lb_addr_get_ptr(p, addr);
+ if (is_type_pointer(type_deref(array.type))) {
+ array = lb_emit_load(p, array);
+ }
+ break;
}
+
lbAddr count_ptr = lb_add_local_generated(p, t_int, false);
lb_addr_store(p, count_ptr, lb_const_int(p->module, t_int, et->Array.count));
lb_build_range_indexed(p, array, val0_type, count_ptr.addr, &val, &key, &loop, &done, rs->reverse);
@@ -1115,62 +1153,43 @@ gb_internal void lb_build_range_stmt(lbProcedure *p, AstRangeStmt *rs, Scope *sc
}
Type *elem = et->BitSet.elem;
- if (is_type_enum(elem)) {
- i64 enum_count = 0;
- lbValue values = lb_enum_values_slice(p, elem, &enum_count);
- lbValue values_data = lb_slice_elem(p, values);
- lbValue max_count = lb_const_int(m, t_int, enum_count);
-
- lbAddr offset_ = lb_add_local_generated(p, t_int, false);
- lb_addr_store(p, offset_, lb_const_int(m, t_int, 0));
-
- loop = lb_create_block(p, "for.bit_set.enum.loop");
- lb_emit_jump(p, loop);
- lb_start_block(p, loop);
-
- lbBlock *body_check = lb_create_block(p, "for.bit_set.enum.body-check");
- lbBlock *body = lb_create_block(p, "for.bit_set.enum.body");
- done = lb_create_block(p, "for.bit_set.enum.done");
-
- lbValue offset = lb_addr_load(p, offset_);
- lbValue cond = lb_emit_comp(p, Token_Lt, offset, max_count);
- lb_emit_if(p, cond, body_check, done);
- lb_start_block(p, body_check);
-
- lbValue val_ptr = lb_emit_ptr_offset(p, values_data, offset);
- lb_emit_increment(p, offset_.addr);
- val = lb_emit_load(p, val_ptr);
- val = lb_emit_conv(p, val, elem);
-
- lbValue check = lb_build_binary_in(p, val, the_set, Token_in);
- lb_emit_if(p, check, body, loop);
- lb_start_block(p, body);
- } else {
- lbAddr offset_ = lb_add_local_generated(p, t_int, false);
- lb_addr_store(p, offset_, lb_const_int(m, t_int, et->BitSet.lower));
+ Type *mask = bit_set_to_int(et);
- lbValue max_count = lb_const_int(m, t_int, et->BitSet.upper);
+ lbValue all_mask = lb_const_value(p->module, mask, exact_bit_set_all_set_mask(et));
+ lbValue initial_mask = lb_emit_arith(p, Token_And, the_set, all_mask, mask);
- loop = lb_create_block(p, "for.bit_set.range.loop");
- lb_emit_jump(p, loop);
- lb_start_block(p, loop);
+ if (rs->reverse) {
+ initial_mask = lb_emit_reverse_bits(p, initial_mask, mask);
+ }
+
+ lbAddr remaining = lb_add_local_generated(p, mask, false);
+ lb_addr_store(p, remaining, initial_mask);
- lbBlock *body_check = lb_create_block(p, "for.bit_set.range.body-check");
- lbBlock *body = lb_create_block(p, "for.bit_set.range.body");
- done = lb_create_block(p, "for.bit_set.range.done");
+ loop = lb_create_block(p, "for.bit_set.loop");
+ lbBlock *body = lb_create_block(p, "for.bit_set.body");
+ done = lb_create_block(p, "for.bit_set.done");
- lbValue offset = lb_addr_load(p, offset_);
- lbValue cond = lb_emit_comp(p, Token_LtEq, offset, max_count);
- lb_emit_if(p, cond, body_check, done);
- lb_start_block(p, body_check);
+ lb_emit_jump(p, loop);
+ lb_start_block(p, loop);
- val = lb_emit_conv(p, offset, elem);
- lb_emit_increment(p, offset_.addr);
+ lbValue remaining_val = lb_addr_load(p, remaining);
+ lbValue cond = lb_emit_comp(p, Token_NotEq, remaining_val, lb_zero(m, mask));
+ lb_emit_if(p, cond, body, done);
- lbValue check = lb_build_binary_in(p, val, the_set, Token_in);
- lb_emit_if(p, check, body, loop);
- lb_start_block(p, body);
+ lb_start_block(p, body);
+ val = lb_emit_count_trailing_zeros(p, remaining_val, mask);
+ val = lb_emit_conv(p, val, elem);
+
+ if (rs->reverse) {
+ val = lb_emit_arith(p, Token_Sub, lb_const_int(m, elem, et->BitSet.lower + 8*type_size_of(mask) - 1), val, elem);
+ } else {
+ val = lb_emit_arith(p, Token_Add, val, lb_const_int(m, elem, et->BitSet.lower), elem);
}
+
+ lbValue reduce_val = lb_emit_arith(p, Token_Sub, remaining_val, lb_const_int(m, mask, 1), mask);
+ remaining_val = lb_emit_arith(p, Token_And, remaining_val, reduce_val, mask);
+ lb_addr_store(p, remaining, remaining_val);
+
break;
}
default:
@@ -1550,6 +1569,14 @@ gb_internal bool lb_switch_stmt_can_be_trivial_jump_table(AstSwitchStmt *ss, boo
gb_internal void lb_build_switch_stmt(lbProcedure *p, AstSwitchStmt *ss, Scope *scope) {
lb_open_scope(p, scope);
+ if (ss->label != nullptr && p->debug_info != nullptr) {
+ lbBlock *label = lb_create_block(p, "switch.label");
+ lb_emit_jump(p, label);
+ lb_start_block(p, label);
+
+ LLVMSetCurrentDebugLocation2(p->builder, lb_debug_location_from_ast(p, ss->label));
+ lb_add_debug_label(p, ss->label, label);
+ }
if (ss->init != nullptr) {
lb_build_stmt(p, ss->init);
}
@@ -1756,6 +1783,7 @@ gb_internal lbAddr lb_store_range_stmt_val(lbProcedure *p, Ast *stmt_val, lbValu
gb_internal void lb_type_case_body(lbProcedure *p, Ast *label, Ast *clause, lbBlock *body, lbBlock *done) {
ast_node(cc, CaseClause, clause);
+ // NOTE(tf2spi): Debug info for label not generated here on purpose
lb_push_target_list(p, label, done, nullptr, nullptr);
lb_build_stmt_list(p, cc->stmts);
lb_close_scope(p, lbDeferExit_Default, body, clause);
@@ -1958,7 +1986,11 @@ gb_internal void lb_build_type_switch_stmt(lbProcedure *p, AstTypeSwitchStmt *ss
lb_add_entity(p->module, case_entity, ptr);
lb_add_debug_local_variable(p, ptr.value, case_entity->type, case_entity->token);
} else {
- lb_store_type_case_implicit(p, clause, parent_value, false);
+ if (by_reference) {
+ lb_store_type_case_implicit(p, clause, parent_ptr, false);
+ } else {
+ lb_store_type_case_implicit(p, clause, parent_value, false);
+ }
}
lb_type_case_body(p, ss->label, clause, body, done);
@@ -1979,8 +2011,7 @@ gb_internal void lb_build_static_variables(lbProcedure *p, AstValueDecl *vd) {
GB_ASSERT(ast_value->tav.mode == Addressing_Constant ||
ast_value->tav.mode == Addressing_Invalid);
- bool allow_local = false;
- value = lb_const_value(p->module, ast_value->tav.type, ast_value->tav.value, allow_local);
+ value = lb_const_value(p->module, ast_value->tav.type, ast_value->tav.value, LB_CONST_CONTEXT_DEFAULT_NO_LOCAL);
}
Ast *ident = vd->names[i];
@@ -2001,34 +2032,45 @@ gb_internal void lb_build_static_variables(lbProcedure *p, AstValueDecl *vd) {
char *c_name = alloc_cstring(permanent_allocator(), mangled_name);
LLVMValueRef global = LLVMAddGlobal(p->module->mod, lb_type(p->module, e->type), c_name);
+ LLVMSetAlignment(global, cast(u32)type_align_of(e->type));
LLVMSetInitializer(global, LLVMConstNull(lb_type(p->module, e->type)));
- if (value.value != nullptr) {
- LLVMSetInitializer(global, value.value);
- }
+
if (e->Variable.is_rodata) {
LLVMSetGlobalConstant(global, true);
}
- if (e->Variable.thread_local_model != "") {
- LLVMSetThreadLocal(global, true);
-
- String m = e->Variable.thread_local_model;
- LLVMThreadLocalMode mode = LLVMGeneralDynamicTLSModel;
- if (m == "default") {
- mode = LLVMGeneralDynamicTLSModel;
- } else if (m == "localdynamic") {
- mode = LLVMLocalDynamicTLSModel;
- } else if (m == "initialexec") {
- mode = LLVMInitialExecTLSModel;
- } else if (m == "localexec") {
- mode = LLVMLocalExecTLSModel;
- } else {
- GB_PANIC("Unhandled thread local mode %.*s", LIT(m));
- }
- LLVMSetThreadLocalMode(global, mode);
- } else {
+
+ if (!lb_apply_thread_local_model(global, e->Variable.thread_local_model)) {
LLVMSetLinkage(global, LLVMInternalLinkage);
}
+ if (value.value != nullptr) {
+ if (is_type_any(e->type)) {
+ Type *var_type = default_type(value.type);
+
+ gbString var_name = gb_string_make(temporary_allocator(), "__$static_any::");
+ var_name = gb_string_append_length(var_name, mangled_name.text, mangled_name.len);
+
+ lbAddr var_global = lb_add_global_generated_with_name(p->module, var_type, value, make_string_c(var_name), nullptr);
+ LLVMValueRef var_global_ref = var_global.addr.value;
+
+ if (e->Variable.is_rodata) {
+ LLVMSetGlobalConstant(var_global_ref, true);
+ }
+
+ if (!lb_apply_thread_local_model(var_global_ref, e->Variable.thread_local_model)) {
+ LLVMSetLinkage(var_global_ref, LLVMInternalLinkage);
+ }
+
+ LLVMValueRef vals[2] = {
+ lb_emit_conv(p, var_global.addr, t_rawptr).value,
+ lb_typeid(p->module, var_type).value,
+ };
+ LLVMValueRef init = llvm_const_named_struct(p->module, e->type, vals, gb_count_of(vals));
+ LLVMSetInitializer(global, init);
+ } else {
+ LLVMSetInitializer(global, value.value);
+ }
+ }
lbValue global_val = {global, alloc_type_pointer(e->type)};
lb_add_entity(p->module, e, global_val);
@@ -2323,6 +2365,14 @@ gb_internal void lb_build_if_stmt(lbProcedure *p, Ast *node) {
else_ = lb_create_block(p, "if.else");
}
if (is->label != nullptr) {
+ if (p->debug_info != nullptr) {
+ lbBlock *label = lb_create_block(p, "if.label");
+ lb_emit_jump(p, label);
+ lb_start_block(p, label);
+
+ LLVMSetCurrentDebugLocation2(p->builder, lb_debug_location_from_ast(p, is->label));
+ lb_add_debug_label(p, is->label, label);
+ }
lbTargetList *tl = lb_push_target_list(p, is->label, done, nullptr, nullptr);
tl->is_block = true;
}
@@ -2415,12 +2465,19 @@ gb_internal void lb_build_for_stmt(lbProcedure *p, Ast *node) {
lb_push_target_list(p, fs->label, done, post, nullptr);
+ if (fs->label != nullptr && p->debug_info != nullptr) {
+ lbBlock *label = lb_create_block(p, "for.label");
+ lb_emit_jump(p, label);
+ lb_start_block(p, label);
+
+ LLVMSetCurrentDebugLocation2(p->builder, lb_debug_location_from_ast(p, fs->label));
+ lb_add_debug_label(p, fs->label, label);
+ }
if (fs->init != nullptr) {
- #if 1
lbBlock *init = lb_create_block(p, "for.init");
lb_emit_jump(p, init);
lb_start_block(p, init);
- #endif
+
lb_build_stmt(p, fs->init);
}
@@ -2436,7 +2493,6 @@ gb_internal void lb_build_for_stmt(lbProcedure *p, Ast *node) {
lb_start_block(p, body);
}
-
lb_build_stmt(p, fs->body);
lb_pop_target_list(p);
@@ -2710,9 +2766,21 @@ gb_internal void lb_build_stmt(lbProcedure *p, Ast *node) {
case_ast_node(bs, BlockStmt, node);
+ lbBlock *body = nullptr;
lbBlock *done = nullptr;
if (bs->label != nullptr) {
+ if (p->debug_info != nullptr) {
+ lbBlock *label = lb_create_block(p, "block.label");
+ lb_emit_jump(p, label);
+ lb_start_block(p, label);
+
+ LLVMSetCurrentDebugLocation2(p->builder, lb_debug_location_from_ast(p, bs->label));
+ lb_add_debug_label(p, bs->label, label);
+ }
+ body = lb_create_block(p, "block.body");
done = lb_create_block(p, "block.done");
+ lb_emit_jump(p, body);
+ lb_start_block(p, body);
lbTargetList *tl = lb_push_target_list(p, bs->label, done, nullptr, nullptr);
tl->is_block = true;
}
@@ -2933,6 +3001,18 @@ gb_internal void lb_emit_defer_stmts(lbProcedure *p, lbDeferExitKind kind, lbBlo
}
defer (p->branch_location_pos = prev_token_pos);
+ // TODO(lucas): In LLVM 21 use the 'use-after-scope' asan option which does this for us.
+ if (kind == lbDeferExit_Return) {
+ for_array(i, p->asan_stack_locals) {
+ lbValue local = p->asan_stack_locals[i];
+
+ auto args = array_make<lbValue>(temporary_allocator(), 2);
+ args[0] = lb_emit_conv(p, local, t_rawptr);
+ args[1] = lb_const_int(p->module, t_int, type_size_of(local.type->Pointer.elem));
+ lb_emit_runtime_call(p, "__asan_unpoison_memory_region", args);
+ }
+ }
+
isize count = p->defer_stmts.count;
isize i = count;
while (i --> 0) {
diff --git a/src/llvm_backend_type.cpp b/src/llvm_backend_type.cpp
index 6c12b37be..4e514c3d1 100644
--- a/src/llvm_backend_type.cpp
+++ b/src/llvm_backend_type.cpp
@@ -1,24 +1,30 @@
-gb_internal isize lb_type_info_index(CheckerInfo *info, Type *type, bool err_on_not_found=true) {
- auto *set = &info->minimum_dependency_type_info_set;
- isize index = type_info_index(info, type, err_on_not_found);
+
+gb_internal void lb_set_odin_rtti_section(LLVMValueRef value) {
+ if (build_context.metrics.os != TargetOs_darwin) {
+ LLVMSetSection(value, ".odinti");
+ }
+}
+
+gb_internal isize lb_type_info_index(CheckerInfo *info, TypeInfoPair pair, bool err_on_not_found=true) {
+ isize index = type_info_index(info, pair, err_on_not_found);
if (index >= 0) {
- auto *found = map_get(set, index+1);
- if (found) {
- GB_ASSERT(*found >= 0);
- return *found + 1;
- }
+ return index;
}
if (err_on_not_found) {
- gb_printf_err("NOT FOUND lb_type_info_index:\n\t%s\n\t@ index %td\n\tmax count: %u\nFound:\n", type_to_string(type), index, set->count);
- for (auto const &entry : *set) {
+ gb_printf_err("NOT FOUND lb_type_info_index:\n\t%s\n\t@ index %td\n\tmax count: %u\nFound:\n", type_to_string(pair.type), index, info->min_dep_type_info_index_map.count);
+ for (auto const &entry : info->min_dep_type_info_index_map) {
isize type_info_index = entry.key;
- gb_printf_err("\t%s\n", type_to_string(info->type_info_types[type_info_index]));
+ gb_printf_err("\t%s\n", type_to_string(info->type_info_types_hash_map[type_info_index].type));
}
GB_PANIC("NOT FOUND");
}
return -1;
}
+gb_internal isize lb_type_info_index(CheckerInfo *info, Type *type, bool err_on_not_found=true) {
+ return lb_type_info_index(info, {type, type_hash_canonical_type(type)}, err_on_not_found);
+}
+
gb_internal u64 lb_typeid_kind(lbModule *m, Type *type, u64 id=0) {
GB_ASSERT(!build_context.no_rtti);
@@ -73,37 +79,8 @@ gb_internal lbValue lb_typeid(lbModule *m, Type *type) {
type = default_type(type);
- u64 id = cast(u64)lb_type_info_index(m->info, type);
- GB_ASSERT(id >= 0);
-
- u64 kind = lb_typeid_kind(m, type, id);
- u64 named = is_type_named(type) && type->kind != Type_Basic;
- u64 special = 0;
- u64 reserved = 0;
-
- if (is_type_cstring(type)) {
- special = 1;
- } else if (is_type_integer(type) && !is_type_unsigned(type)) {
- special = 1;
- }
-
- u64 data = 0;
- if (build_context.ptr_size == 4) {
- GB_ASSERT(id <= (1u<<24u));
- data |= (id &~ (1u<<24)) << 0u; // index
- data |= (kind &~ (1u<<5)) << 24u; // kind
- data |= (named &~ (1u<<1)) << 29u; // named
- data |= (special &~ (1u<<1)) << 30u; // special
- data |= (reserved &~ (1u<<1)) << 31u; // reserved
- } else {
- GB_ASSERT(build_context.ptr_size == 8);
- GB_ASSERT(id <= (1ull<<56u));
- data |= (id &~ (1ull<<56)) << 0ul; // index
- data |= (kind &~ (1ull<<5)) << 56ull; // kind
- data |= (named &~ (1ull<<1)) << 61ull; // named
- data |= (special &~ (1ull<<1)) << 62ull; // special
- data |= (reserved &~ (1ull<<1)) << 63ull; // reserved
- }
+ u64 data = type_hash_canonical_type(type);
+ GB_ASSERT(data != 0);
lbValue res = {};
res.value = LLVMConstInt(lb_type(m, t_typeid), data, false);
@@ -250,6 +227,7 @@ gb_internal void lb_setup_type_info_data_giant_array(lbModule *m, i64 global_typ
gb_snprintf(name, 63, "__$ti-%lld", cast(long long)index);
LLVMValueRef g = LLVMAddGlobal(m->mod, type, name);
lb_make_global_private_const(g);
+ lb_set_odin_rtti_section(g);
return g;
};
@@ -279,13 +257,14 @@ gb_internal void lb_setup_type_info_data_giant_array(lbModule *m, i64 global_typ
LLVMTypeRef *modified_types = lb_setup_modified_types_for_type_info(m, global_type_info_data_entity_count);
defer (gb_free(heap_allocator(), modified_types));
- for_array(type_info_type_index, info->type_info_types) {
- Type *t = info->type_info_types[type_info_type_index];
+ for_array(type_info_type_index, info->type_info_types_hash_map) {
+ auto const &tt = info->type_info_types_hash_map[type_info_type_index];
+ Type *t = tt.type;
if (t == nullptr || t == t_invalid) {
continue;
}
- isize entry_index = lb_type_info_index(info, t, false);
+ isize entry_index = lb_type_info_index(info, tt, false);
if (entry_index <= 0) {
continue;
}
@@ -342,8 +321,8 @@ gb_internal void lb_setup_type_info_data_giant_array(lbModule *m, i64 global_typ
return giant_const_values[index];
};
- for_array(type_info_type_index, info->type_info_types) {
- Type *t = info->type_info_types[type_info_type_index];
+ for_array(type_info_type_index, info->type_info_types_hash_map) {
+ Type *t = info->type_info_types_hash_map[type_info_type_index].type;
if (t == nullptr || t == t_invalid) {
continue;
}
@@ -744,6 +723,8 @@ gb_internal void lb_setup_type_info_data_giant_array(lbModule *m, i64 global_typ
LLVMSetInitializer(value_array.value, value_init);
LLVMSetGlobalConstant(name_array.value, true);
LLVMSetGlobalConstant(value_array.value, true);
+ lb_set_odin_rtti_section(name_array.value);
+ lb_set_odin_rtti_section(value_array.value);
lbValue v_count = lb_const_int(m, t_int, fields.count);
@@ -1071,7 +1052,12 @@ gb_internal void lb_setup_type_info_data_giant_array(lbModule *m, i64 global_typ
LLVMSetInitializer(giant_const_values[entry_index], LLVMConstNamedStruct(stype, small_const_values, variant_index+1));
}
for (isize i = 0; i < global_type_info_data_entity_count; i++) {
- giant_const_values[i] = LLVMConstPointerCast(giant_const_values[i], lb_type(m, t_type_info_ptr));
+ auto *ptr = &giant_const_values[i];
+ if (*ptr != nullptr) {
+ *ptr = LLVMConstPointerCast(*ptr, lb_type(m, t_type_info_ptr));
+ } else {
+ *ptr = LLVMConstNull(lb_type(m, t_type_info_ptr));
+ }
}
@@ -1079,6 +1065,7 @@ gb_internal void lb_setup_type_info_data_giant_array(lbModule *m, i64 global_typ
LLVMValueRef giant_array = lb_global_type_info_data_ptr(m).value;
LLVMSetInitializer(giant_array, giant_const);
lb_make_global_private_const(giant_array);
+ lb_set_odin_rtti_section(giant_array);
}
diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp
index 7b7c9d6e9..521553147 100644
--- a/src/llvm_backend_utility.cpp
+++ b/src/llvm_backend_utility.cpp
@@ -771,9 +771,7 @@ gb_internal lbValue lb_emit_union_cast(lbProcedure *p, lbValue value, Type *type
auto args = array_make<lbValue>(permanent_allocator(), arg_count);
args[0] = ok;
- args[1] = lb_const_string(m, get_file_path_string(pos.file_id));
- args[2] = lb_const_int(m, t_i32, pos.line);
- args[3] = lb_const_int(m, t_i32, pos.column);
+ lb_set_file_line_col(p, array_slice(args, 1, args.count), pos);
if (!build_context.no_rtti) {
args[4] = lb_typeid(m, src_type);
@@ -847,9 +845,7 @@ gb_internal lbAddr lb_emit_any_cast_addr(lbProcedure *p, lbValue value, Type *ty
auto args = array_make<lbValue>(permanent_allocator(), arg_count);
args[0] = ok;
- args[1] = lb_const_string(m, get_file_path_string(pos.file_id));
- args[2] = lb_const_int(m, t_i32, pos.line);
- args[3] = lb_const_int(m, t_i32, pos.column);
+ lb_set_file_line_col(p, array_slice(args, 1, args.count), pos);
if (!build_context.no_rtti) {
args[4] = any_typeid;
@@ -975,6 +971,13 @@ gb_internal i32 lb_convert_struct_index(lbModule *m, Type *t, i32 index) {
if (t->kind == Type_Struct) {
auto field_remapping = lb_get_struct_remapping(m, t);
return field_remapping[index];
+ } else if (is_type_any(t) && build_context.ptr_size == 4) {
+ GB_ASSERT(t->kind == Type_Basic);
+ GB_ASSERT(t->Basic.kind == Basic_any);
+ switch (index) {
+ case 0: return 0; // data
+ case 1: return 2; // id
+ }
} else if (build_context.ptr_size != build_context.int_size) {
switch (t->kind) {
case Type_Basic:
@@ -2091,25 +2094,127 @@ gb_internal void lb_set_wasm_export_attributes(LLVMValueRef value, String export
}
-
gb_internal lbAddr lb_handle_objc_find_or_register_selector(lbProcedure *p, String const &name) {
- lbAddr *found = string_map_get(&p->module->objc_selectors, name);
+ lbModule *m = p->module;
+ lbAddr *found = string_map_get(&m->objc_selectors, name);
if (found) {
return *found;
+ }
+
+ lbModule *default_module = &p->module->gen->default_module;
+
+ gbString global_name = gb_string_make(permanent_allocator(), "__$objc_SEL::");
+ global_name = gb_string_append_length(global_name, name.text, name.len);
+
+ LLVMTypeRef t = lb_type(m, t_objc_SEL);
+ lbValue g = {};
+ g.value = LLVMAddGlobal(m->mod, t, global_name);
+ g.type = alloc_type_pointer(t_objc_SEL);
+
+ if (default_module == m) {
+ LLVMSetInitializer(g.value, LLVMConstNull(t));
+ lb_add_member(m, make_string_c(global_name), g);
} else {
- lbModule *default_module = &p->module->gen->default_module;
- Entity *e = nullptr;
- lbAddr default_addr = lb_add_global_generated(default_module, t_objc_SEL, {}, &e);
+ LLVMSetLinkage(g.value, LLVMExternalLinkage);
+ }
- lbValue ptr = lb_find_value_from_entity(p->module, e);
- lbAddr local_addr = lb_addr(ptr);
+ mpsc_enqueue(&m->gen->objc_selectors, lbObjCGlobal{m, global_name, name, t_objc_SEL});
- string_map_set(&default_module->objc_selectors, name, default_addr);
- if (default_module != p->module) {
- string_map_set(&p->module->objc_selectors, name, local_addr);
- }
- return local_addr;
+ lbAddr addr = lb_addr(g);
+ string_map_set(&m->objc_selectors, name, addr);
+ return addr;
+}
+
+gb_internal lbAddr lb_handle_objc_find_or_register_class(lbProcedure *p, String const &name, Type *class_impl_type) {
+ lbModule *m = p->module;
+ lbAddr *found = string_map_get(&m->objc_classes, name);
+ if (found) {
+ return *found;
+ }
+
+ lbModule *default_module = &p->module->gen->default_module;
+
+ gbString global_name = gb_string_make(permanent_allocator(), "__$objc_Class::");
+ global_name = gb_string_append_length(global_name, name.text, name.len);
+
+ LLVMTypeRef t = lb_type(m, t_objc_Class);
+ lbValue g = {};
+ g.value = LLVMAddGlobal(m->mod, t, global_name);
+ g.type = alloc_type_pointer(t_objc_Class);
+
+ if (default_module == m) {
+ LLVMSetInitializer(g.value, LLVMConstNull(t));
+ lb_add_member(m, make_string_c(global_name), g);
+ } else {
+ LLVMSetLinkage(g.value, LLVMExternalLinkage);
}
+ mpsc_enqueue(&m->gen->objc_classes, lbObjCGlobal{m, global_name, name, t_objc_Class, class_impl_type});
+
+ lbAddr addr = lb_addr(g);
+ string_map_set(&m->objc_classes, name, addr);
+ return addr;
+}
+
+gb_internal lbAddr lb_handle_objc_find_or_register_ivar(lbModule *m, Type *self_type) {
+
+ String name = self_type->Named.type_name->TypeName.objc_class_name;
+ GB_ASSERT(name != "");
+
+ lbAddr *found = string_map_get(&m->objc_ivars, name);
+ if (found) {
+ return *found;
+ }
+
+ lbModule *default_module = &m->gen->default_module;
+
+ gbString global_name = gb_string_make(permanent_allocator(), "__$objc_ivar::");
+ global_name = gb_string_append_length(global_name, name.text, name.len);
+
+ // Create a global variable to store offset of the ivar in an instance of an object
+ LLVMTypeRef t = lb_type(m, t_int);
+
+ lbValue g = {};
+ g.value = LLVMAddGlobal(m->mod, t, global_name);
+ g.type = t_int_ptr;
+
+ if (default_module == m) {
+ LLVMSetInitializer(g.value, LLVMConstInt(t, 0, true));
+ lb_add_member(m, make_string_c(global_name), g);
+ } else {
+ LLVMSetLinkage(g.value, LLVMExternalLinkage);
+ }
+
+ mpsc_enqueue(&m->gen->objc_ivars, lbObjCGlobal{m, global_name, name, t_int, self_type});
+
+ lbAddr addr = lb_addr(g);
+ string_map_set(&m->objc_ivars, name, addr);
+ return addr;
+}
+
+gb_internal lbValue lb_handle_objc_ivar_for_objc_object_pointer(lbProcedure *p, lbValue self) {
+ GB_ASSERT(self.type->kind == Type_Pointer && self.type->Pointer.elem->kind == Type_Named);
+
+ Type *self_type = self.type->Pointer.elem;
+
+ lbValue self_uptr = lb_emit_conv(p, self, t_uintptr);
+
+ lbValue ivar_offset = lb_addr_load(p, lb_handle_objc_find_or_register_ivar(p->module, self_type));
+ lbValue ivar_offset_uptr = lb_emit_conv(p, ivar_offset, t_uintptr);
+
+
+ lbValue ivar_uptr = lb_emit_arith(p, Token_Add, self_uptr, ivar_offset_uptr, t_uintptr);
+
+ Type *ivar_type = self_type->Named.type_name->TypeName.objc_ivar;
+ return lb_emit_conv(p, ivar_uptr, alloc_type_pointer(ivar_type));
+}
+
+gb_internal lbValue lb_handle_objc_ivar_get(lbProcedure *p, Ast *expr) {
+ ast_node(ce, CallExpr, expr);
+
+ GB_ASSERT(ce->args[0]->tav.type->kind == Type_Pointer);
+ lbValue self = lb_build_expr(p, ce->args[0]);
+
+ return lb_handle_objc_ivar_for_objc_object_pointer(p, self);
}
gb_internal lbValue lb_handle_objc_find_selector(lbProcedure *p, Ast *expr) {
@@ -2138,25 +2243,6 @@ gb_internal lbValue lb_handle_objc_register_selector(lbProcedure *p, Ast *expr)
return lb_addr_load(p, dst);
}
-gb_internal lbAddr lb_handle_objc_find_or_register_class(lbProcedure *p, String const &name) {
- lbAddr *found = string_map_get(&p->module->objc_classes, name);
- if (found) {
- return *found;
- } else {
- lbModule *default_module = &p->module->gen->default_module;
- Entity *e = nullptr;
- lbAddr default_addr = lb_add_global_generated(default_module, t_objc_SEL, {}, &e);
-
- lbValue ptr = lb_find_value_from_entity(p->module, e);
- lbAddr local_addr = lb_addr(ptr);
-
- string_map_set(&default_module->objc_classes, name, default_addr);
- if (default_module != p->module) {
- string_map_set(&p->module->objc_classes, name, local_addr);
- }
- return local_addr;
- }
-}
gb_internal lbValue lb_handle_objc_find_class(lbProcedure *p, Ast *expr) {
ast_node(ce, CallExpr, expr);
@@ -2164,7 +2250,7 @@ gb_internal lbValue lb_handle_objc_find_class(lbProcedure *p, Ast *expr) {
auto tav = ce->args[0]->tav;
GB_ASSERT(tav.value.kind == ExactValue_String);
String name = tav.value.value_string;
- return lb_addr_load(p, lb_handle_objc_find_or_register_class(p, name));
+ return lb_addr_load(p, lb_handle_objc_find_or_register_class(p, name, nullptr));
}
gb_internal lbValue lb_handle_objc_register_class(lbProcedure *p, Ast *expr) {
@@ -2174,7 +2260,7 @@ gb_internal lbValue lb_handle_objc_register_class(lbProcedure *p, Ast *expr) {
auto tav = ce->args[0]->tav;
GB_ASSERT(tav.value.kind == ExactValue_String);
String name = tav.value.value_string;
- lbAddr dst = lb_handle_objc_find_or_register_class(p, name);
+ lbAddr dst = lb_handle_objc_find_or_register_class(p, name, nullptr);
auto args = array_make<lbValue>(permanent_allocator(), 3);
args[0] = lb_const_nil(m, t_objc_Class);
@@ -2196,23 +2282,9 @@ gb_internal lbValue lb_handle_objc_id(lbProcedure *p, Ast *expr) {
GB_ASSERT(e->kind == Entity_TypeName);
String name = e->TypeName.objc_class_name;
- lbAddr *found = string_map_get(&p->module->objc_classes, name);
- if (found) {
- return lb_addr_load(p, *found);
- } else {
- lbModule *default_module = &p->module->gen->default_module;
- Entity *e = nullptr;
- lbAddr default_addr = lb_add_global_generated(default_module, t_objc_Class, {}, &e);
-
- lbValue ptr = lb_find_value_from_entity(p->module, e);
- lbAddr local_addr = lb_addr(ptr);
+ Type *class_impl_type = e->TypeName.objc_is_implementation ? type : nullptr;
- string_map_set(&default_module->objc_classes, name, default_addr);
- if (default_module != p->module) {
- string_map_set(&p->module->objc_classes, name, local_addr);
- }
- return lb_addr_load(p, local_addr);
- }
+ return lb_addr_load(p, lb_handle_objc_find_or_register_class(p, name, class_impl_type));
}
return lb_build_expr(p, expr);
@@ -2258,9 +2330,6 @@ gb_internal lbValue lb_handle_objc_send(lbProcedure *p, Ast *expr) {
return lb_emit_call(p, the_proc, args);
}
-
-
-
gb_internal LLVMAtomicOrdering llvm_atomic_ordering_from_odin(ExactValue const &value) {
GB_ASSERT(value.kind == ExactValue_Integer);
i64 v = exact_value_to_i64(value);
diff --git a/src/main.cpp b/src/main.cpp
index 41c7170f6..f988aff6a 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -74,6 +74,7 @@ gb_global Timings global_timings = {0};
#include "cached.cpp"
#include "linker.cpp"
+#include "bundle_command.cpp"
#if defined(GB_SYSTEM_WINDOWS) && defined(ODIN_TILDE_BACKEND)
#define ALLOW_TILDE 1
@@ -87,13 +88,6 @@ gb_global Timings global_timings = {0};
#include "llvm_backend.cpp"
-#if defined(GB_SYSTEM_OSX)
- #include <llvm/Config/llvm-config.h>
- #if LLVM_VERSION_MAJOR < 11 || (LLVM_VERSION_MAJOR > 14 && LLVM_VERSION_MAJOR < 17) || LLVM_VERSION_MAJOR > 19
- #error LLVM Version 11..=14 or 17..=19 is required => "brew install llvm@14"
- #endif
-#endif
-
#include "bug_report.cpp"
// NOTE(bill): 'name' is used in debugging and profiling modes
@@ -283,10 +277,11 @@ gb_internal void usage(String argv0, String argv1 = {}) {
print_usage_line(1, "build Compiles directory of .odin files, as an executable.");
print_usage_line(1, " One must contain the program's entry point, all must be in the same package.");
print_usage_line(1, "run Same as 'build', but also then runs the newly compiled executable.");
- print_usage_line(1, "check Parses, and type checks a directory of .odin files.");
+ print_usage_line(1, "bundle Bundles a directory in a specific layout for that platform.");
+ print_usage_line(1, "check Parses and type checks a directory of .odin files.");
print_usage_line(1, "strip-semicolon Parses, type checks, and removes unneeded semicolons from the entire program.");
print_usage_line(1, "test Builds and runs procedures with the attribute @(test) in the initial package.");
- print_usage_line(1, "doc Generates documentation on a directory of .odin files.");
+ print_usage_line(1, "doc Generates documentation from a directory of .odin files.");
print_usage_line(1, "version Prints version.");
print_usage_line(1, "report Prints information useful to reporting a bug.");
print_usage_line(1, "root Prints the root path where Odin looks for the builtin collections.");
@@ -317,6 +312,7 @@ enum BuildFlagKind {
BuildFlag_Collection,
BuildFlag_Define,
BuildFlag_BuildMode,
+ BuildFlag_KeepExecutable,
BuildFlag_Target,
BuildFlag_Subtarget,
BuildFlag_Debug,
@@ -324,6 +320,7 @@ enum BuildFlagKind {
BuildFlag_NoBoundsCheck,
BuildFlag_NoTypeAssert,
BuildFlag_NoDynamicLiterals,
+ BuildFlag_DynamicLiterals,
BuildFlag_NoCRT,
BuildFlag_NoRPath,
BuildFlag_NoEntryPoint,
@@ -331,6 +328,7 @@ enum BuildFlagKind {
BuildFlag_UseRADLink,
BuildFlag_Linker,
BuildFlag_UseSeparateModules,
+ BuildFlag_UseSingleModule,
BuildFlag_NoThreadedChecker,
BuildFlag_ShowDebugMessages,
@@ -372,6 +370,7 @@ enum BuildFlagKind {
BuildFlag_NoRTTI,
BuildFlag_DynamicMapCalls,
BuildFlag_ObfuscateSourceCodeLocations,
+ BuildFlag_SourceCodeLocations,
BuildFlag_Compact,
BuildFlag_GlobalDefinitions,
@@ -414,6 +413,10 @@ enum BuildFlagKind {
BuildFlag_Subsystem,
#endif
+ BuildFlag_AndroidKeystore,
+ BuildFlag_AndroidKeystoreAlias,
+ BuildFlag_AndroidKeystorePassword,
+
BuildFlag_COUNT,
};
@@ -432,12 +435,12 @@ struct BuildFlag {
BuildFlagKind kind;
String name;
BuildFlagParamKind param_kind;
- u32 command_support;
+ u64 command_support;
bool allow_multiple;
};
-gb_internal void add_flag(Array<BuildFlag> *build_flags, BuildFlagKind kind, String name, BuildFlagParamKind param_kind, u32 command_support, bool allow_multiple=false) {
+gb_internal void add_flag(Array<BuildFlag> *build_flags, BuildFlagKind kind, String name, BuildFlagParamKind param_kind, u64 command_support, bool allow_multiple=false) {
BuildFlag flag = {kind, name, param_kind, command_support, allow_multiple};
array_add(build_flags, flag);
}
@@ -530,6 +533,7 @@ gb_internal bool parse_build_flags(Array<String> args) {
add_flag(&build_flags, BuildFlag_Collection, str_lit("collection"), BuildFlagParam_String, Command__does_check);
add_flag(&build_flags, BuildFlag_Define, str_lit("define"), BuildFlagParam_String, Command__does_check, true);
add_flag(&build_flags, BuildFlag_BuildMode, str_lit("build-mode"), BuildFlagParam_String, Command__does_build); // Commands_build is not used to allow for a better error message
+ add_flag(&build_flags, BuildFlag_KeepExecutable, str_lit("keep-executable"), BuildFlagParam_None, Command__does_build | Command_test);
add_flag(&build_flags, BuildFlag_Target, str_lit("target"), BuildFlagParam_String, Command__does_check);
add_flag(&build_flags, BuildFlag_Subtarget, str_lit("subtarget"), BuildFlagParam_String, Command__does_check);
add_flag(&build_flags, BuildFlag_Debug, str_lit("debug"), BuildFlagParam_None, Command__does_check);
@@ -538,6 +542,7 @@ gb_internal bool parse_build_flags(Array<String> args) {
add_flag(&build_flags, BuildFlag_NoTypeAssert, str_lit("no-type-assert"), BuildFlagParam_None, Command__does_check);
add_flag(&build_flags, BuildFlag_NoThreadLocal, str_lit("no-thread-local"), BuildFlagParam_None, Command__does_check);
add_flag(&build_flags, BuildFlag_NoDynamicLiterals, str_lit("no-dynamic-literals"), BuildFlagParam_None, Command__does_check);
+ add_flag(&build_flags, BuildFlag_DynamicLiterals, str_lit("dynamic-literals"), BuildFlagParam_None, Command__does_check);
add_flag(&build_flags, BuildFlag_NoCRT, str_lit("no-crt"), BuildFlagParam_None, Command__does_build);
add_flag(&build_flags, BuildFlag_NoRPath, str_lit("no-rpath"), BuildFlagParam_None, Command__does_build);
add_flag(&build_flags, BuildFlag_NoEntryPoint, str_lit("no-entry-point"), BuildFlagParam_None, Command__does_check &~ Command_test);
@@ -545,6 +550,7 @@ gb_internal bool parse_build_flags(Array<String> args) {
add_flag(&build_flags, BuildFlag_UseRADLink, str_lit("radlink"), BuildFlagParam_None, Command__does_build);
add_flag(&build_flags, BuildFlag_Linker, str_lit("linker"), BuildFlagParam_String, Command__does_build);
add_flag(&build_flags, BuildFlag_UseSeparateModules, str_lit("use-separate-modules"), BuildFlagParam_None, Command__does_build);
+ add_flag(&build_flags, BuildFlag_UseSingleModule, str_lit("use-single-module"), BuildFlagParam_None, Command__does_build);
add_flag(&build_flags, BuildFlag_NoThreadedChecker, str_lit("no-threaded-checker"), BuildFlagParam_None, Command__does_check);
add_flag(&build_flags, BuildFlag_ShowDebugMessages, str_lit("show-debug-messages"), BuildFlagParam_None, Command_all);
@@ -572,7 +578,7 @@ gb_internal bool parse_build_flags(Array<String> args) {
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_StrictTargetFeatures, str_lit("strict-target-features"), BuildFlagParam_None, Command__does_build);
- add_flag(&build_flags, BuildFlag_MinimumOSVersion, str_lit("minimum-os-version"), BuildFlagParam_String, Command__does_build);
+ add_flag(&build_flags, BuildFlag_MinimumOSVersion, str_lit("minimum-os-version"), BuildFlagParam_String, Command__does_build | Command_bundle_android);
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);
@@ -589,9 +595,10 @@ gb_internal bool parse_build_flags(Array<String> args) {
add_flag(&build_flags, BuildFlag_DynamicMapCalls, str_lit("dynamic-map-calls"), BuildFlagParam_None, Command__does_check);
add_flag(&build_flags, BuildFlag_ObfuscateSourceCodeLocations, str_lit("obfuscate-source-code-locations"), BuildFlagParam_None, Command__does_build);
+ add_flag(&build_flags, BuildFlag_SourceCodeLocations, str_lit("source-code-locations"), BuildFlagParam_String, Command__does_build);
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 | Command_test);
+ add_flag(&build_flags, BuildFlag_AllPackages, str_lit("all-packages"), BuildFlagParam_None, Command_doc | Command_test | Command_build);
add_flag(&build_flags, BuildFlag_DocFormat, str_lit("doc-format"), BuildFlagParam_None, Command_doc);
add_flag(&build_flags, BuildFlag_IgnoreWarnings, str_lit("ignore-warnings"), BuildFlagParam_None, Command_all);
@@ -629,9 +636,20 @@ gb_internal bool parse_build_flags(Array<String> args) {
add_flag(&build_flags, BuildFlag_Subsystem, str_lit("subsystem"), BuildFlagParam_String, Command__does_build);
#endif
+ add_flag(&build_flags, BuildFlag_AndroidKeystore, str_lit("android-keystore"), BuildFlagParam_String, Command_bundle_android);
+ add_flag(&build_flags, BuildFlag_AndroidKeystoreAlias, str_lit("android-keystore-alias"), BuildFlagParam_String, Command_bundle_android);
+ add_flag(&build_flags, BuildFlag_AndroidKeystorePassword, str_lit("android-keystore-password"), BuildFlagParam_String, Command_bundle_android);
+
- GB_ASSERT(args.count >= 3);
- Array<String> flag_args = array_slice(args, 3, args.count);
+ Array<String> flag_args = {};
+
+ if (build_context.command_kind == Command_bundle_android) {
+ GB_ASSERT(args.count >= 4);
+ flag_args = array_slice(args, 4, args.count);
+ } else {
+ GB_ASSERT(args.count >= 3);
+ flag_args = array_slice(args, 3, args.count);
+ }
bool set_flags[BuildFlag_COUNT] = {};
@@ -1110,8 +1128,9 @@ gb_internal bool parse_build_flags(Array<String> args) {
String str = value.value_string;
bool found = false;
- if (selected_target_metrics->metrics->os != TargetOs_darwin) {
- gb_printf_err("-subtarget can only be used with darwin based targets at the moment\n");
+ if (selected_target_metrics->metrics->os != TargetOs_darwin &&
+ selected_target_metrics->metrics->os != TargetOs_linux ) {
+ gb_printf_err("-subtarget can only be used with darwin and linux based targets at the moment\n");
bad_flags = true;
break;
}
@@ -1178,6 +1197,9 @@ gb_internal bool parse_build_flags(Array<String> args) {
break;
}
+ case BuildFlag_KeepExecutable:
+ build_context.keep_executable = true;
+ break;
case BuildFlag_Debug:
build_context.ODIN_DEBUG = true;
@@ -1194,6 +1216,9 @@ gb_internal bool parse_build_flags(Array<String> args) {
case BuildFlag_NoDynamicLiterals:
gb_printf_err("Warning: Use of -no-dynamic-literals is now redundant\n");
break;
+ case BuildFlag_DynamicLiterals:
+ build_context.dynamic_literals = true;
+ break;
case BuildFlag_NoCRT:
build_context.no_crt = true;
break;
@@ -1240,8 +1265,19 @@ gb_internal bool parse_build_flags(Array<String> args) {
case BuildFlag_UseSeparateModules:
+ if (build_context.use_single_module) {
+ gb_printf_err("-use-separate-modules cannot be used with -use-single-module\n");
+ bad_flags = true;
+ }
build_context.use_separate_modules = true;
break;
+ case BuildFlag_UseSingleModule:
+ if (build_context.use_separate_modules) {
+ gb_printf_err("-use-single-module cannot be used with -use-separate-modules\n");
+ bad_flags = true;
+ }
+ build_context.use_single_module = true;
+ break;
case BuildFlag_NoThreadedChecker:
build_context.no_threaded_checker = true;
break;
@@ -1388,7 +1424,23 @@ gb_internal bool parse_build_flags(Array<String> args) {
break;
case BuildFlag_ObfuscateSourceCodeLocations:
- build_context.obfuscate_source_code_locations = true;
+ gb_printf_err("'-obfuscate-source-code-locations' is now deprecated in favor of '-source-code-locations:obfuscated'\n");
+ build_context.source_code_location_info = SourceCodeLocationInfo_Obfuscated;
+ break;
+
+ case BuildFlag_SourceCodeLocations:
+ if (str_eq_ignore_case(value.value_string, str_lit("normal"))) {
+ build_context.source_code_location_info = SourceCodeLocationInfo_Normal;
+ } else if (str_eq_ignore_case(value.value_string, str_lit("obfuscated"))) {
+ build_context.source_code_location_info = SourceCodeLocationInfo_Obfuscated;
+ } else if (str_eq_ignore_case(value.value_string, str_lit("filename"))) {
+ build_context.source_code_location_info = SourceCodeLocationInfo_Filename;
+ } else if (str_eq_ignore_case(value.value_string, str_lit("none"))) {
+ build_context.source_code_location_info = SourceCodeLocationInfo_None;
+ } else {
+ gb_printf_err("-source-code-locations:<string> options are 'normal', 'obfuscated', 'filename', and 'none'\n");
+ bad_flags = true;
+ }
break;
case BuildFlag_DefaultToNilAllocator:
@@ -1521,6 +1573,11 @@ gb_internal bool parse_build_flags(Array<String> args) {
case BuildFlag_Sanitize:
GB_ASSERT(value.kind == ExactValue_String);
+ if (build_context.sanitizer_flags != 0) {
+ gb_printf_err("-sanitize:<string> may only be used once\n");
+ bad_flags = true;
+ }
+
if (str_eq_ignore_case(value.value_string, str_lit("address"))) {
build_context.sanitizer_flags |= SanitizerFlag_Address;
} else if (str_eq_ignore_case(value.value_string, str_lit("memory"))) {
@@ -1593,9 +1650,9 @@ gb_internal bool parse_build_flags(Array<String> args) {
GB_ASSERT(value.kind == ExactValue_String);
String subsystem = value.value_string;
bool subsystem_found = false;
- for (int i = 0; i < Windows_Subsystem_COUNT; i++) {
+ for (int i = 1; i < Windows_Subsystem_COUNT; i++) {
if (str_eq_ignore_case(subsystem, windows_subsystem_names[i])) {
- build_context.ODIN_WINDOWS_SUBSYSTEM = windows_subsystem_names[i];
+ build_context.ODIN_WINDOWS_SUBSYSTEM = Windows_Subsystem(i);
subsystem_found = true;
break;
}
@@ -1604,7 +1661,7 @@ gb_internal bool parse_build_flags(Array<String> args) {
// WINDOW is a hidden alias for WINDOWS. Check it.
String subsystem_windows_alias = str_lit("WINDOW");
if (!subsystem_found && str_eq_ignore_case(subsystem, subsystem_windows_alias)) {
- build_context.ODIN_WINDOWS_SUBSYSTEM = windows_subsystem_names[Windows_Subsystem_WINDOWS];
+ build_context.ODIN_WINDOWS_SUBSYSTEM = Windows_Subsystem_WINDOWS;
subsystem_found = true;
break;
}
@@ -1612,8 +1669,8 @@ gb_internal bool parse_build_flags(Array<String> args) {
if (!subsystem_found) {
gb_printf_err("Invalid -subsystem string, got %.*s. Expected one of:\n", LIT(subsystem));
gb_printf_err("\t");
- for (int i = 0; i < Windows_Subsystem_COUNT; i++) {
- if (i > 0) {
+ for (int i = 1; i < Windows_Subsystem_COUNT; i++) {
+ if (i > 1) {
gb_printf_err(", ");
}
gb_printf_err("%.*s", LIT(windows_subsystem_names[i]));
@@ -1631,6 +1688,20 @@ gb_internal bool parse_build_flags(Array<String> args) {
}
#endif
+ case BuildFlag_AndroidKeystore:
+ GB_ASSERT(value.kind == ExactValue_String);
+ build_context.android_keystore = value.value_string;
+ break;
+
+ case BuildFlag_AndroidKeystoreAlias:
+ GB_ASSERT(value.kind == ExactValue_String);
+ build_context.android_keystore_alias = value.value_string;
+ break;
+
+ case BuildFlag_AndroidKeystorePassword:
+ GB_ASSERT(value.kind == ExactValue_String);
+ build_context.android_keystore_password = value.value_string;
+ break;
}
}
@@ -1646,8 +1717,8 @@ gb_internal bool parse_build_flags(Array<String> args) {
gb_printf_err("'%.*s' is supported with the following commands:\n", LIT(name));
gb_printf_err("\t");
i32 count = 0;
- for (u32 i = 0; i < 32; i++) {
- if (found_bf.command_support & (1<<i)) {
+ for (u64 i = 0; i < 64; i++) {
+ if (found_bf.command_support & (1ull<<i)) {
if (count > 0) {
gb_printf_err(", ");
}
@@ -1685,6 +1756,12 @@ gb_internal bool parse_build_flags(Array<String> args) {
bad_flags = true;
}
+
+ if ((build_context.command_kind & (Command_doc | Command_test)) == 0 && build_context.test_all_packages) {
+ gb_printf_err("`-test-all-packages` can only be used with `odin build -build-mode:test`, `odin test`, or `odin doc`.\n");
+ bad_flags = true;
+ }
+
return !bad_flags;
}
@@ -1801,7 +1878,10 @@ gb_internal void check_defines(BuildContext *bc, Checker *c) {
if (!found) {
ERROR_BLOCK();
warning(nullptr, "given -define:%.*s is unused in the project", LIT(name));
- error_line("\tSuggestion: use the -show-defineables flag for an overview of the possible defines\n");
+
+ if (!global_ignore_warnings()) {
+ error_line("\tSuggestion: use the -show-defineables flag for an overview of the possible defines\n");
+ }
}
}
}
@@ -1934,39 +2014,39 @@ gb_internal void show_timings(Checker *c, Timings *t) {
if (build_context.show_debug_messages && build_context.show_more_timings) {
{
- gb_printf("\n");
- gb_printf("Total Lines - %td\n", lines);
- gb_printf("Total Tokens - %td\n", tokens);
- gb_printf("Total Files - %td\n", files);
- gb_printf("Total Packages - %td\n", packages);
- gb_printf("Total File Size - %td\n", total_file_size);
- gb_printf("\n");
+ gb_printf_err("\n");
+ gb_printf_err("Total Lines - %td\n", lines);
+ gb_printf_err("Total Tokens - %td\n", tokens);
+ gb_printf_err("Total Files - %td\n", files);
+ gb_printf_err("Total Packages - %td\n", packages);
+ gb_printf_err("Total File Size - %td\n", total_file_size);
+ gb_printf_err("\n");
}
{
f64 time = total_tokenizing_time;
- gb_printf("Tokenization Only\n");
- gb_printf("LOC/s - %.3f\n", cast(f64)lines/time);
- gb_printf("us/LOC - %.3f\n", 1.0e6*time/cast(f64)lines);
- gb_printf("Tokens/s - %.3f\n", cast(f64)tokens/time);
- gb_printf("us/Token - %.3f\n", 1.0e6*time/cast(f64)tokens);
- gb_printf("bytes/s - %.3f\n", cast(f64)total_file_size/time);
- gb_printf("MiB/s - %.3f\n", cast(f64)(total_file_size/time)/(1024*1024));
- gb_printf("us/bytes - %.3f\n", 1.0e6*time/cast(f64)total_file_size);
+ gb_printf_err("Tokenization Only\n");
+ gb_printf_err("LOC/s - %.3f\n", cast(f64)lines/time);
+ gb_printf_err("us/LOC - %.3f\n", 1.0e6*time/cast(f64)lines);
+ gb_printf_err("Tokens/s - %.3f\n", cast(f64)tokens/time);
+ gb_printf_err("us/Token - %.3f\n", 1.0e6*time/cast(f64)tokens);
+ gb_printf_err("bytes/s - %.3f\n", cast(f64)total_file_size/time);
+ gb_printf_err("MiB/s - %.3f\n", cast(f64)(total_file_size/time)/(1024*1024));
+ gb_printf_err("us/bytes - %.3f\n", 1.0e6*time/cast(f64)total_file_size);
- gb_printf("\n");
+ gb_printf_err("\n");
}
{
f64 time = total_parsing_time;
- gb_printf("Parsing Only\n");
- gb_printf("LOC/s - %.3f\n", cast(f64)lines/time);
- gb_printf("us/LOC - %.3f\n", 1.0e6*time/cast(f64)lines);
- gb_printf("Tokens/s - %.3f\n", cast(f64)tokens/time);
- gb_printf("us/Token - %.3f\n", 1.0e6*time/cast(f64)tokens);
- gb_printf("bytes/s - %.3f\n", cast(f64)total_file_size/time);
- gb_printf("MiB/s - %.3f\n", cast(f64)(total_file_size/time)/(1024*1024));
- gb_printf("us/bytes - %.3f\n", 1.0e6*time/cast(f64)total_file_size);
+ gb_printf_err("Parsing Only\n");
+ gb_printf_err("LOC/s - %.3f\n", cast(f64)lines/time);
+ gb_printf_err("us/LOC - %.3f\n", 1.0e6*time/cast(f64)lines);
+ gb_printf_err("Tokens/s - %.3f\n", cast(f64)tokens/time);
+ gb_printf_err("us/Token - %.3f\n", 1.0e6*time/cast(f64)tokens);
+ gb_printf_err("bytes/s - %.3f\n", cast(f64)total_file_size/time);
+ gb_printf_err("MiB/s - %.3f\n", cast(f64)(total_file_size/time)/(1024*1024));
+ gb_printf_err("us/bytes - %.3f\n", 1.0e6*time/cast(f64)total_file_size);
- gb_printf("\n");
+ gb_printf_err("\n");
}
{
TimeStamp ts = {};
@@ -1979,16 +2059,16 @@ gb_internal void show_timings(Checker *c, Timings *t) {
GB_ASSERT(ts.label == "parse files");
f64 parse_time = time_stamp_as_s(ts, t->freq);
- gb_printf("Parse pass\n");
- gb_printf("LOC/s - %.3f\n", cast(f64)lines/parse_time);
- gb_printf("us/LOC - %.3f\n", 1.0e6*parse_time/cast(f64)lines);
- gb_printf("Tokens/s - %.3f\n", cast(f64)tokens/parse_time);
- gb_printf("us/Token - %.3f\n", 1.0e6*parse_time/cast(f64)tokens);
- gb_printf("bytes/s - %.3f\n", cast(f64)total_file_size/parse_time);
- gb_printf("MiB/s - %.3f\n", cast(f64)(total_file_size/parse_time)/(1024*1024));
- gb_printf("us/bytes - %.3f\n", 1.0e6*parse_time/cast(f64)total_file_size);
+ gb_printf_err("Parse pass\n");
+ gb_printf_err("LOC/s - %.3f\n", cast(f64)lines/parse_time);
+ gb_printf_err("us/LOC - %.3f\n", 1.0e6*parse_time/cast(f64)lines);
+ gb_printf_err("Tokens/s - %.3f\n", cast(f64)tokens/parse_time);
+ gb_printf_err("us/Token - %.3f\n", 1.0e6*parse_time/cast(f64)tokens);
+ gb_printf_err("bytes/s - %.3f\n", cast(f64)total_file_size/parse_time);
+ gb_printf_err("MiB/s - %.3f\n", cast(f64)(total_file_size/parse_time)/(1024*1024));
+ gb_printf_err("us/bytes - %.3f\n", 1.0e6*parse_time/cast(f64)total_file_size);
- gb_printf("\n");
+ gb_printf_err("\n");
}
{
TimeStamp ts = {};
@@ -2009,27 +2089,27 @@ gb_internal void show_timings(Checker *c, Timings *t) {
ts.finish = ts_end.finish;
f64 parse_time = time_stamp_as_s(ts, t->freq);
- gb_printf("Checker pass\n");
- gb_printf("LOC/s - %.3f\n", cast(f64)lines/parse_time);
- gb_printf("us/LOC - %.3f\n", 1.0e6*parse_time/cast(f64)lines);
- gb_printf("Tokens/s - %.3f\n", cast(f64)tokens/parse_time);
- gb_printf("us/Token - %.3f\n", 1.0e6*parse_time/cast(f64)tokens);
- gb_printf("bytes/s - %.3f\n", cast(f64)total_file_size/parse_time);
- gb_printf("MiB/s - %.3f\n", (cast(f64)total_file_size/parse_time)/(1024*1024));
- gb_printf("us/bytes - %.3f\n", 1.0e6*parse_time/cast(f64)total_file_size);
- gb_printf("\n");
+ gb_printf_err("Checker pass\n");
+ gb_printf_err("LOC/s - %.3f\n", cast(f64)lines/parse_time);
+ gb_printf_err("us/LOC - %.3f\n", 1.0e6*parse_time/cast(f64)lines);
+ gb_printf_err("Tokens/s - %.3f\n", cast(f64)tokens/parse_time);
+ gb_printf_err("us/Token - %.3f\n", 1.0e6*parse_time/cast(f64)tokens);
+ gb_printf_err("bytes/s - %.3f\n", cast(f64)total_file_size/parse_time);
+ gb_printf_err("MiB/s - %.3f\n", (cast(f64)total_file_size/parse_time)/(1024*1024));
+ gb_printf_err("us/bytes - %.3f\n", 1.0e6*parse_time/cast(f64)total_file_size);
+ gb_printf_err("\n");
}
{
f64 total_time = t->total_time_seconds;
- gb_printf("Total pass\n");
- gb_printf("LOC/s - %.3f\n", cast(f64)lines/total_time);
- gb_printf("us/LOC - %.3f\n", 1.0e6*total_time/cast(f64)lines);
- gb_printf("Tokens/s - %.3f\n", cast(f64)tokens/total_time);
- gb_printf("us/Token - %.3f\n", 1.0e6*total_time/cast(f64)tokens);
- gb_printf("bytes/s - %.3f\n", cast(f64)total_file_size/total_time);
- gb_printf("MiB/s - %.3f\n", cast(f64)(total_file_size/total_time)/(1024*1024));
- gb_printf("us/bytes - %.3f\n", 1.0e6*total_time/cast(f64)total_file_size);
- gb_printf("\n");
+ gb_printf_err("Total pass\n");
+ gb_printf_err("LOC/s - %.3f\n", cast(f64)lines/total_time);
+ gb_printf_err("us/LOC - %.3f\n", 1.0e6*total_time/cast(f64)lines);
+ gb_printf_err("Tokens/s - %.3f\n", cast(f64)tokens/total_time);
+ gb_printf_err("us/Token - %.3f\n", 1.0e6*total_time/cast(f64)tokens);
+ gb_printf_err("bytes/s - %.3f\n", cast(f64)total_file_size/total_time);
+ gb_printf_err("MiB/s - %.3f\n", cast(f64)(total_file_size/total_time)/(1024*1024));
+ gb_printf_err("us/bytes - %.3f\n", 1.0e6*total_time/cast(f64)total_file_size);
+ gb_printf_err("\n");
}
}
}
@@ -2160,7 +2240,7 @@ gb_internal void remove_temp_files(lbGenerator *gen) {
return;
}
- TIME_SECTION("remove keep temp files");
+ TIME_SECTION("remove temp files");
for (String const &path : gen->output_temp_paths) {
gb_file_remove(cast(char const *)path.text);
@@ -2180,20 +2260,30 @@ gb_internal void remove_temp_files(lbGenerator *gen) {
}
-gb_internal void print_show_help(String const arg0, String command, String optional_flag = {}) {
+gb_internal int print_show_help(String const arg0, String command, String optional_flag = {}) {
+ bool help_resolved = false;
+ bool printed_usage_header = false;
+ bool printed_flags_header = false;
+
if (command == "help" && optional_flag.len != 0 && optional_flag[0] != '-') {
command = optional_flag;
optional_flag = {};
}
- print_usage_line(0, "%.*s is a tool for managing Odin source code.", LIT(arg0));
- print_usage_line(0, "Usage:");
- print_usage_line(1, "%.*s %.*s [arguments]", LIT(arg0), LIT(command));
- print_usage_line(0, "");
- defer (print_usage_line(0, ""));
-
+ auto const print_usage_header_once = [&help_resolved, &printed_usage_header, arg0, command]() {
+ if (printed_usage_header) {
+ return;
+ }
+ print_usage_line(0, "%.*s is a tool for managing Odin source code.", LIT(arg0));
+ print_usage_line(0, "Usage:");
+ print_usage_line(1, "%.*s %.*s [arguments]", LIT(arg0), LIT(command));
+ print_usage_line(0, "");
+ help_resolved = true;
+ printed_usage_header = true;
+ };
if (command == "build") {
+ print_usage_header_once();
print_usage_line(1, "build Compiles directory of .odin files as an executable.");
print_usage_line(2, "One must contain the program's entry point, all must be in the same package.");
print_usage_line(2, "Use `-file` to build a single file instead.");
@@ -2202,6 +2292,7 @@ gb_internal void print_show_help(String const arg0, String command, String optio
print_usage_line(3, "odin build <dir> Builds package in <dir>.");
print_usage_line(3, "odin build filename.odin -file Builds single-file package, must contain entry point.");
} else if (command == "run") {
+ print_usage_header_once();
print_usage_line(1, "run Same as 'build', but also then runs the newly compiled executable.");
print_usage_line(2, "Append an empty flag and then the args, '-- <args>', to specify args for the output.");
print_usage_line(2, "Examples:");
@@ -2209,24 +2300,40 @@ gb_internal void print_show_help(String const arg0, String command, String optio
print_usage_line(3, "odin run <dir> Builds and runs package in <dir>.");
print_usage_line(3, "odin run filename.odin -file Builds and runs single-file package, must contain entry point.");
} else if (command == "check") {
+ print_usage_header_once();
print_usage_line(1, "check Parses and type checks directory of .odin files.");
print_usage_line(2, "Examples:");
print_usage_line(3, "odin check . Type checks package in current directory.");
print_usage_line(3, "odin check <dir> Type checks package in <dir>.");
print_usage_line(3, "odin check filename.odin -file Type checks single-file package, must contain entry point.");
} else if (command == "test") {
+ print_usage_header_once();
print_usage_line(1, "test Builds and runs procedures with the attribute @(test) in the initial package.");
} else if (command == "doc") {
+ print_usage_header_once();
print_usage_line(1, "doc Generates documentation from a directory of .odin files.");
print_usage_line(2, "Examples:");
print_usage_line(3, "odin doc . Generates documentation on package in current directory.");
print_usage_line(3, "odin doc <dir> Generates documentation on package in <dir>.");
print_usage_line(3, "odin doc filename.odin -file Generates documentation on single-file package.");
} else if (command == "version") {
+ print_usage_header_once();
print_usage_line(1, "version Prints version.");
} else if (command == "strip-semicolon") {
+ print_usage_header_once();
print_usage_line(1, "strip-semicolon");
print_usage_line(2, "Parses and type checks .odin file(s) and then removes unneeded semicolons from the entire project.");
+ } else if (command == "bundle") {
+ print_usage_header_once();
+ print_usage_line(1, "bundle <platform> Bundles a directory in a specific layout for that platform");
+ print_usage_line(2, "Supported platforms:");
+ print_usage_line(3, "android");
+ } else if (command == "report") {
+ print_usage_header_once();
+ print_usage_line(1, "report Prints information useful to reporting a bug.");
+ } else if (command == "root") {
+ print_usage_header_once();
+ print_usage_line(1, "root Prints the root path where Odin looks for the builtin collections.");
}
bool doc = command == "doc";
@@ -2236,6 +2343,7 @@ gb_internal void print_show_help(String const arg0, String command, String optio
bool strip_semicolon = command == "strip-semicolon";
bool check_only = command == "check" || strip_semicolon;
bool check = run_or_build || check_only;
+ bool bundle = command == "bundle";
if (command == "help") {
doc = true;
@@ -2247,13 +2355,10 @@ gb_internal void print_show_help(String const arg0, String command, String optio
check = true;
}
- print_usage_line(0, "");
- print_usage_line(1, "Flags");
- print_usage_line(0, "");
- auto const print_flag = [&optional_flag](char const *flag) -> bool {
+ auto const print_flag = [&optional_flag, &help_resolved, &printed_flags_header, print_usage_header_once](char const *flag) -> bool {
if (optional_flag.len != 0) {
String f = make_string_c(flag);
isize i = string_index_byte(f, ':');
@@ -2264,6 +2369,14 @@ gb_internal void print_show_help(String const arg0, String command, String optio
return false;
}
}
+ print_usage_header_once();
+ if (!printed_flags_header) {
+ print_usage_line(0, "");
+ print_usage_line(1, "Flags");
+ print_usage_line(0, "");
+ printed_flags_header = true;
+ }
+ help_resolved = true;
print_usage_line(0, "");
print_usage_line(1, flag);
return true;
@@ -2285,20 +2398,26 @@ gb_internal void print_show_help(String const arg0, String command, String optio
if (print_flag("-build-mode:<mode>")) {
print_usage_line(2, "Sets the build mode.");
print_usage_line(2, "Available options:");
- print_usage_line(3, "-build-mode:exe Builds as an executable.");
- print_usage_line(3, "-build-mode:test Builds as an executable that executes tests.");
- print_usage_line(3, "-build-mode:dll Builds as a dynamically linked library.");
- print_usage_line(3, "-build-mode:shared Builds as a dynamically linked library.");
- print_usage_line(3, "-build-mode:dynamic Builds as a dynamically linked library.");
- print_usage_line(3, "-build-mode:lib Builds as a statically linked library.");
- print_usage_line(3, "-build-mode:static Builds as a statically linked library.");
- print_usage_line(3, "-build-mode:obj Builds as an object file.");
- print_usage_line(3, "-build-mode:object Builds as an object file.");
- print_usage_line(3, "-build-mode:assembly Builds as an assembly file.");
- print_usage_line(3, "-build-mode:assembler Builds as an assembly file.");
- print_usage_line(3, "-build-mode:asm Builds as an assembly file.");
- print_usage_line(3, "-build-mode:llvm-ir Builds as an LLVM IR file.");
- print_usage_line(3, "-build-mode:llvm Builds as an LLVM IR file.");
+ print_usage_line(3, "-build-mode:exe Builds as an executable.");
+ print_usage_line(3, "-build-mode:test Builds as an executable that executes tests.");
+ print_usage_line(3, "-build-mode:dll Builds as a dynamically linked library.");
+ print_usage_line(3, "-build-mode:shared Builds as a dynamically linked library.");
+ print_usage_line(3, "-build-mode:dynamic Builds as a dynamically linked library.");
+ print_usage_line(3, "-build-mode:lib Builds as a statically linked library.");
+ print_usage_line(3, "-build-mode:static Builds as a statically linked library.");
+ print_usage_line(3, "-build-mode:obj Builds as an object file.");
+ print_usage_line(3, "-build-mode:object Builds as an object file.");
+ print_usage_line(3, "-build-mode:assembly Builds as an assembly file.");
+ print_usage_line(3, "-build-mode:assembler Builds as an assembly file.");
+ print_usage_line(3, "-build-mode:asm Builds as an assembly file.");
+ print_usage_line(3, "-build-mode:llvm-ir Builds as an LLVM IR file.");
+ print_usage_line(3, "-build-mode:llvm Builds as an LLVM IR file.");
+ }
+ }
+
+ if (test_only) {
+ if (print_flag("-build-only")) {
+ print_usage_line(2, "Only builds the test executable; does not automatically run it afterwards.");
}
}
@@ -2307,16 +2426,16 @@ gb_internal void print_show_help(String const arg0, String command, String optio
print_usage_line(2, "Defines a library collection used for imports.");
print_usage_line(2, "Example: -collection:shared=dir/to/shared");
print_usage_line(2, "Usage in Code:");
- print_usage_line(3, "import \"shared:foo\"");
+ print_usage_line(3, "import \"shared:foo\"");
}
if (print_flag("-custom-attribute:<string>")) {
print_usage_line(2, "Add a custom attribute which will be ignored if it is unknown.");
print_usage_line(2, "This can be used with metaprogramming tools.");
print_usage_line(2, "Examples:");
- print_usage_line(3, "-custom-attribute:my_tag");
- print_usage_line(3, "-custom-attribute:my_tag,the_other_thing");
- print_usage_line(3, "-custom-attribute:my_tag -custom-attribute:the_other_thing");
+ print_usage_line(3, "-custom-attribute:my_tag");
+ print_usage_line(3, "-custom-attribute:my_tag,the_other_thing");
+ print_usage_line(3, "-custom-attribute:my_tag -custom-attribute:the_other_thing");
}
}
@@ -2331,11 +2450,15 @@ gb_internal void print_show_help(String const arg0, String command, String optio
print_usage_line(2, "Sets the default allocator to be the nil_allocator, an allocator which does nothing.");
}
+ if (print_flag("-default-to-panic-allocator")) {
+ print_usage_line(2, "Sets the default allocator to be the panic_allocator, an allocator which calls panic() on any allocation attempt.");
+ }
+
if (print_flag("-define:<name>=<value>")) {
print_usage_line(2, "Defines a scalar boolean, integer or string as global constant.");
print_usage_line(2, "Example: -define:SPAM=123");
print_usage_line(2, "Usage in code:");
- print_usage_line(3, "#config(SPAM, default_value)");
+ print_usage_line(3, "#config(SPAM, default_value)");
}
}
@@ -2370,9 +2493,9 @@ gb_internal void print_show_help(String const arg0, String command, String optio
if (check) {
if (print_flag("-error-pos-style:<string>")) {
print_usage_line(2, "Available options:");
- print_usage_line(3, "-error-pos-style:unix file/path:45:3:");
- print_usage_line(3, "-error-pos-style:odin file/path(45:3)");
- print_usage_line(3, "-error-pos-style:default (Defaults to 'odin'.)");
+ print_usage_line(3, "-error-pos-style:unix file/path:45:3:");
+ print_usage_line(3, "-error-pos-style:odin file/path(45:3)");
+ print_usage_line(3, "-error-pos-style:default (Defaults to 'odin'.)");
}
if (print_flag("-export-defineables:<filename>")) {
@@ -2383,8 +2506,8 @@ gb_internal void print_show_help(String const arg0, String command, String optio
if (print_flag("-export-dependencies:<format>")) {
print_usage_line(2, "Exports dependencies to one of a few formats. Requires `-export-dependencies-file`.");
print_usage_line(2, "Available options:");
- print_usage_line(3, "-export-dependencies:make Exports in Makefile format");
- print_usage_line(3, "-export-dependencies:json Exports in JSON format");
+ print_usage_line(3, "-export-dependencies:make Exports in Makefile format");
+ print_usage_line(3, "-export-dependencies:json Exports in JSON format");
}
if (print_flag("-export-dependencies-file:<filename>")) {
@@ -2395,8 +2518,8 @@ gb_internal void print_show_help(String const arg0, String command, String optio
if (print_flag("-export-timings:<format>")) {
print_usage_line(2, "Exports timings to one of a few formats. Requires `-show-timings` or `-show-more-timings`.");
print_usage_line(2, "Available options:");
- print_usage_line(3, "-export-timings:json Exports compile time stats to JSON.");
- print_usage_line(3, "-export-timings:csv Exports compile time stats to CSV.");
+ print_usage_line(3, "-export-timings:json Exports compile time stats to JSON.");
+ print_usage_line(3, "-export-timings:csv Exports compile time stats to CSV.");
}
if (print_flag("-export-timings-file:<filename>")) {
@@ -2460,6 +2583,14 @@ gb_internal void print_show_help(String const arg0, String command, String optio
}
}
+ if (test_only || run_or_build) {
+ if (print_flag("-keep-executable")) {
+ print_usage_line(2, "Keep the executable generated by `odin test` or `odin run` after running it. We clean it up by default.");
+ print_usage_line(2, "If you build your program or test using `odin build`, the compiler does not automatically execute");
+ print_usage_line(2, "the resulting program, and this option is not applicable.");
+ }
+ }
+
if (run_or_build) {
if (print_flag("-linker:<string>")) {
print_usage_line(2, "Specify the linker to use.");
@@ -2486,9 +2617,9 @@ gb_internal void print_show_help(String const arg0, String command, String optio
if (print_flag("-microarch:<string>")) {
print_usage_line(2, "Specifies the specific micro-architecture for the build in a string.");
print_usage_line(2, "Examples:");
- print_usage_line(3, "-microarch:sandybridge");
- print_usage_line(3, "-microarch:native");
- print_usage_line(3, "-microarch:\"?\" for a list");
+ print_usage_line(3, "-microarch:sandybridge");
+ print_usage_line(3, "-microarch:native");
+ print_usage_line(3, "-microarch:\"?\" for a list");
}
}
@@ -2499,13 +2630,15 @@ gb_internal void print_show_help(String const arg0, String command, String optio
}
}
- if (run_or_build) {
+ if (run_or_build || bundle) {
if (print_flag("-minimum-os-version:<string>")) {
print_usage_line(2, "Sets the minimum OS version targeted by the application.");
print_usage_line(2, "Default: -minimum-os-version:11.0.0");
- print_usage_line(2, "Only used when target is Darwin, if given, linking mismatched versions will emit a warning.");
+ print_usage_line(2, "Only used when target is Darwin or subtarget is Android, if given, linking mismatched versions will emit a warning.");
}
+ }
+ if (run_or_build) {
if (print_flag("-no-bounds-check")) {
print_usage_line(2, "Disables bounds checking program wide.");
}
@@ -2543,10 +2676,10 @@ gb_internal void print_show_help(String const arg0, String command, String optio
if (print_flag("-o:<string>")) {
print_usage_line(2, "Sets the optimization mode for compilation.");
print_usage_line(2, "Available options:");
- print_usage_line(3, "-o:none");
- print_usage_line(3, "-o:minimal");
- print_usage_line(3, "-o:size");
- print_usage_line(3, "-o:speed");
+ print_usage_line(3, "-o:none");
+ print_usage_line(3, "-o:minimal");
+ print_usage_line(3, "-o:size");
+ print_usage_line(3, "-o:speed");
if (LB_USE_NEW_PASS_SYSTEM) {
print_usage_line(3, "-o:aggressive (use this with caution)");
}
@@ -2554,8 +2687,14 @@ gb_internal void print_show_help(String const arg0, String command, String optio
}
- if (print_flag("-obfuscate-source-code-locations")) {
- print_usage_line(2, "Obfuscate the file and procedure strings, and line and column numbers, stored with a 'runtime.Source_Code_Location' value.");
+ if (print_flag("-source-code-locations:<string>")) {
+ print_usage_line(2, "Processes the file and procedure strings, and line and column numbers, stored with a 'runtime.Source_Code_Location' value.");
+ print_usage_line(2, "Available options:");
+ print_usage_line(3, "-source-code-locations:normal");
+ print_usage_line(3, "-source-code-locations:obfuscated");
+ print_usage_line(3, "-source-code-locations:filename");
+ print_usage_line(3, "-source-code-locations:none");
+ print_usage_line(2, "The default is -source-code-locations:normal.");
}
@@ -2567,7 +2706,7 @@ gb_internal void print_show_help(String const arg0, String command, String optio
if (doc) {
if (print_flag("-out:<filepath>")) {
- print_usage_line(2, "Sets the base name of the resultig .odin-doc file.");
+ print_usage_line(2, "Sets the base name of the resulting .odin-doc file.");
print_usage_line(2, "The extension can be optionally included; the resulting file will always have an extension of '.odin-doc'.");
print_usage_line(2, "Example: -out:foo");
}
@@ -2597,10 +2736,10 @@ gb_internal void print_show_help(String const arg0, String command, String optio
if (print_flag("-reloc-mode:<string>")) {
print_usage_line(2, "Specifies the reloc mode.");
print_usage_line(2, "Available options:");
- print_usage_line(3, "-reloc-mode:default");
- print_usage_line(3, "-reloc-mode:static");
- print_usage_line(3, "-reloc-mode:pic");
- print_usage_line(3, "-reloc-mode:dynamic-no-pic");
+ print_usage_line(3, "-reloc-mode:default");
+ print_usage_line(3, "-reloc-mode:static");
+ print_usage_line(3, "-reloc-mode:pic");
+ print_usage_line(3, "-reloc-mode:dynamic-no-pic");
}
#if defined(GB_SYSTEM_WINDOWS)
@@ -2615,10 +2754,9 @@ gb_internal void print_show_help(String const arg0, String command, String optio
if (print_flag("-sanitize:<string>")) {
print_usage_line(2, "Enables sanitization analysis.");
print_usage_line(2, "Available options:");
- print_usage_line(3, "-sanitize:address");
- print_usage_line(3, "-sanitize:memory");
- print_usage_line(3, "-sanitize:thread");
- print_usage_line(2, "NOTE: This flag can be used multiple times.");
+ print_usage_line(3, "-sanitize:address");
+ print_usage_line(3, "-sanitize:memory");
+ print_usage_line(3, "-sanitize:thread");
}
}
@@ -2678,17 +2816,32 @@ gb_internal void print_show_help(String const arg0, String command, String optio
print_usage_line(2, "[Windows only]");
print_usage_line(2, "Defines the subsystem for the application.");
print_usage_line(2, "Available options:");
- print_usage_line(3, "-subsystem:console");
- print_usage_line(3, "-subsystem:windows");
+ print_usage_line(3, "-subsystem:console");
+ print_usage_line(3, "-subsystem:windows");
}
#endif
+ }
+
+ if (build) {
+ if (print_flag("-subtarget:<subtarget>")) {
+ print_usage_line(2, "[Darwin and Linux only]");
+ print_usage_line(2, "Available subtargets:");
+ String prefix = str_lit("-subtarget:");
+ for (u32 i = 1; i < Subtarget_COUNT; i++) {
+ String name = subtarget_strings[i];
+ String help_string = concatenate_strings(temporary_allocator(), prefix, name);
+ print_usage_line(3, (const char *)help_string.text);
+ }
+ }
+ }
+ if (run_or_build) {
if (print_flag("-target-features:<string>")) {
print_usage_line(2, "Specifies CPU features to enable on top of the enabled features implied by -microarch.");
print_usage_line(2, "Examples:");
- print_usage_line(3, "-target-features:atomics");
- print_usage_line(3, "-target-features:\"sse2,aes\"");
- print_usage_line(3, "-target-features:\"?\" for a list");
+ print_usage_line(3, "-target-features:atomics");
+ print_usage_line(3, "-target-features:\"sse2,aes\"");
+ print_usage_line(3, "-target-features:\"?\" for a list");
}
}
@@ -2710,8 +2863,12 @@ gb_internal void print_show_help(String const arg0, String command, String optio
if (run_or_build) {
if (print_flag("-use-separate-modules")) {
print_usage_line(2, "The backend generates multiple build units which are then linked together.");
- print_usage_line(2, "Normally, a single build unit is generated for a standard project.");
- print_usage_line(2, "This is the default behaviour on Windows for '-o:none' and '-o:minimal' builds.");
+ print_usage_line(2, "This is the default behaviour for '-o:none' and '-o:minimal' builds.");
+ print_usage_line(2, "Normally, a single build unit is generated for a standard project for '-o:speed' or '-o:size'.");
+ }
+ if (print_flag("-use-single-module")) {
+ print_usage_line(2, "The backend generates only a single build unit.");
+ print_usage_line(2, "This is the default behaviour for '-o:speed' or '-o:size'.");
}
}
@@ -2721,11 +2878,11 @@ gb_internal void print_show_help(String const arg0, String command, String optio
if (print_flag("-vet")) {
print_usage_line(2, "Does extra checks on the code.");
print_usage_line(2, "Extra checks include:");
- print_usage_line(3, "-vet-unused");
- print_usage_line(3, "-vet-unused-variables");
- print_usage_line(3, "-vet-unused-imports");
- print_usage_line(3, "-vet-shadowing");
- print_usage_line(3, "-vet-using-stmt");
+ print_usage_line(3, "-vet-unused");
+ print_usage_line(3, "-vet-unused-variables");
+ print_usage_line(3, "-vet-unused-imports");
+ print_usage_line(3, "-vet-shadowing");
+ print_usage_line(3, "-vet-using-stmt");
}
if (print_flag("-vet-cast")) {
@@ -2792,6 +2949,40 @@ gb_internal void print_show_help(String const arg0, String command, String optio
print_usage_line(2, "Treats warning messages as error messages.");
}
}
+
+ if (bundle) {
+ print_usage_line(0, "");
+ print_usage_line(1, "Android-specific flags");
+ print_usage_line(0, "");
+ if (print_flag("-android-keystore:<string>")) {
+ print_usage_line(2, "Specifies the keystore file to use to sign the apk.");
+ }
+
+ if (print_flag("-android-keystore-alias:<string>")) {
+ print_usage_line(2, "Specifies the key alias to use when signing the apk");
+ print_usage_line(2, "Can be omitted if the keystore only contains one key");
+ }
+
+ if (print_flag("-android-keystore-password:<string>")) {
+ print_usage_line(2, "Sets the password to use to unlock the keystore");
+ print_usage_line(2, "If this is omitted, the terminal will prompt you to provide it.");
+ }
+ }
+
+ if (!help_resolved) {
+ usage(arg0);
+ print_usage_line(0, "");
+ if (command == "help") {
+ print_usage_line(0, "'%.*s' is not a recognized flag.", LIT(optional_flag));
+ } else {
+ print_usage_line(0, "'%.*s' is not a recognized command.", LIT(command));
+ }
+ return 1;
+ }
+
+ print_usage_line(0, "");
+
+ return 0;
}
gb_internal void print_show_unused(Checker *c) {
@@ -3164,6 +3355,16 @@ int main(int arg_count, char const **arg_ptr) {
String run_args_string = {};
isize last_non_run_arg = args.count;
+ for_array(i, args) {
+ if (args[i] == "--") {
+ break;
+ }
+ if (args[i] == "-help" || args[i] == "--help") {
+ build_context.show_help = true;
+ return print_show_help(args[0], command);
+ }
+ }
+
bool run_output = false;
if (command == "run" || command == "test") {
if (args.count < 3) {
@@ -3257,6 +3458,10 @@ int main(int arg_count, char const **arg_ptr) {
return 1;
#endif
} else if (command == "version") {
+ if (args.count != 2) {
+ usage(args[0]);
+ return 1;
+ }
build_context.command_kind = Command_version;
gb_printf("%.*s version %.*s", LIT(args[0]), LIT(ODIN_VERSION));
@@ -3271,6 +3476,10 @@ int main(int arg_count, char const **arg_ptr) {
gb_printf("\n");
return 0;
} else if (command == "report") {
+ if (args.count != 2) {
+ usage(args[0]);
+ return 1;
+ }
build_context.command_kind = Command_bug_report;
print_bug_report_help();
return 0;
@@ -3279,10 +3488,26 @@ int main(int arg_count, char const **arg_ptr) {
usage(args[0]);
return 1;
} else {
- print_show_help(args[0], args[1], args[2]);
- return 0;
+ return print_show_help(args[0], args[1], args[2]);
}
+ } else if (command == "bundle") {
+ if (args.count < 4) {
+ usage(args[0]);
+ return 1;
+ }
+ if (args[2] == "android") {
+ build_context.command_kind = Command_bundle_android;
+ } else {
+ gb_printf_err("Unknown package command: '%.*s'\n", LIT(args[2]));
+ usage(args[0]);
+ return 1;
+ }
+ init_filename = args[3];
} else if (command == "root") {
+ if (args.count != 2) {
+ usage(args[0]);
+ return 1;
+ }
gb_printf("%.*s", LIT(odin_root_dir()));
return 0;
} else if (command == "clear-cache") {
@@ -3298,11 +3523,6 @@ int main(int arg_count, char const **arg_ptr) {
init_filename = copy_string(permanent_allocator(), init_filename);
- if (init_filename == "-help" ||
- init_filename == "--help") {
- build_context.show_help = true;
- }
-
if (init_filename.len > 0 && !build_context.show_help) {
// The command must be build, run, test, check, or another that takes a directory or filename.
if (!path_is_directory(init_filename)) {
@@ -3316,10 +3536,14 @@ int main(int arg_count, char const **arg_ptr) {
}
if (!single_file_package) {
- gb_printf_err("ERROR: `%.*s %.*s` takes a package as its first argument.\n", LIT(args[0]), LIT(command));
+ gb_printf_err("ERROR: `%.*s %.*s` takes a package/directory as its first argument.\n", LIT(args[0]), LIT(command));
if (init_filename == "-file") {
gb_printf_err("Did you mean `%.*s %.*s <filename.odin> -file`?\n", LIT(args[0]), LIT(command));
} else {
+ if (!gb_file_exists(cast(const char*)init_filename.text)) {
+ gb_printf_err("The file '%.*s' was not found.\n", LIT(init_filename));
+ return 1;
+ }
gb_printf_err("Did you mean `%.*s %.*s %.*s -file`?\n", LIT(args[0]), LIT(command), LIT(init_filename));
}
@@ -3349,8 +3573,11 @@ int main(int arg_count, char const **arg_ptr) {
}
if (build_context.show_help) {
- print_show_help(args[0], command);
- return 0;
+ return print_show_help(args[0], command);
+ }
+
+ if (command == "bundle") {
+ return bundle(init_filename);
}
// NOTE(bill): add 'shared' directory if it is not already set
@@ -3569,10 +3796,15 @@ int main(int arg_count, char const **arg_ptr) {
}
if (build_context.generate_docs) {
+ MAIN_TIME_SECTION("generate documentation");
if (global_error_collector.count != 0) {
return 1;
}
generate_documentation(checker);
+
+ if (build_context.show_timings) {
+ show_timings(checker, &global_timings);
+ }
return 0;
}
@@ -3687,6 +3919,21 @@ end_of_code_gen:;
defer (gb_free(heap_allocator(), exe_name.text));
system_must_exec_command_line_app("odin run", "\"%.*s\" %.*s", LIT(exe_name), LIT(run_args_string));
+
+ if (!build_context.keep_executable) {
+ char const *filename = cast(char const *)exe_name.text;
+ gb_file_remove(filename);
+
+ if (build_context.ODIN_DEBUG) {
+ if (build_context.metrics.os == TargetOs_windows || build_context.metrics.os == TargetOs_darwin) {
+ String symbol_path = path_to_string(heap_allocator(), build_context.build_paths[BuildPath_Symbols]);
+ defer (gb_free(heap_allocator(), symbol_path.text));
+
+ filename = cast(char const *)symbol_path.text;
+ gb_file_remove(filename);
+ }
+ }
+ }
}
return 0;
}
diff --git a/src/name_canonicalization.cpp b/src/name_canonicalization.cpp
new file mode 100644
index 000000000..0372f5039
--- /dev/null
+++ b/src/name_canonicalization.cpp
@@ -0,0 +1,787 @@
+gb_internal bool is_in_doc_writer(void);
+
+gb_internal GB_COMPARE_PROC(type_info_pair_cmp) {
+ TypeInfoPair *x = cast(TypeInfoPair *)a;
+ TypeInfoPair *y = cast(TypeInfoPair *)b;
+ if (x->hash == y->hash) {
+ return 0;
+ }
+ return x->hash < y->hash ? -1 : +1;
+}
+
+
+gb_internal gbAllocator type_set_allocator(void) {
+ return heap_allocator();
+}
+
+gb_internal TypeSetIterator begin(TypeSet &set) noexcept {
+ usize index = 0;
+ while (index < set.capacity) {
+ TypeInfoPair key = set.keys[index];
+ if (key.hash != 0 && key.hash != TYPE_SET_TOMBSTONE) {
+ break;
+ }
+ index++;
+ }
+ return TypeSetIterator{&set, index};
+}
+gb_internal TypeSetIterator end(TypeSet &set) noexcept {
+ return TypeSetIterator{&set, set.capacity};
+}
+
+
+gb_internal void type_set_init(TypeSet *s, isize capacity) {
+ GB_ASSERT(s->keys == nullptr);
+ if (capacity != 0) {
+ capacity = next_pow2_isize(gb_max(16, capacity));
+ s->keys = gb_alloc_array(type_set_allocator(), TypeInfoPair, capacity);
+ // This memory will be zeroed, no need to explicitly zero it
+ }
+ s->count = 0;
+ s->capacity = capacity;
+}
+
+gb_internal void type_set_destroy(TypeSet *s) {
+ gb_free(type_set_allocator(), s->keys);
+ s->keys = nullptr;
+ s->count = 0;
+ s->capacity = 0;
+}
+
+
+gb_internal isize type_set__find(TypeSet *s, TypeInfoPair pair) {
+ GB_ASSERT(pair.type != nullptr);
+ GB_ASSERT(pair.hash != 0);
+ if (s->count != 0) {
+ usize hash = pair.hash;
+ usize mask = s->capacity-1;
+ usize hash_index = cast(usize)hash & mask;
+ for (usize i = 0; i < s->capacity; i++) {
+ Type *key = s->keys[hash_index].type;
+ if (are_types_identical_unique_tuples(key, pair.type)) {
+ return hash_index;
+ } else if (key == 0) {
+ return -1;
+ }
+ hash_index = (hash_index+1)&mask;
+ }
+ }
+ return -1;
+}
+gb_internal isize type_set__find(TypeSet *s, Type *ptr) {
+ GB_ASSERT(ptr != 0);
+ if (s->count != 0) {
+ usize hash = cast(usize)type_hash_canonical_type(ptr);
+ usize mask = s->capacity-1;
+ usize hash_index = cast(usize)hash & mask;
+ for (usize i = 0; i < s->capacity; i++) {
+ Type *key = s->keys[hash_index].type;
+ if (are_types_identical_unique_tuples(key, ptr)) {
+ return hash_index;
+ } else if (key == 0) {
+ return -1;
+ }
+ hash_index = (hash_index+1)&mask;
+ }
+ }
+ return -1;
+}
+
+gb_internal bool type_set__full(TypeSet *s) {
+ return 0.75f * s->capacity <= s->count;
+}
+
+gb_internal gb_inline void type_set_grow(TypeSet *old_set) {
+ if (old_set->capacity == 0) {
+ type_set_init(old_set);
+ return;
+ }
+
+ TypeSet new_set = {};
+ type_set_init(&new_set, gb_max(old_set->capacity<<1, 16));
+
+ for (TypeInfoPair const &set : *old_set) {
+ bool was_new = type_set_update(&new_set, set);
+ GB_ASSERT(!was_new);
+ }
+ GB_ASSERT(old_set->count == new_set.count);
+
+ type_set_destroy(old_set);
+
+ *old_set = new_set;
+}
+
+
+gb_internal gb_inline bool type_set_exists(TypeSet *s, Type *ptr) {
+ return type_set__find(s, ptr) >= 0;
+}
+gb_internal gb_inline bool type_set_exists(TypeSet *s, TypeInfoPair pair) {
+ return type_set__find(s, pair) >= 0;
+}
+gb_internal gb_inline TypeInfoPair *type_set_retrieve(TypeSet *s, Type *type) {
+ isize index = type_set__find(s, type);
+ if (index >= 0) {
+ return &s->keys[index];
+ }
+ return nullptr;
+}
+
+
+gb_internal bool type_set_update(TypeSet *s, TypeInfoPair pair) { // returns true if it previously existsed
+ if (type_set_exists(s, pair)) {
+ return true;
+ }
+
+ if (s->keys == nullptr) {
+ type_set_init(s);
+ } else if (type_set__full(s)) {
+ type_set_grow(s);
+ }
+ GB_ASSERT(s->count < s->capacity);
+ GB_ASSERT(s->capacity >= 0);
+
+ usize mask = s->capacity-1;
+ usize hash = cast(usize)pair.hash;
+ usize hash_index = (cast(usize)hash) & mask;
+ GB_ASSERT(hash_index < s->capacity);
+ for (usize i = 0; i < s->capacity; i++) {
+ TypeInfoPair *key = &s->keys[hash_index];
+ GB_ASSERT(!are_types_identical_unique_tuples(key->type, pair.type));
+ if (key->hash == TYPE_SET_TOMBSTONE || key->hash == 0) {
+ *key = pair;
+ s->count++;
+ return false;
+ }
+ hash_index = (hash_index+1)&mask;
+ }
+
+ GB_PANIC("ptr set out of memory");
+ return false;
+}
+
+gb_internal bool type_set_update(TypeSet *s, Type *ptr) { // returns true if it previously existsed
+ TypeInfoPair pair = {ptr, type_hash_canonical_type(ptr)};
+ return type_set_update(s, pair);
+}
+
+
+gb_internal Type *type_set_add(TypeSet *s, Type *ptr) {
+ type_set_update(s, ptr);
+ return ptr;
+}
+
+gb_internal Type *type_set_add(TypeSet *s, TypeInfoPair pair) {
+ type_set_update(s, pair);
+ return pair.type;
+}
+
+
+
+gb_internal void type_set_remove(TypeSet *s, Type *ptr) {
+ isize index = type_set__find(s, ptr);
+ if (index >= 0) {
+ GB_ASSERT(s->count > 0);
+ s->keys[index].type = nullptr;
+ s->keys[index].hash = TYPE_SET_TOMBSTONE;
+ s->count--;
+ }
+}
+
+gb_internal gb_inline void type_set_clear(TypeSet *s) {
+ s->count = 0;
+ gb_zero_size(s->keys, s->capacity*gb_size_of(*s->keys));
+}
+
+
+#define TYPE_WRITER_PROC(name) bool name(TypeWriter *w, void const *ptr, isize len)
+typedef TYPE_WRITER_PROC(TypeWriterProc);
+
+
+struct TypeWriter {
+ TypeWriterProc *proc;
+ void *user_data;
+};
+
+bool type_writer_append(TypeWriter *w, void const *ptr, isize len) {
+ return w->proc(w, ptr, len);
+}
+
+bool type_writer_appendb(TypeWriter *w, char b) {
+ return w->proc(w, &b, 1);
+}
+
+bool type_writer_appendc(TypeWriter *w, char const *str) {
+ isize len = gb_strlen(str);
+ return w->proc(w, str, len);
+}
+
+bool type_writer_append_fmt(TypeWriter *w, char const *fmt, ...) {
+ va_list va;
+ char *str;
+ va_start(va, fmt);
+ str = gb_bprintf_va(fmt, va);
+ va_end(va);
+
+ return type_writer_appendc(w, str);
+}
+
+
+
+TYPE_WRITER_PROC(type_writer_string_writer_proc) {
+ gbString *s = cast(gbString *)&w->user_data;
+ *s = gb_string_append_length(*s, ptr, len);
+ return true;
+}
+
+void type_writer_make_string(TypeWriter *w, gbAllocator allocator) {
+ w->user_data = gb_string_make(allocator, "");
+ w->proc = type_writer_string_writer_proc;
+}
+
+void type_writer_destroy_string(TypeWriter *w) {
+ gb_string_free(cast(gbString)w->user_data);
+}
+
+
+TYPE_WRITER_PROC(type_writer_hasher_writer_proc) {
+ u64 *seed = cast(u64 *)w->user_data;
+ *seed = fnv64a(ptr, len, *seed);
+ return true;
+}
+
+void type_writer_make_hasher(TypeWriter *w, u64 *hash) {
+ w->user_data = hash;
+ w->proc = type_writer_hasher_writer_proc;
+}
+
+
+
+
+gb_internal void write_canonical_params(TypeWriter *w, Type *params) {
+ type_writer_appendc(w, "(");
+ defer (type_writer_appendc(w, ")"));
+
+ if (params == nullptr) {
+ return;
+ }
+ GB_ASSERT(params->kind == Type_Tuple);
+ for_array(i, params->Tuple.variables) {
+ Entity *v = params->Tuple.variables[i];
+ if (i > 0) {
+ type_writer_appendc(w, CANONICAL_PARAM_SEPARATOR);
+ }
+ type_writer_append(w, v->token.string.text, v->token.string.len);
+ type_writer_appendc(w, CANONICAL_TYPE_SEPARATOR);
+
+ switch (v->kind) {
+ case Entity_Variable:
+ if (v->flags&EntityFlag_CVarArg) {
+ type_writer_appendc(w, CANONICAL_PARAM_C_VARARG);
+ }
+ if (v->flags&EntityFlag_Ellipsis) {
+ Type *slice = base_type(v->type);
+ type_writer_appendc(w, CANONICAL_PARAM_VARARG);
+ GB_ASSERT(v->type->kind == Type_Slice);
+ write_type_to_canonical_string(w, slice->Slice.elem);
+ } else {
+ write_type_to_canonical_string(w, v->type);
+ }
+ if (is_in_doc_writer()) {
+ // NOTE(bill): This just exists to make sure the entities default values exist when
+ // writing to the odin doc format
+ Ast *expr = v->Variable.init_expr;
+ if (expr == nullptr) {
+ expr = v->Variable.param_value.original_ast_expr;
+ }
+ if (expr != nullptr) {
+ type_writer_appendc(w, "=");
+ gbString s = write_expr_to_string( // Minor leak
+ gb_string_make(temporary_allocator(), ""),
+ expr,
+ build_context.cmd_doc_flags & CmdDocFlag_Short
+ );
+ type_writer_append(w, s, gb_string_length(s));
+ }
+ }
+ break;
+ case Entity_TypeName:
+ type_writer_appendc(w, CANONICAL_PARAM_TYPEID);
+ write_type_to_canonical_string(w, v->type);
+ break;
+ case Entity_Constant:
+ {
+ type_writer_appendc(w, CANONICAL_PARAM_CONST);
+ gbString s = exact_value_to_string(v->Constant.value, 1<<16);
+ type_writer_append(w, s, gb_string_length(s));
+ gb_string_free(s);
+ }
+ break;
+ default:
+ GB_PANIC("TODO(bill): handle non type/const parapoly parameter values");
+ break;
+ }
+ }
+ return;
+}
+
+gb_internal u64 type_hash_canonical_type(Type *type) {
+ if (type == nullptr) {
+ return 0;
+ }
+ u64 hash = fnv64a(nullptr, 0);
+ TypeWriter w = {};
+ type_writer_make_hasher(&w, &hash);
+ write_type_to_canonical_string(&w, type);
+
+ return hash ? hash : 1;
+}
+
+gb_internal String type_to_canonical_string(gbAllocator allocator, Type *type) {
+ TypeWriter w = {};
+ type_writer_make_string(&w, allocator);
+ write_type_to_canonical_string(&w, type);
+
+ gbString s = cast(gbString)w.user_data;
+ return make_string(cast(u8 const *)s, gb_string_length(s));
+}
+
+gb_internal gbString temp_canonical_string(Type *type) {
+ TypeWriter w = {};
+ type_writer_make_string(&w, temporary_allocator());
+ write_type_to_canonical_string(&w, type);
+
+ return cast(gbString)w.user_data;
+}
+
+gb_internal gbString string_canonical_entity_name(gbAllocator allocator, Entity *e) {
+ TypeWriter w = {};
+ type_writer_make_string(&w, allocator);
+ write_canonical_entity_name(&w, e);
+ return cast(gbString)w.user_data;
+}
+
+
+
+gb_internal void write_canonical_parent_prefix(TypeWriter *w, Entity *e) {
+ GB_ASSERT(e != nullptr);
+ if (e->kind == Entity_Procedure || e->kind == Entity_TypeName) {
+ if (e->kind == Entity_Procedure && (e->Procedure.is_export || e->Procedure.is_foreign)) {
+ // no prefix
+ return;
+ }
+ if (e->parent_proc_decl) {
+ Entity *p = e->parent_proc_decl->entity;
+ write_canonical_parent_prefix(w, p);
+ type_writer_append(w, p->token.string.text, p->token.string.len);
+ if (is_type_polymorphic(p->type)) {
+ type_writer_appendc(w, CANONICAL_TYPE_SEPARATOR);
+ write_type_to_canonical_string(w, p->type);
+ }
+ type_writer_appendc(w, CANONICAL_NAME_SEPARATOR);
+
+ } else if (e->pkg && (scope_lookup_current(e->pkg->scope, e->token.string) == e)) {
+ type_writer_append(w, e->pkg->name.text, e->pkg->name.len);
+ if (e->pkg->name == "llvm") {
+ type_writer_appendc(w, "$");
+ }
+ type_writer_appendc(w, CANONICAL_NAME_SEPARATOR);
+ } else {
+ String file_name = filename_without_directory(e->file->fullpath);
+ type_writer_append(w, e->pkg->name.text, e->pkg->name.len);
+ if (e->pkg->name == "llvm") {
+ type_writer_appendc(w, "$");
+ }
+ type_writer_append_fmt(w, CANONICAL_NAME_SEPARATOR "%.*s" CANONICAL_NAME_SEPARATOR, LIT(file_name));
+ }
+ } else {
+ GB_PANIC("TODO(bill): handle entity kind: %d", e->kind);
+ }
+ if (e->kind == Entity_Procedure && e->Procedure.is_anonymous) {
+ String file_name = filename_without_directory(e->file->fullpath);
+ type_writer_append_fmt(w, CANONICAL_ANON_PREFIX "_%.*s:%d", LIT(file_name), e->token.pos.offset);
+ } else {
+ type_writer_append(w, e->token.string.text, e->token.string.len);
+ }
+
+ if (is_type_polymorphic(e->type)) {
+ type_writer_appendc(w, CANONICAL_TYPE_SEPARATOR);
+ write_type_to_canonical_string(w, e->type);
+ }
+ type_writer_appendc(w, CANONICAL_NAME_SEPARATOR);
+
+ return;
+}
+
+gb_internal void write_canonical_entity_name(TypeWriter *w, Entity *e) {
+ GB_ASSERT(e != nullptr);
+
+ if (e->token.string == "_") {
+ GB_PANIC("_ string");
+ }
+ if (e->token.string.len == 0) {
+ GB_PANIC("empty string");
+ }
+
+ if (e->kind == Entity_Variable) {
+ bool is_foreign = e->Variable.is_foreign;
+ bool is_export = e->Variable.is_export;
+ if (e->Variable.link_name.len > 0) {
+ type_writer_append(w, e->Variable.link_name.text, e->Variable.link_name.len);
+ return;
+ } else if (is_foreign || is_export) {
+ type_writer_append(w, e->token.string.text, e->token.string.len);
+ return;
+ }
+ } else if (e->kind == Entity_Procedure && e->Procedure.link_name.len > 0) {
+ type_writer_append(w, e->Procedure.link_name.text, e->Procedure.link_name.len);
+ return;
+ } else if (e->kind == Entity_Procedure && e->Procedure.is_export) {
+ type_writer_append(w, e->token.string.text, e->token.string.len);
+ return;
+ }
+
+ bool write_scope_index_suffix = false;
+
+ if (e->scope->flags & (ScopeFlag_Builtin)) {
+ goto write_base_name;
+ } else if ((e->scope->flags & (ScopeFlag_File | ScopeFlag_Pkg)) == 0 ||
+ e->flags & EntityFlag_NotExported) {
+ Scope *s = e->scope;
+
+ while ((s->flags & (ScopeFlag_Proc|ScopeFlag_File)) == 0 && s->decl_info == nullptr) {
+ if (s->parent == nullptr) {
+ break;
+ }
+ s = s->parent;
+ }
+
+ if (s->decl_info != nullptr && s->decl_info->entity) {
+ Entity *parent = s->decl_info->entity;
+ write_canonical_parent_prefix(w, parent);
+ if (e->scope->index > 0) {
+ write_scope_index_suffix = true;
+ }
+
+ goto write_base_name;
+ } else if ((s->flags & ScopeFlag_File) && s->file != nullptr) {
+ String file_name = filename_without_directory(s->file->fullpath);
+ type_writer_append(w, e->pkg->name.text, e->pkg->name.len);
+ if (e->pkg->name == "llvm") {
+ type_writer_appendc(w, "$");
+ }
+ type_writer_appendc(w, gb_bprintf(CANONICAL_NAME_SEPARATOR "[%.*s]" CANONICAL_NAME_SEPARATOR, LIT(file_name)));
+ goto write_base_name;
+ } else if (s->flags & (ScopeFlag_Builtin)) {
+ goto write_base_name;
+ }
+ gb_printf_err("%s WEIRD ENTITY TYPE %s %u %p\n", token_pos_to_string(e->token.pos), type_to_string(e->type), s->flags, s->decl_info);
+
+ auto const print_scope_flags = [](Scope *s) {
+ if (s->flags & ScopeFlag_Pkg) gb_printf_err("Pkg ");
+ if (s->flags & ScopeFlag_Builtin) gb_printf_err("Builtin ");
+ if (s->flags & ScopeFlag_Global) gb_printf_err("Global ");
+ if (s->flags & ScopeFlag_File) gb_printf_err("File ");
+ if (s->flags & ScopeFlag_Init) gb_printf_err("Init ");
+ if (s->flags & ScopeFlag_Proc) gb_printf_err("Proc ");
+ if (s->flags & ScopeFlag_Type) gb_printf_err("Type ");
+ if (s->flags & ScopeFlag_HasBeenImported) gb_printf_err("HasBeenImported ");
+ if (s->flags & ScopeFlag_ContextDefined) gb_printf_err("ContextDefined ");
+ gb_printf_err("\n");
+ };
+
+ print_scope_flags(s);
+ GB_PANIC("weird entity %.*s", LIT(e->token.string));
+ }
+ if (e->pkg != nullptr) {
+ type_writer_append(w, e->pkg->name.text, e->pkg->name.len);
+ type_writer_appendc(w, CANONICAL_NAME_SEPARATOR);
+ }
+
+write_base_name:
+
+ switch (e->kind) {
+ case Entity_TypeName:
+ {
+
+ Type *params = nullptr;
+ Entity *parent = type_get_polymorphic_parent(e->type, &params);
+ if (parent && (parent->token.string == e->token.string)) {
+ type_writer_append(w, parent->token.string.text, parent->token.string.len);
+ write_canonical_params(w, params);
+ } else {
+ type_writer_append(w, e->token.string.text, e->token.string.len);
+ }
+ }
+ break;
+
+ case Entity_Constant:
+ // For debug symbols only
+ /*fallthrough*/
+ case Entity_Procedure:
+ case Entity_Variable:
+ type_writer_append(w, e->token.string.text, e->token.string.len);
+ if (is_type_polymorphic(e->type)) {
+ type_writer_appendc(w, CANONICAL_TYPE_SEPARATOR);
+ write_type_to_canonical_string(w, e->type);
+ }
+ break;
+
+ default:
+ GB_PANIC("TODO(bill): entity kind %d", e->kind);
+ break;
+ }
+
+ if (write_scope_index_suffix) {
+ GB_ASSERT(e != nullptr && e->scope != nullptr);
+ type_writer_append_fmt(w, CANONICAL_NAME_SEPARATOR "$%d", e->scope->index);
+ }
+
+ return;
+}
+
+
+// NOTE(bill): This exists so that we deterministically hash a type by serializing it to a canonical string
+gb_internal void write_type_to_canonical_string(TypeWriter *w, Type *type) {
+ if (type == nullptr) {
+ type_writer_appendc(w, CANONICAL_NONE_TYPE); // none/void type
+ return;
+ }
+
+ type = default_type(type);
+ GB_ASSERT(!is_type_untyped(type));
+
+ switch (type->kind) {
+ case Type_Basic:
+ type_writer_append(w, type->Basic.name.text, type->Basic.name.len);
+ return;
+ case Type_Pointer:
+ type_writer_appendb(w, '^');
+ write_type_to_canonical_string(w, type->Pointer.elem);
+ return;
+ case Type_MultiPointer:
+ type_writer_appendc(w, "[^]");
+ write_type_to_canonical_string(w, type->Pointer.elem);
+ return;
+ case Type_SoaPointer:
+ type_writer_appendc(w, "#soa^");
+ write_type_to_canonical_string(w, type->Pointer.elem);
+ return;
+ case Type_EnumeratedArray:
+ if (type->EnumeratedArray.is_sparse) {
+ type_writer_appendc(w, "#sparse");
+ }
+ type_writer_appendb(w, '[');
+ write_type_to_canonical_string(w, type->EnumeratedArray.index);
+ type_writer_appendb(w, ']');
+ write_type_to_canonical_string(w, type->EnumeratedArray.elem);
+ return;
+ case Type_Array:
+ type_writer_append_fmt(w, "[%lld]", cast(long long)type->Array.count);
+ write_type_to_canonical_string(w, type->Array.elem);
+ return;
+ case Type_Slice:
+ type_writer_appendc(w, "[]");
+ write_type_to_canonical_string(w, type->Array.elem);
+ return;
+ case Type_DynamicArray:
+ type_writer_appendc(w, "[dynamic]");
+ write_type_to_canonical_string(w, type->DynamicArray.elem);
+ return;
+ case Type_SimdVector:
+ type_writer_append_fmt(w, "#simd[%lld]", cast(long long)type->SimdVector.count);
+ write_type_to_canonical_string(w, type->SimdVector.elem);
+ return;
+ case Type_Matrix:
+ if (type->Matrix.is_row_major) {
+ type_writer_appendc(w, "#row_major ");
+ }
+ type_writer_append_fmt(w, "matrix[%lld, %lld]", cast(long long)type->Matrix.row_count, cast(long long)type->Matrix.column_count);
+ write_type_to_canonical_string(w, type->Matrix.elem);
+ return;
+ case Type_Map:
+ type_writer_appendc(w, "map[");
+ write_type_to_canonical_string(w, type->Map.key);
+ type_writer_appendc(w, "]");
+ write_type_to_canonical_string(w, type->Map.value);
+ return;
+
+ case Type_Enum:
+ type_writer_appendc(w, "enum");
+ if (type->Enum.base_type != nullptr) {
+ type_writer_appendb(w, ' ');
+ write_type_to_canonical_string(w, type->Enum.base_type);
+ type_writer_appendb(w, ' ');
+ }
+ type_writer_appendb(w, '{');
+ for_array(i, type->Enum.fields) {
+ Entity *f = type->Enum.fields[i];
+ GB_ASSERT(f->kind == Entity_Constant);
+ if (i > 0) {
+ type_writer_appendc(w, CANONICAL_FIELD_SEPARATOR);
+ }
+ type_writer_append(w, f->token.string.text, f->token.string.len);
+ type_writer_appendc(w, "=");
+
+ gbString s = exact_value_to_string(f->Constant.value, 1<<16);
+ type_writer_append(w, s, gb_string_length(s));
+ gb_string_free(s);
+ }
+ type_writer_appendb(w, '}');
+ return;
+ case Type_BitSet:
+ type_writer_appendc(w, "bit_set[");
+ if (type->BitSet.elem == nullptr) {
+ type_writer_appendc(w, CANONICAL_NONE_TYPE);
+ } else if (is_type_enum(type->BitSet.elem)) {
+ write_type_to_canonical_string(w, type->BitSet.elem);
+ } else {
+ type_writer_append_fmt(w, "%lld", type->BitSet.lower);
+ type_writer_append_fmt(w, CANONICAL_RANGE_OPERATOR);
+ type_writer_append_fmt(w, "%lld", type->BitSet.upper);
+ }
+ if (type->BitSet.underlying != nullptr) {
+ type_writer_appendc(w, ";");
+ write_type_to_canonical_string(w, type->BitSet.underlying);
+ }
+ type_writer_appendc(w, "]");
+ return;
+
+ case Type_Union:
+ type_writer_appendc(w, "union");
+
+ if (is_in_doc_writer() && type->Union.polymorphic_params) {
+ write_canonical_params(w, type->Union.polymorphic_params);
+ }
+
+ switch (type->Union.kind) {
+ case UnionType_no_nil: type_writer_appendc(w, "#no_nil"); break;
+ case UnionType_shared_nil: type_writer_appendc(w, "#shared_nil"); break;
+ }
+ if (type->Union.custom_align != 0) {
+ type_writer_append_fmt(w, "#align(%lld)", cast(long long)type->Union.custom_align);
+ }
+ type_writer_appendc(w, "{");
+ for_array(i, type->Union.variants) {
+ Type *t = type->Union.variants[i];
+ if (i > 0) type_writer_appendc(w, CANONICAL_FIELD_SEPARATOR);
+ write_type_to_canonical_string(w, t);
+ }
+ type_writer_appendc(w, "}");
+ return;
+ case Type_Struct:
+ if (type->Struct.soa_kind != StructSoa_None) {
+ switch (type->Struct.soa_kind) {
+ case StructSoa_Fixed: type_writer_append_fmt(w, "#soa[%lld]", cast(long long)type->Struct.soa_count); break;
+ case StructSoa_Slice: type_writer_appendc(w, "#soa[]"); break;
+ case StructSoa_Dynamic: type_writer_appendc(w, "#soa[dynamic]"); break;
+ default: GB_PANIC("Unknown StructSoaKind"); break;
+ }
+ return write_type_to_canonical_string(w, type->Struct.soa_elem);
+ }
+
+ type_writer_appendc(w, "struct");
+
+ if (is_in_doc_writer() && type->Struct.polymorphic_params) {
+ write_canonical_params(w, type->Struct.polymorphic_params);
+ }
+
+ if (type->Struct.is_packed) type_writer_appendc(w, "#packed");
+ if (type->Struct.is_raw_union) type_writer_appendc(w, "#raw_union");
+ if (type->Struct.is_no_copy) type_writer_appendc(w, "#no_copy");
+ if (type->Struct.custom_min_field_align != 0) type_writer_append_fmt(w, "#min_field_align(%lld)", cast(long long)type->Struct.custom_min_field_align);
+ if (type->Struct.custom_max_field_align != 0) type_writer_append_fmt(w, "#max_field_align(%lld)", cast(long long)type->Struct.custom_max_field_align);
+ if (type->Struct.custom_align != 0) type_writer_append_fmt(w, "#align(%lld)", cast(long long)type->Struct.custom_align);
+ type_writer_appendb(w, '{');
+ for_array(i, type->Struct.fields) {
+ Entity *f = type->Struct.fields[i];
+ GB_ASSERT(f->kind == Entity_Variable);
+ if (i > 0) {
+ type_writer_appendc(w, CANONICAL_FIELD_SEPARATOR);
+ }
+ type_writer_append(w, f->token.string.text, f->token.string.len);
+ type_writer_appendc(w, CANONICAL_TYPE_SEPARATOR);
+ write_type_to_canonical_string(w, f->type);
+ String tag = {};
+ if (type->Struct.tags != nullptr) {
+ tag = type->Struct.tags[i];
+ }
+ if (tag.len != 0) {
+ String s = quote_to_ascii(heap_allocator(), tag);
+ type_writer_append(w, s.text, s.len);
+ gb_free(heap_allocator(), s.text);
+ }
+ }
+ type_writer_appendb(w, '}');
+ return;
+
+ case Type_BitField:
+ type_writer_appendc(w, "bit_field");
+ write_type_to_canonical_string(w, type->BitField.backing_type);
+ type_writer_appendc(w, " {");
+ for (isize i = 0; i < type->BitField.fields.count; i++) {
+ Entity *f = type->BitField.fields[i];
+ if (i > 0) {
+ type_writer_appendc(w, CANONICAL_FIELD_SEPARATOR);
+ }
+ type_writer_append(w, f->token.string.text, f->token.string.len);
+ type_writer_appendc(w, CANONICAL_TYPE_SEPARATOR);
+ write_type_to_canonical_string(w, f->type);
+ type_writer_appendc(w, CANONICAL_BIT_FIELD_SEPARATOR);
+ type_writer_append_fmt(w, "%u", type->BitField.bit_sizes[i]);
+ }
+ type_writer_appendc(w, " }");
+ return;
+
+ case Type_Proc:
+ type_writer_appendc(w, "proc");
+ if (default_calling_convention() != type->Proc.calling_convention) {
+ type_writer_appendc(w, "\"");
+ type_writer_appendc(w, proc_calling_convention_strings[type->Proc.calling_convention]);
+ type_writer_appendc(w, "\"");
+ }
+
+ write_canonical_params(w, type->Proc.params);
+ if (type->Proc.result_count > 0) {
+ type_writer_appendc(w, "->");
+ write_canonical_params(w, type->Proc.results);
+ }
+ return;
+
+ case Type_Generic:
+ if (is_in_doc_writer()) {
+ type_writer_appendc(w, "$");
+ type_writer_append(w, type->Generic.name.text, type->Generic.name.len);
+ type_writer_append_fmt(w, "-%lld", cast(long long)type->Generic.id);
+ if (type->Generic.specialized) {
+ type_writer_appendc(w, "/");
+ write_type_to_canonical_string(w, type->Generic.specialized);
+ }
+ } else if (type->Generic.specialized) {
+ // If we have a specialized type, use that instead of panicking
+ write_type_to_canonical_string(w, type->Generic.specialized);
+ } else {
+ // For unspecialized generics, use a generic placeholder string
+ type_writer_appendc(w, "rawptr");
+ }
+ return;
+
+ case Type_Named:
+ if (type->Named.type_name != nullptr) {
+ write_canonical_entity_name(w, type->Named.type_name);
+ return;
+ } else {
+ type_writer_append(w, type->Named.name.text, type->Named.name.len);
+ }
+ return;
+
+ case Type_Tuple:
+ type_writer_appendc(w, "params");
+ write_canonical_params(w, type);
+ return;
+ default:
+ GB_PANIC("unknown type kind %d %.*s", type->kind, LIT(type_strings[type->kind]));
+ break;
+ }
+
+ return;
+} \ No newline at end of file
diff --git a/src/name_canonicalization.hpp b/src/name_canonicalization.hpp
new file mode 100644
index 000000000..304aff42e
--- /dev/null
+++ b/src/name_canonicalization.hpp
@@ -0,0 +1,128 @@
+/*
+ General Rules for canonical name mangling
+
+ * No spaces between any values
+
+ * normal declarations - pkg::name
+ * builtin names - just their normal name e.g. `i32` or `string`
+ * nested (zero level) - pkg::parent1::parent2::name
+ * nested (more scopes) - pkg::parent1::parent2::name[4]
+ * [4] indicates the 4th scope within a procedure numbered in depth-first order
+ * file private - pkg::[file_name]::name
+ * Example: `pkg::[file.odin]::Type`
+ * polymorphic procedure/type - pkg::foo:TYPE
+ * naming convention for parameters
+ * type
+ * $typeid_based_name
+ * $$constant_parameter
+ * Example: `foo::to_thing:proc(u64)->([]u8)`
+ * nested decl in polymorphic procedure - pkg::foo:TYPE::name
+ * anonymous procedures - pkg::foo::$anon[file.odin:123]
+ * 123 is the file offset in bytes
+*/
+
+#define CANONICAL_TYPE_SEPARATOR ":"
+#define CANONICAL_NAME_SEPARATOR "::"
+// #define CANONICAL_NAME_SEPARATOR "·"
+
+#define CANONICAL_BIT_FIELD_SEPARATOR "|"
+
+#define CANONICAL_PARAM_SEPARATOR ","
+
+#define CANONICAL_PARAM_TYPEID "$"
+#define CANONICAL_PARAM_CONST "$$"
+
+#define CANONICAL_PARAM_C_VARARG "#c_vararg"
+#define CANONICAL_PARAM_VARARG ".."
+
+#define CANONICAL_FIELD_SEPARATOR ","
+
+#define CANONICAL_ANON_PREFIX "$anon"
+
+#define CANONICAL_NONE_TYPE "<>"
+
+#define CANONICAL_RANGE_OPERATOR "..="
+
+struct TypeWriter;
+
+gb_internal void write_type_to_canonical_string(TypeWriter *w, Type *type);
+gb_internal void write_canonical_entity_name(TypeWriter *w, Entity *e);
+gb_internal u64 type_hash_canonical_type(Type *type);
+gb_internal String type_to_canonical_string(gbAllocator allocator, Type *type);
+gb_internal gbString temp_canonical_string(Type *type);
+
+
+gb_internal GB_COMPARE_PROC(type_info_pair_cmp);
+
+
+struct TypeInfoPair {
+ Type *type;
+ u64 hash; // see: type_hash_canonical_type
+};
+
+struct TypeSet {
+ TypeInfoPair *keys;
+ usize count;
+ usize capacity;
+};
+
+static constexpr u64 TYPE_SET_TOMBSTONE = ~(u64)(0ull);
+
+struct TypeSetIterator {
+ TypeSet *set;
+ usize index;
+
+ TypeSetIterator &operator++() noexcept {
+ for (;;) {
+ ++index;
+ if (set->capacity == index) {
+ return *this;
+ }
+ TypeInfoPair key = set->keys[index];
+ if (key.hash != 0 && key.hash != TYPE_SET_TOMBSTONE) {
+ return *this;
+ }
+ }
+ }
+
+ bool operator==(TypeSetIterator const &other) const noexcept {
+ return this->set == other.set && this->index == other.index;
+ }
+
+
+ operator TypeInfoPair *() const {
+ return &set->keys[index];
+ }
+};
+
+
+gb_internal void type_set_init (TypeSet *s, isize capacity = 16);
+gb_internal void type_set_destroy(TypeSet *s);
+gb_internal Type *type_set_add (TypeSet *s, Type *ptr);
+gb_internal Type *type_set_add (TypeSet *s, TypeInfoPair pair);
+gb_internal bool type_set_update (TypeSet *s, Type *ptr); // returns true if it previously existed
+gb_internal bool type_set_update (TypeSet *s, TypeInfoPair pair); // returns true if it previously existed
+gb_internal bool type_set_exists (TypeSet *s, Type *ptr);
+gb_internal void type_set_remove (TypeSet *s, Type *ptr);
+gb_internal void type_set_clear (TypeSet *s);
+gb_internal TypeInfoPair *type_set_retrieve(TypeSet *s, Type *ptr);
+
+gb_internal TypeSetIterator begin(TypeSet &set) noexcept;
+gb_internal TypeSetIterator end(TypeSet &set) noexcept;
+
+
+template <typename V>
+gb_internal gb_inline V *map_get(PtrMap<u64, V> *h, Type *key) {
+ return map_get(h, type_hash_canonical_type(key));
+}
+template <typename V>
+gb_internal gb_inline void map_set(PtrMap<u64, V> *h, Type *key, V const &value) {
+ map_set(h, type_hash_canonical_type(key), value);
+}
+
+template <typename V>
+gb_internal gb_inline V &map_must_get(PtrMap<u64, V> *h, Type *key) {
+ V *ptr = map_get(h, type_hash_canonical_type(key));
+ GB_ASSERT(ptr != nullptr);
+ return *ptr;
+} \ No newline at end of file
diff --git a/src/parser.cpp b/src/parser.cpp
index 94f8fd42c..942e83f29 100644
--- a/src/parser.cpp
+++ b/src/parser.cpp
@@ -3016,9 +3016,10 @@ gb_internal Ast *parse_operand(AstFile *f, bool lhs) {
syntax_error(token, "Expected a type or range, got nothing");
}
- if (allow_token(f, Token_Semicolon)) {
+ if (f->curr_token.kind == Token_Semicolon && f->curr_token.string == ";") {
+ expect_token(f, Token_Semicolon);
underlying = parse_type(f);
- } else if (allow_token(f, Token_Comma)) {
+ } else if (allow_token(f, Token_Comma) || allow_token(f, Token_Semicolon)) {
String p = token_to_string(f->prev_token);
syntax_error(token_end_of_line(f, f->prev_token), "Expected a semicolon, got a %.*s", LIT(p));
@@ -3273,6 +3274,8 @@ gb_internal Ast *parse_atom_expr(AstFile *f, Ast *operand, bool lhs) {
case Token_OpenBracket: {
bool prev_allow_range = f->allow_range;
f->allow_range = false;
+ defer (f->allow_range = prev_allow_range);
+
Token open = {}, close = {}, interval = {};
Ast *indices[2] = {};
@@ -3281,6 +3284,13 @@ gb_internal Ast *parse_atom_expr(AstFile *f, Ast *operand, bool lhs) {
f->expr_level++;
open = expect_token(f, Token_OpenBracket);
+ if (f->curr_token.kind == Token_CloseBracket) {
+ error(f->curr_token, "Expected an operand, got ]");
+ close = expect_token(f, Token_CloseBracket);
+ operand = ast_index_expr(f, operand, nullptr, open, close);
+ break;
+ }
+
switch (f->curr_token.kind) {
case Token_Ellipsis:
case Token_RangeFull:
@@ -3330,7 +3340,6 @@ gb_internal Ast *parse_atom_expr(AstFile *f, Ast *operand, bool lhs) {
operand = ast_index_expr(f, operand, indices[0], open, close);
}
- f->allow_range = prev_allow_range;
} break;
case Token_Pointer: // Deference
@@ -4342,30 +4351,132 @@ gb_internal Ast *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_fl
}
- if (f->curr_token.kind == Token_Colon) {
- Array<Ast *> names = convert_to_ident_list(f, list, true, allow_poly_names); // Copy for semantic reasons
+ if (f->curr_token.kind != Token_Colon) {
+ // NOTE(bill): proc(Type, Type, Type)
+ for (AstAndFlags const &item : list) {
+ Ast *type = item.node;
+ Token token = blank_token;
+ if (allowed_flags&FieldFlag_Results) {
+ // NOTE(bill): Make this nothing and not `_`
+ token.string = str_lit("");
+ }
+
+ auto names = array_make<Ast *>(ast_allocator(f), 1);
+ token.pos = ast_token(type).pos;
+ names[0] = ast_ident(f, token);
+ u32 flags = check_field_prefixes(f, list.count, allowed_flags, item.flags);
+ Token tag = {};
+ Ast *param = ast_field(f, names, item.node, nullptr, flags, tag, docs, f->line_comment);
+ array_add(&params, param);
+ }
+
+ if (name_count_) *name_count_ = total_name_count;
+ return ast_field_list(f, start_token, params);
+ }
+
+ // NOTE(bill): proc(ident, ident, ident: Type)
+
+ if (f->prev_token.kind == Token_Comma) {
+ syntax_error(f->prev_token, "Trailing comma before a colon is not allowed");
+ }
+ Array<Ast *> names = convert_to_ident_list(f, list, true, allow_poly_names); // Copy for semantic reasons
+ if (names.count == 0) {
+ syntax_error(f->curr_token, "Empty field declaration");
+ }
+ bool any_polymorphic_names = check_procedure_name_list(names);
+ u32 set_flags = 0;
+ if (list.count > 0) {
+ set_flags = list[0].flags;
+ }
+ set_flags = check_field_prefixes(f, names.count, allowed_flags, set_flags);
+ total_name_count += names.count;
+
+ Ast *type = nullptr;
+ Ast *default_value = nullptr;
+ Token tag = {};
+
+ expect_token_after(f, Token_Colon, "field list");
+ if (f->curr_token.kind != Token_Eq) {
+ type = parse_var_type(f, allow_ellipsis, allow_typeid_token);
+ Ast *tt = unparen_expr(type);
+ if (tt == nullptr) {
+ syntax_error(f->prev_token, "Invalid type expression in field list");
+ } else if (is_signature && !any_polymorphic_names && tt->kind == Ast_TypeidType && tt->TypeidType.specialization != nullptr) {
+ syntax_error(type, "Specialization of typeid is not allowed without polymorphic names");
+ }
+ }
+
+ if (allow_token(f, Token_Eq)) {
+ default_value = parse_expr(f, false);
+ if (!allow_default_parameters) {
+ syntax_error(f->curr_token, "Default parameters are only allowed for procedures");
+ default_value = nullptr;
+ }
+ }
+
+ if (default_value != nullptr && names.count > 1) {
+ syntax_error(f->curr_token, "Default parameters can only be applied to single values");
+ }
+
+ if (allowed_flags == FieldFlag_Struct && default_value != nullptr) {
+ syntax_error(default_value, "Default parameters are not allowed for structs");
+ default_value = nullptr;
+ }
+
+ if (type != nullptr && type->kind == Ast_Ellipsis) {
+ if (seen_ellipsis) syntax_error(type, "Extra variadic parameter after ellipsis");
+ seen_ellipsis = true;
+ if (names.count != 1) {
+ syntax_error(type, "Variadic parameters can only have one field name");
+ }
+ } else if (seen_ellipsis && default_value == nullptr) {
+ syntax_error(f->curr_token, "Extra parameter after ellipsis without a default value");
+ }
+
+ if (type != nullptr && default_value == nullptr) {
+ if (f->curr_token.kind == Token_String) {
+ tag = expect_token(f, Token_String);
+ if ((allowed_flags & FieldFlag_Tags) == 0) {
+ syntax_error(tag, "Field tags are only allowed within structures");
+ }
+ }
+ }
+
+ bool more_fields = allow_field_separator(f);
+ Ast *param = ast_field(f, names, type, default_value, set_flags, tag, docs, f->line_comment);
+ array_add(&params, param);
+
+ if (!more_fields) {
+ if (name_count_) *name_count_ = total_name_count;
+ return ast_field_list(f, start_token, params);
+ }
+
+ while (f->curr_token.kind != follow &&
+ f->curr_token.kind != Token_EOF &&
+ f->curr_token.kind != Token_Semicolon) {
+ CommentGroup *docs = f->lead_comment;
+
+ if (!is_signature) parse_enforce_tabs(f);
+ u32 set_flags = parse_field_prefixes(f);
+ Token tag = {};
+ Array<Ast *> names = parse_ident_list(f, allow_poly_names);
if (names.count == 0) {
syntax_error(f->curr_token, "Empty field declaration");
+ break;
}
bool any_polymorphic_names = check_procedure_name_list(names);
- u32 set_flags = 0;
- if (list.count > 0) {
- set_flags = list[0].flags;
- }
set_flags = check_field_prefixes(f, names.count, allowed_flags, set_flags);
total_name_count += names.count;
Ast *type = nullptr;
Ast *default_value = nullptr;
- Token tag = {};
-
expect_token_after(f, Token_Colon, "field list");
if (f->curr_token.kind != Token_Eq) {
type = parse_var_type(f, allow_ellipsis, allow_typeid_token);
Ast *tt = unparen_expr(type);
- if (tt == nullptr) {
- syntax_error(f->prev_token, "Invalid type expression in field list");
- } else if (is_signature && !any_polymorphic_names && tt->kind == Ast_TypeidType && tt->TypeidType.specialization != nullptr) {
+ if (is_signature && !any_polymorphic_names &&
+ tt != nullptr &&
+ tt->kind == Ast_TypeidType && tt->TypeidType.specialization != nullptr) {
syntax_error(type, "Specialization of typeid is not allowed without polymorphic names");
}
}
@@ -4382,11 +4493,6 @@ gb_internal Ast *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_fl
syntax_error(f->curr_token, "Default parameters can only be applied to single values");
}
- if (allowed_flags == FieldFlag_Struct && default_value != nullptr) {
- syntax_error(default_value, "Default parameters are not allowed for structs");
- default_value = nullptr;
- }
-
if (type != nullptr && type->kind == Ast_Ellipsis) {
if (seen_ellipsis) syntax_error(type, "Extra variadic parameter after ellipsis");
seen_ellipsis = true;
@@ -4406,105 +4512,14 @@ gb_internal Ast *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_fl
}
}
- bool more_fields = allow_field_separator(f);
+
+ bool ok = allow_field_separator(f);
Ast *param = ast_field(f, names, type, default_value, set_flags, tag, docs, f->line_comment);
array_add(&params, param);
- if (!more_fields) {
- if (name_count_) *name_count_ = total_name_count;
- return ast_field_list(f, start_token, params);
- }
-
- while (f->curr_token.kind != follow &&
- f->curr_token.kind != Token_EOF &&
- f->curr_token.kind != Token_Semicolon) {
- CommentGroup *docs = f->lead_comment;
-
- if (!is_signature) parse_enforce_tabs(f);
- u32 set_flags = parse_field_prefixes(f);
- Token tag = {};
- Array<Ast *> names = parse_ident_list(f, allow_poly_names);
- if (names.count == 0) {
- syntax_error(f->curr_token, "Empty field declaration");
- break;
- }
- bool any_polymorphic_names = check_procedure_name_list(names);
- set_flags = check_field_prefixes(f, names.count, allowed_flags, set_flags);
- total_name_count += names.count;
-
- Ast *type = nullptr;
- Ast *default_value = nullptr;
- expect_token_after(f, Token_Colon, "field list");
- if (f->curr_token.kind != Token_Eq) {
- type = parse_var_type(f, allow_ellipsis, allow_typeid_token);
- Ast *tt = unparen_expr(type);
- if (is_signature && !any_polymorphic_names &&
- tt != nullptr &&
- tt->kind == Ast_TypeidType && tt->TypeidType.specialization != nullptr) {
- syntax_error(type, "Specialization of typeid is not allowed without polymorphic names");
- }
- }
-
- if (allow_token(f, Token_Eq)) {
- default_value = parse_expr(f, false);
- if (!allow_default_parameters) {
- syntax_error(f->curr_token, "Default parameters are only allowed for procedures");
- default_value = nullptr;
- }
- }
-
- if (default_value != nullptr && names.count > 1) {
- syntax_error(f->curr_token, "Default parameters can only be applied to single values");
- }
-
- if (type != nullptr && type->kind == Ast_Ellipsis) {
- if (seen_ellipsis) syntax_error(type, "Extra variadic parameter after ellipsis");
- seen_ellipsis = true;
- if (names.count != 1) {
- syntax_error(type, "Variadic parameters can only have one field name");
- }
- } else if (seen_ellipsis && default_value == nullptr) {
- syntax_error(f->curr_token, "Extra parameter after ellipsis without a default value");
- }
-
- if (type != nullptr && default_value == nullptr) {
- if (f->curr_token.kind == Token_String) {
- tag = expect_token(f, Token_String);
- if ((allowed_flags & FieldFlag_Tags) == 0) {
- syntax_error(tag, "Field tags are only allowed within structures");
- }
- }
- }
-
-
- bool ok = allow_field_separator(f);
- Ast *param = ast_field(f, names, type, default_value, set_flags, tag, docs, f->line_comment);
- array_add(&params, param);
-
- if (!ok) {
- break;
- }
- }
-
- if (name_count_) *name_count_ = total_name_count;
- return ast_field_list(f, start_token, params);
- }
-
- for (AstAndFlags const &item : list) {
- Ast *type = item.node;
- Token token = blank_token;
- if (allowed_flags&FieldFlag_Results) {
- // NOTE(bill): Make this nothing and not `_`
- token.string = str_lit("");
+ if (!ok) {
+ break;
}
-
- auto names = array_make<Ast *>(ast_allocator(f), 1);
- token.pos = ast_token(type).pos;
- names[0] = ast_ident(f, token);
- u32 flags = check_field_prefixes(f, list.count, allowed_flags, item.flags);
- Token tag = {};
- Ast *param = ast_field(f, names, item.node, nullptr, flags, tag, docs, f->line_comment);
- array_add(&params, param);
}
if (name_count_) *name_count_ = total_name_count;
@@ -4572,6 +4587,9 @@ gb_internal Ast *parse_do_body(AstFile *f, Token const &token, char const *msg)
gb_internal bool parse_control_statement_semicolon_separator(AstFile *f) {
Token tok = peek_token(f);
if (tok.kind != Token_OpenBrace) {
+ if (f->curr_token.kind == Token_Semicolon && f->curr_token.string != ";") {
+ syntax_error(token_end_of_line(f, f->prev_token), "Expected ';', got newline");
+ }
return allow_token(f, Token_Semicolon);
}
if (f->curr_token.string == ";") {
@@ -5776,7 +5794,7 @@ gb_internal AstPackage *try_add_import_path(Parser *p, String path, String const
for (FileInfo fi : list) {
String name = fi.name;
String ext = path_extension(name);
- if (ext == FILE_EXT) {
+ if (ext == FILE_EXT && !path_is_directory(name)) {
files_with_ext += 1;
}
if (ext == FILE_EXT && !is_excluded_target_filename(name)) {
@@ -5801,7 +5819,7 @@ gb_internal AstPackage *try_add_import_path(Parser *p, String path, String const
for (FileInfo fi : list) {
String name = fi.name;
String ext = path_extension(name);
- if (ext == FILE_EXT) {
+ if (ext == FILE_EXT && !path_is_directory(name)) {
if (is_excluded_target_filename(name)) {
continue;
}
@@ -6147,7 +6165,7 @@ gb_internal String build_tag_get_token(String s, String *out) {
isize width = utf8_decode(&s[n], s.len-n, &rune);
if (n == 0 && rune == '!') {
- } else if (!rune_is_letter(rune) && !rune_is_digit(rune)) {
+ } else if (!rune_is_letter(rune) && !rune_is_digit(rune) && rune != ':') {
isize k = gb_max(gb_max(n, width), 1);
*out = substring(s, k, s.len);
return substring(s, 0, k);
@@ -6199,7 +6217,9 @@ gb_internal bool parse_build_tag(Token token_for_pos, String s) {
continue;
}
- TargetOsKind os = get_target_os_from_string(p);
+ Subtarget subtarget = Subtarget_Default;
+
+ TargetOsKind os = get_target_os_from_string(p, &subtarget);
TargetArchKind arch = get_target_arch_from_string(p);
num_tokens += 1;
@@ -6213,11 +6233,13 @@ gb_internal bool parse_build_tag(Token token_for_pos, String s) {
if (os != TargetOs_Invalid) {
this_kind_os_seen = true;
+ bool same_subtarget = (subtarget == Subtarget_Default) || (subtarget == selected_subtarget);
+
GB_ASSERT(arch == TargetArch_Invalid);
if (is_notted) {
- this_kind_correct = this_kind_correct && (os != build_context.metrics.os);
+ this_kind_correct = this_kind_correct && (os != build_context.metrics.os || !same_subtarget);
} else {
- this_kind_correct = this_kind_correct && (os == build_context.metrics.os);
+ this_kind_correct = this_kind_correct && (os == build_context.metrics.os && same_subtarget);
}
} else if (arch != TargetArch_Invalid) {
this_kind_arch_seen = true;
diff --git a/src/path.cpp b/src/path.cpp
index 2c08ddd98..d5e982088 100644
--- a/src/path.cpp
+++ b/src/path.cpp
@@ -30,28 +30,80 @@ gb_internal String remove_directory_from_path(String const &s) {
}
-// NOTE(Mark Naughton): getcwd as String
-#if !defined(GB_SYSTEM_WINDOWS)
-gb_internal String get_current_directory(void) {
- char cwd[256];
- getcwd(cwd, 256);
+#if defined(GB_SYSTEM_WINDOWS)
+gb_global SRWLOCK cwd_lock;
+
+String get_working_directory(gbAllocator allocator) {
+ AcquireSRWLockExclusive(&cwd_lock);
+
+ TEMPORARY_ALLOCATOR_GUARD();
+
+ DWORD sz_utf16 = GetCurrentDirectoryW(0, nullptr);
+ wchar_t *dir_buf_wstr = gb_alloc_array(temporary_allocator(), wchar_t, sz_utf16);
+ if (dir_buf_wstr == nullptr) {
+ ReleaseSRWLockExclusive(&cwd_lock);
+ return {};
+ }
+
+ DWORD n = GetCurrentDirectoryW(sz_utf16, dir_buf_wstr);
+ GB_ASSERT(n+1 == sz_utf16);
+ ReleaseSRWLockExclusive(&cwd_lock);
+
+
+ isize buf_len = sz_utf16*4;
+ u8 *buf = gb_alloc_array(allocator, u8, buf_len);
+ gb_ucs2_to_utf8(buf, buf_len, cast(u16 *)dir_buf_wstr);
+
+ return make_string_c(cast(char const *)buf);
+}
+
+bool set_working_directory(String dir) {
+ bool ok = false;
+ TEMPORARY_ALLOCATOR_GUARD();
+
+ char const *cdir = alloc_cstring(temporary_allocator(), dir);
+ wchar_t *wstr = gb__alloc_utf8_to_ucs2(temporary_allocator(), cdir, nullptr);
- return make_string_c(cwd);
+ AcquireSRWLockExclusive(&cwd_lock);
+
+ ok = SetCurrentDirectoryW(wstr);
+
+ ReleaseSRWLockExclusive(&cwd_lock);
+
+ return ok;
}
#else
-gb_internal String get_current_directory(void) {
- gbAllocator a = heap_allocator();
- wchar_t cwd[256];
- GetCurrentDirectoryW(256, cwd);
+String get_working_directory(gbAllocator allocator) {
+ TEMPORARY_ALLOCATOR_GUARD();
- String16 wstr = make_string16_c(cwd);
+ auto buf = array_make<char>(temporary_allocator());
+ size_t size = PATH_MAX;
- return string16_to_string(a, wstr);
+ char const *cwd = nullptr;
+ for (; cwd == nullptr; size *= 2) {
+ array_resize(&buf, size);
+
+ cwd = getcwd(buf.data, buf.count);
+ if (cwd == nullptr && errno != ERANGE) {
+ return {};
+ }
+ }
+
+ return copy_string(allocator, make_string_c(cwd));
+}
+
+bool set_working_directory(String dir) {
+ TEMPORARY_ALLOCATOR_GUARD();
+ char const *cdir = alloc_cstring(temporary_allocator(), dir);
+ return !chdir(cdir);
}
+
#endif
+
+
gb_internal bool path_is_directory(String path);
gb_internal String directory_from_path(String const &s) {
diff --git a/src/ptr_map.cpp b/src/ptr_map.cpp
index 1c157c386..61f703cf1 100644
--- a/src/ptr_map.cpp
+++ b/src/ptr_map.cpp
@@ -15,7 +15,7 @@ static void *const MAP_TOMBSTONE = (void *)~(uintptr)0;
template <typename K, typename V>
struct PtrMapEntry {
static_assert(sizeof(K) == sizeof(void *), "Key size must be pointer size");
-
+
K key;
V value;
};
@@ -374,7 +374,7 @@ struct PtrMapIterator {
}
bool operator==(PtrMapIterator<K, V> const &other) const noexcept {
- return this->map == other->map && this->index == other->index;
+ return this->map == other.map && this->index == other.index;
}
operator PtrMapEntry<K, V> *() const {
@@ -858,4 +858,4 @@ gb_internal OrderedInsertPtrMapEntry<K, V> *end(OrderedInsertPtrMap<K, V> &m) {
template <typename K, typename V>
gb_internal OrderedInsertPtrMapEntry<K, V> const *end(OrderedInsertPtrMap<K, V> const &m) {
return m.entries + m.count;
-} \ No newline at end of file
+}
diff --git a/src/ptr_set.cpp b/src/ptr_set.cpp
index ff4befc37..5097e2bb6 100644
--- a/src/ptr_set.cpp
+++ b/src/ptr_set.cpp
@@ -42,7 +42,7 @@ gb_internal void ptr_set_destroy(PtrSet<T> *s) {
template <typename T>
gb_internal isize ptr_set__find(PtrSet<T> *s, T ptr) {
- GB_ASSERT(ptr != nullptr);
+ GB_ASSERT(ptr != 0);
if (s->count != 0) {
#if 0
for (usize i = 0; i < s->capacity; i++) {
@@ -58,7 +58,7 @@ gb_internal isize ptr_set__find(PtrSet<T> *s, T ptr) {
T key = s->keys[hash_index];
if (key == ptr) {
return hash_index;
- } else if (key == nullptr) {
+ } else if (key == 0) {
return -1;
}
hash_index = (hash_index+1)&mask;
@@ -122,7 +122,7 @@ gb_internal bool ptr_set_update(PtrSet<T> *s, T ptr) { // returns true if it pre
for (usize i = 0; i < s->capacity; i++) {
T *key = &s->keys[hash_index];
GB_ASSERT(*key != ptr);
- if (*key == (T)PtrSet<T>::TOMBSTONE || *key == nullptr) {
+ if (*key == (T)PtrSet<T>::TOMBSTONE || *key == 0) {
*key = ptr;
s->count++;
return false;
@@ -169,7 +169,7 @@ struct PtrSetIterator {
return *this;
}
T key = set->keys[index];
- if (key != nullptr && key != (T)PtrSet<T>::TOMBSTONE) {
+ if (key != 0 && key != (T)PtrSet<T>::TOMBSTONE) {
return *this;
}
}
@@ -191,7 +191,7 @@ gb_internal PtrSetIterator<T> begin(PtrSet<T> &set) noexcept {
usize index = 0;
while (index < set.capacity) {
T key = set.keys[index];
- if (key != nullptr && key != (T)PtrSet<T>::TOMBSTONE) {
+ if (key != 0 && key != (T)PtrSet<T>::TOMBSTONE) {
break;
}
index++;
diff --git a/src/string.cpp b/src/string.cpp
index b001adf0e..ae8d066b1 100644
--- a/src/string.cpp
+++ b/src/string.cpp
@@ -273,6 +273,15 @@ gb_internal String path_extension(String const &str, bool include_dot = true) {
return substring(str, include_dot ? pos : pos + 1, str.len);
}
+
+gb_internal String path_remove_extension(String const &str) {
+ isize pos = string_extension_position(str);
+ if (pos < 0) {
+ return str;
+ }
+ return substring(str, 0, pos);
+}
+
gb_internal String string_trim_whitespace(String str) {
while (str.len > 0 && rune_is_whitespace(str[str.len-1])) {
str.len--;
@@ -327,6 +336,83 @@ gb_internal Array<String> split_lines_from_array(Array<u8> const &array, gbAlloc
return lines;
}
+enum : u32 { PRIME_RABIN_KARP = 16777619u };
+
+gb_internal u32 hash_str_rabin_karp(String const &s, u32 *pow_) {
+ u32 hash = 0;
+ u32 pow = 1;
+ for (isize i = 0; i < s.len; i++) {
+ hash = hash*PRIME_RABIN_KARP + cast(u32)s.text[i];
+ }
+ u32 sq = PRIME_RABIN_KARP;
+ for (isize i = s.len; i > 0; i >>= 1) {
+ if ((i & 1) != 0) {
+ pow *= sq;
+ }
+ sq *= sq;
+ }
+ if (pow_) *pow_ = pow;
+ return hash;
+
+}
+
+
+gb_internal isize string_index(String const &s, String const &substr) {
+ isize n = substr.len;
+ if (n == 0) {
+ return 0;
+ } else if (n == 1) {
+ return string_index_byte(s, substr[0]);
+ } else if (n == s.len) {
+ if (s == substr) {
+ return 0;
+ }
+ return -1;
+ } else if (n > s.len) {
+ return -1;
+ }
+ u32 pow = 1;
+ u32 hash = hash_str_rabin_karp(s, &pow);
+ u32 h = 0;
+ for (isize i = 0; i < n; i++) {
+ h = h*PRIME_RABIN_KARP + cast(u32)s.text[i];
+ }
+ if (h == hash && substring(s, 0, n) == substr) {
+ return 0;
+ }
+ for (isize i = n; i < s.len; /**/) {
+ h *= PRIME_RABIN_KARP;
+ h += cast(u32)s.text[i];
+ h -= pow * u32(s.text[i-n]);
+ i += 1;
+ if (h == hash && substring(s, i-n, i) == substr) {
+ return i - n;
+ }
+ }
+ return -1;
+}
+
+
+struct StringPartition {
+ String head;
+ String match;
+ String tail;
+};
+
+gb_internal StringPartition string_partition(String const &str, String const &sep) {
+ StringPartition res = {};
+ isize i = string_index(str, sep);
+ if (i < 0) {
+ res.head = str;
+ return res;
+ }
+
+ res.head = substring(str, 0, i);
+ res.match = substring(str, i, i+sep.len);
+ res.tail = substring(str, i+sep.len, str.len);
+ return res;
+}
+
gb_internal bool string_contains_char(String const &s, u8 c) {
isize i;
for (i = 0; i < s.len; i++) {
diff --git a/src/threading.cpp b/src/threading.cpp
index af8fd803c..a0d1c4049 100644
--- a/src/threading.cpp
+++ b/src/threading.cpp
@@ -756,7 +756,7 @@ gb_internal void futex_signal(Futex *f) {
perror("Futex wake");
GB_PANIC("futex wake fail");
- } else if (ret == 1) {
+ } else {
return;
}
}
@@ -773,7 +773,7 @@ gb_internal void futex_broadcast(Futex *f) {
perror("Futex wake");
GB_PANIC("futex wake fail");
- } else if (ret == 1) {
+ } else {
return;
}
}
@@ -783,7 +783,7 @@ gb_internal void futex_wait(Futex *f, Footex val) {
for (;;) {
int ret = futex((volatile uint32_t *)f, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, val, NULL, NULL);
if (ret == -1) {
- if (*f != val) {
+ if (errno == EAGAIN) {
return;
}
diff --git a/src/timings.cpp b/src/timings.cpp
index 3f8402b36..f6e86867f 100644
--- a/src/timings.cpp
+++ b/src/timings.cpp
@@ -197,7 +197,7 @@ gb_internal void timings_print_all(Timings *t, TimingUnit unit = TimingUnit_Mill
f64 total_time = time_stamp(t->total, t->freq, unit);
- gb_printf("%.*s%.*s - % 9.3f %s - %6.2f%%\n",
+ gb_printf_err("%.*s%.*s - % 9.3f %s - %6.2f%%\n",
LIT(t->total.label),
cast(int)(max_len-t->total.label.len), SPACES,
total_time,
@@ -207,7 +207,7 @@ gb_internal void timings_print_all(Timings *t, TimingUnit unit = TimingUnit_Mill
for_array(i, t->sections) {
TimeStamp ts = t->sections[i];
f64 section_time = time_stamp(ts, t->freq, unit);
- gb_printf("%.*s%.*s - % 9.3f %s - %6.2f%%\n",
+ gb_printf_err("%.*s%.*s - % 9.3f %s - %6.2f%%\n",
LIT(ts.label),
cast(int)(max_len-ts.label.len), SPACES,
section_time,
diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp
index 53f6135d0..ffa53abb5 100644
--- a/src/tokenizer.cpp
+++ b/src/tokenizer.cpp
@@ -968,6 +968,7 @@ gb_internal void tokenizer_get_token(Tokenizer *t, Token *token, int repeat=0) {
advance_to_next_rune(t);
for (isize comment_scope = 1; comment_scope > 0; /**/) {
if (t->curr_rune == GB_RUNE_EOF) {
+ tokenizer_err(t, "Multi-line comment not terminated");
break;
} else if (t->curr_rune == '/') {
advance_to_next_rune(t);
diff --git a/src/types.cpp b/src/types.cpp
index 233f903a3..74da7f6aa 100644
--- a/src/types.cpp
+++ b/src/types.cpp
@@ -1,5 +1,5 @@
-struct Scope;
struct Ast;
+struct Scope;
struct Entity;
enum BasicKind {
@@ -111,7 +111,7 @@ enum BasicFlag {
BasicFlag_Ordered = BasicFlag_Integer | BasicFlag_Float | BasicFlag_String | BasicFlag_Pointer | BasicFlag_Rune,
BasicFlag_OrderedNumeric = BasicFlag_Integer | BasicFlag_Float | BasicFlag_Rune,
BasicFlag_ConstantType = BasicFlag_Boolean | BasicFlag_Numeric | BasicFlag_String | BasicFlag_Pointer | BasicFlag_Rune,
- BasicFlag_SimpleCompare = BasicFlag_Boolean | BasicFlag_Numeric | BasicFlag_Pointer | BasicFlag_Rune,
+ BasicFlag_SimpleCompare = BasicFlag_Boolean | BasicFlag_Integer | BasicFlag_Pointer | BasicFlag_Rune,
};
struct BasicType {
@@ -161,10 +161,10 @@ struct TypeStruct {
struct TypeUnion {
Slice<Type *> variants;
-
+
Ast * node;
Scope * scope;
-
+
i64 variant_block_size;
i64 custom_align;
Type * polymorphic_params; // Type_Tuple
@@ -503,9 +503,9 @@ gb_global Type basic_types[] = {
{Type_Basic, {Basic_rawptr, BasicFlag_Pointer, -1, STR_LIT("rawptr")}},
{Type_Basic, {Basic_string, BasicFlag_String, -1, STR_LIT("string")}},
{Type_Basic, {Basic_cstring, BasicFlag_String, -1, STR_LIT("cstring")}},
- {Type_Basic, {Basic_any, 0, -1, STR_LIT("any")}},
+ {Type_Basic, {Basic_any, 0, 16, STR_LIT("any")}},
- {Type_Basic, {Basic_typeid, 0, -1, STR_LIT("typeid")}},
+ {Type_Basic, {Basic_typeid, 0, 8, STR_LIT("typeid")}},
// Endian
{Type_Basic, {Basic_i16le, BasicFlag_Integer | BasicFlag_EndianLittle, 2, STR_LIT("i16le")}},
@@ -729,10 +729,12 @@ gb_global Type *t_map_set_proc = nullptr;
gb_global Type *t_objc_object = nullptr;
gb_global Type *t_objc_selector = nullptr;
gb_global Type *t_objc_class = nullptr;
+gb_global Type *t_objc_ivar = nullptr;
gb_global Type *t_objc_id = nullptr;
gb_global Type *t_objc_SEL = nullptr;
gb_global Type *t_objc_Class = nullptr;
+gb_global Type *t_objc_Ivar = nullptr;
enum OdinAtomicMemoryOrder : i32 {
OdinAtomicMemoryOrder_relaxed = 0, // unordered
@@ -856,41 +858,29 @@ gb_internal void type_path_pop(TypePath *tp) {
#define FAILURE_SIZE 0
#define FAILURE_ALIGNMENT 0
-gb_internal bool type_ptr_set_exists(PtrSet<Type *> *s, Type *t);
-
-gb_internal bool type_ptr_set_update(PtrSet<Type *> *s, Type *t) {
- if (t == nullptr) {
- return true;
- }
- if (type_ptr_set_exists(s, t)) {
- return true;
+gb_internal Type *base_type(Type *t) {
+ for (;;) {
+ if (t == nullptr) {
+ break;
+ }
+ if (t->kind != Type_Named) {
+ break;
+ }
+ if (t == t->Named.base) {
+ return t_invalid;
+ }
+ t = t->Named.base;
}
- ptr_set_add(s, t);
- return false;
+ return t;
}
-gb_internal bool type_ptr_set_exists(PtrSet<Type *> *s, Type *t) {
- if (t == nullptr) {
- return true;
- }
-
- if (ptr_set_exists(s, t)) {
- return true;
- }
-
- // TODO(bill, 2019-10-05): This is very slow and it's probably a lot
- // faster to cache types correctly
- for (Type *f : *s) {
- if (are_types_identical(t, f)) {
- ptr_set_add(s, t);
- return true;
- }
+gb_internal Type *base_named_type(Type *t) {
+ if (t->kind != Type_Named) {
+ return t_invalid;
}
- return false;
-}
-
-gb_internal Type *base_type(Type *t) {
+ Type *prev_named = t;
+ t = t->Named.base;
for (;;) {
if (t == nullptr) {
break;
@@ -901,9 +891,10 @@ gb_internal Type *base_type(Type *t) {
if (t == t->Named.base) {
return t_invalid;
}
+ prev_named = t;
t = t->Named.base;
}
- return t;
+ return prev_named;
}
gb_internal Type *base_enum_type(Type *t) {
@@ -1212,6 +1203,7 @@ gb_internal Type *type_deref(Type *t, bool allow_multi_pointer) {
}
gb_internal bool is_type_named(Type *t) {
+ if (t == nullptr) { return false; }
if (t->kind == Type_Basic) {
return true;
}
@@ -1221,6 +1213,7 @@ gb_internal bool is_type_named(Type *t) {
gb_internal bool is_type_boolean(Type *t) {
// t = core_type(t);
t = base_type(t);
+ if (t == nullptr) { return false; }
if (t->kind == Type_Basic) {
return (t->Basic.flags & BasicFlag_Boolean) != 0;
}
@@ -1229,6 +1222,7 @@ gb_internal bool is_type_boolean(Type *t) {
gb_internal bool is_type_integer(Type *t) {
// t = core_type(t);
t = base_type(t);
+ if (t == nullptr) { return false; }
if (t->kind == Type_Basic) {
return (t->Basic.flags & BasicFlag_Integer) != 0;
}
@@ -1250,15 +1244,18 @@ gb_internal bool is_type_integer_like(Type *t) {
gb_internal bool is_type_unsigned(Type *t) {
t = base_type(t);
- // t = core_type(t);
+ if (t == nullptr) { return false; }
if (t->kind == Type_Basic) {
return (t->Basic.flags & BasicFlag_Unsigned) != 0;
}
+ if (t->kind == Type_Enum) {
+ return (t->Enum.base_type->Basic.flags & BasicFlag_Unsigned) != 0;
+ }
return false;
}
gb_internal bool is_type_integer_128bit(Type *t) {
- // t = core_type(t);
t = base_type(t);
+ if (t == nullptr) { return false; }
if (t->kind == Type_Basic) {
return (t->Basic.flags & BasicFlag_Integer) != 0 && t->Basic.size == 16;
}
@@ -1267,6 +1264,7 @@ gb_internal bool is_type_integer_128bit(Type *t) {
gb_internal bool is_type_rune(Type *t) {
// t = core_type(t);
t = base_type(t);
+ if (t == nullptr) { return false; }
if (t->kind == Type_Basic) {
return (t->Basic.flags & BasicFlag_Rune) != 0;
}
@@ -1275,6 +1273,7 @@ gb_internal bool is_type_rune(Type *t) {
gb_internal bool is_type_numeric(Type *t) {
// t = core_type(t);
t = base_type(t);
+ if (t == nullptr) { return false; }
if (t->kind == Type_Basic) {
return (t->Basic.flags & BasicFlag_Numeric) != 0;
} else if (t->kind == Type_Enum) {
@@ -1288,6 +1287,7 @@ gb_internal bool is_type_numeric(Type *t) {
}
gb_internal bool is_type_string(Type *t) {
t = base_type(t);
+ if (t == nullptr) { return false; }
if (t->kind == Type_Basic) {
return (t->Basic.flags & BasicFlag_String) != 0;
}
@@ -1295,6 +1295,7 @@ gb_internal bool is_type_string(Type *t) {
}
gb_internal bool is_type_cstring(Type *t) {
t = base_type(t);
+ if (t == nullptr) { return false; }
if (t->kind == Type_Basic) {
return t->Basic.kind == Basic_cstring;
}
@@ -1302,9 +1303,7 @@ gb_internal bool is_type_cstring(Type *t) {
}
gb_internal bool is_type_typed(Type *t) {
t = base_type(t);
- if (t == nullptr) {
- return false;
- }
+ if (t == nullptr) { return false; }
if (t->kind == Type_Basic) {
return (t->Basic.flags & BasicFlag_Untyped) == 0;
}
@@ -1312,9 +1311,7 @@ gb_internal bool is_type_typed(Type *t) {
}
gb_internal bool is_type_untyped(Type *t) {
t = base_type(t);
- if (t == nullptr) {
- return false;
- }
+ if (t == nullptr) { return false; }
if (t->kind == Type_Basic) {
return (t->Basic.flags & BasicFlag_Untyped) != 0;
}
@@ -1322,6 +1319,7 @@ gb_internal bool is_type_untyped(Type *t) {
}
gb_internal bool is_type_ordered(Type *t) {
t = core_type(t);
+ if (t == nullptr) { return false; }
switch (t->kind) {
case Type_Basic:
return (t->Basic.flags & BasicFlag_Ordered) != 0;
@@ -1334,6 +1332,7 @@ gb_internal bool is_type_ordered(Type *t) {
}
gb_internal bool is_type_ordered_numeric(Type *t) {
t = core_type(t);
+ if (t == nullptr) { return false; }
switch (t->kind) {
case Type_Basic:
return (t->Basic.flags & BasicFlag_OrderedNumeric) != 0;
@@ -1342,6 +1341,7 @@ gb_internal bool is_type_ordered_numeric(Type *t) {
}
gb_internal bool is_type_constant_type(Type *t) {
t = core_type(t);
+ if (t == nullptr) { return false; }
if (t->kind == Type_Basic) {
return (t->Basic.flags & BasicFlag_ConstantType) != 0;
}
@@ -1355,6 +1355,7 @@ gb_internal bool is_type_constant_type(Type *t) {
}
gb_internal bool is_type_float(Type *t) {
t = core_type(t);
+ if (t == nullptr) { return false; }
if (t->kind == Type_Basic) {
return (t->Basic.flags & BasicFlag_Float) != 0;
}
@@ -1362,6 +1363,7 @@ gb_internal bool is_type_float(Type *t) {
}
gb_internal bool is_type_complex(Type *t) {
t = core_type(t);
+ if (t == nullptr) { return false; }
if (t->kind == Type_Basic) {
return (t->Basic.flags & BasicFlag_Complex) != 0;
}
@@ -1369,6 +1371,7 @@ gb_internal bool is_type_complex(Type *t) {
}
gb_internal bool is_type_quaternion(Type *t) {
t = core_type(t);
+ if (t == nullptr) { return false; }
if (t->kind == Type_Basic) {
return (t->Basic.flags & BasicFlag_Quaternion) != 0;
}
@@ -1376,6 +1379,7 @@ gb_internal bool is_type_quaternion(Type *t) {
}
gb_internal bool is_type_complex_or_quaternion(Type *t) {
t = core_type(t);
+ if (t == nullptr) { return false; }
if (t->kind == Type_Basic) {
return (t->Basic.flags & (BasicFlag_Complex|BasicFlag_Quaternion)) != 0;
}
@@ -1383,6 +1387,7 @@ gb_internal bool is_type_complex_or_quaternion(Type *t) {
}
gb_internal bool is_type_pointer(Type *t) {
t = base_type(t);
+ if (t == nullptr) { return false; }
if (t->kind == Type_Basic) {
return (t->Basic.flags & BasicFlag_Pointer) != 0;
}
@@ -1390,10 +1395,12 @@ gb_internal bool is_type_pointer(Type *t) {
}
gb_internal bool is_type_soa_pointer(Type *t) {
t = base_type(t);
+ if (t == nullptr) { return false; }
return t->kind == Type_SoaPointer;
}
gb_internal bool is_type_multi_pointer(Type *t) {
t = base_type(t);
+ if (t == nullptr) { return false; }
return t->kind == Type_MultiPointer;
}
gb_internal bool is_type_internally_pointer_like(Type *t) {
@@ -1402,6 +1409,7 @@ gb_internal bool is_type_internally_pointer_like(Type *t) {
gb_internal bool is_type_tuple(Type *t) {
t = base_type(t);
+ if (t == nullptr) { return false; }
return t->kind == Type_Tuple;
}
gb_internal bool is_type_uintptr(Type *t) {
@@ -1424,21 +1432,24 @@ gb_internal bool is_type_u8(Type *t) {
}
gb_internal bool is_type_array(Type *t) {
t = base_type(t);
+ if (t == nullptr) { return false; }
return t->kind == Type_Array;
}
gb_internal bool is_type_enumerated_array(Type *t) {
t = base_type(t);
+ if (t == nullptr) { return false; }
return t->kind == Type_EnumeratedArray;
}
gb_internal bool is_type_matrix(Type *t) {
t = base_type(t);
+ if (t == nullptr) { return false; }
return t->kind == Type_Matrix;
}
gb_internal i64 matrix_align_of(Type *t, struct TypePath *tp) {
t = base_type(t);
GB_ASSERT(t->kind == Type_Matrix);
-
+
Type *elem = t->Matrix.elem;
i64 row_count = gb_max(t->Matrix.row_count, 1);
i64 column_count = gb_max(t->Matrix.column_count, 1);
@@ -1450,15 +1461,15 @@ gb_internal i64 matrix_align_of(Type *t, struct TypePath *tp) {
i64 elem_align = type_align_of_internal(elem, tp);
if (pop) type_path_pop(tp);
-
+
i64 elem_size = type_size_of(elem);
-
+
// NOTE(bill, 2021-10-25): The alignment strategy here is to have zero padding
// It would be better for performance to pad each column so that each column
// could be maximally aligned but as a compromise, having no padding will be
// beneficial to third libraries that assume no padding
-
+
i64 total_expected_size = row_count*column_count*elem_size;
// i64 min_alignment = prev_pow2(elem_align * row_count);
i64 min_alignment = prev_pow2(total_expected_size);
@@ -1466,7 +1477,7 @@ gb_internal i64 matrix_align_of(Type *t, struct TypePath *tp) {
min_alignment >>= 1;
}
min_alignment = gb_max(min_alignment, elem_align);
-
+
i64 align = gb_min(min_alignment, build_context.max_simd_align);
return align;
}
@@ -1480,7 +1491,7 @@ gb_internal i64 matrix_type_stride_in_bytes(Type *t, struct TypePath *tp) {
} else if (t->Matrix.row_count == 0) {
return 0;
}
-
+
i64 elem_size;
if (tp != nullptr) {
elem_size = type_size_of_internal(t->Matrix.elem, tp);
@@ -1489,7 +1500,7 @@ gb_internal i64 matrix_type_stride_in_bytes(Type *t, struct TypePath *tp) {
}
i64 stride_in_bytes = 0;
-
+
// NOTE(bill, 2021-10-25): The alignment strategy here is to have zero padding
// It would be better for performance to pad each column/row so that each column/row
// could be maximally aligned but as a compromise, having no padding will be
@@ -1545,7 +1556,7 @@ gb_internal i64 matrix_row_major_index_to_offset(Type *t, i64 index) {
gb_internal i64 matrix_column_major_index_to_offset(Type *t, i64 index) {
t = base_type(t);
GB_ASSERT(t->kind == Type_Matrix);
-
+
i64 row_index = index%t->Matrix.row_count;
i64 column_index = index/t->Matrix.row_count;
return matrix_indices_to_offset(t, row_index, column_index);
@@ -1566,7 +1577,7 @@ gb_internal bool is_type_valid_for_matrix_elems(Type *t) {
return true;
} else if (is_type_complex(t)) {
return true;
- }
+ }
if (t->kind == Type_Generic) {
return true;
}
@@ -1575,22 +1586,27 @@ gb_internal bool is_type_valid_for_matrix_elems(Type *t) {
gb_internal bool is_type_dynamic_array(Type *t) {
t = base_type(t);
+ if (t == nullptr) { return false; }
return t->kind == Type_DynamicArray;
}
gb_internal bool is_type_slice(Type *t) {
t = base_type(t);
+ if (t == nullptr) { return false; }
return t->kind == Type_Slice;
}
gb_internal bool is_type_proc(Type *t) {
t = base_type(t);
+ if (t == nullptr) { return false; }
return t->kind == Type_Proc;
}
gb_internal bool is_type_asm_proc(Type *t) {
t = base_type(t);
+ if (t == nullptr) { return false; }
return t->kind == Type_Proc && t->Proc.calling_convention == ProcCC_InlineAsm;
}
gb_internal bool is_type_simd_vector(Type *t) {
t = base_type(t);
+ if (t == nullptr) { return false; }
return t->kind == Type_SimdVector;
}
@@ -1630,11 +1646,13 @@ gb_internal Type *base_any_array_type(Type *t) {
gb_internal bool is_type_generic(Type *t) {
t = base_type(t);
+ if (t == nullptr) { return false; }
return t->kind == Type_Generic;
}
gb_internal bool is_type_u8_slice(Type *t) {
t = base_type(t);
+ if (t == nullptr) { return false; }
if (t->kind == Type_Slice) {
return is_type_u8(t->Slice.elem);
}
@@ -1642,6 +1660,7 @@ gb_internal bool is_type_u8_slice(Type *t) {
}
gb_internal bool is_type_u8_array(Type *t) {
t = base_type(t);
+ if (t == nullptr) { return false; }
if (t->kind == Type_Array) {
return is_type_u8(t->Array.elem);
}
@@ -1649,6 +1668,7 @@ gb_internal bool is_type_u8_array(Type *t) {
}
gb_internal bool is_type_u8_ptr(Type *t) {
t = base_type(t);
+ if (t == nullptr) { return false; }
if (t->kind == Type_Pointer) {
return is_type_u8(t->Slice.elem);
}
@@ -1656,6 +1676,7 @@ gb_internal bool is_type_u8_ptr(Type *t) {
}
gb_internal bool is_type_u8_multi_ptr(Type *t) {
t = base_type(t);
+ if (t == nullptr) { return false; }
if (t->kind == Type_MultiPointer) {
return is_type_u8(t->Slice.elem);
}
@@ -1663,6 +1684,7 @@ gb_internal bool is_type_u8_multi_ptr(Type *t) {
}
gb_internal bool is_type_rune_array(Type *t) {
t = base_type(t);
+ if (t == nullptr) { return false; }
if (t->kind == Type_Array) {
return is_type_rune(t->Array.elem);
}
@@ -1801,6 +1823,27 @@ gb_internal bool is_type_union_maybe_pointer_original_alignment(Type *t) {
}
+enum TypeEndianKind {
+ TypeEndian_Platform,
+ TypeEndian_Little,
+ TypeEndian_Big,
+};
+
+gb_internal TypeEndianKind type_endian_kind_of(Type *t) {
+ t = core_type(t);
+ if (t->kind == Type_Basic) {
+ if (t->Basic.flags & BasicFlag_EndianLittle) {
+ return TypeEndian_Little;
+ }
+ if (t->Basic.flags & BasicFlag_EndianBig) {
+ return TypeEndian_Big;
+ }
+ } else if (t->kind == Type_BitSet) {
+ return type_endian_kind_of(bit_set_to_int(t));
+ }
+ return TypeEndian_Platform;
+}
+
gb_internal bool is_type_endian_big(Type *t) {
t = core_type(t);
@@ -1967,7 +2010,13 @@ gb_internal bool is_type_untyped_uninit(Type *t) {
}
gb_internal bool is_type_empty_union(Type *t) {
+ if (t == nullptr) {
+ return false;
+ }
t = base_type(t);
+ if (t == nullptr) {
+ return false;
+ }
return t->kind == Type_Union && t->Union.variants.count == 0;
}
@@ -2098,6 +2147,26 @@ gb_internal bool is_type_sliceable(Type *t) {
return false;
}
+gb_internal Entity *type_get_polymorphic_parent(Type *t, Type **params_) {
+ t = base_type(t);
+ if (t == nullptr) {
+ return nullptr;
+ }
+ Type *parent = nullptr;
+ if (t->kind == Type_Struct) {
+ parent = t->Struct.polymorphic_parent;
+ if (params_) *params_ = t->Struct.polymorphic_params;
+ } else if (t->kind == Type_Union) {
+ parent = t->Union.polymorphic_parent;
+ if (params_) *params_ = t->Union.polymorphic_params;
+ }
+ if (parent != nullptr) {
+ GB_ASSERT(parent->kind == Type_Named);
+
+ return parent->Named.type_name;
+ }
+ return nullptr;
+}
gb_internal bool is_type_polymorphic_record(Type *t) {
t = base_type(t);
@@ -2464,7 +2533,7 @@ gb_internal bool is_type_simple_compare(Type *t) {
case Type_Proc:
case Type_BitSet:
return true;
-
+
case Type_Matrix:
return is_type_simple_compare(t->Matrix.elem);
@@ -2636,7 +2705,7 @@ gb_internal bool are_types_identical(Type *x, Type *y) {
y = y->Named.base;
}
}
- if (x->kind != y->kind) {
+ if (x == nullptr || y == nullptr || x->kind != y->kind) {
return false;
}
@@ -2711,7 +2780,7 @@ gb_internal bool are_types_identical_internal(Type *x, Type *y, bool check_tuple
case Type_Array:
return (x->Array.count == y->Array.count) && are_types_identical(x->Array.elem, y->Array.elem);
-
+
case Type_Matrix:
return x->Matrix.row_count == y->Matrix.row_count &&
x->Matrix.column_count == y->Matrix.column_count &&
@@ -2736,7 +2805,37 @@ gb_internal bool are_types_identical_internal(Type *x, Type *y, bool check_tuple
case Type_Enum:
- return x == y; // NOTE(bill): All enums are unique
+ if (x == y) {
+ return true;
+ }
+ if (x->Enum.fields.count != y->Enum.fields.count) {
+ return false;
+ }
+ if (!are_types_identical(x->Enum.base_type, y->Enum.base_type)) {
+ return false;
+ }
+ if (x->Enum.min_value_index != y->Enum.min_value_index) {
+ return false;
+ }
+ if (x->Enum.max_value_index != y->Enum.max_value_index) {
+ return false;
+ }
+
+ for (isize i = 0; i < x->Enum.fields.count; i++) {
+ Entity *a = x->Enum.fields[i];
+ Entity *b = y->Enum.fields[i];
+ if (a->token.string != b->token.string) {
+ return false;
+ }
+ GB_ASSERT(a->kind == b->kind);
+ GB_ASSERT(a->kind == Entity_Constant);
+ bool same = compare_exact_values(Token_CmpEq, a->Constant.value, b->Constant.value);
+ if (!same) {
+ return false;
+ }
+ }
+
+ return true;
case Type_Union:
if (x->Union.variants.count == y->Union.variants.count &&
@@ -2794,7 +2893,9 @@ gb_internal bool are_types_identical_internal(Type *x, Type *y, bool check_tuple
return false;
}
}
- return are_types_identical(x->Struct.polymorphic_params, y->Struct.polymorphic_params);
+ // TODO(bill): Which is the correct logic here?
+ // return are_types_identical(x->Struct.polymorphic_params, y->Struct.polymorphic_params);
+ return true;
}
break;
@@ -2893,6 +2994,10 @@ gb_internal Type *default_type(Type *type) {
case Basic_UntypedString: return t_string;
case Basic_UntypedRune: return t_rune;
}
+ } else if (type->kind == Type_Generic) {
+ if (type->Generic.specialized) {
+ return default_type(type->Generic.specialized);
+ }
}
return type;
}
@@ -2991,11 +3096,15 @@ gb_internal i64 union_tag_size(Type *u) {
compiler_error("how many variants do you have?! %lld", cast(long long)u->Union.variants.count);
}
- for_array(i, u->Union.variants) {
- Type *variant_type = u->Union.variants[i];
- i64 align = type_align_of(variant_type);
- if (max_align < align) {
- max_align = align;
+ if (u->Union.custom_align > 0) {
+ max_align = gb_max(max_align, u->Union.custom_align);
+ } else {
+ for_array(i, u->Union.variants) {
+ Type *variant_type = u->Union.variants[i];
+ i64 align = type_align_of(variant_type);
+ if (max_align < align) {
+ max_align = align;
+ }
}
}
@@ -3288,6 +3397,15 @@ gb_internal Selection lookup_field_with_selection(Type *type_, String field_name
}
}
}
+
+ Type *objc_ivar_type = e->TypeName.objc_ivar;
+ if (objc_ivar_type != nullptr) {
+ sel = lookup_field_with_selection(objc_ivar_type, field_name, false, sel, allow_blank_ident);
+ if (sel.entity != nullptr) {
+ sel.pseudo_field = true;
+ return sel;
+ }
+ }
}
if (is_type_polymorphic(type)) {
@@ -3571,7 +3689,7 @@ gb_internal bool are_struct_fields_reordered(Type *type) {
return false;
}
GB_ASSERT(type->Struct.offsets != nullptr);
-
+
i64 prev_offset = 0;
for_array(i, type->Struct.fields) {
i64 offset = type->Struct.offsets[i];
@@ -3592,9 +3710,9 @@ gb_internal Slice<i32> struct_fields_index_by_increasing_offset(gbAllocator allo
return {};
}
GB_ASSERT(type->Struct.offsets != nullptr);
-
+
auto indices = slice_make<i32>(allocator, type->Struct.fields.count);
-
+
i64 prev_offset = 0;
bool is_ordered = true;
for_array(i, indices) {
@@ -3609,14 +3727,14 @@ gb_internal Slice<i32> struct_fields_index_by_increasing_offset(gbAllocator allo
isize n = indices.count;
for (isize i = 1; i < n; i++) {
isize j = i;
-
+
while (j > 0 && type->Struct.offsets[indices[j-1]] > type->Struct.offsets[indices[j]]) {
gb_swap(i32, indices[j-1], indices[j]);
j -= 1;
- }
+ }
}
}
-
+
return indices;
}
@@ -3664,8 +3782,8 @@ gb_internal i64 type_size_of(Type *t) {
switch (t->Basic.kind) {
case Basic_string: size = 2*build_context.int_size; break;
case Basic_cstring: size = build_context.ptr_size; break;
- case Basic_any: size = 2*build_context.ptr_size; break;
- case Basic_typeid: size = build_context.ptr_size; break;
+ case Basic_any: size = 16; break;
+ case Basic_typeid: size = 8; break;
case Basic_int: case Basic_uint:
size = build_context.int_size;
@@ -3727,8 +3845,8 @@ gb_internal i64 type_align_of_internal(Type *t, TypePath *path) {
switch (t->Basic.kind) {
case Basic_string: return build_context.int_size;
case Basic_cstring: return build_context.ptr_size;
- case Basic_any: return build_context.ptr_size;
- case Basic_typeid: return build_context.ptr_size;
+ case Basic_any: return 8;
+ case Basic_typeid: return 8;
case Basic_int: case Basic_uint:
return build_context.int_size;
@@ -3866,8 +3984,8 @@ gb_internal i64 type_align_of_internal(Type *t, TypePath *path) {
// IMPORTANT TODO(bill): Figure out the alignment of vector types
return gb_clamp(next_pow2(type_size_of_internal(t, path)), 1, build_context.max_simd_align*2);
}
-
- case Type_Matrix:
+
+ case Type_Matrix:
return matrix_align_of(t, path);
case Type_SoaPointer:
@@ -3978,8 +4096,8 @@ gb_internal i64 type_size_of_internal(Type *t, TypePath *path) {
switch (kind) {
case Basic_string: return 2*build_context.int_size;
case Basic_cstring: return build_context.ptr_size;
- case Basic_any: return 2*build_context.ptr_size;
- case Basic_typeid: return build_context.ptr_size;
+ case Basic_any: return 16;
+ case Basic_typeid: return 8;
case Basic_int: case Basic_uint:
return build_context.int_size;
@@ -4069,10 +4187,10 @@ gb_internal i64 type_size_of_internal(Type *t, TypePath *path) {
}
i64 max = 0;
- i64 field_size = 0;
for_array(i, t->Union.variants) {
Type *variant_type = t->Union.variants[i];
+
i64 size = type_size_of_internal(variant_type, path);
if (max < size) {
max = size;
@@ -4091,7 +4209,7 @@ gb_internal i64 type_size_of_internal(Type *t, TypePath *path) {
size = align_formula(max, tag_size);
// NOTE(bill): Calculate the padding between the common fields and the tag
t->Union.tag_size = cast(i16)tag_size;
- t->Union.variant_block_size = size - field_size;
+ t->Union.variant_block_size = size;
size += tag_size;
}
@@ -4154,7 +4272,7 @@ gb_internal i64 type_size_of_internal(Type *t, TypePath *path) {
Type *elem = t->SimdVector.elem;
return count * type_size_of_internal(elem, path);
}
-
+
case Type_Matrix: {
i64 stride_in_bytes = matrix_type_stride_in_bytes(t, path);
if (t->Matrix.is_row_major) {
@@ -4215,7 +4333,7 @@ gb_internal i64 type_offset_of(Type *t, i64 index, Type **field_type_) {
return 0; // data
case 1:
if (field_type_) *field_type_ = t_typeid;
- return build_context.ptr_size; // id
+ return 8; // id
}
}
break;
@@ -4286,8 +4404,8 @@ gb_internal i64 type_offset_of_from_selection(Type *type, Selection sel) {
}
} else if (t->Basic.kind == Basic_any) {
switch (index) {
- case 0: t = t_type_info_ptr; break;
- case 1: t = t_rawptr; break;
+ case 0: t = t_rawptr; break;
+ case 1: t = t_typeid; break;
}
}
break;
@@ -4503,7 +4621,84 @@ gb_internal Type *alloc_type_proc_from_types(Type **param_types, unsigned param_
// return type;
// }
-gb_internal gbString write_type_to_string(gbString str, Type *type, bool shorthand=false) {
+// Index a type that is internally a struct or array.
+gb_internal Type *type_internal_index(Type *t, isize index) {
+ Type *bt = base_type(t);
+ if (bt == nullptr) {
+ return nullptr;
+ }
+
+ switch (bt->kind) {
+ case Type_Basic:
+ {
+ switch (bt->Basic.kind) {
+ case Basic_complex32: return t_f16;
+ case Basic_complex64: return t_f32;
+ case Basic_complex128: return t_f64;
+ case Basic_quaternion64: return t_f16;
+ case Basic_quaternion128: return t_f32;
+ case Basic_quaternion256: return t_f64;
+ case Basic_string:
+ {
+ GB_ASSERT(index == 0 || index == 1);
+ return index == 0 ? t_u8_ptr : t_int;
+ }
+ case Basic_any:
+ {
+ GB_ASSERT(index == 0 || index == 1);
+ return index == 0 ? t_rawptr : t_typeid;
+ }
+ }
+ }
+ break;
+
+ case Type_Array: return bt->Array.elem;
+ case Type_EnumeratedArray: return bt->EnumeratedArray.elem;
+ case Type_SimdVector: return bt->SimdVector.elem;
+ case Type_Slice:
+ {
+ GB_ASSERT(index == 0 || index == 1);
+ return index == 0 ? t_rawptr : t_typeid;
+ }
+ case Type_DynamicArray:
+ {
+ switch (index) {
+ case 0: return t_rawptr;
+ case 1: return t_int;
+ case 2: return t_int;
+ case 3: return t_allocator;
+ default: GB_PANIC("invalid raw dynamic array index");
+ };
+ }
+ case Type_Struct:
+ return get_struct_field_type(bt, index);
+ case Type_Union:
+ if (index < bt->Union.variants.count) {
+ return bt->Union.variants[index];
+ }
+ return union_tag_type(bt);
+ case Type_Tuple:
+ return bt->Tuple.variables[index]->type;
+ case Type_Matrix:
+ return bt->Matrix.elem;
+ case Type_SoaPointer:
+ {
+ GB_ASSERT(index == 0 || index == 1);
+ return index == 0 ? t_rawptr : t_int;
+ }
+ case Type_Map:
+ return type_internal_index(bt->Map.debug_metadata_type, index);
+ case Type_BitField:
+ return type_internal_index(bt->BitField.backing_type, index);
+ case Type_Generic:
+ return type_internal_index(bt->Generic.specialized, index);
+ };
+
+ GB_PANIC("Unhandled type %s", type_to_string(bt));
+ return nullptr;
+};
+
+gb_internal gbString write_type_to_string(gbString str, Type *type, bool shorthand=false, bool allow_polymorphic=false) {
if (type == nullptr) {
return gb_string_appendc(str, "<no type>");
}
@@ -4528,24 +4723,24 @@ gb_internal gbString write_type_to_string(gbString str, Type *type, bool shortha
str = gb_string_append_length(str, name.text, name.len);
if (type->Generic.specialized != nullptr) {
str = gb_string_append_rune(str, '/');
- str = write_type_to_string(str, type->Generic.specialized);
+ str = write_type_to_string(str, type->Generic.specialized, shorthand, allow_polymorphic);
}
}
break;
case Type_Pointer:
str = gb_string_append_rune(str, '^');
- str = write_type_to_string(str, type->Pointer.elem);
+ str = write_type_to_string(str, type->Pointer.elem, shorthand, allow_polymorphic);
break;
case Type_SoaPointer:
str = gb_string_appendc(str, "#soa ^");
- str = write_type_to_string(str, type->SoaPointer.elem);
+ str = write_type_to_string(str, type->SoaPointer.elem, shorthand, allow_polymorphic);
break;
case Type_MultiPointer:
str = gb_string_appendc(str, "[^]");
- str = write_type_to_string(str, type->Pointer.elem);
+ str = write_type_to_string(str, type->Pointer.elem, shorthand, allow_polymorphic);
break;
case Type_EnumeratedArray:
@@ -4553,31 +4748,31 @@ gb_internal gbString write_type_to_string(gbString str, Type *type, bool shortha
str = gb_string_appendc(str, "#sparse");
}
str = gb_string_append_rune(str, '[');
- str = write_type_to_string(str, type->EnumeratedArray.index);
+ str = write_type_to_string(str, type->EnumeratedArray.index, shorthand, allow_polymorphic);
str = gb_string_append_rune(str, ']');
- str = write_type_to_string(str, type->EnumeratedArray.elem);
+ str = write_type_to_string(str, type->EnumeratedArray.elem, shorthand, allow_polymorphic);
break;
case Type_Array:
- str = gb_string_appendc(str, gb_bprintf("[%d]", cast(int)type->Array.count));
- str = write_type_to_string(str, type->Array.elem);
+ str = gb_string_appendc(str, gb_bprintf("[%lld]", cast(long long)type->Array.count));
+ str = write_type_to_string(str, type->Array.elem, shorthand, allow_polymorphic);
break;
case Type_Slice:
str = gb_string_appendc(str, "[]");
- str = write_type_to_string(str, type->Array.elem);
+ str = write_type_to_string(str, type->Array.elem, shorthand, allow_polymorphic);
break;
case Type_DynamicArray:
str = gb_string_appendc(str, "[dynamic]");
- str = write_type_to_string(str, type->DynamicArray.elem);
+ str = write_type_to_string(str, type->DynamicArray.elem, shorthand, allow_polymorphic);
break;
case Type_Enum:
str = gb_string_appendc(str, "enum");
if (type->Enum.base_type != nullptr) {
str = gb_string_appendc(str, " ");
- str = write_type_to_string(str, type->Enum.base_type);
+ str = write_type_to_string(str, type->Enum.base_type, shorthand, allow_polymorphic);
}
str = gb_string_appendc(str, " {");
for_array(i, type->Enum.fields) {
@@ -4594,6 +4789,13 @@ gb_internal gbString write_type_to_string(gbString str, Type *type, bool shortha
case Type_Union:
str = gb_string_appendc(str, "union");
+
+ if (allow_polymorphic && type->Struct.polymorphic_params) {
+ str = gb_string_appendc(str, "(");
+ str = write_type_to_string(str, type->Struct.polymorphic_params, shorthand, allow_polymorphic);
+ str = gb_string_appendc(str, ")");
+ }
+
switch (type->Union.kind) {
case UnionType_no_nil: str = gb_string_appendc(str, " #no_nil"); break;
case UnionType_shared_nil: str = gb_string_appendc(str, " #shared_nil"); break;
@@ -4603,7 +4805,7 @@ gb_internal gbString write_type_to_string(gbString str, Type *type, bool shortha
for_array(i, type->Union.variants) {
Type *t = type->Union.variants[i];
if (i > 0) str = gb_string_appendc(str, ", ");
- str = write_type_to_string(str, t);
+ str = write_type_to_string(str, t, shorthand, allow_polymorphic);
}
str = gb_string_append_rune(str, '}');
break;
@@ -4616,17 +4818,24 @@ gb_internal gbString write_type_to_string(gbString str, Type *type, bool shortha
case StructSoa_Dynamic: str = gb_string_appendc(str, "#soa[dynamic]"); break;
default: GB_PANIC("Unknown StructSoaKind"); break;
}
- str = write_type_to_string(str, type->Struct.soa_elem);
+ str = write_type_to_string(str, type->Struct.soa_elem, shorthand, allow_polymorphic);
break;
}
str = gb_string_appendc(str, "struct");
+
+ if (allow_polymorphic && type->Struct.polymorphic_params) {
+ str = gb_string_appendc(str, "(");
+ str = write_type_to_string(str, type->Struct.polymorphic_params, shorthand, allow_polymorphic);
+ str = gb_string_appendc(str, ")");
+ }
+
if (type->Struct.is_packed) str = gb_string_appendc(str, " #packed");
if (type->Struct.is_raw_union) str = gb_string_appendc(str, " #raw_union");
if (type->Struct.is_no_copy) str = gb_string_appendc(str, " #no_copy");
if (type->Struct.custom_align != 0) str = gb_string_append_fmt(str, " #align %d", cast(int)type->Struct.custom_align);
- str = gb_string_appendc(str, " {");
+ str = gb_string_appendc(str, " {");
if (shorthand && type->Struct.fields.count > 16) {
str = gb_string_append_fmt(str, "%lld fields...", cast(long long)type->Struct.fields.count);
@@ -4639,7 +4848,7 @@ gb_internal gbString write_type_to_string(gbString str, Type *type, bool shortha
}
str = gb_string_append_length(str, f->token.string.text, f->token.string.len);
str = gb_string_appendc(str, ": ");
- str = write_type_to_string(str, f->type);
+ str = write_type_to_string(str, f->type, shorthand, allow_polymorphic);
}
}
str = gb_string_append_rune(str, '}');
@@ -4647,9 +4856,9 @@ gb_internal gbString write_type_to_string(gbString str, Type *type, bool shortha
case Type_Map: {
str = gb_string_appendc(str, "map[");
- str = write_type_to_string(str, type->Map.key);
+ str = write_type_to_string(str, type->Map.key, shorthand, allow_polymorphic);
str = gb_string_append_rune(str, ']');
- str = write_type_to_string(str, type->Map.value);
+ str = write_type_to_string(str, type->Map.value, shorthand, allow_polymorphic);
} break;
case Type_Named:
@@ -4679,9 +4888,11 @@ gb_internal gbString write_type_to_string(gbString str, Type *type, bool shortha
str = gb_string_append_length(str, name.text, name.len);
if (!is_type_untyped(var->type)) {
str = gb_string_appendc(str, ": ");
- str = write_type_to_string(str, var->type);
- str = gb_string_appendc(str, " = ");
- str = write_exact_value_to_string(str, var->Constant.value);
+ str = write_type_to_string(str, var->type, shorthand, allow_polymorphic);
+ if (var->Constant.value.kind) {
+ str = gb_string_appendc(str, " = ");
+ str = write_exact_value_to_string(str, var->Constant.value);
+ }
} else {
str = gb_string_appendc(str, " := ");
str = write_exact_value_to_string(str, var->Constant.value);
@@ -4697,20 +4908,31 @@ gb_internal gbString write_type_to_string(gbString str, Type *type, bool shortha
Type *slice = base_type(var->type);
str = gb_string_appendc(str, "..");
GB_ASSERT(var->type->kind == Type_Slice);
- str = write_type_to_string(str, slice->Slice.elem);
+ str = write_type_to_string(str, slice->Slice.elem, shorthand, allow_polymorphic);
} else {
- str = write_type_to_string(str, var->type);
+ str = write_type_to_string(str, var->type, shorthand, allow_polymorphic);
}
} else {
GB_ASSERT(var->kind == Entity_TypeName);
if (var->type->kind == Type_Generic) {
- str = gb_string_appendc(str, "typeid/");
- str = write_type_to_string(str, var->type);
+ if (var->token.string.len != 0) {
+ String name = var->token.string;
+ str = gb_string_appendc(str, "$");
+ str = gb_string_append_length(str, name.text, name.len);
+ str = gb_string_appendc(str, ": typeid");
+ if (var->type->Generic.specialized) {
+ str = gb_string_appendc(str, "/");
+ str = write_type_to_string(str, var->type->Generic.specialized, shorthand, allow_polymorphic);
+ }
+ } else {
+ str = gb_string_appendc(str, "typeid/");
+ str = write_type_to_string(str, var->type, shorthand, allow_polymorphic);
+ }
} else {
str = gb_string_appendc(str, "$");
str = gb_string_append_length(str, name.text, name.len);
str = gb_string_appendc(str, "=");
- str = write_type_to_string(str, var->type);
+ str = write_type_to_string(str, var->type, shorthand, allow_polymorphic);
}
}
}
@@ -4732,10 +4954,10 @@ gb_internal gbString write_type_to_string(gbString str, Type *type, bool shortha
}
break;
case ProcCC_CDecl:
- str = gb_string_appendc(str, " \"cdecl\" ");
+ str = gb_string_appendc(str, " \"c\" ");
break;
case ProcCC_StdCall:
- str = gb_string_appendc(str, " \"stdcall\" ");
+ str = gb_string_appendc(str, " \"std\" ");
break;
case ProcCC_FastCall:
str = gb_string_appendc(str, " \"fastcall\" ");
@@ -4756,7 +4978,7 @@ gb_internal gbString write_type_to_string(gbString str, Type *type, bool shortha
}
str = gb_string_appendc(str, "(");
if (type->Proc.params) {
- str = write_type_to_string(str, type->Proc.params);
+ str = write_type_to_string(str, type->Proc.params, shorthand, allow_polymorphic);
}
str = gb_string_appendc(str, ")");
if (type->Proc.results) {
@@ -4764,7 +4986,7 @@ gb_internal gbString write_type_to_string(gbString str, Type *type, bool shortha
if (type->Proc.results->Tuple.variables.count > 1) {
str = gb_string_appendc(str, "(");
}
- str = write_type_to_string(str, type->Proc.results);
+ str = write_type_to_string(str, type->Proc.results, shorthand, allow_polymorphic);
if (type->Proc.results->Tuple.variables.count > 1) {
str = gb_string_appendc(str, ")");
}
@@ -4773,8 +4995,10 @@ gb_internal gbString write_type_to_string(gbString str, Type *type, bool shortha
case Type_BitSet:
str = gb_string_appendc(str, "bit_set[");
- if (is_type_enum(type->BitSet.elem)) {
- str = write_type_to_string(str, type->BitSet.elem);
+ if (type->BitSet.elem == nullptr) {
+ str = gb_string_appendc(str, "<unresolved>");
+ } else if (is_type_enum(type->BitSet.elem)) {
+ str = write_type_to_string(str, type->BitSet.elem, shorthand, allow_polymorphic);
} else {
str = gb_string_append_fmt(str, "%lld", type->BitSet.lower);
str = gb_string_append_fmt(str, "..=");
@@ -4782,27 +5006,27 @@ gb_internal gbString write_type_to_string(gbString str, Type *type, bool shortha
}
if (type->BitSet.underlying != nullptr) {
str = gb_string_appendc(str, "; ");
- str = write_type_to_string(str, type->BitSet.underlying);
+ str = write_type_to_string(str, type->BitSet.underlying, shorthand, allow_polymorphic);
}
str = gb_string_appendc(str, "]");
break;
case Type_SimdVector:
str = gb_string_append_fmt(str, "#simd[%d]", cast(int)type->SimdVector.count);
- str = write_type_to_string(str, type->SimdVector.elem);
+ str = write_type_to_string(str, type->SimdVector.elem, shorthand, allow_polymorphic);
break;
-
+
case Type_Matrix:
if (type->Matrix.is_row_major) {
str = gb_string_appendc(str, "#row_major ");
}
str = gb_string_appendc(str, gb_bprintf("matrix[%d, %d]", cast(int)type->Matrix.row_count, cast(int)type->Matrix.column_count));
- str = write_type_to_string(str, type->Matrix.elem);
+ str = write_type_to_string(str, type->Matrix.elem, shorthand, allow_polymorphic);
break;
case Type_BitField:
str = gb_string_appendc(str, "bit_field ");
- str = write_type_to_string(str, type->BitField.backing_type);
+ str = write_type_to_string(str, type->BitField.backing_type, shorthand, allow_polymorphic);
str = gb_string_appendc(str, " {");
for (isize i = 0; i < type->BitField.fields.count; i++) {
Entity *f = type->BitField.fields[i];
@@ -4811,7 +5035,7 @@ gb_internal gbString write_type_to_string(gbString str, Type *type, bool shortha
}
str = gb_string_append_length(str, f->token.string.text, f->token.string.len);
str = gb_string_appendc(str, ": ");
- str = write_type_to_string(str, f->type);
+ str = write_type_to_string(str, f->type, shorthand, allow_polymorphic);
str = gb_string_append_fmt(str, " | %u", type->BitField.bit_sizes[i]);
}
str = gb_string_appendc(str, " }");
@@ -4829,9 +5053,11 @@ gb_internal gbString type_to_string(Type *type, bool shorthand) {
return write_type_to_string(gb_string_make(heap_allocator(), ""), type, shorthand);
}
-gb_internal gbString type_to_string_shorthand(Type *type) {
- return type_to_string(type, true);
+gb_internal gbString type_to_string_polymorphic(Type *type) {
+ return write_type_to_string(gb_string_make(heap_allocator(), ""), type, false, true);
}
-
+gb_internal gbString type_to_string_shorthand(Type *type) {
+ return type_to_string(type, true);
+}