aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAndreas T Jonsson <mail@andreasjonsson.se>2024-04-25 22:04:40 +0200
committerAndreas T Jonsson <mail@andreasjonsson.se>2024-04-25 22:04:40 +0200
commit9a008d10f3d8f97ff11ba948d6939bec7e6beb6d (patch)
tree8b2fd91da22620b6e0a7158a66429f1af4aca210 /src
parent3000508c027c9d30c168266d0ae276cc14de3982 (diff)
parentf745fff640ab1582bdfdd18a7239c58fa37db753 (diff)
Merge branch 'master' into netbsd
Diffstat (limited to 'src')
-rw-r--r--src/build_settings.cpp146
-rw-r--r--src/check_stmt.cpp47
-rw-r--r--src/check_type.cpp92
-rw-r--r--src/checker.cpp13
-rw-r--r--src/checker.hpp5
-rw-r--r--src/common_memory.cpp4
-rw-r--r--src/entity.cpp2
-rw-r--r--src/error.cpp214
-rw-r--r--src/llvm_abi.cpp5
-rw-r--r--src/llvm_backend.cpp2
-rw-r--r--src/llvm_backend.hpp1
-rw-r--r--src/llvm_backend_debug.cpp14
-rw-r--r--src/llvm_backend_expr.cpp227
-rw-r--r--src/llvm_backend_general.cpp127
-rw-r--r--src/llvm_backend_proc.cpp13
-rw-r--r--src/llvm_backend_type.cpp10
-rw-r--r--src/llvm_backend_utility.cpp85
-rw-r--r--src/main.cpp65
-rw-r--r--src/parser.cpp6
-rw-r--r--src/string.cpp74
-rw-r--r--src/tokenizer.cpp1
-rw-r--r--src/types.cpp1
22 files changed, 824 insertions, 330 deletions
diff --git a/src/build_settings.cpp b/src/build_settings.cpp
index cd57816ab..9ecc11cb5 100644
--- a/src/build_settings.cpp
+++ b/src/build_settings.cpp
@@ -274,13 +274,16 @@ enum BuildPath : u8 {
};
enum VetFlags : u64 {
- VetFlag_NONE = 0,
- VetFlag_Unused = 1u<<0, // 1
- VetFlag_Shadowing = 1u<<1, // 2
- VetFlag_UsingStmt = 1u<<2, // 4
- VetFlag_UsingParam = 1u<<3, // 8
- VetFlag_Style = 1u<<4, // 16
- VetFlag_Semicolon = 1u<<5, // 32
+ VetFlag_NONE = 0,
+ VetFlag_Shadowing = 1u<<0,
+ VetFlag_UsingStmt = 1u<<1,
+ VetFlag_UsingParam = 1u<<2,
+ VetFlag_Style = 1u<<3,
+ VetFlag_Semicolon = 1u<<4,
+ VetFlag_UnusedVariables = 1u<<5,
+ VetFlag_UnusedImports = 1u<<6,
+
+ VetFlag_Unused = VetFlag_UnusedVariables|VetFlag_UnusedImports,
VetFlag_All = VetFlag_Unused|VetFlag_Shadowing|VetFlag_UsingStmt,
@@ -290,6 +293,10 @@ enum VetFlags : u64 {
u64 get_vet_flag_from_name(String const &name) {
if (name == "unused") {
return VetFlag_Unused;
+ } else if (name == "unused-variables") {
+ return VetFlag_UnusedVariables;
+ } else if (name == "unused-imports") {
+ return VetFlag_UnusedImports;
} else if (name == "shadowing") {
return VetFlag_Shadowing;
} else if (name == "using-stmt") {
@@ -377,6 +384,7 @@ struct BuildContext {
bool keep_temp_files;
bool ignore_unknown_attributes;
bool no_bounds_check;
+ bool no_type_assert;
bool no_dynamic_literals;
bool no_output_files;
bool no_crt;
@@ -634,6 +642,15 @@ gb_global TargetMetrics target_freestanding_amd64_sysv = {
TargetABI_SysV,
};
+gb_global TargetMetrics target_freestanding_amd64_win64 = {
+ TargetOs_freestanding,
+ TargetArch_amd64,
+ 8, 8, 8, 16,
+ str_lit("x86_64-pc-none-msvc"),
+ str_lit("e-m:w-i64:64-f80:128-n8:16:32:64-S128"),
+ TargetABI_Win64,
+};
+
gb_global TargetMetrics target_freestanding_arm64 = {
TargetOs_freestanding,
TargetArch_arm64,
@@ -676,7 +693,9 @@ gb_global NamedTargetMetrics named_targets[] = {
{ str_lit("js_wasm64p32"), &target_js_wasm64p32 },
{ str_lit("wasi_wasm64p32"), &target_wasi_wasm64p32 },
- { str_lit("freestanding_amd64_sysv"), &target_freestanding_amd64_sysv },
+ { str_lit("freestanding_amd64_sysv"), &target_freestanding_amd64_sysv },
+ { str_lit("freestanding_amd64_win64"), &target_freestanding_amd64_win64 },
+
{ str_lit("freestanding_arm64"), &target_freestanding_arm64 },
};
@@ -832,13 +851,11 @@ gb_internal String odin_root_dir(void) {
char const *found = gb_get_env("ODIN_ROOT", a);
if (found) {
String path = path_to_full_path(a, make_string_c(found));
- if (path[path.len-1] != '/' && path[path.len-1] != '\\') {
#if defined(GB_SYSTEM_WINDOWS)
- path = concatenate_strings(a, path, WIN32_SEPARATOR_STRING);
+ path = normalize_path(a, path, WIN32_SEPARATOR_STRING);
#else
- path = concatenate_strings(a, path, NIX_SEPARATOR_STRING);
+ path = normalize_path(a, path, NIX_SEPARATOR_STRING);
#endif
- }
global_module_path = path;
global_module_path_set = true;
@@ -1461,26 +1478,6 @@ gb_internal void init_build_context(TargetMetrics *cross_target, Subtarget subta
}
bc->metrics = *metrics;
- if (metrics->os == TargetOs_darwin) {
- if (!bc->minimum_os_version_string_given) {
- bc->minimum_os_version_string = str_lit("11.0.0");
- }
-
- switch (subtarget) {
- case Subtarget_Default:
- bc->metrics.target_triplet = concatenate_strings(permanent_allocator(), bc->metrics.target_triplet, bc->minimum_os_version_string);
- break;
- case Subtarget_iOS:
- if (metrics->arch == TargetArch_arm64) {
- bc->metrics.target_triplet = str_lit("arm64-apple-ios");
- } else if (metrics->arch == TargetArch_amd64) {
- bc->metrics.target_triplet = str_lit("x86_64-apple-ios");
- } else {
- GB_PANIC("Unknown architecture for darwin");
- }
- break;
- }
- }
bc->ODIN_OS = target_os_names[metrics->os];
bc->ODIN_ARCH = target_arch_names[metrics->arch];
@@ -1516,65 +1513,26 @@ gb_internal void init_build_context(TargetMetrics *cross_target, Subtarget subta
bc->ODIN_WINDOWS_SUBSYSTEM = windows_subsystem_names[Windows_Subsystem_CONSOLE];
}
- // NOTE(zangent): The linker flags to set the build architecture are different
- // across OSs. It doesn't make sense to allocate extra data on the heap
- // here, so I just #defined the linker flags to keep things concise.
- if (bc->metrics.arch == TargetArch_amd64) {
- switch (bc->metrics.os) {
- case TargetOs_windows:
- bc->link_flags = str_lit("/machine:x64 ");
- break;
- case TargetOs_darwin:
- bc->link_flags = str_lit("-arch x86_64 ");
+ if (metrics->os == TargetOs_darwin && subtarget == Subtarget_iOS) {
+ switch (metrics->arch) {
+ case TargetArch_arm64:
+ bc->metrics.target_triplet = str_lit("arm64-apple-ios");
break;
- case TargetOs_linux:
- bc->link_flags = str_lit("-arch x86-64 ");
- break;
- case TargetOs_freebsd:
- bc->link_flags = str_lit("-arch x86-64 ");
- break;
- case TargetOs_openbsd:
- bc->link_flags = str_lit("-arch x86-64 ");
- break;
- case TargetOs_netbsd:
- bc->link_flags = str_lit("-arch x86-64 ");
- break;
- case TargetOs_haiku:
- bc->link_flags = str_lit("-arch x86-64 ");
- break;
- }
- } else if (bc->metrics.arch == TargetArch_i386) {
- switch (bc->metrics.os) {
- case TargetOs_windows:
- bc->link_flags = str_lit("/machine:x86 ");
- break;
- case TargetOs_darwin:
- gb_printf_err("Unsupported architecture\n");
- gb_exit(1);
- break;
- case TargetOs_linux:
- bc->link_flags = str_lit("-arch x86 ");
- break;
- case TargetOs_freebsd:
- bc->link_flags = str_lit("-arch x86 ");
- break;
- }
- } else if (bc->metrics.arch == TargetArch_arm32) {
- switch (bc->metrics.os) {
- case TargetOs_linux:
- bc->link_flags = str_lit("-arch arm ");
+ case TargetArch_amd64:
+ bc->metrics.target_triplet = str_lit("x86_64-apple-ios");
break;
default:
- gb_printf_err("Compiler Error: Unsupported architecture\n");
- gb_exit(1);
+ GB_PANIC("Unknown architecture for darwin");
}
- } else if (bc->metrics.arch == TargetArch_arm64) {
- switch (bc->metrics.os) {
- case TargetOs_darwin:
- bc->link_flags = str_lit("-arch arm64 ");
+ }
+
+ if (bc->metrics.os == TargetOs_windows) {
+ switch (bc->metrics.arch) {
+ case TargetArch_amd64:
+ bc->link_flags = str_lit("/machine:x64 ");
break;
- case TargetOs_linux:
- bc->link_flags = str_lit("-arch aarch64 ");
+ case TargetArch_i386:
+ bc->link_flags = str_lit("/machine:x86 ");
break;
}
} else if (is_arch_wasm()) {
@@ -1594,8 +1552,20 @@ gb_internal void init_build_context(TargetMetrics *cross_target, Subtarget subta
// Disallow on wasm
bc->use_separate_modules = false;
} else {
- gb_printf_err("Compiler Error: Unsupported architecture\n");
- gb_exit(1);
+ bc->link_flags = concatenate3_strings(permanent_allocator(),
+ str_lit("-target "), bc->metrics.target_triplet, str_lit(" "));
+ }
+
+ // NOTE: needs to be done after adding the -target flag to the linker flags so the linker
+ // does not annoy the user with version warnings.
+ if (metrics->os == TargetOs_darwin) {
+ if (!bc->minimum_os_version_string_given) {
+ bc->minimum_os_version_string = str_lit("11.0.0");
+ }
+
+ if (subtarget == Subtarget_Default) {
+ bc->metrics.target_triplet = concatenate_strings(permanent_allocator(), bc->metrics.target_triplet, bc->minimum_os_version_string);
+ }
}
if (bc->ODIN_DEBUG && !bc->custom_optimization_level) {
diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp
index fc3b9aa43..971841165 100644
--- a/src/check_stmt.cpp
+++ b/src/check_stmt.cpp
@@ -474,16 +474,59 @@ gb_internal Type *check_assignment_variable(CheckerContext *ctx, Operand *lhs, O
}
Entity *e = entity_of_node(lhs->expr);
+ Entity *original_e = e;
+
+ Ast *name = unparen_expr(lhs->expr);
+ while (name->kind == Ast_SelectorExpr) {
+ name = name->SelectorExpr.expr;
+ e = entity_of_node(name);
+ }
+ if (e == nullptr) {
+ e = original_e;
+ }
gbString str = expr_to_string(lhs->expr);
if (e != nullptr && e->flags & EntityFlag_Param) {
+ ERROR_BLOCK();
if (e->flags & EntityFlag_Using) {
error(lhs->expr, "Cannot assign to '%s' which is from a 'using' procedure parameter", str);
} else {
error(lhs->expr, "Cannot assign to '%s' which is a procedure parameter", str);
}
+ error_line("\tSuggestion: Did you mean to pass '%.*s' by pointer?\n", LIT(e->token.string));
+ show_error_on_line(e->token.pos, token_pos_end(e->token));
} else {
+ ERROR_BLOCK();
error(lhs->expr, "Cannot assign to '%s'", str);
+
+ if (e && e->flags & EntityFlag_ForValue) {
+ isize offset = show_error_on_line(e->token.pos, token_pos_end(e->token), "Suggestion:");
+ if (offset < 0) {
+ if (is_type_map(e->type)) {
+ error_line("\tSuggestion: Did you mean? 'for key, &%.*s in ...'\n", LIT(e->token.string));
+ } else {
+ error_line("\tSuggestion: Did you mean? 'for &%.*s in ...'\n", LIT(e->token.string));
+ }
+ } else {
+ error_line("\t");
+ for (isize i = 0; i < offset-1; i++) {
+ error_line(" ");
+ }
+ error_line("'%.*s' is immutable, declare it as '&%.*s' to make it mutable\n", LIT(e->token.string), LIT(e->token.string));
+ }
+
+ } else if (e && e->flags & EntityFlag_SwitchValue) {
+ isize offset = show_error_on_line(e->token.pos, token_pos_end(e->token), "Suggestion:");
+ if (offset < 0) {
+ error_line("\tSuggestion: Did you mean? 'switch &%.*s in ...'\n", LIT(e->token.string));
+ } else {
+ error_line("\t");
+ for (isize i = 0; i < offset-1; i++) {
+ error_line(" ");
+ }
+ error_line("'%.*s' is immutable, declare it as '&%.*s' to make it mutable\n", LIT(e->token.string), LIT(e->token.string));
+ }
+ }
}
gb_string_free(str);
@@ -2355,14 +2398,14 @@ gb_internal void check_return_stmt(CheckerContext *ctx, Ast *node) {
unsafe_return_error(o, "the address of a compound literal");
} else if (x->kind == Ast_IndexExpr) {
Entity *f = entity_of_node(x->IndexExpr.expr);
- if (is_type_array_like(f->type) || is_type_matrix(f->type)) {
+ if (f && (is_type_array_like(f->type) || is_type_matrix(f->type))) {
if (is_entity_local_variable(f)) {
unsafe_return_error(o, "the address of an indexed variable", f->type);
}
}
} else if (x->kind == Ast_MatrixIndexExpr) {
Entity *f = entity_of_node(x->MatrixIndexExpr.expr);
- if (is_type_matrix(f->type) && is_entity_local_variable(f)) {
+ if (f && (is_type_matrix(f->type) && is_entity_local_variable(f))) {
unsafe_return_error(o, "the address of an indexed variable", f->type);
}
}
diff --git a/src/check_type.cpp b/src/check_type.cpp
index f1d991acb..ab8c0b057 100644
--- a/src/check_type.cpp
+++ b/src/check_type.cpp
@@ -29,10 +29,11 @@ gb_internal void populate_using_array_index(CheckerContext *ctx, Ast *node, AstF
}
}
-gb_internal void populate_using_entity_scope(CheckerContext *ctx, Ast *node, AstField *field, Type *t) {
+gb_internal void populate_using_entity_scope(CheckerContext *ctx, Ast *node, AstField *field, Type *t, isize level) {
if (t == nullptr) {
return;
}
+ Type *original_type = t;
t = base_type(type_deref(t));
gbString str = nullptr;
defer (gb_string_free(str));
@@ -46,16 +47,18 @@ gb_internal void populate_using_entity_scope(CheckerContext *ctx, Ast *node, Ast
String name = f->token.string;
Entity *e = scope_lookup_current(ctx->scope, name);
if (e != nullptr && name != "_") {
+ gbString ot = type_to_string(original_type);
// TODO(bill): Better type error
if (str != nullptr) {
- error(e->token, "'%.*s' is already declared in '%s'", LIT(name), str);
+ error(e->token, "'%.*s' is already declared in '%s', through 'using' from '%s'", LIT(name), str, ot);
} else {
- error(e->token, "'%.*s' is already declared", LIT(name));
+ error(e->token, "'%.*s' is already declared, through 'using' from '%s'", LIT(name), ot);
}
+ gb_string_free(ot);
} else {
add_entity(ctx, ctx->scope, nullptr, f);
if (f->flags & EntityFlag_Using) {
- populate_using_entity_scope(ctx, node, field, f->type);
+ populate_using_entity_scope(ctx, node, field, f->type, level+1);
}
}
}
@@ -200,7 +203,7 @@ gb_internal void check_struct_fields(CheckerContext *ctx, Ast *node, Slice<Entit
continue;
}
- populate_using_entity_scope(ctx, node, p, type);
+ populate_using_entity_scope(ctx, node, p, type, 1);
}
if (is_subtype && p->names.count > 0) {
@@ -952,14 +955,19 @@ gb_internal void check_bit_field_type(CheckerContext *ctx, Type *bit_field_type,
GB_ASSERT(is_type_bit_field(bit_field_type));
Type *backing_type = check_type(ctx, bf->backing_type);
- if (backing_type == nullptr || !is_valid_bit_field_backing_type(backing_type)) {
- error(node, "Backing type for a bit_field must be an integer or an array of an integer");
- return;
- }
- bit_field_type->BitField.backing_type = backing_type;
+ bit_field_type->BitField.backing_type = backing_type ? backing_type : t_u8;
bit_field_type->BitField.scope = ctx->scope;
+ if (backing_type == nullptr) {
+ error(bf->backing_type, "Backing type for a bit_field must be an integer or an array of an integer");
+ return;
+ }
+ if (!is_valid_bit_field_backing_type(backing_type)) {
+ error(bf->backing_type, "Backing type for a bit_field must be an integer or an array of an integer");
+ return;
+ }
+
auto fields = array_make<Entity *>(permanent_allocator(), 0, bf->fields.count);
auto bit_sizes = array_make<u8> (permanent_allocator(), 0, bf->fields.count);
auto tags = array_make<String> (permanent_allocator(), 0, bf->fields.count);
@@ -1093,6 +1101,45 @@ gb_internal void check_bit_field_type(CheckerContext *ctx, Type *bit_field_type,
gb_string_free(s);
}
+ enum EndianKind {
+ Endian_Unknown,
+ Endian_Native,
+ Endian_Little,
+ Endian_Big,
+ };
+ auto const &determine_endian_kind = [](Type *type) -> EndianKind {
+ if (is_type_boolean(type)) {
+ // NOTE(bill): it doesn't matter, and when it does,
+ // that api is absolutely stupid
+ return Endian_Unknown;
+ } else if (is_type_endian_specific(type)) {
+ if (is_type_endian_little(type)) {
+ return Endian_Little;
+ } else {
+ return Endian_Big;
+ }
+ }
+ return Endian_Native;
+ };
+
+ EndianKind backing_type_endian_kind = determine_endian_kind(core_array_type(backing_type));
+ EndianKind endian_kind = Endian_Unknown;
+ for (Entity *f : fields) {
+ EndianKind field_kind = determine_endian_kind(f->type);
+
+ if (field_kind && backing_type_endian_kind != field_kind) {
+ error(f->token, "All 'bit_field' field types must match the same endian kind as the backing type, i.e. all native, all little, or all big");
+ }
+
+ if (endian_kind == Endian_Unknown) {
+ endian_kind = field_kind;
+ } else if (field_kind && endian_kind != field_kind) {
+ error(f->token, "All 'bit_field' field types must be of the same endian variety, i.e. all native, all little, or all big");
+ }
+ }
+
+
+
if (bit_sizes.count > 0 && is_type_integer(backing_type)) {
bool all_booleans = is_type_boolean(fields[0]->type);
bool all_ones = bit_sizes[0] == 1;
@@ -2495,18 +2542,16 @@ gb_internal Type *get_map_cell_type(Type *type) {
return s;
}
-gb_internal void init_map_internal_types(Type *type) {
+gb_internal void init_map_internal_debug_types(Type *type) {
GB_ASSERT(type->kind == Type_Map);
GB_ASSERT(t_allocator != nullptr);
- if (type->Map.lookup_result_type != nullptr) return;
+ if (type->Map.debug_metadata_type != nullptr) return;
Type *key = type->Map.key;
Type *value = type->Map.value;
GB_ASSERT(key != nullptr);
GB_ASSERT(value != nullptr);
-
-
Type *key_cell = get_map_cell_type(key);
Type *value_cell = get_map_cell_type(value);
@@ -2541,6 +2586,18 @@ gb_internal void init_map_internal_types(Type *type) {
gb_unused(type_size_of(debug_type));
type->Map.debug_metadata_type = debug_type;
+}
+
+
+gb_internal void init_map_internal_types(Type *type) {
+ GB_ASSERT(type->kind == Type_Map);
+ GB_ASSERT(t_allocator != nullptr);
+ if (type->Map.lookup_result_type != nullptr) return;
+
+ Type *key = type->Map.key;
+ Type *value = type->Map.value;
+ GB_ASSERT(key != nullptr);
+ GB_ASSERT(value != nullptr);
type->Map.lookup_result_type = make_optional_ok_type(value);
}
@@ -2613,8 +2670,6 @@ gb_internal void check_map_type(CheckerContext *ctx, Type *type, Ast *node) {
init_core_map_type(ctx->checker);
init_map_internal_types(type);
-
- // error(node, "'map' types are not yet implemented");
}
gb_internal void check_matrix_type(CheckerContext *ctx, Type **type, Ast *node) {
@@ -3233,6 +3288,11 @@ gb_internal bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, T
Type *elem = t_invalid;
Operand o = {};
+ if (unparen_expr(pt->type) == nullptr) {
+ error(e, "Invalid pointer type");
+ return false;
+ }
+
check_expr_or_type(&c, &o, pt->type);
if (o.mode != Addressing_Invalid && o.mode != Addressing_Type) {
if (o.mode == Addressing_Variable) {
diff --git a/src/checker.cpp b/src/checker.cpp
index 77d894624..f36677c84 100644
--- a/src/checker.cpp
+++ b/src/checker.cpp
@@ -703,11 +703,11 @@ gb_internal void check_scope_usage(Checker *c, Scope *scope, u64 vet_flags) {
array_add(&vetted_entities, ve_unused);
} else if (is_shadowed) {
array_add(&vetted_entities, ve_shadowed);
- } else if (e->kind == Entity_Variable && (e->flags & (EntityFlag_Param|EntityFlag_Using)) == 0) {
+ } else if (e->kind == Entity_Variable && (e->flags & (EntityFlag_Param|EntityFlag_Using|EntityFlag_Static)) == 0 && !e->Variable.is_global) {
i64 sz = type_size_of(e->type);
// TODO(bill): When is a good size warn?
- // Is 128 KiB good enough?
- if (sz >= 1ll<<17) {
+ // Is >256 KiB good enough?
+ if (sz > 1ll<<18) {
gbString type_str = type_to_string(e->type);
warning(e->token, "Declaration of '%.*s' may cause a stack overflow due to its type '%s' having a size of %lld bytes", LIT(e->token.string), type_str, cast(long long)sz);
gb_string_free(type_str);
@@ -728,7 +728,10 @@ gb_internal void check_scope_usage(Checker *c, Scope *scope, u64 vet_flags) {
} else if (vet_flags) {
switch (ve.kind) {
case VettedEntity_Unused:
- if (vet_flags & VetFlag_Unused) {
+ if (e->kind == Entity_Variable && (vet_flags & VetFlag_UnusedVariables) != 0) {
+ error(e->token, "'%.*s' declared but not used", LIT(name));
+ }
+ if ((e->kind == Entity_ImportName || e->kind == Entity_LibraryName) && (vet_flags & VetFlag_UnusedImports) != 0) {
error(e->token, "'%.*s' declared but not used", LIT(name));
}
break;
@@ -1109,6 +1112,8 @@ gb_internal void init_universal(void) {
add_global_bool_constant("ODIN_DEBUG", bc->ODIN_DEBUG);
add_global_bool_constant("ODIN_DISABLE_ASSERT", bc->ODIN_DISABLE_ASSERT);
add_global_bool_constant("ODIN_DEFAULT_TO_NIL_ALLOCATOR", bc->ODIN_DEFAULT_TO_NIL_ALLOCATOR);
+ add_global_bool_constant("ODIN_NO_BOUNDS_CHECK", build_context.no_bounds_check);
+ add_global_bool_constant("ODIN_NO_TYPE_ASSERT", build_context.no_type_assert);
add_global_bool_constant("ODIN_DEFAULT_TO_PANIC_ALLOCATOR", bc->ODIN_DEFAULT_TO_PANIC_ALLOCATOR);
add_global_bool_constant("ODIN_NO_DYNAMIC_LITERALS", bc->no_dynamic_literals);
add_global_bool_constant("ODIN_NO_CRT", bc->no_crt);
diff --git a/src/checker.hpp b/src/checker.hpp
index 1701da58d..2ade9312e 100644
--- a/src/checker.hpp
+++ b/src/checker.hpp
@@ -563,4 +563,7 @@ gb_internal void init_mem_allocator(Checker *c);
gb_internal void add_untyped_expressions(CheckerInfo *cinfo, UntypedExprInfoMap *untyped);
-gb_internal GenTypesData *ensure_polymorphic_record_entity_has_gen_types(CheckerContext *ctx, Type *original_type); \ No newline at end of file
+gb_internal GenTypesData *ensure_polymorphic_record_entity_has_gen_types(CheckerContext *ctx, Type *original_type);
+
+
+gb_internal void init_map_internal_types(Type *type); \ No newline at end of file
diff --git a/src/common_memory.cpp b/src/common_memory.cpp
index c6ee88f03..60e570eee 100644
--- a/src/common_memory.cpp
+++ b/src/common_memory.cpp
@@ -163,6 +163,10 @@ gb_internal void platform_virtual_memory_protect(void *memory, isize size);
GB_ASSERT(is_protected);
}
#else
+ #if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
+ #define MAP_ANONYMOUS MAP_ANON
+ #endif
+
gb_internal void platform_virtual_memory_init(void) {
global_platform_memory_block_sentinel.prev = &global_platform_memory_block_sentinel;
global_platform_memory_block_sentinel.next = &global_platform_memory_block_sentinel;
diff --git a/src/entity.cpp b/src/entity.cpp
index 6cea0930f..a12e1d0a6 100644
--- a/src/entity.cpp
+++ b/src/entity.cpp
@@ -496,7 +496,7 @@ gb_internal bool is_entity_local_variable(Entity *e) {
if (e->scope == nullptr) {
return true;
}
- if (e->flags & (EntityFlag_ForValue|EntityFlag_SwitchValue)) {
+ if (e->flags & (EntityFlag_ForValue|EntityFlag_SwitchValue|EntityFlag_Static)) {
return false;
}
diff --git a/src/error.cpp b/src/error.cpp
index eb167d4c3..7fb62c966 100644
--- a/src/error.cpp
+++ b/src/error.cpp
@@ -7,7 +7,8 @@ struct ErrorValue {
ErrorValueKind kind;
TokenPos pos;
TokenPos end;
- Array<String> msgs;
+ Array<u8> msg;
+ bool seen_newline;
};
struct ErrorCollector {
@@ -30,19 +31,21 @@ gb_global ErrorCollector global_error_collector;
gb_internal void push_error_value(TokenPos const &pos, ErrorValueKind kind = ErrorValue_Error) {
GB_ASSERT_MSG(global_error_collector.curr_error_value_set.load() == false, "Possible race condition in error handling system, please report this with an issue");
ErrorValue ev = {kind, pos};
- ev.msgs.allocator = heap_allocator();
+ ev.msg.allocator = heap_allocator();
global_error_collector.curr_error_value = ev;
global_error_collector.curr_error_value_set.store(true);
}
gb_internal void pop_error_value(void) {
+ mutex_lock(&global_error_collector.mutex);
if (global_error_collector.curr_error_value_set.load()) {
array_add(&global_error_collector.error_values, global_error_collector.curr_error_value);
global_error_collector.curr_error_value = {};
global_error_collector.curr_error_value_set.store(false);
}
+ mutex_unlock(&global_error_collector.mutex);
}
@@ -84,6 +87,7 @@ gb_internal bool set_file_path_string(i32 index, String const &path) {
bool ok = false;
GB_ASSERT(index >= 0);
mutex_lock(&global_error_collector.path_mutex);
+ mutex_lock(&global_files_mutex);
if (index >= global_file_path_strings.count) {
array_resize(&global_file_path_strings, index+1);
@@ -94,6 +98,7 @@ gb_internal bool set_file_path_string(i32 index, String const &path) {
ok = true;
}
+ mutex_unlock(&global_files_mutex);
mutex_unlock(&global_error_collector.path_mutex);
return ok;
}
@@ -102,6 +107,7 @@ gb_internal bool thread_safe_set_ast_file_from_id(i32 index, AstFile *file) {
bool ok = false;
GB_ASSERT(index >= 0);
mutex_lock(&global_error_collector.path_mutex);
+ mutex_lock(&global_files_mutex);
if (index >= global_files.count) {
array_resize(&global_files, index+1);
@@ -111,7 +117,7 @@ gb_internal bool thread_safe_set_ast_file_from_id(i32 index, AstFile *file) {
global_files[index] = file;
ok = true;
}
-
+ mutex_unlock(&global_files_mutex);
mutex_unlock(&global_error_collector.path_mutex);
return ok;
}
@@ -119,12 +125,14 @@ gb_internal bool thread_safe_set_ast_file_from_id(i32 index, AstFile *file) {
gb_internal String get_file_path_string(i32 index) {
GB_ASSERT(index >= 0);
mutex_lock(&global_error_collector.path_mutex);
+ mutex_lock(&global_files_mutex);
String path = {};
if (index < global_file_path_strings.count) {
path = global_file_path_strings[index];
}
+ mutex_unlock(&global_files_mutex);
mutex_unlock(&global_error_collector.path_mutex);
return path;
}
@@ -132,12 +140,14 @@ gb_internal String get_file_path_string(i32 index) {
gb_internal AstFile *thread_safe_get_ast_file_from_id(i32 index) {
GB_ASSERT(index >= 0);
mutex_lock(&global_error_collector.path_mutex);
+ mutex_lock(&global_files_mutex);
AstFile *file = nullptr;
if (index < global_files.count) {
file = global_files[index];
}
+ mutex_unlock(&global_files_mutex);
mutex_unlock(&global_error_collector.path_mutex);
return file;
}
@@ -173,9 +183,18 @@ gb_internal ERROR_OUT_PROC(default_error_out_va) {
isize n = len-1;
if (n > 0) {
- String msg = copy_string(permanent_allocator(), {(u8 *)buf, n});
ErrorValue *ev = get_error_value();
- array_add(&ev->msgs, msg);
+ if (terse_errors()) {
+ for (isize i = 0; i < n && !ev->seen_newline; i++) {
+ u8 c = cast(u8)buf[i];
+ if (c == '\n') {
+ ev->seen_newline = true;
+ }
+ array_add(&ev->msg, c);
+ }
+ } else {
+ array_add_elems(&ev->msg, (u8 *)buf, n);
+ }
}
}
@@ -247,10 +266,10 @@ gb_internal void terminal_reset_colours(void) {
}
-gb_internal bool show_error_on_line(TokenPos const &pos, TokenPos end) {
+gb_internal isize show_error_on_line(TokenPos const &pos, TokenPos end, char const *prefix=nullptr) {
get_error_value()->end = end;
if (!show_error_line()) {
- return false;
+ return -1;
}
i32 offset = 0;
@@ -270,6 +289,10 @@ gb_internal bool show_error_on_line(TokenPos const &pos, TokenPos end) {
MAX_LINE_LENGTH_PADDED = MAX_LINE_LENGTH-MAX_TAB_WIDTH-ELLIPSIS_PADDING,
};
+ if (prefix) {
+ error_out("\t%s\n\n", prefix);
+ }
+
error_out("\t");
terminal_set_colours(TerminalStyle_Bold, TerminalColour_White);
@@ -281,10 +304,11 @@ gb_internal bool show_error_on_line(TokenPos const &pos, TokenPos end) {
if (line_len > MAX_LINE_LENGTH_PADDED) {
i32 left = MAX_TAB_WIDTH;
- if (offset > 0) {
- line_text += offset-left;
- line_len -= offset-left;
- offset = left+MAX_TAB_WIDTH/2;
+ i32 diff = gb_max(offset-left, 0);
+ if (diff > 0) {
+ line_text += diff;
+ line_len -= diff;
+ offset = left + ELLIPSIS_PADDING/2;
}
if (line_len > MAX_LINE_LENGTH_PADDED) {
line_len = MAX_LINE_LENGTH_PADDED;
@@ -293,7 +317,7 @@ gb_internal bool show_error_on_line(TokenPos const &pos, TokenPos end) {
squiggle_extra = 1;
}
}
- if (offset > 0) {
+ if (diff > 0) {
error_out("... %.*s ...", cast(i32)line_len, line_text);
} else {
error_out("%.*s ...", cast(i32)line_len, line_text);
@@ -328,9 +352,9 @@ gb_internal bool show_error_on_line(TokenPos const &pos, TokenPos end) {
terminal_reset_colours();
error_out("\n");
- return true;
+ return offset;
}
- return false;
+ return -1;
}
gb_internal void error_out_empty(void) {
@@ -367,7 +391,11 @@ gb_internal void error_va(TokenPos const &pos, TokenPos end, char const *fmt, va
error_out("\n");
} else if (global_error_collector.prev != pos) {
global_error_collector.prev = pos;
- error_out_pos(pos);
+ if (json_errors()) {
+ error_out_empty();
+ } else {
+ error_out_pos(pos);
+ }
if (has_ansi_terminal_colours()) {
error_out_coloured("Error: ", TerminalStyle_Normal, TerminalColour_Red);
}
@@ -400,7 +428,11 @@ gb_internal void warning_va(TokenPos const &pos, TokenPos end, char const *fmt,
error_out("\n");
} else if (global_error_collector.prev != pos) {
global_error_collector.prev = pos;
- error_out_pos(pos);
+ if (json_errors()) {
+ error_out_empty();
+ } else {
+ error_out_pos(pos);
+ }
error_out_coloured("Warning: ", TerminalStyle_Normal, TerminalColour_Yellow);
error_out_va(fmt, va);
error_out("\n");
@@ -433,7 +465,11 @@ gb_internal void error_no_newline_va(TokenPos const &pos, char const *fmt, va_li
error_out_va(fmt, va);
} else if (global_error_collector.prev != pos) {
global_error_collector.prev = pos;
- error_out_pos(pos);
+ if (json_errors()) {
+ error_out_empty();
+ } else {
+ error_out_pos(pos);
+ }
if (has_ansi_terminal_colours()) {
error_out_coloured("Error: ", TerminalStyle_Normal, TerminalColour_Red);
}
@@ -458,7 +494,11 @@ gb_internal void syntax_error_va(TokenPos const &pos, TokenPos end, char const *
// NOTE(bill): Duplicate error, skip it
if (global_error_collector.prev != pos) {
global_error_collector.prev = pos;
- error_out_pos(pos);
+ if (json_errors()) {
+ error_out_empty();
+ } else {
+ error_out_pos(pos);
+ }
error_out_coloured("Syntax Error: ", TerminalStyle_Normal, TerminalColour_Red);
error_out_va(fmt, va);
error_out("\n");
@@ -492,7 +532,11 @@ gb_internal void syntax_error_with_verbose_va(TokenPos const &pos, TokenPos end,
error_out("\n");
} else if (global_error_collector.prev != pos) {
global_error_collector.prev = pos;
- error_out_pos(pos);
+ if (json_errors()) {
+ error_out_empty();
+ } else {
+ error_out_pos(pos);
+ }
if (has_ansi_terminal_colours()) {
error_out_coloured("Syntax_Error: ", TerminalStyle_Normal, TerminalColour_Red);
}
@@ -521,7 +565,11 @@ gb_internal void syntax_warning_va(TokenPos const &pos, TokenPos end, char const
// NOTE(bill): Duplicate error, skip it
if (global_error_collector.prev != pos) {
global_error_collector.prev = pos;
- error_out_pos(pos);
+ if (json_errors()) {
+ error_out_empty();
+ } else {
+ error_out_pos(pos);
+ }
error_out_coloured("Syntax Warning: ", TerminalStyle_Normal, TerminalColour_Yellow);
error_out_va(fmt, va);
error_out("\n");
@@ -633,109 +681,119 @@ gb_internal int error_value_cmp(void const *a, void const *b) {
}
gb_internal void print_all_errors(void) {
- auto const &escape_char = [](gbFile *f, u8 c) {
+ auto const &escape_char = [](gbString res, u8 c) -> gbString {
switch (c) {
- case '\n': gb_file_write(f, "\\n", 2); break;
- case '"': gb_file_write(f, "\\\"", 2); break;
- case '\\': gb_file_write(f, "\\\\", 2); break;
- case '\b': gb_file_write(f, "\\b", 2); break;
- case '\f': gb_file_write(f, "\\f", 2); break;
- case '\r': gb_file_write(f, "\\r", 2); break;
- case '\t': gb_file_write(f, "\\t", 2); break;
+ case '\n': res = gb_string_append_length(res, "\\n", 2); break;
+ case '"': res = gb_string_append_length(res, "\\\"", 2); break;
+ case '\\': res = gb_string_append_length(res, "\\\\", 2); break;
+ case '\b': res = gb_string_append_length(res, "\\b", 2); break;
+ case '\f': res = gb_string_append_length(res, "\\f", 2); break;
+ case '\r': res = gb_string_append_length(res, "\\r", 2); break;
+ case '\t': res = gb_string_append_length(res, "\\t", 2); break;
default:
if ('\x00' <= c && c <= '\x1f') {
- gb_fprintf(f, "\\u%04x", c);
+ res = gb_string_append_fmt(res, "\\u%04x", c);
} else {
- gb_file_write(f, &c, 1);
+ res = gb_string_append_length(res, &c, 1);
}
break;
}
+ return res;
};
GB_ASSERT(any_errors() || any_warnings());
- gbFile *f = gb_file_get_standard(gbFileStandard_Error);
+
array_sort(global_error_collector.error_values, error_value_cmp);
+ gbString res = gb_string_make(heap_allocator(), "");
+ defer (gb_string_free(res));
if (json_errors()) {
- gb_fprintf(f, "{\n");
- gb_fprintf(f, "\t\"error_count\": %td,\n", global_error_collector.error_values.count);
- gb_fprintf(f, "\t\"errors\": [\n");
+ res = gb_string_append_fmt(res, "{\n");
+ res = gb_string_append_fmt(res, "\t\"error_count\": %td,\n", global_error_collector.error_values.count);
+ res = gb_string_append_fmt(res, "\t\"errors\": [\n");
for_array(i, global_error_collector.error_values) {
ErrorValue ev = global_error_collector.error_values[i];
- gb_fprintf(f, "\t\t{\n");
+ res = gb_string_append_fmt(res, "\t\t{\n");
- gb_fprintf(f, "\t\t\t\"type\": \"");
+ res = gb_string_append_fmt(res, "\t\t\t\"type\": \"");
if (ev.kind == ErrorValue_Warning) {
- gb_fprintf(f, "warning");
+ res = gb_string_append_fmt(res, "warning");
} else {
- gb_fprintf(f, "error");
+ res = gb_string_append_fmt(res, "error");
}
- gb_fprintf(f, "\",\n");
+ res = gb_string_append_fmt(res, "\",\n");
- gb_fprintf(f, "\t\t\t\"pos\": {\n");
+ res = gb_string_append_fmt(res, "\t\t\t\"pos\": {\n");
if (ev.pos.file_id) {
- gb_fprintf(f, "\t\t\t\t\"file\": \"");
+ res = gb_string_append_fmt(res, "\t\t\t\t\"file\": \"");
String file = get_file_path_string(ev.pos.file_id);
for (isize k = 0; k < file.len; k++) {
- escape_char(f, file.text[k]);
+ res = escape_char(res, file.text[k]);
}
- gb_fprintf(f, "\",\n");
- gb_fprintf(f, "\t\t\t\t\"offset\": %d,\n", ev.pos.offset);
- gb_fprintf(f, "\t\t\t\t\"line\": %d,\n", ev.pos.line);
- gb_fprintf(f, "\t\t\t\t\"column\": %d,\n", ev.pos.column);
+ res = gb_string_append_fmt(res, "\",\n");
+ res = gb_string_append_fmt(res, "\t\t\t\t\"offset\": %d,\n", ev.pos.offset);
+ res = gb_string_append_fmt(res, "\t\t\t\t\"line\": %d,\n", ev.pos.line);
+ res = gb_string_append_fmt(res, "\t\t\t\t\"column\": %d,\n", ev.pos.column);
i32 end_column = gb_max(ev.end.column, ev.pos.column);
- gb_fprintf(f, "\t\t\t\t\"end_column\": %d\n", end_column);
- gb_fprintf(f, "\t\t\t},\n");
+ res = gb_string_append_fmt(res, "\t\t\t\t\"end_column\": %d\n", end_column);
+ res = gb_string_append_fmt(res, "\t\t\t},\n");
}
- gb_fprintf(f, "\t\t\t\"msgs\": [\n");
-
- if (ev.msgs.count > 1) {
- gb_fprintf(f, "\t\t\t\t\"");
-
- for (isize j = 1; j < ev.msgs.count; j++) {
- String msg = ev.msgs[j];
- for (isize k = 0; k < msg.len; k++) {
- u8 c = msg.text[k];
- if (c == '\n') {
- if (k+1 == msg.len && j+1 == ev.msgs.count) {
- // don't do the last one
- } else {
- gb_fprintf(f, "\",\n");
- gb_fprintf(f, "\t\t\t\t\"");
- }
- } else {
- escape_char(f, c);
- }
+ res = gb_string_append_fmt(res, "\t\t\t\"msgs\": [\n");
+
+ auto lines = split_lines_from_array(ev.msg, heap_allocator());
+ defer (array_free(&lines));
+
+ if (lines.count > 0) {
+ res = gb_string_append_fmt(res, "\t\t\t\t\"");
+
+ for (isize j = 0; j < lines.count; j++) {
+ String line = lines[j];
+ for (isize k = 0; k < line.len; k++) {
+ u8 c = line.text[k];
+ res = escape_char(res, c);
+ }
+ if (j+1 < lines.count) {
+ res = gb_string_append_fmt(res, "\",\n");
+ res = gb_string_append_fmt(res, "\t\t\t\t\"");
}
}
- gb_fprintf(f, "\"\n");
+ res = gb_string_append_fmt(res, "\"\n");
}
- gb_fprintf(f, "\t\t\t]\n");
- gb_fprintf(f, "\t\t}");
+ res = gb_string_append_fmt(res, "\t\t\t]\n");
+ res = gb_string_append_fmt(res, "\t\t}");
if (i+1 != global_error_collector.error_values.count) {
- gb_fprintf(f, ",");
+ res = gb_string_append_fmt(res, ",");
}
- gb_fprintf(f, "\n");
+ res = gb_string_append_fmt(res, "\n");
}
- gb_fprintf(f, "\t]\n");
- gb_fprintf(f, "}\n");
+ res = gb_string_append_fmt(res, "\t]\n");
+ res = gb_string_append_fmt(res, "}\n");
} else {
for_array(i, global_error_collector.error_values) {
ErrorValue ev = global_error_collector.error_values[i];
- for (isize j = 0; j < ev.msgs.count; j++) {
- String msg = ev.msgs[j];
- gb_file_write(f, msg.text, msg.len);
- if (terse_errors() && string_contains_char(msg, '\n')) {
+ String_Iterator it = {{ev.msg.data, ev.msg.count}, 0};
+
+ for (isize line_idx = 0; /**/; line_idx++) {
+ String line = string_split_iterator(&it, '\n');
+ if (line.len == 0) {
+ break;
+ }
+ line = string_trim_trailing_whitespace(line);
+ res = gb_string_append_length(res, line.text, line.len);
+ res = gb_string_append_length(res, " \n", 2);
+ if (line_idx == 0 && terse_errors()) {
break;
}
}
}
}
+ gbFile *f = gb_file_get_standard(gbFileStandard_Error);
+ gb_file_write(f, res, gb_string_length(res));
} \ No newline at end of file
diff --git a/src/llvm_abi.cpp b/src/llvm_abi.cpp
index 88bb58c55..85a16d321 100644
--- a/src/llvm_abi.cpp
+++ b/src/llvm_abi.cpp
@@ -1131,8 +1131,9 @@ namespace lbAbiArm64 {
if (size <= 16) {
LLVMTypeRef cast_type = nullptr;
- GB_ASSERT(size > 0);
- if (size <= 8) {
+ if (size == 0) {
+ cast_type = LLVMStructTypeInContext(c, nullptr, 0, false);
+ } else if (size <= 8) {
cast_type = LLVMIntTypeInContext(c, cast(unsigned)(size*8));
} else {
unsigned count = cast(unsigned)((size+7)/8);
diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp
index 645a091b0..4b94cf020 100644
--- a/src/llvm_backend.cpp
+++ b/src/llvm_backend.cpp
@@ -2659,7 +2659,7 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
LLVMSetInitializer(g, LLVMConstNull(internal_llvm_type));
LLVMSetLinkage(g, USE_SEPARATE_MODULES ? LLVMExternalLinkage : LLVMInternalLinkage);
LLVMSetUnnamedAddress(g, LLVMGlobalUnnamedAddr);
- LLVMSetGlobalConstant(g, /*true*/false);
+ LLVMSetGlobalConstant(g, true);
lbValue value = {};
value.value = g;
diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp
index c4bf2691d..7dc5f6b63 100644
--- a/src/llvm_backend.hpp
+++ b/src/llvm_backend.hpp
@@ -122,7 +122,6 @@ struct lbAddr {
} swizzle_large;
struct {
Type *type;
- i64 index;
i64 bit_offset;
i64 bit_size;
} bitfield;
diff --git a/src/llvm_backend_debug.cpp b/src/llvm_backend_debug.cpp
index 511ff0475..2654a1d28 100644
--- a/src/llvm_backend_debug.cpp
+++ b/src/llvm_backend_debug.cpp
@@ -739,6 +739,7 @@ gb_internal LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) {
}
case Type_Map: {
+ init_map_internal_debug_types(type);
Type *bt = base_type(type->Map.debug_metadata_type);
GB_ASSERT(bt->kind == Type_Struct);
@@ -945,6 +946,7 @@ gb_internal LLVMMetadataRef lb_debug_type(lbModule *m, Type *type) {
}
case Type_Map: {
+ init_map_internal_debug_types(bt);
bt = base_type(bt->Map.debug_metadata_type);
GB_ASSERT(bt->kind == Type_Struct);
return lb_debug_struct(m, type, bt, name, scope, file, line);
@@ -1025,7 +1027,7 @@ gb_internal void lb_add_debug_local_variable(lbProcedure *p, LLVMValueRef ptr, T
LLVMDIBuilderInsertDeclareAtEnd(m->debug_builder, storage, var_info, llvm_expr, llvm_debug_loc, block);
}
-gb_internal void lb_add_debug_param_variable(lbProcedure *p, LLVMValueRef ptr, Type *type, Token const &token, unsigned arg_number, lbBlock *block, lbArgKind arg_kind) {
+gb_internal void lb_add_debug_param_variable(lbProcedure *p, LLVMValueRef ptr, Type *type, Token const &token, unsigned arg_number, lbBlock *block) {
if (p->debug_info == nullptr) {
return;
}
@@ -1086,15 +1088,7 @@ gb_internal void lb_add_debug_param_variable(lbProcedure *p, LLVMValueRef ptr, T
// NOTE(bill, 2022-02-01): For parameter values, you must insert them at the end of the decl block
// The reason is that if the parameter is at index 0 and a pointer, there is not such things as an
// instruction "before" it.
- switch (arg_kind) {
- case lbArg_Direct:
- LLVMDIBuilderInsertDbgValueAtEnd(m->debug_builder, storage, var_info, llvm_expr, llvm_debug_loc, block->block);
- break;
- case lbArg_Indirect:
- LLVMDIBuilderInsertDeclareAtEnd(m->debug_builder, storage, var_info, llvm_expr, llvm_debug_loc, block->block);
- break;
- }
-
+ LLVMDIBuilderInsertDeclareAtEnd(m->debug_builder, storage, var_info, llvm_expr, llvm_debug_loc, block->block);
}
diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp
index fcec59968..ee1a384ae 100644
--- a/src/llvm_backend_expr.cpp
+++ b/src/llvm_backend_expr.cpp
@@ -2138,14 +2138,45 @@ gb_internal lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) {
if (is_type_array_like(dst)) {
Type *elem = base_array_type(dst);
+ isize index_count = cast(isize)get_array_type_count(dst);
+
+ isize inlineable = type_size_of(dst) <= build_context.max_simd_align;
lbValue e = lb_emit_conv(p, value, elem);
+ if (inlineable && lb_is_const(e)) {
+ lbAddr v = {};
+ if (e.value) {
+ TEMPORARY_ALLOCATOR_GUARD();
+ LLVMValueRef *values = gb_alloc_array(temporary_allocator(), LLVMValueRef, index_count);
+ for (isize i = 0; i < index_count; i++) {
+ values[i] = e.value;
+ }
+ lbValue array_const_value = {};
+ array_const_value.type = t;
+ array_const_value.value = LLVMConstArray(lb_type(m, elem), values, cast(unsigned)index_count);
+ v = lb_add_global_generated(m, t, array_const_value);
+ } else {
+ v = lb_add_global_generated(m, t);
+ }
+
+ lb_make_global_private_const(v);
+ return lb_addr_load(p, v);
+ }
+
// NOTE(bill): Doesn't need to be zero because it will be initialized in the loops
lbAddr v = lb_add_local_generated(p, t, false);
- isize index_count = cast(isize)get_array_type_count(dst);
- for (isize i = 0; i < index_count; i++) {
- lbValue elem = lb_emit_array_epi(p, v.addr, i);
+ if (!inlineable) {
+ auto loop_data = lb_loop_start(p, index_count, t_int);
+
+ lbValue elem = lb_emit_array_ep(p, v.addr, loop_data.idx);
lb_emit_store(p, elem, e);
+
+ lb_loop_end(p, loop_data);
+ } else {
+ for (isize i = 0; i < index_count; i++) {
+ lbValue elem = lb_emit_array_epi(p, v.addr, i);
+ lb_emit_store(p, elem, e);
+ }
}
return lb_addr_load(p, v);
}
@@ -3085,7 +3116,7 @@ gb_internal lbValue lb_build_unary_and(lbProcedure *p, Ast *expr) {
Type *dst_type = type;
- if ((p->state_flags & StateFlag_no_type_assert) == 0) {
+ if (!build_context.no_type_assert && (p->state_flags & StateFlag_no_type_assert) == 0) {
lbValue src_tag = {};
lbValue dst_tag = {};
if (is_type_union_maybe_pointer(src_type)) {
@@ -3125,7 +3156,7 @@ gb_internal lbValue lb_build_unary_and(lbProcedure *p, Ast *expr) {
v = lb_emit_load(p, v);
}
lbValue data_ptr = lb_emit_struct_ev(p, v, 0);
- if ((p->state_flags & StateFlag_no_type_assert) == 0) {
+ if (!build_context.no_type_assert && (p->state_flags & StateFlag_no_type_assert) == 0) {
GB_ASSERT(!build_context.no_rtti);
lbValue any_id = lb_emit_struct_ev(p, v, 1);
@@ -4265,7 +4296,19 @@ gb_internal lbAddr lb_build_addr_compound_lit(lbProcedure *p, Ast *expr) {
switch (bt->kind) {
default: GB_PANIC("Unknown CompoundLit type: %s", type_to_string(type)); break;
- case Type_BitField:
+ case Type_BitField: {
+ TEMPORARY_ALLOCATOR_GUARD();
+
+ // Type *backing_type = core_type(bt->BitField.backing_type);
+
+ struct FieldData {
+ Type *field_type;
+ u64 bit_offset;
+ u64 bit_size;
+ };
+ auto values = array_make<lbValue>(temporary_allocator(), 0, cl->elems.count);
+ auto fields = array_make<FieldData>(temporary_allocator(), 0, cl->elems.count);
+
for (Ast *elem : cl->elems) {
ast_node(fv, FieldValue, elem);
String name = fv->field->Ident.token.string;
@@ -4276,26 +4319,172 @@ gb_internal lbAddr lb_build_addr_compound_lit(lbProcedure *p, Ast *expr) {
GB_ASSERT(sel.entity != nullptr);
i64 index = sel.index[0];
- i64 bit_offset = 0;
- i64 bit_size = -1;
- for_array(i, bt->BitField.fields) {
- Entity *f = bt->BitField.fields[i];
- if (f == sel.entity) {
- bit_offset = bt->BitField.bit_offsets[i];
- bit_size = bt->BitField.bit_sizes[i];
- break;
- }
- }
+ Entity *f = bt->BitField.fields[index];
+ GB_ASSERT(f == sel.entity);
+ i64 bit_offset = bt->BitField.bit_offsets[index];
+ i64 bit_size = bt->BitField.bit_sizes[index];
GB_ASSERT(bit_size > 0);
Type *field_type = sel.entity->type;
lbValue field_expr = lb_build_expr(p, fv->value);
field_expr = lb_emit_conv(p, field_expr, field_type);
+ array_add(&values, field_expr);
+ array_add(&fields, FieldData{field_type, cast(u64)bit_offset, cast(u64)bit_size});
+ }
+
+ // NOTE(bill): inline insertion sort should be good enough, right?
+ for (isize i = 1; i < values.count; i++) {
+ for (isize j = i;
+ j > 0 && fields[i].bit_offset < fields[j].bit_offset;
+ j--) {
+ auto vtmp = values[j];
+ values[j] = values[j-1];
+ values[j-1] = vtmp;
+
+ auto ftmp = fields[j];
+ fields[j] = fields[j-1];
+ fields[j-1] = ftmp;
+ }
+ }
+
+ bool any_fields_different_endian = false;
+ for (auto const &f : fields) {
+ if (is_type_different_to_arch_endianness(f.field_type)) {
+ // NOTE(bill): Just be slow for this, to be correct
+ any_fields_different_endian = true;
+ break;
+ }
+ }
+
+ if (!any_fields_different_endian &&
+ fields.count == bt->BitField.fields.count) {
+ // SINGLE INTEGER BACKING ONLY
+
+ Type *backing_type = core_type(bt->BitField.backing_type);
+ GB_ASSERT(is_type_integer(backing_type) ||
+ (is_type_array(backing_type) && is_type_integer(backing_type->Array.elem)));
+
+ // NOTE(bill): all fields are present
+ // this means no masking is necessary since on write, the bits will be overridden
+
+ lbValue dst_byte_ptr = lb_emit_conv(p, v.addr, t_u8_ptr);
+ u64 total_bit_size = cast(u64)(8*type_size_of(bt));
+
+ if (is_type_integer(backing_type)) {
+ LLVMTypeRef lit = lb_type(p->module, backing_type);
+
+ LLVMValueRef res = LLVMConstInt(lit, 0, false);
+
+ for (isize i = 0; i < fields.count; i++) {
+ auto const &f = fields[i];
+
+ LLVMValueRef mask = LLVMConstInt(lit, 1, false);
+ mask = LLVMConstShl(mask, LLVMConstInt(lit, f.bit_size, false));
+ mask = LLVMConstSub(mask, LLVMConstInt(lit, 1, false));
+
+ LLVMValueRef elem = values[i].value;
+ elem = LLVMBuildZExt(p->builder, elem, lit, "");
+ elem = LLVMBuildAnd(p->builder, elem, mask, "");
- lbAddr field_addr = lb_addr_bit_field(v.addr, field_type, index, bit_offset, bit_size);
- lb_addr_store(p, field_addr, field_expr);
+ elem = LLVMBuildShl(p->builder, elem, LLVMConstInt(lit, f.bit_offset, false), "");
+
+ res = LLVMBuildOr(p->builder, res, elem, "");
+ }
+
+ LLVMBuildStore(p->builder, res, v.addr.value);
+ } else if (is_type_array(backing_type)) {
+ // ARRAY OF INTEGER BACKING
+
+ i64 array_count = backing_type->Array.count;
+ LLVMTypeRef lit = lb_type(p->module, core_type(backing_type->Array.elem));
+ gb_unused(array_count);
+ gb_unused(lit);
+
+ LLVMValueRef *elems = gb_alloc_array(temporary_allocator(), LLVMValueRef, array_count);
+ for (i64 i = 0; i < array_count; i++) {
+ elems[i] = LLVMConstInt(lit, 0, false);
+ }
+
+ u64 elem_bit_size = cast(u64)(8*type_size_of(backing_type->Array.elem));
+ u64 curr_bit_offset = 0;
+ for (isize i = 0; i < fields.count; i++) {
+ auto const &f = fields[i];
+
+ LLVMValueRef val = values[i].value;
+ LLVMTypeRef vt = lb_type(p->module, values[i].type);
+ for (u64 bits_to_set = f.bit_size;
+ bits_to_set > 0;
+ /**/) {
+ i64 elem_idx = curr_bit_offset/elem_bit_size;
+ u64 elem_bit_offset = curr_bit_offset%elem_bit_size;
+
+ u64 mask_width = gb_min(bits_to_set, elem_bit_size-elem_bit_offset);
+ GB_ASSERT(mask_width > 0);
+ bits_to_set -= mask_width;
+
+ LLVMValueRef mask = LLVMConstInt(vt, 1, false);
+ mask = LLVMConstShl(mask, LLVMConstInt(vt, mask_width, false));
+ mask = LLVMConstSub(mask, LLVMConstInt(vt, 1, false));
+
+ LLVMValueRef to_set = LLVMBuildAnd(p->builder, val, mask, "");
+
+ if (elem_bit_offset != 0) {
+ to_set = LLVMBuildShl(p->builder, to_set, LLVMConstInt(vt, elem_bit_offset, false), "");
+ }
+ to_set = LLVMBuildTrunc(p->builder, to_set, lit, "");
+
+ if (LLVMIsNull(elems[elem_idx])) {
+ elems[elem_idx] = to_set; // don't even bother doing `0 | to_set`
+ } else {
+ elems[elem_idx] = LLVMBuildOr(p->builder, elems[elem_idx], to_set, "");
+ }
+
+ if (mask_width != 0) {
+ val = LLVMBuildLShr(p->builder, val, LLVMConstInt(vt, mask_width, false), "");
+ }
+ curr_bit_offset += mask_width;
+ }
+
+ GB_ASSERT(curr_bit_offset == f.bit_offset + f.bit_size);
+ }
+
+ for (i64 i = 0; i < array_count; i++) {
+ LLVMValueRef elem_ptr = LLVMBuildStructGEP2(p->builder, lb_type(p->module, backing_type), v.addr.value, cast(unsigned)i, "");
+ LLVMBuildStore(p->builder, elems[i], elem_ptr);
+ }
+ } else {
+ // SLOW STORAGE
+
+ for_array(i, fields) {
+ auto const &f = fields[i];
+
+ if ((f.bit_offset & 7) == 0) {
+ u64 unpacked_bit_size = cast(u64)(8*type_size_of(f.field_type));
+ u64 byte_size = (f.bit_size+7)/8;
+
+ if (f.bit_offset + unpacked_bit_size <= total_bit_size) {
+ byte_size = unpacked_bit_size/8;
+ }
+ lbValue dst = lb_emit_ptr_offset(p, dst_byte_ptr, lb_const_int(p->module, t_int, f.bit_offset/8));
+ lbValue src = lb_address_from_load_or_generate_local(p, values[i]);
+ lb_mem_copy_non_overlapping(p, dst, src, lb_const_int(p->module, t_uintptr, byte_size));
+ } else {
+ lbAddr dst = lb_addr_bit_field(v.addr, f.field_type, f.bit_offset, f.bit_size);
+ lb_addr_store(p, dst, values[i]);
+ }
+ }
+ }
+ } else {
+ // individual storing
+ for_array(i, values) {
+ auto const &f = fields[i];
+ lbAddr dst = lb_addr_bit_field(v.addr, f.field_type, f.bit_offset, f.bit_size);
+ lb_addr_store(p, dst, values[i]);
+ }
}
+
return v;
+ }
case Type_Struct: {
// TODO(bill): "constant" '#raw_union's are not initialized constantly at the moment.
@@ -4740,7 +4929,7 @@ gb_internal lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) {
u8 bit_size = bf_type->BitField.bit_sizes[index];
i64 bit_offset = bf_type->BitField.bit_offsets[index];
- return lb_addr_bit_field(ptr, f->type, index, bit_offset, bit_size);
+ return lb_addr_bit_field(ptr, f->type, bit_offset, bit_size);
}
{
diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp
index 0d8d9258a..02afa628c 100644
--- a/src/llvm_backend_general.cpp
+++ b/src/llvm_backend_general.cpp
@@ -211,7 +211,7 @@ gb_internal void lb_loop_end(lbProcedure *p, lbLoopData const &data) {
gb_internal void lb_make_global_private_const(LLVMValueRef global_data) {
- LLVMSetLinkage(global_data, LLVMPrivateLinkage);
+ LLVMSetLinkage(global_data, LLVMLinkerPrivateLinkage);
LLVMSetUnnamedAddress(global_data, LLVMGlobalUnnamedAddr);
LLVMSetGlobalConstant(global_data, true);
}
@@ -450,14 +450,13 @@ gb_internal lbAddr lb_addr_swizzle_large(lbValue addr, Type *array_type, Slice<i
return v;
}
-gb_internal lbAddr lb_addr_bit_field(lbValue addr, Type *type, i64 index, i64 bit_offset, i64 bit_size) {
+gb_internal lbAddr lb_addr_bit_field(lbValue addr, Type *type, i64 bit_offset, i64 bit_size) {
GB_ASSERT(is_type_pointer(addr.type));
Type *mt = type_deref(addr.type);
GB_ASSERT_MSG(is_type_bit_field(mt), "%s", type_to_string(mt));
lbAddr v = {lbAddr_BitField, addr};
v.bitfield.type = type;
- v.bitfield.index = index;
v.bitfield.bit_offset = bit_offset;
v.bitfield.bit_size = bit_size;
return v;
@@ -774,13 +773,40 @@ gb_internal void lb_addr_store(lbProcedure *p, lbAddr addr, lbValue value) {
if (addr.kind == lbAddr_BitField) {
lbValue dst = addr.addr;
+ if (is_type_endian_big(addr.bitfield.type)) {
+ i64 shift_amount = 8*type_size_of(value.type) - addr.bitfield.bit_size;
+ lbValue shifted_value = value;
+ shifted_value.value = LLVMBuildLShr(p->builder,
+ shifted_value.value,
+ LLVMConstInt(LLVMTypeOf(shifted_value.value), shift_amount, false), "");
+
+ lbValue src = lb_address_from_load_or_generate_local(p, shifted_value);
+
+ auto args = array_make<lbValue>(temporary_allocator(), 4);
+ args[0] = dst;
+ args[1] = src;
+ args[2] = lb_const_int(p->module, t_uintptr, addr.bitfield.bit_offset);
+ args[3] = lb_const_int(p->module, t_uintptr, addr.bitfield.bit_size);
+ lb_emit_runtime_call(p, "__write_bits", args);
+ } else if ((addr.bitfield.bit_offset % 8) == 0 &&
+ (addr.bitfield.bit_size % 8) == 0) {
+ lbValue src = lb_address_from_load_or_generate_local(p, value);
+
+ lbValue byte_offset = lb_const_int(p->module, t_uintptr, addr.bitfield.bit_offset/8);
+ lbValue byte_size = lb_const_int(p->module, t_uintptr, addr.bitfield.bit_size/8);
+ lbValue dst_offset = lb_emit_conv(p, dst, t_u8_ptr);
+ dst_offset = lb_emit_ptr_offset(p, dst_offset, byte_offset);
+ lb_mem_copy_non_overlapping(p, dst_offset, src, byte_size);
+ } else {
+ lbValue src = lb_address_from_load_or_generate_local(p, value);
- auto args = array_make<lbValue>(temporary_allocator(), 4);
- args[0] = dst;
- args[1] = lb_address_from_load_or_generate_local(p, value);
- args[2] = lb_const_int(p->module, t_uintptr, addr.bitfield.bit_offset);
- args[3] = lb_const_int(p->module, t_uintptr, addr.bitfield.bit_size);
- lb_emit_runtime_call(p, "__write_bits", args);
+ auto args = array_make<lbValue>(temporary_allocator(), 4);
+ args[0] = dst;
+ args[1] = src;
+ args[2] = lb_const_int(p->module, t_uintptr, addr.bitfield.bit_offset);
+ args[3] = lb_const_int(p->module, t_uintptr, addr.bitfield.bit_size);
+ lb_emit_runtime_call(p, "__write_bits", args);
+ }
return;
} else if (addr.kind == lbAddr_RelativePointer) {
Type *rel_ptr = base_type(lb_addr_type(addr));
@@ -954,16 +980,6 @@ gb_internal void lb_addr_store(lbProcedure *p, lbAddr addr, lbValue value) {
GB_ASSERT(value.value != nullptr);
value = lb_emit_conv(p, value, lb_addr_type(addr));
- // if (lb_is_const_or_global(value)) {
- // // NOTE(bill): Just bypass the actual storage and set the initializer
- // if (LLVMGetValueKind(addr.addr.value) == LLVMGlobalVariableValueKind) {
- // LLVMValueRef dst = addr.addr.value;
- // LLVMValueRef src = value.value;
- // LLVMSetInitializer(dst, src);
- // return;
- // }
- // }
-
lb_emit_store(p, addr.addr, value);
}
@@ -1098,23 +1114,76 @@ gb_internal lbValue lb_addr_load(lbProcedure *p, lbAddr const &addr) {
GB_ASSERT(addr.addr.value != nullptr);
if (addr.kind == lbAddr_BitField) {
+ Type *ct = core_type(addr.bitfield.type);
+ bool do_mask = false;
+ if (is_type_unsigned(ct) || is_type_boolean(ct)) {
+ // Mask
+ if (addr.bitfield.bit_size != 8*type_size_of(ct)) {
+ do_mask = true;
+ }
+ }
+
+ i64 total_bitfield_bit_size = 8*type_size_of(lb_addr_type(addr));
+ i64 dst_byte_size = type_size_of(addr.bitfield.type);
lbAddr dst = lb_add_local_generated(p, addr.bitfield.type, true);
lbValue src = addr.addr;
- auto args = array_make<lbValue>(temporary_allocator(), 4);
- args[0] = dst.addr;
- args[1] = src;
- args[2] = lb_const_int(p->module, t_uintptr, addr.bitfield.bit_offset);
- args[3] = lb_const_int(p->module, t_uintptr, addr.bitfield.bit_size);
- lb_emit_runtime_call(p, "__read_bits", args);
+ lbValue bit_offset = lb_const_int(p->module, t_uintptr, addr.bitfield.bit_offset);
+ lbValue bit_size = lb_const_int(p->module, t_uintptr, addr.bitfield.bit_size);
+ lbValue byte_offset = lb_const_int(p->module, t_uintptr, (addr.bitfield.bit_offset+7)/8);
+ lbValue byte_size = lb_const_int(p->module, t_uintptr, (addr.bitfield.bit_size+7)/8);
+
+ GB_ASSERT(type_size_of(addr.bitfield.type) >= ((addr.bitfield.bit_size+7)/8));
+
+ lbValue r = {};
+ if (is_type_endian_big(addr.bitfield.type)) {
+ auto args = array_make<lbValue>(temporary_allocator(), 4);
+ args[0] = dst.addr;
+ args[1] = src;
+ args[2] = bit_offset;
+ args[3] = bit_size;
+ lb_emit_runtime_call(p, "__read_bits", args);
+
+ LLVMValueRef shift_amount = LLVMConstInt(
+ lb_type(p->module, lb_addr_type(dst)),
+ 8*dst_byte_size - addr.bitfield.bit_size,
+ false
+ );
+ r = lb_addr_load(p, dst);
+ r.value = LLVMBuildShl(p->builder, r.value, shift_amount, "");
+ } else if ((addr.bitfield.bit_offset % 8) == 0) {
+ lbValue copy_size = byte_size;
+ lbValue src_offset = lb_emit_conv(p, src, t_u8_ptr);
+ src_offset = lb_emit_ptr_offset(p, src_offset, byte_offset);
+ if (addr.bitfield.bit_offset + dst_byte_size <= total_bitfield_bit_size) {
+ do_mask = true;
+ copy_size = lb_const_int(p->module, t_uintptr, dst_byte_size);
+ }
+ lb_mem_copy_non_overlapping(p, dst.addr, src_offset, copy_size, false);
+ r = lb_addr_load(p, dst);
+ } else {
+ auto args = array_make<lbValue>(temporary_allocator(), 4);
+ args[0] = dst.addr;
+ args[1] = src;
+ args[2] = bit_offset;
+ args[3] = bit_size;
+ lb_emit_runtime_call(p, "__read_bits", args);
+ r = lb_addr_load(p, dst);
+ }
- lbValue r = lb_addr_load(p, dst);
+ Type *t = addr.bitfield.type;
+
+ if (do_mask) {
+ GB_ASSERT(addr.bitfield.bit_size < 8*type_size_of(ct));
+
+ lbValue mask = lb_const_int(p->module, t, (1ull<<cast(u64)addr.bitfield.bit_size)-1);
+ r = lb_emit_arith(p, Token_And, r, mask, t);
+ }
- if (!is_type_unsigned(core_type(addr.bitfield.type))) {
+ if (!is_type_unsigned(ct) && !is_type_boolean(ct)) {
// Sign extension
// m := 1<<(bit_size-1)
// r = (r XOR m) - m
- Type *t = addr.bitfield.type;
lbValue m = lb_const_int(p->module, t, 1ull<<(addr.bitfield.bit_size-1));
r = lb_emit_arith(p, Token_Xor, r, m, t);
r = lb_emit_arith(p, Token_Sub, r, m, t);
@@ -2080,7 +2149,7 @@ gb_internal LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
break;
case Type_Map:
- init_map_internal_types(type);
+ init_map_internal_debug_types(type);
GB_ASSERT(t_raw_map != nullptr);
return lb_type_internal(m, t_raw_map);
diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp
index bb4aed3f1..f73698d34 100644
--- a/src/llvm_backend_proc.cpp
+++ b/src/llvm_backend_proc.cpp
@@ -597,16 +597,7 @@ gb_internal void lb_begin_procedure_body(lbProcedure *p) {
lbValue ptr = lb_address_from_load_or_generate_local(p, param);
GB_ASSERT(LLVMIsAAllocaInst(ptr.value));
lb_add_entity(p->module, e, ptr);
-
- lbBlock *block = p->decl_block;
- if (original_value != value) {
- block = p->curr_block;
- }
- LLVMValueRef debug_storage_value = value;
- if (original_value != value && LLVMIsALoadInst(value)) {
- debug_storage_value = LLVMGetOperand(value, 0);
- }
- lb_add_debug_param_variable(p, debug_storage_value, e->type, e->token, param_index+1, block, arg_type->kind);
+ lb_add_debug_param_variable(p, ptr.value, e->type, e->token, param_index+1, p->curr_block);
}
} else if (arg_type->kind == lbArg_Indirect) {
if (e->token.string.len != 0 && !is_blank_ident(e->token.string)) {
@@ -614,7 +605,7 @@ gb_internal void lb_begin_procedure_body(lbProcedure *p) {
ptr.value = LLVMGetParam(p->value, param_offset+param_index);
ptr.type = alloc_type_pointer(e->type);
lb_add_entity(p->module, e, ptr);
- lb_add_debug_param_variable(p, ptr.value, e->type, e->token, param_index+1, p->decl_block, arg_type->kind);
+ lb_add_debug_param_variable(p, ptr.value, e->type, e->token, param_index+1, p->decl_block);
}
}
}
diff --git a/src/llvm_backend_type.cpp b/src/llvm_backend_type.cpp
index 93e2874a5..e202a59ba 100644
--- a/src/llvm_backend_type.cpp
+++ b/src/llvm_backend_type.cpp
@@ -249,9 +249,7 @@ gb_internal void lb_setup_type_info_data_giant_array(lbModule *m, i64 global_typ
char name[64] = {};
gb_snprintf(name, 63, "__$ti-%lld", cast(long long)index);
LLVMValueRef g = LLVMAddGlobal(m->mod, type, name);
- LLVMSetLinkage(g, LLVMInternalLinkage);
- LLVMSetUnnamedAddress(g, LLVMGlobalUnnamedAddr);
- LLVMSetGlobalConstant(g, true);
+ lb_make_global_private_const(g);
return g;
};
@@ -903,7 +901,7 @@ gb_internal void lb_setup_type_info_data_giant_array(lbModule *m, i64 global_typ
case Type_Map: {
tag_type = t_type_info_map;
- init_map_internal_types(t);
+ init_map_internal_debug_types(t);
LLVMValueRef vals[3] = {
get_type_info_ptr(m, t->Map.key),
@@ -1103,6 +1101,7 @@ gb_internal void lb_setup_type_info_data_giant_array(lbModule *m, i64 global_typ
LLVMValueRef giant_const = LLVMConstArray(lb_type(m, t_type_info_ptr), giant_const_values, cast(unsigned)global_type_info_data_entity_count);
LLVMValueRef giant_array = lb_global_type_info_data_ptr(m).value;
LLVMSetInitializer(giant_array, giant_const);
+ lb_make_global_private_const(giant_array);
}
@@ -1132,4 +1131,7 @@ gb_internal void lb_setup_type_info_data(lbModule *m) { // NOTE(bill): Setup typ
LLVMValueRef slice = llvm_const_slice_internal(m, data, len);
LLVMSetInitializer(global_type_table.value, slice);
+
+ // force it to be constant
+ LLVMSetGlobalConstant(global_type_table.value, true);
}
diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp
index 865c3f1ec..c01ab0692 100644
--- a/src/llvm_backend_utility.cpp
+++ b/src/llvm_backend_utility.cpp
@@ -97,15 +97,12 @@ gb_internal void lb_mem_zero_ptr(lbProcedure *p, LLVMValueRef ptr, Type *type, u
LLVMTypeRef llvm_type = lb_type(p->module, type);
LLVMTypeKind kind = LLVMGetTypeKind(llvm_type);
-
+ i64 sz = type_size_of(type);
switch (kind) {
case LLVMStructTypeKind:
case LLVMArrayTypeKind:
- {
- // NOTE(bill): Enforce zeroing through memset to make sure padding is zeroed too
- i32 sz = cast(i32)type_size_of(type);
- lb_mem_zero_ptr_internal(p, ptr, lb_const_int(p->module, t_int, sz).value, alignment, false);
- }
+ // NOTE(bill): Enforce zeroing through memset to make sure padding is zeroed too
+ lb_mem_zero_ptr_internal(p, ptr, lb_const_int(p->module, t_int, sz).value, alignment, false);
break;
default:
LLVMBuildStore(p->builder, LLVMConstNull(lb_type(p->module, type)), ptr);
@@ -728,29 +725,31 @@ gb_internal lbValue lb_emit_union_cast(lbProcedure *p, lbValue value, Type *type
lb_start_block(p, end_block);
if (!is_tuple) {
- GB_ASSERT((p->state_flags & StateFlag_no_type_assert) == 0);
- // NOTE(bill): Panic on invalid conversion
- Type *dst_type = tuple->Tuple.variables[0]->type;
-
- isize arg_count = 7;
- if (build_context.no_rtti) {
- arg_count = 4;
- }
+ if (!build_context.no_type_assert) {
+ GB_ASSERT((p->state_flags & StateFlag_no_type_assert) == 0);
+ // NOTE(bill): Panic on invalid conversion
+ Type *dst_type = tuple->Tuple.variables[0]->type;
+
+ isize arg_count = 7;
+ if (build_context.no_rtti) {
+ arg_count = 4;
+ }
- lbValue ok = lb_emit_load(p, lb_emit_struct_ep(p, v.addr, 1));
- auto args = array_make<lbValue>(permanent_allocator(), arg_count);
- args[0] = ok;
+ lbValue ok = lb_emit_load(p, lb_emit_struct_ep(p, v.addr, 1));
+ auto args = array_make<lbValue>(permanent_allocator(), arg_count);
+ args[0] = ok;
- args[1] = lb_const_string(m, get_file_path_string(pos.file_id));
- args[2] = lb_const_int(m, t_i32, pos.line);
- args[3] = lb_const_int(m, t_i32, pos.column);
+ args[1] = lb_const_string(m, get_file_path_string(pos.file_id));
+ args[2] = lb_const_int(m, t_i32, pos.line);
+ args[3] = lb_const_int(m, t_i32, pos.column);
- if (!build_context.no_rtti) {
- args[4] = lb_typeid(m, src_type);
- args[5] = lb_typeid(m, dst_type);
- args[6] = lb_emit_conv(p, value_, t_rawptr);
+ if (!build_context.no_rtti) {
+ args[4] = lb_typeid(m, src_type);
+ args[5] = lb_typeid(m, dst_type);
+ args[6] = lb_emit_conv(p, value_, t_rawptr);
+ }
+ lb_emit_runtime_call(p, "type_assertion_check2", args);
}
- lb_emit_runtime_call(p, "type_assertion_check2", args);
return lb_emit_load(p, lb_emit_struct_ep(p, v.addr, 0));
}
@@ -806,25 +805,27 @@ gb_internal lbAddr lb_emit_any_cast_addr(lbProcedure *p, lbValue value, Type *ty
if (!is_tuple) {
// NOTE(bill): Panic on invalid conversion
- lbValue ok = lb_emit_load(p, lb_emit_struct_ep(p, v.addr, 1));
+ if (!build_context.no_type_assert) {
+ lbValue ok = lb_emit_load(p, lb_emit_struct_ep(p, v.addr, 1));
- isize arg_count = 7;
- if (build_context.no_rtti) {
- arg_count = 4;
- }
- auto args = array_make<lbValue>(permanent_allocator(), arg_count);
- args[0] = ok;
+ isize arg_count = 7;
+ if (build_context.no_rtti) {
+ arg_count = 4;
+ }
+ auto args = array_make<lbValue>(permanent_allocator(), arg_count);
+ args[0] = ok;
- args[1] = lb_const_string(m, get_file_path_string(pos.file_id));
- args[2] = lb_const_int(m, t_i32, pos.line);
- args[3] = lb_const_int(m, t_i32, pos.column);
+ args[1] = lb_const_string(m, get_file_path_string(pos.file_id));
+ args[2] = lb_const_int(m, t_i32, pos.line);
+ args[3] = lb_const_int(m, t_i32, pos.column);
- if (!build_context.no_rtti) {
- args[4] = any_typeid;
- args[5] = dst_typeid;
- args[6] = lb_emit_struct_ev(p, value, 0);
+ if (!build_context.no_rtti) {
+ args[4] = any_typeid;
+ args[5] = dst_typeid;
+ args[6] = lb_emit_struct_ev(p, value, 0);
+ }
+ lb_emit_runtime_call(p, "type_assertion_check2", args);
}
- lb_emit_runtime_call(p, "type_assertion_check2", args);
return lb_addr(lb_emit_struct_ep(p, v.addr, 0));
}
@@ -1125,7 +1126,7 @@ gb_internal lbValue lb_emit_struct_ep(lbProcedure *p, lbValue s, i32 index) {
case 3: result_type = t_allocator; break;
}
} else if (is_type_map(t)) {
- init_map_internal_types(t);
+ init_map_internal_debug_types(t);
Type *itp = alloc_type_pointer(t_raw_map);
s = lb_emit_transmute(p, s, itp);
@@ -1264,7 +1265,7 @@ gb_internal lbValue lb_emit_struct_ev(lbProcedure *p, lbValue s, i32 index) {
case Type_Map:
{
- init_map_internal_types(t);
+ init_map_internal_debug_types(t);
switch (index) {
case 0: result_type = get_struct_field_type(t_raw_map, 0); break;
case 1: result_type = get_struct_field_type(t_raw_map, 1); break;
diff --git a/src/main.cpp b/src/main.cpp
index 2dbb72ca2..ee7de7f81 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -198,7 +198,12 @@ gb_internal void print_usage_line(i32 indent, char const *fmt, ...) {
gb_printf("\n");
}
-gb_internal void usage(String argv0) {
+gb_internal void usage(String argv0, String argv1 = {}) {
+ if (argv1 == "run.") {
+ print_usage_line(0, "Did you mean 'odin run .'?");
+ } else if (argv1 == "build.") {
+ print_usage_line(0, "Did you mean 'odin build .'?");
+ }
print_usage_line(0, "%.*s is a tool for managing Odin source code.", LIT(argv0));
print_usage_line(0, "Usage:");
print_usage_line(1, "%.*s command [arguments]", LIT(argv0));
@@ -212,6 +217,7 @@ gb_internal void usage(String argv0) {
print_usage_line(1, "doc Generates documentation on a directory of .odin files.");
print_usage_line(1, "version Prints version.");
print_usage_line(1, "report Prints information useful to reporting a bug.");
+ print_usage_line(1, "root Prints the root path where Odin looks for the builtin collections.");
print_usage_line(0, "");
print_usage_line(0, "For further details on a command, invoke command help:");
print_usage_line(1, "e.g. `odin build -help` or `odin help build`");
@@ -242,6 +248,7 @@ enum BuildFlagKind {
BuildFlag_Debug,
BuildFlag_DisableAssert,
BuildFlag_NoBoundsCheck,
+ BuildFlag_NoTypeAssert,
BuildFlag_NoDynamicLiterals,
BuildFlag_NoCRT,
BuildFlag_NoEntryPoint,
@@ -253,6 +260,8 @@ enum BuildFlagKind {
BuildFlag_Vet,
BuildFlag_VetShadowing,
BuildFlag_VetUnused,
+ BuildFlag_VetUnusedImports,
+ BuildFlag_VetUnusedVariables,
BuildFlag_VetUsingStmt,
BuildFlag_VetUsingParam,
BuildFlag_VetStyle,
@@ -333,12 +342,12 @@ struct BuildFlag {
String name;
BuildFlagParamKind param_kind;
u32 command_support;
- bool allow_mulitple;
+ bool allow_multiple;
};
-gb_internal void add_flag(Array<BuildFlag> *build_flags, BuildFlagKind kind, String name, BuildFlagParamKind param_kind, u32 command_support, bool allow_mulitple=false) {
- BuildFlag flag = {kind, name, param_kind, command_support, allow_mulitple};
+gb_internal void add_flag(Array<BuildFlag> *build_flags, BuildFlagKind kind, String name, BuildFlagParamKind param_kind, u32 command_support, bool allow_multiple=false) {
+ BuildFlag flag = {kind, name, param_kind, command_support, allow_multiple};
array_add(build_flags, flag);
}
@@ -433,6 +442,7 @@ gb_internal bool parse_build_flags(Array<String> args) {
add_flag(&build_flags, BuildFlag_Debug, str_lit("debug"), BuildFlagParam_None, Command__does_check);
add_flag(&build_flags, BuildFlag_DisableAssert, str_lit("disable-assert"), BuildFlagParam_None, Command__does_check);
add_flag(&build_flags, BuildFlag_NoBoundsCheck, str_lit("no-bounds-check"), BuildFlagParam_None, Command__does_check);
+ add_flag(&build_flags, BuildFlag_NoTypeAssert, str_lit("no-type-assert"), BuildFlagParam_None, Command__does_check);
add_flag(&build_flags, BuildFlag_NoThreadLocal, str_lit("no-thread-local"), BuildFlagParam_None, Command__does_check);
add_flag(&build_flags, BuildFlag_NoDynamicLiterals, str_lit("no-dynamic-literals"), BuildFlagParam_None, Command__does_check);
add_flag(&build_flags, BuildFlag_NoCRT, str_lit("no-crt"), BuildFlagParam_None, Command__does_build);
@@ -444,6 +454,8 @@ gb_internal bool parse_build_flags(Array<String> args) {
add_flag(&build_flags, BuildFlag_Vet, str_lit("vet"), BuildFlagParam_None, Command__does_check);
add_flag(&build_flags, BuildFlag_VetUnused, str_lit("vet-unused"), BuildFlagParam_None, Command__does_check);
+ add_flag(&build_flags, BuildFlag_VetUnusedVariables, str_lit("vet-unused-variables"), BuildFlagParam_None, Command__does_check);
+ add_flag(&build_flags, BuildFlag_VetUnusedImports, str_lit("vet-unused-imports"), BuildFlagParam_None, Command__does_check);
add_flag(&build_flags, BuildFlag_VetShadowing, str_lit("vet-shadowing"), BuildFlagParam_None, Command__does_check);
add_flag(&build_flags, BuildFlag_VetUsingStmt, str_lit("vet-using-stmt"), BuildFlagParam_None, Command__does_check);
add_flag(&build_flags, BuildFlag_VetUsingParam, str_lit("vet-using-param"), BuildFlagParam_None, Command__does_check);
@@ -1008,6 +1020,9 @@ gb_internal bool parse_build_flags(Array<String> args) {
case BuildFlag_NoBoundsCheck:
build_context.no_bounds_check = true;
break;
+ case BuildFlag_NoTypeAssert:
+ build_context.no_type_assert = true;
+ break;
case BuildFlag_NoDynamicLiterals:
build_context.no_dynamic_literals = true;
break;
@@ -1026,10 +1041,9 @@ gb_internal bool parse_build_flags(Array<String> args) {
case BuildFlag_UseSeparateModules:
build_context.use_separate_modules = true;
break;
- case BuildFlag_NoThreadedChecker: {
+ case BuildFlag_NoThreadedChecker:
build_context.no_threaded_checker = true;
break;
- }
case BuildFlag_ShowDebugMessages:
build_context.show_debug_messages = true;
break;
@@ -1037,12 +1051,14 @@ gb_internal bool parse_build_flags(Array<String> args) {
build_context.vet_flags |= VetFlag_All;
break;
- case BuildFlag_VetUnused: build_context.vet_flags |= VetFlag_Unused; break;
- case BuildFlag_VetShadowing: build_context.vet_flags |= VetFlag_Shadowing; break;
- case BuildFlag_VetUsingStmt: build_context.vet_flags |= VetFlag_UsingStmt; break;
- case BuildFlag_VetUsingParam: build_context.vet_flags |= VetFlag_UsingParam; break;
- case BuildFlag_VetStyle: build_context.vet_flags |= VetFlag_Style; break;
- case BuildFlag_VetSemicolon: build_context.vet_flags |= VetFlag_Semicolon; break;
+ case BuildFlag_VetUnusedVariables: build_context.vet_flags |= VetFlag_UnusedVariables; break;
+ case BuildFlag_VetUnusedImports: build_context.vet_flags |= VetFlag_UnusedImports; break;
+ case BuildFlag_VetUnused: build_context.vet_flags |= VetFlag_Unused; break;
+ case BuildFlag_VetShadowing: build_context.vet_flags |= VetFlag_Shadowing; break;
+ case BuildFlag_VetUsingStmt: build_context.vet_flags |= VetFlag_UsingStmt; break;
+ case BuildFlag_VetUsingParam: build_context.vet_flags |= VetFlag_UsingParam; break;
+ case BuildFlag_VetStyle: build_context.vet_flags |= VetFlag_Style; break;
+ case BuildFlag_VetSemicolon: build_context.vet_flags |= VetFlag_Semicolon; break;
case BuildFlag_IgnoreUnknownAttributes:
build_context.ignore_unknown_attributes = true;
@@ -1347,7 +1363,7 @@ gb_internal bool parse_build_flags(Array<String> args) {
}
}
- if (!bf.allow_mulitple) {
+ if (!bf.allow_multiple) {
set_flags[bf.kind] = ok;
}
}
@@ -1844,6 +1860,10 @@ gb_internal void print_show_help(String const arg0, String const &command) {
print_usage_line(2, "Disables bounds checking program wide.");
print_usage_line(0, "");
+ print_usage_line(1, "-no-type-assert");
+ print_usage_line(2, "Disables type assertion checking program wide.");
+ print_usage_line(0, "");
+
print_usage_line(1, "-no-crt");
print_usage_line(2, "Disables automatic linking with the C Run Time.");
print_usage_line(0, "");
@@ -1875,6 +1895,8 @@ gb_internal void print_show_help(String const arg0, String const &command) {
print_usage_line(2, "Does extra checks on the code.");
print_usage_line(2, "Extra checks include:");
print_usage_line(3, "-vet-unused");
+ print_usage_line(3, "-vet-unused-variables");
+ print_usage_line(3, "-vet-unused-imports");
print_usage_line(3, "-vet-shadowing");
print_usage_line(3, "-vet-using-stmt");
print_usage_line(0, "");
@@ -1883,6 +1905,14 @@ gb_internal void print_show_help(String const arg0, String const &command) {
print_usage_line(2, "Checks for unused declarations.");
print_usage_line(0, "");
+ print_usage_line(1, "-vet-unused-variables");
+ print_usage_line(2, "Checks for unused variable declarations.");
+ print_usage_line(0, "");
+
+ print_usage_line(1, "-vet-unused-imports");
+ print_usage_line(2, "Checks for unused import declarations.");
+ print_usage_line(0, "");
+
print_usage_line(1, "-vet-shadowing");
print_usage_line(2, "Checks for variable shadowing within procedures.");
print_usage_line(0, "");
@@ -2557,8 +2587,15 @@ int main(int arg_count, char const **arg_ptr) {
print_show_help(args[0], args[2]);
return 0;
}
+ } else if (command == "root") {
+ gb_printf("%.*s", LIT(odin_root_dir()));
+ return 0;
} else {
- usage(args[0]);
+ String argv1 = {};
+ if (args.count > 1) {
+ argv1 = args[1];
+ }
+ usage(args[0], argv1);
return 1;
}
diff --git a/src/parser.cpp b/src/parser.cpp
index 01a3069ff..f4d3dc48d 100644
--- a/src/parser.cpp
+++ b/src/parser.cpp
@@ -6114,7 +6114,13 @@ gb_internal bool parse_file(Parser *p, AstFile *f) {
CommentGroup *docs = f->lead_comment;
if (f->curr_token.kind != Token_package) {
+ ERROR_BLOCK();
syntax_error(f->curr_token, "Expected a package declaration at the beginning of the file");
+ // IMPORTANT NOTE(bill): this is technically a race condition with the suggestion, but it's ony a suggession
+ // so in practice is should be "fine"
+ if (f->pkg && f->pkg->name != "") {
+ error_line("\tSuggestion: Add 'package %.*s' to the top of the file\n", LIT(f->pkg->name));
+ }
return false;
}
diff --git a/src/string.cpp b/src/string.cpp
index 7bfa52f33..b92dd589e 100644
--- a/src/string.cpp
+++ b/src/string.cpp
@@ -171,6 +171,9 @@ template <isize N> gb_internal bool operator > (String const &a, char const (&b
template <isize N> gb_internal bool operator <= (String const &a, char const (&b)[N]) { return str_le(a, make_string(cast(u8 *)b, N-1)); }
template <isize N> gb_internal bool operator >= (String const &a, char const (&b)[N]) { return str_ge(a, make_string(cast(u8 *)b, N-1)); }
+template <> bool operator == (String const &a, char const (&b)[1]) { return a.len == 0; }
+template <> bool operator != (String const &a, char const (&b)[1]) { return a.len != 0; }
+
gb_internal gb_inline bool string_starts_with(String const &s, String const &prefix) {
if (prefix.len > s.len) {
return false;
@@ -234,11 +237,16 @@ gb_internal String string_split_iterator(String_Iterator *it, const char sep) {
return substring(it->str, start, end);
}
+gb_internal gb_inline bool is_separator(u8 const &ch) {
+ return (ch == '/' || ch == '\\');
+}
+
+
gb_internal gb_inline isize string_extension_position(String const &str) {
isize dot_pos = -1;
isize i = str.len;
while (i --> 0) {
- if (str[i] == '\\' || str[i] == '/')
+ if (is_separator(str[i]))
break;
if (str[i] == '.') {
dot_pos = i;
@@ -273,6 +281,43 @@ gb_internal String string_trim_whitespace(String str) {
return str;
}
+gb_internal String string_trim_trailing_whitespace(String str) {
+ while (str.len > 0) {
+ u8 c = str[str.len-1];
+ if (rune_is_whitespace(c) || c == 0) {
+ str.len -= 1;
+ } else {
+ break;
+ }
+ }
+ return str;
+}
+
+gb_internal String split_lines_first_line_from_array(Array<u8> const &array, gbAllocator allocator) {
+ String_Iterator it = {{array.data, array.count}, 0};
+
+ String line = string_split_iterator(&it, '\n');
+ line = string_trim_trailing_whitespace(line);
+ return line;
+}
+
+gb_internal Array<String> split_lines_from_array(Array<u8> const &array, gbAllocator allocator) {
+ Array<String> lines = {};
+ lines.allocator = allocator;
+
+ String_Iterator it = {{array.data, array.count}, 0};
+
+ for (;;) {
+ String line = string_split_iterator(&it, '\n');
+ if (line.len == 0) {
+ break;
+ }
+ line = string_trim_trailing_whitespace(line);
+ array_add(&lines, line);
+ }
+
+ return lines;
+}
gb_internal bool string_contains_char(String const &s, u8 c) {
isize i;
@@ -292,8 +337,7 @@ gb_internal String filename_from_path(String s) {
if (i > 0) {
isize j = 0;
for (j = s.len-1; j >= 0; j--) {
- if (s[j] == '/' ||
- s[j] == '\\') {
+ if (is_separator(s[j])) {
break;
}
}
@@ -306,8 +350,7 @@ gb_internal String filename_from_path(String s) {
gb_internal String filename_without_directory(String s) {
isize j = 0;
for (j = s.len-1; j >= 0; j--) {
- if (s[j] == '/' ||
- s[j] == '\\') {
+ if (is_separator(s[j])) {
break;
}
}
@@ -370,7 +413,26 @@ gb_internal String copy_string(gbAllocator a, String const &s) {
return make_string(data, s.len);
}
-
+gb_internal String normalize_path(gbAllocator a, String const &path, String const &sep) {
+ String s;
+ if (sep.len < 1) {
+ return path;
+ }
+ if (path.len < 1) {
+ s = STR_LIT("");
+ } else if (is_separator(path[path.len-1])) {
+ s = copy_string(a, path);
+ } else {
+ s = concatenate_strings(a, path, sep);
+ }
+ isize i;
+ for (i = 0; i < s.len; i++) {
+ if (is_separator(s.text[i])) {
+ s.text[i] = sep.text[0];
+ }
+ }
+ return s;
+}
#if defined(GB_SYSTEM_WINDOWS)
diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp
index 3d5348074..fdff9224a 100644
--- a/src/tokenizer.cpp
+++ b/src/tokenizer.cpp
@@ -193,6 +193,7 @@ gb_internal void init_keyword_hash_table(void) {
gb_global Array<String> global_file_path_strings; // index is file id
gb_global Array<struct AstFile *> global_files; // index is file id
+gb_global BlockingMutex global_files_mutex;
gb_internal String get_file_path_string(i32 index);
gb_internal struct AstFile *thread_safe_get_ast_file_from_id(i32 index);
diff --git a/src/types.cpp b/src/types.cpp
index 97512d29b..18cb12ea1 100644
--- a/src/types.cpp
+++ b/src/types.cpp
@@ -769,7 +769,6 @@ gb_internal gbString type_to_string (Type *type, bool shorthand=true);
gb_internal gbString type_to_string (Type *type, gbAllocator allocator, bool shorthand=true);
gb_internal i64 type_size_of_internal(Type *t, TypePath *path);
gb_internal i64 type_align_of_internal(Type *t, TypePath *path);
-gb_internal void init_map_internal_types(Type *type);
gb_internal Type * bit_set_to_int(Type *t);
gb_internal bool are_types_identical(Type *x, Type *y);