aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/build_settings.cpp110
-rw-r--r--src/check_builtin.cpp992
-rw-r--r--src/check_decl.cpp2
-rw-r--r--src/check_expr.cpp140
-rw-r--r--src/check_stmt.cpp59
-rw-r--r--src/check_type.cpp33
-rw-r--r--src/checker.cpp18
-rw-r--r--src/checker.hpp9
-rw-r--r--src/checker_builtin_procs.hpp12
-rw-r--r--src/docs_format.cpp2
-rw-r--r--src/docs_writer.cpp4
-rw-r--r--src/gb/gb.h2
-rw-r--r--src/llvm_abi.cpp28
-rw-r--r--src/llvm_backend.cpp11
-rw-r--r--src/llvm_backend.hpp33
-rw-r--r--src/llvm_backend_const.cpp15
-rw-r--r--src/llvm_backend_expr.cpp2317
-rw-r--r--src/llvm_backend_general.cpp422
-rw-r--r--src/llvm_backend_opt.cpp4
-rw-r--r--src/llvm_backend_proc.cpp317
-rw-r--r--src/llvm_backend_stmt.cpp27
-rw-r--r--src/llvm_backend_type.cpp95
-rw-r--r--src/llvm_backend_utility.cpp326
-rw-r--r--src/main.cpp8
-rw-r--r--src/microsoft_craziness.h355
-rw-r--r--src/parser.cpp76
-rw-r--r--src/parser.hpp11
-rw-r--r--src/string.cpp10
-rw-r--r--src/types.cpp121
29 files changed, 2942 insertions, 2617 deletions
diff --git a/src/build_settings.cpp b/src/build_settings.cpp
index 65da09df0..3f6be3c48 100644
--- a/src/build_settings.cpp
+++ b/src/build_settings.cpp
@@ -116,6 +116,7 @@ struct TargetMetrics {
TargetArchKind arch;
isize word_size;
isize max_align;
+ isize max_simd_align;
String target_triplet;
String target_data_layout;
TargetABIKind abi;
@@ -204,7 +205,7 @@ enum BuildPath : u8 {
BuildPath_Main_Package, // Input Path to the package directory (or file) we're building.
BuildPath_RC, // Input Path for .rc file, can be set with `-resource:`.
BuildPath_RES, // Output Path for .res file, generated from previous.
- BuildPath_Win_SDK_Root, // windows_sdk_root
+ BuildPath_Win_SDK_Bin_Path, // windows_sdk_bin_path
BuildPath_Win_SDK_UM_Lib, // windows_sdk_um_library_path
BuildPath_Win_SDK_UCRT_Lib, // windows_sdk_ucrt_library_path
BuildPath_VS_EXE, // vs_exe_path
@@ -228,14 +229,16 @@ struct BuildContext {
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_FOREIGN_ERROR_PROCEDURES;
+ bool ODIN_VALGRIND_SUPPORT;
ErrorPosStyle ODIN_ERROR_POS_STYLE;
TargetEndianKind endian_kind;
// In bytes
- i64 word_size; // Size of a pointer, must be >= 4
- i64 max_align; // max alignment, must be >= 1 (and typically >= word_size)
+ i64 word_size; // Size of a pointer, must be >= 4
+ i64 max_align; // max alignment, must be >= 1 (and typically >= word_size)
+ i64 max_simd_align; // max alignment, must be >= 1 (and typically >= word_size)
CommandKind command_kind;
String command;
@@ -338,15 +341,13 @@ bool global_ignore_warnings(void) {
gb_global TargetMetrics target_windows_i386 = {
TargetOs_windows,
TargetArch_i386,
- 4,
- 8,
+ 4, 4, 8,
str_lit("i386-pc-windows-msvc"),
};
gb_global TargetMetrics target_windows_amd64 = {
TargetOs_windows,
TargetArch_amd64,
- 8,
- 16,
+ 8, 8, 16,
str_lit("x86_64-pc-windows-msvc"),
str_lit("e-m:w-i64:64-f80:128-n8:16:32:64-S128"),
};
@@ -354,24 +355,21 @@ gb_global TargetMetrics target_windows_amd64 = {
gb_global TargetMetrics target_linux_i386 = {
TargetOs_linux,
TargetArch_i386,
- 4,
- 8,
+ 4, 4, 8,
str_lit("i386-pc-linux-gnu"),
};
gb_global TargetMetrics target_linux_amd64 = {
TargetOs_linux,
TargetArch_amd64,
- 8,
- 16,
+ 8, 8, 16,
str_lit("x86_64-pc-linux-gnu"),
str_lit("e-m:w-i64:64-f80:128-n8:16:32:64-S128"),
};
gb_global TargetMetrics target_linux_arm64 = {
TargetOs_linux,
TargetArch_arm64,
- 8,
- 16,
+ 8, 8, 16,
str_lit("aarch64-linux-elf"),
str_lit("e-m:o-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64"),
};
@@ -379,8 +377,7 @@ gb_global TargetMetrics target_linux_arm64 = {
gb_global TargetMetrics target_linux_arm32 = {
TargetOs_linux,
TargetArch_arm32,
- 4,
- 8,
+ 4, 4, 8,
str_lit("arm-linux-gnu"),
str_lit("e-m:o-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64"),
};
@@ -388,8 +385,7 @@ gb_global TargetMetrics target_linux_arm32 = {
gb_global TargetMetrics target_darwin_amd64 = {
TargetOs_darwin,
TargetArch_amd64,
- 8,
- 16,
+ 8, 8, 16,
str_lit("x86_64-apple-darwin"),
str_lit("e-m:o-i64:64-f80:128-n8:16:32:64-S128"),
};
@@ -397,8 +393,7 @@ gb_global TargetMetrics target_darwin_amd64 = {
gb_global TargetMetrics target_darwin_arm64 = {
TargetOs_darwin,
TargetArch_arm64,
- 8,
- 16,
+ 8, 8, 16,
str_lit("arm64-apple-macosx11.0.0"),
str_lit("e-m:o-i64:64-i128:128-n32:64-S128"), // TODO(bill): Is this correct?
};
@@ -406,16 +401,14 @@ gb_global TargetMetrics target_darwin_arm64 = {
gb_global TargetMetrics target_freebsd_i386 = {
TargetOs_freebsd,
TargetArch_i386,
- 4,
- 8,
+ 4, 4, 8,
str_lit("i386-unknown-freebsd-elf"),
};
gb_global TargetMetrics target_freebsd_amd64 = {
TargetOs_freebsd,
TargetArch_amd64,
- 8,
- 16,
+ 8, 8, 16,
str_lit("x86_64-unknown-freebsd-elf"),
str_lit("e-m:w-i64:64-f80:128-n8:16:32:64-S128"),
};
@@ -423,8 +416,7 @@ gb_global TargetMetrics target_freebsd_amd64 = {
gb_global TargetMetrics target_openbsd_amd64 = {
TargetOs_openbsd,
TargetArch_amd64,
- 8,
- 16,
+ 8, 8, 16,
str_lit("x86_64-unknown-openbsd-elf"),
str_lit("e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"),
};
@@ -432,62 +424,48 @@ gb_global TargetMetrics target_openbsd_amd64 = {
gb_global TargetMetrics target_essence_amd64 = {
TargetOs_essence,
TargetArch_amd64,
- 8,
- 16,
+ 8, 8, 16,
str_lit("x86_64-pc-none-elf"),
};
+
gb_global TargetMetrics target_freestanding_wasm32 = {
TargetOs_freestanding,
TargetArch_wasm32,
- 4,
- 8,
+ 4, 8, 16,
str_lit("wasm32-freestanding-js"),
- str_lit(""),
+ str_lit("e-m:e-p:32:32-i64:64-n32:64-S128"),
};
gb_global TargetMetrics target_js_wasm32 = {
TargetOs_js,
TargetArch_wasm32,
- 4,
- 8,
+ 4, 8, 16,
str_lit("wasm32-js-js"),
- str_lit(""),
-};
-
-gb_global TargetMetrics target_js_wasm64 = {
- TargetOs_js,
- TargetArch_wasm64,
- 8,
- 16,
- str_lit("wasm64-js-js"),
- str_lit(""),
+ str_lit("e-m:e-p:32:32-i64:64-n32:64-S128"),
};
gb_global TargetMetrics target_wasi_wasm32 = {
TargetOs_wasi,
TargetArch_wasm32,
- 4,
- 8,
+ 4, 8, 16,
str_lit("wasm32-wasi-js"),
- str_lit(""),
+ str_lit("e-m:e-p:32:32-i64:64-n32:64-S128"),
};
-// gb_global TargetMetrics target_freestanding_wasm64 = {
-// TargetOs_freestanding,
-// TargetArch_wasm64,
-// 8,
-// 16,
-// str_lit("wasm64-freestanding-js"),
-// str_lit(""),
-// };
+gb_global TargetMetrics target_js_wasm64 = {
+ TargetOs_js,
+ TargetArch_wasm64,
+ 8, 8, 16,
+ str_lit("wasm64-js-js"),
+ str_lit(""),
+};
gb_global TargetMetrics target_freestanding_amd64_sysv = {
TargetOs_freestanding,
TargetArch_amd64,
- 8,
- 16,
+ 8, 8, 16,
str_lit("x86_64-pc-none-gnu"),
str_lit("e-m:w-i64:64-f80:128-n8:16:32:64-S128"),
TargetABI_SysV,
@@ -516,7 +494,7 @@ gb_global NamedTargetMetrics named_targets[] = {
{ str_lit("freestanding_wasm32"), &target_freestanding_wasm32 },
{ str_lit("wasi_wasm32"), &target_wasi_wasm32 },
{ str_lit("js_wasm32"), &target_js_wasm32 },
- { str_lit("js_wasm64"), &target_js_wasm64 },
+ // { str_lit("js_wasm64"), &target_js_wasm64 },
{ str_lit("freestanding_amd64_sysv"), &target_freestanding_amd64_sysv },
};
@@ -1083,14 +1061,16 @@ void init_build_context(TargetMetrics *cross_target) {
GB_ASSERT(metrics->arch != TargetArch_Invalid);
GB_ASSERT(metrics->word_size > 1);
GB_ASSERT(metrics->max_align > 1);
+ GB_ASSERT(metrics->max_simd_align > 1);
bc->metrics = *metrics;
- bc->ODIN_OS = target_os_names[metrics->os];
- bc->ODIN_ARCH = target_arch_names[metrics->arch];
- bc->endian_kind = target_endians[metrics->arch];
- bc->word_size = metrics->word_size;
- bc->max_align = metrics->max_align;
+ bc->ODIN_OS = target_os_names[metrics->os];
+ bc->ODIN_ARCH = target_arch_names[metrics->arch];
+ bc->endian_kind = target_endians[metrics->arch];
+ bc->word_size = metrics->word_size;
+ bc->max_align = metrics->max_align;
+ bc->max_simd_align = metrics->max_simd_align;
bc->link_flags = str_lit(" ");
#if defined(DEFAULT_TO_THREADED_CHECKER)
@@ -1190,6 +1170,8 @@ void init_build_context(TargetMetrics *cross_target) {
bc->optimization_level = gb_clamp(bc->optimization_level, 0, 3);
+ bc->ODIN_VALGRIND_SUPPORT = is_arch_x86() && build_context.metrics.os != TargetOs_windows;
+
#undef LINK_FLAG_X64
#undef LINK_FLAG_386
}
@@ -1336,7 +1318,7 @@ bool init_build_paths(String init_filename) {
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_Utf8 find_result = find_visual_studio_and_windows_sdk_utf8();
+ Find_Result find_result = find_visual_studio_and_windows_sdk();
defer (mc_free_all());
if (find_result.windows_sdk_version == 0) {
@@ -1357,8 +1339,8 @@ bool init_build_paths(String init_filename) {
if (find_result.windows_sdk_um_library_path.len > 0) {
GB_ASSERT(find_result.windows_sdk_ucrt_library_path.len > 0);
- if (find_result.windows_sdk_root.len > 0) {
- bc->build_paths[BuildPath_Win_SDK_Root] = path_from_string(ha, find_result.windows_sdk_root);
+ if (find_result.windows_sdk_bin_path.len > 0) {
+ bc->build_paths[BuildPath_Win_SDK_Bin_Path] = path_from_string(ha, find_result.windows_sdk_bin_path);
}
if (find_result.windows_sdk_um_library_path.len > 0) {
diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp
index 8108604ba..e55a2e024 100644
--- a/src/check_builtin.cpp
+++ b/src/check_builtin.cpp
@@ -1074,6 +1074,505 @@ bool check_builtin_simd_operation(CheckerContext *c, Operand *operand, Ast *call
return false;
}
+bool cache_load_file_directive(CheckerContext *c, Ast *call, String const &original_string, bool err_on_not_found, LoadFileCache **cache_) {
+ ast_node(ce, CallExpr, call);
+ ast_node(bd, BasicDirective, ce->proc);
+ String builtin_name = bd->name.string;
+
+ String base_dir = dir_from_path(get_file_path_string(call->file_id));
+
+ BlockingMutex *ignore_mutex = nullptr;
+ String path = {};
+ bool ok = determine_path_from_string(ignore_mutex, call, base_dir, original_string, &path);
+ gb_unused(ok);
+
+
+ MUTEX_GUARD(&c->info->load_file_mutex);
+
+ gbFileError file_error = gbFileError_None;
+ String data = {};
+
+ LoadFileCache **cache_ptr = string_map_get(&c->info->load_file_cache, path);
+ LoadFileCache *cache = cache_ptr ? *cache_ptr : nullptr;
+ if (cache) {
+ file_error = cache->file_error;
+ data = cache->data;
+ }
+ defer ({
+ if (cache == nullptr) {
+ LoadFileCache *new_cache = gb_alloc_item(permanent_allocator(), LoadFileCache);
+ new_cache->path = path;
+ new_cache->data = data;
+ new_cache->file_error = file_error;
+ string_map_init(&new_cache->hashes, heap_allocator(), 32);
+ string_map_set(&c->info->load_file_cache, path, new_cache);
+ if (cache_) *cache_ = new_cache;
+ } else {
+ cache->data = data;
+ cache->file_error = file_error;
+ if (cache_) *cache_ = cache;
+ }
+ });
+
+ char *c_str = alloc_cstring(heap_allocator(), path);
+ defer (gb_free(heap_allocator(), c_str));
+
+ gbFile f = {};
+ if (cache == nullptr) {
+ file_error = gb_file_open(&f, c_str);
+ }
+ defer (gb_file_close(&f));
+
+ switch (file_error) {
+ default:
+ case gbFileError_Invalid:
+ if (err_on_not_found) {
+ error(ce->proc, "Failed to `#%.*s` file: %s; invalid file or cannot be found", LIT(builtin_name), c_str);
+ }
+ call->state_flags |= StateFlag_DirectiveWasFalse;
+ return false;
+ case gbFileError_NotExists:
+ if (err_on_not_found) {
+ error(ce->proc, "Failed to `#%.*s` file: %s; file cannot be found", LIT(builtin_name), c_str);
+ }
+ call->state_flags |= StateFlag_DirectiveWasFalse;
+ return false;
+ case gbFileError_Permission:
+ if (err_on_not_found) {
+ error(ce->proc, "Failed to `#%.*s` file: %s; file permissions problem", LIT(builtin_name), c_str);
+ }
+ call->state_flags |= StateFlag_DirectiveWasFalse;
+ return false;
+ case gbFileError_None:
+ // Okay
+ break;
+ }
+
+ if (cache == nullptr) {
+ isize file_size = cast(isize)gb_file_size(&f);
+ if (file_size > 0) {
+ u8 *ptr = cast(u8 *)gb_alloc(permanent_allocator(), file_size+1);
+ gb_file_read_at(&f, ptr, file_size, 0);
+ ptr[file_size] = '\0';
+ data.text = ptr;
+ data.len = file_size;
+ }
+ }
+
+ return true;
+}
+
+
+bool is_valid_type_for_load(Type *type) {
+ if (type == t_invalid) {
+ return false;
+ } else if (is_type_string(type)) {
+ return true;
+ } else if (is_type_slice(type) /*|| is_type_array(type) || is_type_enumerated_array(type)*/) {
+ Type *elem = nullptr;
+ Type *bt = base_type(type);
+ if (bt->kind == Type_Slice) {
+ elem = bt->Slice.elem;
+ } else if (bt->kind == Type_Array) {
+ elem = bt->Array.elem;
+ } else if (bt->kind == Type_EnumeratedArray) {
+ elem = bt->EnumeratedArray.elem;
+ }
+ GB_ASSERT(elem != nullptr);
+ return is_type_load_safe(elem);
+ }
+ return false;
+}
+
+LoadDirectiveResult check_load_directive(CheckerContext *c, Operand *operand, Ast *call, Type *type_hint, bool err_on_not_found) {
+ ast_node(ce, CallExpr, call);
+ ast_node(bd, BasicDirective, ce->proc);
+ String name = bd->name.string;
+ GB_ASSERT(name == "load");
+
+ if (ce->args.count != 1 && ce->args.count != 2) {
+ if (ce->args.count == 0) {
+ error(ce->close, "'#%.*s' expects 1 or 2 arguments, got 0", LIT(name));
+ } else {
+ error(ce->args[0], "'#%.*s' expects 1 or 2 arguments, got %td", LIT(name), ce->args.count);
+ }
+
+ return LoadDirective_Error;
+ }
+
+ Ast *arg = ce->args[0];
+ Operand o = {};
+ check_expr(c, &o, arg);
+ if (o.mode != Addressing_Constant) {
+ error(arg, "'#%.*s' expected a constant string argument", LIT(name));
+ return LoadDirective_Error;
+ }
+
+ if (!is_type_string(o.type)) {
+ gbString str = type_to_string(o.type);
+ error(arg, "'#%.*s' expected a constant string, got %s", LIT(name), str);
+ gb_string_free(str);
+ return LoadDirective_Error;
+ }
+
+ GB_ASSERT(o.value.kind == ExactValue_String);
+
+ operand->type = t_u8_slice;
+ if (ce->args.count == 1) {
+ if (type_hint && is_valid_type_for_load(type_hint)) {
+ operand->type = type_hint;
+ }
+ } else if (ce->args.count == 2) {
+ Ast *arg_type = ce->args[1];
+ Type *type = check_type(c, arg_type);
+ if (type != nullptr) {
+ if (is_valid_type_for_load(type)) {
+ operand->type = type;
+ } else {
+ gbString type_str = type_to_string(type);
+ error(arg_type, "'#%.*s' invalid type, expected a string, or slice of simple types, got %s", LIT(name), type_str);
+ gb_string_free(type_str);
+ }
+ }
+ } else {
+ GB_PANIC("unreachable");
+ }
+ operand->mode = Addressing_Constant;
+
+ LoadFileCache *cache = nullptr;
+ if (cache_load_file_directive(c, call, o.value.value_string, err_on_not_found, &cache)) {
+ operand->value = exact_value_string(cache->data);
+ return LoadDirective_Success;
+ }
+ return LoadDirective_NotFound;
+
+}
+
+
+bool check_builtin_procedure_directive(CheckerContext *c, Operand *operand, Ast *call, Type *type_hint) {
+ ast_node(ce, CallExpr, call);
+ ast_node(bd, BasicDirective, ce->proc);
+ String name = bd->name.string;
+ if (name == "location") {
+ if (ce->args.count > 1) {
+ error(ce->args[0], "'#location' expects either 0 or 1 arguments, got %td", ce->args.count);
+ }
+ if (ce->args.count > 0) {
+ Ast *arg = ce->args[0];
+ Entity *e = nullptr;
+ Operand o = {};
+ if (arg->kind == Ast_Ident) {
+ e = check_ident(c, &o, arg, nullptr, nullptr, true);
+ } else if (arg->kind == Ast_SelectorExpr) {
+ e = check_selector(c, &o, arg, nullptr);
+ }
+ if (e == nullptr) {
+ error(ce->args[0], "'#location' expected a valid entity name");
+ }
+ }
+
+ operand->type = t_source_code_location;
+ operand->mode = Addressing_Value;
+ } else if (name == "load") {
+ return check_load_directive(c, operand, call, type_hint, true) == LoadDirective_Success;
+ } else if (name == "load_hash") {
+ if (ce->args.count != 2) {
+ if (ce->args.count == 0) {
+ error(ce->close, "'#load_hash' expects 2 argument, got 0");
+ } else {
+ error(ce->args[0], "'#load_hash' expects 2 argument, got %td", ce->args.count);
+ }
+ return false;
+ }
+
+ Ast *arg0 = ce->args[0];
+ Ast *arg1 = ce->args[1];
+ Operand o = {};
+ check_expr(c, &o, arg0);
+ if (o.mode != Addressing_Constant) {
+ error(arg0, "'#load_hash' expected a constant string argument");
+ return false;
+ }
+
+ if (!is_type_string(o.type)) {
+ gbString str = type_to_string(o.type);
+ error(arg0, "'#load_hash' expected a constant string, got %s", str);
+ gb_string_free(str);
+ return false;
+ }
+
+ Operand o_hash = {};
+ check_expr(c, &o_hash, arg1);
+ if (o_hash.mode != Addressing_Constant) {
+ error(arg1, "'#load_hash' expected a constant string argument");
+ return false;
+ }
+
+ if (!is_type_string(o_hash.type)) {
+ gbString str = type_to_string(o.type);
+ error(arg1, "'#load_hash' expected a constant string, got %s", str);
+ gb_string_free(str);
+ return false;
+ }
+ gbAllocator a = heap_allocator();
+
+ GB_ASSERT(o.value.kind == ExactValue_String);
+ GB_ASSERT(o_hash.value.kind == ExactValue_String);
+
+ String original_string = o.value.value_string;
+ String hash_kind = o_hash.value.value_string;
+
+ String supported_hashes[] = {
+ str_lit("adler32"),
+ str_lit("crc32"),
+ str_lit("crc64"),
+ str_lit("fnv32"),
+ str_lit("fnv64"),
+ str_lit("fnv32a"),
+ str_lit("fnv64a"),
+ str_lit("murmur32"),
+ str_lit("murmur64"),
+ };
+
+ bool hash_found = false;
+ for (isize i = 0; i < gb_count_of(supported_hashes); i++) {
+ if (supported_hashes[i] == hash_kind) {
+ hash_found = true;
+ break;
+ }
+ }
+ if (!hash_found) {
+ ERROR_BLOCK();
+ error(ce->proc, "Invalid hash kind passed to `#load_hash`, got: %.*s", LIT(hash_kind));
+ error_line("\tAvailable hash kinds:\n");
+ for (isize i = 0; i < gb_count_of(supported_hashes); i++) {
+ error_line("\t%.*s\n", LIT(supported_hashes[i]));
+ }
+ return false;
+ }
+
+ LoadFileCache *cache = nullptr;
+ if (cache_load_file_directive(c, call, original_string, true, &cache)) {
+ MUTEX_GUARD(&c->info->load_file_mutex);
+ // TODO(bill): make these procedures fast :P
+ u64 hash_value = 0;
+ u64 *hash_value_ptr = string_map_get(&cache->hashes, hash_kind);
+ if (hash_value_ptr) {
+ hash_value = *hash_value_ptr;
+ } else {
+ u8 *data = cache->data.text;
+ isize file_size = cache->data.len;
+ if (hash_kind == "adler32") {
+ hash_value = gb_adler32(data, file_size);
+ } else if (hash_kind == "crc32") {
+ hash_value = gb_crc32(data, file_size);
+ } else if (hash_kind == "crc64") {
+ hash_value = gb_crc64(data, file_size);
+ } else if (hash_kind == "fnv32") {
+ hash_value = gb_fnv32(data, file_size);
+ } else if (hash_kind == "fnv64") {
+ hash_value = gb_fnv64(data, file_size);
+ } else if (hash_kind == "fnv32a") {
+ hash_value = fnv32a(data, file_size);
+ } else if (hash_kind == "fnv64a") {
+ hash_value = fnv64a(data, file_size);
+ } else if (hash_kind == "murmur32") {
+ hash_value = gb_murmur32(data, file_size);
+ } else if (hash_kind == "murmur64") {
+ hash_value = gb_murmur64(data, file_size);
+ } else {
+ compiler_error("unhandled hash kind: %.*s", LIT(hash_kind));
+ }
+ string_map_set(&cache->hashes, hash_kind, hash_value);
+ }
+
+ operand->type = t_untyped_integer;
+ operand->mode = Addressing_Constant;
+ operand->value = exact_value_u64(hash_value);
+ return true;
+ }
+ return false;
+ } else if (name == "load_or") {
+ warning(call, "'#load_or' is deprecated in favour of '#load(path) or_else default'");
+
+ if (ce->args.count != 2) {
+ if (ce->args.count == 0) {
+ error(ce->close, "'#load_or' expects 2 arguments, got 0");
+ } else {
+ error(ce->args[0], "'#load_or' expects 2 arguments, got %td", ce->args.count);
+ }
+ return false;
+ }
+
+ Ast *arg = ce->args[0];
+ Operand o = {};
+ check_expr(c, &o, arg);
+ if (o.mode != Addressing_Constant) {
+ error(arg, "'#load_or' expected a constant string argument");
+ return false;
+ }
+
+ if (!is_type_string(o.type)) {
+ gbString str = type_to_string(o.type);
+ error(arg, "'#load_or' expected a constant string, got %s", str);
+ gb_string_free(str);
+ return false;
+ }
+
+ Ast *default_arg = ce->args[1];
+ Operand default_op = {};
+ check_expr_with_type_hint(c, &default_op, default_arg, t_u8_slice);
+ if (default_op.mode != Addressing_Constant) {
+ error(arg, "'#load_or' expected a constant '[]byte' argument");
+ return false;
+ }
+
+ if (!are_types_identical(base_type(default_op.type), t_u8_slice)) {
+ gbString str = type_to_string(default_op.type);
+ error(arg, "'#load_or' expected a constant '[]byte', got %s", str);
+ gb_string_free(str);
+ return false;
+ }
+ GB_ASSERT(o.value.kind == ExactValue_String);
+ String original_string = o.value.value_string;
+
+ operand->type = t_u8_slice;
+ operand->mode = Addressing_Constant;
+ LoadFileCache *cache = nullptr;
+ if (cache_load_file_directive(c, call, original_string, false, &cache)) {
+ operand->value = exact_value_string(cache->data);
+ } else {
+ operand->value = default_op.value;
+ }
+ } else if (name == "assert") {
+ if (ce->args.count != 1 && ce->args.count != 2) {
+ error(call, "'#assert' expects either 1 or 2 arguments, got %td", ce->args.count);
+ return false;
+ }
+ if (!is_type_boolean(operand->type) || operand->mode != Addressing_Constant) {
+ gbString str = expr_to_string(ce->args[0]);
+ error(call, "'%s' is not a constant boolean", str);
+ gb_string_free(str);
+ return false;
+ }
+ if (ce->args.count == 2) {
+ Ast *arg = unparen_expr(ce->args[1]);
+ if (arg == nullptr || arg->kind != Ast_BasicLit || arg->BasicLit.token.kind != Token_String) {
+ gbString str = expr_to_string(arg);
+ error(call, "'%s' is not a constant string", str);
+ gb_string_free(str);
+ return false;
+ }
+ }
+
+ if (!operand->value.value_bool) {
+ gbString arg1 = expr_to_string(ce->args[0]);
+ gbString arg2 = {};
+
+ if (ce->args.count == 1) {
+ error(call, "Compile time assertion: %s", arg1);
+ } else {
+ arg2 = expr_to_string(ce->args[1]);
+ error(call, "Compile time assertion: %s (%s)", arg1, arg2);
+ }
+
+ if (c->proc_name != "") {
+ gbString str = type_to_string(c->curr_proc_sig);
+ error_line("\tCalled within '%.*s' :: %s\n", LIT(c->proc_name), str);
+ gb_string_free(str);
+ }
+
+ gb_string_free(arg1);
+ if (ce->args.count == 2) {
+ gb_string_free(arg2);
+ }
+ }
+
+ operand->type = t_untyped_bool;
+ operand->mode = Addressing_Constant;
+ } else if (name == "panic") {
+ if (ce->args.count != 1) {
+ error(call, "'#panic' expects 1 argument, got %td", ce->args.count);
+ return false;
+ }
+ if (!is_type_string(operand->type) && operand->mode != Addressing_Constant) {
+ gbString str = expr_to_string(ce->args[0]);
+ error(call, "'%s' is not a constant string", str);
+ gb_string_free(str);
+ return false;
+ }
+ error(call, "Compile time panic: %.*s", LIT(operand->value.value_string));
+ if (c->proc_name != "") {
+ gbString str = type_to_string(c->curr_proc_sig);
+ error_line("\tCalled within '%.*s' :: %s\n", LIT(c->proc_name), str);
+ gb_string_free(str);
+ }
+ operand->type = t_invalid;
+ operand->mode = Addressing_NoValue;
+ } else if (name == "defined") {
+ if (ce->args.count != 1) {
+ error(call, "'#defined' expects 1 argument, got %td", ce->args.count);
+ return false;
+ }
+ Ast *arg = unparen_expr(ce->args[0]);
+ if (arg == nullptr || (arg->kind != Ast_Ident && arg->kind != Ast_SelectorExpr)) {
+ error(call, "'#defined' expects an identifier or selector expression, got %.*s", LIT(ast_strings[arg->kind]));
+ return false;
+ }
+
+ if (c->curr_proc_decl == nullptr) {
+ error(call, "'#defined' is only allowed within a procedure, prefer the replacement '#config(NAME, default_value)'");
+ return false;
+ }
+
+ bool is_defined = check_identifier_exists(c->scope, arg);
+ gb_unused(is_defined);
+ operand->type = t_untyped_bool;
+ operand->mode = Addressing_Constant;
+ operand->value = exact_value_bool(false);
+
+ } else if (name == "config") {
+ if (ce->args.count != 2) {
+ error(call, "'#config' expects 2 argument, got %td", ce->args.count);
+ return false;
+ }
+ Ast *arg = unparen_expr(ce->args[0]);
+ if (arg == nullptr || arg->kind != Ast_Ident) {
+ error(call, "'#config' expects an identifier, got %.*s", LIT(ast_strings[arg->kind]));
+ return false;
+ }
+
+ Ast *def_arg = unparen_expr(ce->args[1]);
+
+ Operand def = {};
+ check_expr(c, &def, def_arg);
+ if (def.mode != Addressing_Constant) {
+ error(def_arg, "'#config' default value must be a constant");
+ return false;
+ }
+
+ String name = arg->Ident.token.string;
+
+
+ operand->type = def.type;
+ operand->mode = def.mode;
+ operand->value = def.value;
+
+ Entity *found = scope_lookup_current(config_pkg->scope, name);
+ if (found != nullptr) {
+ if (found->kind != Entity_Constant) {
+ error(arg, "'#config' entity '%.*s' found but expected a constant", LIT(name));
+ } else {
+ operand->type = found->type;
+ operand->mode = Addressing_Constant;
+ operand->value = found->Constant.value;
+ }
+ }
+ } else {
+ error(call, "Unknown directive call: #%.*s", LIT(name));
+ }
+ return true;
+}
bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 id, Type *type_hint) {
ast_node(ce, CallExpr, call);
@@ -1186,458 +1685,8 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
mpmc_enqueue(&c->info->intrinsics_entry_point_usage, call);
break;
- case BuiltinProc_DIRECTIVE: {
- ast_node(bd, BasicDirective, ce->proc);
- String name = bd->name.string;
- if (name == "location") {
- if (ce->args.count > 1) {
- error(ce->args[0], "'#location' expects either 0 or 1 arguments, got %td", ce->args.count);
- }
- if (ce->args.count > 0) {
- Ast *arg = ce->args[0];
- Entity *e = nullptr;
- Operand o = {};
- if (arg->kind == Ast_Ident) {
- e = check_ident(c, &o, arg, nullptr, nullptr, true);
- } else if (arg->kind == Ast_SelectorExpr) {
- e = check_selector(c, &o, arg, nullptr);
- }
- if (e == nullptr) {
- error(ce->args[0], "'#location' expected a valid entity name");
- }
- }
-
- operand->type = t_source_code_location;
- operand->mode = Addressing_Value;
- } else if (name == "load") {
- if (ce->args.count != 1) {
- if (ce->args.count == 0) {
- error(ce->close, "'#load' expects 1 argument, got 0");
- } else {
- error(ce->args[0], "'#load' expects 1 argument, got %td", ce->args.count);
- }
-
- return false;
- }
-
- Ast *arg = ce->args[0];
- Operand o = {};
- check_expr(c, &o, arg);
- if (o.mode != Addressing_Constant) {
- error(arg, "'#load' expected a constant string argument");
- return false;
- }
-
- if (!is_type_string(o.type)) {
- gbString str = type_to_string(o.type);
- error(arg, "'#load' expected a constant string, got %s", str);
- gb_string_free(str);
- return false;
- }
-
- gbAllocator a = heap_allocator();
-
- GB_ASSERT(o.value.kind == ExactValue_String);
- String base_dir = dir_from_path(get_file_path_string(bd->token.pos.file_id));
- String original_string = o.value.value_string;
-
-
- BlockingMutex *ignore_mutex = nullptr;
- String path = {};
- bool ok = determine_path_from_string(ignore_mutex, call, base_dir, original_string, &path);
- gb_unused(ok);
-
- char *c_str = alloc_cstring(a, path);
- defer (gb_free(a, c_str));
-
-
- gbFile f = {};
- gbFileError file_err = gb_file_open(&f, c_str);
- defer (gb_file_close(&f));
-
- switch (file_err) {
- default:
- case gbFileError_Invalid:
- error(ce->proc, "Failed to `#load` file: %s; invalid file or cannot be found", c_str);
- return false;
- case gbFileError_NotExists:
- error(ce->proc, "Failed to `#load` file: %s; file cannot be found", c_str);
- return false;
- case gbFileError_Permission:
- error(ce->proc, "Failed to `#load` file: %s; file permissions problem", c_str);
- return false;
- case gbFileError_None:
- // Okay
- break;
- }
-
- String result = {};
- isize file_size = cast(isize)gb_file_size(&f);
- if (file_size > 0) {
- u8 *data = cast(u8 *)gb_alloc(a, file_size+1);
- gb_file_read_at(&f, data, file_size, 0);
- data[file_size] = '\0';
- result.text = data;
- result.len = file_size;
- }
-
- operand->type = t_u8_slice;
- operand->mode = Addressing_Constant;
- operand->value = exact_value_string(result);
-
- } else if (name == "load_hash") {
- if (ce->args.count != 2) {
- if (ce->args.count == 0) {
- error(ce->close, "'#load_hash' expects 2 argument, got 0");
- } else {
- error(ce->args[0], "'#load_hash' expects 2 argument, got %td", ce->args.count);
- }
- return false;
- }
-
- Ast *arg0 = ce->args[0];
- Ast *arg1 = ce->args[1];
- Operand o = {};
- check_expr(c, &o, arg0);
- if (o.mode != Addressing_Constant) {
- error(arg0, "'#load_hash' expected a constant string argument");
- return false;
- }
-
- if (!is_type_string(o.type)) {
- gbString str = type_to_string(o.type);
- error(arg0, "'#load_hash' expected a constant string, got %s", str);
- gb_string_free(str);
- return false;
- }
-
- Operand o_hash = {};
- check_expr(c, &o_hash, arg1);
- if (o_hash.mode != Addressing_Constant) {
- error(arg1, "'#load_hash' expected a constant string argument");
- return false;
- }
-
- if (!is_type_string(o_hash.type)) {
- gbString str = type_to_string(o.type);
- error(arg1, "'#load_hash' expected a constant string, got %s", str);
- gb_string_free(str);
- return false;
- }
-
-
- gbAllocator a = heap_allocator();
-
- GB_ASSERT(o.value.kind == ExactValue_String);
- GB_ASSERT(o_hash.value.kind == ExactValue_String);
-
- String base_dir = dir_from_path(get_file_path_string(bd->token.pos.file_id));
- String original_string = o.value.value_string;
- String hash_kind = o_hash.value.value_string;
-
- String supported_hashes[] = {
- str_lit("adler32"),
- str_lit("crc32"),
- str_lit("crc64"),
- str_lit("fnv32"),
- str_lit("fnv64"),
- str_lit("fnv32a"),
- str_lit("fnv64a"),
- str_lit("murmur32"),
- str_lit("murmur64"),
- };
-
- bool hash_found = false;
- for (isize i = 0; i < gb_count_of(supported_hashes); i++) {
- if (supported_hashes[i] == hash_kind) {
- hash_found = true;
- break;
- }
- }
- if (!hash_found) {
- ERROR_BLOCK();
- error(ce->proc, "Invalid hash kind passed to `#load_hash`, got: %.*s", LIT(hash_kind));
- error_line("\tAvailable hash kinds:\n");
- for (isize i = 0; i < gb_count_of(supported_hashes); i++) {
- error_line("\t%.*s\n", LIT(supported_hashes[i]));
- }
- return false;
- }
-
-
- BlockingMutex *ignore_mutex = nullptr;
- String path = {};
- bool ok = determine_path_from_string(ignore_mutex, call, base_dir, original_string, &path);
- gb_unused(ok);
-
- char *c_str = alloc_cstring(a, path);
- defer (gb_free(a, c_str));
-
-
- gbFile f = {};
- gbFileError file_err = gb_file_open(&f, c_str);
- defer (gb_file_close(&f));
-
- switch (file_err) {
- default:
- case gbFileError_Invalid:
- error(ce->proc, "Failed to `#load_hash` file: %s; invalid file or cannot be found", c_str);
- return false;
- case gbFileError_NotExists:
- error(ce->proc, "Failed to `#load_hash` file: %s; file cannot be found", c_str);
- return false;
- case gbFileError_Permission:
- error(ce->proc, "Failed to `#load_hash` file: %s; file permissions problem", c_str);
- return false;
- case gbFileError_None:
- // Okay
- break;
- }
-
- // TODO(bill): make these procedures fast :P
-
- u64 hash_value = 0;
- String result = {};
- isize file_size = cast(isize)gb_file_size(&f);
- if (file_size > 0) {
- u8 *data = cast(u8 *)gb_alloc(a, file_size);
- gb_file_read_at(&f, data, file_size, 0);
- if (hash_kind == "adler32") {
- hash_value = gb_adler32(data, file_size);
- } else if (hash_kind == "crc32") {
- hash_value = gb_crc32(data, file_size);
- } else if (hash_kind == "crc64") {
- hash_value = gb_crc64(data, file_size);
- } else if (hash_kind == "fnv32") {
- hash_value = gb_fnv32(data, file_size);
- } else if (hash_kind == "fnv64") {
- hash_value = gb_fnv64(data, file_size);
- } else if (hash_kind == "fnv32a") {
- hash_value = fnv32a(data, file_size);
- } else if (hash_kind == "fnv64a") {
- hash_value = fnv64a(data, file_size);
- } else if (hash_kind == "murmur32") {
- hash_value = gb_murmur32(data, file_size);
- } else if (hash_kind == "murmur64") {
- hash_value = gb_murmur64(data, file_size);
- } else {
- compiler_error("unhandled hash kind: %.*s", LIT(hash_kind));
- }
- gb_free(a, data);
- }
-
- operand->type = t_untyped_integer;
- operand->mode = Addressing_Constant;
- operand->value = exact_value_u64(hash_value);
-
- } else if (name == "load_or") {
- if (ce->args.count != 2) {
- if (ce->args.count == 0) {
- error(ce->close, "'#load_or' expects 2 arguments, got 0");
- } else {
- error(ce->args[0], "'#load_or' expects 2 arguments, got %td", ce->args.count);
- }
- return false;
- }
-
- Ast *arg = ce->args[0];
- Operand o = {};
- check_expr(c, &o, arg);
- if (o.mode != Addressing_Constant) {
- error(arg, "'#load_or' expected a constant string argument");
- return false;
- }
-
- if (!is_type_string(o.type)) {
- gbString str = type_to_string(o.type);
- error(arg, "'#load_or' expected a constant string, got %s", str);
- gb_string_free(str);
- return false;
- }
-
- Ast *default_arg = ce->args[1];
- Operand default_op = {};
- check_expr_with_type_hint(c, &default_op, default_arg, t_u8_slice);
- if (default_op.mode != Addressing_Constant) {
- error(arg, "'#load_or' expected a constant '[]byte' argument");
- return false;
- }
-
- if (!are_types_identical(base_type(default_op.type), t_u8_slice)) {
- gbString str = type_to_string(default_op.type);
- error(arg, "'#load_or' expected a constant '[]byte', got %s", str);
- gb_string_free(str);
- return false;
- }
-
- gbAllocator a = heap_allocator();
-
- GB_ASSERT(o.value.kind == ExactValue_String);
- String base_dir = dir_from_path(get_file_path_string(bd->token.pos.file_id));
- String original_string = o.value.value_string;
-
-
- BlockingMutex *ignore_mutex = nullptr;
- String path = {};
- bool ok = determine_path_from_string(ignore_mutex, call, base_dir, original_string, &path);
- gb_unused(ok);
-
- char *c_str = alloc_cstring(a, path);
- defer (gb_free(a, c_str));
-
-
- gbFile f = {};
- gbFileError file_err = gb_file_open(&f, c_str);
- defer (gb_file_close(&f));
-
- operand->type = t_u8_slice;
- operand->mode = Addressing_Constant;
- if (file_err == gbFileError_None) {
- String result = {};
- isize file_size = cast(isize)gb_file_size(&f);
- if (file_size > 0) {
- u8 *data = cast(u8 *)gb_alloc(a, file_size+1);
- gb_file_read_at(&f, data, file_size, 0);
- data[file_size] = '\0';
- result.text = data;
- result.len = file_size;
- }
-
- operand->value = exact_value_string(result);
- } else {
- operand->value = default_op.value;
- }
-
- } else if (name == "assert") {
- if (ce->args.count != 1 && ce->args.count != 2) {
- error(call, "'#assert' expects either 1 or 2 arguments, got %td", ce->args.count);
- return false;
- }
- if (!is_type_boolean(operand->type) || operand->mode != Addressing_Constant) {
- gbString str = expr_to_string(ce->args[0]);
- error(call, "'%s' is not a constant boolean", str);
- gb_string_free(str);
- return false;
- }
- if (ce->args.count == 2) {
- Ast *arg = unparen_expr(ce->args[1]);
- if (arg == nullptr || arg->kind != Ast_BasicLit || arg->BasicLit.token.kind != Token_String) {
- gbString str = expr_to_string(arg);
- error(call, "'%s' is not a constant string", str);
- gb_string_free(str);
- return false;
- }
- }
-
- if (!operand->value.value_bool) {
- gbString arg1 = expr_to_string(ce->args[0]);
- gbString arg2 = {};
-
- if (ce->args.count == 1) {
- error(call, "Compile time assertion: %s", arg1);
- } else {
- arg2 = expr_to_string(ce->args[1]);
- error(call, "Compile time assertion: %s (%s)", arg1, arg2);
- }
-
- if (c->proc_name != "") {
- gbString str = type_to_string(c->curr_proc_sig);
- error_line("\tCalled within '%.*s' :: %s\n", LIT(c->proc_name), str);
- gb_string_free(str);
- }
-
- gb_string_free(arg1);
- if (ce->args.count == 2) {
- gb_string_free(arg2);
- }
- }
-
- operand->type = t_untyped_bool;
- operand->mode = Addressing_Constant;
- } else if (name == "panic") {
- if (ce->args.count != 1) {
- error(call, "'#panic' expects 1 argument, got %td", ce->args.count);
- return false;
- }
- if (!is_type_string(operand->type) && operand->mode != Addressing_Constant) {
- gbString str = expr_to_string(ce->args[0]);
- error(call, "'%s' is not a constant string", str);
- gb_string_free(str);
- return false;
- }
- error(call, "Compile time panic: %.*s", LIT(operand->value.value_string));
- if (c->proc_name != "") {
- gbString str = type_to_string(c->curr_proc_sig);
- error_line("\tCalled within '%.*s' :: %s\n", LIT(c->proc_name), str);
- gb_string_free(str);
- }
- operand->type = t_invalid;
- operand->mode = Addressing_NoValue;
- } else if (name == "defined") {
- if (ce->args.count != 1) {
- error(call, "'#defined' expects 1 argument, got %td", ce->args.count);
- return false;
- }
- Ast *arg = unparen_expr(ce->args[0]);
- if (arg == nullptr || (arg->kind != Ast_Ident && arg->kind != Ast_SelectorExpr)) {
- error(call, "'#defined' expects an identifier or selector expression, got %.*s", LIT(ast_strings[arg->kind]));
- return false;
- }
-
- if (c->curr_proc_decl == nullptr) {
- error(call, "'#defined' is only allowed within a procedure, prefer the replacement '#config(NAME, default_value)'");
- return false;
- }
-
- bool is_defined = check_identifier_exists(c->scope, arg);
- gb_unused(is_defined);
- operand->type = t_untyped_bool;
- operand->mode = Addressing_Constant;
- operand->value = exact_value_bool(false);
-
- } else if (name == "config") {
- if (ce->args.count != 2) {
- error(call, "'#config' expects 2 argument, got %td", ce->args.count);
- return false;
- }
- Ast *arg = unparen_expr(ce->args[0]);
- if (arg == nullptr || arg->kind != Ast_Ident) {
- error(call, "'#config' expects an identifier, got %.*s", LIT(ast_strings[arg->kind]));
- return false;
- }
-
- Ast *def_arg = unparen_expr(ce->args[1]);
-
- Operand def = {};
- check_expr(c, &def, def_arg);
- if (def.mode != Addressing_Constant) {
- error(def_arg, "'#config' default value must be a constant");
- return false;
- }
-
- String name = arg->Ident.token.string;
-
-
- operand->type = def.type;
- operand->mode = def.mode;
- operand->value = def.value;
-
- Entity *found = scope_lookup_current(config_pkg->scope, name);
- if (found != nullptr) {
- if (found->kind != Entity_Constant) {
- error(arg, "'#config' entity '%.*s' found but expected a constant", LIT(name));
- } else {
- operand->type = found->type;
- operand->mode = Addressing_Constant;
- operand->value = found->Constant.value;
- }
- }
- } else {
- error(call, "Unknown directive call: #%.*s", LIT(name));
- }
-
- break;
- }
+ case BuiltinProc_DIRECTIVE:
+ return check_builtin_procedure_directive(c, operand, call, type_hint);
case BuiltinProc_len:
check_expr_or_type(c, operand, ce->args[0]);
@@ -3569,6 +3618,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
operand->mode = Addressing_NoValue;
break;
+ case BuiltinProc_unreachable:
case BuiltinProc_trap:
case BuiltinProc_debug_trap:
operand->mode = Addressing_NoValue;
@@ -4473,7 +4523,8 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
if (x.mode != Addressing_Invalid) {
convert_to_typed(c, &x, t_uintptr);
}
- if (!is_type_uintptr(operand->type)) {
+ convert_to_typed(c, &x, t_uintptr);
+ if (!is_type_uintptr(x.type)) {
gbString t = type_to_string(x.type);
error(x.expr, "Argument %td must be of type 'uintptr', got %s", i, t);
gb_string_free(t);
@@ -5338,6 +5389,41 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
}
break;
+ case BuiltinProc_valgrind_client_request:
+ {
+ if (!is_arch_x86()) {
+ error(call, "'%.*s' is only allowed on x86 targets (i386, amd64)", LIT(builtin_name));
+ return false;
+ }
+
+ enum {ARG_COUNT = 7};
+ GB_ASSERT(builtin_procs[BuiltinProc_valgrind_client_request].arg_count == ARG_COUNT);
+
+ Operand operands[ARG_COUNT] = {};
+ for (isize i = 0; i < ARG_COUNT; i++) {
+ Operand *op = &operands[i];
+ check_expr_with_type_hint(c, op, ce->args[i], t_uintptr);
+ if (op->mode == Addressing_Invalid) {
+ return false;
+ }
+ convert_to_typed(c, op, t_uintptr);
+ if (op->mode == Addressing_Invalid) {
+ return false;
+ }
+ if (!are_types_identical(op->type, t_uintptr)) {
+ gbString str = type_to_string(op->type);
+ error(op->expr, "'%.*s' expected a uintptr, got %s", LIT(builtin_name), str);
+ gb_string_free(str);
+ return false;
+ }
+ }
+
+ operand->type = t_uintptr;
+ operand->mode = Addressing_Value;
+ operand->value = {};
+ return true;
+ }
+
}
return true;
diff --git a/src/check_decl.cpp b/src/check_decl.cpp
index 86280b6cb..9d043e60a 100644
--- a/src/check_decl.cpp
+++ b/src/check_decl.cpp
@@ -320,7 +320,7 @@ void check_type_decl(CheckerContext *ctx, Entity *e, Ast *init_expr, Type *def)
} else if (is_type_any(e->type)) {
error(init_expr, "'distinct' cannot be applied to 'any'");
is_distinct = false;
- } else if (is_type_simd_vector(e->type)) {
+ } else if (is_type_simd_vector(e->type) || is_type_soa_pointer(e->type)) {
gbString str = type_to_string(e->type);
error(init_expr, "'distinct' cannot be applied to '%s'", str);
gb_string_free(str);
diff --git a/src/check_expr.cpp b/src/check_expr.cpp
index cf9f2f751..9c2d20781 100644
--- a/src/check_expr.cpp
+++ b/src/check_expr.cpp
@@ -119,6 +119,29 @@ void check_or_else_split_types(CheckerContext *c, Operand *x, String const &name
void check_or_else_expr_no_value_error(CheckerContext *c, String const &name, Operand const &x, Type *type_hint);
void check_or_return_split_types(CheckerContext *c, Operand *x, String const &name, Type **left_type_, Type **right_type_);
+bool is_diverging_expr(Ast *expr);
+
+
+enum LoadDirectiveResult {
+ LoadDirective_Success = 0,
+ LoadDirective_Error = 1,
+ LoadDirective_NotFound = 2,
+};
+
+bool is_load_directive_call(Ast *call) {
+ call = unparen_expr(call);
+ if (call->kind != Ast_CallExpr) {
+ return false;
+ }
+ ast_node(ce, CallExpr, call);
+ if (ce->proc->kind != Ast_BasicDirective) {
+ return false;
+ }
+ ast_node(bd, BasicDirective, ce->proc);
+ String name = bd->name.string;
+ return name == "load";
+}
+LoadDirectiveResult check_load_directive(CheckerContext *c, Operand *operand, Ast *call, Type *type_hint, bool err_on_not_found);
void check_did_you_mean_print(DidYouMeanAnswers *d, char const *prefix = "") {
auto results = did_you_mean_results(d);
@@ -795,6 +818,10 @@ i64 check_distance_between_types(CheckerContext *c, Operand *operand, Type *type
}
if (is_type_matrix(dst)) {
+ if (are_types_identical(src, dst)) {
+ return 5;
+ }
+
Type *dst_elem = base_array_type(dst);
i64 distance = check_distance_between_types(c, operand, dst_elem);
if (distance >= 0) {
@@ -2051,7 +2078,7 @@ bool check_is_not_addressable(CheckerContext *c, Operand *o) {
return false;
}
- return o->mode != Addressing_Variable;
+ return o->mode != Addressing_Variable && o->mode != Addressing_SoaVariable;
}
void check_unary_expr(CheckerContext *c, Operand *o, Token op, Ast *node) {
@@ -2068,9 +2095,6 @@ void check_unary_expr(CheckerContext *c, Operand *o, Token op, Ast *node) {
error(op, "Cannot take the pointer address of '%s' which is a procedure parameter", str);
} else {
switch (o->mode) {
- case Addressing_SoaVariable:
- error(op, "Cannot take the pointer address of '%s' as it is an indirect index of an SOA struct", str);
- break;
case Addressing_Constant:
error(op, "Cannot take the pointer address of '%s' which is a constant", str);
break;
@@ -2098,7 +2122,19 @@ void check_unary_expr(CheckerContext *c, Operand *o, Token op, Ast *node) {
return;
}
- o->type = alloc_type_pointer(o->type);
+ if (o->mode == Addressing_SoaVariable) {
+ ast_node(ue, UnaryExpr, node);
+ if (ast_node_expect(ue->expr, Ast_IndexExpr)) {
+ ast_node(ie, IndexExpr, ue->expr);
+ Type *soa_type = type_of_expr(ie->expr);
+ GB_ASSERT(is_type_soa_struct(soa_type));
+ o->type = alloc_type_soa_pointer(soa_type);
+ } else {
+ o->type = alloc_type_pointer(o->type);
+ }
+ } else {
+ o->type = alloc_type_pointer(o->type);
+ }
switch (o->mode) {
case Addressing_OptionalOk:
@@ -2495,8 +2531,17 @@ void check_shift(CheckerContext *c, Operand *x, Operand *y, Ast *node, Type *typ
x->expr->tav.is_lhs = true;
}
x->mode = Addressing_Value;
- if (type_hint && is_type_integer(type_hint)) {
- x->type = type_hint;
+ if (type_hint) {
+ if (is_type_integer(type_hint)) {
+ x->type = type_hint;
+ } 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);
+ gb_string_free(x_str);
+ gb_string_free(to_type);
+ x->mode = Addressing_Invalid;
+ }
}
// x->value = x_val;
return;
@@ -2512,7 +2557,7 @@ void check_shift(CheckerContext *c, Operand *x, Operand *y, Ast *node, Type *typ
// TODO(bill): Should we support shifts for fixed arrays and #simd vectors?
if (!is_type_integer(x->type)) {
- gbString err_str = expr_to_string(y->expr);
+ 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;
@@ -7388,9 +7433,59 @@ ExprKind check_or_else_expr(CheckerContext *c, Operand *o, Ast *node, Type *type
String name = oe->token.string;
Ast *arg = oe->x;
Ast *default_value = oe->y;
-
Operand x = {};
Operand y = {};
+
+ // NOTE(bill, 2022-08-11): edge case to handle #load(path) or_else default
+ if (is_load_directive_call(arg)) {
+ LoadDirectiveResult res = check_load_directive(c, &x, arg, type_hint, false);
+
+ // Allow for chaining of '#load(path) or_else #load(path)'
+ if (!(is_load_directive_call(default_value) && res == LoadDirective_Success)) {
+ bool y_is_diverging = false;
+ check_expr_base(c, &y, default_value, x.type);
+ switch (y.mode) {
+ case Addressing_NoValue:
+ if (is_diverging_expr(y.expr)) {
+ // Allow
+ y.mode = Addressing_Value;
+ y_is_diverging = true;
+ } else {
+ error_operand_no_value(&y);
+ y.mode = Addressing_Invalid;
+ }
+ break;
+ case Addressing_Type:
+ error_operand_not_expression(&y);
+ y.mode = Addressing_Invalid;
+ break;
+ }
+
+ if (y.mode == Addressing_Invalid) {
+ o->mode = Addressing_Value;
+ o->type = t_invalid;
+ o->expr = node;
+ return Expr_Expr;
+ }
+
+ if (!y_is_diverging) {
+ check_assignment(c, &y, x.type, name);
+ if (y.mode != Addressing_Constant) {
+ error(y.expr, "expected a constant expression on the right-hand side of 'or_else' in conjuction with '#load'");
+ }
+ }
+ }
+
+ if (res == LoadDirective_Success) {
+ *o = x;
+ } else {
+ *o = y;
+ }
+ o->expr = node;
+
+ return Expr_Expr;
+ }
+
check_multi_expr_with_type_hint(c, &x, arg, type_hint);
if (x.mode == Addressing_Invalid) {
o->mode = Addressing_Value;
@@ -7398,9 +7493,25 @@ ExprKind check_or_else_expr(CheckerContext *c, Operand *o, Ast *node, Type *type
o->expr = node;
return Expr_Expr;
}
+ bool y_is_diverging = false;
+ check_expr_base(c, &y, default_value, x.type);
+ switch (y.mode) {
+ case Addressing_NoValue:
+ if (is_diverging_expr(y.expr)) {
+ // Allow
+ y.mode = Addressing_Value;
+ y_is_diverging = true;
+ } else {
+ error_operand_no_value(&y);
+ y.mode = Addressing_Invalid;
+ }
+ break;
+ case Addressing_Type:
+ error_operand_not_expression(&y);
+ y.mode = Addressing_Invalid;
+ break;
+ }
- check_multi_expr_with_type_hint(c, &y, default_value, x.type);
- error_operand_no_value(&y);
if (y.mode == Addressing_Invalid) {
o->mode = Addressing_Value;
o->type = t_invalid;
@@ -7414,7 +7525,9 @@ ExprKind check_or_else_expr(CheckerContext *c, Operand *o, Ast *node, Type *type
add_type_and_value(&c->checker->info, arg, x.mode, x.type, x.value);
if (left_type != nullptr) {
- check_assignment(c, &y, left_type, name);
+ if (!y_is_diverging) {
+ check_assignment(c, &y, left_type, name);
+ }
} else {
check_or_else_expr_no_value_error(c, name, x, type_hint);
}
@@ -9358,6 +9471,9 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
if (t->kind == Type_Pointer && !is_type_empty_union(t->Pointer.elem)) {
o->mode = Addressing_Variable;
o->type = t->Pointer.elem;
+ } else if (t->kind == Type_SoaPointer) {
+ o->mode = Addressing_SoaVariable;
+ o->type = type_deref(t);
} else if (t->kind == Type_RelativePointer) {
if (o->mode != Addressing_Variable) {
gbString str = expr_to_string(o->expr);
diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp
index a6f6f1a7d..d741ceabf 100644
--- a/src/check_stmt.cpp
+++ b/src/check_stmt.cpp
@@ -1,8 +1,5 @@
-bool is_diverging_stmt(Ast *stmt) {
- if (stmt->kind != Ast_ExprStmt) {
- return false;
- }
- Ast *expr = unparen_expr(stmt->ExprStmt.expr);
+bool is_diverging_expr(Ast *expr) {
+ expr = unparen_expr(expr);
if (expr->kind != Ast_CallExpr) {
return false;
}
@@ -26,6 +23,12 @@ bool is_diverging_stmt(Ast *stmt) {
t = base_type(t);
return t != nullptr && t->kind == Type_Proc && t->Proc.diverging;
}
+bool is_diverging_stmt(Ast *stmt) {
+ if (stmt->kind != Ast_ExprStmt) {
+ return false;
+ }
+ return is_diverging_expr(stmt->ExprStmt.expr);
+}
bool contains_deferred_call(Ast *node) {
if (node->viral_state_flags & ViralStateFlag_ContainsDeferredProcedure) {
@@ -1393,6 +1396,23 @@ bool check_stmt_internal_builtin_proc_id(Ast *expr, BuiltinProcId *id_) {
return id != BuiltinProc_Invalid;
}
+bool check_expr_is_stack_variable(Ast *expr) {
+ expr = unparen_expr(expr);
+ Entity *e = entity_of_node(expr);
+ if (e && e->kind == Entity_Variable) {
+ if (e->flags & (EntityFlag_Static|EntityFlag_Using)) {
+ // okay
+ } else if (e->Variable.thread_local_model.len != 0) {
+ // okay
+ } else if (e->scope) {
+ if ((e->scope->flags & (ScopeFlag_Global|ScopeFlag_File|ScopeFlag_Type)) == 0) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
u32 mod_flags = flags & (~Stmt_FallthroughAllowed);
switch (node->kind) {
@@ -1444,6 +1464,12 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
AstSelectorCallExpr *se = &expr->SelectorCallExpr;
ast_node(ce, CallExpr, se->call);
Type *t = base_type(type_of_expr(ce->proc));
+ if (t == nullptr) {
+ gbString expr_str = expr_to_string(ce->proc);
+ error(node, "'%s' is not a value field nor procedure", expr_str);
+ gb_string_free(expr_str);
+ return;
+ }
if (t->kind == Type_Proc) {
do_require = t->Proc.require_results;
} else if (check_stmt_internal_builtin_proc_id(ce->proc, &builtin_id)) {
@@ -1675,6 +1701,29 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
if (is_type_untyped(o->type)) {
update_untyped_expr_type(ctx, o->expr, e->type, true);
}
+
+
+ // NOTE(bill): This is very basic escape analysis
+ // This needs to be improved tremendously, and a lot of it done during the
+ // middle-end (or LLVM side) to improve checks and error messages
+ Ast *expr = unparen_expr(o->expr);
+ if (expr->kind == Ast_UnaryExpr && expr->UnaryExpr.op.kind == Token_And) {
+ Ast *x = unparen_expr(expr->UnaryExpr.expr);
+ if (x->kind == Ast_CompoundLit) {
+ error(expr, "Cannot return the address to a stack value from a procedure");
+ } else if (x->kind == Ast_IndexExpr) {
+ Ast *array = x->IndexExpr.expr;
+ if (is_type_array_like(type_of_expr(array)) && check_expr_is_stack_variable(array)) {
+ gbString t = type_to_string(type_of_expr(array));
+ error(expr, "Cannot return the address to an element of stack variable from a procedure, of type %s", t);
+ gb_string_free(t);
+ }
+ } else {
+ if (check_expr_is_stack_variable(x)) {
+ error(expr, "Cannot return the address to a stack variable from a procedure");
+ }
+ }
+ }
}
}
case_end;
diff --git a/src/check_type.cpp b/src/check_type.cpp
index dea523599..da0a9706b 100644
--- a/src/check_type.cpp
+++ b/src/check_type.cpp
@@ -695,11 +695,6 @@ void check_union_type(CheckerContext *ctx, Type *union_type, Ast *node, Array<Op
error(ut->align, "A union with #no_nil must have at least 2 variants");
}
break;
- case UnionType_maybe:
- if (variants.count != 1) {
- error(ut->align, "A union with #maybe must have at 1 variant, got %lld", cast(long long)variants.count);
- }
- break;
}
if (ut->align != nullptr) {
@@ -2698,9 +2693,12 @@ bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, Type *named_t
case_ast_node(ue, UnaryExpr, e);
switch (ue->op.kind) {
case Token_Pointer:
- *type = alloc_type_pointer(check_type(ctx, ue->expr));
- set_base_type(named_type, *type);
- return true;
+ {
+ Type *elem = check_type(ctx, ue->expr);
+ *type = alloc_type_pointer(elem);
+ set_base_type(named_type, *type);
+ return true;
+ }
}
case_end;
@@ -2726,7 +2724,24 @@ bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, Type *named_t
elem = o.type;
}
- *type = alloc_type_pointer(elem);
+ if (pt->tag != nullptr) {
+ GB_ASSERT(pt->tag->kind == Ast_BasicDirective);
+ String name = pt->tag->BasicDirective.name.string;
+ if (name == "soa") {
+ // TODO(bill): generic #soa pointers
+ if (is_type_soa_struct(elem)) {
+ *type = alloc_type_soa_pointer(elem);
+ } else {
+ error(pt->tag, "#soa pointers require an #soa record type as the element");
+ *type = alloc_type_pointer(elem);
+ }
+ } else {
+ error(pt->tag, "Invalid tag applied to pointer, got #%.*s", LIT(name));
+ *type = alloc_type_pointer(elem);
+ }
+ } else {
+ *type = alloc_type_pointer(elem);
+ }
set_base_type(named_type, *type);
return true;
case_end;
diff --git a/src/checker.cpp b/src/checker.cpp
index 874839ece..a7470a4c9 100644
--- a/src/checker.cpp
+++ b/src/checker.cpp
@@ -1037,6 +1037,9 @@ void init_universal(void) {
add_global_bool_constant("ODIN_FOREIGN_ERROR_PROCEDURES", bc->ODIN_FOREIGN_ERROR_PROCEDURES);
add_global_bool_constant("ODIN_DISALLOW_RTTI", bc->disallow_rtti);
+ add_global_bool_constant("ODIN_VALGRIND_SUPPORT", bc->ODIN_VALGRIND_SUPPORT);
+
+
// Builtin Procedures
for (isize i = 0; i < gb_count_of(builtin_procs); i++) {
@@ -1170,6 +1173,8 @@ void init_checker_info(CheckerInfo *i) {
mutex_init(&i->objc_types_mutex);
map_init(&i->objc_msgSend_types, a);
+ mutex_init(&i->load_file_mutex);
+ string_map_init(&i->load_file_cache, a);
}
void destroy_checker_info(CheckerInfo *i) {
@@ -1205,6 +1210,8 @@ void destroy_checker_info(CheckerInfo *i) {
mutex_destroy(&i->objc_types_mutex);
map_destroy(&i->objc_msgSend_types);
+ mutex_init(&i->load_file_mutex);
+ string_map_destroy(&i->load_file_cache);
}
CheckerContext make_checker_context(Checker *c) {
@@ -1947,6 +1954,11 @@ void add_type_info_type_internal(CheckerContext *c, Type *t) {
add_type_info_type_internal(c, bt->Matrix.elem);
break;
+ case Type_SoaPointer:
+ add_type_info_type_internal(c, bt->SoaPointer.elem);
+ break;
+
+
default:
GB_PANIC("Unhandled type: %*.s %d", LIT(type_strings[bt->kind]), bt->kind);
break;
@@ -2164,6 +2176,10 @@ void add_min_dep_type_info(Checker *c, Type *t) {
add_min_dep_type_info(c, bt->Matrix.elem);
break;
+ case Type_SoaPointer:
+ add_min_dep_type_info(c, bt->SoaPointer.elem);
+ break;
+
default:
GB_PANIC("Unhandled type: %*.s", LIT(type_strings[bt->kind]));
break;
@@ -2756,6 +2772,7 @@ void init_core_type_info(Checker *c) {
t_type_info_relative_pointer = find_core_type(c, str_lit("Type_Info_Relative_Pointer"));
t_type_info_relative_slice = find_core_type(c, str_lit("Type_Info_Relative_Slice"));
t_type_info_matrix = find_core_type(c, str_lit("Type_Info_Matrix"));
+ t_type_info_soa_pointer = find_core_type(c, str_lit("Type_Info_Soa_Pointer"));
t_type_info_named_ptr = alloc_type_pointer(t_type_info_named);
t_type_info_integer_ptr = alloc_type_pointer(t_type_info_integer);
@@ -2784,6 +2801,7 @@ void init_core_type_info(Checker *c) {
t_type_info_relative_pointer_ptr = alloc_type_pointer(t_type_info_relative_pointer);
t_type_info_relative_slice_ptr = alloc_type_pointer(t_type_info_relative_slice);
t_type_info_matrix_ptr = alloc_type_pointer(t_type_info_matrix);
+ t_type_info_soa_pointer_ptr = alloc_type_pointer(t_type_info_soa_pointer);
}
void init_mem_allocator(Checker *c) {
diff --git a/src/checker.hpp b/src/checker.hpp
index f11a00532..badcd93d5 100644
--- a/src/checker.hpp
+++ b/src/checker.hpp
@@ -287,6 +287,12 @@ struct ObjcMsgData {
ObjcMsgKind kind;
Type *proc_type;
};
+struct LoadFileCache {
+ String path;
+ gbFileError file_error;
+ String data;
+ StringMap<u64> hashes;
+};
// CheckerInfo stores all the symbol information for a type-checked program
struct CheckerInfo {
@@ -363,6 +369,9 @@ struct CheckerInfo {
BlockingMutex objc_types_mutex;
PtrMap<Ast *, ObjcMsgData> objc_msgSend_types;
+
+ BlockingMutex load_file_mutex;
+ StringMap<LoadFileCache *> load_file_cache;
};
struct CheckerContext {
diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp
index 05f256775..717422df1 100644
--- a/src/checker_builtin_procs.hpp
+++ b/src/checker_builtin_procs.hpp
@@ -40,6 +40,8 @@ enum BuiltinProcId {
BuiltinProc_hadamard_product,
BuiltinProc_matrix_flatten,
+ BuiltinProc_unreachable,
+
BuiltinProc_DIRECTIVE, // NOTE(bill): This is used for specialized hash-prefixed procedures
// "Intrinsics"
@@ -289,6 +291,8 @@ BuiltinProc__type_end,
BuiltinProc_wasm_memory_atomic_wait32,
BuiltinProc_wasm_memory_atomic_notify32,
+ BuiltinProc_valgrind_client_request,
+
BuiltinProc_COUNT,
};
gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
@@ -330,6 +334,8 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
{STR_LIT("hadamard_product"), 2, false, Expr_Expr, BuiltinProcPkg_builtin},
{STR_LIT("matrix_flatten"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
+ {STR_LIT("unreachable"), 0, false, Expr_Expr, BuiltinProcPkg_builtin, /*diverging*/true},
+
{STR_LIT(""), 0, true, Expr_Expr, BuiltinProcPkg_builtin}, // DIRECTIVE
@@ -341,7 +347,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
{STR_LIT("alloca"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("cpu_relax"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
- {STR_LIT("trap"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics, /*diverging*/true},
+ {STR_LIT("trap"), 0, false, Expr_Expr, BuiltinProcPkg_intrinsics, /*diverging*/true},
{STR_LIT("debug_trap"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics, /*diverging*/false},
{STR_LIT("read_cycle_counter"), 0, false, Expr_Expr, BuiltinProcPkg_intrinsics},
@@ -434,7 +440,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
{STR_LIT("simd_neg"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
- {STR_LIT("simd_abs"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
+ {STR_LIT("simd_abs"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("simd_min"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("simd_max"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
@@ -578,4 +584,6 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
{STR_LIT("wasm_memory_size"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("wasm_memory_atomic_wait32"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("wasm_memory_atomic_notify32"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
+
+ {STR_LIT("valgrind_client_request"), 7, false, Expr_Expr, BuiltinProcPkg_intrinsics},
};
diff --git a/src/docs_format.cpp b/src/docs_format.cpp
index ee32d0e05..b13b8b364 100644
--- a/src/docs_format.cpp
+++ b/src/docs_format.cpp
@@ -83,6 +83,7 @@ enum OdinDocTypeKind : u32 {
OdinDocType_RelativeSlice = 21,
OdinDocType_MultiPointer = 22,
OdinDocType_Matrix = 23,
+ OdinDocType_SoaPointer = 24,
};
enum OdinDocTypeFlag_Basic : u32 {
@@ -98,7 +99,6 @@ enum OdinDocTypeFlag_Struct : u32 {
enum OdinDocTypeFlag_Union : u32 {
OdinDocTypeFlag_Union_polymorphic = 1<<0,
OdinDocTypeFlag_Union_no_nil = 1<<1,
- OdinDocTypeFlag_Union_maybe = 1<<2,
OdinDocTypeFlag_Union_shared_nil = 1<<3,
};
diff --git a/src/docs_writer.cpp b/src/docs_writer.cpp
index 2f531a45c..1b8e1fc34 100644
--- a/src/docs_writer.cpp
+++ b/src/docs_writer.cpp
@@ -532,6 +532,10 @@ OdinDocTypeIndex odin_doc_type(OdinDocWriter *w, Type *type) {
doc_type.kind = OdinDocType_MultiPointer;
doc_type.types = odin_doc_type_as_slice(w, type->MultiPointer.elem);
break;
+ case Type_SoaPointer:
+ doc_type.kind = OdinDocType_SoaPointer;
+ doc_type.types = odin_doc_type_as_slice(w, type->SoaPointer.elem);
+ break;
case Type_Array:
doc_type.kind = OdinDocType_Array;
doc_type.elem_count_len = 1;
diff --git a/src/gb/gb.h b/src/gb/gb.h
index d09c7618b..90f2fd15a 100644
--- a/src/gb/gb.h
+++ b/src/gb/gb.h
@@ -90,7 +90,7 @@ extern "C" {
#error This operating system is not supported
#endif
-#if defined(GB_SYSTEM_OPENBSD)
+#if defined(GB_SYSTEM_UNIX)
#include <sys/wait.h>
#endif
diff --git a/src/llvm_abi.cpp b/src/llvm_abi.cpp
index b22a839b3..4bdc31077 100644
--- a/src/llvm_abi.cpp
+++ b/src/llvm_abi.cpp
@@ -62,7 +62,7 @@ bool lb_is_type_kind(LLVMTypeRef type, LLVMTypeKind kind) {
return LLVMGetTypeKind(type) == kind;
}
-LLVMTypeRef lb_function_type_to_llvm_ptr(lbFunctionType *ft, bool is_var_arg) {
+LLVMTypeRef lb_function_type_to_llvm_raw(lbFunctionType *ft, bool is_var_arg) {
unsigned arg_count = cast(unsigned)ft->args.count;
unsigned offset = 0;
@@ -108,10 +108,16 @@ LLVMTypeRef lb_function_type_to_llvm_ptr(lbFunctionType *ft, bool is_var_arg) {
}
unsigned total_arg_count = arg_index;
LLVMTypeRef func_type = LLVMFunctionType(ret, args, total_arg_count, is_var_arg);
- return LLVMPointerType(func_type, 0);
+ return func_type;
}
+// LLVMTypeRef lb_function_type_to_llvm_ptr(lbFunctionType *ft, bool is_var_arg) {
+// LLVMTypeRef func_type = lb_function_type_to_llvm_raw(ft, is_var_arg);
+// return LLVMPointerType(func_type, 0);
+// }
+
+
void lb_add_function_type_attributes(LLVMValueRef fn, lbFunctionType *ft, ProcCallingConvention calling_convention) {
if (ft == nullptr) {
return;
@@ -217,7 +223,7 @@ i64 lb_sizeof(LLVMTypeRef type) {
break;
case LLVMArrayTypeKind:
{
- LLVMTypeRef elem = LLVMGetElementType(type);
+ LLVMTypeRef elem = OdinLLVMGetArrayElementType(type);
i64 elem_size = lb_sizeof(elem);
i64 count = LLVMGetArrayLength(type);
i64 size = count * elem_size;
@@ -229,7 +235,7 @@ i64 lb_sizeof(LLVMTypeRef type) {
return 8;
case LLVMVectorTypeKind:
{
- LLVMTypeRef elem = LLVMGetElementType(type);
+ LLVMTypeRef elem = OdinLLVMGetVectorElementType(type);
i64 elem_size = lb_sizeof(elem);
i64 count = LLVMGetVectorSize(type);
i64 size = count * elem_size;
@@ -277,18 +283,18 @@ i64 lb_alignof(LLVMTypeRef type) {
}
break;
case LLVMArrayTypeKind:
- return lb_alignof(LLVMGetElementType(type));
+ return lb_alignof(OdinLLVMGetArrayElementType(type));
case LLVMX86_MMXTypeKind:
return 8;
case LLVMVectorTypeKind:
{
// TODO(bill): This appears to be correct but LLVM isn't necessarily "great" with regards to documentation
- LLVMTypeRef elem = LLVMGetElementType(type);
+ LLVMTypeRef elem = OdinLLVMGetVectorElementType(type);
i64 elem_size = lb_sizeof(elem);
i64 count = LLVMGetVectorSize(type);
i64 size = count * elem_size;
- return gb_clamp(next_pow2(size), 1, build_context.max_align);
+ return gb_clamp(next_pow2(size), 1, build_context.max_simd_align);
}
}
@@ -787,7 +793,7 @@ namespace lbAbiAmd64SysV {
case LLVMArrayTypeKind:
{
i64 len = LLVMGetArrayLength(t);
- LLVMTypeRef elem = LLVMGetElementType(t);
+ LLVMTypeRef elem = OdinLLVMGetArrayElementType(t);
i64 elem_sz = lb_sizeof(elem);
for (i64 i = 0; i < len; i++) {
classify_with(elem, cls, ix, off + i*elem_sz);
@@ -797,7 +803,7 @@ namespace lbAbiAmd64SysV {
case LLVMVectorTypeKind:
{
i64 len = LLVMGetVectorSize(t);
- LLVMTypeRef elem = LLVMGetElementType(t);
+ LLVMTypeRef elem = OdinLLVMGetVectorElementType(t);
i64 elem_sz = lb_sizeof(elem);
LLVMTypeKind elem_kind = LLVMGetTypeKind(elem);
RegClass reg = RegClass_NoClass;
@@ -907,7 +913,7 @@ namespace lbAbiArm64 {
if (len == 0) {
return false;
}
- LLVMTypeRef elem = LLVMGetElementType(type);
+ LLVMTypeRef elem = OdinLLVMGetArrayElementType(type);
LLVMTypeRef base_type = nullptr;
unsigned member_count = 0;
if (is_homogenous_aggregate(c, elem, &base_type, &member_count)) {
@@ -1123,7 +1129,7 @@ namespace lbAbiWasm {
}
if (sz <= MAX_DIRECT_STRUCT_SIZE) {
if (kind == LLVMArrayTypeKind) {
- if (is_basic_register_type(LLVMGetElementType(type))) {
+ if (is_basic_register_type(OdinLLVMGetArrayElementType(type))) {
return true;
}
} else if (kind == LLVMStructTypeKind) {
diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp
index cf7389ec1..6ee1541d6 100644
--- a/src/llvm_backend.cpp
+++ b/src/llvm_backend.cpp
@@ -739,11 +739,11 @@ lbProcedure *lb_create_startup_runtime(lbModule *main_module, lbProcedure *start
lb_begin_procedure_body(p);
if (startup_type_info) {
- LLVMBuildCall2(p->builder, LLVMGetElementType(lb_type(main_module, startup_type_info->type)), startup_type_info->value, nullptr, 0, "");
+ LLVMBuildCall2(p->builder, lb_type_internal_for_procedures_raw(main_module, startup_type_info->type), startup_type_info->value, nullptr, 0, "");
}
if (objc_names) {
- LLVMBuildCall2(p->builder, LLVMGetElementType(lb_type(main_module, objc_names->type)), objc_names->value, nullptr, 0, "");
+ LLVMBuildCall2(p->builder, lb_type_internal_for_procedures_raw(main_module, objc_names->type), objc_names->value, nullptr, 0, "");
}
for_array(i, global_variables) {
@@ -762,7 +762,7 @@ lbProcedure *lb_create_startup_runtime(lbModule *main_module, lbProcedure *start
if (init_expr != nullptr) {
lbValue init = lb_build_expr(p, init_expr);
if (init.value == nullptr) {
- LLVMTypeRef global_type = LLVMGetElementType(LLVMTypeOf(var->var.value));
+ LLVMTypeRef global_type = llvm_addr_type(p->module, var->var);
if (is_type_untyped_undef(init.type)) {
// LLVMSetInitializer(var->var.value, LLVMGetUndef(global_type));
LLVMSetInitializer(var->var.value, LLVMConstNull(global_type));
@@ -805,8 +805,7 @@ lbProcedure *lb_create_startup_runtime(lbModule *main_module, lbProcedure *start
lb_emit_store(p, data, lb_emit_conv(p, gp, t_rawptr));
lb_emit_store(p, ti, lb_type_info(main_module, var_type));
} else {
- LLVMTypeRef pvt = LLVMTypeOf(var->var.value);
- LLVMTypeRef vt = LLVMGetElementType(pvt);
+ LLVMTypeRef vt = llvm_addr_type(p->module, var->var);
lbValue src0 = lb_emit_conv(p, var->init, t);
LLVMValueRef src = OdinLLVMBuildTransmute(p, src0.value, vt);
LLVMValueRef dst = var->var.value;
@@ -933,7 +932,7 @@ lbProcedure *lb_create_main_procedure(lbModule *m, lbProcedure *startup_runtime)
GB_ASSERT(LLVMIsConstant(vals[1]));
GB_ASSERT(LLVMIsConstant(vals[2]));
- LLVMValueRef dst = LLVMConstInBoundsGEP(all_tests_array.value, indices, gb_count_of(indices));
+ LLVMValueRef dst = LLVMConstInBoundsGEP2(llvm_addr_type(m, all_tests_array), all_tests_array.value, indices, gb_count_of(indices));
LLVMValueRef src = llvm_const_named_struct(m, t_Internal_Test, vals, gb_count_of(vals));
LLVMBuildStore(p->builder, src, dst);
diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp
index a09286d0b..79f0f37e7 100644
--- a/src/llvm_backend.hpp
+++ b/src/llvm_backend.hpp
@@ -42,6 +42,18 @@
#define ODIN_LLVM_MINIMUM_VERSION_12 0
#endif
+#if LLVM_VERSION_MAJOR > 13 || (LLVM_VERSION_MAJOR == 13 && LLVM_VERSION_MINOR >= 0 && LLVM_VERSION_PATCH > 0)
+#define ODIN_LLVM_MINIMUM_VERSION_13 1
+#else
+#define ODIN_LLVM_MINIMUM_VERSION_13 0
+#endif
+
+#if LLVM_VERSION_MAJOR > 14 || (LLVM_VERSION_MAJOR == 14 && LLVM_VERSION_MINOR >= 0 && LLVM_VERSION_PATCH > 0)
+#define ODIN_LLVM_MINIMUM_VERSION_14 1
+#else
+#define ODIN_LLVM_MINIMUM_VERSION_14 0
+#endif
+
struct lbProcedure;
struct lbValue {
@@ -115,6 +127,7 @@ struct lbModule {
AstPackage *pkg; // associated
PtrMap<Type *, LLVMTypeRef> types;
+ PtrMap<Type *, LLVMTypeRef> func_raw_types;
PtrMap<void *, lbStructFieldRemapping> struct_field_remapping; // Key: LLVMTypeRef or Type *
i32 internal_type_level;
@@ -299,7 +312,11 @@ struct lbProcedure {
-
+#if !ODIN_LLVM_MINIMUM_VERSION_14
+#define LLVMConstGEP2(Ty__, ConstantVal__, ConstantIndices__, NumIndices__) LLVMConstGEP(ConstantVal__, ConstantIndices__, NumIndices__)
+#define LLVMConstInBoundsGEP2(Ty__, ConstantVal__, ConstantIndices__, NumIndices__) LLVMConstInBoundsGEP(ConstantVal__, ConstantIndices__, NumIndices__)
+#define LLVMBuildPtrDiff2(Builder__, Ty__, LHS__, RHS__, Name__) LLVMBuildPtrDiff(Builder__, LHS__, RHS__, Name__)
+#endif
bool lb_init_generator(lbGenerator *gen, Checker *c);
@@ -314,7 +331,8 @@ lbProcedure *lb_create_procedure(lbModule *module, Entity *entity, bool ignore_b
void lb_end_procedure(lbProcedure *p);
-LLVMTypeRef lb_type(lbModule *m, Type *type);
+LLVMTypeRef lb_type(lbModule *m, Type *type);
+LLVMTypeRef llvm_get_element_type(LLVMTypeRef type);
lbBlock *lb_create_block(lbProcedure *p, char const *name, bool append=false);
@@ -327,7 +345,7 @@ lbValue lb_const_int(lbModule *m, Type *type, u64 value);
lbAddr lb_addr(lbValue addr);
Type *lb_addr_type(lbAddr const &addr);
-LLVMTypeRef lb_addr_lb_type(lbAddr const &addr);
+LLVMTypeRef llvm_addr_type(lbModule *module, lbValue addr_val);
void lb_addr_store(lbProcedure *p, lbAddr addr, lbValue value);
lbValue lb_addr_load(lbProcedure *p, lbAddr const &addr);
lbValue lb_emit_load(lbProcedure *p, lbValue v);
@@ -339,8 +357,9 @@ lbValue lb_build_expr(lbProcedure *p, Ast *expr);
lbAddr lb_build_addr(lbProcedure *p, Ast *expr);
void lb_build_stmt_list(lbProcedure *p, Array<Ast *> const &stmts);
-lbValue lb_build_gep(lbProcedure *p, lbValue const &value, i32 index) ;
-
+lbValue lb_emit_epi(lbProcedure *p, lbValue const &value, isize index);
+lbValue lb_emit_epi(lbModule *m, lbValue const &value, isize index);
+lbValue lb_emit_array_epi(lbModule *m, lbValue s, isize index);
lbValue lb_emit_struct_ep(lbProcedure *p, lbValue s, i32 index);
lbValue lb_emit_struct_ev(lbProcedure *p, lbValue s, i32 index);
lbValue lb_emit_array_epi(lbProcedure *p, lbValue value, isize index);
@@ -480,6 +499,7 @@ LLVMTypeRef lb_type_padding_filler(lbModule *m, i64 padding, i64 padding_align);
LLVMValueRef llvm_basic_shuffle(lbProcedure *p, LLVMValueRef vector, LLVMValueRef mask);
+LLVMValueRef lb_call_intrinsic(lbProcedure *p, const char *name, LLVMValueRef* args, unsigned arg_count, LLVMTypeRef* types, unsigned type_count);
void lb_mem_copy_overlapping(lbProcedure *p, lbValue dst, lbValue src, lbValue len, bool is_volatile=false);
void lb_mem_copy_non_overlapping(lbProcedure *p, lbValue dst, lbValue src, lbValue len, bool is_volatile=false);
LLVMValueRef lb_mem_zero_ptr_internal(lbProcedure *p, LLVMValueRef ptr, LLVMValueRef len, unsigned alignment, bool is_volatile);
@@ -488,6 +508,9 @@ i64 lb_max_zero_init_size(void) {
return cast(i64)(4*build_context.word_size);
}
+LLVMTypeRef OdinLLVMGetArrayElementType(LLVMTypeRef type);
+LLVMTypeRef OdinLLVMGetVectorElementType(LLVMTypeRef type);
+
#define LB_STARTUP_RUNTIME_PROC_NAME "__$startup_runtime"
#define LB_STARTUP_TYPE_INFO_PROC_NAME "__$startup_type_info"
#define LB_TYPE_INFO_DATA_NAME "__$type_info_data"
diff --git a/src/llvm_backend_const.cpp b/src/llvm_backend_const.cpp
index 24b2bc3a2..2d14070e2 100644
--- a/src/llvm_backend_const.cpp
+++ b/src/llvm_backend_const.cpp
@@ -10,11 +10,12 @@ bool lb_is_const(lbValue value) {
return false;
}
-
bool lb_is_const_or_global(lbValue value) {
if (lb_is_const(value)) {
return true;
}
+ // TODO remove use of LLVMGetElementType
+ #if 0
if (LLVMGetValueKind(value.value) == LLVMGlobalVariableValueKind) {
LLVMTypeRef t = LLVMGetElementType(LLVMTypeOf(value.value));
if (!lb_is_type_kind(t, LLVMPointerTypeKind)) {
@@ -23,6 +24,7 @@ bool lb_is_const_or_global(lbValue value) {
LLVMTypeRef elem = LLVMGetElementType(t);
return lb_is_type_kind(elem, LLVMFunctionTypeKind);
}
+ #endif
return false;
}
@@ -389,8 +391,8 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc
if (is_type_slice(type)) {
if (value.kind == ExactValue_String) {
- GB_ASSERT(is_type_u8_slice(type));
- res.value = lb_find_or_add_entity_string_byte_slice(m, value.value_string).value;
+ GB_ASSERT(is_type_slice(type));
+ res.value = lb_find_or_add_entity_string_byte_slice_with_type(m, value.value_string, original_type).value;
return res;
} else {
ast_node(cl, CompoundLit, value.value_compound);
@@ -418,7 +420,7 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc
{
LLVMValueRef indices[2] = {llvm_zero(m), llvm_zero(m)};
- LLVMValueRef ptr = LLVMBuildInBoundsGEP(p->builder, array_data, indices, 2, "");
+ LLVMValueRef ptr = LLVMBuildInBoundsGEP2(p->builder, llvm_type, array_data, indices, 2, "");
LLVMValueRef len = LLVMConstInt(lb_type(m, t_int), count, true);
lbAddr slice = lb_add_local_generated(p, type, false);
lb_fill_slice(p, slice, {ptr, alloc_type_pointer(elem)}, {len, t_int});
@@ -445,7 +447,7 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc
{
LLVMValueRef indices[2] = {llvm_zero(m), llvm_zero(m)};
- LLVMValueRef ptr = LLVMConstInBoundsGEP(array_data, indices, 2);
+ LLVMValueRef ptr = LLVMConstInBoundsGEP2(lb_type(m, t), array_data, indices, 2);
LLVMValueRef len = LLVMConstInt(lb_type(m, t_int), count, true);
LLVMValueRef values[2] = {ptr, len};
@@ -1007,7 +1009,7 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc
for (isize i = 0; i < value_count; i++) {
LLVMValueRef val = old_values[i];
if (!LLVMIsConstant(val)) {
- LLVMValueRef dst = LLVMBuildStructGEP(p->builder, v.addr.value, cast(unsigned)i, "");
+ LLVMValueRef dst = LLVMBuildStructGEP2(p->builder, llvm_addr_type(p->module, v.addr), v.addr.value, cast(unsigned)i, "");
LLVMBuildStore(p->builder, val, dst);
}
}
@@ -1041,7 +1043,6 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc
i64 v = big_int_to_i64(&tav.value.value_integer);
i64 lower = type->BitSet.lower;
u64 index = cast(u64)(v-lower);
- gb_printf_err("index: %llu\n", index);
BigInt bit = {};
big_int_from_u64(&bit, index);
big_int_shl(&bit, &one, &bit);
diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp
index b28470770..7d81d1407 100644
--- a/src/llvm_backend_expr.cpp
+++ b/src/llvm_backend_expr.cpp
@@ -137,7 +137,7 @@ lbValue lb_emit_unary_arith(lbProcedure *p, TokenKind op, lbValue x, Type *type)
lbAddr res_addr = lb_add_local(p, type, nullptr, false, 0, true);
lbValue res = lb_addr_get_ptr(p, res_addr);
- bool inline_array_arith = type_size_of(type) <= build_context.max_align;
+ bool inline_array_arith = lb_can_try_to_inline_array_arith(type);
i32 count = cast(i32)get_array_type_count(tl);
@@ -243,8 +243,9 @@ lbValue lb_emit_unary_arith(lbProcedure *p, TokenKind op, lbValue x, Type *type)
LLVMValueRef v1 = LLVMBuildFNeg(p->builder, LLVMBuildExtractValue(p->builder, x.value, 1, ""), "");
lbAddr addr = lb_add_local_generated(p, x.type, false);
- LLVMBuildStore(p->builder, v0, LLVMBuildStructGEP(p->builder, addr.addr.value, 0, ""));
- LLVMBuildStore(p->builder, v1, LLVMBuildStructGEP(p->builder, addr.addr.value, 1, ""));
+ LLVMTypeRef type = llvm_addr_type(p->module, addr.addr);
+ LLVMBuildStore(p->builder, v0, LLVMBuildStructGEP2(p->builder, type, addr.addr.value, 0, ""));
+ LLVMBuildStore(p->builder, v1, LLVMBuildStructGEP2(p->builder, type, addr.addr.value, 1, ""));
return lb_addr_load(p, addr);
} else if (is_type_quaternion(x.type)) {
@@ -254,10 +255,11 @@ lbValue lb_emit_unary_arith(lbProcedure *p, TokenKind op, lbValue x, Type *type)
LLVMValueRef v3 = LLVMBuildFNeg(p->builder, LLVMBuildExtractValue(p->builder, x.value, 3, ""), "");
lbAddr addr = lb_add_local_generated(p, x.type, false);
- LLVMBuildStore(p->builder, v0, LLVMBuildStructGEP(p->builder, addr.addr.value, 0, ""));
- LLVMBuildStore(p->builder, v1, LLVMBuildStructGEP(p->builder, addr.addr.value, 1, ""));
- LLVMBuildStore(p->builder, v2, LLVMBuildStructGEP(p->builder, addr.addr.value, 2, ""));
- LLVMBuildStore(p->builder, v3, LLVMBuildStructGEP(p->builder, addr.addr.value, 3, ""));
+ LLVMTypeRef type = llvm_addr_type(p->module, addr.addr);
+ LLVMBuildStore(p->builder, v0, LLVMBuildStructGEP2(p->builder, type, addr.addr.value, 0, ""));
+ LLVMBuildStore(p->builder, v1, LLVMBuildStructGEP2(p->builder, type, addr.addr.value, 1, ""));
+ LLVMBuildStore(p->builder, v2, LLVMBuildStructGEP2(p->builder, type, addr.addr.value, 2, ""));
+ LLVMBuildStore(p->builder, v3, LLVMBuildStructGEP2(p->builder, type, addr.addr.value, 3, ""));
return lb_addr_load(p, addr);
} else if (is_type_simd_vector(x.type)) {
Type *elem = base_array_type(x.type);
@@ -434,7 +436,7 @@ lbValue lb_emit_arith_array(lbProcedure *p, TokenKind op, lbValue lhs, lbValue r
return direct_vector_res;
}
- bool inline_array_arith = type_size_of(type) <= build_context.max_align;
+ bool inline_array_arith = lb_can_try_to_inline_array_arith(type);
if (inline_array_arith) {
auto dst_ptrs = slice_make<lbValue>(temporary_allocator(), n);
@@ -543,7 +545,7 @@ LLVMValueRef lb_matrix_to_vector(lbProcedure *p, lbValue matrix) {
#if 1
LLVMValueRef ptr = lb_address_from_load_or_generate_local(p, matrix).value;
LLVMValueRef matrix_vector_ptr = LLVMBuildPointerCast(p->builder, ptr, LLVMPointerType(total_matrix_type, 0), "");
- LLVMValueRef matrix_vector = LLVMBuildLoad(p->builder, matrix_vector_ptr, "");
+ LLVMValueRef matrix_vector = LLVMBuildLoad2(p->builder, total_matrix_type, matrix_vector_ptr, "");
LLVMSetAlignment(matrix_vector, cast(unsigned)type_align_of(mt));
return matrix_vector;
#else
@@ -555,7 +557,7 @@ LLVMValueRef lb_matrix_to_vector(lbProcedure *p, lbValue matrix) {
LLVMValueRef lb_matrix_trimmed_vector_mask(lbProcedure *p, Type *mt) {
mt = base_type(mt);
GB_ASSERT(mt->kind == Type_Matrix);
-
+
unsigned stride = cast(unsigned)matrix_type_stride_in_elems(mt);
unsigned row_count = cast(unsigned)mt->Matrix.row_count;
unsigned column_count = cast(unsigned)mt->Matrix.column_count;
@@ -567,23 +569,23 @@ LLVMValueRef lb_matrix_trimmed_vector_mask(lbProcedure *p, Type *mt) {
mask_elems[mask_elems_index++] = lb_const_int(p->module, t_u32, offset).value;
}
}
-
+
LLVMValueRef mask = LLVMConstVector(mask_elems.data, cast(unsigned)mask_elems.count);
return mask;
}
LLVMValueRef lb_matrix_to_trimmed_vector(lbProcedure *p, lbValue m) {
LLVMValueRef vector = lb_matrix_to_vector(p, m);
-
+
Type *mt = base_type(m.type);
GB_ASSERT(mt->kind == Type_Matrix);
-
+
unsigned stride = cast(unsigned)matrix_type_stride_in_elems(mt);
unsigned row_count = cast(unsigned)mt->Matrix.row_count;
if (stride == row_count) {
return vector;
}
-
+
LLVMValueRef mask = lb_matrix_trimmed_vector_mask(p, mt);
LLVMValueRef trimmed_vector = llvm_basic_shuffle(p, vector, mask);
return trimmed_vector;
@@ -619,28 +621,28 @@ lbValue lb_emit_matrix_tranpose(lbProcedure *p, lbValue m, Type *type) {
}
Type *mt = base_type(m.type);
GB_ASSERT(mt->kind == Type_Matrix);
-
+
if (lb_is_matrix_simdable(mt)) {
unsigned stride = cast(unsigned)matrix_type_stride_in_elems(mt);
unsigned row_count = cast(unsigned)mt->Matrix.row_count;
unsigned column_count = cast(unsigned)mt->Matrix.column_count;
-
+
auto rows = slice_make<LLVMValueRef>(permanent_allocator(), row_count);
auto mask_elems = slice_make<LLVMValueRef>(permanent_allocator(), column_count);
-
+
LLVMValueRef vector = lb_matrix_to_vector(p, m);
for (unsigned i = 0; i < row_count; i++) {
for (unsigned j = 0; j < column_count; j++) {
unsigned offset = stride*j + i;
mask_elems[j] = lb_const_int(p->module, t_u32, offset).value;
}
-
+
// transpose mask
LLVMValueRef mask = LLVMConstVector(mask_elems.data, column_count);
LLVMValueRef row = llvm_basic_shuffle(p, vector, mask);
rows[i] = row;
}
-
+
lbAddr res = lb_add_local_generated(p, type, true);
for_array(i, rows) {
LLVMValueRef row = rows[i];
@@ -649,12 +651,12 @@ lbValue lb_emit_matrix_tranpose(lbProcedure *p, lbValue m, Type *type) {
ptr = LLVMBuildPointerCast(p->builder, ptr, LLVMPointerType(LLVMTypeOf(row), 0), "");
LLVMBuildStore(p->builder, row, ptr);
}
-
+
return lb_addr_load(p, res);
}
-
+
lbAddr res = lb_add_local_generated(p, type, true);
-
+
i64 row_count = mt->Matrix.row_count;
i64 column_count = mt->Matrix.column_count;
for (i64 j = 0; j < column_count; j++) {
@@ -672,10 +674,10 @@ lbValue lb_matrix_cast_vector_to_type(lbProcedure *p, LLVMValueRef vector, Type
LLVMValueRef res_ptr = res.addr.value;
unsigned alignment = cast(unsigned)gb_max(type_align_of(type), lb_alignof(LLVMTypeOf(vector)));
LLVMSetAlignment(res_ptr, alignment);
-
+
res_ptr = LLVMBuildPointerCast(p->builder, res_ptr, LLVMPointerType(LLVMTypeOf(vector), 0), "");
LLVMBuildStore(p->builder, vector, res_ptr);
-
+
return lb_addr_load(p, res);
}
@@ -687,14 +689,14 @@ lbValue lb_emit_matrix_flatten(lbProcedure *p, lbValue m, Type *type) {
}
Type *mt = base_type(m.type);
GB_ASSERT(mt->kind == Type_Matrix);
-
+
if (lb_is_matrix_simdable(mt)) {
LLVMValueRef vector = lb_matrix_to_trimmed_vector(p, m);
return lb_matrix_cast_vector_to_type(p, vector, type);
}
-
+
lbAddr res = lb_add_local_generated(p, type, true);
-
+
i64 row_count = mt->Matrix.row_count;
i64 column_count = mt->Matrix.column_count;
for (i64 j = 0; j < column_count; j++) {
@@ -715,17 +717,17 @@ lbValue lb_emit_outer_product(lbProcedure *p, lbValue a, lbValue b, Type *type)
GB_ASSERT(mt->kind == Type_Matrix);
GB_ASSERT(at->kind == Type_Array);
GB_ASSERT(bt->kind == Type_Array);
-
-
+
+
i64 row_count = mt->Matrix.row_count;
i64 column_count = mt->Matrix.column_count;
-
+
GB_ASSERT(row_count == at->Array.count);
GB_ASSERT(column_count == bt->Array.count);
-
-
+
+
lbAddr res = lb_add_local_generated(p, type, true);
-
+
for (i64 j = 0; j < column_count; j++) {
for (i64 i = 0; i < row_count; i++) {
lbValue x = lb_emit_struct_ev(p, a, cast(i32)i);
@@ -741,51 +743,51 @@ lbValue lb_emit_outer_product(lbProcedure *p, lbValue a, lbValue b, Type *type)
lbValue lb_emit_matrix_mul(lbProcedure *p, lbValue lhs, lbValue rhs, Type *type) {
// TODO(bill): Handle edge case for f16 types on x86(-64) platforms
-
+
Type *xt = base_type(lhs.type);
Type *yt = base_type(rhs.type);
-
+
GB_ASSERT(is_type_matrix(type));
GB_ASSERT(is_type_matrix(xt));
GB_ASSERT(is_type_matrix(yt));
GB_ASSERT(xt->Matrix.column_count == yt->Matrix.row_count);
GB_ASSERT(are_types_identical(xt->Matrix.elem, yt->Matrix.elem));
-
+
Type *elem = xt->Matrix.elem;
-
+
unsigned outer_rows = cast(unsigned)xt->Matrix.row_count;
unsigned inner = cast(unsigned)xt->Matrix.column_count;
unsigned outer_columns = cast(unsigned)yt->Matrix.column_count;
-
+
if (lb_is_matrix_simdable(xt)) {
unsigned x_stride = cast(unsigned)matrix_type_stride_in_elems(xt);
unsigned y_stride = cast(unsigned)matrix_type_stride_in_elems(yt);
-
+
auto x_rows = slice_make<LLVMValueRef>(permanent_allocator(), outer_rows);
auto y_columns = slice_make<LLVMValueRef>(permanent_allocator(), outer_columns);
-
+
LLVMValueRef x_vector = lb_matrix_to_vector(p, lhs);
LLVMValueRef y_vector = lb_matrix_to_vector(p, rhs);
-
+
auto mask_elems = slice_make<LLVMValueRef>(permanent_allocator(), inner);
for (unsigned i = 0; i < outer_rows; i++) {
for (unsigned j = 0; j < inner; j++) {
unsigned offset = x_stride*j + i;
mask_elems[j] = lb_const_int(p->module, t_u32, offset).value;
}
-
+
// transpose mask
LLVMValueRef mask = LLVMConstVector(mask_elems.data, inner);
LLVMValueRef row = llvm_basic_shuffle(p, x_vector, mask);
x_rows[i] = row;
}
-
+
for (unsigned i = 0; i < outer_columns; i++) {
LLVMValueRef mask = llvm_mask_iota(p->module, y_stride*i, inner);
LLVMValueRef column = llvm_basic_shuffle(p, y_vector, mask);
y_columns[i] = column;
}
-
+
lbAddr res = lb_add_local_generated(p, type, true);
for_array(i, x_rows) {
LLVMValueRef x_row = x_rows[i];
@@ -795,15 +797,15 @@ lbValue lb_emit_matrix_mul(lbProcedure *p, lbValue lhs, lbValue rhs, Type *type)
lbValue dst = lb_emit_matrix_epi(p, res.addr, i, j);
LLVMBuildStore(p->builder, elem, dst.value);
}
- }
+ }
return lb_addr_load(p, res);
}
-
+
{
lbAddr res = lb_add_local_generated(p, type, true);
-
+
auto inners = slice_make<lbValue[2]>(permanent_allocator(), inner);
-
+
for (unsigned j = 0; j < outer_columns; j++) {
for (unsigned i = 0; i < outer_rows; i++) {
lbValue dst = lb_emit_matrix_epi(p, res.addr, i, j);
@@ -811,7 +813,7 @@ lbValue lb_emit_matrix_mul(lbProcedure *p, lbValue lhs, lbValue rhs, Type *type)
inners[k][0] = lb_emit_matrix_ev(p, lhs, i, k);
inners[k][1] = lb_emit_matrix_ev(p, rhs, k, j);
}
-
+
lbValue sum = lb_const_nil(p->module, elem);
for (unsigned k = 0; k < inner; k++) {
lbValue a = inners[k][0];
@@ -821,51 +823,51 @@ lbValue lb_emit_matrix_mul(lbProcedure *p, lbValue lhs, lbValue rhs, Type *type)
lb_emit_store(p, dst, sum);
}
}
-
+
return lb_addr_load(p, res);
}
}
lbValue lb_emit_matrix_mul_vector(lbProcedure *p, lbValue lhs, lbValue rhs, Type *type) {
// TODO(bill): Handle edge case for f16 types on x86(-64) platforms
-
+
Type *mt = base_type(lhs.type);
Type *vt = base_type(rhs.type);
-
+
GB_ASSERT(is_type_matrix(mt));
GB_ASSERT(is_type_array_like(vt));
-
+
i64 vector_count = get_array_type_count(vt);
-
+
GB_ASSERT(mt->Matrix.column_count == vector_count);
GB_ASSERT(are_types_identical(mt->Matrix.elem, base_array_type(vt)));
-
+
Type *elem = mt->Matrix.elem;
-
+
if (lb_is_matrix_simdable(mt)) {
unsigned stride = cast(unsigned)matrix_type_stride_in_elems(mt);
-
+
unsigned row_count = cast(unsigned)mt->Matrix.row_count;
unsigned column_count = cast(unsigned)mt->Matrix.column_count;
auto m_columns = slice_make<LLVMValueRef>(permanent_allocator(), column_count);
auto v_rows = slice_make<LLVMValueRef>(permanent_allocator(), column_count);
-
- LLVMValueRef matrix_vector = lb_matrix_to_vector(p, lhs);
-
+
+ LLVMValueRef matrix_vector = lb_matrix_to_vector(p, lhs);
+
for (unsigned column_index = 0; column_index < column_count; column_index++) {
LLVMValueRef mask = llvm_mask_iota(p->module, stride*column_index, row_count);
LLVMValueRef column = llvm_basic_shuffle(p, matrix_vector, mask);
m_columns[column_index] = column;
}
-
+
for (unsigned row_index = 0; row_index < column_count; row_index++) {
LLVMValueRef value = lb_emit_struct_ev(p, rhs, row_index).value;
LLVMValueRef row = llvm_vector_broadcast(p, value, row_count);
v_rows[row_index] = row;
}
-
+
GB_ASSERT(column_count > 0);
-
+
LLVMValueRef vector = nullptr;
for (i64 i = 0; i < column_count; i++) {
if (i == 0) {
@@ -874,51 +876,51 @@ lbValue lb_emit_matrix_mul_vector(lbProcedure *p, lbValue lhs, lbValue rhs, Type
vector = llvm_vector_mul_add(p, m_columns[i], v_rows[i], vector);
}
}
-
+
return lb_matrix_cast_vector_to_type(p, vector, type);
}
-
+
lbAddr res = lb_add_local_generated(p, type, true);
-
+
for (i64 i = 0; i < mt->Matrix.row_count; i++) {
for (i64 j = 0; j < mt->Matrix.column_count; j++) {
lbValue dst = lb_emit_matrix_epi(p, res.addr, i, 0);
lbValue d0 = lb_emit_load(p, dst);
-
+
lbValue a = lb_emit_matrix_ev(p, lhs, i, j);
lbValue b = lb_emit_struct_ev(p, rhs, cast(i32)j);
lbValue c = lb_emit_mul_add(p, a, b, d0, elem);
lb_emit_store(p, dst, c);
}
}
-
+
return lb_addr_load(p, res);
}
lbValue lb_emit_vector_mul_matrix(lbProcedure *p, lbValue lhs, lbValue rhs, Type *type) {
// TODO(bill): Handle edge case for f16 types on x86(-64) platforms
-
+
Type *mt = base_type(rhs.type);
Type *vt = base_type(lhs.type);
-
+
GB_ASSERT(is_type_matrix(mt));
GB_ASSERT(is_type_array_like(vt));
-
+
i64 vector_count = get_array_type_count(vt);
-
+
GB_ASSERT(vector_count == mt->Matrix.row_count);
GB_ASSERT(are_types_identical(mt->Matrix.elem, base_array_type(vt)));
-
+
Type *elem = mt->Matrix.elem;
-
+
if (lb_is_matrix_simdable(mt)) {
unsigned stride = cast(unsigned)matrix_type_stride_in_elems(mt);
-
+
unsigned row_count = cast(unsigned)mt->Matrix.row_count;
unsigned column_count = cast(unsigned)mt->Matrix.column_count; gb_unused(column_count);
auto m_columns = slice_make<LLVMValueRef>(permanent_allocator(), row_count);
auto v_rows = slice_make<LLVMValueRef>(permanent_allocator(), row_count);
-
+
LLVMValueRef matrix_vector = lb_matrix_to_vector(p, rhs);
auto mask_elems = slice_make<LLVMValueRef>(permanent_allocator(), column_count);
@@ -927,21 +929,21 @@ lbValue lb_emit_vector_mul_matrix(lbProcedure *p, lbValue lhs, lbValue rhs, Type
unsigned offset = row_index + column_index*stride;
mask_elems[column_index] = lb_const_int(p->module, t_u32, offset).value;
}
-
+
// transpose mask
LLVMValueRef mask = LLVMConstVector(mask_elems.data, column_count);
LLVMValueRef column = llvm_basic_shuffle(p, matrix_vector, mask);
m_columns[row_index] = column;
}
-
+
for (unsigned column_index = 0; column_index < row_count; column_index++) {
LLVMValueRef value = lb_emit_struct_ev(p, lhs, column_index).value;
LLVMValueRef row = llvm_vector_broadcast(p, value, column_count);
v_rows[column_index] = row;
}
-
+
GB_ASSERT(row_count > 0);
-
+
LLVMValueRef vector = nullptr;
for (i64 i = 0; i < row_count; i++) {
if (i == 0) {
@@ -955,27 +957,27 @@ lbValue lb_emit_vector_mul_matrix(lbProcedure *p, lbValue lhs, lbValue rhs, Type
LLVMValueRef res_ptr = res.addr.value;
unsigned alignment = cast(unsigned)gb_max(type_align_of(type), lb_alignof(LLVMTypeOf(vector)));
LLVMSetAlignment(res_ptr, alignment);
-
+
res_ptr = LLVMBuildPointerCast(p->builder, res_ptr, LLVMPointerType(LLVMTypeOf(vector), 0), "");
LLVMBuildStore(p->builder, vector, res_ptr);
-
+
return lb_addr_load(p, res);
}
-
+
lbAddr res = lb_add_local_generated(p, type, true);
-
+
for (i64 j = 0; j < mt->Matrix.column_count; j++) {
for (i64 k = 0; k < mt->Matrix.row_count; k++) {
lbValue dst = lb_emit_matrix_epi(p, res.addr, 0, j);
lbValue d0 = lb_emit_load(p, dst);
-
+
lbValue a = lb_emit_struct_ev(p, lhs, cast(i32)k);
lbValue b = lb_emit_matrix_ev(p, rhs, k, j);
lbValue c = lb_emit_mul_add(p, a, b, d0, elem);
lb_emit_store(p, dst, c);
}
}
-
+
return lb_addr_load(p, res);
}
@@ -984,12 +986,12 @@ lbValue lb_emit_vector_mul_matrix(lbProcedure *p, lbValue lhs, lbValue rhs, Type
lbValue lb_emit_arith_matrix(lbProcedure *p, TokenKind op, lbValue lhs, lbValue rhs, Type *type, bool component_wise) {
GB_ASSERT(is_type_matrix(lhs.type) || is_type_matrix(rhs.type));
-
-
+
+
if (op == Token_Mul && !component_wise) {
Type *xt = base_type(lhs.type);
Type *yt = base_type(rhs.type);
-
+
if (xt->kind == Type_Matrix) {
if (yt->kind == Type_Matrix) {
return lb_emit_matrix_mul(p, lhs, rhs, type);
@@ -1000,17 +1002,17 @@ lbValue lb_emit_arith_matrix(lbProcedure *p, TokenKind op, lbValue lhs, lbValue
GB_ASSERT(yt->kind == Type_Matrix);
return lb_emit_vector_mul_matrix(p, lhs, rhs, type);
}
-
+
} else {
if (is_type_matrix(lhs.type)) {
rhs = lb_emit_conv(p, rhs, lhs.type);
} else {
lhs = lb_emit_conv(p, lhs, rhs.type);
}
-
+
Type *xt = base_type(lhs.type);
Type *yt = base_type(rhs.type);
-
+
GB_ASSERT_MSG(are_types_identical(xt, yt), "%s %.*s %s", type_to_string(lhs.type), LIT(token_strings[op]), type_to_string(rhs.type));
GB_ASSERT(xt->kind == Type_Matrix);
// element-wise arithmetic
@@ -1019,8 +1021,8 @@ lbValue lb_emit_arith_matrix(lbProcedure *p, TokenKind op, lbValue lhs, lbValue
lbValue array_rhs = rhs;
Type *array_type = alloc_type_array(xt->Matrix.elem, matrix_type_total_internal_elems(xt));
GB_ASSERT(type_size_of(array_type) == type_size_of(xt));
-
- array_lhs.type = array_type;
+
+ array_lhs.type = array_type;
array_rhs.type = array_type;
if (token_is_comparison(op)) {
@@ -1033,7 +1035,7 @@ lbValue lb_emit_arith_matrix(lbProcedure *p, TokenKind op, lbValue lhs, lbValue
}
}
-
+
GB_PANIC("TODO: lb_emit_arith_matrix");
return {};
@@ -1314,13 +1316,13 @@ lbValue lb_build_binary_expr(lbProcedure *p, Ast *expr) {
ast_node(be, BinaryExpr, expr);
TypeAndValue tv = type_and_value_of_expr(expr);
-
+
if (is_type_matrix(be->left->tav.type) || is_type_matrix(be->right->tav.type)) {
lbValue left = lb_build_expr(p, be->left);
lbValue right = lb_build_expr(p, be->right);
return lb_emit_arith_matrix(p, be->op.kind, left, right, default_type(tv.type));
}
-
+
switch (be->op.kind) {
case Token_Add:
@@ -1690,7 +1692,7 @@ lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) {
}
return res;
}
-
+
if (is_type_complex(src) && is_type_complex(dst)) {
Type *ft = base_complex_elem_type(dst);
@@ -1775,12 +1777,9 @@ lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) {
lbValue res = {};
res = lb_emit_conv(p, value, platform_src_type);
res = lb_emit_conv(p, res, platform_dst_type);
- if (is_type_different_to_arch_endianness(dst)) {
- res = lb_emit_byte_swap(p, res, platform_dst_type);
- }
return lb_emit_conv(p, res, t);
}
-
+
if (is_type_integer_128bit(dst)) {
auto args = array_make<lbValue>(temporary_allocator(), 1);
args[0] = value;
@@ -2053,10 +2052,10 @@ lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) {
}
return lb_addr_load(p, v);
}
-
+
if (is_type_matrix(dst) && !is_type_matrix(src)) {
GB_ASSERT_MSG(dst->Matrix.row_count == dst->Matrix.column_count, "%s <- %s", type_to_string(dst), type_to_string(src));
-
+
Type *elem = base_array_type(dst);
lbValue e = lb_emit_conv(p, value, elem);
lbAddr v = lb_add_local_generated(p, t, false);
@@ -2065,16 +2064,16 @@ lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) {
lbValue ptr = lb_emit_matrix_epi(p, v.addr, j, j);
lb_emit_store(p, ptr, e);
}
-
-
+
+
return lb_addr_load(p, v);
}
-
+
if (is_type_matrix(dst) && is_type_matrix(src)) {
GB_ASSERT(dst->kind == Type_Matrix);
GB_ASSERT(src->kind == Type_Matrix);
lbAddr v = lb_add_local_generated(p, t, true);
-
+
if (is_matrix_square(dst) && is_matrix_square(dst)) {
for (i64 j = 0; j < dst->Matrix.column_count; j++) {
for (i64 i = 0; i < dst->Matrix.row_count; i++) {
@@ -2093,15 +2092,15 @@ lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) {
i64 dst_count = dst->Matrix.row_count*dst->Matrix.column_count;
i64 src_count = src->Matrix.row_count*src->Matrix.column_count;
GB_ASSERT(dst_count == src_count);
-
+
lbValue pdst = v.addr;
lbValue psrc = lb_address_from_load_or_generate_local(p, value);
-
+
bool same_elem_base_types = are_types_identical(
base_type(dst->Matrix.elem),
base_type(src->Matrix.elem)
);
-
+
if (same_elem_base_types && type_size_of(dst) == type_size_of(src)) {
lb_mem_copy_overlapping(p, v.addr, psrc, lb_const_int(p->module, t_int, type_size_of(dst)));
} else {
@@ -2115,9 +2114,9 @@ lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) {
}
}
return lb_addr_load(p, v);
- }
-
-
+ }
+
+
if (is_type_any(dst)) {
if (is_type_untyped_nil(src)) {
@@ -2270,6 +2269,9 @@ lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left, lbValue ri
}
}
+ a = core_type(left.type);
+ b = core_type(right.type);
+
if (is_type_matrix(a) && (op_kind == Token_CmpEq || op_kind == Token_NotEq)) {
Type *tl = base_type(a);
lbValue lhs = lb_address_from_load_or_generate_local(p, left);
@@ -2301,7 +2303,7 @@ lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left, lbValue ri
cmp_op = Token_And;
}
- bool inline_array_arith = type_size_of(tl) <= build_context.max_align;
+ bool inline_array_arith = lb_can_try_to_inline_array_arith(tl);
i32 count = 0;
switch (tl->kind) {
case Type_Array: count = cast(i32)tl->Array.count; break;
@@ -2721,7 +2723,7 @@ lbValue lb_emit_comp_against_nil(lbProcedure *p, TokenKind op_kind, lbValue x) {
unsigned indices[2] = {0, 0};
lbValue hashes_data = lb_emit_struct_ep(p, map_ptr, 0);
lbValue hashes_data_ptr_ptr = lb_emit_struct_ep(p, hashes_data, 0);
- LLVMValueRef hashes_data_ptr = LLVMBuildLoad(p->builder, hashes_data_ptr_ptr.value, "");
+ LLVMValueRef hashes_data_ptr = LLVMBuildLoad2(p->builder, llvm_addr_type(p->module, hashes_data_ptr_ptr), hashes_data_ptr_ptr.value, "");
if (op_kind == Token_CmpEq) {
res.value = LLVMBuildIsNull(p->builder, hashes_data_ptr, "");
@@ -2800,7 +2802,15 @@ lbValue lb_emit_comp_against_nil(lbProcedure *p, TokenKind op_kind, lbValue x) {
return {};
}
+lbValue lb_make_soa_pointer(lbProcedure *p, Type *type, lbValue const &addr, lbValue const &index) {
+ lbAddr v = lb_add_local_generated(p, type, false);
+ lbValue ptr = lb_emit_struct_ep(p, v.addr, 0);
+ lbValue idx = lb_emit_struct_ep(p, v.addr, 1);
+ lb_emit_store(p, ptr, addr);
+ lb_emit_store(p, idx, index);
+ return lb_addr_load(p, v);
+}
lbValue lb_build_unary_and(lbProcedure *p, Ast *expr) {
ast_node(ue, UnaryExpr, expr);
@@ -2839,7 +2849,17 @@ lbValue lb_build_unary_and(lbProcedure *p, Ast *expr) {
lb_emit_store(p, gep1, ok);
return lb_addr_load(p, res);
- } if (ue_expr->kind == Ast_CompoundLit) {
+ } else if (is_type_soa_pointer(tv.type)) {
+ ast_node(ie, IndexExpr, ue_expr);
+ lbValue addr = lb_build_addr_ptr(p, ie->expr);
+ lbValue index = lb_build_expr(p, ie->index);
+
+ if (!build_context.no_bounds_check) {
+ // TODO(bill): soa bounds checking
+ }
+
+ return lb_make_soa_pointer(p, tv.type, addr, index);
+ } else if (ue_expr->kind == Ast_CompoundLit) {
lbValue v = lb_build_expr(p, ue->expr);
Type *type = v.type;
@@ -3322,7 +3342,7 @@ lbValue lb_build_expr_internal(lbProcedure *p, Ast *expr) {
default: GB_PANIC("Unhandled inline asm dialect"); break;
}
- LLVMTypeRef func_type = LLVMGetElementType(lb_type(p->module, t));
+ LLVMTypeRef func_type = lb_type_internal_for_procedures_raw(p->module, t);
LLVMValueRef the_asm = llvm_get_inline_asm(func_type, asm_string, constraints_string, ia->has_side_effects, ia->has_side_effects, dialect);
GB_ASSERT(the_asm != nullptr);
return {the_asm, t};
@@ -3468,6 +3488,901 @@ lbAddr lb_build_addr(lbProcedure *p, Ast *expr) {
return addr;
}
+void lb_build_addr_compound_lit_populate(lbProcedure *p, Slice<Ast *> const &elems, Array<lbCompoundLitElemTempData> *temp_data, Type *compound_type) {
+ Type *bt = base_type(compound_type);
+ Type *et = nullptr;
+ switch (bt->kind) {
+ case Type_Array: et = bt->Array.elem; break;
+ case Type_EnumeratedArray: et = bt->EnumeratedArray.elem; break;
+ case Type_Slice: et = bt->Slice.elem; break;
+ case Type_BitSet: et = bt->BitSet.elem; break;
+ case Type_DynamicArray: et = bt->DynamicArray.elem; break;
+ case Type_SimdVector: et = bt->SimdVector.elem; break;
+ case Type_Matrix: et = bt->Matrix.elem; break;
+ }
+ GB_ASSERT(et != nullptr);
+
+
+ // NOTE(bill): Separate value, gep, store into their own chunks
+ for_array(i, elems) {
+ Ast *elem = elems[i];
+ if (elem->kind == Ast_FieldValue) {
+ ast_node(fv, FieldValue, elem);
+ if (lb_is_elem_const(fv->value, et)) {
+ continue;
+ }
+ 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;
+ }
+
+ lbValue value = lb_emit_conv(p, lb_build_expr(p, fv->value), et);
+
+ GB_ASSERT((hi-lo) > 0);
+
+ if (bt->kind == Type_Matrix) {
+ for (i64 k = lo; k < hi; k++) {
+ lbCompoundLitElemTempData data = {};
+ data.value = value;
+
+ data.elem_index = matrix_row_major_index_to_offset(bt, k);
+ array_add(temp_data, data);
+ }
+ } else {
+ enum {MAX_ELEMENT_AMOUNT = 32};
+ if ((hi-lo) <= MAX_ELEMENT_AMOUNT) {
+ for (i64 k = lo; k < hi; k++) {
+ lbCompoundLitElemTempData data = {};
+ data.value = value;
+ data.elem_index = k;
+ array_add(temp_data, data);
+ }
+ } else {
+ lbCompoundLitElemTempData data = {};
+ data.value = value;
+ data.elem_index = lo;
+ data.elem_length = hi-lo;
+ array_add(temp_data, data);
+ }
+ }
+ } else {
+ auto tav = fv->field->tav;
+ GB_ASSERT(tav.mode == Addressing_Constant);
+ i64 index = exact_value_to_i64(tav.value);
+
+ lbValue value = lb_emit_conv(p, lb_build_expr(p, fv->value), et);
+ GB_ASSERT(!is_type_tuple(value.type));
+
+ lbCompoundLitElemTempData data = {};
+ data.value = value;
+ data.expr = fv->value;
+ if (bt->kind == Type_Matrix) {
+ data.elem_index = matrix_row_major_index_to_offset(bt, index);
+ } else {
+ data.elem_index = index;
+ }
+ array_add(temp_data, data);
+ }
+
+ } else {
+ if (bt->kind != Type_DynamicArray && lb_is_elem_const(elem, et)) {
+ continue;
+ }
+
+ lbValue field_expr = lb_build_expr(p, elem);
+ GB_ASSERT(!is_type_tuple(field_expr.type));
+
+ lbValue ev = lb_emit_conv(p, field_expr, et);
+
+ lbCompoundLitElemTempData data = {};
+ data.value = ev;
+ if (bt->kind == Type_Matrix) {
+ data.elem_index = matrix_row_major_index_to_offset(bt, i);
+ } else {
+ data.elem_index = i;
+ }
+ array_add(temp_data, data);
+ }
+ }
+}
+void lb_build_addr_compound_lit_assign_array(lbProcedure *p, Array<lbCompoundLitElemTempData> const &temp_data) {
+ for_array(i, temp_data) {
+ auto td = temp_data[i];
+ if (td.value.value != nullptr) {
+ if (td.elem_length > 0) {
+ auto loop_data = lb_loop_start(p, cast(isize)td.elem_length, t_i32);
+ {
+ lbValue dst = td.gep;
+ dst = lb_emit_ptr_offset(p, dst, loop_data.idx);
+ lb_emit_store(p, dst, td.value);
+ }
+ lb_loop_end(p, loop_data);
+ } else {
+ lb_emit_store(p, td.gep, td.value);
+ }
+ }
+ }
+}
+
+lbAddr lb_build_addr_index_expr(lbProcedure *p, Ast *expr) {
+ ast_node(ie, IndexExpr, expr);
+
+ Type *t = base_type(type_of_expr(ie->expr));
+
+ bool deref = is_type_pointer(t);
+ t = base_type(type_deref(t));
+ if (is_type_soa_struct(t)) {
+ // SOA STRUCTURES!!!!
+ lbValue val = lb_build_addr_ptr(p, ie->expr);
+ if (deref) {
+ val = lb_emit_load(p, val);
+ }
+
+ lbValue index = lb_build_expr(p, ie->index);
+ return lb_addr_soa_variable(val, index, ie->index);
+ }
+
+ if (ie->expr->tav.mode == Addressing_SoaVariable) {
+ // SOA Structures for slices/dynamic arrays
+ GB_ASSERT(is_type_pointer(type_of_expr(ie->expr)));
+
+ lbValue field = lb_build_expr(p, ie->expr);
+ lbValue index = lb_build_expr(p, ie->index);
+
+
+ if (!build_context.no_bounds_check) {
+ // TODO HACK(bill): Clean up this hack to get the length for bounds checking
+ // GB_ASSERT(LLVMIsALoadInst(field.value));
+
+ // lbValue a = {};
+ // a.value = LLVMGetOperand(field.value, 0);
+ // a.type = alloc_type_pointer(field.type);
+
+ // irInstr *b = &a->Instr;
+ // GB_ASSERT(b->kind == irInstr_StructElementPtr);
+ // lbValue base_struct = b->StructElementPtr.address;
+
+ // GB_ASSERT(is_type_soa_struct(type_deref(ir_type(base_struct))));
+ // lbValue len = ir_soa_struct_len(p, base_struct);
+ // lb_emit_bounds_check(p, ast_token(ie->index), index, len);
+ }
+ lbValue val = lb_emit_ptr_offset(p, field, index);
+ return lb_addr(val);
+ }
+
+ GB_ASSERT_MSG(is_type_indexable(t), "%s %s", type_to_string(t), expr_to_string(expr));
+
+ if (is_type_map(t)) {
+ lbAddr map_addr = lb_build_addr(p, ie->expr);
+ lbValue map_val = lb_addr_load(p, map_addr);
+ if (deref) {
+ map_val = lb_emit_load(p, map_val);
+ }
+
+ lbValue key = lb_build_expr(p, ie->index);
+ key = lb_emit_conv(p, key, t->Map.key);
+
+ Type *result_type = type_of_expr(expr);
+ lbValue map_ptr = lb_address_from_load_or_generate_local(p, map_val);
+ return lb_addr_map(map_ptr, key, t, result_type);
+ }
+
+ switch (t->kind) {
+ case Type_Array: {
+ lbValue array = {};
+ array = lb_build_addr_ptr(p, ie->expr);
+ if (deref) {
+ array = lb_emit_load(p, array);
+ }
+ lbValue index = lb_build_expr(p, ie->index);
+ index = lb_emit_conv(p, index, t_int);
+ lbValue elem = lb_emit_array_ep(p, array, index);
+
+ auto index_tv = type_and_value_of_expr(ie->index);
+ if (index_tv.mode != Addressing_Constant) {
+ lbValue len = lb_const_int(p->module, t_int, t->Array.count);
+ lb_emit_bounds_check(p, ast_token(ie->index), index, len);
+ }
+ return lb_addr(elem);
+ }
+
+ case Type_EnumeratedArray: {
+ lbValue array = {};
+ array = lb_build_addr_ptr(p, ie->expr);
+ if (deref) {
+ array = lb_emit_load(p, array);
+ }
+
+ Type *index_type = t->EnumeratedArray.index;
+
+ auto index_tv = type_and_value_of_expr(ie->index);
+
+ lbValue index = {};
+ if (compare_exact_values(Token_NotEq, *t->EnumeratedArray.min_value, exact_value_i64(0))) {
+ if (index_tv.mode == Addressing_Constant) {
+ ExactValue idx = exact_value_sub(index_tv.value, *t->EnumeratedArray.min_value);
+ index = lb_const_value(p->module, index_type, idx);
+ } else {
+ index = lb_emit_conv(p, lb_build_expr(p, ie->index), t_int);
+ index = lb_emit_arith(p, Token_Sub, index, lb_const_value(p->module, index_type, *t->EnumeratedArray.min_value), index_type);
+ }
+ } else {
+ index = lb_emit_conv(p, lb_build_expr(p, ie->index), t_int);
+ }
+
+ lbValue elem = lb_emit_array_ep(p, array, index);
+
+ if (index_tv.mode != Addressing_Constant) {
+ lbValue len = lb_const_int(p->module, t_int, t->EnumeratedArray.count);
+ lb_emit_bounds_check(p, ast_token(ie->index), index, len);
+ }
+ return lb_addr(elem);
+ }
+
+ case Type_Slice: {
+ lbValue slice = {};
+ slice = lb_build_expr(p, ie->expr);
+ if (deref) {
+ slice = lb_emit_load(p, slice);
+ }
+ lbValue elem = lb_slice_elem(p, slice);
+ lbValue index = lb_emit_conv(p, lb_build_expr(p, ie->index), t_int);
+ lbValue len = lb_slice_len(p, slice);
+ lb_emit_bounds_check(p, ast_token(ie->index), index, len);
+ lbValue v = lb_emit_ptr_offset(p, elem, index);
+ return lb_addr(v);
+ }
+
+ case Type_MultiPointer: {
+ lbValue multi_ptr = {};
+ multi_ptr = lb_build_expr(p, ie->expr);
+ if (deref) {
+ multi_ptr = lb_emit_load(p, multi_ptr);
+ }
+ lbValue index = lb_build_expr(p, ie->index);
+ lbValue v = {};
+
+ LLVMValueRef indices[1] = {index.value};
+ v.value = LLVMBuildGEP2(p->builder, lb_type(p->module, t->MultiPointer.elem), multi_ptr.value, indices, 1, "foo");
+ v.type = alloc_type_pointer(t->MultiPointer.elem);
+ return lb_addr(v);
+ }
+
+ case Type_RelativeSlice: {
+ lbAddr slice_addr = {};
+ if (deref) {
+ slice_addr = lb_addr(lb_build_expr(p, ie->expr));
+ } else {
+ slice_addr = lb_build_addr(p, ie->expr);
+ }
+ lbValue slice = lb_addr_load(p, slice_addr);
+
+ lbValue elem = lb_slice_elem(p, slice);
+ lbValue index = lb_emit_conv(p, lb_build_expr(p, ie->index), t_int);
+ lbValue len = lb_slice_len(p, slice);
+ lb_emit_bounds_check(p, ast_token(ie->index), index, len);
+ lbValue v = lb_emit_ptr_offset(p, elem, index);
+ return lb_addr(v);
+ }
+
+ case Type_DynamicArray: {
+ lbValue dynamic_array = {};
+ dynamic_array = lb_build_expr(p, ie->expr);
+ if (deref) {
+ dynamic_array = lb_emit_load(p, dynamic_array);
+ }
+ lbValue elem = lb_dynamic_array_elem(p, dynamic_array);
+ lbValue len = lb_dynamic_array_len(p, dynamic_array);
+ lbValue index = lb_emit_conv(p, lb_build_expr(p, ie->index), t_int);
+ lb_emit_bounds_check(p, ast_token(ie->index), index, len);
+ lbValue v = lb_emit_ptr_offset(p, elem, index);
+ return lb_addr(v);
+ }
+
+ case Type_Matrix: {
+ lbValue matrix = {};
+ matrix = lb_build_addr_ptr(p, ie->expr);
+ if (deref) {
+ matrix = lb_emit_load(p, matrix);
+ }
+ lbValue index = lb_build_expr(p, ie->index);
+ index = lb_emit_conv(p, index, t_int);
+ lbValue elem = lb_emit_matrix_ep(p, matrix, lb_const_int(p->module, t_int, 0), index);
+ elem = lb_emit_conv(p, elem, alloc_type_pointer(type_of_expr(expr)));
+
+ auto index_tv = type_and_value_of_expr(ie->index);
+ if (index_tv.mode != Addressing_Constant) {
+ lbValue len = lb_const_int(p->module, t_int, t->Matrix.column_count);
+ lb_emit_bounds_check(p, ast_token(ie->index), index, len);
+ }
+ return lb_addr(elem);
+ }
+
+
+ case Type_Basic: { // Basic_string
+ lbValue str;
+ lbValue elem;
+ lbValue len;
+ lbValue index;
+
+ str = lb_build_expr(p, ie->expr);
+ if (deref) {
+ str = lb_emit_load(p, str);
+ }
+ elem = lb_string_elem(p, str);
+ len = lb_string_len(p, str);
+
+ index = lb_emit_conv(p, lb_build_expr(p, ie->index), t_int);
+ lb_emit_bounds_check(p, ast_token(ie->index), index, len);
+
+ return lb_addr(lb_emit_ptr_offset(p, elem, index));
+ }
+ }
+ return {};
+}
+
+
+lbAddr lb_build_addr_slice_expr(lbProcedure *p, Ast *expr) {
+ ast_node(se, SliceExpr, expr);
+
+ lbValue low = lb_const_int(p->module, t_int, 0);
+ lbValue high = {};
+
+ if (se->low != nullptr) {
+ low = lb_correct_endianness(p, lb_build_expr(p, se->low));
+ }
+ if (se->high != nullptr) {
+ high = lb_correct_endianness(p, lb_build_expr(p, se->high));
+ }
+
+ 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;
+ lbValue len = lb_slice_len(p, base);
+ if (high.value == nullptr) high = len;
+
+ if (!no_indices) {
+ lb_emit_slice_bounds_check(p, se->open, low, high, len, se->low != nullptr);
+ }
+
+ lbValue elem = lb_emit_ptr_offset(p, lb_slice_elem(p, base), low);
+ lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int);
+
+ lbAddr slice = lb_add_local_generated(p, slice_type, false);
+ lb_fill_slice(p, slice, elem, new_len);
+ return slice;
+ }
+
+ case Type_RelativeSlice:
+ GB_PANIC("TODO(bill): Type_RelativeSlice should be handled above already on the lb_addr_load");
+ break;
+
+ case Type_DynamicArray: {
+ Type *elem_type = type->DynamicArray.elem;
+ Type *slice_type = alloc_type_slice(elem_type);
+
+ lbValue len = lb_dynamic_array_len(p, base);
+ if (high.value == nullptr) high = len;
+
+ if (!no_indices) {
+ lb_emit_slice_bounds_check(p, se->open, low, high, len, se->low != nullptr);
+ }
+
+ lbValue elem = lb_emit_ptr_offset(p, lb_dynamic_array_elem(p, base), low);
+ lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int);
+
+ lbAddr slice = lb_add_local_generated(p, slice_type, false);
+ lb_fill_slice(p, slice, elem, new_len);
+ return slice;
+ }
+
+ case Type_MultiPointer: {
+ lbAddr res = lb_add_local_generated(p, type_of_expr(expr), false);
+ if (se->high == nullptr) {
+ lbValue offset = base;
+ LLVMValueRef indices[1] = {low.value};
+ offset.value = LLVMBuildGEP2(p->builder, lb_type(p->module, offset.type->MultiPointer.elem), offset.value, indices, 1, "");
+ lb_addr_store(p, res, offset);
+ } else {
+ low = lb_emit_conv(p, low, t_int);
+ high = lb_emit_conv(p, high, t_int);
+
+ lb_emit_multi_pointer_slice_bounds_check(p, se->open, low, high);
+
+ LLVMValueRef indices[1] = {low.value};
+ LLVMValueRef ptr = LLVMBuildGEP2(p->builder, lb_type(p->module, base.type->MultiPointer.elem), base.value, indices, 1, "");
+ LLVMValueRef len = LLVMBuildSub(p->builder, high.value, low.value, "");
+
+ LLVMValueRef gep0 = lb_emit_struct_ep(p, res.addr, 0).value;
+ LLVMValueRef gep1 = lb_emit_struct_ep(p, res.addr, 1).value;
+ LLVMBuildStore(p->builder, ptr, gep0);
+ LLVMBuildStore(p->builder, len, gep1);
+ }
+ return res;
+ }
+
+ case Type_Array: {
+ Type *slice_type = alloc_type_slice(type->Array.elem);
+ lbValue len = lb_const_int(p->module, t_int, type->Array.count);
+
+ if (high.value == nullptr) high = len;
+
+ bool low_const = type_and_value_of_expr(se->low).mode == Addressing_Constant;
+ bool high_const = type_and_value_of_expr(se->high).mode == Addressing_Constant;
+
+ if (!low_const || !high_const) {
+ if (!no_indices) {
+ lb_emit_slice_bounds_check(p, se->open, low, high, len, se->low != nullptr);
+ }
+ }
+ lbValue elem = lb_emit_ptr_offset(p, lb_array_elem(p, lb_addr_get_ptr(p, addr)), low);
+ lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int);
+
+ lbAddr slice = lb_add_local_generated(p, slice_type, false);
+ lb_fill_slice(p, slice, elem, new_len);
+ return slice;
+ }
+
+ case Type_Basic: {
+ GB_ASSERT(type == t_string);
+ lbValue len = lb_string_len(p, base);
+ if (high.value == nullptr) high = len;
+
+ if (!no_indices) {
+ lb_emit_slice_bounds_check(p, se->open, low, high, len, se->low != nullptr);
+ }
+
+ lbValue elem = lb_emit_ptr_offset(p, lb_string_elem(p, base), low);
+ lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int);
+
+ lbAddr str = lb_add_local_generated(p, t_string, false);
+ lb_fill_string(p, str, elem, new_len);
+ return str;
+ }
+
+
+ case Type_Struct:
+ if (is_type_soa_struct(type)) {
+ lbValue len = lb_soa_struct_len(p, lb_addr_get_ptr(p, addr));
+ if (high.value == nullptr) high = len;
+
+ if (!no_indices) {
+ lb_emit_slice_bounds_check(p, se->open, low, high, len, se->low != nullptr);
+ }
+ #if 1
+
+ lbAddr dst = lb_add_local_generated(p, type_of_expr(expr), true);
+ if (type->Struct.soa_kind == StructSoa_Fixed) {
+ i32 field_count = cast(i32)type->Struct.fields.count;
+ for (i32 i = 0; i < field_count; i++) {
+ lbValue field_dst = lb_emit_struct_ep(p, dst.addr, i);
+ lbValue field_src = lb_emit_struct_ep(p, lb_addr_get_ptr(p, addr), i);
+ field_src = lb_emit_array_ep(p, field_src, low);
+ lb_emit_store(p, field_dst, field_src);
+ }
+
+ lbValue len_dst = lb_emit_struct_ep(p, dst.addr, field_count);
+ lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int);
+ lb_emit_store(p, len_dst, new_len);
+ } else if (type->Struct.soa_kind == StructSoa_Slice) {
+ if (no_indices) {
+ lb_addr_store(p, dst, base);
+ } else {
+ i32 field_count = cast(i32)type->Struct.fields.count - 1;
+ for (i32 i = 0; i < field_count; i++) {
+ lbValue field_dst = lb_emit_struct_ep(p, dst.addr, i);
+ lbValue field_src = lb_emit_struct_ev(p, base, i);
+ field_src = lb_emit_ptr_offset(p, field_src, low);
+ lb_emit_store(p, field_dst, field_src);
+ }
+
+
+ lbValue len_dst = lb_emit_struct_ep(p, dst.addr, field_count);
+ lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int);
+ lb_emit_store(p, len_dst, new_len);
+ }
+ } else if (type->Struct.soa_kind == StructSoa_Dynamic) {
+ i32 field_count = cast(i32)type->Struct.fields.count - 3;
+ for (i32 i = 0; i < field_count; i++) {
+ lbValue field_dst = lb_emit_struct_ep(p, dst.addr, i);
+ lbValue field_src = lb_emit_struct_ev(p, base, i);
+ field_src = lb_emit_ptr_offset(p, field_src, low);
+ lb_emit_store(p, field_dst, field_src);
+ }
+
+
+ lbValue len_dst = lb_emit_struct_ep(p, dst.addr, field_count);
+ lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int);
+ lb_emit_store(p, len_dst, new_len);
+ }
+
+ return dst;
+ #endif
+ }
+ break;
+
+ }
+
+ GB_PANIC("Unknown slicable type");
+ return {};
+}
+
+
+lbAddr lb_build_addr_compound_lit(lbProcedure *p, Ast *expr) {
+ ast_node(cl, CompoundLit, expr);
+
+ Type *type = type_of_expr(expr);
+ Type *bt = base_type(type);
+
+ lbAddr v = lb_add_local_generated(p, type, true);
+
+ Type *et = nullptr;
+ switch (bt->kind) {
+ case Type_Array: et = bt->Array.elem; break;
+ case Type_EnumeratedArray: et = bt->EnumeratedArray.elem; break;
+ case Type_Slice: et = bt->Slice.elem; break;
+ case Type_BitSet: et = bt->BitSet.elem; break;
+ case Type_SimdVector: et = bt->SimdVector.elem; break;
+ case Type_Matrix: et = bt->Matrix.elem; break;
+ }
+
+ String proc_name = {};
+ if (p->entity) {
+ proc_name = p->entity->token.string;
+ }
+ TokenPos pos = ast_token(expr).pos;
+
+ switch (bt->kind) {
+ default: GB_PANIC("Unknown CompoundLit type: %s", type_to_string(type)); break;
+
+ case Type_Struct: {
+ // TODO(bill): "constant" '#raw_union's are not initialized constantly at the moment.
+ // NOTE(bill): This is due to the layout of the unions when printed to LLVM-IR
+ bool is_raw_union = is_type_raw_union(bt);
+ GB_ASSERT(is_type_struct(bt) || is_raw_union);
+ TypeStruct *st = &bt->Struct;
+ if (cl->elems.count > 0) {
+ lb_addr_store(p, v, lb_const_value(p->module, type, exact_value_compound(expr)));
+ lbValue comp_lit_ptr = lb_addr_get_ptr(p, v);
+
+ for_array(field_index, cl->elems) {
+ Ast *elem = cl->elems[field_index];
+
+ lbValue field_expr = {};
+ Entity *field = nullptr;
+ isize index = field_index;
+
+ if (elem->kind == Ast_FieldValue) {
+ ast_node(fv, FieldValue, elem);
+ String name = fv->field->Ident.token.string;
+ Selection sel = lookup_field(bt, name, false);
+ index = sel.index[0];
+ elem = fv->value;
+ TypeAndValue tav = type_and_value_of_expr(elem);
+ } else {
+ TypeAndValue tav = type_and_value_of_expr(elem);
+ Selection sel = lookup_field_from_index(bt, st->fields[field_index]->Variable.field_index);
+ index = sel.index[0];
+ }
+
+ field = st->fields[index];
+ Type *ft = field->type;
+ if (!is_raw_union && !is_type_typeid(ft) && lb_is_elem_const(elem, ft)) {
+ continue;
+ }
+
+ field_expr = lb_build_expr(p, elem);
+
+ lbValue gep = {};
+ if (is_raw_union) {
+ gep = lb_emit_conv(p, comp_lit_ptr, alloc_type_pointer(ft));
+ } else {
+ gep = lb_emit_struct_ep(p, comp_lit_ptr, cast(i32)index);
+ }
+
+ Type *fet = field_expr.type;
+ GB_ASSERT(fet->kind != Type_Tuple);
+
+ // HACK TODO(bill): THIS IS A MASSIVE HACK!!!!
+ if (is_type_union(ft) && !are_types_identical(fet, ft) && !is_type_untyped(fet)) {
+ GB_ASSERT_MSG(union_variant_index(ft, fet) > 0, "%s", type_to_string(fet));
+
+ lb_emit_store_union_variant(p, gep, field_expr, fet);
+ } else {
+ lbValue fv = lb_emit_conv(p, field_expr, ft);
+ lb_emit_store(p, gep, fv);
+ }
+ }
+ }
+ break;
+ }
+
+ case Type_Map: {
+ if (cl->elems.count == 0) {
+ break;
+ }
+ GB_ASSERT(!build_context.no_dynamic_literals);
+ {
+ auto args = array_make<lbValue>(permanent_allocator(), 3);
+ args[0] = lb_gen_map_header(p, v.addr, type);
+ args[1] = lb_const_int(p->module, t_int, 2*cl->elems.count);
+ args[2] = lb_emit_source_code_location(p, proc_name, pos);
+ lb_emit_runtime_call(p, "__dynamic_map_reserve", args);
+ }
+ for_array(field_index, cl->elems) {
+ Ast *elem = cl->elems[field_index];
+ ast_node(fv, FieldValue, elem);
+
+ lbValue key = lb_build_expr(p, fv->field);
+ lbValue value = lb_build_expr(p, fv->value);
+ lb_insert_dynamic_map_key_and_value(p, v, type, key, value, elem);
+ }
+ break;
+ }
+
+ case Type_Array: {
+ if (cl->elems.count > 0) {
+ lb_addr_store(p, v, lb_const_value(p->module, type, exact_value_compound(expr)));
+
+ auto temp_data = array_make<lbCompoundLitElemTempData>(temporary_allocator(), 0, cl->elems.count);
+
+ lb_build_addr_compound_lit_populate(p, cl->elems, &temp_data, type);
+
+ lbValue dst_ptr = lb_addr_get_ptr(p, v);
+ for_array(i, temp_data) {
+ i32 index = cast(i32)(temp_data[i].elem_index);
+ temp_data[i].gep = lb_emit_array_epi(p, dst_ptr, index);
+ }
+
+ lb_build_addr_compound_lit_assign_array(p, temp_data);
+ }
+ break;
+ }
+ case Type_EnumeratedArray: {
+ if (cl->elems.count > 0) {
+ lb_addr_store(p, v, lb_const_value(p->module, type, exact_value_compound(expr)));
+
+ auto temp_data = array_make<lbCompoundLitElemTempData>(temporary_allocator(), 0, cl->elems.count);
+
+ lb_build_addr_compound_lit_populate(p, cl->elems, &temp_data, type);
+
+ lbValue dst_ptr = lb_addr_get_ptr(p, v);
+ i64 index_offset = exact_value_to_i64(*bt->EnumeratedArray.min_value);
+ for_array(i, temp_data) {
+ i32 index = cast(i32)(temp_data[i].elem_index - index_offset);
+ temp_data[i].gep = lb_emit_array_epi(p, dst_ptr, index);
+ }
+
+ lb_build_addr_compound_lit_assign_array(p, temp_data);
+ }
+ break;
+ }
+ case Type_Slice: {
+ if (cl->elems.count > 0) {
+ lbValue slice = lb_const_value(p->module, type, exact_value_compound(expr));
+
+ lbValue data = lb_slice_elem(p, slice);
+
+ auto temp_data = array_make<lbCompoundLitElemTempData>(temporary_allocator(), 0, cl->elems.count);
+
+ lb_build_addr_compound_lit_populate(p, cl->elems, &temp_data, type);
+
+ for_array(i, temp_data) {
+ temp_data[i].gep = lb_emit_ptr_offset(p, data, lb_const_int(p->module, t_int, temp_data[i].elem_index));
+ }
+
+ lb_build_addr_compound_lit_assign_array(p, temp_data);
+
+ {
+ lbValue count = {};
+ count.type = t_int;
+
+ if (lb_is_const(slice)) {
+ unsigned indices[1] = {1};
+ count.value = LLVMConstExtractValue(slice.value, indices, gb_count_of(indices));
+ } else {
+ count.value = LLVMBuildExtractValue(p->builder, slice.value, 1, "");
+ }
+ lb_fill_slice(p, v, data, count);
+ }
+ }
+ break;
+ }
+
+ case Type_DynamicArray: {
+ if (cl->elems.count == 0) {
+ break;
+ }
+ GB_ASSERT(!build_context.no_dynamic_literals);
+
+ Type *et = bt->DynamicArray.elem;
+ lbValue size = lb_const_int(p->module, t_int, type_size_of(et));
+ lbValue align = lb_const_int(p->module, t_int, type_align_of(et));
+
+ i64 item_count = gb_max(cl->max_count, cl->elems.count);
+ {
+
+ auto args = array_make<lbValue>(permanent_allocator(), 5);
+ args[0] = lb_emit_conv(p, lb_addr_get_ptr(p, v), t_rawptr);
+ args[1] = size;
+ args[2] = align;
+ args[3] = lb_const_int(p->module, t_int, item_count);
+ args[4] = lb_emit_source_code_location(p, proc_name, pos);
+ lb_emit_runtime_call(p, "__dynamic_array_reserve", args);
+ }
+
+ lbValue items = lb_generate_local_array(p, et, item_count);
+
+ auto temp_data = array_make<lbCompoundLitElemTempData>(temporary_allocator(), 0, cl->elems.count);
+ lb_build_addr_compound_lit_populate(p, cl->elems, &temp_data, type);
+
+ for_array(i, temp_data) {
+ temp_data[i].gep = lb_emit_array_epi(p, items, temp_data[i].elem_index);
+ }
+ lb_build_addr_compound_lit_assign_array(p, temp_data);
+
+ {
+ auto args = array_make<lbValue>(permanent_allocator(), 6);
+ args[0] = lb_emit_conv(p, v.addr, t_rawptr);
+ args[1] = size;
+ args[2] = align;
+ args[3] = lb_emit_conv(p, items, t_rawptr);
+ args[4] = lb_const_int(p->module, t_int, item_count);
+ args[5] = lb_emit_source_code_location(p, proc_name, pos);
+ lb_emit_runtime_call(p, "__dynamic_array_append", args);
+ }
+ break;
+ }
+
+ case Type_Basic: {
+ GB_ASSERT(is_type_any(bt));
+ if (cl->elems.count > 0) {
+ lb_addr_store(p, v, lb_const_value(p->module, type, exact_value_compound(expr)));
+ String field_names[2] = {
+ str_lit("data"),
+ str_lit("id"),
+ };
+ Type *field_types[2] = {
+ t_rawptr,
+ t_typeid,
+ };
+
+ for_array(field_index, cl->elems) {
+ Ast *elem = cl->elems[field_index];
+
+ lbValue field_expr = {};
+ isize index = field_index;
+
+ if (elem->kind == Ast_FieldValue) {
+ ast_node(fv, FieldValue, elem);
+ Selection sel = lookup_field(bt, fv->field->Ident.token.string, false);
+ index = sel.index[0];
+ elem = fv->value;
+ } else {
+ TypeAndValue tav = type_and_value_of_expr(elem);
+ Selection sel = lookup_field(bt, field_names[field_index], false);
+ index = sel.index[0];
+ }
+
+ field_expr = lb_build_expr(p, elem);
+
+ GB_ASSERT(field_expr.type->kind != Type_Tuple);
+
+ Type *ft = field_types[index];
+ lbValue fv = lb_emit_conv(p, field_expr, ft);
+ lbValue gep = lb_emit_struct_ep(p, lb_addr_get_ptr(p, v), cast(i32)index);
+ lb_emit_store(p, gep, fv);
+ }
+ }
+
+ break;
+ }
+
+ case Type_BitSet: {
+ i64 sz = type_size_of(type);
+ if (cl->elems.count > 0 && sz > 0) {
+ lb_addr_store(p, v, lb_const_value(p->module, type, exact_value_compound(expr)));
+
+ lbValue lower = lb_const_value(p->module, t_int, exact_value_i64(bt->BitSet.lower));
+ for_array(i, cl->elems) {
+ Ast *elem = cl->elems[i];
+ GB_ASSERT(elem->kind != Ast_FieldValue);
+
+ if (lb_is_elem_const(elem, et)) {
+ continue;
+ }
+
+ lbValue expr = lb_build_expr(p, elem);
+ GB_ASSERT(expr.type->kind != Type_Tuple);
+
+ Type *it = bit_set_to_int(bt);
+ lbValue one = lb_const_value(p->module, it, exact_value_i64(1));
+ lbValue e = lb_emit_conv(p, expr, it);
+ e = lb_emit_arith(p, Token_Sub, e, lower, it);
+ e = lb_emit_arith(p, Token_Shl, one, e, it);
+
+ lbValue old_value = lb_emit_transmute(p, lb_addr_load(p, v), it);
+ lbValue new_value = lb_emit_arith(p, Token_Or, old_value, e, it);
+ new_value = lb_emit_transmute(p, new_value, type);
+ lb_addr_store(p, v, new_value);
+ }
+ }
+ break;
+ }
+
+ case Type_Matrix: {
+ if (cl->elems.count > 0) {
+ lb_addr_store(p, v, lb_const_value(p->module, type, exact_value_compound(expr)));
+
+ auto temp_data = array_make<lbCompoundLitElemTempData>(temporary_allocator(), 0, cl->elems.count);
+
+ lb_build_addr_compound_lit_populate(p, cl->elems, &temp_data, type);
+
+ lbValue dst_ptr = lb_addr_get_ptr(p, v);
+ for_array(i, temp_data) {
+ temp_data[i].gep = lb_emit_array_epi(p, dst_ptr, temp_data[i].elem_index);
+ }
+
+ lb_build_addr_compound_lit_assign_array(p, temp_data);
+ }
+ break;
+ }
+
+ case Type_SimdVector: {
+ if (cl->elems.count > 0) {
+ lbValue vector_value = lb_const_value(p->module, type, exact_value_compound(expr));
+ defer (lb_addr_store(p, v, vector_value));
+
+ auto temp_data = array_make<lbCompoundLitElemTempData>(temporary_allocator(), 0, cl->elems.count);
+
+ lb_build_addr_compound_lit_populate(p, cl->elems, &temp_data, type);
+
+ // TODO(bill): reduce the need for individual `insertelement` if a `shufflevector`
+ // might be a better option
+ for_array(i, temp_data) {
+ auto td = temp_data[i];
+ if (td.value.value != nullptr) {
+ if (td.elem_length > 0) {
+ for (i64 k = 0; k < td.elem_length; k++) {
+ LLVMValueRef index = lb_const_int(p->module, t_u32, td.elem_index + k).value;
+ vector_value.value = LLVMBuildInsertElement(p->builder, vector_value.value, td.value.value, index, "");
+ }
+ } else {
+ LLVMValueRef index = lb_const_int(p->module, t_u32, td.elem_index).value;
+ vector_value.value = LLVMBuildInsertElement(p->builder, vector_value.value, td.value.value, index, "");
+
+ }
+ }
+ }
+ }
+ break;
+ }
+ }
+
+ return v;
+}
+
lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) {
switch (expr->kind) {
@@ -3601,6 +4516,7 @@ lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) {
// NOTE(bill): just patch the index in place
sel.index[0] = addr.swizzle.indices[sel.index[0]];
}
+
lbValue a = lb_addr_get_ptr(p, addr);
a = lb_emit_deep_field_gep(p, a, sel);
return lb_addr(a);
@@ -3652,225 +4568,15 @@ lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) {
case_end;
case_ast_node(ie, IndexExpr, expr);
- Type *t = base_type(type_of_expr(ie->expr));
-
- bool deref = is_type_pointer(t);
- t = base_type(type_deref(t));
- if (is_type_soa_struct(t)) {
- // SOA STRUCTURES!!!!
- lbValue val = lb_build_addr_ptr(p, ie->expr);
- if (deref) {
- val = lb_emit_load(p, val);
- }
-
- lbValue index = lb_build_expr(p, ie->index);
- return lb_addr_soa_variable(val, index, ie->index);
- }
-
- if (ie->expr->tav.mode == Addressing_SoaVariable) {
- // SOA Structures for slices/dynamic arrays
- GB_ASSERT(is_type_pointer(type_of_expr(ie->expr)));
-
- lbValue field = lb_build_expr(p, ie->expr);
- lbValue index = lb_build_expr(p, ie->index);
-
-
- if (!build_context.no_bounds_check) {
- // TODO HACK(bill): Clean up this hack to get the length for bounds checking
- // GB_ASSERT(LLVMIsALoadInst(field.value));
-
- // lbValue a = {};
- // a.value = LLVMGetOperand(field.value, 0);
- // a.type = alloc_type_pointer(field.type);
-
- // irInstr *b = &a->Instr;
- // GB_ASSERT(b->kind == irInstr_StructElementPtr);
- // lbValue base_struct = b->StructElementPtr.address;
-
- // GB_ASSERT(is_type_soa_struct(type_deref(ir_type(base_struct))));
- // lbValue len = ir_soa_struct_len(p, base_struct);
- // lb_emit_bounds_check(p, ast_token(ie->index), index, len);
- }
- lbValue val = lb_emit_ptr_offset(p, field, index);
- return lb_addr(val);
- }
-
- GB_ASSERT_MSG(is_type_indexable(t), "%s %s", type_to_string(t), expr_to_string(expr));
-
- if (is_type_map(t)) {
- lbAddr map_addr = lb_build_addr(p, ie->expr);
- lbValue map_val = lb_addr_load(p, map_addr);
- if (deref) {
- map_val = lb_emit_load(p, map_val);
- }
-
- lbValue key = lb_build_expr(p, ie->index);
- key = lb_emit_conv(p, key, t->Map.key);
-
- Type *result_type = type_of_expr(expr);
- lbValue map_ptr = lb_address_from_load_or_generate_local(p, map_val);
- return lb_addr_map(map_ptr, key, t, result_type);
- }
-
- switch (t->kind) {
- case Type_Array: {
- lbValue array = {};
- array = lb_build_addr_ptr(p, ie->expr);
- if (deref) {
- array = lb_emit_load(p, array);
- }
- lbValue index = lb_build_expr(p, ie->index);
- index = lb_emit_conv(p, index, t_int);
- lbValue elem = lb_emit_array_ep(p, array, index);
-
- auto index_tv = type_and_value_of_expr(ie->index);
- if (index_tv.mode != Addressing_Constant) {
- lbValue len = lb_const_int(p->module, t_int, t->Array.count);
- lb_emit_bounds_check(p, ast_token(ie->index), index, len);
- }
- return lb_addr(elem);
- }
-
- case Type_EnumeratedArray: {
- lbValue array = {};
- array = lb_build_addr_ptr(p, ie->expr);
- if (deref) {
- array = lb_emit_load(p, array);
- }
-
- Type *index_type = t->EnumeratedArray.index;
-
- auto index_tv = type_and_value_of_expr(ie->index);
-
- lbValue index = {};
- if (compare_exact_values(Token_NotEq, *t->EnumeratedArray.min_value, exact_value_i64(0))) {
- if (index_tv.mode == Addressing_Constant) {
- ExactValue idx = exact_value_sub(index_tv.value, *t->EnumeratedArray.min_value);
- index = lb_const_value(p->module, index_type, idx);
- } else {
- index = lb_emit_conv(p, lb_build_expr(p, ie->index), t_int);
- index = lb_emit_arith(p, Token_Sub, index, lb_const_value(p->module, index_type, *t->EnumeratedArray.min_value), index_type);
- }
- } else {
- index = lb_emit_conv(p, lb_build_expr(p, ie->index), t_int);
- }
-
- lbValue elem = lb_emit_array_ep(p, array, index);
-
- if (index_tv.mode != Addressing_Constant) {
- lbValue len = lb_const_int(p->module, t_int, t->EnumeratedArray.count);
- lb_emit_bounds_check(p, ast_token(ie->index), index, len);
- }
- return lb_addr(elem);
- }
-
- case Type_Slice: {
- lbValue slice = {};
- slice = lb_build_expr(p, ie->expr);
- if (deref) {
- slice = lb_emit_load(p, slice);
- }
- lbValue elem = lb_slice_elem(p, slice);
- lbValue index = lb_emit_conv(p, lb_build_expr(p, ie->index), t_int);
- lbValue len = lb_slice_len(p, slice);
- lb_emit_bounds_check(p, ast_token(ie->index), index, len);
- lbValue v = lb_emit_ptr_offset(p, elem, index);
- return lb_addr(v);
- }
-
- case Type_MultiPointer: {
- lbValue multi_ptr = {};
- multi_ptr = lb_build_expr(p, ie->expr);
- if (deref) {
- multi_ptr = lb_emit_load(p, multi_ptr);
- }
- lbValue index = lb_build_expr(p, ie->index);
- lbValue v = {};
-
- LLVMValueRef indices[1] = {index.value};
- v.value = LLVMBuildGEP(p->builder, multi_ptr.value, indices, 1, "");
- v.type = alloc_type_pointer(t->MultiPointer.elem);
- return lb_addr(v);
- }
-
- case Type_RelativeSlice: {
- lbAddr slice_addr = {};
- if (deref) {
- slice_addr = lb_addr(lb_build_expr(p, ie->expr));
- } else {
- slice_addr = lb_build_addr(p, ie->expr);
- }
- lbValue slice = lb_addr_load(p, slice_addr);
-
- lbValue elem = lb_slice_elem(p, slice);
- lbValue index = lb_emit_conv(p, lb_build_expr(p, ie->index), t_int);
- lbValue len = lb_slice_len(p, slice);
- lb_emit_bounds_check(p, ast_token(ie->index), index, len);
- lbValue v = lb_emit_ptr_offset(p, elem, index);
- return lb_addr(v);
- }
-
- case Type_DynamicArray: {
- lbValue dynamic_array = {};
- dynamic_array = lb_build_expr(p, ie->expr);
- if (deref) {
- dynamic_array = lb_emit_load(p, dynamic_array);
- }
- lbValue elem = lb_dynamic_array_elem(p, dynamic_array);
- lbValue len = lb_dynamic_array_len(p, dynamic_array);
- lbValue index = lb_emit_conv(p, lb_build_expr(p, ie->index), t_int);
- lb_emit_bounds_check(p, ast_token(ie->index), index, len);
- lbValue v = lb_emit_ptr_offset(p, elem, index);
- return lb_addr(v);
- }
-
- case Type_Matrix: {
- lbValue matrix = {};
- matrix = lb_build_addr_ptr(p, ie->expr);
- if (deref) {
- matrix = lb_emit_load(p, matrix);
- }
- lbValue index = lb_build_expr(p, ie->index);
- index = lb_emit_conv(p, index, t_int);
- lbValue elem = lb_emit_matrix_ep(p, matrix, lb_const_int(p->module, t_int, 0), index);
- elem = lb_emit_conv(p, elem, alloc_type_pointer(type_of_expr(expr)));
-
- auto index_tv = type_and_value_of_expr(ie->index);
- if (index_tv.mode != Addressing_Constant) {
- lbValue len = lb_const_int(p->module, t_int, t->Matrix.column_count);
- lb_emit_bounds_check(p, ast_token(ie->index), index, len);
- }
- return lb_addr(elem);
- }
-
-
- case Type_Basic: { // Basic_string
- lbValue str;
- lbValue elem;
- lbValue len;
- lbValue index;
-
- str = lb_build_expr(p, ie->expr);
- if (deref) {
- str = lb_emit_load(p, str);
- }
- elem = lb_string_elem(p, str);
- len = lb_string_len(p, str);
-
- index = lb_emit_conv(p, lb_build_expr(p, ie->index), t_int);
- lb_emit_bounds_check(p, ast_token(ie->index), index, len);
-
- return lb_addr(lb_emit_ptr_offset(p, elem, index));
- }
- }
+ return lb_build_addr_index_expr(p, expr);
case_end;
-
+
case_ast_node(ie, MatrixIndexExpr, expr);
Type *t = base_type(type_of_expr(ie->expr));
bool deref = is_type_pointer(t);
t = base_type(type_deref(t));
-
+
lbValue m = {};
m = lb_build_addr_ptr(p, ie->expr);
if (deref) {
@@ -3890,210 +4596,25 @@ lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) {
lb_emit_matrix_bounds_check(p, ast_token(ie->row_index), row_index, column_index, row_count, column_count);
}
return lb_addr(elem);
-
-
- case_end;
- case_ast_node(se, SliceExpr, expr);
-
- lbValue low = lb_const_int(p->module, t_int, 0);
- lbValue high = {};
-
- if (se->low != nullptr) {
- low = lb_correct_endianness(p, lb_build_expr(p, se->low));
- }
- if (se->high != nullptr) {
- high = lb_correct_endianness(p, lb_build_expr(p, se->high));
- }
-
- 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;
- lbValue len = lb_slice_len(p, base);
- if (high.value == nullptr) high = len;
-
- if (!no_indices) {
- lb_emit_slice_bounds_check(p, se->open, low, high, len, se->low != nullptr);
- }
-
- lbValue elem = lb_emit_ptr_offset(p, lb_slice_elem(p, base), low);
- lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int);
- lbAddr slice = lb_add_local_generated(p, slice_type, false);
- lb_fill_slice(p, slice, elem, new_len);
- return slice;
- }
-
- case Type_RelativeSlice:
- GB_PANIC("TODO(bill): Type_RelativeSlice should be handled above already on the lb_addr_load");
- break;
-
- case Type_DynamicArray: {
- Type *elem_type = type->DynamicArray.elem;
- Type *slice_type = alloc_type_slice(elem_type);
-
- lbValue len = lb_dynamic_array_len(p, base);
- if (high.value == nullptr) high = len;
-
- if (!no_indices) {
- lb_emit_slice_bounds_check(p, se->open, low, high, len, se->low != nullptr);
- }
-
- lbValue elem = lb_emit_ptr_offset(p, lb_dynamic_array_elem(p, base), low);
- lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int);
-
- lbAddr slice = lb_add_local_generated(p, slice_type, false);
- lb_fill_slice(p, slice, elem, new_len);
- return slice;
- }
-
- case Type_MultiPointer: {
- lbAddr res = lb_add_local_generated(p, type_of_expr(expr), false);
- if (se->high == nullptr) {
- lbValue offset = base;
- LLVMValueRef indices[1] = {low.value};
- offset.value = LLVMBuildGEP(p->builder, offset.value, indices, 1, "");
- lb_addr_store(p, res, offset);
- } else {
- low = lb_emit_conv(p, low, t_int);
- high = lb_emit_conv(p, high, t_int);
-
- lb_emit_multi_pointer_slice_bounds_check(p, se->open, low, high);
-
- LLVMValueRef indices[1] = {low.value};
- LLVMValueRef ptr = LLVMBuildGEP(p->builder, base.value, indices, 1, "");
- LLVMValueRef len = LLVMBuildSub(p->builder, high.value, low.value, "");
-
- LLVMValueRef gep0 = lb_emit_struct_ep(p, res.addr, 0).value;
- LLVMValueRef gep1 = lb_emit_struct_ep(p, res.addr, 1).value;
- LLVMBuildStore(p->builder, ptr, gep0);
- LLVMBuildStore(p->builder, len, gep1);
- }
- return res;
- }
-
- case Type_Array: {
- Type *slice_type = alloc_type_slice(type->Array.elem);
- lbValue len = lb_const_int(p->module, t_int, type->Array.count);
-
- if (high.value == nullptr) high = len;
-
- bool low_const = type_and_value_of_expr(se->low).mode == Addressing_Constant;
- bool high_const = type_and_value_of_expr(se->high).mode == Addressing_Constant;
-
- if (!low_const || !high_const) {
- if (!no_indices) {
- lb_emit_slice_bounds_check(p, se->open, low, high, len, se->low != nullptr);
- }
- }
- lbValue elem = lb_emit_ptr_offset(p, lb_array_elem(p, lb_addr_get_ptr(p, addr)), low);
- lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int);
-
- lbAddr slice = lb_add_local_generated(p, slice_type, false);
- lb_fill_slice(p, slice, elem, new_len);
- return slice;
- }
-
- case Type_Basic: {
- GB_ASSERT(type == t_string);
- lbValue len = lb_string_len(p, base);
- if (high.value == nullptr) high = len;
-
- if (!no_indices) {
- lb_emit_slice_bounds_check(p, se->open, low, high, len, se->low != nullptr);
- }
-
- lbValue elem = lb_emit_ptr_offset(p, lb_string_elem(p, base), low);
- lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int);
-
- lbAddr str = lb_add_local_generated(p, t_string, false);
- lb_fill_string(p, str, elem, new_len);
- return str;
- }
-
-
- case Type_Struct:
- if (is_type_soa_struct(type)) {
- lbValue len = lb_soa_struct_len(p, lb_addr_get_ptr(p, addr));
- if (high.value == nullptr) high = len;
-
- if (!no_indices) {
- lb_emit_slice_bounds_check(p, se->open, low, high, len, se->low != nullptr);
- }
- #if 1
-
- lbAddr dst = lb_add_local_generated(p, type_of_expr(expr), true);
- if (type->Struct.soa_kind == StructSoa_Fixed) {
- i32 field_count = cast(i32)type->Struct.fields.count;
- for (i32 i = 0; i < field_count; i++) {
- lbValue field_dst = lb_emit_struct_ep(p, dst.addr, i);
- lbValue field_src = lb_emit_struct_ep(p, lb_addr_get_ptr(p, addr), i);
- field_src = lb_emit_array_ep(p, field_src, low);
- lb_emit_store(p, field_dst, field_src);
- }
-
- lbValue len_dst = lb_emit_struct_ep(p, dst.addr, field_count);
- lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int);
- lb_emit_store(p, len_dst, new_len);
- } else if (type->Struct.soa_kind == StructSoa_Slice) {
- if (no_indices) {
- lb_addr_store(p, dst, base);
- } else {
- i32 field_count = cast(i32)type->Struct.fields.count - 1;
- for (i32 i = 0; i < field_count; i++) {
- lbValue field_dst = lb_emit_struct_ep(p, dst.addr, i);
- lbValue field_src = lb_emit_struct_ev(p, base, i);
- field_src = lb_emit_ptr_offset(p, field_src, low);
- lb_emit_store(p, field_dst, field_src);
- }
-
-
- lbValue len_dst = lb_emit_struct_ep(p, dst.addr, field_count);
- lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int);
- lb_emit_store(p, len_dst, new_len);
- }
- } else if (type->Struct.soa_kind == StructSoa_Dynamic) {
- i32 field_count = cast(i32)type->Struct.fields.count - 3;
- for (i32 i = 0; i < field_count; i++) {
- lbValue field_dst = lb_emit_struct_ep(p, dst.addr, i);
- lbValue field_src = lb_emit_struct_ev(p, base, i);
- field_src = lb_emit_ptr_offset(p, field_src, low);
- lb_emit_store(p, field_dst, field_src);
- }
-
-
- lbValue len_dst = lb_emit_struct_ep(p, dst.addr, field_count);
- lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int);
- lb_emit_store(p, len_dst, new_len);
- }
-
- return dst;
- #endif
- }
- break;
-
- }
+ case_end;
- GB_PANIC("Unknown slicable type");
+ case_ast_node(se, SliceExpr, expr);
+ return lb_build_addr_slice_expr(p, expr);
case_end;
case_ast_node(de, DerefExpr, expr);
- if (is_type_relative_pointer(type_of_expr(de->expr))) {
+ Type *t = type_of_expr(de->expr);
+ if (is_type_relative_pointer(t)) {
lbAddr addr = lb_build_addr(p, de->expr);
addr.relative.deref = true;
- return addr;\
+ return addr;
+ } else if (is_type_soa_pointer(t)) {
+ lbValue value = lb_build_expr(p, de->expr);
+ lbValue ptr = lb_emit_struct_ev(p, value, 0);
+ lbValue idx = lb_emit_struct_ev(p, value, 1);
+ return lb_addr_soa_variable(ptr, idx, nullptr);
}
lbValue addr = lb_build_expr(p, de->expr);
return lb_addr(addr);
@@ -4129,747 +4650,7 @@ lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) {
case_end;
case_ast_node(cl, CompoundLit, expr);
- Type *type = type_of_expr(expr);
- Type *bt = base_type(type);
-
- lbAddr v = lb_add_local_generated(p, type, true);
-
- Type *et = nullptr;
- switch (bt->kind) {
- case Type_Array: et = bt->Array.elem; break;
- case Type_EnumeratedArray: et = bt->EnumeratedArray.elem; break;
- case Type_Slice: et = bt->Slice.elem; break;
- case Type_BitSet: et = bt->BitSet.elem; break;
- case Type_SimdVector: et = bt->SimdVector.elem; break;
- case Type_Matrix: et = bt->Matrix.elem; break;
- }
-
- String proc_name = {};
- if (p->entity) {
- proc_name = p->entity->token.string;
- }
- TokenPos pos = ast_token(expr).pos;
-
- switch (bt->kind) {
- default: GB_PANIC("Unknown CompoundLit type: %s", type_to_string(type)); break;
-
- case Type_Struct: {
- // TODO(bill): "constant" '#raw_union's are not initialized constantly at the moment.
- // NOTE(bill): This is due to the layout of the unions when printed to LLVM-IR
- bool is_raw_union = is_type_raw_union(bt);
- GB_ASSERT(is_type_struct(bt) || is_raw_union);
- TypeStruct *st = &bt->Struct;
- if (cl->elems.count > 0) {
- lb_addr_store(p, v, lb_const_value(p->module, type, exact_value_compound(expr)));
- lbValue comp_lit_ptr = lb_addr_get_ptr(p, v);
-
- for_array(field_index, cl->elems) {
- Ast *elem = cl->elems[field_index];
-
- lbValue field_expr = {};
- Entity *field = nullptr;
- isize index = field_index;
-
- if (elem->kind == Ast_FieldValue) {
- ast_node(fv, FieldValue, elem);
- String name = fv->field->Ident.token.string;
- Selection sel = lookup_field(bt, name, false);
- index = sel.index[0];
- elem = fv->value;
- TypeAndValue tav = type_and_value_of_expr(elem);
- } else {
- TypeAndValue tav = type_and_value_of_expr(elem);
- Selection sel = lookup_field_from_index(bt, st->fields[field_index]->Variable.field_index);
- index = sel.index[0];
- }
-
- field = st->fields[index];
- Type *ft = field->type;
- if (!is_raw_union && !is_type_typeid(ft) && lb_is_elem_const(elem, ft)) {
- continue;
- }
-
- field_expr = lb_build_expr(p, elem);
-
- lbValue gep = {};
- if (is_raw_union) {
- gep = lb_emit_conv(p, comp_lit_ptr, alloc_type_pointer(ft));
- } else {
- gep = lb_emit_struct_ep(p, comp_lit_ptr, cast(i32)index);
- }
-
- Type *fet = field_expr.type;
- GB_ASSERT(fet->kind != Type_Tuple);
-
- // HACK TODO(bill): THIS IS A MASSIVE HACK!!!!
- if (is_type_union(ft) && !are_types_identical(fet, ft) && !is_type_untyped(fet)) {
- GB_ASSERT_MSG(union_variant_index(ft, fet) > 0, "%s", type_to_string(fet));
-
- lb_emit_store_union_variant(p, gep, field_expr, fet);
- } else {
- lbValue fv = lb_emit_conv(p, field_expr, ft);
- lb_emit_store(p, gep, fv);
- }
- }
- }
- break;
- }
-
- case Type_Map: {
- if (cl->elems.count == 0) {
- break;
- }
- {
- auto args = array_make<lbValue>(permanent_allocator(), 3);
- args[0] = lb_gen_map_header(p, v.addr, type);
- args[1] = lb_const_int(p->module, t_int, 2*cl->elems.count);
- args[2] = lb_emit_source_code_location(p, proc_name, pos);
- lb_emit_runtime_call(p, "__dynamic_map_reserve", args);
- }
- for_array(field_index, cl->elems) {
- Ast *elem = cl->elems[field_index];
- ast_node(fv, FieldValue, elem);
-
- lbValue key = lb_build_expr(p, fv->field);
- lbValue value = lb_build_expr(p, fv->value);
- lb_insert_dynamic_map_key_and_value(p, v, type, key, value, elem);
- }
- break;
- }
-
- case Type_Array: {
- if (cl->elems.count > 0) {
- lb_addr_store(p, v, lb_const_value(p->module, type, exact_value_compound(expr)));
-
- auto temp_data = array_make<lbCompoundLitElemTempData>(temporary_allocator(), 0, cl->elems.count);
-
- // NOTE(bill): Separate value, gep, store into their own chunks
- for_array(i, cl->elems) {
- Ast *elem = cl->elems[i];
- if (elem->kind == Ast_FieldValue) {
- ast_node(fv, FieldValue, elem);
- if (lb_is_elem_const(fv->value, et)) {
- continue;
- }
- 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;
- }
-
- lbValue value = lb_build_expr(p, fv->value);
-
- for (i64 k = lo; k < hi; k++) {
- lbCompoundLitElemTempData data = {};
- data.value = value;
- data.elem_index = cast(i32)k;
- array_add(&temp_data, data);
- }
-
- } else {
- auto tav = fv->field->tav;
- GB_ASSERT(tav.mode == Addressing_Constant);
- i64 index = exact_value_to_i64(tav.value);
-
- lbValue value = lb_build_expr(p, fv->value);
- lbCompoundLitElemTempData data = {};
- data.value = lb_emit_conv(p, value, et);
- data.expr = fv->value;
- data.elem_index = cast(i32)index;
- array_add(&temp_data, data);
- }
-
- } else {
- if (lb_is_elem_const(elem, et)) {
- continue;
- }
- lbCompoundLitElemTempData data = {};
- data.expr = elem;
- data.elem_index = cast(i32)i;
- array_add(&temp_data, data);
- }
- }
-
- for_array(i, temp_data) {
- temp_data[i].gep = lb_emit_array_epi(p, lb_addr_get_ptr(p, v), temp_data[i].elem_index);
- }
-
- for_array(i, temp_data) {
- lbValue field_expr = temp_data[i].value;
- Ast *expr = temp_data[i].expr;
-
- auto prev_hint = lb_set_copy_elision_hint(p, lb_addr(temp_data[i].gep), expr);
-
- if (field_expr.value == nullptr) {
- field_expr = lb_build_expr(p, expr);
- }
- Type *t = field_expr.type;
- GB_ASSERT(t->kind != Type_Tuple);
- lbValue ev = lb_emit_conv(p, field_expr, et);
-
- if (!p->copy_elision_hint.used) {
- temp_data[i].value = ev;
- }
-
- lb_reset_copy_elision_hint(p, prev_hint);
- }
-
- for_array(i, temp_data) {
- if (temp_data[i].value.value != nullptr) {
- lb_emit_store(p, temp_data[i].gep, temp_data[i].value);
- }
- }
- }
- break;
- }
- case Type_EnumeratedArray: {
- if (cl->elems.count > 0) {
- lb_addr_store(p, v, lb_const_value(p->module, type, exact_value_compound(expr)));
-
- auto temp_data = array_make<lbCompoundLitElemTempData>(temporary_allocator(), 0, cl->elems.count);
-
- // NOTE(bill): Separate value, gep, store into their own chunks
- for_array(i, cl->elems) {
- Ast *elem = cl->elems[i];
- if (elem->kind == Ast_FieldValue) {
- ast_node(fv, FieldValue, elem);
- if (lb_is_elem_const(fv->value, et)) {
- continue;
- }
- 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;
- }
-
- lbValue value = lb_build_expr(p, fv->value);
-
- for (i64 k = lo; k < hi; k++) {
- lbCompoundLitElemTempData data = {};
- data.value = value;
- data.elem_index = cast(i32)k;
- array_add(&temp_data, data);
- }
-
- } else {
- auto tav = fv->field->tav;
- GB_ASSERT(tav.mode == Addressing_Constant);
- i64 index = exact_value_to_i64(tav.value);
-
- lbValue value = lb_build_expr(p, fv->value);
- lbCompoundLitElemTempData data = {};
- data.value = lb_emit_conv(p, value, et);
- data.expr = fv->value;
- data.elem_index = cast(i32)index;
- array_add(&temp_data, data);
- }
-
- } else {
- if (lb_is_elem_const(elem, et)) {
- continue;
- }
- lbCompoundLitElemTempData data = {};
- data.expr = elem;
- data.elem_index = cast(i32)i;
- array_add(&temp_data, data);
- }
- }
-
-
- i32 index_offset = cast(i32)exact_value_to_i64(*bt->EnumeratedArray.min_value);
-
- for_array(i, temp_data) {
- i32 index = temp_data[i].elem_index - index_offset;
- temp_data[i].gep = lb_emit_array_epi(p, lb_addr_get_ptr(p, v), index);
- }
-
- for_array(i, temp_data) {
- lbValue field_expr = temp_data[i].value;
- Ast *expr = temp_data[i].expr;
-
- auto prev_hint = lb_set_copy_elision_hint(p, lb_addr(temp_data[i].gep), expr);
-
- if (field_expr.value == nullptr) {
- field_expr = lb_build_expr(p, expr);
- }
- Type *t = field_expr.type;
- GB_ASSERT(t->kind != Type_Tuple);
- lbValue ev = lb_emit_conv(p, field_expr, et);
-
- if (!p->copy_elision_hint.used) {
- temp_data[i].value = ev;
- }
-
- lb_reset_copy_elision_hint(p, prev_hint);
- }
-
- for_array(i, temp_data) {
- if (temp_data[i].value.value != nullptr) {
- lb_emit_store(p, temp_data[i].gep, temp_data[i].value);
- }
- }
- }
- break;
- }
- case Type_Slice: {
- if (cl->elems.count > 0) {
- lbValue slice = lb_const_value(p->module, type, exact_value_compound(expr));
-
- lbValue data = lb_slice_elem(p, slice);
-
- auto temp_data = array_make<lbCompoundLitElemTempData>(temporary_allocator(), 0, cl->elems.count);
-
- for_array(i, cl->elems) {
- Ast *elem = cl->elems[i];
- if (elem->kind == Ast_FieldValue) {
- ast_node(fv, FieldValue, elem);
-
- if (lb_is_elem_const(fv->value, et)) {
- continue;
- }
-
- 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;
- }
-
- lbValue value = lb_emit_conv(p, lb_build_expr(p, fv->value), et);
-
- for (i64 k = lo; k < hi; k++) {
- lbCompoundLitElemTempData data = {};
- data.value = value;
- data.elem_index = cast(i32)k;
- array_add(&temp_data, data);
- }
-
- } else {
- GB_ASSERT(fv->field->tav.mode == Addressing_Constant);
- i64 index = exact_value_to_i64(fv->field->tav.value);
-
- lbValue field_expr = lb_build_expr(p, fv->value);
- GB_ASSERT(!is_type_tuple(field_expr.type));
-
- lbValue ev = lb_emit_conv(p, field_expr, et);
-
- lbCompoundLitElemTempData data = {};
- data.value = ev;
- data.elem_index = cast(i32)index;
- array_add(&temp_data, data);
- }
- } else {
- if (lb_is_elem_const(elem, et)) {
- continue;
- }
- lbValue field_expr = lb_build_expr(p, elem);
- GB_ASSERT(!is_type_tuple(field_expr.type));
-
- lbValue ev = lb_emit_conv(p, field_expr, et);
-
- lbCompoundLitElemTempData data = {};
- data.value = ev;
- data.elem_index = cast(i32)i;
- array_add(&temp_data, data);
- }
- }
-
- for_array(i, temp_data) {
- temp_data[i].gep = lb_emit_ptr_offset(p, data, lb_const_int(p->module, t_int, temp_data[i].elem_index));
- }
-
- for_array(i, temp_data) {
- lb_emit_store(p, temp_data[i].gep, temp_data[i].value);
- }
-
- {
- lbValue count = {};
- count.type = t_int;
-
- if (lb_is_const(slice)) {
- unsigned indices[1] = {1};
- count.value = LLVMConstExtractValue(slice.value, indices, gb_count_of(indices));
- } else {
- count.value = LLVMBuildExtractValue(p->builder, slice.value, 1, "");
- }
- lb_fill_slice(p, v, data, count);
- }
- }
- break;
- }
-
- case Type_DynamicArray: {
- if (cl->elems.count == 0) {
- break;
- }
- Type *et = bt->DynamicArray.elem;
- lbValue size = lb_const_int(p->module, t_int, type_size_of(et));
- lbValue align = lb_const_int(p->module, t_int, type_align_of(et));
-
- i64 item_count = gb_max(cl->max_count, cl->elems.count);
- {
-
- auto args = array_make<lbValue>(permanent_allocator(), 5);
- args[0] = lb_emit_conv(p, lb_addr_get_ptr(p, v), t_rawptr);
- args[1] = size;
- args[2] = align;
- args[3] = lb_const_int(p->module, t_int, 2*item_count); // TODO(bill): Is this too much waste?
- args[4] = lb_emit_source_code_location(p, proc_name, pos);
- lb_emit_runtime_call(p, "__dynamic_array_reserve", args);
- }
-
- lbValue items = lb_generate_local_array(p, et, item_count);
- // lbValue items = lb_generate_global_array(p->module, et, item_count, str_lit("dacl$"), cast(i64)cast(intptr)expr);
-
- for_array(i, cl->elems) {
- Ast *elem = cl->elems[i];
- if (elem->kind == Ast_FieldValue) {
- 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;
- }
-
- lbValue value = lb_emit_conv(p, lb_build_expr(p, fv->value), et);
-
- for (i64 k = lo; k < hi; k++) {
- lbValue ep = lb_emit_array_epi(p, items, cast(i32)k);
- lb_emit_store(p, ep, value);
- }
- } else {
- GB_ASSERT(fv->field->tav.mode == Addressing_Constant);
-
- i64 field_index = exact_value_to_i64(fv->field->tav.value);
-
- lbValue ev = lb_build_expr(p, fv->value);
- lbValue value = lb_emit_conv(p, ev, et);
- lbValue ep = lb_emit_array_epi(p, items, cast(i32)field_index);
- lb_emit_store(p, ep, value);
- }
- } else {
- lbValue value = lb_emit_conv(p, lb_build_expr(p, elem), et);
- lbValue ep = lb_emit_array_epi(p, items, cast(i32)i);
- lb_emit_store(p, ep, value);
- }
- }
-
- {
- auto args = array_make<lbValue>(permanent_allocator(), 6);
- args[0] = lb_emit_conv(p, v.addr, t_rawptr);
- args[1] = size;
- args[2] = align;
- args[3] = lb_emit_conv(p, items, t_rawptr);
- args[4] = lb_const_int(p->module, t_int, item_count);
- args[5] = lb_emit_source_code_location(p, proc_name, pos);
- lb_emit_runtime_call(p, "__dynamic_array_append", args);
- }
- break;
- }
-
- case Type_Basic: {
- GB_ASSERT(is_type_any(bt));
- if (cl->elems.count > 0) {
- lb_addr_store(p, v, lb_const_value(p->module, type, exact_value_compound(expr)));
- String field_names[2] = {
- str_lit("data"),
- str_lit("id"),
- };
- Type *field_types[2] = {
- t_rawptr,
- t_typeid,
- };
-
- for_array(field_index, cl->elems) {
- Ast *elem = cl->elems[field_index];
-
- lbValue field_expr = {};
- isize index = field_index;
-
- if (elem->kind == Ast_FieldValue) {
- ast_node(fv, FieldValue, elem);
- Selection sel = lookup_field(bt, fv->field->Ident.token.string, false);
- index = sel.index[0];
- elem = fv->value;
- } else {
- TypeAndValue tav = type_and_value_of_expr(elem);
- Selection sel = lookup_field(bt, field_names[field_index], false);
- index = sel.index[0];
- }
-
- field_expr = lb_build_expr(p, elem);
-
- GB_ASSERT(field_expr.type->kind != Type_Tuple);
-
- Type *ft = field_types[index];
- lbValue fv = lb_emit_conv(p, field_expr, ft);
- lbValue gep = lb_emit_struct_ep(p, lb_addr_get_ptr(p, v), cast(i32)index);
- lb_emit_store(p, gep, fv);
- }
- }
-
- break;
- }
-
- case Type_BitSet: {
- i64 sz = type_size_of(type);
- if (cl->elems.count > 0 && sz > 0) {
- lb_addr_store(p, v, lb_const_value(p->module, type, exact_value_compound(expr)));
-
- lbValue lower = lb_const_value(p->module, t_int, exact_value_i64(bt->BitSet.lower));
- for_array(i, cl->elems) {
- Ast *elem = cl->elems[i];
- GB_ASSERT(elem->kind != Ast_FieldValue);
-
- if (lb_is_elem_const(elem, et)) {
- continue;
- }
-
- lbValue expr = lb_build_expr(p, elem);
- GB_ASSERT(expr.type->kind != Type_Tuple);
-
- Type *it = bit_set_to_int(bt);
- lbValue one = lb_const_value(p->module, it, exact_value_i64(1));
- lbValue e = lb_emit_conv(p, expr, it);
- e = lb_emit_arith(p, Token_Sub, e, lower, it);
- e = lb_emit_arith(p, Token_Shl, one, e, it);
-
- lbValue old_value = lb_emit_transmute(p, lb_addr_load(p, v), it);
- lbValue new_value = lb_emit_arith(p, Token_Or, old_value, e, it);
- new_value = lb_emit_transmute(p, new_value, type);
- lb_addr_store(p, v, new_value);
- }
- }
- break;
- }
-
- case Type_Matrix: {
- if (cl->elems.count > 0) {
- lb_addr_store(p, v, lb_const_value(p->module, type, exact_value_compound(expr)));
-
- auto temp_data = array_make<lbCompoundLitElemTempData>(temporary_allocator(), 0, cl->elems.count);
-
- // NOTE(bill): Separate value, gep, store into their own chunks
- for_array(i, cl->elems) {
- Ast *elem = cl->elems[i];
-
- if (elem->kind == Ast_FieldValue) {
- ast_node(fv, FieldValue, elem);
- if (lb_is_elem_const(fv->value, et)) {
- continue;
- }
- 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;
- }
-
- lbValue value = lb_build_expr(p, fv->value);
-
- for (i64 k = lo; k < hi; k++) {
- lbCompoundLitElemTempData data = {};
- data.value = value;
-
- data.elem_index = cast(i32)matrix_row_major_index_to_offset(bt, k);
- array_add(&temp_data, data);
- }
-
- } else {
- auto tav = fv->field->tav;
- GB_ASSERT(tav.mode == Addressing_Constant);
- i64 index = exact_value_to_i64(tav.value);
-
- lbValue value = lb_build_expr(p, fv->value);
- lbCompoundLitElemTempData data = {};
- data.value = lb_emit_conv(p, value, et);
- data.expr = fv->value;
-
- data.elem_index = cast(i32)matrix_row_major_index_to_offset(bt, index);
- array_add(&temp_data, data);
- }
-
- } else {
- if (lb_is_elem_const(elem, et)) {
- continue;
- }
- lbCompoundLitElemTempData data = {};
- data.expr = elem;
- data.elem_index = cast(i32)matrix_row_major_index_to_offset(bt, i);
- array_add(&temp_data, data);
- }
- }
-
- for_array(i, temp_data) {
- temp_data[i].gep = lb_emit_array_epi(p, lb_addr_get_ptr(p, v), temp_data[i].elem_index);
- }
-
- for_array(i, temp_data) {
- lbValue field_expr = temp_data[i].value;
- Ast *expr = temp_data[i].expr;
-
- auto prev_hint = lb_set_copy_elision_hint(p, lb_addr(temp_data[i].gep), expr);
-
- if (field_expr.value == nullptr) {
- field_expr = lb_build_expr(p, expr);
- }
- Type *t = field_expr.type;
- GB_ASSERT(t->kind != Type_Tuple);
- lbValue ev = lb_emit_conv(p, field_expr, et);
-
- if (!p->copy_elision_hint.used) {
- temp_data[i].value = ev;
- }
-
- lb_reset_copy_elision_hint(p, prev_hint);
- }
-
- for_array(i, temp_data) {
- if (temp_data[i].value.value != nullptr) {
- lb_emit_store(p, temp_data[i].gep, temp_data[i].value);
- }
- }
- }
- break;
- }
-
- case Type_SimdVector: {
- if (cl->elems.count > 0) {
- lbValue vector_value = lb_const_value(p->module, type, exact_value_compound(expr));
- defer (lb_addr_store(p, v, vector_value));
-
- auto temp_data = array_make<lbCompoundLitElemTempData>(temporary_allocator(), 0, cl->elems.count);
-
- // NOTE(bill): Separate value, store into their own chunks
- for_array(i, cl->elems) {
- Ast *elem = cl->elems[i];
- if (elem->kind == Ast_FieldValue) {
- ast_node(fv, FieldValue, elem);
- if (lb_is_elem_const(fv->value, et)) {
- continue;
- }
- 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;
- }
-
- lbValue value = lb_build_expr(p, fv->value);
-
- for (i64 k = lo; k < hi; k++) {
- lbCompoundLitElemTempData data = {};
- data.value = value;
- data.elem_index = cast(i32)k;
- array_add(&temp_data, data);
- }
-
- } else {
- auto tav = fv->field->tav;
- GB_ASSERT(tav.mode == Addressing_Constant);
- i64 index = exact_value_to_i64(tav.value);
-
- lbValue value = lb_build_expr(p, fv->value);
- lbCompoundLitElemTempData data = {};
- data.value = lb_emit_conv(p, value, et);
- data.expr = fv->value;
- data.elem_index = cast(i32)index;
- array_add(&temp_data, data);
- }
-
- } else {
- if (lb_is_elem_const(elem, et)) {
- continue;
- }
- lbCompoundLitElemTempData data = {};
- data.expr = elem;
- data.elem_index = cast(i32)i;
- array_add(&temp_data, data);
- }
- }
-
-
- for_array(i, temp_data) {
- lbValue field_expr = temp_data[i].value;
- Ast *expr = temp_data[i].expr;
-
- auto prev_hint = lb_set_copy_elision_hint(p, lb_addr(temp_data[i].gep), expr);
-
- if (field_expr.value == nullptr) {
- field_expr = lb_build_expr(p, expr);
- }
- Type *t = field_expr.type;
- GB_ASSERT(t->kind != Type_Tuple);
- lbValue ev = lb_emit_conv(p, field_expr, et);
-
- if (!p->copy_elision_hint.used) {
- temp_data[i].value = ev;
- }
-
- lb_reset_copy_elision_hint(p, prev_hint);
- }
-
-
- // TODO(bill): reduce the need for individual `insertelement` if a `shufflevector`
- // might be a better option
-
- for_array(i, temp_data) {
- if (temp_data[i].value.value != nullptr) {
- LLVMValueRef index = lb_const_int(p->module, t_u32, temp_data[i].elem_index).value;
- vector_value.value = LLVMBuildInsertElement(p->builder, vector_value.value, temp_data[i].value.value, index, "");
- }
- }
- }
- break;
- }
- }
-
- return v;
+ return lb_build_addr_compound_lit(p, expr);
case_end;
case_ast_node(tc, TypeCast, expr);
diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp
index b61439238..6f98458fa 100644
--- a/src/llvm_backend_general.cpp
+++ b/src/llvm_backend_general.cpp
@@ -56,6 +56,7 @@ void lb_init_module(lbModule *m, Checker *c) {
gbAllocator a = heap_allocator();
map_init(&m->types, a);
+ map_init(&m->func_raw_types, a);
map_init(&m->struct_field_remapping, a);
map_init(&m->values, a);
map_init(&m->soa_values, a);
@@ -174,7 +175,8 @@ struct lbLoopData {
struct lbCompoundLitElemTempData {
Ast * expr;
lbValue value;
- i32 elem_index;
+ i64 elem_index;
+ i64 elem_length;
lbValue gep;
};
@@ -211,6 +213,45 @@ void lb_loop_end(lbProcedure *p, lbLoopData const &data) {
}
+// This emits a GEP at 0, index
+lbValue lb_emit_epi(lbProcedure *p, lbValue const &value, isize index) {
+ GB_ASSERT(is_type_pointer(value.type));
+ Type *type = type_deref(value.type);
+
+ LLVMValueRef indices[2] = {
+ LLVMConstInt(lb_type(p->module, t_int), 0, false),
+ LLVMConstInt(lb_type(p->module, t_int), cast(unsigned long long)index, false),
+ };
+ LLVMTypeRef llvm_type = lb_type(p->module, type);
+ lbValue res = {};
+ Type *ptr = base_array_type(type);
+ res.type = alloc_type_pointer(ptr);
+ if (LLVMIsConstant(value.value)) {
+ res.value = LLVMConstGEP2(llvm_type, value.value, indices, gb_count_of(indices));
+ } else {
+ res.value = LLVMBuildGEP2(p->builder, llvm_type, value.value, indices, gb_count_of(indices), "");
+ }
+ return res;
+}
+// This emits a GEP at 0, index
+lbValue lb_emit_epi(lbModule *m, lbValue const &value, isize index) {
+ GB_ASSERT(is_type_pointer(value.type));
+ GB_ASSERT(LLVMIsConstant(value.value));
+ Type *type = type_deref(value.type);
+
+ LLVMValueRef indices[2] = {
+ LLVMConstInt(lb_type(m, t_int), 0, false),
+ LLVMConstInt(lb_type(m, t_int), cast(unsigned long long)index, false),
+ };
+ lbValue res = {};
+ Type *ptr = base_array_type(type);
+ res.type = alloc_type_pointer(ptr);
+ res.value = LLVMConstGEP2(lb_type(m, type), value.value, indices, gb_count_of(indices));
+ return res;
+}
+
+
+
LLVMValueRef llvm_zero(lbModule *m) {
return LLVMConstInt(lb_type(m, t_int), 0, false);
}
@@ -341,9 +382,6 @@ Type *lb_addr_type(lbAddr const &addr) {
}
return type_deref(addr.addr.type);
}
-LLVMTypeRef lb_addr_lb_type(lbAddr const &addr) {
- return LLVMGetElementType(LLVMTypeOf(addr.addr.value));
-}
lbValue lb_addr_get_ptr(lbProcedure *p, lbAddr const &addr) {
if (addr.addr.value == nullptr) {
@@ -530,6 +568,13 @@ void lb_emit_slice_bounds_check(lbProcedure *p, Token token, lbValue low, lbValu
}
}
+unsigned lb_try_get_alignment(LLVMValueRef addr_ptr, unsigned default_alignment) {
+ if (LLVMIsAGlobalValue(addr_ptr) || LLVMIsAAllocaInst(addr_ptr) || LLVMIsALoadInst(addr_ptr)) {
+ return LLVMGetAlignment(addr_ptr);
+ }
+ return default_alignment;
+}
+
bool lb_try_update_alignment(LLVMValueRef addr_ptr, unsigned alignment) {
if (LLVMIsAGlobalValue(addr_ptr) || LLVMIsAAllocaInst(addr_ptr) || LLVMIsALoadInst(addr_ptr)) {
if (LLVMGetAlignment(addr_ptr) < alignment) {
@@ -546,6 +591,9 @@ bool lb_try_update_alignment(lbValue ptr, unsigned alignment) {
return lb_try_update_alignment(ptr.value, alignment);
}
+bool lb_can_try_to_inline_array_arith(Type *t) {
+ return type_size_of(t) <= build_context.max_simd_align;
+}
bool lb_try_vector_cast(lbModule *m, lbValue ptr, LLVMTypeRef *vector_type_) {
Type *array_type = base_type(type_deref(ptr.type));
@@ -554,7 +602,7 @@ bool lb_try_vector_cast(lbModule *m, lbValue ptr, LLVMTypeRef *vector_type_) {
Type *elem_type = base_array_type(array_type);
// TODO(bill): Determine what is the correct limit for doing vector arithmetic
- if (type_size_of(array_type) <= build_context.max_align &&
+ if (lb_can_try_to_inline_array_arith(array_type) &&
is_type_valid_vector_elem(elem_type)) {
// Try to treat it like a vector if possible
bool possible = false;
@@ -854,8 +902,12 @@ void lb_emit_store(lbProcedure *p, lbValue ptr, lbValue value) {
Type *a = type_deref(ptr.type);
if (LLVMIsNull(value.value)) {
- LLVMTypeRef src_t = LLVMGetElementType(LLVMTypeOf(ptr.value));
- if (lb_sizeof(src_t) <= lb_max_zero_init_size()) {
+ LLVMTypeRef src_t = llvm_addr_type(p->module, ptr);
+ if (is_type_proc(a)) {
+ LLVMTypeRef rawptr_type = lb_type(p->module, t_rawptr);
+ LLVMTypeRef rawptr_ptr_type = LLVMPointerType(rawptr_type, 0);
+ LLVMBuildStore(p->builder, LLVMConstNull(rawptr_type), LLVMBuildBitCast(p->builder, ptr.value, rawptr_ptr_type, ""));
+ } else if (lb_sizeof(src_t) <= lb_max_zero_init_size()) {
LLVMBuildStore(p->builder, LLVMConstNull(src_t), ptr.value);
} else {
lb_mem_zero_ptr(p, ptr.value, a, 1);
@@ -873,25 +925,46 @@ void lb_emit_store(lbProcedure *p, lbValue ptr, lbValue value) {
enum {MAX_STORE_SIZE = 64};
- if (LLVMIsALoadInst(value.value) && lb_sizeof(LLVMTypeOf(value.value)) > MAX_STORE_SIZE) {
- LLVMValueRef dst_ptr = ptr.value;
- LLVMValueRef src_ptr = LLVMGetOperand(value.value, 0);
- src_ptr = LLVMBuildPointerCast(p->builder, src_ptr, LLVMTypeOf(dst_ptr), "");
-
- LLVMBuildMemMove(p->builder,
- dst_ptr, 1,
- src_ptr, 1,
- LLVMConstInt(LLVMInt64TypeInContext(p->module->ctx), lb_sizeof(LLVMTypeOf(value.value)), false));
- return;
+ if (lb_sizeof(LLVMTypeOf(value.value)) > MAX_STORE_SIZE) {
+ if (LLVMIsALoadInst(value.value)) {
+ LLVMValueRef dst_ptr = ptr.value;
+ LLVMValueRef src_ptr_original = LLVMGetOperand(value.value, 0);
+ LLVMValueRef src_ptr = LLVMBuildPointerCast(p->builder, src_ptr_original, LLVMTypeOf(dst_ptr), "");
+
+ LLVMBuildMemMove(p->builder,
+ dst_ptr, lb_try_get_alignment(dst_ptr, 1),
+ src_ptr, lb_try_get_alignment(src_ptr_original, 1),
+ 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);
+ LLVMValueRef global_data = addr.addr.value;
+ // make it truly private data
+ LLVMSetLinkage(global_data, LLVMPrivateLinkage);
+ LLVMSetUnnamedAddress(global_data, LLVMGlobalUnnamedAddr);
+ LLVMSetGlobalConstant(global_data, true);
+
+ LLVMValueRef dst_ptr = ptr.value;
+ LLVMValueRef src_ptr = global_data;
+ src_ptr = LLVMBuildPointerCast(p->builder, src_ptr, LLVMTypeOf(dst_ptr), "");
+
+ LLVMBuildMemMove(p->builder,
+ dst_ptr, lb_try_get_alignment(dst_ptr, 1),
+ src_ptr, lb_try_get_alignment(global_data, 1),
+ LLVMConstInt(LLVMInt64TypeInContext(p->module->ctx), lb_sizeof(LLVMTypeOf(value.value)), false));
+ return;
+ }
}
if (lb_is_type_proc_recursive(a)) {
// NOTE(bill, 2020-11-11): Because of certain LLVM rules, a procedure value may be
// stored as regular pointer with no procedure information
- LLVMTypeRef src_t = LLVMGetElementType(LLVMTypeOf(ptr.value));
- LLVMValueRef v = LLVMBuildPointerCast(p->builder, value.value, src_t, "");
- LLVMBuildStore(p->builder, v, ptr.value);
+ LLVMTypeRef rawptr_type = lb_type(p->module, t_rawptr);
+ LLVMTypeRef rawptr_ptr_type = LLVMPointerType(rawptr_type, 0);
+ LLVMBuildStore(p->builder,
+ LLVMBuildPointerCast(p->builder, value.value, rawptr_type, ""),
+ LLVMBuildPointerCast(p->builder, ptr.value, rawptr_ptr_type, ""));
} else {
Type *ca = core_type(a);
if (ca->kind == Type_Basic || ca->kind == Type_Proc) {
@@ -904,8 +977,8 @@ void lb_emit_store(lbProcedure *p, lbValue ptr, lbValue value) {
}
}
-LLVMTypeRef llvm_addr_type(lbValue addr_val) {
- return LLVMGetElementType(LLVMTypeOf(addr_val.value));
+LLVMTypeRef llvm_addr_type(lbModule *module, lbValue addr_val) {
+ return lb_type(module, type_deref(addr_val.type));
}
lbValue lb_emit_load(lbProcedure *p, lbValue value) {
@@ -914,12 +987,18 @@ lbValue lb_emit_load(lbProcedure *p, lbValue value) {
Type *vt = base_type(value.type);
GB_ASSERT(vt->kind == Type_MultiPointer);
Type *t = vt->MultiPointer.elem;
- LLVMValueRef v = LLVMBuildLoad2(p->builder, llvm_addr_type(value), value.value, "");
+ LLVMValueRef v = LLVMBuildLoad2(p->builder, lb_type(p->module, t), value.value, "");
return lbValue{v, t};
+ } else if (is_type_soa_pointer(value.type)) {
+ lbValue ptr = lb_emit_struct_ev(p, value, 0);
+ lbValue idx = lb_emit_struct_ev(p, value, 1);
+ lbAddr addr = lb_addr_soa_variable(ptr, idx, nullptr);
+ return lb_addr_load(p, addr);
}
+
GB_ASSERT(is_type_pointer(value.type));
Type *t = type_deref(value.type);
- LLVMValueRef v = LLVMBuildLoad2(p->builder, llvm_addr_type(value), value.value, "");
+ LLVMValueRef v = LLVMBuildLoad2(p->builder, lb_type(p->module, t), value.value, "");
return lbValue{v, t};
}
@@ -1184,12 +1263,12 @@ lbValue lb_emit_union_tag_ptr(lbProcedure *p, lbValue u) {
Type *tag_type = union_tag_type(ut);
- LLVMTypeRef uvt = LLVMGetElementType(LLVMTypeOf(u.value));
+ LLVMTypeRef uvt = llvm_addr_type(p->module, u);
unsigned element_count = LLVMCountStructElementTypes(uvt);
GB_ASSERT_MSG(element_count >= 2, "element_count=%u (%s) != (%s)", element_count, type_to_string(ut), LLVMPrintTypeToString(uvt));
lbValue tag_ptr = {};
- tag_ptr.value = LLVMBuildStructGEP(p->builder, u.value, 1, "");
+ tag_ptr.value = LLVMBuildStructGEP2(p->builder, uvt, u.value, 1, "");
tag_ptr.type = alloc_type_pointer(tag_type);
return tag_ptr;
}
@@ -1413,6 +1492,116 @@ String lb_get_entity_name(lbModule *m, Entity *e, String default_name) {
}
+LLVMTypeRef lb_type_internal_for_procedures_raw(lbModule *m, Type *type) {
+ Type *original_type = type;
+ type = base_type(original_type);
+ GB_ASSERT(type->kind == Type_Proc);
+
+ LLVMTypeRef *found = map_get(&m->func_raw_types, type);
+ if (found) {
+ return *found;
+ }
+
+ unsigned param_count = 0;
+ if (type->Proc.calling_convention == ProcCC_Odin) {
+ param_count += 1;
+ }
+
+ if (type->Proc.param_count != 0) {
+ GB_ASSERT(type->Proc.params->kind == Type_Tuple);
+ for_array(i, type->Proc.params->Tuple.variables) {
+ Entity *e = type->Proc.params->Tuple.variables[i];
+ if (e->kind != Entity_Variable) {
+ continue;
+ }
+ if (e->flags & EntityFlag_CVarArg) {
+ continue;
+ }
+ param_count += 1;
+ }
+ }
+ m->internal_type_level += 1;
+ defer (m->internal_type_level -= 1);
+
+ LLVMTypeRef ret = nullptr;
+ LLVMTypeRef *params = gb_alloc_array(permanent_allocator(), LLVMTypeRef, param_count);
+ if (type->Proc.result_count != 0) {
+ Type *single_ret = reduce_tuple_to_single_type(type->Proc.results);
+ ret = lb_type(m, single_ret);
+ if (ret != nullptr) {
+ if (is_type_boolean(single_ret) &&
+ is_calling_convention_none(type->Proc.calling_convention) &&
+ type_size_of(single_ret) <= 1) {
+ ret = LLVMInt1TypeInContext(m->ctx);
+ }
+ }
+ }
+
+ unsigned param_index = 0;
+ if (type->Proc.param_count != 0) {
+ GB_ASSERT(type->Proc.params->kind == Type_Tuple);
+ for_array(i, type->Proc.params->Tuple.variables) {
+ Entity *e = type->Proc.params->Tuple.variables[i];
+ if (e->kind != Entity_Variable) {
+ continue;
+ }
+ if (e->flags & EntityFlag_CVarArg) {
+ continue;
+ }
+ Type *e_type = reduce_tuple_to_single_type(e->type);
+
+ LLVMTypeRef param_type = nullptr;
+ if (e->flags & EntityFlag_ByPtr) {
+ param_type = lb_type(m, alloc_type_pointer(e_type));
+ } else if (is_type_boolean(e_type) &&
+ type_size_of(e_type) <= 1) {
+ param_type = LLVMInt1TypeInContext(m->ctx);
+ } else {
+ if (is_type_proc(e_type)) {
+ param_type = lb_type(m, t_rawptr);
+ } else {
+ param_type = lb_type(m, e_type);
+ }
+ }
+
+ params[param_index++] = param_type;
+ }
+ }
+ if (param_index < param_count) {
+ params[param_index++] = lb_type(m, t_rawptr);
+ }
+ GB_ASSERT(param_index == param_count);
+
+ lbFunctionType *ft = lb_get_abi_info(m->ctx, params, param_count, ret, ret != nullptr, type->Proc.calling_convention);
+ {
+ for_array(j, ft->args) {
+ auto arg = ft->args[j];
+ GB_ASSERT_MSG(LLVMGetTypeContext(arg.type) == ft->ctx,
+ "\n\t%s %td/%td"
+ "\n\tArgTypeCtx: %p\n\tCurrentCtx: %p\n\tGlobalCtx: %p",
+ LLVMPrintTypeToString(arg.type),
+ j, ft->args.count,
+ LLVMGetTypeContext(arg.type), ft->ctx, LLVMGetGlobalContext());
+ }
+ GB_ASSERT_MSG(LLVMGetTypeContext(ft->ret.type) == ft->ctx,
+ "\n\t%s"
+ "\n\tRetTypeCtx: %p\n\tCurrentCtx: %p\n\tGlobalCtx: %p",
+ LLVMPrintTypeToString(ft->ret.type),
+ LLVMGetTypeContext(ft->ret.type), ft->ctx, LLVMGetGlobalContext());
+ }
+
+ map_set(&m->function_type_map, type, ft);
+ LLVMTypeRef new_abi_fn_type = lb_function_type_to_llvm_raw(ft, type->Proc.c_vararg);
+
+ GB_ASSERT_MSG(LLVMGetTypeContext(new_abi_fn_type) == m->ctx,
+ "\n\tFuncTypeCtx: %p\n\tCurrentCtx: %p\n\tGlobalCtx: %p",
+ LLVMGetTypeContext(new_abi_fn_type), m->ctx, LLVMGetGlobalContext());
+
+ map_set(&m->func_raw_types, type, new_abi_fn_type);
+
+ return new_abi_fn_type;
+
+}
LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
LLVMContextRef ctx = m->ctx;
i64 size = type_size_of(type); // Check size
@@ -1916,103 +2105,8 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
if (m->internal_type_level > 1) { // TODO HACK(bill): is this really enough?
return LLVMPointerType(LLVMIntTypeInContext(m->ctx, 8), 0);
} else {
- unsigned param_count = 0;
- if (type->Proc.calling_convention == ProcCC_Odin) {
- param_count += 1;
- }
-
- if (type->Proc.param_count != 0) {
- GB_ASSERT(type->Proc.params->kind == Type_Tuple);
- for_array(i, type->Proc.params->Tuple.variables) {
- Entity *e = type->Proc.params->Tuple.variables[i];
- if (e->kind != Entity_Variable) {
- continue;
- }
- if (e->flags & EntityFlag_CVarArg) {
- continue;
- }
- param_count += 1;
- }
- }
- m->internal_type_level += 1;
- defer (m->internal_type_level -= 1);
-
- LLVMTypeRef ret = nullptr;
- LLVMTypeRef *params = gb_alloc_array(permanent_allocator(), LLVMTypeRef, param_count);
- if (type->Proc.result_count != 0) {
- Type *single_ret = reduce_tuple_to_single_type(type->Proc.results);
- ret = lb_type(m, single_ret);
- if (ret != nullptr) {
- if (is_type_boolean(single_ret) &&
- is_calling_convention_none(type->Proc.calling_convention) &&
- type_size_of(single_ret) <= 1) {
- ret = LLVMInt1TypeInContext(m->ctx);
- }
- }
- }
-
- unsigned param_index = 0;
- if (type->Proc.param_count != 0) {
- GB_ASSERT(type->Proc.params->kind == Type_Tuple);
- for_array(i, type->Proc.params->Tuple.variables) {
- Entity *e = type->Proc.params->Tuple.variables[i];
- if (e->kind != Entity_Variable) {
- continue;
- }
- if (e->flags & EntityFlag_CVarArg) {
- continue;
- }
- Type *e_type = reduce_tuple_to_single_type(e->type);
-
- LLVMTypeRef param_type = nullptr;
- if (e->flags & EntityFlag_ByPtr) {
- param_type = lb_type(m, alloc_type_pointer(e_type));
- } else if (is_type_boolean(e_type) &&
- type_size_of(e_type) <= 1) {
- param_type = LLVMInt1TypeInContext(m->ctx);
- } else {
- if (is_type_proc(e_type)) {
- param_type = lb_type(m, t_rawptr);
- } else {
- param_type = lb_type(m, e_type);
- }
- }
-
- params[param_index++] = param_type;
- }
- }
- if (param_index < param_count) {
- params[param_index++] = lb_type(m, t_rawptr);
- }
- GB_ASSERT(param_index == param_count);
-
- lbFunctionType *ft = lb_get_abi_info(m->ctx, params, param_count, ret, ret != nullptr, type->Proc.calling_convention);
- {
- for_array(j, ft->args) {
- auto arg = ft->args[j];
- GB_ASSERT_MSG(LLVMGetTypeContext(arg.type) == ft->ctx,
- "\n\t%s %td/%td"
- "\n\tArgTypeCtx: %p\n\tCurrentCtx: %p\n\tGlobalCtx: %p",
- LLVMPrintTypeToString(arg.type),
- j, ft->args.count,
- LLVMGetTypeContext(arg.type), ft->ctx, LLVMGetGlobalContext());
- }
- GB_ASSERT_MSG(LLVMGetTypeContext(ft->ret.type) == ft->ctx,
- "\n\t%s"
- "\n\tRetTypeCtx: %p\n\tCurrentCtx: %p\n\tGlobalCtx: %p",
- LLVMPrintTypeToString(ft->ret.type),
- LLVMGetTypeContext(ft->ret.type), ft->ctx, LLVMGetGlobalContext());
- }
-
- map_set(&m->function_type_map, type, ft);
- LLVMTypeRef new_abi_fn_ptr_type = lb_function_type_to_llvm_ptr(ft, type->Proc.c_vararg);
- LLVMTypeRef new_abi_fn_type = LLVMGetElementType(new_abi_fn_ptr_type);
-
- GB_ASSERT_MSG(LLVMGetTypeContext(new_abi_fn_type) == m->ctx,
- "\n\tFuncTypeCtx: %p\n\tCurrentCtx: %p\n\tGlobalCtx: %p",
- LLVMGetTypeContext(new_abi_fn_type), m->ctx, LLVMGetGlobalContext());
-
- return new_abi_fn_ptr_type;
+ LLVMTypeRef proc_raw_type = lb_type_internal_for_procedures_raw(m, type);
+ return LLVMPointerType(proc_raw_type, 0);
}
break;
@@ -2055,6 +2149,15 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
m->internal_type_level += 1;
return t;
}
+
+ case Type_SoaPointer:
+ {
+ unsigned field_count = 2;
+ LLVMTypeRef *fields = gb_alloc_array(permanent_allocator(), LLVMTypeRef, field_count);
+ fields[0] = LLVMPointerType(lb_type(m, type->Pointer.elem), 0);
+ fields[1] = LLVMIntTypeInContext(ctx, 8*cast(unsigned)build_context.word_size);
+ return LLVMStructTypeInContext(ctx, fields, field_count, false);
+ }
}
@@ -2259,6 +2362,17 @@ void lb_emit_if(lbProcedure *p, lbValue cond, lbBlock *true_block, lbBlock *fals
}
+gb_inline LLVMTypeRef OdinLLVMGetInternalElementType(LLVMTypeRef type) {
+ return LLVMGetElementType(type);
+}
+LLVMTypeRef OdinLLVMGetArrayElementType(LLVMTypeRef type) {
+ GB_ASSERT(lb_is_type_kind(type, LLVMArrayTypeKind));
+ return OdinLLVMGetInternalElementType(type);
+}
+LLVMTypeRef OdinLLVMGetVectorElementType(LLVMTypeRef type) {
+ GB_ASSERT(lb_is_type_kind(type, LLVMVectorTypeKind));
+ return OdinLLVMGetInternalElementType(type);
+}
LLVMValueRef OdinLLVMBuildTransmute(lbProcedure *p, LLVMValueRef val, LLVMTypeRef dst_type) {
@@ -2329,7 +2443,7 @@ general_end:;
if (LLVMIsALoadInst(val) && (src_size >= 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 = LLVMBuildLoad(p->builder, val_ptr, "");
+ LLVMValueRef loaded_val = LLVMBuildLoad2(p->builder, dst_type, val_ptr, "");
// LLVMSetAlignment(loaded_val, gb_min(src_align, dst_align));
@@ -2345,7 +2459,7 @@ general_end:;
LLVMValueRef nptr = LLVMBuildPointerCast(p->builder, ptr, LLVMPointerType(src_type, 0), "");
LLVMBuildStore(p->builder, val, nptr);
- return LLVMBuildLoad(p->builder, ptr, "");
+ return LLVMBuildLoad2(p->builder, dst_type, ptr, "");
}
}
@@ -2371,14 +2485,15 @@ LLVMValueRef lb_find_or_add_entity_string_ptr(lbModule *m, String const &str) {
isize len = gb_snprintf(name, max_len, "csbs$%x", id);
len -= 1;
- LLVMValueRef global_data = LLVMAddGlobal(m->mod, LLVMTypeOf(data), name);
+ LLVMTypeRef type = LLVMTypeOf(data);
+ LLVMValueRef global_data = LLVMAddGlobal(m->mod, type, name);
LLVMSetInitializer(global_data, data);
LLVMSetLinkage(global_data, LLVMPrivateLinkage);
LLVMSetUnnamedAddress(global_data, LLVMGlobalUnnamedAddr);
LLVMSetAlignment(global_data, 1);
LLVMSetGlobalConstant(global_data, true);
- LLVMValueRef ptr = LLVMConstInBoundsGEP(global_data, indices, 2);
+ LLVMValueRef ptr = LLVMConstInBoundsGEP2(type, global_data, indices, 2);
string_map_set(&m->const_strings, key, ptr);
return ptr;
}
@@ -2416,7 +2531,8 @@ lbValue lb_find_or_add_entity_string_byte_slice(lbModule *m, String const &str)
isize len = gb_snprintf(name, max_len, "csbs$%x", id);
len -= 1;
}
- LLVMValueRef global_data = LLVMAddGlobal(m->mod, LLVMTypeOf(data), name);
+ LLVMTypeRef type = LLVMTypeOf(data);
+ LLVMValueRef global_data = LLVMAddGlobal(m->mod, type, name);
LLVMSetInitializer(global_data, data);
LLVMSetLinkage(global_data, LLVMPrivateLinkage);
LLVMSetUnnamedAddress(global_data, LLVMGlobalUnnamedAddr);
@@ -2425,7 +2541,7 @@ lbValue lb_find_or_add_entity_string_byte_slice(lbModule *m, String const &str)
LLVMValueRef ptr = nullptr;
if (str.len != 0) {
- ptr = LLVMConstInBoundsGEP(global_data, indices, 2);
+ ptr = LLVMConstInBoundsGEP2(type, global_data, indices, 2);
} else {
ptr = LLVMConstNull(lb_type(m, t_u8_ptr));
}
@@ -2437,7 +2553,55 @@ lbValue lb_find_or_add_entity_string_byte_slice(lbModule *m, String const &str)
res.type = t_u8_slice;
return res;
}
+lbValue lb_find_or_add_entity_string_byte_slice_with_type(lbModule *m, String const &str, Type *slice_type) {
+ GB_ASSERT(is_type_slice(slice_type));
+ LLVMValueRef indices[2] = {llvm_zero(m), llvm_zero(m)};
+ LLVMValueRef data = LLVMConstStringInContext(m->ctx,
+ cast(char const *)str.text,
+ cast(unsigned)str.len,
+ 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;
+ }
+ LLVMTypeRef type = LLVMTypeOf(data);
+ LLVMValueRef global_data = LLVMAddGlobal(m->mod, type, name);
+ LLVMSetInitializer(global_data, data);
+ LLVMSetLinkage(global_data, LLVMPrivateLinkage);
+ LLVMSetUnnamedAddress(global_data, LLVMGlobalUnnamedAddr);
+ LLVMSetAlignment(global_data, 1);
+ LLVMSetGlobalConstant(global_data, true);
+
+ i64 data_len = str.len;
+ LLVMValueRef ptr = nullptr;
+ if (data_len != 0) {
+ ptr = LLVMConstInBoundsGEP2(type, global_data, indices, 2);
+ } else {
+ ptr = LLVMConstNull(lb_type(m, t_u8_ptr));
+ }
+ if (!is_type_u8_slice(slice_type)) {
+ Type *bt = base_type(slice_type);
+ Type *elem = bt->Slice.elem;
+ i64 sz = type_size_of(elem);
+ GB_ASSERT(sz > 0);
+ ptr = LLVMConstPointerCast(ptr, lb_type(m, alloc_type_pointer(elem)));
+ data_len /= sz;
+ }
+
+ LLVMValueRef len = LLVMConstInt(lb_type(m, t_int), data_len, true);
+ LLVMValueRef values[2] = {ptr, len};
+ lbValue res = {};
+ res.value = llvm_const_named_struct(m, slice_type, values, 2);
+ res.type = slice_type;
+ return res;
+}
diff --git a/src/llvm_backend_opt.cpp b/src/llvm_backend_opt.cpp
index 6b80b21d6..e2f51b868 100644
--- a/src/llvm_backend_opt.cpp
+++ b/src/llvm_backend_opt.cpp
@@ -62,7 +62,9 @@ void lb_basic_populate_function_pass_manager(LLVMPassManagerRef fpm, i32 optimiz
LLVMAddPromoteMemoryToRegisterPass(fpm);
LLVMAddMergedLoadStoreMotionPass(fpm);
LLVM_ADD_CONSTANT_VALUE_PASS(fpm);
- LLVMAddEarlyCSEPass(fpm);
+ if (!build_context.ODIN_DEBUG) {
+ LLVMAddEarlyCSEPass(fpm);
+ }
}
}
diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp
index 0b0c0794b..f85d8397c 100644
--- a/src/llvm_backend_proc.cpp
+++ b/src/llvm_backend_proc.cpp
@@ -1,3 +1,13 @@
+
+LLVMValueRef lb_call_intrinsic(lbProcedure *p, const char *name, LLVMValueRef* args, unsigned arg_count, LLVMTypeRef* types, unsigned type_count)
+{
+ unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
+ GB_ASSERT_MSG(id != 0, "Unable to find %s", name);
+ LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, type_count);
+ LLVMTypeRef call_type = LLVMIntrinsicGetType(p->module->ctx, id, types, type_count);
+ return LLVMBuildCall2(p->builder, call_type, ip, args, arg_count, "");
+}
+
void lb_mem_copy_overlapping(lbProcedure *p, lbValue dst, lbValue src, lbValue len, bool is_volatile) {
dst = lb_emit_conv(p, dst, t_rawptr);
src = lb_emit_conv(p, src, t_rawptr);
@@ -10,23 +20,23 @@ void lb_mem_copy_overlapping(lbProcedure *p, lbValue dst, lbValue src, lbValue l
name = "llvm.memmove.inline";
}
}
-
LLVMTypeRef types[3] = {
lb_type(p->module, t_rawptr),
lb_type(p->module, t_rawptr),
lb_type(p->module, t_int)
};
- unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
- GB_ASSERT_MSG(id != 0, "Unable to find %s.%s.%s.%s", name, LLVMPrintTypeToString(types[0]), LLVMPrintTypeToString(types[1]), LLVMPrintTypeToString(types[2]));
- LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types));
-
- LLVMValueRef args[4] = {};
- args[0] = dst.value;
- args[1] = src.value;
- args[2] = len.value;
- args[3] = LLVMConstInt(LLVMInt1TypeInContext(p->module->ctx), 0, is_volatile);
- LLVMBuildCall(p->builder, ip, args, gb_count_of(args), "");
+ LLVMValueRef args[4] = {
+ dst.value,
+ src.value,
+ len.value,
+ LLVMConstInt(LLVMInt1TypeInContext(p->module->ctx), 0, is_volatile)
+ };
+
+ lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types));
}
+
+
+
void lb_mem_copy_non_overlapping(lbProcedure *p, lbValue dst, lbValue src, lbValue len, bool is_volatile) {
dst = lb_emit_conv(p, dst, t_rawptr);
src = lb_emit_conv(p, src, t_rawptr);
@@ -45,16 +55,14 @@ void lb_mem_copy_non_overlapping(lbProcedure *p, lbValue dst, lbValue src, lbVal
lb_type(p->module, t_rawptr),
lb_type(p->module, t_int)
};
- unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
- GB_ASSERT_MSG(id != 0, "Unable to find %s.%s.%s.%s", name, LLVMPrintTypeToString(types[0]), LLVMPrintTypeToString(types[1]), LLVMPrintTypeToString(types[2]));
- LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types));
-
- LLVMValueRef args[4] = {};
- args[0] = dst.value;
- args[1] = src.value;
- args[2] = len.value;
- args[3] = LLVMConstInt(LLVMInt1TypeInContext(p->module->ctx), 0, is_volatile);
- LLVMBuildCall(p->builder, ip, args, gb_count_of(args), "");
+
+ LLVMValueRef args[4] = {
+ dst.value,
+ src.value,
+ len.value,
+ LLVMConstInt(LLVMInt1TypeInContext(p->module->ctx), 0, is_volatile) };
+
+ lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types));
}
@@ -121,8 +129,7 @@ lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool ignore_body)
}
char *c_link_name = alloc_cstring(permanent_allocator(), p->name);
- LLVMTypeRef func_ptr_type = lb_type(m, p->type);
- LLVMTypeRef func_type = LLVMGetElementType(func_ptr_type);
+ LLVMTypeRef func_type = lb_get_procedure_raw_type(m, p->type);
p->value = LLVMAddFunction(m->mod, c_link_name, func_type);
@@ -141,34 +148,30 @@ lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool ignore_body)
lb_add_attribute_to_proc(m, p->value, "noredzone");
}
- if (build_context.optimization_level == 0 && build_context.ODIN_DEBUG) {
+
+ switch (p->inlining) {
+ case ProcInlining_inline:
+ lb_add_attribute_to_proc(m, p->value, "alwaysinline");
+ break;
+ case ProcInlining_no_inline:
lb_add_attribute_to_proc(m, p->value, "noinline");
- lb_add_attribute_to_proc(m, p->value, "optnone");
- } else {
- switch (p->inlining) {
- case ProcInlining_inline:
- lb_add_attribute_to_proc(m, p->value, "alwaysinline");
- break;
- case ProcInlining_no_inline:
- lb_add_attribute_to_proc(m, p->value, "noinline");
- break;
- }
+ break;
+ }
- switch (entity->Procedure.optimization_mode) {
- case ProcedureOptimizationMode_None:
- lb_add_attribute_to_proc(m, p->value, "optnone");
- break;
- case ProcedureOptimizationMode_Minimal:
- lb_add_attribute_to_proc(m, p->value, "optnone");
- break;
- case ProcedureOptimizationMode_Size:
- lb_add_attribute_to_proc(m, p->value, "optsize");
- break;
- case ProcedureOptimizationMode_Speed:
- // TODO(bill): handle this correctly
- lb_add_attribute_to_proc(m, p->value, "optsize");
- break;
- }
+ switch (entity->Procedure.optimization_mode) {
+ case ProcedureOptimizationMode_None:
+ lb_add_attribute_to_proc(m, p->value, "optnone");
+ break;
+ case ProcedureOptimizationMode_Minimal:
+ lb_add_attribute_to_proc(m, p->value, "optnone");
+ break;
+ case ProcedureOptimizationMode_Size:
+ lb_add_attribute_to_proc(m, p->value, "optsize");
+ break;
+ case ProcedureOptimizationMode_Speed:
+ // TODO(bill): handle this correctly
+ lb_add_attribute_to_proc(m, p->value, "optsize");
+ break;
}
if (!entity->Procedure.target_feature_disabled &&
@@ -346,8 +349,7 @@ lbProcedure *lb_create_dummy_procedure(lbModule *m, String link_name, Type *type
char *c_link_name = alloc_cstring(permanent_allocator(), p->name);
- LLVMTypeRef func_ptr_type = lb_type(m, p->type);
- LLVMTypeRef func_type = LLVMGetElementType(func_ptr_type);
+ LLVMTypeRef func_type = lb_get_procedure_raw_type(m, p->type);
p->value = LLVMAddFunction(m->mod, c_link_name, func_type);
@@ -745,12 +747,12 @@ lbValue lb_emit_call_internal(lbProcedure *p, lbValue value, lbValue return_ptr,
GB_ASSERT(curr_block != p->decl_block->block);
{
- LLVMTypeRef ftp = lb_type(p->module, value.type);
+ LLVMTypeRef fnp = lb_type_internal_for_procedures_raw(p->module, value.type);
+ LLVMTypeRef ftp = LLVMPointerType(fnp, 0);
LLVMValueRef fn = value.value;
if (!lb_is_type_kind(LLVMTypeOf(value.value), LLVMFunctionTypeKind)) {
fn = LLVMBuildPointerCast(p->builder, fn, ftp, "");
}
- LLVMTypeRef fnp = LLVMGetElementType(LLVMTypeOf(fn));
GB_ASSERT_MSG(lb_is_type_kind(fnp, LLVMFunctionTypeKind), "%s", LLVMPrintTypeToString(fnp));
{
@@ -1264,13 +1266,8 @@ lbValue lb_build_builtin_simd_proc(lbProcedure *p, Ast *expr, TypeAndValue const
}
args[args_count++] = arg0.value;
-
LLVMTypeRef types[1] = {lb_type(p->module, arg0.type)};
- unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
- GB_ASSERT_MSG(id != 0, "Unable to find %s.%s", name, LLVMPrintTypeToString(types[0]));
- LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types));
-
- res.value = LLVMBuildCall(p->builder, ip, args, cast(unsigned)args_count, "");
+ res.value = lb_call_intrinsic(p, name, args, cast(unsigned)args_count, types, gb_count_of(types));
return res;
}
case BuiltinProc_simd_reduce_min:
@@ -1303,15 +1300,11 @@ lbValue lb_build_builtin_simd_proc(lbProcedure *p, Ast *expr, TypeAndValue const
case BuiltinProc_simd_reduce_or: name = "llvm.vector.reduce.or"; break;
case BuiltinProc_simd_reduce_xor: name = "llvm.vector.reduce.xor"; break;
}
- LLVMTypeRef types[1] = {lb_type(p->module, arg0.type)};
- unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
- GB_ASSERT_MSG(id != 0, "Unable to find %s.%s", name, LLVMPrintTypeToString(types[0]));
- LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types));
- LLVMValueRef args[1] = {};
- args[0] = arg0.value;
+ LLVMTypeRef types[1] = { lb_type(p->module, arg0.type) };
+ LLVMValueRef args[1] = { arg0.value };
- res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), "");
+ res.value = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types));
return res;
}
@@ -1360,15 +1353,10 @@ lbValue lb_build_builtin_simd_proc(lbProcedure *p, Ast *expr, TypeAndValue const
case BuiltinProc_simd_nearest: name = "llvm.nearbyint"; break;
}
- LLVMTypeRef types[1] = {lb_type(p->module, arg0.type)};
- unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
- GB_ASSERT_MSG(id != 0, "Unable to find %s.%s", name, LLVMPrintTypeToString(types[0]));
- LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types));
+ LLVMTypeRef types[1] = { lb_type(p->module, arg0.type) };
+ LLVMValueRef args[1] = { arg0.value };
- LLVMValueRef args[1] = {};
- args[0] = arg0.value;
-
- res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), "");
+ res.value = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types));
return res;
}
@@ -1432,15 +1420,10 @@ lbValue lb_build_builtin_simd_proc(lbProcedure *p, Ast *expr, TypeAndValue const
}
LLVMTypeRef types[1] = {lb_type(p->module, arg0.type)};
- unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
- GB_ASSERT_MSG(id != 0, "Unable to find %s.%s", name, LLVMPrintTypeToString(types[0]));
- LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types));
- LLVMValueRef args[2] = {};
- args[0] = arg0.value;
- args[1] = arg1.value;
+ LLVMValueRef args[2] = { arg0.value, arg1.value };
- res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), "");
+ res.value = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types));
return res;
}
@@ -1851,6 +1834,11 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
return lb_emit_matrix_flatten(p, m, tv.type);
}
+ case BuiltinProc_unreachable:
+ lb_emit_unreachable(p);
+ return {};
+
+
// "Intrinsics"
case BuiltinProc_alloca:
@@ -1898,11 +1886,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
case BuiltinProc_trap: name = "llvm.trap"; break;
}
- unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
- GB_ASSERT_MSG(id != 0, "Unable to find %s", name);
- LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, nullptr, 0);
-
- LLVMBuildCall(p->builder, ip, nullptr, 0, "");
+ lb_call_intrinsic(p, name, nullptr, 0, nullptr, 0);
if (id == BuiltinProc_trap) {
LLVMBuildUnreachable(p->builder);
}
@@ -1922,11 +1906,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
res.value = LLVMBuildCall2(p->builder, func_type, the_asm, nullptr, 0, "");
} else {
char const *name = "llvm.readcyclecounter";
- unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
- GB_ASSERT_MSG(id != 0, "Unable to find %s", name);
- LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, nullptr, 0);
-
- res.value = LLVMBuildCall(p->builder, ip, nullptr, 0, "");
+ res.value = lb_call_intrinsic(p, name, nullptr, 0, nullptr, 0);
}
return res;
}
@@ -1981,16 +1961,11 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
}
}
LLVMTypeRef types[1] = {lb_type(p->module, type)};
- unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
- GB_ASSERT_MSG(id != 0, "Unable to find %s.%s", name, LLVMPrintTypeToString(types[0]));
- LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types));
- LLVMValueRef args[2] = {};
- args[0] = x.value;
- args[1] = y.value;
+ LLVMValueRef args[2] = { x.value, y.value };
lbValue res = {};
- res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), "");
+ res.value = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types));
if (is_type_tuple(main_type)) {
Type *res_type = nullptr;
@@ -2017,15 +1992,11 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
char const *name = "llvm.sqrt";
LLVMTypeRef types[1] = {lb_type(p->module, type)};
- unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
- GB_ASSERT_MSG(id != 0, "Unable to find %s.%s", name, LLVMPrintTypeToString(types[0]));
- LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types));
- LLVMValueRef args[1] = {};
- args[0] = x.value;
+ LLVMValueRef args[1] = { x.value };
lbValue res = {};
- res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), "");
+ res.value = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types));
res.type = type;
return res;
}
@@ -2040,17 +2011,11 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
char const *name = "llvm.fma";
LLVMTypeRef types[1] = {lb_type(p->module, type)};
- unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
- GB_ASSERT_MSG(id != 0, "Unable to find %s.%s", name, LLVMPrintTypeToString(types[0]));
- LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types));
- LLVMValueRef args[3] = {};
- args[0] = x.value;
- args[1] = y.value;
- args[2] = z.value;
+ LLVMValueRef args[3] = { x.value, y.value, z.value };
lbValue res = {};
- res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), "");
+ res.value = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types));
res.type = type;
return res;
}
@@ -2102,15 +2067,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
lbValue ptr = lb_build_expr(p, ce->args[0]);
lbValue len = lb_build_expr(p, ce->args[1]);
len = lb_emit_conv(p, len, t_int);
-
- LLVMValueRef indices[1] = {
- len.value,
- };
-
- lbValue res = {};
- res.type = tv.type;
- res.value = LLVMBuildGEP(p->builder, ptr.value, indices, gb_count_of(indices), "");
- return res;
+ return lb_emit_ptr_offset(p, ptr, len);
}
case BuiltinProc_ptr_sub:
{
@@ -2118,7 +2075,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
lbValue ptr1 = lb_build_expr(p, ce->args[1]);
LLVMTypeRef type_int = lb_type(p->module, t_int);
- LLVMValueRef diff = LLVMBuildPtrDiff(p->builder, ptr0.value, ptr1.value, "");
+ LLVMValueRef diff = LLVMBuildPtrDiff2(p->builder, lb_type(p->module, ptr0.type), ptr0.value, ptr1.value, "");
diff = LLVMBuildIntCast2(p->builder, diff, type_int, /*signed*/true, "");
lbValue res = {};
@@ -2169,7 +2126,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
case BuiltinProc_atomic_load_explicit: {
lbValue dst = lb_build_expr(p, ce->args[0]);
- LLVMValueRef instr = LLVMBuildLoad(p->builder, dst.value, "");
+ LLVMValueRef instr = LLVMBuildLoad2(p->builder, lb_type(p->module, type_deref(dst.type)), dst.value, "");
switch (id) {
case BuiltinProc_non_temporal_load:
{
@@ -2343,18 +2300,14 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
GB_ASSERT(name != nullptr);
LLVMTypeRef types[1] = {lb_type(p->module, platform_type)};
- unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
- GB_ASSERT_MSG(id != 0, "Unable to find %s.%s", name, LLVMPrintTypeToString(types[0]));
- LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types));
-
lbValue res = {};
- LLVMValueRef args[3] = {};
- args[0] = x.value;
- args[1] = y.value;
- args[2] = scale.value;
+ LLVMValueRef args[3] = {
+ x.value,
+ y.value,
+ scale.value };
- res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), "");
+ res.value = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types));
res.type = platform_type;
return lb_emit_conv(p, res, tv.type);
}
@@ -2368,17 +2321,10 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
char const *name = "llvm.expect";
LLVMTypeRef types[1] = {lb_type(p->module, t)};
- unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
- GB_ASSERT_MSG(id != 0, "Unable to find %s.%s", name, LLVMPrintTypeToString(types[0]));
- LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types));
-
lbValue res = {};
+ LLVMValueRef args[2] = { x.value, y.value };
- LLVMValueRef args[2] = {};
- args[0] = x.value;
- args[1] = y.value;
-
- res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), "");
+ res.value = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types));
res.type = t;
return lb_emit_conv(p, res, t);
}
@@ -2414,9 +2360,6 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
char const *name = "llvm.prefetch";
LLVMTypeRef types[1] = {lb_type(p->module, t_rawptr)};
- unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
- GB_ASSERT_MSG(id != 0, "Unable to find %s.%s", name, LLVMPrintTypeToString(types[0]));
- LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types));
LLVMTypeRef llvm_i32 = lb_type(p->module, t_i32);
LLVMValueRef args[4] = {};
@@ -2426,7 +2369,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
args[3] = LLVMConstInt(llvm_i32, cache, false);
lbValue res = {};
- res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), "");
+ res.value = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types));
res.type = nullptr;
return res;
}
@@ -2672,7 +2615,8 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
isize len = gb_snprintf(name, max_len, "csbs$%x", id);
len -= 1;
}
- LLVMValueRef global_data = LLVMAddGlobal(m->mod, LLVMTypeOf(array), name);
+ LLVMTypeRef type = LLVMTypeOf(array);
+ LLVMValueRef global_data = LLVMAddGlobal(m->mod, type, name);
LLVMSetInitializer(global_data, array);
LLVMSetLinkage(global_data, LLVMInternalLinkage);
@@ -2684,7 +2628,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
};
lbValue res = {};
res.type = tv.type;
- res.value = LLVMBuildInBoundsGEP(p->builder, global_data, indices, gb_count_of(indices), "");
+ res.value = LLVMBuildInBoundsGEP2(p->builder, type, global_data, indices, gb_count_of(indices), "");
return res;
}
@@ -2695,9 +2639,6 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
LLVMTypeRef types[1] = {
lb_type(p->module, t_uintptr),
};
- unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
- GB_ASSERT_MSG(id != 0, "Unable to find %s", name, LLVMPrintTypeToString(types[0]));
- LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types));
LLVMValueRef args[2] = {};
args[0] = lb_emit_conv(p, lb_build_expr(p, ce->args[0]), t_uintptr).value;
@@ -2705,7 +2646,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
lbValue res = {};
res.type = tv.type;
- res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), "");
+ res.value = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types));
return res;
}
case BuiltinProc_wasm_memory_size:
@@ -2714,16 +2655,13 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
LLVMTypeRef types[1] = {
lb_type(p->module, t_uintptr),
};
- unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
- GB_ASSERT_MSG(id != 0, "Unable to find %s", name, LLVMPrintTypeToString(types[0]));
- LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types));
LLVMValueRef args[1] = {};
args[0] = lb_emit_conv(p, lb_build_expr(p, ce->args[0]), t_uintptr).value;
lbValue res = {};
res.type = tv.type;
- res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), "");
+ res.value = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types));
return res;
}
@@ -2733,9 +2671,6 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
LLVMTypeRef types[1] = {
lb_type(p->module, t_u32),
};
- unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
- GB_ASSERT_MSG(id != 0, "Unable to find %s", name, LLVMPrintTypeToString(types[0]));
- LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, nullptr, 0); // types, gb_count_of(types));
Type *t_u32_ptr = alloc_type_pointer(t_u32);
@@ -2746,7 +2681,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
lbValue res = {};
res.type = tv.type;
- res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), "");
+ res.value = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types));
return res;
}
@@ -2756,19 +2691,16 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
LLVMTypeRef types[1] = {
lb_type(p->module, t_u32),
};
- unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
- GB_ASSERT_MSG(id != 0, "Unable to find %s", name, LLVMPrintTypeToString(types[0]));
- LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, nullptr, 0); // types, gb_count_of(types));
Type *t_u32_ptr = alloc_type_pointer(t_u32);
- LLVMValueRef args[2] = {};
- args[0] = lb_emit_conv(p, lb_build_expr(p, ce->args[0]), t_u32_ptr).value;
- args[1] = lb_emit_conv(p, lb_build_expr(p, ce->args[1]), t_u32).value;
+ LLVMValueRef args[2] = {
+ lb_emit_conv(p, lb_build_expr(p, ce->args[0]), t_u32_ptr).value,
+ lb_emit_conv(p, lb_build_expr(p, ce->args[1]), t_u32).value };
lbValue res = {};
res.type = tv.type;
- res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), "");
+ res.value = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types));
return res;
}
@@ -2777,7 +2709,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
{
Type *param_types[2] = {t_u32, t_u32};
Type *type = alloc_type_proc_from_types(param_types, gb_count_of(param_types), tv.type, false, ProcCC_None);
- LLVMTypeRef func_type = LLVMGetElementType(lb_type(p->module, type));
+ LLVMTypeRef func_type = lb_get_procedure_raw_type(p->module, type);
LLVMValueRef the_asm = llvm_get_inline_asm(
func_type,
str_lit("cpuid"),
@@ -2797,7 +2729,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
case BuiltinProc_x86_xgetbv:
{
Type *type = alloc_type_proc_from_types(&t_u32, 1, tv.type, false, ProcCC_None);
- LLVMTypeRef func_type = LLVMGetElementType(lb_type(p->module, type));
+ LLVMTypeRef func_type = lb_get_procedure_raw_type(p->module, type);
LLVMValueRef the_asm = llvm_get_inline_asm(
func_type,
str_lit("xgetbv"),
@@ -2813,6 +2745,55 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
res.value = LLVMBuildCall2(p->builder, func_type, the_asm, args, gb_count_of(args), "");
return res;
}
+
+ case BuiltinProc_valgrind_client_request:
+ {
+ lbValue args[7] = {};
+ for (isize i = 0; i < 7; i++) {
+ args[i] = lb_emit_conv(p, lb_build_expr(p, ce->args[i]), t_uintptr);
+ }
+ if (!build_context.ODIN_VALGRIND_SUPPORT) {
+ return args[0];
+ }
+ lbValue array = lb_generate_local_array(p, t_uintptr, 6, false);
+ for (isize i = 0; i < 6; i++) {
+ lbValue gep = lb_emit_array_epi(p, array, i);
+ lb_emit_store(p, gep, args[i+1]);
+ }
+
+ switch (build_context.metrics.arch) {
+ case TargetArch_amd64:
+ {
+ Type *param_types[2] = {};
+ param_types[0] = t_uintptr;
+ param_types[1] = array.type;
+
+ Type *type = alloc_type_proc_from_types(param_types, gb_count_of(param_types), t_uintptr, false, ProcCC_None);
+ LLVMTypeRef func_type = lb_get_procedure_raw_type(p->module, type);
+ LLVMValueRef the_asm = llvm_get_inline_asm(
+ func_type,
+ str_lit("rolq $3, %rdi; rolq $13, %rdi\n rolq $61, %rdi; rolq $51, %rdi\n xchgq %rbx, %rbx"),
+ str_lit("={rdx},{rdx},{rax},cc,memory"),
+ true
+ );
+
+ LLVMValueRef asm_args[2] = {};
+ asm_args[0] = args[0].value;
+ asm_args[1] = array.value;
+
+ lbValue res = {};
+ res.type = t_uintptr;
+ res.value = LLVMBuildCall2(p->builder, func_type, the_asm, asm_args, gb_count_of(asm_args), "");
+ return res;
+ }
+ break;
+ default:
+ GB_PANIC("Unsupported architecture: %.*s", LIT(target_arch_names[build_context.metrics.arch]));
+ break;
+ }
+
+ }
+
}
GB_PANIC("Unhandled built-in procedure %.*s", LIT(builtin_procs[id].name));
diff --git a/src/llvm_backend_stmt.cpp b/src/llvm_backend_stmt.cpp
index f131bb3db..175c4c537 100644
--- a/src/llvm_backend_stmt.cpp
+++ b/src/llvm_backend_stmt.cpp
@@ -458,15 +458,6 @@ void lb_build_range_interval(lbProcedure *p, AstBinaryExpr *node,
val1_type = type_of_expr(rs->vals[1]);
}
- if (val0_type != nullptr) {
- Entity *e = entity_of_node(rs->vals[0]);
- lb_add_local(p, e->type, e, true);
- }
- if (val1_type != nullptr) {
- Entity *e = entity_of_node(rs->vals[1]);
- lb_add_local(p, e->type, e, true);
- }
-
TokenKind op = Token_Lt;
switch (node->op.kind) {
case Token_Ellipsis: op = Token_LtEq; break;
@@ -478,10 +469,22 @@ void lb_build_range_interval(lbProcedure *p, AstBinaryExpr *node,
lbValue lower = lb_build_expr(p, node->left);
lbValue upper = {}; // initialized each time in the loop
- lbAddr value = lb_add_local_generated(p, val0_type ? val0_type : lower.type, false);
+ lbAddr value;
+ if (val0_type != nullptr) {
+ Entity *e = entity_of_node(rs->vals[0]);
+ value = lb_add_local(p, val0_type, e, false);
+ } else {
+ value = lb_add_local_generated(p, lower.type, false);
+ }
lb_addr_store(p, value, lower);
- lbAddr index = lb_add_local_generated(p, t_int, false);
+ lbAddr index;
+ if (val1_type != nullptr) {
+ Entity *e = entity_of_node(rs->vals[1]);
+ index = lb_add_local(p, val1_type, e, false);
+ } else {
+ index = lb_add_local_generated(p, t_int, false);
+ }
lb_addr_store(p, index, lb_const_int(m, t_int, 0));
lbBlock *loop = lb_create_block(p, "for.interval.loop");
@@ -1793,7 +1796,7 @@ void lb_build_assign_stmt_array(lbProcedure *p, TokenKind op, lbAddr const &lhs,
lbValue rhs = lb_emit_conv(p, value, lhs_type);
- bool inline_array_arith = type_size_of(array_type) <= build_context.max_align;
+ bool inline_array_arith = lb_can_try_to_inline_array_arith(array_type);
if (lhs.kind == lbAddr_Swizzle) {
diff --git a/src/llvm_backend_type.cpp b/src/llvm_backend_type.cpp
index 2e7b2788a..d424fa5b2 100644
--- a/src/llvm_backend_type.cpp
+++ b/src/llvm_backend_type.cpp
@@ -57,6 +57,7 @@ lbValue lb_typeid(lbModule *m, Type *type) {
case Type_SimdVector: kind = Typeid_Simd_Vector; break;
case Type_RelativePointer: kind = Typeid_Relative_Pointer; break;
case Type_RelativeSlice: kind = Typeid_Relative_Slice; break;
+ case Type_SoaPointer: kind = Typeid_SoaPointer; break;
}
if (is_type_cstring(type)) {
@@ -97,34 +98,12 @@ lbValue lb_type_info(lbModule *m, Type *type) {
isize index = lb_type_info_index(m->info, type);
GB_ASSERT(index >= 0);
- LLVMTypeRef it = lb_type(m, t_int);
- LLVMValueRef indices[2] = {
- LLVMConstInt(it, 0, false),
- LLVMConstInt(it, index, true),
- };
-
- lbValue value = {};
- value.value = LLVMConstGEP(lb_global_type_info_data_ptr(m).value, indices, gb_count_of(indices));
- value.type = t_type_info_ptr;
- return value;
+ lbValue data = lb_global_type_info_data_ptr(m);
+ return lb_emit_array_epi(m, data, index);
}
-lbValue lb_get_type_info_ptr(lbModule *m, Type *type) {
- GB_ASSERT(!build_context.disallow_rtti);
-
- i32 index = cast(i32)lb_type_info_index(m->info, type);
- GB_ASSERT(index >= 0);
- // gb_printf_err("%d %s\n", index, type_to_string(type));
-
- LLVMValueRef indices[2] = {
- LLVMConstInt(lb_type(m, t_int), 0, false),
- LLVMConstInt(lb_type(m, t_int), index, false),
- };
-
- lbValue res = {};
- res.type = t_type_info_ptr;
- res.value = LLVMConstGEP(lb_global_type_info_data_ptr(m).value, indices, cast(unsigned)gb_count_of(indices));
- return res;
+LLVMTypeRef lb_get_procedure_raw_type(lbModule *m, Type *type) {
+ return lb_type_internal_for_procedures_raw(m, type);
}
@@ -178,10 +157,10 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
LLVMValueRef indices[2] = {llvm_zero(m), llvm_zero(m)};
LLVMValueRef values[2] = {
- LLVMConstInBoundsGEP(lb_global_type_info_data_ptr(m).value, indices, gb_count_of(indices)),
+ LLVMConstInBoundsGEP2(lb_type(m, lb_global_type_info_data_entity->type), lb_global_type_info_data_ptr(m).value, indices, gb_count_of(indices)),
LLVMConstInt(lb_type(m, t_int), type->Array.count, true),
};
- LLVMValueRef slice = llvm_const_named_struct_internal(llvm_addr_type(global_type_table), values, gb_count_of(values));
+ LLVMValueRef slice = llvm_const_named_struct_internal(lb_type(m, type_deref(global_type_table.type)), values, gb_count_of(values));
LLVMSetInitializer(global_type_table.value, slice);
}
@@ -260,7 +239,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
LLVMValueRef vals[4] = {
lb_const_string(p->module, t->Named.type_name->token.string).value,
- lb_get_type_info_ptr(m, t->Named.base).value,
+ lb_type_info(m, t->Named.base).value,
pkg_name,
loc.value
};
@@ -419,7 +398,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
case Type_Pointer: {
tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_pointer_ptr);
- lbValue gep = lb_get_type_info_ptr(m, t->Pointer.elem);
+ lbValue gep = lb_type_info(m, t->Pointer.elem);
LLVMValueRef vals[1] = {
gep.value,
@@ -433,7 +412,21 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
}
case Type_MultiPointer: {
tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_multi_pointer_ptr);
- lbValue gep = lb_get_type_info_ptr(m, t->MultiPointer.elem);
+ lbValue gep = lb_type_info(m, t->MultiPointer.elem);
+
+ LLVMValueRef vals[1] = {
+ gep.value,
+ };
+
+ lbValue res = {};
+ res.type = type_deref(tag.type);
+ res.value = llvm_const_named_struct(m, res.type, vals, gb_count_of(vals));
+ lb_emit_store(p, tag, res);
+ break;
+ }
+ case Type_SoaPointer: {
+ tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_soa_pointer_ptr);
+ lbValue gep = lb_type_info(m, t->SoaPointer.elem);
LLVMValueRef vals[1] = {
gep.value,
@@ -450,7 +443,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
i64 ez = type_size_of(t->Array.elem);
LLVMValueRef vals[3] = {
- lb_get_type_info_ptr(m, t->Array.elem).value,
+ lb_type_info(m, t->Array.elem).value,
lb_const_int(m, t_int, ez).value,
lb_const_int(m, t_int, t->Array.count).value,
};
@@ -465,8 +458,8 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_enumerated_array_ptr);
LLVMValueRef vals[7] = {
- lb_get_type_info_ptr(m, t->EnumeratedArray.elem).value,
- lb_get_type_info_ptr(m, t->EnumeratedArray.index).value,
+ lb_type_info(m, t->EnumeratedArray.elem).value,
+ lb_type_info(m, t->EnumeratedArray.index).value,
lb_const_int(m, t_int, type_size_of(t->EnumeratedArray.elem)).value,
lb_const_int(m, t_int, t->EnumeratedArray.count).value,
@@ -497,7 +490,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_dynamic_array_ptr);
LLVMValueRef vals[2] = {
- lb_get_type_info_ptr(m, t->DynamicArray.elem).value,
+ lb_type_info(m, t->DynamicArray.elem).value,
lb_const_int(m, t_int, type_size_of(t->DynamicArray.elem)).value,
};
@@ -511,7 +504,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_slice_ptr);
LLVMValueRef vals[2] = {
- lb_get_type_info_ptr(m, t->Slice.elem).value,
+ lb_type_info(m, t->Slice.elem).value,
lb_const_int(m, t_int, type_size_of(t->Slice.elem)).value,
};
@@ -527,10 +520,10 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
LLVMValueRef params = LLVMConstNull(lb_type(m, t_type_info_ptr));
LLVMValueRef results = LLVMConstNull(lb_type(m, t_type_info_ptr));
if (t->Proc.params != nullptr) {
- params = lb_get_type_info_ptr(m, t->Proc.params).value;
+ params = lb_type_info(m, t->Proc.params).value;
}
if (t->Proc.results != nullptr) {
- results = lb_get_type_info_ptr(m, t->Proc.results).value;
+ results = lb_type_info(m, t->Proc.results).value;
}
LLVMValueRef vals[4] = {
@@ -649,7 +642,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
// NOTE(bill): Zeroth is nil so ignore it
for (isize variant_index = 0; variant_index < variant_count; variant_index++) {
Type *vt = t->Union.variants[variant_index];
- lbValue tip = lb_get_type_info_ptr(m, vt);
+ lbValue tip = lb_type_info(m, vt);
lbValue index = lb_const_int(m, t_int, variant_index);
lbValue type_info = lb_emit_ptr_offset(p, memory_types, index);
@@ -737,7 +730,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
for (isize source_index = 0; source_index < count; source_index++) {
// TODO(bill): Order fields in source order not layout order
Entity *f = t->Struct.fields[source_index];
- lbValue tip = lb_get_type_info_ptr(m, f->type);
+ lbValue tip = lb_type_info(m, f->type);
i64 foffset = 0;
if (!t->Struct.is_raw_union) {
GB_ASSERT(t->Struct.offsets != nullptr);
@@ -794,11 +787,11 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_map_ptr);
init_map_internal_types(t);
- lbValue gst = lb_get_type_info_ptr(m, t->Map.generated_struct_type);
+ lbValue gst = lb_type_info(m, t->Map.generated_struct_type);
LLVMValueRef vals[5] = {
- lb_get_type_info_ptr(m, t->Map.key).value,
- lb_get_type_info_ptr(m, t->Map.value).value,
+ lb_type_info(m, t->Map.key).value,
+ lb_type_info(m, t->Map.value).value,
gst.value,
lb_get_equal_proc_for_type(m, t->Map.key).value,
lb_get_hasher_proc_for_type(m, t->Map.key).value
@@ -819,13 +812,13 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
LLVMValueRef vals[4] = {
- lb_get_type_info_ptr(m, t->BitSet.elem).value,
+ lb_type_info(m, t->BitSet.elem).value,
LLVMConstNull(lb_type(m, t_type_info_ptr)),
lb_const_int(m, t_i64, t->BitSet.lower).value,
lb_const_int(m, t_i64, t->BitSet.upper).value,
};
if (t->BitSet.underlying != nullptr) {
- vals[1] =lb_get_type_info_ptr(m, t->BitSet.underlying).value;
+ vals[1] =lb_type_info(m, t->BitSet.underlying).value;
}
lbValue res = {};
@@ -841,7 +834,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
LLVMValueRef vals[3] = {};
- vals[0] = lb_get_type_info_ptr(m, t->SimdVector.elem).value;
+ vals[0] = lb_type_info(m, t->SimdVector.elem).value;
vals[1] = lb_const_int(m, t_int, type_size_of(t->SimdVector.elem)).value;
vals[2] = lb_const_int(m, t_int, t->SimdVector.count).value;
@@ -856,8 +849,8 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
{
tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_relative_pointer_ptr);
LLVMValueRef vals[2] = {
- lb_get_type_info_ptr(m, t->RelativePointer.pointer_type).value,
- lb_get_type_info_ptr(m, t->RelativePointer.base_integer).value,
+ lb_type_info(m, t->RelativePointer.pointer_type).value,
+ lb_type_info(m, t->RelativePointer.base_integer).value,
};
lbValue res = {};
@@ -870,8 +863,8 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
{
tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_relative_slice_ptr);
LLVMValueRef vals[2] = {
- lb_get_type_info_ptr(m, t->RelativeSlice.slice_type).value,
- lb_get_type_info_ptr(m, t->RelativeSlice.base_integer).value,
+ lb_type_info(m, t->RelativeSlice.slice_type).value,
+ lb_type_info(m, t->RelativeSlice.base_integer).value,
};
lbValue res = {};
@@ -886,7 +879,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
i64 ez = type_size_of(t->Matrix.elem);
LLVMValueRef vals[5] = {
- lb_get_type_info_ptr(m, t->Matrix.elem).value,
+ lb_type_info(m, t->Matrix.elem).value,
lb_const_int(m, t_int, ez).value,
lb_const_int(m, t_int, matrix_type_stride_in_elems(t)).value,
lb_const_int(m, t_int, t->Matrix.row_count).value,
diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp
index 88ec2f22c..7163f1d9e 100644
--- a/src/llvm_backend_utility.cpp
+++ b/src/llvm_backend_utility.cpp
@@ -39,6 +39,13 @@ bool lb_is_type_aggregate(Type *t) {
return false;
}
+void lb_emit_unreachable(lbProcedure *p) {
+ LLVMValueRef instr = LLVMGetLastInstruction(p->curr_block->block);
+ if (instr == nullptr || !lb_is_instr_terminating(instr)) {
+ lb_call_intrinsic(p, "llvm.trap", nullptr, 0, nullptr, 0);
+ LLVMBuildUnreachable(p->builder);
+ }
+}
lbValue lb_correct_endianness(lbProcedure *p, lbValue value) {
Type *src = core_type(value.type);
@@ -73,9 +80,6 @@ LLVMValueRef lb_mem_zero_ptr_internal(lbProcedure *p, LLVMValueRef ptr, LLVMValu
lb_type(p->module, t_int)
};
if (true || is_inlinable) {
- unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
- GB_ASSERT_MSG(id != 0, "Unable to find %s.%s.%s", name, LLVMPrintTypeToString(types[0]), LLVMPrintTypeToString(types[1]));
- LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types));
LLVMValueRef args[4] = {};
args[0] = LLVMBuildPointerCast(p->builder, ptr, types[0], "");
@@ -83,16 +87,18 @@ LLVMValueRef lb_mem_zero_ptr_internal(lbProcedure *p, LLVMValueRef ptr, LLVMValu
args[2] = LLVMBuildIntCast2(p->builder, len, types[1], /*signed*/false, "");
args[3] = LLVMConstInt(LLVMInt1TypeInContext(p->module->ctx), is_volatile, false);
- return LLVMBuildCall(p->builder, ip, args, gb_count_of(args), "");
+ return lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types));
} else {
- LLVMValueRef ip = lb_lookup_runtime_procedure(p->module, str_lit("memset")).value;
+ lbValue pr = lb_lookup_runtime_procedure(p->module, str_lit("memset"));
LLVMValueRef args[3] = {};
args[0] = LLVMBuildPointerCast(p->builder, ptr, types[0], "");
args[1] = LLVMConstInt(LLVMInt32TypeInContext(p->module->ctx), 0, false);
args[2] = LLVMBuildIntCast2(p->builder, len, types[1], /*signed*/false, "");
- return LLVMBuildCall(p->builder, ip, args, gb_count_of(args), "");
+ // We always get the function pointer type rather than the function and there is apparently no way around that?
+ LLVMTypeRef type = lb_type_internal_for_procedures_raw(p->module, pr.type);
+ return LLVMBuildCall2(p->builder, type, pr.value, args, gb_count_of(args), "");
}
}
@@ -346,44 +352,65 @@ lbValue lb_emit_try_has_value(lbProcedure *p, lbValue rhs) {
lbValue lb_emit_or_else(lbProcedure *p, Ast *arg, Ast *else_expr, TypeAndValue const &tv) {
+ if (arg->state_flags & StateFlag_DirectiveWasFalse) {
+ return lb_build_expr(p, else_expr);
+ }
+
lbValue lhs = {};
lbValue rhs = {};
lb_emit_try_lhs_rhs(p, arg, tv, &lhs, &rhs);
- LLVMValueRef incoming_values[2] = {};
- LLVMBasicBlockRef incoming_blocks[2] = {};
-
GB_ASSERT(else_expr != nullptr);
- lbBlock *then = lb_create_block(p, "or_else.then");
- lbBlock *done = lb_create_block(p, "or_else.done"); // NOTE(bill): Append later
- lbBlock *else_ = lb_create_block(p, "or_else.else");
-
- lb_emit_if(p, lb_emit_try_has_value(p, rhs), then, else_);
- lb_start_block(p, then);
Type *type = default_type(tv.type);
- incoming_values[0] = lb_emit_conv(p, lhs, type).value;
+ if (is_diverging_expr(else_expr)) {
+ lbBlock *then = lb_create_block(p, "or_else.then");
+ lbBlock *else_ = lb_create_block(p, "or_else.else");
- lb_emit_jump(p, done);
- lb_start_block(p, else_);
+ lb_emit_if(p, lb_emit_try_has_value(p, rhs), then, else_);
+ // NOTE(bill): else block needs to be straight afterwards to make sure that the actual value is used
+ // from the then block
+ lb_start_block(p, else_);
- incoming_values[1] = lb_emit_conv(p, lb_build_expr(p, else_expr), type).value;
+ lb_build_expr(p, else_expr);
+ lb_emit_unreachable(p); // add just in case
- lb_emit_jump(p, done);
- lb_start_block(p, done);
+ lb_start_block(p, then);
+ return lb_emit_conv(p, lhs, type);
+ } else {
+ LLVMValueRef incoming_values[2] = {};
+ LLVMBasicBlockRef incoming_blocks[2] = {};
- lbValue res = {};
- res.value = LLVMBuildPhi(p->builder, lb_type(p->module, type), "");
- res.type = type;
+ lbBlock *then = lb_create_block(p, "or_else.then");
+ lbBlock *done = lb_create_block(p, "or_else.done"); // NOTE(bill): Append later
+ lbBlock *else_ = lb_create_block(p, "or_else.else");
- GB_ASSERT(p->curr_block->preds.count >= 2);
- incoming_blocks[0] = p->curr_block->preds[0]->block;
- incoming_blocks[1] = p->curr_block->preds[1]->block;
+ lb_emit_if(p, lb_emit_try_has_value(p, rhs), then, else_);
+ lb_start_block(p, then);
- LLVMAddIncoming(res.value, incoming_values, incoming_blocks, 2);
+ incoming_values[0] = lb_emit_conv(p, lhs, type).value;
- return res;
+ lb_emit_jump(p, done);
+ lb_start_block(p, else_);
+
+ incoming_values[1] = lb_emit_conv(p, lb_build_expr(p, else_expr), type).value;
+
+ lb_emit_jump(p, done);
+ lb_start_block(p, done);
+
+ lbValue res = {};
+ res.value = LLVMBuildPhi(p->builder, lb_type(p->module, type), "");
+ res.type = type;
+
+ GB_ASSERT(p->curr_block->preds.count >= 2);
+ incoming_blocks[0] = p->curr_block->preds[0]->block;
+ incoming_blocks[1] = p->curr_block->preds[1]->block;
+
+ LLVMAddIncoming(res.value, incoming_values, incoming_blocks, 2);
+
+ return res;
+ }
}
void lb_build_return_stmt(lbProcedure *p, Slice<Ast *> const &return_results);
@@ -460,15 +487,11 @@ lbValue lb_emit_byte_swap(lbProcedure *p, lbValue value, Type *end_type) {
char const *name = "llvm.bswap";
LLVMTypeRef types[1] = {lb_type(p->module, value.type)};
- unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
- GB_ASSERT_MSG(id != 0, "Unable to find %s.%s", name, LLVMPrintTypeToString(types[0]));
- LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types));
- LLVMValueRef args[1] = {};
- args[0] = value.value;
+ LLVMValueRef args[1] = { value.value };
lbValue res = {};
- res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), "");
+ res.value = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types));
res.type = value.type;
if (is_type_float(original_type)) {
@@ -486,15 +509,10 @@ lbValue lb_emit_count_ones(lbProcedure *p, lbValue x, Type *type) {
char const *name = "llvm.ctpop";
LLVMTypeRef types[1] = {lb_type(p->module, type)};
- unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
- GB_ASSERT_MSG(id != 0, "Unable to find %s.%s", name, LLVMPrintTypeToString(types[0]));
- LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types));
-
- LLVMValueRef args[1] = {};
- args[0] = x.value;
+ LLVMValueRef args[1] = { x.value };
lbValue res = {};
- res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), "");
+ res.value = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types));
res.type = type;
return res;
}
@@ -515,16 +533,13 @@ lbValue lb_emit_count_trailing_zeros(lbProcedure *p, lbValue x, Type *type) {
char const *name = "llvm.cttz";
LLVMTypeRef types[1] = {lb_type(p->module, type)};
- unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
- GB_ASSERT_MSG(id != 0, "Unable to find %s.%s", name, LLVMPrintTypeToString(types[0]));
- LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types));
- LLVMValueRef args[2] = {};
- args[0] = x.value;
- args[1] = LLVMConstNull(LLVMInt1TypeInContext(p->module->ctx));
+ LLVMValueRef args[2] = {
+ x.value,
+ LLVMConstNull(LLVMInt1TypeInContext(p->module->ctx)) };
lbValue res = {};
- res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), "");
+ res.value = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types));
res.type = type;
return res;
}
@@ -534,16 +549,13 @@ lbValue lb_emit_count_leading_zeros(lbProcedure *p, lbValue x, Type *type) {
char const *name = "llvm.ctlz";
LLVMTypeRef types[1] = {lb_type(p->module, type)};
- unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
- GB_ASSERT_MSG(id != 0, "Unable to find %s.%s", name, LLVMPrintTypeToString(types[0]));
- LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types));
- LLVMValueRef args[2] = {};
- args[0] = x.value;
- args[1] = LLVMConstNull(LLVMInt1TypeInContext(p->module->ctx));
+ LLVMValueRef args[2] = {
+ x.value,
+ LLVMConstNull(LLVMInt1TypeInContext(p->module->ctx)) };
lbValue res = {};
- res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), "");
+ res.value = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types));
res.type = type;
return res;
}
@@ -555,15 +567,11 @@ lbValue lb_emit_reverse_bits(lbProcedure *p, lbValue x, Type *type) {
char const *name = "llvm.bitreverse";
LLVMTypeRef types[1] = {lb_type(p->module, type)};
- unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
- GB_ASSERT_MSG(id != 0, "Unable to find %s.%s", name, LLVMPrintTypeToString(types[0]));
- LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types));
- LLVMValueRef args[1] = {};
- args[0] = x.value;
+ LLVMValueRef args[1] = { x.value };
lbValue res = {};
- res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), "");
+ res.value = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types));
res.type = type;
return res;
}
@@ -984,6 +992,11 @@ lbValue lb_emit_struct_ep(lbProcedure *p, lbValue s, i32 index) {
case 0: result_type = t->RelativeSlice.base_integer; break;
case 1: result_type = t->RelativeSlice.base_integer; break;
}
+ } else if (is_type_soa_pointer(t)) {
+ switch (index) {
+ case 0: result_type = alloc_type_pointer(t->SoaPointer.elem); break;
+ case 1: result_type = t_int; break;
+ }
} else {
GB_PANIC("TODO(bill): struct_gep type: %s, %d", type_to_string(s.type), index);
}
@@ -994,15 +1007,16 @@ lbValue lb_emit_struct_ep(lbProcedure *p, lbValue s, i32 index) {
index = lb_convert_struct_index(p->module, t, index);
if (lb_is_const(s)) {
+ // NOTE(bill): this cannot be replaced with lb_emit_epi
lbModule *m = p->module;
lbValue res = {};
LLVMValueRef indices[2] = {llvm_zero(m), LLVMConstInt(lb_type(m, t_i32), index, false)};
- res.value = LLVMConstGEP(s.value, indices, gb_count_of(indices));
+ res.value = LLVMConstGEP2(lb_type(m, type_deref(s.type)), s.value, indices, gb_count_of(indices));
res.type = alloc_type_pointer(result_type);
return res;
} else {
lbValue res = {};
- LLVMTypeRef st = LLVMGetElementType(LLVMTypeOf(s.value));
+ LLVMTypeRef st = lb_type(p->module, type_deref(s.type));
// gb_printf_err("%s\n", type_to_string(s.type));
// gb_printf_err("%s\n", LLVMPrintTypeToString(LLVMTypeOf(s.value)));
// gb_printf_err("%d\n", index);
@@ -1010,7 +1024,7 @@ lbValue lb_emit_struct_ep(lbProcedure *p, lbValue s, i32 index) {
unsigned count = LLVMCountStructElementTypes(st);
GB_ASSERT_MSG(count >= cast(unsigned)index, "%u %d %d", count, index, original_index);
- res.value = LLVMBuildStructGEP(p->builder, s.value, cast(unsigned)index, "");
+ res.value = LLVMBuildStructGEP2(p->builder, st, s.value, cast(unsigned)index, "");
res.type = alloc_type_pointer(result_type);
return res;
}
@@ -1114,6 +1128,13 @@ lbValue lb_emit_struct_ev(lbProcedure *p, lbValue s, i32 index) {
result_type = t->Array.elem;
break;
+ case Type_SoaPointer:
+ switch (index) {
+ case 0: result_type = alloc_type_pointer(t->SoaPointer.elem); break;
+ case 1: result_type = t_int; break;
+ }
+ break;
+
default:
GB_PANIC("TODO(bill): struct_ev type: %s, %d", type_to_string(s.type), index);
break;
@@ -1141,7 +1162,28 @@ lbValue lb_emit_deep_field_gep(lbProcedure *p, lbValue e, Selection sel) {
}
type = core_type(type);
- if (is_type_quaternion(type)) {
+ if (type->kind == Type_SoaPointer) {
+ lbValue addr = lb_emit_struct_ep(p, e, 0);
+ lbValue index = lb_emit_struct_ep(p, e, 1);
+ addr = lb_emit_load(p, addr);
+ index = lb_emit_load(p, index);
+
+ i32 first_index = sel.index[0];
+ Selection sub_sel = sel;
+ sub_sel.index.data += 1;
+ sub_sel.index.count -= 1;
+
+ lbValue arr = lb_emit_struct_ep(p, addr, first_index);
+
+ Type *t = base_type(type_deref(addr.type));
+ GB_ASSERT(is_type_soa_struct(t));
+
+ if (t->Struct.soa_kind == StructSoa_Fixed) {
+ e = lb_emit_array_ep(p, arr, index);
+ } else {
+ e = lb_emit_ptr_offset(p, lb_emit_load(p, arr), index);
+ }
+ } else if (is_type_quaternion(type)) {
e = lb_emit_struct_ep(p, e, index);
} else if (is_type_raw_union(type)) {
type = get_struct_field_type(type, index);
@@ -1216,7 +1258,12 @@ lbValue lb_emit_array_ep(lbProcedure *p, lbValue s, lbValue index) {
Type *ptr = base_array_type(st);
lbValue res = {};
- res.value = LLVMBuildGEP(p->builder, s.value, indices, 2, "");
+
+ if (LLVMIsConstant(s.value) && LLVMIsConstant(index.value)) {
+ res.value = LLVMConstGEP2(lb_type(p->module, st), s.value, indices, gb_count_of(indices));
+ } else {
+ res.value = LLVMBuildGEP2(p->builder, lb_type(p->module, st), s.value, indices, gb_count_of(indices), "");
+ }
res.type = alloc_type_pointer(ptr);
return res;
}
@@ -1226,24 +1273,16 @@ lbValue lb_emit_array_epi(lbProcedure *p, lbValue s, isize index) {
GB_ASSERT(is_type_pointer(t));
Type *st = base_type(type_deref(t));
GB_ASSERT_MSG(is_type_array(st) || is_type_enumerated_array(st) || is_type_matrix(st), "%s", type_to_string(st));
-
GB_ASSERT(0 <= index);
- Type *ptr = base_array_type(st);
-
-
- LLVMValueRef indices[2] = {
- LLVMConstInt(lb_type(p->module, t_int), 0, false),
- LLVMConstInt(lb_type(p->module, t_int), cast(unsigned)index, false),
- };
-
- lbValue res = {};
- if (lb_is_const(s)) {
- res.value = LLVMConstGEP(s.value, indices, gb_count_of(indices));
- } else {
- res.value = LLVMBuildGEP(p->builder, s.value, indices, gb_count_of(indices), "");
- }
- res.type = alloc_type_pointer(ptr);
- return res;
+ return lb_emit_epi(p, s, index);
+}
+lbValue lb_emit_array_epi(lbModule *m, lbValue s, isize index) {
+ Type *t = s.type;
+ GB_ASSERT(is_type_pointer(t));
+ Type *st = base_type(type_deref(t));
+ GB_ASSERT_MSG(is_type_array(st) || is_type_enumerated_array(st) || is_type_matrix(st), "%s", type_to_string(st));
+ GB_ASSERT(0 <= index);
+ return lb_emit_epi(m, s, index);
}
lbValue lb_emit_ptr_offset(lbProcedure *p, lbValue ptr, lbValue index) {
@@ -1251,11 +1290,12 @@ lbValue lb_emit_ptr_offset(lbProcedure *p, lbValue ptr, lbValue index) {
LLVMValueRef indices[1] = {index.value};
lbValue res = {};
res.type = ptr.type;
+ LLVMTypeRef type = lb_type(p->module, type_deref(res.type, true));
if (lb_is_const(ptr) && lb_is_const(index)) {
- res.value = LLVMConstGEP(ptr.value, indices, 1);
+ res.value = LLVMConstGEP2(type, ptr.value, indices, 1);
} else {
- res.value = LLVMBuildGEP(p->builder, ptr.value, indices, 1, "");
+ res.value = LLVMBuildGEP2(p->builder, type, ptr.value, indices, 1, "");
}
return res;
}
@@ -1264,63 +1304,18 @@ lbValue lb_emit_matrix_epi(lbProcedure *p, lbValue s, isize row, isize column) {
Type *t = s.type;
GB_ASSERT(is_type_pointer(t));
Type *mt = base_type(type_deref(t));
-
- Type *ptr = base_array_type(mt);
-
if (column == 0) {
GB_ASSERT_MSG(is_type_matrix(mt) || is_type_array_like(mt), "%s", type_to_string(mt));
-
- LLVMValueRef indices[2] = {
- LLVMConstInt(lb_type(p->module, t_int), 0, false),
- LLVMConstInt(lb_type(p->module, t_int), cast(unsigned)row, false),
- };
-
- lbValue res = {};
- if (lb_is_const(s)) {
- res.value = LLVMConstGEP(s.value, indices, gb_count_of(indices));
- } else {
- res.value = LLVMBuildGEP(p->builder, s.value, indices, gb_count_of(indices), "");
- }
-
- Type *ptr = base_array_type(mt);
- res.type = alloc_type_pointer(ptr);
- return res;
+ return lb_emit_epi(p, s, row);
} else if (row == 0 && is_type_array_like(mt)) {
- LLVMValueRef indices[2] = {
- LLVMConstInt(lb_type(p->module, t_int), 0, false),
- LLVMConstInt(lb_type(p->module, t_int), cast(unsigned)column, false),
- };
-
- lbValue res = {};
- if (lb_is_const(s)) {
- res.value = LLVMConstGEP(s.value, indices, gb_count_of(indices));
- } else {
- res.value = LLVMBuildGEP(p->builder, s.value, indices, gb_count_of(indices), "");
- }
-
- Type *ptr = base_array_type(mt);
- res.type = alloc_type_pointer(ptr);
- return res;
+ return lb_emit_epi(p, s, column);
}
GB_ASSERT_MSG(is_type_matrix(mt), "%s", type_to_string(mt));
isize offset = matrix_indices_to_offset(mt, row, column);
-
- LLVMValueRef indices[2] = {
- LLVMConstInt(lb_type(p->module, t_int), 0, false),
- LLVMConstInt(lb_type(p->module, t_int), cast(unsigned)offset, false),
- };
-
- lbValue res = {};
- if (lb_is_const(s)) {
- res.value = LLVMConstGEP(s.value, indices, gb_count_of(indices));
- } else {
- res.value = LLVMBuildGEP(p->builder, s.value, indices, gb_count_of(indices), "");
- }
- res.type = alloc_type_pointer(ptr);
- return res;
+ return lb_emit_epi(p, s, offset);
}
lbValue lb_emit_matrix_ep(lbProcedure *p, lbValue s, lbValue row, lbValue column) {
@@ -1343,11 +1338,12 @@ lbValue lb_emit_matrix_ep(lbProcedure *p, lbValue s, lbValue row, lbValue column
index,
};
+ LLVMTypeRef type = lb_type(p->module, mt);
lbValue res = {};
if (lb_is_const(s)) {
- res.value = LLVMConstGEP(s.value, indices, gb_count_of(indices));
+ res.value = LLVMConstGEP2(type, s.value, indices, gb_count_of(indices));
} else {
- res.value = LLVMBuildGEP(p->builder, s.value, indices, gb_count_of(indices), "");
+ res.value = LLVMBuildGEP2(p->builder, type, s.value, indices, gb_count_of(indices), "");
}
res.type = alloc_type_pointer(ptr);
return res;
@@ -1551,18 +1547,12 @@ lbValue lb_emit_mul_add(lbProcedure *p, lbValue a, lbValue b, lbValue c, Type *t
if (is_possible) {
char const *name = "llvm.fma";
- unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
- GB_ASSERT_MSG(id != 0, "Unable to find %s", name);
-
- LLVMTypeRef types[1] = {};
- types[0] = lb_type(m, t);
-
- LLVMValueRef ip = LLVMGetIntrinsicDeclaration(m->mod, id, types, gb_count_of(types));
- LLVMValueRef values[3] = {};
- values[0] = a.value;
- values[1] = b.value;
- values[2] = c.value;
- LLVMValueRef call = LLVMBuildCall(p->builder, ip, values, gb_count_of(values), "");
+ LLVMTypeRef types[1] = { lb_type(m, t) };
+ LLVMValueRef values[3] = {
+ a.value,
+ b.value,
+ c.value };
+ LLVMValueRef call = lb_call_intrinsic(p, name, values, gb_count_of(values), types, gb_count_of(types));
return {call, t};
} else {
lbValue x = lb_emit_arith(p, Token_Mul, a, b, t);
@@ -1661,7 +1651,7 @@ LLVMValueRef llvm_vector_expand_to_power_of_two(lbProcedure *p, LLVMValueRef val
LLVMValueRef llvm_vector_reduce_add(lbProcedure *p, LLVMValueRef value) {
LLVMTypeRef type = LLVMTypeOf(value);
GB_ASSERT(LLVMGetTypeKind(type) == LLVMVectorTypeKind);
- LLVMTypeRef elem = LLVMGetElementType(type);
+ LLVMTypeRef elem = OdinLLVMGetVectorElementType(type);
unsigned len = LLVMGetVectorSize(type);
if (len == 0) {
return LLVMConstNull(type);
@@ -1691,15 +1681,9 @@ LLVMValueRef llvm_vector_reduce_add(lbProcedure *p, LLVMValueRef value) {
unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
if (id != 0 && false) {
- LLVMTypeRef types[1] = {};
- types[0] = type;
-
- LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types));
- LLVMValueRef values[2] = {};
- values[0] = LLVMConstNull(elem);
- values[1] = value;
- LLVMValueRef call = LLVMBuildCall(p->builder, ip, values+value_offset, value_count, "");
- return call;
+ LLVMTypeRef types[1] = { type };
+ LLVMValueRef values[2] = { LLVMConstNull(elem), value };
+ return lb_call_intrinsic(p, name, values + value_offset, value_count, types, gb_count_of(types));
}
// Manual reduce
@@ -1743,7 +1727,7 @@ LLVMValueRef llvm_vector_reduce_add(lbProcedure *p, LLVMValueRef value) {
LLVMValueRef llvm_vector_add(lbProcedure *p, LLVMValueRef a, LLVMValueRef b) {
GB_ASSERT(LLVMTypeOf(a) == LLVMTypeOf(b));
- LLVMTypeRef elem = LLVMGetElementType(LLVMTypeOf(a));
+ LLVMTypeRef elem = OdinLLVMGetVectorElementType(LLVMTypeOf(a));
if (LLVMGetTypeKind(elem) == LLVMIntegerTypeKind) {
return LLVMBuildAdd(p->builder, a, b, "");
@@ -1754,7 +1738,7 @@ LLVMValueRef llvm_vector_add(lbProcedure *p, LLVMValueRef a, LLVMValueRef b) {
LLVMValueRef llvm_vector_mul(lbProcedure *p, LLVMValueRef a, LLVMValueRef b) {
GB_ASSERT(LLVMTypeOf(a) == LLVMTypeOf(b));
- LLVMTypeRef elem = LLVMGetElementType(LLVMTypeOf(a));
+ LLVMTypeRef elem = OdinLLVMGetVectorElementType(LLVMTypeOf(a));
if (LLVMGetTypeKind(elem) == LLVMIntegerTypeKind) {
return LLVMBuildMul(p->builder, a, b, "");
@@ -1768,14 +1752,13 @@ LLVMValueRef llvm_vector_dot(lbProcedure *p, LLVMValueRef a, LLVMValueRef b) {
}
LLVMValueRef llvm_vector_mul_add(lbProcedure *p, LLVMValueRef a, LLVMValueRef b, LLVMValueRef c) {
- lbModule *m = p->module;
-
+
LLVMTypeRef t = LLVMTypeOf(a);
GB_ASSERT(t == LLVMTypeOf(b));
GB_ASSERT(t == LLVMTypeOf(c));
GB_ASSERT(LLVMGetTypeKind(t) == LLVMVectorTypeKind);
- LLVMTypeRef elem = LLVMGetElementType(t);
+ LLVMTypeRef elem = OdinLLVMGetVectorElementType(t);
bool is_possible = false;
@@ -1791,18 +1774,9 @@ LLVMValueRef llvm_vector_mul_add(lbProcedure *p, LLVMValueRef a, LLVMValueRef b,
if (is_possible) {
char const *name = "llvm.fmuladd";
- unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
- GB_ASSERT_MSG(id != 0, "Unable to find %s", name);
-
- LLVMTypeRef types[1] = {};
- types[0] = t;
-
- LLVMValueRef ip = LLVMGetIntrinsicDeclaration(m->mod, id, types, gb_count_of(types));
- LLVMValueRef values[3] = {};
- values[0] = a;
- values[1] = b;
- values[2] = c;
- LLVMValueRef call = LLVMBuildCall(p->builder, ip, values, gb_count_of(values), "");
+ LLVMTypeRef types[1] = { t };
+ LLVMValueRef values[3] = { a, b, c};
+ LLVMValueRef call = lb_call_intrinsic(p, name, values, gb_count_of(values), types, gb_count_of(types));
return call;
} else {
LLVMValueRef x = llvm_vector_mul(p, a, b);
@@ -1817,7 +1791,7 @@ LLVMValueRef llvm_get_inline_asm(LLVMTypeRef func_type, String const &str, Strin
cast(char *)clobbers.text, cast(size_t)clobbers.len,
has_side_effects, is_align_stack,
dialect
- #if LLVM_VERSION_MAJOR >= 13
+ #if LLVM_VERSION_MAJOR >= 13
, /*CanThrow*/false
#endif
);
diff --git a/src/main.cpp b/src/main.cpp
index beefec702..ef1b8dda1 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -283,6 +283,9 @@ i32 linker_stage(lbGenerator *gen) {
String vs_exe_path = path_to_string(heap_allocator(), build_context.build_paths[BuildPath_VS_EXE]);
defer (gb_free(heap_allocator(), vs_exe_path.text));
+ String windows_sdk_bin_path = path_to_string(heap_allocator(), build_context.build_paths[BuildPath_Win_SDK_Bin_Path]);
+ defer (gb_free(heap_allocator(), windows_sdk_bin_path.text));
+
char const *subsystem_str = build_context.use_subsystem_windows ? "WINDOWS" : "CONSOLE";
if (!build_context.use_lld) { // msvc
if (build_context.has_resource) {
@@ -292,7 +295,8 @@ i32 linker_stage(lbGenerator *gen) {
defer (gb_free(heap_allocator(), res_path.text));
result = system_exec_command_line_app("msvc-link",
- "\"rc.exe\" /nologo /fo \"%.*s\" \"%.*s\"",
+ "\"%.*src.exe\" /nologo /fo \"%.*s\" \"%.*s\"",
+ LIT(windows_sdk_bin_path),
LIT(res_path),
LIT(rc_path)
);
@@ -1558,7 +1562,7 @@ bool parse_build_flags(Array<String> args) {
bad_flags = true;
break;
}
- build_context.resource_filepath = substring(path, 0, string_extension_position(path));
+ build_context.resource_filepath = path;
build_context.has_resource = true;
} else {
gb_printf_err("Invalid -resource path, got %.*s\n", LIT(path));
diff --git a/src/microsoft_craziness.h b/src/microsoft_craziness.h
index 812513875..7d23f2557 100644
--- a/src/microsoft_craziness.h
+++ b/src/microsoft_craziness.h
@@ -50,18 +50,7 @@ gb_global gbAllocator mc_allocator = heap_allocator();
struct Find_Result {
int windows_sdk_version; // Zero if no Windows SDK found.
- wchar_t const *windows_sdk_root;
- wchar_t const *windows_sdk_um_library_path;
- wchar_t const *windows_sdk_ucrt_library_path;
-
- wchar_t const *vs_exe_path;
- wchar_t const *vs_library_path;
-};
-
-struct Find_Result_Utf8 {
- int windows_sdk_version; // Zero if no Windows SDK found.
-
- String windows_sdk_root;
+ String windows_sdk_bin_path;
String windows_sdk_um_library_path;
String windows_sdk_ucrt_library_path;
@@ -69,8 +58,6 @@ struct Find_Result_Utf8 {
String vs_library_path;
};
-Find_Result_Utf8 find_visual_studio_and_windows_sdk_utf8();
-
String mc_wstring_to_string(wchar_t const *str) {
return string16_to_string(mc_allocator, make_string16_c(str));
}
@@ -87,6 +74,10 @@ String mc_concat(String a, String b, String c) {
return concatenate3_strings(mc_allocator, a, b, c);
}
+String mc_concat(String a, String b, String c, String d) {
+ return concatenate4_strings(mc_allocator, a, b, c, d);
+}
+
String mc_get_env(String key) {
char const * value = gb_get_env((char const *)key.text, mc_allocator);
return make_string_c(value);
@@ -219,19 +210,19 @@ struct DECLSPEC_UUID("42843719-DB4C-46C2-8E7C-64F1816EFD5B") DECLSPEC_NOVTABLE I
// The beginning of the actual code that does things.
-struct Version_Data_Utf8 {
- i32 best_version[4]; // For Windows 8 versions, only two of these numbers are used.
+struct Version_Data {
+ i32 best_version[4];
String best_name;
};
-typedef void (*MC_Visit_Proc)(String short_name, String full_name, Version_Data_Utf8 *data);
-bool mc_visit_files(String dir_name, Version_Data_Utf8 *data, MC_Visit_Proc proc) {
+typedef void (*MC_Visit_Proc)(String short_name, String full_name, Version_Data *data);
+bool mc_visit_files(String dir_name, Version_Data *data, MC_Visit_Proc proc) {
// Visit everything in one folder (non-recursively). If it's a directory
// that doesn't start with ".", call the visit proc on it. The visit proc
// will see if the filename conforms to the expected versioning pattern.
- String wildcard_name = mc_concat(dir_name, str_lit("\\*"));
+ String wildcard_name = mc_concat(dir_name, str_lit("*"));
defer (mc_free(wildcard_name));
MC_Find_Data find_data;
@@ -242,7 +233,7 @@ bool mc_visit_files(String dir_name, Version_Data_Utf8 *data, MC_Visit_Proc proc
bool success = true;
while (success) {
if ((find_data.file_attributes & FILE_ATTRIBUTE_DIRECTORY) && (find_data.filename[0] != '.')) {
- String full_name = mc_concat(dir_name, str_lit("\\"), find_data.filename);
+ String full_name = mc_concat(dir_name, find_data.filename);
defer (mc_free(full_name));
proc(find_data.filename, full_name, data);
@@ -284,7 +275,7 @@ String find_windows_kit_root(HKEY key, String const version) {
return value;
}
-void win10_best(String short_name, String full_name, Version_Data_Utf8 *data) {
+void win10_best(String short_name, String full_name, Version_Data *data) {
// Find the Windows 10 subdirectory with the highest version number.
int i0, i1, i2, i3;
@@ -304,11 +295,11 @@ void win10_best(String short_name, String full_name, Version_Data_Utf8 *data) {
// we have to copy_string and free here because visit_files free's the full_name string
// after we execute this function, so Win*_Data would contain an invalid pointer.
- if (data->best_name.len > 0) mc_free(data->best_name);
+ if (data->best_name.len) mc_free(data->best_name);
data->best_name = copy_string(mc_allocator, full_name);
- if (data->best_name.len > 0) {
+ if (data->best_name.len) {
data->best_version[0] = i0;
data->best_version[1] = i1;
data->best_version[2] = i2;
@@ -316,34 +307,8 @@ void win10_best(String short_name, String full_name, Version_Data_Utf8 *data) {
}
}
-void win8_best(String short_name, String full_name, Version_Data_Utf8 *data) {
- // Find the Windows 8 subdirectory with the highest version number.
-
- int i0, i1;
- auto success = sscanf_s((const char *const)short_name.text, "winv%d.%d", &i0, &i1);
- if (success < 2) return;
-
- if (i0 < data->best_version[0]) return;
- else if (i0 == data->best_version[0]) {
- if (i1 < data->best_version[1]) return;
- }
-
- // we have to copy_string and free here because visit_files free's the full_name string
- // after we execute this function, so Win*_Data would contain an invalid pointer.
- if (data->best_name.len > 0) mc_free(data->best_name);
- data->best_name = copy_string(mc_allocator, full_name);
-
- if (data->best_name.len > 0) {
- data->best_version[0] = i0;
- data->best_version[1] = i1;
- }
-}
-
-void find_windows_kit_root(Find_Result_Utf8 *result) {
- // Information about the Windows 10 and Windows 8 development kits
- // is stored in the same place in the registry. We open a key
- // to that place, first checking preferntially for a Windows 10 kit,
- // then, if that's not found, a Windows 8 kit.
+void find_windows_kit_paths(Find_Result *result) {
+ bool sdk_found = false;
HKEY main_key;
@@ -355,44 +320,42 @@ void find_windows_kit_root(Find_Result_Utf8 *result) {
// Look for a Windows 10 entry.
String windows10_root = find_windows_kit_root(main_key, str_lit("KitsRoot10"));
- if (windows10_root.len > 0) {
+ if (windows10_root.len) {
defer (mc_free(windows10_root));
- String windows10_lib = mc_concat(windows10_root, str_lit("Lib"));
+ String windows10_lib = mc_concat(windows10_root, str_lit("Lib\\"));
+ Version_Data data_lib = {0};
+ mc_visit_files(windows10_lib, &data_lib, win10_best);
defer (mc_free(windows10_lib));
+ defer (mc_free(data_lib.best_name));
+
+ String windows10_bin = mc_concat(windows10_root, str_lit("bin\\"));
+ Version_Data data_bin = {0};
+ mc_visit_files(windows10_bin, &data_bin, win10_best);
+ defer (mc_free(windows10_bin));
+ defer (mc_free(data_bin.best_name));
- Version_Data_Utf8 data = {0};
- mc_visit_files(windows10_lib, &data, win10_best);
- if (data.best_name.len > 0) {
- result->windows_sdk_version = 10;
- result->windows_sdk_root = mc_concat(data.best_name, str_lit("\\"));
- return;
+ if (data_lib.best_name.len && data_bin.best_name.len) {
+ if (build_context.metrics.arch == TargetArch_amd64) {
+ result->windows_sdk_um_library_path = mc_concat(data_lib.best_name, str_lit("\\um\\x64\\"));
+ result->windows_sdk_ucrt_library_path = mc_concat(data_lib.best_name, str_lit("\\ucrt\\x64\\"));
+ result->windows_sdk_bin_path = mc_concat(data_bin.best_name, str_lit("\\x64\\"));
+ sdk_found = true;
+ } else if (build_context.metrics.arch == TargetArch_i386) {
+ result->windows_sdk_um_library_path = mc_concat(data_lib.best_name, str_lit("\\um\\x86\\"));
+ result->windows_sdk_ucrt_library_path = mc_concat(data_lib.best_name, str_lit("\\ucrt\\x86\\"));
+ result->windows_sdk_bin_path = mc_concat(data_bin.best_name, str_lit("\\x86\\"));
+ sdk_found = true;
+ }
}
- mc_free(data.best_name);
}
- // Look for a Windows 8 entry.
- String windows8_root = find_windows_kit_root(main_key, str_lit("KitsRoot81"));
-
- if (windows8_root.len > 0) {
- defer (mc_free(windows8_root));
-
- String windows8_lib = mc_concat(windows8_root, str_lit("Lib"));
- defer (mc_free(windows8_lib));
-
- Version_Data_Utf8 data = {0};
- mc_visit_files(windows8_lib, &data, win8_best);
- if (data.best_name.len > 0) {
- result->windows_sdk_version = 8;
- result->windows_sdk_root = mc_concat(data.best_name, str_lit("\\"));
- return;
- }
- mc_free(data.best_name);
+ if (sdk_found) {
+ result->windows_sdk_version = 10;
}
- // If we get here, we failed to find anything.
}
-bool find_visual_studio_by_fighting_through_microsoft_craziness(Find_Result_Utf8 *result) {
+bool find_visual_studio_by_fighting_through_microsoft_craziness(Find_Result *result) {
// The name of this procedure is kind of cryptic. Its purpose is
// to fight through Microsoft craziness. The things that the fine
// Visual Studio team want you to do, JUST TO FIND A SINGLE FOLDER
@@ -555,54 +518,97 @@ bool find_visual_studio_by_fighting_through_microsoft_craziness(Find_Result_Utf8
}
// NOTE(WalterPlinge): Environment variables can help to find Visual C++ and WinSDK paths for both
-// official and portable installations (like mmozeiko's portable msvc script). This will only use
-// the first paths it finds, and won't overwrite any values that `result` already has.
-bool find_msvc_install_from_env_vars(Find_Result_Utf8 *result) {
+// official and portable installations (like mmozeiko's portable msvc script).
+void find_windows_kit_paths_from_env_vars(Find_Result *result) {
if (build_context.metrics.arch != TargetArch_amd64 && build_context.metrics.arch != TargetArch_i386) {
- return false;
+ return;
}
- // We can find windows sdk using the following combination of env vars:
- // (UniversalCRTSdkDir or WindowsSdkDir) and (WindowsSDKLibVersion or WindowsSDKVersion)
- bool sdk_found = false;
+ // We can find windows sdk lib dir using the following combination of env vars:
+ // (WindowsSdkDir or UniversalCRTSdkDir) and (WindowsSDKVersion or WindowsSDKLibVersion)
+ bool sdk_lib_found = false;
+
+ // We can find windows sdk bin dir using the following combination of env vars:
+ // (WindowsSdkVerBinPath) or ((WindowsSdkBinPath or WindowsSdkDir or UniversalCRTSdkDir) and (WindowsSDKVersion || WindowsSDKLibVersion))
+ bool sdk_bin_found = false;
// These appear to be suitable env vars used by Visual Studio
String win_sdk_ver_env = mc_get_env(str_lit("WindowsSDKVersion"));
- String win_sdk_lib_env = mc_get_env(str_lit("WindowsSDKLibVersion"));
+ String win_sdk_lib_ver_env = mc_get_env(str_lit("WindowsSDKLibVersion"));
String win_sdk_dir_env = mc_get_env(str_lit("WindowsSdkDir"));
String crt_sdk_dir_env = mc_get_env(str_lit("UniversalCRTSdkDir"));
+ String win_sdk_bin_path_env = mc_get_env(str_lit("WindowsSdkBinPath"));
+ String win_sdk_ver_bin_path_env = mc_get_env(str_lit("WindowsSdkVerBinPath"));
defer ({
mc_free(win_sdk_ver_env);
- mc_free(win_sdk_lib_env);
+ mc_free(win_sdk_lib_ver_env);
mc_free(win_sdk_dir_env);
mc_free(crt_sdk_dir_env);
+ mc_free(win_sdk_bin_path_env);
+ mc_free(win_sdk_ver_bin_path_env);
});
+ if (win_sdk_ver_bin_path_env.len || ((win_sdk_bin_path_env.len || win_sdk_dir_env.len || crt_sdk_dir_env.len) && (win_sdk_ver_env.len || win_sdk_lib_ver_env.len))) {
+ String bin;
+ defer (mc_free(bin));
+
+ if (win_sdk_ver_bin_path_env.len) {
+ String dir = win_sdk_ver_bin_path_env;
+
+ // Add trailing '\' in case it was missing
+ bin = mc_concat(dir, dir[dir.len - 1] != '\\' ? str_lit("\\") : str_lit(""));
+ } else {
+ String dir = win_sdk_bin_path_env.len ? win_sdk_bin_path_env : win_sdk_dir_env.len ? win_sdk_dir_env : crt_sdk_dir_env;
+ String ver = win_sdk_ver_env.len ? win_sdk_ver_env : win_sdk_lib_ver_env;
+
+ // Add trailing '\' in case it was missing
+ dir = mc_concat(dir, dir[dir.len - 1] != '\\' ? str_lit("\\") : str_lit(""));
+ ver = mc_concat(ver, ver[ver.len - 1] != '\\' ? str_lit("\\") : str_lit(""));
+ defer (mc_free(dir));
+ defer (mc_free(ver));
+
+ // Append "bin" for win_sdk_dir_env and crt_sdk_dir_env
+ String dir_bin = mc_concat(dir, win_sdk_bin_path_env.len ? str_lit("") : str_lit("bin\\"));
+ defer (mc_free(dir_bin));
+
+ bin = mc_concat(dir_bin, ver);
+ }
+
+ if (build_context.metrics.arch == TargetArch_amd64) {
+ result->windows_sdk_bin_path = mc_concat(bin, str_lit("x64\\"));
+ sdk_bin_found = true;
+ } else if (build_context.metrics.arch == TargetArch_i386) {
+ result->windows_sdk_bin_path = mc_concat(bin, str_lit("x86\\"));
+ sdk_bin_found = true;
+ }
+ }
+
// NOTE(WalterPlinge): If any combination is found, let's just assume they are correct
- if ((win_sdk_ver_env.len || win_sdk_lib_env.len) && (win_sdk_dir_env.len || crt_sdk_dir_env.len)) {
- //? Maybe we need to handle missing '\' at end of strings, so far it doesn't seem an issue
+ if ((win_sdk_ver_env.len || win_sdk_lib_ver_env.len) && (win_sdk_dir_env.len || crt_sdk_dir_env.len)) {
String dir = win_sdk_dir_env.len ? win_sdk_dir_env : crt_sdk_dir_env;
- String ver = win_sdk_ver_env.len ? win_sdk_ver_env : win_sdk_lib_env;
-
- // These have trailing '\' as we are just composing the path
- String um_dir = build_context.metrics.arch == TargetArch_amd64
- ? str_lit("um\\x64\\")
- : str_lit("um\\x86\\");
- String ucrt_dir = build_context.metrics.arch == TargetArch_amd64
- ? str_lit("ucrt\\x64\\")
- : str_lit("ucrt\\x86\\");
+ String ver = win_sdk_ver_env.len ? win_sdk_ver_env : win_sdk_lib_ver_env;
- result->windows_sdk_root = mc_concat(dir, str_lit("Lib\\"), ver);
- result->windows_sdk_um_library_path = mc_concat(result->windows_sdk_root, um_dir);
- result->windows_sdk_ucrt_library_path = mc_concat(result->windows_sdk_root, ucrt_dir);
+ // Add trailing '\' in case it was missing
+ dir = mc_concat(dir, dir[dir.len - 1] != '\\' ? str_lit("\\") : str_lit(""));
+ ver = mc_concat(ver, ver[ver.len - 1] != '\\' ? str_lit("\\") : str_lit(""));
+ defer (mc_free(dir));
+ defer (mc_free(ver));
- sdk_found = true;
+ if (build_context.metrics.arch == TargetArch_amd64) {
+ result->windows_sdk_um_library_path = mc_concat(dir, str_lit("Lib\\"), ver, str_lit("um\\x64\\"));
+ result->windows_sdk_ucrt_library_path = mc_concat(dir, str_lit("Lib\\"), ver, str_lit("ucrt\\x64\\"));
+ sdk_lib_found = true;
+ } else if (build_context.metrics.arch == TargetArch_i386) {
+ result->windows_sdk_um_library_path = mc_concat(dir, str_lit("Lib\\"), ver, str_lit("um\\x86\\"));
+ result->windows_sdk_ucrt_library_path = mc_concat(dir, str_lit("Lib\\"), ver, str_lit("ucrt\\x86\\"));
+ sdk_lib_found = true;
+ }
}
// If we haven't found it yet, we can loop through LIB for specific folders
//? This may not be robust enough using `um\x64` and `ucrt\x64`
- if (!sdk_found) {
+ if (!sdk_lib_found) {
String lib = mc_get_env(str_lit("LIB"));
defer (mc_free(lib));
@@ -624,38 +630,30 @@ bool find_msvc_install_from_env_vars(Find_Result_Utf8 *result) {
continue;
}
hi = c;
- String dir = substring(lib, lo, hi);
defer (lo = hi + 1);
+ // Skip when there are two ;; in a row
+ if (lo == hi) {
+ continue;
+ }
+
+ String dir = substring(lib, lo, hi);
+
// Remove the last slash so we can match with the strings above
String end = dir[dir.len - 1] == '\\'
? substring(dir, 0, dir.len - 1)
: substring(dir, 0, dir.len);
- // Find one and we can make the other
if (string_ends_with(end, um_dir)) {
- result->windows_sdk_um_library_path = mc_concat(end, str_lit("\\"));
- break;
+ result->windows_sdk_um_library_path = mc_concat(end, str_lit("\\"));
} else if (string_ends_with(end, ucrt_dir)) {
result->windows_sdk_ucrt_library_path = mc_concat(end, str_lit("\\"));
- break;
}
- }
-
- // Get the root from the one we found, and make the other
- // NOTE(WalterPlinge): we need to copy the string so that we don't risk a double free
- if (result->windows_sdk_um_library_path.len > 0) {
- String root = substring(result->windows_sdk_um_library_path, 0, result->windows_sdk_um_library_path.len - 1 - um_dir.len);
- result->windows_sdk_root = copy_string(mc_allocator, root);
- result->windows_sdk_ucrt_library_path = mc_concat(result->windows_sdk_root, ucrt_dir, str_lit("\\"));
- } else if (result->windows_sdk_ucrt_library_path.len > 0) {
- String root = substring(result->windows_sdk_ucrt_library_path, 0, result->windows_sdk_ucrt_library_path.len - 1 - ucrt_dir.len);
- result->windows_sdk_root = copy_string(mc_allocator, root);
- result->windows_sdk_um_library_path = mc_concat(result->windows_sdk_root, um_dir, str_lit("\\"));
- }
- if (result->windows_sdk_root.len > 0) {
- sdk_found = true;
+ if (result->windows_sdk_um_library_path.len && result->windows_sdk_ucrt_library_path.len) {
+ sdk_lib_found = true;
+ break;
+ }
}
}
}
@@ -663,33 +661,36 @@ bool find_msvc_install_from_env_vars(Find_Result_Utf8 *result) {
// NOTE(WalterPlinge): So far this function assumes it will only be called if MSVC was
// installed using mmozeiko's portable msvc script, which uses the windows 10 sdk.
// This may need to be changed later if it ends up causing problems.
- if (sdk_found && result->windows_sdk_version == 0) {
+ if (sdk_bin_found && sdk_lib_found) {
result->windows_sdk_version = 10;
}
+}
- bool vs_found = false;
-
- if (result->vs_exe_path.len > 0 && result->vs_library_path.len > 0) {
- vs_found = true;
+// NOTE(WalterPlinge): Environment variables can help to find Visual C++ and WinSDK paths for both
+// official and portable installations (like mmozeiko's portable msvc script). This will only use
+// the first paths it finds, and won't overwrite any values that `result` already has.
+void find_visual_studio_paths_from_env_vars(Find_Result *result) {
+ if (build_context.metrics.arch != TargetArch_amd64 && build_context.metrics.arch != TargetArch_i386) {
+ return;
}
- // We can find visual studio using VCToolsInstallDir
- if (!vs_found) {
- String vctid = mc_get_env(str_lit("VCToolsInstallDir"));
- defer (mc_free(vctid));
-
- if (vctid.len) {
- String exe = build_context.metrics.arch == TargetArch_amd64
- ? str_lit("bin\\Hostx64\\x64\\")
- : str_lit("bin\\Hostx86\\x86\\");
- String lib = build_context.metrics.arch == TargetArch_amd64
- ? str_lit("lib\\x64\\")
- : str_lit("lib\\x86\\");
+ bool vs_found = false;
- result->vs_exe_path = mc_concat(vctid, exe);
- result->vs_library_path = mc_concat(vctid, lib);
- vs_found = true;
- }
+ // We can find visual studio using VCToolsInstallDir
+ String vctid = mc_get_env(str_lit("VCToolsInstallDir"));
+ defer (mc_free(vctid));
+
+ if (vctid.len) {
+ String exe = build_context.metrics.arch == TargetArch_amd64
+ ? str_lit("bin\\Hostx64\\x64\\")
+ : str_lit("bin\\Hostx86\\x86\\");
+ String lib = build_context.metrics.arch == TargetArch_amd64
+ ? str_lit("lib\\x64\\")
+ : str_lit("lib\\x86\\");
+
+ result->vs_exe_path = mc_concat(vctid, exe);
+ result->vs_library_path = mc_concat(vctid, lib);
+ vs_found = true;
}
// If we haven't found it yet, we can loop through Path for specific folders
@@ -701,21 +702,32 @@ bool find_msvc_install_from_env_vars(Find_Result_Utf8 *result) {
String exe = build_context.metrics.arch == TargetArch_amd64
? str_lit("bin\\Hostx64\\x64")
: str_lit("bin\\Hostx86\\x86");
+ // The environment variable may have an uppercase X even though the folder is lowercase
+ String exe2 = build_context.metrics.arch == TargetArch_amd64
+ ? str_lit("bin\\HostX64\\x64")
+ : str_lit("bin\\HostX86\\x86");
String lib = build_context.metrics.arch == TargetArch_amd64
? str_lit("lib\\x64")
: str_lit("lib\\x86");
isize lo = {0};
isize hi = {0};
- for (isize c = 0; c < path.len; c += 1) {
- if (path[c] != ';') {
+ for (isize c = 0; c <= path.len; c += 1) {
+ if (c != path.len && path[c] != ';') {
continue;
}
hi = c;
- String dir = substring(path, lo, hi);
defer (lo = hi + 1);
+ // Skip when there are two ;; in a row
+ if (lo == hi) {
+ continue;
+ }
+
+ String dir = substring(path, lo, hi);
+
+ // Remove the last slash so we can match with the strings above
String end = dir[dir.len - 1] == '\\'
? substring(dir, 0, dir.len - 1)
: substring(dir, 0, dir.len);
@@ -726,7 +738,10 @@ bool find_msvc_install_from_env_vars(Find_Result_Utf8 *result) {
defer (mc_free(cl));
defer (mc_free(link));
- if (!string_ends_with(end, exe) || !gb_file_exists((char *)cl.text) || !gb_file_exists((char *)link.text)) {
+ if (!string_ends_with(end, exe) && !string_ends_with(end, exe2)) {
+ continue;
+ }
+ if (!gb_file_exists((char *)cl.text) || !gb_file_exists((char *)link.text)) {
continue;
}
@@ -735,42 +750,36 @@ bool find_msvc_install_from_env_vars(Find_Result_Utf8 *result) {
result->vs_library_path = mc_concat(root, lib, str_lit("\\"));
vs_found = true;
+ break;
}
}
}
-
- return sdk_found && vs_found;
}
-Find_Result_Utf8 find_visual_studio_and_windows_sdk_utf8() {
- Find_Result_Utf8 r = {};
- find_windows_kit_root(&r);
+Find_Result find_visual_studio_and_windows_sdk() {
+ Find_Result r = {};
+ find_windows_kit_paths(&r);
+ find_visual_studio_by_fighting_through_microsoft_craziness(&r);
- if (r.windows_sdk_root.len > 0) {
- if (build_context.metrics.arch == TargetArch_amd64) {
- r.windows_sdk_um_library_path = mc_concat(r.windows_sdk_root, str_lit("um\\x64\\"));
- r.windows_sdk_ucrt_library_path = mc_concat(r.windows_sdk_root, str_lit("ucrt\\x64\\"));
- } else if (build_context.metrics.arch == TargetArch_i386) {
- r.windows_sdk_um_library_path = mc_concat(r.windows_sdk_root, str_lit("um\\x86\\"));
- r.windows_sdk_ucrt_library_path = mc_concat(r.windows_sdk_root, str_lit("ucrt\\x86\\"));
- }
- }
+ bool sdk_found =
+ r.windows_sdk_bin_path.len &&
+ r.windows_sdk_um_library_path.len &&
+ r.windows_sdk_ucrt_library_path.len ;
- find_visual_studio_by_fighting_through_microsoft_craziness(&r);
+ bool vs_found =
+ r.vs_exe_path.len &&
+ r.vs_library_path.len ;
- bool all_found =
- r.windows_sdk_root.len > 0 &&
- r.windows_sdk_um_library_path.len > 0 &&
- r.windows_sdk_ucrt_library_path.len > 0 &&
- r.vs_exe_path.len > 0 &&
- r.vs_library_path.len > 0;
+ if (!sdk_found) {
+ find_windows_kit_paths_from_env_vars(&r);
+ }
- if (!all_found) {
- find_msvc_install_from_env_vars(&r);
+ if (!vs_found) {
+ find_visual_studio_paths_from_env_vars(&r);
}
#if 0
- printf("windows_sdk_root: %.*s\n", LIT(r.windows_sdk_root));
+ printf("windows_sdk_bin_path: %.*s\n", LIT(r.windows_sdk_bin_path));
printf("windows_sdk_um_library_path: %.*s\n", LIT(r.windows_sdk_um_library_path));
printf("windows_sdk_ucrt_library_path: %.*s\n", LIT(r.windows_sdk_ucrt_library_path));
printf("vs_exe_path: %.*s\n", LIT(r.vs_exe_path));
diff --git a/src/parser.cpp b/src/parser.cpp
index 247255ce8..9a5531289 100644
--- a/src/parser.cpp
+++ b/src/parser.cpp
@@ -356,6 +356,7 @@ Ast *clone_ast(Ast *node) {
break;
case Ast_PointerType:
n->PointerType.type = clone_ast(n->PointerType.type);
+ n->PointerType.tag = clone_ast(n->PointerType.tag);
break;
case Ast_MultiPointerType:
n->MultiPointerType.type = clone_ast(n->MultiPointerType.type);
@@ -2167,10 +2168,11 @@ Ast *parse_operand(AstFile *f, bool lhs) {
Ast *original_type = parse_type(f);
Ast *type = unparen_expr(original_type);
switch (type->kind) {
- case Ast_ArrayType: type->ArrayType.tag = tag; break;
+ case Ast_ArrayType: type->ArrayType.tag = tag; break;
case Ast_DynamicArrayType: type->DynamicArrayType.tag = tag; break;
+ case Ast_PointerType: type->PointerType.tag = tag; break;
default:
- syntax_error(type, "Expected an array type after #%.*s, got %.*s", LIT(name.string), LIT(ast_strings[type->kind]));
+ syntax_error(type, "Expected an array or pointer type after #%.*s, got %.*s", LIT(name.string), LIT(ast_strings[type->kind]));
break;
}
return original_type;
@@ -2548,21 +2550,15 @@ Ast *parse_operand(AstFile *f, bool lhs) {
syntax_error(tag, "Invalid union tag '#%.*s'", LIT(tag.string));
}
}
- if (no_nil && maybe) {
- syntax_error(f->curr_token, "#maybe and #no_nil cannot be applied together");
- }
+
if (no_nil && shared_nil) {
syntax_error(f->curr_token, "#shared_nil and #no_nil cannot be applied together");
}
- if (shared_nil && maybe) {
- syntax_error(f->curr_token, "#maybe and #shared_nil cannot be applied together");
- }
-
if (maybe) {
- union_kind = UnionType_maybe;
syntax_error(f->curr_token, "#maybe functionality has now been merged with standard 'union' functionality");
- } else if (no_nil) {
+ }
+ if (no_nil) {
union_kind = UnionType_no_nil;
} else if (shared_nil) {
union_kind = UnionType_shared_nil;
@@ -3550,49 +3546,34 @@ Ast *parse_var_type(AstFile *f, bool allow_ellipsis, bool allow_typeid_token) {
}
-enum FieldPrefixKind : i32 {
- FieldPrefix_Unknown = -1,
- FieldPrefix_Invalid = 0,
-
- FieldPrefix_using, // implies #subtype
- FieldPrefix_const,
- FieldPrefix_no_alias,
- FieldPrefix_c_vararg,
- FieldPrefix_auto_cast,
- FieldPrefix_any_int,
- FieldPrefix_subtype, // does not imply `using` semantics
- FieldPrefix_by_ptr,
-};
-
struct ParseFieldPrefixMapping {
String name;
TokenKind token_kind;
- FieldPrefixKind prefix;
FieldFlag flag;
};
gb_global ParseFieldPrefixMapping parse_field_prefix_mappings[] = {
- {str_lit("using"), Token_using, FieldPrefix_using, FieldFlag_using},
- {str_lit("auto_cast"), Token_auto_cast, FieldPrefix_auto_cast, FieldFlag_auto_cast},
- {str_lit("no_alias"), Token_Hash, FieldPrefix_no_alias, FieldFlag_no_alias},
- {str_lit("c_vararg"), Token_Hash, FieldPrefix_c_vararg, FieldFlag_c_vararg},
- {str_lit("const"), Token_Hash, FieldPrefix_const, FieldFlag_const},
- {str_lit("any_int"), Token_Hash, FieldPrefix_any_int, FieldFlag_any_int},
- {str_lit("subtype"), Token_Hash, FieldPrefix_subtype, FieldFlag_subtype},
- {str_lit("by_ptr"), Token_Hash, FieldPrefix_by_ptr, FieldFlag_by_ptr},
+ {str_lit("using"), Token_using, FieldFlag_using},
+ {str_lit("auto_cast"), Token_auto_cast, FieldFlag_auto_cast},
+ {str_lit("no_alias"), Token_Hash, FieldFlag_no_alias},
+ {str_lit("c_vararg"), Token_Hash, FieldFlag_c_vararg},
+ {str_lit("const"), Token_Hash, FieldFlag_const},
+ {str_lit("any_int"), Token_Hash, FieldFlag_any_int},
+ {str_lit("subtype"), Token_Hash, FieldFlag_subtype},
+ {str_lit("by_ptr"), Token_Hash, FieldFlag_by_ptr},
};
-FieldPrefixKind is_token_field_prefix(AstFile *f) {
+FieldFlag is_token_field_prefix(AstFile *f) {
switch (f->curr_token.kind) {
case Token_EOF:
- return FieldPrefix_Invalid;
+ return FieldFlag_Invalid;
case Token_using:
- return FieldPrefix_using;
+ return FieldFlag_using;
case Token_auto_cast:
- return FieldPrefix_auto_cast;
+ return FieldFlag_auto_cast;
case Token_Hash:
advance_token(f);
@@ -3602,33 +3583,33 @@ FieldPrefixKind is_token_field_prefix(AstFile *f) {
auto const &mapping = parse_field_prefix_mappings[i];
if (mapping.token_kind == Token_Hash) {
if (f->curr_token.string == mapping.name) {
- return mapping.prefix;
+ return mapping.flag;
}
}
}
break;
}
- return FieldPrefix_Unknown;
+ return FieldFlag_Unknown;
}
- return FieldPrefix_Invalid;
+ return FieldFlag_Invalid;
}
u32 parse_field_prefixes(AstFile *f) {
i32 counts[gb_count_of(parse_field_prefix_mappings)] = {};
for (;;) {
- FieldPrefixKind kind = is_token_field_prefix(f);
- if (kind == FieldPrefix_Invalid) {
+ FieldFlag flag = is_token_field_prefix(f);
+ if (flag & FieldFlag_Invalid) {
break;
}
- if (kind == FieldPrefix_Unknown) {
+ if (flag & FieldFlag_Unknown) {
syntax_error(f->curr_token, "Unknown prefix kind '#%.*s'", LIT(f->curr_token.string));
advance_token(f);
continue;
}
for (i32 i = 0; i < gb_count_of(parse_field_prefix_mappings); i++) {
- if (parse_field_prefix_mappings[i].prefix == kind) {
+ if (parse_field_prefix_mappings[i].flag == flag) {
counts[i] += 1;
advance_token(f);
break;
@@ -3894,7 +3875,8 @@ Ast *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKi
while (f->curr_token.kind != follow &&
- f->curr_token.kind != Token_EOF) {
+ f->curr_token.kind != Token_EOF &&
+ f->curr_token.kind != Token_Semicolon) {
CommentGroup *docs = f->lead_comment;
u32 set_flags = parse_field_prefixes(f);
Token tag = {};
@@ -3922,7 +3904,7 @@ Ast *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKi
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;
+ default_value = nullptr;
}
}
diff --git a/src/parser.hpp b/src/parser.hpp
index 3126e0a02..7433744e6 100644
--- a/src/parser.hpp
+++ b/src/parser.hpp
@@ -282,7 +282,8 @@ enum StateFlag : u8 {
StateFlag_type_assert = 1<<2,
StateFlag_no_type_assert = 1<<3,
- StateFlag_SelectorCallExpr = 1<<6,
+ StateFlag_SelectorCallExpr = 1<<5,
+ StateFlag_DirectiveWasFalse = 1<<6,
StateFlag_BeenHandled = 1<<7,
};
@@ -308,6 +309,10 @@ enum FieldFlag : u32 {
FieldFlag_Tags = 1<<10,
FieldFlag_Results = 1<<16,
+
+ FieldFlag_Unknown = 1u<<30,
+ FieldFlag_Invalid = 1u<<31,
+
// Parameter List Restrictions
FieldFlag_Signature = FieldFlag_ellipsis|FieldFlag_using|FieldFlag_no_alias|FieldFlag_c_vararg|FieldFlag_auto_cast|FieldFlag_const|FieldFlag_any_int|FieldFlag_by_ptr,
FieldFlag_Struct = FieldFlag_using|FieldFlag_subtype|FieldFlag_Tags,
@@ -335,7 +340,6 @@ char const *inline_asm_dialect_strings[InlineAsmDialect_COUNT] = {
enum UnionTypeKind : u8 {
UnionType_Normal = 0,
- UnionType_maybe = 1, // removed
UnionType_no_nil = 2,
UnionType_shared_nil = 3,
};
@@ -647,7 +651,8 @@ AST_KIND(_TypeBegin, "", bool) \
}) \
AST_KIND(PointerType, "pointer type", struct { \
Token token; \
- Ast *type; \
+ Ast *type; \
+ Ast *tag; \
}) \
AST_KIND(RelativeType, "relative type", struct { \
Ast *tag; \
diff --git a/src/string.cpp b/src/string.cpp
index 44eccd2d2..bc55e370c 100644
--- a/src/string.cpp
+++ b/src/string.cpp
@@ -324,6 +324,16 @@ String concatenate3_strings(gbAllocator a, String const &x, String const &y, Str
data[len] = 0;
return make_string(data, len);
}
+String concatenate4_strings(gbAllocator a, String const &x, String const &y, String const &z, String const &w) {
+ isize len = x.len+y.len+z.len+w.len;
+ u8 *data = gb_alloc_array(a, u8, len+1);
+ gb_memmove(data, x.text, x.len);
+ gb_memmove(data+x.len, y.text, y.len);
+ gb_memmove(data+x.len+y.len, z.text, z.len);
+ gb_memmove(data+x.len+y.len+z.len, w.text, w.len);
+ data[len] = 0;
+ return make_string(data, len);
+}
String string_join_and_quote(gbAllocator a, Array<String> strings) {
if (!strings.count) {
diff --git a/src/types.cpp b/src/types.cpp
index 5f112ce09..b7cb4dd2c 100644
--- a/src/types.cpp
+++ b/src/types.cpp
@@ -278,7 +278,8 @@ struct TypeProc {
Type *generic_row_count; \
Type *generic_column_count; \
i64 stride_in_bytes; \
- })
+ }) \
+ TYPE_KIND(SoaPointer, struct { Type *elem; })
enum TypeKind {
@@ -350,6 +351,7 @@ enum Typeid_Kind : u8 {
Typeid_Relative_Pointer,
Typeid_Relative_Slice,
Typeid_Matrix,
+ Typeid_SoaPointer,
};
// IMPORTANT NOTE(bill): This must match the same as the in core.odin
@@ -644,6 +646,7 @@ gb_global Type *t_type_info_simd_vector = nullptr;
gb_global Type *t_type_info_relative_pointer = nullptr;
gb_global Type *t_type_info_relative_slice = nullptr;
gb_global Type *t_type_info_matrix = nullptr;
+gb_global Type *t_type_info_soa_pointer = nullptr;
gb_global Type *t_type_info_named_ptr = nullptr;
gb_global Type *t_type_info_integer_ptr = nullptr;
@@ -672,6 +675,7 @@ gb_global Type *t_type_info_simd_vector_ptr = nullptr;
gb_global Type *t_type_info_relative_pointer_ptr = nullptr;
gb_global Type *t_type_info_relative_slice_ptr = nullptr;
gb_global Type *t_type_info_matrix_ptr = nullptr;
+gb_global Type *t_type_info_soa_pointer_ptr = nullptr;
gb_global Type *t_allocator = nullptr;
gb_global Type *t_allocator_ptr = nullptr;
@@ -735,6 +739,7 @@ Type * bit_set_to_int(Type *t);
bool are_types_identical(Type *x, Type *y);
bool is_type_pointer(Type *t);
+bool is_type_soa_pointer(Type *t);
bool is_type_proc(Type *t);
bool is_type_slice(Type *t);
bool is_type_integer(Type *t);
@@ -917,6 +922,13 @@ Type *alloc_type_multi_pointer(Type *elem) {
return t;
}
+Type *alloc_type_soa_pointer(Type *elem) {
+ Type *t = alloc_type(Type_SoaPointer);
+ t->SoaPointer.elem = elem;
+ return t;
+}
+
+
Type *alloc_type_array(Type *elem, i64 count, Type *generic_count = nullptr) {
if (generic_count != nullptr) {
Type *t = alloc_type(Type_Array);
@@ -1103,17 +1115,28 @@ Type *alloc_type_simd_vector(i64 count, Type *elem, Type *generic_count=nullptr)
////////////////////////////////////////////////////////////////
-Type *type_deref(Type *t) {
+Type *type_deref(Type *t, bool allow_multi_pointer=false) {
if (t != nullptr) {
Type *bt = base_type(t);
if (bt == nullptr) {
return nullptr;
}
- if (bt->kind == Type_Pointer) {
+ switch (bt->kind) {
+ case Type_Pointer:
return bt->Pointer.elem;
- }
- if (bt->kind == Type_RelativePointer) {
+ case Type_RelativePointer:
return type_deref(bt->RelativePointer.pointer_type);
+ case Type_SoaPointer:
+ {
+ Type *elem = base_type(bt->SoaPointer.elem);
+ GB_ASSERT(elem->kind == Type_Struct && elem->Struct.soa_kind != StructSoa_None);
+ return elem->Struct.soa_elem;
+ }
+ case Type_MultiPointer:
+ if (allow_multi_pointer) {
+ return bt->MultiPointer.elem;
+ }
+ break;
}
}
return t;
@@ -1327,6 +1350,10 @@ bool is_type_pointer(Type *t) {
}
return t->kind == Type_Pointer;
}
+bool is_type_soa_pointer(Type *t) {
+ t = base_type(t);
+ return t->kind == Type_SoaPointer;
+}
bool is_type_multi_pointer(Type *t) {
t = base_type(t);
return t->kind == Type_MultiPointer;
@@ -1401,7 +1428,7 @@ i64 matrix_align_of(Type *t, struct TypePath *tp) {
}
GB_ASSERT(min_alignment >= elem_align);
- i64 align = gb_min(min_alignment, build_context.max_align);
+ i64 align = gb_min(min_alignment, build_context.max_simd_align);
return align;
}
@@ -1804,7 +1831,7 @@ bool is_type_dereferenceable(Type *t) {
if (is_type_rawptr(t)) {
return false;
}
- return is_type_pointer(t);
+ return is_type_pointer(t) || is_type_soa_pointer(t);
}
@@ -2079,6 +2106,9 @@ bool is_type_polymorphic(Type *t, bool or_specialized=false) {
case Type_Pointer:
return is_type_polymorphic(t->Pointer.elem, or_specialized);
+ case Type_SoaPointer:
+ return is_type_polymorphic(t->SoaPointer.elem, or_specialized);
+
case Type_EnumeratedArray:
if (is_type_polymorphic(t->EnumeratedArray.index, or_specialized)) {
return true;
@@ -2196,6 +2226,7 @@ bool type_has_nil(Type *t) {
case Type_Slice:
case Type_Proc:
case Type_Pointer:
+ case Type_SoaPointer:
case Type_MultiPointer:
case Type_DynamicArray:
case Type_Map:
@@ -2262,6 +2293,8 @@ bool is_type_comparable(Type *t) {
return true;
case Type_Pointer:
return true;
+ case Type_SoaPointer:
+ return true;
case Type_MultiPointer:
return true;
case Type_Enum:
@@ -2335,6 +2368,7 @@ bool is_type_simple_compare(Type *t) {
case Type_Pointer:
case Type_MultiPointer:
+ case Type_SoaPointer:
case Type_Proc:
case Type_BitSet:
return true;
@@ -2369,6 +2403,57 @@ bool is_type_simple_compare(Type *t) {
return false;
}
+bool is_type_load_safe(Type *type) {
+ GB_ASSERT(type != nullptr);
+ type = core_type(core_array_type(type));
+ switch (type->kind) {
+ case Type_Basic:
+ return (type->Basic.flags & (BasicFlag_Boolean|BasicFlag_Numeric|BasicFlag_Rune)) != 0;
+
+ case Type_BitSet:
+ if (type->BitSet.underlying) {
+ return is_type_load_safe(type->BitSet.underlying);
+ }
+ return true;
+
+ case Type_RelativePointer:
+ case Type_RelativeSlice:
+ return true;
+
+ case Type_Pointer:
+ case Type_MultiPointer:
+ case Type_Slice:
+ case Type_DynamicArray:
+ case Type_Proc:
+ case Type_SoaPointer:
+ return false;
+
+ case Type_Enum:
+ case Type_EnumeratedArray:
+ case Type_Array:
+ case Type_SimdVector:
+ case Type_Matrix:
+ GB_PANIC("should never be hit");
+ return false;
+
+ case Type_Struct:
+ for_array(i, type->Struct.fields) {
+ if (!is_type_load_safe(type->Struct.fields[i]->type)) {
+ return false;
+ }
+ }
+ return type_size_of(type) > 0;
+ case Type_Union:
+ for_array(i, type->Union.variants) {
+ if (!is_type_load_safe(type->Union.variants[i])) {
+ return false;
+ }
+ }
+ return type_size_of(type) > 0;
+ }
+ return false;
+}
+
String lookup_subtype_polymorphic_field(Type *dst, Type *src) {
Type *prev_src = src;
// Type *prev_dst = dst;
@@ -2558,6 +2643,12 @@ bool are_types_identical_internal(Type *x, Type *y, bool check_tuple_names) {
}
break;
+ case Type_SoaPointer:
+ if (y->kind == Type_SoaPointer) {
+ return are_types_identical(x->SoaPointer.elem, y->SoaPointer.elem);
+ }
+ break;
+
case Type_Named:
if (y->kind == Type_Named) {
return x->Named.type_name == y->Named.type_name;
@@ -3465,7 +3556,7 @@ i64 type_align_of_internal(Type *t, TypePath *path) {
case Type_SimdVector: {
// 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_align*2);
+ return gb_clamp(next_pow2(type_size_of_internal(t, path)), 1, build_context.max_simd_align*2);
}
case Type_Matrix:
@@ -3475,12 +3566,14 @@ i64 type_align_of_internal(Type *t, TypePath *path) {
return type_align_of_internal(t->RelativePointer.base_integer, path);
case Type_RelativeSlice:
return type_align_of_internal(t->RelativeSlice.base_integer, path);
+
+ case Type_SoaPointer:
+ return build_context.word_size;
}
- // return gb_clamp(next_pow2(type_size_of(t)), 1, build_context.max_align);
// NOTE(bill): Things that are bigger than build_context.word_size, are actually comprised of smaller types
// TODO(bill): Is this correct for 128-bit types (integers)?
- return gb_clamp(next_pow2(type_size_of_internal(t, path)), 1, build_context.word_size);
+ return gb_clamp(next_pow2(type_size_of_internal(t, path)), 1, build_context.max_align);
}
i64 *type_set_offsets_of(Slice<Entity *> const &fields, bool is_packed, bool is_raw_union) {
@@ -3580,6 +3673,9 @@ i64 type_size_of_internal(Type *t, TypePath *path) {
case Type_MultiPointer:
return build_context.word_size;
+ case Type_SoaPointer:
+ return build_context.word_size*2;
+
case Type_Array: {
i64 count, align, size, alignment;
count = t->Array.count;
@@ -4017,6 +4113,11 @@ gbString write_type_to_string(gbString str, Type *type, bool shorthand=false) {
str = write_type_to_string(str, type->Pointer.elem);
break;
+ case Type_SoaPointer:
+ str = gb_string_appendc(str, "#soa ^");
+ str = write_type_to_string(str, type->SoaPointer.elem);
+ break;
+
case Type_MultiPointer:
str = gb_string_appendc(str, "[^]");
str = write_type_to_string(str, type->Pointer.elem);