aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorflysand7 <thebumboni@gmail.com>2025-03-02 20:05:55 +1100
committerflysand7 <thebumboni@gmail.com>2025-03-02 20:05:55 +1100
commit698c510ba7bb5794b3eeed7aecb8327386f00da7 (patch)
tree8c376debaf24f3ac8782192310e49e730509cdf9 /src
parent5d290dce069cb257b2e3effdd4e9b1e7dc21e722 (diff)
parentf390598b403eb336276ef9161753bf26d24d0d01 (diff)
Merge branch 'master' into docs-simd
Diffstat (limited to 'src')
-rw-r--r--src/big_int.cpp5
-rw-r--r--src/bug_report.cpp4
-rw-r--r--src/build_settings.cpp51
-rw-r--r--src/check_builtin.cpp43
-rw-r--r--src/check_decl.cpp111
-rw-r--r--src/check_expr.cpp93
-rw-r--r--src/check_stmt.cpp75
-rw-r--r--src/check_type.cpp32
-rw-r--r--src/checker.cpp250
-rw-r--r--src/checker.hpp28
-rw-r--r--src/checker_builtin_procs.hpp6
-rw-r--r--src/common.cpp4
-rw-r--r--src/docs_writer.cpp65
-rw-r--r--src/entity.cpp3
-rw-r--r--src/exact_value.cpp6
-rw-r--r--src/gb/gb.h15
-rw-r--r--src/linker.cpp33
-rw-r--r--src/llvm_backend.cpp158
-rw-r--r--src/llvm_backend.hpp54
-rw-r--r--src/llvm_backend_const.cpp48
-rw-r--r--src/llvm_backend_debug.cpp42
-rw-r--r--src/llvm_backend_expr.cpp87
-rw-r--r--src/llvm_backend_general.cpp307
-rw-r--r--src/llvm_backend_proc.cpp95
-rw-r--r--src/llvm_backend_stmt.cpp327
-rw-r--r--src/llvm_backend_type.cpp73
-rw-r--r--src/llvm_backend_utility.cpp141
-rw-r--r--src/main.cpp46
-rw-r--r--src/name_canonicalization.cpp752
-rw-r--r--src/name_canonicalization.hpp128
-rw-r--r--src/parser.cpp364
-rw-r--r--src/parser.hpp3
-rw-r--r--src/ptr_set.cpp10
-rw-r--r--src/string.cpp10
-rw-r--r--src/types.cpp220
35 files changed, 2675 insertions, 1014 deletions
diff --git a/src/big_int.cpp b/src/big_int.cpp
index 8e476f090..0b0a9a400 100644
--- a/src/big_int.cpp
+++ b/src/big_int.cpp
@@ -251,7 +251,10 @@ gb_internal void big_int_from_string(BigInt *dst, String const &s, bool *success
exp *= 10;
exp += v;
}
- big_int_exp_u64(dst, &b, exp, success);
+ BigInt tmp = {};
+ mp_init(&tmp);
+ big_int_exp_u64(&tmp, &b, exp, success);
+ big_int_mul_eq(dst, &tmp);
}
if (is_negative) {
diff --git a/src/bug_report.cpp b/src/bug_report.cpp
index ca5d0a395..c44c4be33 100644
--- a/src/bug_report.cpp
+++ b/src/bug_report.cpp
@@ -532,9 +532,9 @@ gb_internal void report_os_info() {
return;
}
- uint32_t major, minor, patch;
+ uint32_t major, minor, patch = 0;
- if (sscanf(cast(const char *)sw_vers, "%u.%u.%u", &major, &minor, &patch) != 3) {
+ if (sscanf(cast(const char *)sw_vers, "%u.%u.%u", &major, &minor, &patch) < 1) {
gb_printf("macOS Unknown\n");
return;
}
diff --git a/src/build_settings.cpp b/src/build_settings.cpp
index 50fae93b8..08df34c57 100644
--- a/src/build_settings.cpp
+++ b/src/build_settings.cpp
@@ -324,6 +324,18 @@ u64 get_vet_flag_from_name(String const &name) {
return VetFlag_NONE;
}
+enum OptInFeatureFlags : u64 {
+ OptInFeatureFlag_NONE = 0,
+ OptInFeatureFlag_DynamicLiterals = 1u<<0,
+};
+
+u64 get_feature_flag_from_name(String const &name) {
+ if (name == "dynamic-literals") {
+ return OptInFeatureFlag_DynamicLiterals;
+ }
+ return OptInFeatureFlag_NONE;
+}
+
enum SanitizerFlags : u32 {
SanitizerFlag_NONE = 0,
@@ -429,7 +441,6 @@ struct BuildContext {
bool ignore_unknown_attributes;
bool no_bounds_check;
bool no_type_assert;
- bool no_dynamic_literals;
bool no_output_files;
bool no_crt;
bool no_rpath;
@@ -461,12 +472,14 @@ struct BuildContext {
bool ignore_microsoft_magic;
bool linker_map_file;
+ bool use_single_module;
bool use_separate_modules;
bool module_per_file;
bool cached;
BuildCacheData build_cache_data;
bool internal_no_inline;
+ bool internal_by_value;
bool no_threaded_checker;
@@ -1707,13 +1720,15 @@ gb_internal void init_build_context(TargetMetrics *cross_target, Subtarget subta
bc->optimization_level = gb_clamp(bc->optimization_level, -1, 3);
-#if defined(GB_SYSTEM_WINDOWS)
if (bc->optimization_level <= 0) {
if (!is_arch_wasm()) {
bc->use_separate_modules = true;
}
}
-#endif
+
+ if (build_context.use_single_module) {
+ bc->use_separate_modules = false;
+ }
// TODO: Static map calls are bugged on `amd64sysv` abi.
@@ -1854,11 +1869,6 @@ gb_internal bool init_build_paths(String init_filename) {
produces_output_file = true;
}
- if (build_context.ODIN_DEFAULT_TO_NIL_ALLOCATOR ||
- build_context.ODIN_DEFAULT_TO_PANIC_ALLOCATOR) {
- bc->no_dynamic_literals = true;
- }
-
if (!produces_output_file) {
// Command doesn't produce output files. We're done.
return true;
@@ -2053,7 +2063,7 @@ gb_internal bool init_build_paths(String init_filename) {
// Do we have an extension? We might not if the output filename was supplied.
if (bc->build_paths[BuildPath_Output].ext.len == 0) {
- if (build_context.metrics.os == TargetOs_windows || build_context.build_mode != BuildMode_Executable) {
+ if (build_context.metrics.os == TargetOs_windows || is_arch_wasm() || build_context.build_mode != BuildMode_Executable) {
bc->build_paths[BuildPath_Output].ext = copy_string(ha, output_extension);
}
}
@@ -2117,6 +2127,7 @@ gb_internal bool init_build_paths(String init_filename) {
}
}
+ bool no_crt_checks_failed = false;
if (build_context.no_crt && !build_context.ODIN_DEFAULT_TO_NIL_ALLOCATOR && !build_context.ODIN_DEFAULT_TO_PANIC_ALLOCATOR) {
switch (build_context.metrics.os) {
case TargetOs_linux:
@@ -2126,11 +2137,29 @@ gb_internal bool init_build_paths(String init_filename) {
case TargetOs_openbsd:
case TargetOs_netbsd:
case TargetOs_haiku:
- gb_printf_err("-no-crt on unix systems requires either -default-to-nil-allocator or -default-to-panic-allocator to also be present because the default allocator requires crt\n");
- return false;
+ gb_printf_err("-no-crt on Unix systems requires either -default-to-nil-allocator or -default-to-panic-allocator to also be present, because the default allocator requires CRT\n");
+ no_crt_checks_failed = true;
}
}
+ if (build_context.no_crt && !build_context.no_thread_local) {
+ switch (build_context.metrics.os) {
+ case TargetOs_linux:
+ case TargetOs_darwin:
+ case TargetOs_essence:
+ case TargetOs_freebsd:
+ case TargetOs_openbsd:
+ case TargetOs_netbsd:
+ case TargetOs_haiku:
+ gb_printf_err("-no-crt on Unix systems requires the -no-thread-local flag to also be present, because the TLS is inaccessible without CRT\n");
+ no_crt_checks_failed = true;
+ }
+ }
+
+ if (no_crt_checks_failed) {
+ return false;
+ }
+
return true;
}
diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp
index ea902387b..023aeff73 100644
--- a/src/check_builtin.cpp
+++ b/src/check_builtin.cpp
@@ -888,6 +888,39 @@ gb_internal bool check_builtin_simd_operation(CheckerContext *c, Operand *operan
return true;
}
+ case BuiltinProc_simd_extract_lsbs:
+ case BuiltinProc_simd_extract_msbs:
+ {
+ Operand x = {};
+ check_expr(c, &x, ce->args[0]); if (x.mode == Addressing_Invalid) return false;
+
+ if (!is_type_simd_vector(x.type)) {
+ gbString xs = type_to_string(x.type);
+ error(x.expr, "'%.*s' expected a simd vector type, got '%s'", LIT(builtin_name), xs);
+ gb_string_free(xs);
+ return false;
+ }
+
+ Type *elem = base_array_type(x.type);
+ if (!is_type_integer_like(elem)) {
+ gbString xs = type_to_string(x.type);
+ error(x.expr, "'%.*s' expected a #simd type with integer or boolean elements, got '%s'", LIT(builtin_name), xs);
+ gb_string_free(xs);
+ return false;
+ }
+
+ i64 num_elems = get_array_type_count(x.type);
+
+ Type *result_type = alloc_type_bit_set();
+ result_type->BitSet.elem = t_int;
+ result_type->BitSet.lower = 0;
+ result_type->BitSet.upper = num_elems - 1;
+
+ operand->mode = Addressing_Value;
+ operand->type = result_type;
+ return true;
+ }
+
case BuiltinProc_simd_shuffle:
{
@@ -3488,9 +3521,12 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
case ExactValue_Integer:
mp_abs(&operand->value.value_integer, &operand->value.value_integer);
break;
- case ExactValue_Float:
- operand->value.value_float = gb_abs(operand->value.value_float);
+ case ExactValue_Float: {
+ u64 abs = bit_cast<u64>(operand->value.value_float);
+ abs &= 0x7FFFFFFFFFFFFFFF;
+ operand->value.value_float = bit_cast<f64>(abs);
break;
+ }
case ExactValue_Complex: {
f64 r = operand->value.value_complex->real;
f64 i = operand->value.value_complex->imag;
@@ -5544,6 +5580,9 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
// NOTE(bill): Is this even correct?
new_type->Union.node = operand->expr;
new_type->Union.scope = bt->Union.scope;
+ if (bt->Union.kind == UnionType_no_nil) {
+ new_type->Union.kind = UnionType_no_nil;
+ }
operand->type = new_type;
}
diff --git a/src/check_decl.cpp b/src/check_decl.cpp
index 60eb030ff..5607ea725 100644
--- a/src/check_decl.cpp
+++ b/src/check_decl.cpp
@@ -60,7 +60,7 @@ gb_internal Type *check_init_variable(CheckerContext *ctx, Entity *e, Operand *o
error(operand->expr, "Cannot assign a type '%s' to variable '%.*s'", t, LIT(e->token.string));
}
if (e->type == nullptr) {
- error_line("\tThe type of the variable '%.*s' cannot be inferred as a type does not have a default type\n", LIT(e->token.string));
+ error_line("\tThe type of the variable '%.*s' cannot be inferred as a type and does not have a default type\n", LIT(e->token.string));
}
e->type = operand->type;
return nullptr;
@@ -94,12 +94,14 @@ gb_internal Type *check_init_variable(CheckerContext *ctx, Entity *e, Operand *o
return nullptr;
}
if (e2->state.load() != EntityState_Resolved) {
- gbString str = type_to_string(t);
- defer (gb_string_free(str));
- error(e->token, "Invalid use of a polymorphic type '%s' in %.*s", str, LIT(context_name));
- e->type = t_invalid;
+ e->type = t;
return nullptr;
}
+ gbString str = type_to_string(t);
+ defer (gb_string_free(str));
+ error(operand->expr, "Invalid use of a non-specialized polymorphic type '%s' in %.*s", str, LIT(context_name));
+ e->type = t_invalid;
+ return nullptr;
} else if (is_type_empty_union(t)) {
gbString str = type_to_string(t);
defer (gb_string_free(str));
@@ -855,6 +857,7 @@ gb_internal Entity *init_entity_foreign_library(CheckerContext *ctx, Entity *e)
} else {
String name = ident->Ident.token.string;
Entity *found = scope_lookup(ctx->scope, name);
+
if (found == nullptr) {
if (is_blank_ident(name)) {
// NOTE(bill): link against nothing
@@ -971,6 +974,43 @@ gb_internal void check_objc_methods(CheckerContext *ctx, Entity *e, AttributeCon
}
}
+gb_internal void check_foreign_procedure(CheckerContext *ctx, Entity *e, DeclInfo *d) {
+ GB_ASSERT(e != nullptr);
+ GB_ASSERT(e->kind == Entity_Procedure);
+ String name = e->Procedure.link_name;
+
+ mutex_lock(&ctx->info->foreign_mutex);
+
+ auto *fp = &ctx->info->foreigns;
+ StringHashKey key = string_hash_string(name);
+ Entity **found = string_map_get(fp, key);
+ if (found && e != *found) {
+ Entity *f = *found;
+ TokenPos pos = f->token.pos;
+ Type *this_type = base_type(e->type);
+ Type *other_type = base_type(f->type);
+ if (is_type_proc(this_type) && is_type_proc(other_type)) {
+ if (!are_signatures_similar_enough(this_type, other_type)) {
+ error(d->proc_lit,
+ "Redeclaration of foreign procedure '%.*s' with different type signatures\n"
+ "\tat %s",
+ LIT(name), token_pos_to_string(pos));
+ }
+ } else if (!signature_parameter_similar_enough(this_type, other_type)) {
+ error(d->proc_lit,
+ "Foreign entity '%.*s' previously declared elsewhere with a different type\n"
+ "\tat %s",
+ LIT(name), token_pos_to_string(pos));
+ }
+ } else if (name == "main") {
+ error(d->proc_lit, "The link name 'main' is reserved for internal use");
+ } else {
+ string_map_set(fp, key, e);
+ }
+
+ mutex_unlock(&ctx->info->foreign_mutex);
+}
+
gb_internal void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
GB_ASSERT(e->type == nullptr);
if (d->proc_lit->kind != Ast_ProcLit) {
@@ -1307,57 +1347,16 @@ gb_internal void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
name = e->Procedure.link_name;
}
Entity *foreign_library = init_entity_foreign_library(ctx, e);
-
- if (is_arch_wasm() && foreign_library != nullptr) {
- String module_name = str_lit("env");
- GB_ASSERT (foreign_library->kind == Entity_LibraryName);
- if (foreign_library->LibraryName.paths.count != 1) {
- error(foreign_library->token, "'foreign import' for '%.*s' architecture may only have one path, got %td",
- LIT(target_arch_names[build_context.metrics.arch]), foreign_library->LibraryName.paths.count);
- }
-
- if (foreign_library->LibraryName.paths.count >= 1) {
- module_name = foreign_library->LibraryName.paths[0];
- }
-
- if (!string_ends_with(module_name, str_lit(".o"))) {
- name = concatenate3_strings(permanent_allocator(), module_name, WASM_MODULE_NAME_SEPARATOR, name);
- }
- }
-
e->Procedure.is_foreign = true;
e->Procedure.link_name = name;
+ e->Procedure.foreign_library = foreign_library;
- mutex_lock(&ctx->info->foreign_mutex);
-
- auto *fp = &ctx->info->foreigns;
- StringHashKey key = string_hash_string(name);
- Entity **found = string_map_get(fp, key);
- if (found && e != *found) {
- Entity *f = *found;
- TokenPos pos = f->token.pos;
- Type *this_type = base_type(e->type);
- Type *other_type = base_type(f->type);
- if (is_type_proc(this_type) && is_type_proc(other_type)) {
- if (!are_signatures_similar_enough(this_type, other_type)) {
- error(d->proc_lit,
- "Redeclaration of foreign procedure '%.*s' with different type signatures\n"
- "\tat %s",
- LIT(name), token_pos_to_string(pos));
- }
- } else if (!signature_parameter_similar_enough(this_type, other_type)) {
- error(d->proc_lit,
- "Foreign entity '%.*s' previously declared elsewhere with a different type\n"
- "\tat %s",
- LIT(name), token_pos_to_string(pos));
- }
- } else if (name == "main") {
- error(d->proc_lit, "The link name 'main' is reserved for internal use");
+ if (is_arch_wasm() && foreign_library != nullptr) {
+ // NOTE(bill): this must be delayed because the foreign import paths might not be evaluated yet until much later
+ mpsc_enqueue(&ctx->info->foreign_decls_to_check, e);
} else {
- string_map_set(fp, key, e);
+ check_foreign_procedure(ctx, e, d);
}
-
- mutex_unlock(&ctx->info->foreign_mutex);
} else {
String name = e->token.string;
if (e->Procedure.link_name.len > 0) {
@@ -1743,8 +1742,8 @@ gb_internal void add_deps_from_child_to_parent(DeclInfo *decl) {
rw_mutex_shared_lock(&decl->type_info_deps_mutex);
rw_mutex_lock(&decl->parent->type_info_deps_mutex);
- for (Type *t : decl->type_info_deps) {
- ptr_set_add(&decl->parent->type_info_deps, t);
+ for (auto const &tt : decl->type_info_deps) {
+ type_set_add(&decl->parent->type_info_deps, tt);
}
rw_mutex_unlock(&decl->parent->type_info_deps_mutex);
@@ -1785,6 +1784,10 @@ gb_internal bool check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *de
ctx->curr_proc_sig = type;
ctx->curr_proc_calling_convention = type->Proc.calling_convention;
+ if (decl->parent && decl->entity && decl->parent->entity) {
+ decl->entity->parent_proc_decl = decl->parent;
+ }
+
if (ctx->pkg->name != "runtime") {
switch (type->Proc.calling_convention) {
case ProcCC_None:
@@ -1874,6 +1877,8 @@ gb_internal bool check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *de
check_open_scope(ctx, body);
{
+ ctx->scope->decl_info = decl;
+
for (auto const &entry : using_entities) {
Entity *uvar = entry.uvar;
Entity *prev = scope_insert(ctx->scope, uvar);
diff --git a/src/check_expr.cpp b/src/check_expr.cpp
index dd0820fee..bd1c34044 100644
--- a/src/check_expr.cpp
+++ b/src/check_expr.cpp
@@ -345,7 +345,7 @@ gb_internal void check_scope_decls(CheckerContext *c, Slice<Ast *> const &nodes,
check_collect_entities(c, nodes);
for (auto const &entry : s->elements) {
- Entity *e = entry.value;
+ Entity *e = entry.value;\
switch (e->kind) {
case Entity_Constant:
case Entity_TypeName:
@@ -1044,7 +1044,7 @@ gb_internal AstPackage *get_package_of_type(Type *type) {
}
-// NOTE(bill): 'content_name' is for debugging and error messages
+// NOTE(bill): 'context_name' is for debugging and error messages
gb_internal void check_assignment(CheckerContext *c, Operand *operand, Type *type, String context_name) {
check_not_tuple(c, operand);
if (operand->mode == Addressing_Invalid) {
@@ -1973,10 +1973,10 @@ gb_internal bool check_binary_op(CheckerContext *c, Operand *o, Token op) {
case Token_Quo:
case Token_QuoEq:
if (is_type_matrix(main_type)) {
- error(op, "Operator '%.*s' is only allowed with matrix types", LIT(op.string));
+ error(op, "Operator '%.*s' is not allowed with matrix types", LIT(op.string));
return false;
} else if (is_type_simd_vector(main_type) && is_type_integer(type)) {
- error(op, "Operator '%.*s' is only allowed with #simd types with integer elements", LIT(op.string));
+ error(op, "Operator '%.*s' is not allowed with #simd types with integer elements", LIT(op.string));
return false;
}
/*fallthrough*/
@@ -2023,14 +2023,14 @@ gb_internal bool check_binary_op(CheckerContext *c, Operand *o, Token op) {
case Token_ModEq:
case Token_ModModEq:
if (is_type_matrix(main_type)) {
- error(op, "Operator '%.*s' is only allowed with matrix types", LIT(op.string));
+ error(op, "Operator '%.*s' is not allowed with matrix types", LIT(op.string));
return false;
}
if (!is_type_integer(type)) {
error(op, "Operator '%.*s' is only allowed with integers", LIT(op.string));
return false;
} else if (is_type_simd_vector(main_type)) {
- error(op, "Operator '%.*s' is only allowed with #simd types with integer elements", LIT(op.string));
+ error(op, "Operator '%.*s' is not allowed with #simd types with integer elements", LIT(op.string));
return false;
}
break;
@@ -3649,7 +3649,8 @@ gb_internal bool check_transmute(CheckerContext *c, Ast *node, Operand *o, Type
gb_string_free(oper_str);
gb_string_free(to_type);
} else if (is_type_integer(src_t) && is_type_integer(dst_t) &&
- types_have_same_internal_endian(src_t, dst_t)) {
+ types_have_same_internal_endian(src_t, dst_t) &&
+ type_endian_kind_of(src_t) == type_endian_kind_of(dst_t)) {
gbString oper_type = type_to_string(src_t);
gbString to_type = type_to_string(dst_t);
error(o->expr, "Use of 'transmute' where 'cast' would be preferred since both are integers of the same endianness, from '%s' to '%s'", oper_type, to_type);
@@ -3672,6 +3673,13 @@ gb_internal bool check_binary_array_expr(CheckerContext *c, Token op, Operand *x
}
}
}
+ if (is_type_simd_vector(x->type) && !is_type_simd_vector(y->type)) {
+ if (check_is_assignable_to(c, y, x->type)) {
+ if (check_binary_op(c, x, op)) {
+ return true;
+ }
+ }
+ }
return false;
}
@@ -4556,6 +4564,19 @@ gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *tar
break;
}
+ case Type_SimdVector: {
+ Type *elem = base_array_type(t);
+ if (check_is_assignable_to(c, operand, elem)) {
+ operand->mode = Addressing_Value;
+ } else {
+ operand->mode = Addressing_Invalid;
+ convert_untyped_error(c, operand, target_type);
+ return;
+ }
+
+ break;
+ }
+
case Type_Matrix: {
Type *elem = base_array_type(t);
if (check_is_assignable_to(c, operand, elem)) {
@@ -4980,8 +5001,12 @@ gb_internal ExactValue get_constant_field_single(CheckerContext *c, ExactValue v
if (success_) *success_ = true;
if (finish_) *finish_ = false;
return tav.value;
+ } else if (is_type_proc(tav.type)) {
+ if (success_) *success_ = true;
+ if (finish_) *finish_ = false;
+ return tav.value;
} else {
- GB_ASSERT(is_type_untyped_nil(tav.type));
+ GB_ASSERT_MSG(is_type_untyped_nil(tav.type), "%s", type_to_string(tav.type));
if (success_) *success_ = true;
if (finish_) *finish_ = false;
return tav.value;
@@ -5484,6 +5509,11 @@ gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *nod
case Addressing_SwizzleVariable:
operand->mode = Addressing_SwizzleVariable;
break;
+ case Addressing_Value:
+ if (is_type_pointer(original_type)) {
+ operand->mode = Addressing_SwizzleVariable;
+ }
+ break;
}
if (array_type->kind == Type_SimdVector) {
@@ -8721,6 +8751,18 @@ gb_internal ExprKind check_basic_directive_expr(CheckerContext *c, Operand *o, A
error(node, "#caller_expression may only be used as a default argument parameter");
o->type = t_string;
o->mode = Addressing_Value;
+ } else if (name == "branch_location") {
+ if (!c->in_defer) {
+ error(node, "#branch_location may only be used within a 'defer' statement");
+ } else if (c->curr_proc_decl) {
+ Entity *e = c->curr_proc_decl->entity;
+ if (e != nullptr) {
+ GB_ASSERT(e->kind == Entity_Procedure);
+ e->Procedure.uses_branch_location = true;
+ }
+ }
+ o->type = t_source_code_location;
+ o->mode = Addressing_Value;
} else {
if (name == "location") {
init_core_source_code_location(c->checker);
@@ -9335,6 +9377,23 @@ gb_internal bool is_expr_inferred_fixed_array(Ast *type_expr) {
return false;
}
+gb_internal bool check_for_dynamic_literals(CheckerContext *c, Ast *node, AstCompoundLit *cl) {
+ if (cl->elems.count > 0 && (check_feature_flags(c, node) & OptInFeatureFlag_DynamicLiterals) == 0) {
+ ERROR_BLOCK();
+ error(node, "Compound literals of dynamic types are disabled by default");
+ error_line("\tSuggestion: If you want to enable them for this specific file, add '#+feature dynamic-literals' at the top of the file\n");
+ error_line("\tWarning: Please understand that dynamic literals will implicitly allocate using the current 'context.allocator' in that scope\n");
+ if (build_context.ODIN_DEFAULT_TO_NIL_ALLOCATOR) {
+ error_line("\tWarning: As '-default-to-panic-allocator' has been set, the dynamic compound literal may not be initialized as expected\n");
+ } else if (build_context.ODIN_DEFAULT_TO_PANIC_ALLOCATOR) {
+ error_line("\tWarning: As '-default-to-panic-allocator' has been set, the dynamic compound literal may not be initialized as expected\n");
+ }
+ return false;
+ }
+
+ return cl->elems.count > 0;
+}
+
gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *node, Type *type_hint) {
ExprKind kind = Expr_Expr;
ast_node(cl, CompoundLit, node);
@@ -9535,11 +9594,6 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *
elem_type = t->DynamicArray.elem;
context_name = str_lit("dynamic array literal");
is_constant = false;
-
- if (!build_context.no_dynamic_literals) {
- add_package_dependency(c, "runtime", "__dynamic_array_reserve");
- add_package_dependency(c, "runtime", "__dynamic_array_append");
- }
} else if (t->kind == Type_SimdVector) {
elem_type = t->SimdVector.elem;
context_name = str_lit("simd vector literal");
@@ -9714,8 +9768,9 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *
if (t->kind == Type_DynamicArray) {
- if (build_context.no_dynamic_literals && cl->elems.count) {
- error(node, "Compound literals of dynamic types have been disabled");
+ if (check_for_dynamic_literals(c, node, cl)) {
+ add_package_dependency(c, "runtime", "__dynamic_array_reserve");
+ add_package_dependency(c, "runtime", "__dynamic_array_append");
}
}
@@ -10104,9 +10159,7 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *
}
}
- if (build_context.no_dynamic_literals && cl->elems.count) {
- error(node, "Compound literals of dynamic types have been disabled");
- } else {
+ if (check_for_dynamic_literals(c, node, cl)) {
add_map_reserve_dependencies(c);
add_map_set_dependencies(c);
}
@@ -10328,7 +10381,7 @@ gb_internal ExprKind check_type_assertion(CheckerContext *c, Operand *o, Ast *no
add_type_info_type(c, o->type);
o->type = type_hint;
o->mode = Addressing_OptionalOk;
- return kind;
+ goto end;
}
}
@@ -10393,6 +10446,8 @@ gb_internal ExprKind check_type_assertion(CheckerContext *c, Operand *o, Ast *no
}
}
+end:;
+
if ((c->state_flags & StateFlag_no_type_assert) == 0) {
add_package_dependency(c, "runtime", "type_assertion_check");
add_package_dependency(c, "runtime", "type_assertion_check2");
diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp
index 2418fcc5c..e81996566 100644
--- a/src/check_stmt.cpp
+++ b/src/check_stmt.cpp
@@ -894,15 +894,49 @@ gb_internal void error_var_decl_identifier(Ast *name) {
}
}
-gb_internal void check_inline_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) {
+gb_internal void check_unroll_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) {
ast_node(irs, UnrollRangeStmt, node);
check_open_scope(ctx, node);
+ defer (check_close_scope(ctx));
Type *val0 = nullptr;
Type *val1 = nullptr;
Entity *entities[2] = {};
isize entity_count = 0;
+ i64 unroll_count = -1;
+
+ if (irs->args.count > 0) {
+ if (irs->args.count > 1) {
+ error(irs->args[1], "#unroll only supports a single argument for the unroll per loop amount");
+ }
+ Ast *arg = irs->args[0];
+ if (arg->kind == Ast_FieldValue) {
+ error(arg, "#unroll does not yet support named arguments");
+ arg = arg->FieldValue.value;
+ }
+
+ Operand x = {};
+ check_expr(ctx, &x, arg);
+ if (x.mode != Addressing_Constant || !is_type_integer(x.type)) {
+ gbString s = expr_to_string(x.expr);
+ error(x.expr, "Expected a constant integer for #unroll, got '%s'", s);
+ gb_string_free(s);
+ } else {
+ ExactValue value = exact_value_to_integer(x.value);
+ i64 v = exact_value_to_i64(value);
+ if (v < 1) {
+ error(x.expr, "Expected a constant integer >= 1 for #unroll, got %lld", cast(long long)v);
+ } else {
+ unroll_count = v;
+ if (v > 1024) {
+ error(x.expr, "Too large of a value for #unroll, got %lld, expected <= 1024", cast(long long)v);
+ }
+ }
+
+ }
+ }
+
Ast *expr = unparen_expr(irs->expr);
ExactValue inline_for_depth = exact_value_i64(0);
@@ -946,18 +980,39 @@ gb_internal void check_inline_range_stmt(CheckerContext *ctx, Ast *node, u32 mod
val0 = t_rune;
val1 = t_int;
inline_for_depth = exact_value_i64(operand.value.value_string.len);
+ if (unroll_count > 0) {
+ error(node, "#unroll(%lld) does not support strings", cast(long long)unroll_count);
+ }
}
break;
case Type_Array:
val0 = t->Array.elem;
val1 = t_int;
- inline_for_depth = exact_value_i64(t->Array.count);
+ inline_for_depth = unroll_count > 0 ? exact_value_i64(unroll_count) : exact_value_i64(t->Array.count);
break;
case Type_EnumeratedArray:
val0 = t->EnumeratedArray.elem;
val1 = t->EnumeratedArray.index;
+ if (unroll_count > 0) {
+ error(node, "#unroll(%lld) does not support enumerated arrays", cast(long long)unroll_count);
+ }
inline_for_depth = exact_value_i64(t->EnumeratedArray.count);
break;
+
+ case Type_Slice:
+ if (unroll_count > 0) {
+ val0 = t->Slice.elem;
+ val1 = t_int;
+ inline_for_depth = exact_value_i64(unroll_count);
+ }
+ break;
+ case Type_DynamicArray:
+ if (unroll_count > 0) {
+ val0 = t->DynamicArray.elem;
+ val1 = t_int;
+ inline_for_depth = exact_value_i64(unroll_count);
+ }
+ break;
}
}
@@ -967,7 +1022,7 @@ gb_internal void check_inline_range_stmt(CheckerContext *ctx, Ast *node, u32 mod
error(operand.expr, "Cannot iterate over '%s' of type '%s' in an '#unroll for' statement", s, t);
gb_string_free(t);
gb_string_free(s);
- } else if (operand.mode != Addressing_Constant) {
+ } else if (operand.mode != Addressing_Constant && unroll_count <= 0) {
error(operand.expr, "An '#unroll for' expression must be known at compile time");
}
}
@@ -1050,8 +1105,6 @@ gb_internal void check_inline_range_stmt(CheckerContext *ctx, Ast *node, u32 mod
check_stmt(ctx, irs->body, mod_flags);
-
- check_close_scope(ctx);
}
gb_internal void check_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) {
@@ -1393,8 +1446,8 @@ gb_internal void check_type_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_
Ast *nil_seen = nullptr;
- PtrSet<Type *> seen = {};
- defer (ptr_set_destroy(&seen));
+ TypeSet seen = {};
+ defer (type_set_destroy(&seen));
for (Ast *stmt : bs->stmts) {
if (stmt->kind != Ast_CaseClause) {
@@ -1462,7 +1515,7 @@ gb_internal void check_type_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_
GB_PANIC("Unknown type to type switch statement");
}
- if (type_ptr_set_update(&seen, y.type)) {
+ if (type_set_update(&seen, y.type)) {
TokenPos pos = cc->token.pos;
gbString expr_str = expr_to_string(y.expr);
error(y.expr,
@@ -1516,7 +1569,7 @@ gb_internal void check_type_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_
auto unhandled = array_make<Type *>(temporary_allocator(), 0, variants.count);
for (Type *t : variants) {
- if (!type_ptr_set_exists(&seen, t)) {
+ if (!type_set_exists(&seen, t)) {
array_add(&unhandled, t);
}
}
@@ -2605,6 +2658,7 @@ gb_internal void check_for_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) {
if (cond && cond->kind == Ast_BinaryExpr &&
cond->BinaryExpr.left && cond->BinaryExpr.right &&
cond->BinaryExpr.op.kind == Token_GtEq &&
+ type_of_expr(cond->BinaryExpr.left) != nullptr &&
is_type_unsigned(type_of_expr(cond->BinaryExpr.left)) &&
cond->BinaryExpr.right->tav.value.kind == ExactValue_Integer &&
is_exact_value_zero(cond->BinaryExpr.right->tav.value)) {
@@ -2612,6 +2666,7 @@ gb_internal void check_for_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) {
} else if (cond && cond->kind == Ast_BinaryExpr &&
cond->BinaryExpr.left && cond->BinaryExpr.right &&
cond->BinaryExpr.op.kind == Token_LtEq &&
+ type_of_expr(cond->BinaryExpr.right) != nullptr &&
is_type_unsigned(type_of_expr(cond->BinaryExpr.right)) &&
cond->BinaryExpr.left->tav.value.kind == ExactValue_Integer &&
is_exact_value_zero(cond->BinaryExpr.left->tav.value)) {
@@ -2677,7 +2732,7 @@ gb_internal void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags)
case_end;
case_ast_node(irs, UnrollRangeStmt, node);
- check_inline_range_stmt(ctx, node, mod_flags);
+ check_unroll_range_stmt(ctx, node, mod_flags);
case_end;
case_ast_node(ss, SwitchStmt, node);
diff --git a/src/check_type.cpp b/src/check_type.cpp
index 13a6125ca..9d4defbb2 100644
--- a/src/check_type.cpp
+++ b/src/check_type.cpp
@@ -685,7 +685,8 @@ gb_internal void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast *
ST_ALIGN(min_field_align);
ST_ALIGN(max_field_align);
ST_ALIGN(align);
- if (struct_type->Struct.custom_align < struct_type->Struct.custom_min_field_align) {
+ if (struct_type->Struct.custom_align != 0 &&
+ struct_type->Struct.custom_align < struct_type->Struct.custom_min_field_align) {
error(st->align, "#align(%lld) is defined to be less than #min_field_align(%lld)",
cast(long long)struct_type->Struct.custom_align,
cast(long long)struct_type->Struct.custom_min_field_align);
@@ -2440,8 +2441,12 @@ gb_internal bool check_procedure_type(CheckerContext *ctx, Type *type, Ast *proc
bool success = true;
isize specialization_count = 0;
Type *params = check_get_params(c, c->scope, pt->params, &variadic, &variadic_index, &success, &specialization_count, operands);
- Type *results = check_get_results(c, c->scope, pt->results);
+ bool no_poly_return = c->disallow_polymorphic_return_types;
+ c->disallow_polymorphic_return_types = c->scope == c->polymorphic_scope;
+ // NOTE(zen3ger): if the parapoly scope is the current proc's scope, then the return types shall not declare new poly vars
+ Type *results = check_get_results(c, c->scope, pt->results);
+ c->disallow_polymorphic_return_types = no_poly_return;
isize param_count = 0;
isize result_count = 0;
@@ -2854,15 +2859,23 @@ gb_internal void check_matrix_type(CheckerContext *ctx, Type **type, Ast *node)
}
if (generic_row == nullptr && row_count < MATRIX_ELEMENT_COUNT_MIN) {
- gbString s = expr_to_string(row.expr);
- error(row.expr, "Invalid matrix row count, expected %d+ rows, got %s", MATRIX_ELEMENT_COUNT_MIN, s);
- gb_string_free(s);
+ if (row.expr == nullptr) {
+ error(node, "Invalid matrix row count, got nothing");
+ } else {
+ gbString s = expr_to_string(row.expr);
+ error(row.expr, "Invalid matrix row count, expected %d+ rows, got %s", MATRIX_ELEMENT_COUNT_MIN, s);
+ gb_string_free(s);
+ }
}
if (generic_column == nullptr && column_count < MATRIX_ELEMENT_COUNT_MIN) {
- gbString s = expr_to_string(column.expr);
- error(column.expr, "Invalid matrix column count, expected %d+ rows, got %s", MATRIX_ELEMENT_COUNT_MIN, s);
- gb_string_free(s);
+ if (column.expr == nullptr) {
+ error(node, "Invalid matrix column count, got nothing");
+ } else {
+ gbString s = expr_to_string(column.expr);
+ error(column.expr, "Invalid matrix column count, expected %d+ rows, got %s", MATRIX_ELEMENT_COUNT_MIN, s);
+ gb_string_free(s);
+ }
}
if ((generic_row == nullptr && generic_column == nullptr) && row_count*column_count > MATRIX_ELEMENT_COUNT_MAX) {
@@ -3383,6 +3396,9 @@ gb_internal bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, T
}
Type *t = alloc_type_generic(ctx->scope, 0, token.string, specific);
if (ctx->allow_polymorphic_types) {
+ if (ctx->disallow_polymorphic_return_types) {
+ error(ident, "Undeclared polymorphic parameter '%.*s' in return type", LIT(token.string));
+ }
Scope *ps = ctx->polymorphic_scope;
Scope *s = ctx->scope;
Scope *entity_scope = s;
diff --git a/src/checker.cpp b/src/checker.cpp
index b7cf343f8..bee3f1efe 100644
--- a/src/checker.cpp
+++ b/src/checker.cpp
@@ -3,7 +3,10 @@
#include "entity.cpp"
#include "types.cpp"
-String get_final_microarchitecture();
+
+gb_internal u64 type_hash_canonical_type(Type *type);
+
+gb_internal String get_final_microarchitecture();
gb_internal void check_expr(CheckerContext *c, Operand *operand, Ast *expression);
gb_internal void check_expr_or_type(CheckerContext *c, Operand *operand, Ast *expression, Type *type_hint=nullptr);
@@ -170,7 +173,7 @@ gb_internal void init_decl_info(DeclInfo *d, Scope *scope, DeclInfo *parent) {
d->parent = parent;
d->scope = scope;
ptr_set_init(&d->deps, 0);
- ptr_set_init(&d->type_info_deps, 0);
+ type_set_init(&d->type_info_deps, 0);
d->labels.allocator = heap_allocator();
d->variadic_reuses.allocator = heap_allocator();
d->variadic_reuse_max_bytes = 0;
@@ -355,6 +358,10 @@ gb_internal void check_open_scope(CheckerContext *c, Ast *node) {
scope->flags |= ScopeFlag_Type;
break;
}
+ if (c->decl && c->decl->proc_lit) {
+ // Number the scopes within a procedure body depth-first
+ scope->index = c->decl->scope_index++;
+ }
c->scope = scope;
c->state_flags |= StateFlag_bounds_check;
}
@@ -542,6 +549,23 @@ gb_internal u64 check_vet_flags(Ast *node) {
return ast_file_vet_flags(file);
}
+gb_internal u64 check_feature_flags(CheckerContext *c, Ast *node) {
+ AstFile *file = c->file;
+ if (file == nullptr &&
+ c->curr_proc_decl &&
+ c->curr_proc_decl->proc_lit) {
+ file = c->curr_proc_decl->proc_lit->file();
+ }
+ if (file == nullptr) {
+ file = node->file();
+ }
+ if (file != nullptr && file->feature_flags_set) {
+ return file->feature_flags;
+ }
+ return 0;
+}
+
+
enum VettedEntityKind {
VettedEntity_Invalid,
@@ -732,9 +756,15 @@ gb_internal void check_scope_usage_internal(Checker *c, Scope *scope, u64 vet_fl
// TODO(bill): When is a good size warn?
// Is >256 KiB good enough?
if (sz > 1ll<<18) {
- gbString type_str = type_to_string(e->type);
- warning(e->token, "Declaration of '%.*s' may cause a stack overflow due to its type '%s' having a size of %lld bytes", LIT(e->token.string), type_str, cast(long long)sz);
- gb_string_free(type_str);
+ bool is_ref = false;
+ if((e->flags & EntityFlag_ForValue) != 0) {
+ is_ref = type_deref(e->Variable.for_loop_parent_type) != NULL;
+ }
+ if(!is_ref) {
+ gbString type_str = type_to_string(e->type);
+ warning(e->token, "Declaration of '%.*s' may cause a stack overflow due to its type '%s' having a size of %lld bytes", LIT(e->token.string), type_str, cast(long long)sz);
+ gb_string_free(type_str);
+ }
}
}
}
@@ -802,11 +832,17 @@ gb_internal void add_dependency(CheckerInfo *info, DeclInfo *d, Entity *e) {
rw_mutex_unlock(&d->deps_mutex);
}
gb_internal void add_type_info_dependency(CheckerInfo *info, DeclInfo *d, Type *type) {
- if (d == nullptr) {
+ if (d == nullptr || type == nullptr) {
return;
}
+ if (type->kind == Type_Named) {
+ Entity *e = type->Named.type_name;
+ if (e->TypeName.is_type_alias) {
+ type = type->Named.base;
+ }
+ }
rw_mutex_lock(&d->type_info_deps_mutex);
- ptr_set_add(&d->type_info_deps, type);
+ type_set_add(&d->type_info_deps, type);
rw_mutex_unlock(&d->type_info_deps_mutex);
}
@@ -1164,7 +1200,6 @@ gb_internal void init_universal(void) {
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);
add_global_bool_constant("ODIN_USE_SEPARATE_MODULES", bc->use_separate_modules);
add_global_bool_constant("ODIN_TEST", bc->command_kind == Command_test);
@@ -1336,8 +1371,11 @@ gb_internal void init_checker_info(CheckerInfo *i) {
string_map_init(&i->foreigns);
// map_init(&i->gen_procs);
map_init(&i->gen_types);
- array_init(&i->type_info_types, a);
- map_init(&i->type_info_map);
+
+ type_set_init(&i->min_dep_type_info_set);
+ map_init(&i->min_dep_type_info_index_map);
+
+ // map_init(&i->type_info_map);
string_map_init(&i->files);
string_map_init(&i->packages);
array_init(&i->variable_init_order, a);
@@ -1356,6 +1394,7 @@ gb_internal void init_checker_info(CheckerInfo *i) {
mpsc_init(&i->required_global_variable_queue, a); // 1<<10);
mpsc_init(&i->required_foreign_imports_through_force_queue, a); // 1<<10);
mpsc_init(&i->foreign_imports_to_check_fullpaths, a); // 1<<10);
+ mpsc_init(&i->foreign_decls_to_check, a); // 1<<10);
mpsc_init(&i->intrinsics_entry_point_usage, a); // 1<<10); // just waste some memory here, even if it probably never used
string_map_init(&i->load_directory_cache);
@@ -1369,8 +1408,10 @@ gb_internal void destroy_checker_info(CheckerInfo *i) {
string_map_destroy(&i->foreigns);
// map_destroy(&i->gen_procs);
map_destroy(&i->gen_types);
- array_free(&i->type_info_types);
- map_destroy(&i->type_info_map);
+
+ type_set_destroy(&i->min_dep_type_info_set);
+ map_destroy(&i->min_dep_type_info_index_map);
+
string_map_destroy(&i->files);
string_map_destroy(&i->packages);
array_free(&i->variable_init_order);
@@ -1382,6 +1423,7 @@ gb_internal void destroy_checker_info(CheckerInfo *i) {
mpsc_destroy(&i->required_global_variable_queue);
mpsc_destroy(&i->required_foreign_imports_through_force_queue);
mpsc_destroy(&i->foreign_imports_to_check_fullpaths);
+ mpsc_destroy(&i->foreign_decls_to_check);
map_destroy(&i->objc_msgSend_types);
string_map_destroy(&i->load_file_cache);
@@ -1603,41 +1645,36 @@ gb_internal void check_remove_expr_info(CheckerContext *c, Ast *e) {
}
}
-
-gb_internal isize type_info_index(CheckerInfo *info, Type *type, bool error_on_failure) {
- type = default_type(type);
- if (type == t_llvm_bool) {
- type = t_bool;
- }
-
- mutex_lock(&info->type_info_mutex);
+gb_internal isize type_info_index(CheckerInfo *info, TypeInfoPair pair, bool error_on_failure) {
+ mutex_lock(&info->minimum_dependency_type_info_mutex);
isize entry_index = -1;
- isize *found_entry_index = map_get(&info->type_info_map, type);
+ u64 hash = pair.hash;
+ isize *found_entry_index = map_get(&info->min_dep_type_info_index_map, hash);
if (found_entry_index) {
entry_index = *found_entry_index;
}
- if (entry_index < 0) {
- // NOTE(bill): Do manual linear search
- for (auto const &e : info->type_info_map) {
- if (are_types_identical_unique_tuples(e.key, type)) {
- entry_index = e.value;
- // NOTE(bill): Add it to the search map
- map_set(&info->type_info_map, type, entry_index);
- break;
- }
- }
- }
-
- mutex_unlock(&info->type_info_mutex);
+ mutex_unlock(&info->minimum_dependency_type_info_mutex);
if (error_on_failure && entry_index < 0) {
- compiler_error("Type_Info for '%s' could not be found", type_to_string(type));
+ compiler_error("Type_Info for '%s' could not be found", type_to_string(pair.type));
}
return entry_index;
}
+gb_internal isize type_info_index(CheckerInfo *info, Type *type, bool error_on_failure) {
+ type = default_type(type);
+ if (type == t_llvm_bool) {
+ type = t_bool;
+ }
+
+ u64 hash = type_hash_canonical_type(type);
+ return type_info_index(info, {type, hash}, error_on_failure);
+}
+
+
+
gb_internal void add_untyped(CheckerContext *c, Ast *expr, AddressingMode mode, Type *type, ExactValue const &value) {
if (expr == nullptr) {
return;
@@ -1989,8 +2026,12 @@ gb_internal void add_type_info_type_internal(CheckerContext *c, Type *t) {
}
add_type_info_dependency(c->info, c->decl, t);
-
+#if 0
MUTEX_GUARD_BLOCK(&c->info->type_info_mutex) {
+ if (type_set_update(&c->info->type_info_set, t)) {
+ // return;
+ }
+
auto found = map_get(&c->info->type_info_map, t);
if (found != nullptr) {
// Types have already been added
@@ -2013,7 +2054,8 @@ gb_internal void add_type_info_type_internal(CheckerContext *c, Type *t) {
// Unique entry
// NOTE(bill): map entries grow linearly and in order
ti_index = c->info->type_info_types.count;
- array_add(&c->info->type_info_types, t);
+ TypeInfoPair tt = {t, type_hash_canonical_type(t)};
+ array_add(&c->info->type_info_types, tt);
}
map_set(&c->checker->info.type_info_map, t, ti_index);
@@ -2208,6 +2250,7 @@ gb_internal void add_type_info_type_internal(CheckerContext *c, Type *t) {
GB_PANIC("Unhandled type: %*.s %d", LIT(type_strings[bt->kind]), bt->kind);
break;
}
+#endif
}
@@ -2265,19 +2308,7 @@ gb_internal void add_min_dep_type_info(Checker *c, Type *t) {
return;
}
- auto *set = &c->info.minimum_dependency_type_info_set;
-
- isize ti_index = type_info_index(&c->info, t, false);
- if (ti_index < 0) {
- add_type_info_type(&c->builtin_ctx, t); // Missing the type information
- ti_index = type_info_index(&c->info, t, false);
- }
- GB_ASSERT(ti_index >= 0);
- // IMPORTANT NOTE(bill): this must be copied as `map_set` takes a const ref
- // and effectively assigns the `+1` of the value
- isize const count = set->count;
- if (map_set_if_not_previously_exists(set, ti_index+1, count)) {
- // Type already exists;
+ if (type_set_update(&c->info.min_dep_type_info_set, t)) {
return;
}
@@ -2477,8 +2508,8 @@ gb_internal void add_dependency_to_set(Checker *c, Entity *entity) {
if (decl == nullptr) {
return;
}
- for (Type *t : decl->type_info_deps) {
- add_min_dep_type_info(c, t);
+ for (TypeInfoPair const tt : decl->type_info_deps) {
+ add_min_dep_type_info(c, tt.type);
}
for (Entity *e : decl->deps) {
@@ -2678,7 +2709,6 @@ gb_internal void generate_minimum_dependency_set(Checker *c, Entity *start) {
isize min_dep_set_cap = next_pow2_isize(entity_count*4); // empirically determined factor
ptr_set_init(&c->info.minimum_dependency_set, min_dep_set_cap);
- map_init(&c->info.minimum_dependency_type_info_set);
#define FORCE_ADD_RUNTIME_ENTITIES(condition, ...) do { \
if (condition) { \
@@ -3870,6 +3900,7 @@ gb_internal DECL_ATTRIBUTE_PROC(type_decl_attribute) {
#include "check_expr.cpp"
#include "check_builtin.cpp"
#include "check_type.cpp"
+#include "name_canonicalization.cpp"
#include "check_decl.cpp"
#include "check_stmt.cpp"
@@ -4992,6 +5023,9 @@ gb_internal DECL_ATTRIBUTE_PROC(foreign_import_decl_attribute) {
error(elem, "Expected a string value for '%.*s'", LIT(name));
}
return true;
+ } else if (name == "export") {
+ ac->is_export = true;
+ return true;
} else if (name == "force" || name == "require") {
if (value != nullptr) {
error(elem, "Expected no parameter for '%.*s'", LIT(name));
@@ -5016,6 +5050,12 @@ gb_internal DECL_ATTRIBUTE_PROC(foreign_import_decl_attribute) {
ac->extra_linker_flags = ev.value_string;
}
return true;
+ } else if (name == "ignore_duplicates") {
+ if (value != nullptr) {
+ error(elem, "Expected no parameter for '%.*s'", LIT(name));
+ }
+ ac->ignore_duplicates = true;
+ return true;
}
return false;
}
@@ -5094,6 +5134,38 @@ gb_internal void check_foreign_import_fullpaths(Checker *c) {
e->LibraryName.paths = fl->fullpaths;
}
+
+ for (Entity *e = nullptr; mpsc_dequeue(&c->info.foreign_decls_to_check, &e); /**/) {
+ GB_ASSERT(e != nullptr);
+ if (e->kind != Entity_Procedure) {
+ continue;
+ }
+ if (!is_arch_wasm()) {
+ continue;
+ }
+ Entity *foreign_library = e->Procedure.foreign_library;
+ GB_ASSERT(foreign_library != nullptr);
+
+ String name = e->Procedure.link_name;
+
+ String module_name = str_lit("env");
+ GB_ASSERT (foreign_library->kind == Entity_LibraryName);
+ if (foreign_library->LibraryName.paths.count != 1) {
+ error(foreign_library->token, "'foreign import' for '%.*s' architecture may only have one path, got %td",
+ LIT(target_arch_names[build_context.metrics.arch]), foreign_library->LibraryName.paths.count);
+ }
+
+ if (foreign_library->LibraryName.paths.count >= 1) {
+ module_name = foreign_library->LibraryName.paths[0];
+ }
+
+ if (!string_ends_with(module_name, str_lit(".o"))) {
+ name = concatenate3_strings(permanent_allocator(), module_name, WASM_MODULE_NAME_SEPARATOR, name);
+ }
+ e->Procedure.link_name = name;
+
+ check_foreign_procedure(&ctx, e, e->decl_info);
+ }
}
gb_internal void check_add_foreign_import_decl(CheckerContext *ctx, Ast *decl) {
@@ -5119,14 +5191,21 @@ gb_internal void check_add_foreign_import_decl(CheckerContext *ctx, Ast *decl) {
GB_ASSERT(fl->library_name.pos.line != 0);
fl->library_name.string = library_name;
+ AttributeContext ac = {};
+ check_decl_attributes(ctx, fl->attributes, foreign_import_decl_attribute, &ac);
+
+ Scope *scope = parent_scope;
+ if (ac.is_export) {
+ scope = parent_scope->parent;
+ }
+
Entity *e = alloc_entity_library_name(parent_scope, fl->library_name, t_invalid,
fl->fullpaths, library_name);
e->LibraryName.decl = decl;
add_entity_flags_from_file(ctx, e, parent_scope);
- add_entity(ctx, parent_scope, nullptr, e);
+ add_entity(ctx, scope, nullptr, e);
+
- AttributeContext ac = {};
- check_decl_attributes(ctx, fl->attributes, foreign_import_decl_attribute, &ac);
if (ac.require_declaration) {
mpsc_enqueue(&ctx->info->required_foreign_imports_through_force_queue, e);
add_entity_use(ctx, nullptr, e);
@@ -5134,6 +5213,9 @@ gb_internal void check_add_foreign_import_decl(CheckerContext *ctx, Ast *decl) {
if (ac.foreign_import_priority_index != 0) {
e->LibraryName.priority_index = ac.foreign_import_priority_index;
}
+ if (ac.ignore_duplicates) {
+ e->LibraryName.ignore_duplicates = true;
+ }
String extra_linker_flags = string_trim_whitespace(ac.extra_linker_flags);
if (extra_linker_flags.len != 0) {
e->LibraryName.extra_linker_flags = extra_linker_flags;
@@ -6244,6 +6326,10 @@ gb_internal void check_deferred_procedures(Checker *c) {
continue;
}
+ if (dst_params == nullptr) {
+ error(src->token, "Deferred procedure must have parameters for %s", attribute);
+ continue;
+ }
GB_ASSERT(dst_params->kind == Type_Tuple);
Type *tsrc = alloc_type_tuple();
@@ -6645,6 +6731,58 @@ gb_internal void check_parsed_files(Checker *c) {
add_type_and_value(&c->builtin_ctx, u.expr, u.info->mode, u.info->type, u.info->value);
}
+ TIME_SECTION("initialize and check for collisions in type info array");
+ {
+ Array<TypeInfoPair> type_info_types; // sorted after filled
+ array_init(&type_info_types, heap_allocator());
+ defer (array_free(&type_info_types));
+
+ for (auto const &tt : c->info.min_dep_type_info_set) {
+ array_add(&type_info_types, tt);
+ }
+ array_sort(type_info_types, type_info_pair_cmp);
+
+ array_init(&c->info.type_info_types_hash_map, heap_allocator(), type_info_types.count*2 + 1);
+ map_reserve(&c->info.min_dep_type_info_index_map, type_info_types.count);
+
+ isize hash_map_len = c->info.type_info_types_hash_map.count;
+ for (auto const &tt : type_info_types) {
+ isize index = tt.hash % hash_map_len;
+ // NOTE(bill): no need for a sanity check since there
+ // will always be enough space for the entries
+ for (;;) {
+ if (index == 0 || c->info.type_info_types_hash_map[index].hash != 0) {
+ index = (index+1) % hash_map_len;
+ continue;
+ }
+ break;
+ }
+ c->info.type_info_types_hash_map[index] = tt;
+
+ bool exists = map_set_if_not_previously_exists(&c->info.min_dep_type_info_index_map, tt.hash, index);
+ if (exists) {
+ for (auto const &entry : c->info.min_dep_type_info_index_map) {
+ if (entry.key != tt.hash) {
+ continue;
+ }
+ auto const &other = type_info_types[entry.value];
+ if (are_types_identical_unique_tuples(tt.type, other.type)) {
+ continue;
+ }
+ gbString t = temp_canonical_string(tt.type);
+ gbString o = temp_canonical_string(other.type);
+ GB_PANIC("%s (%s) %llu vs %s (%s) %llu",
+ type_to_string(tt.type, false), t, cast(unsigned long long)tt.hash,
+ type_to_string(other.type, false), o, cast(unsigned long long)other.hash);
+ }
+ }
+ }
+
+
+ GB_ASSERT(c->info.min_dep_type_info_index_map.count <= type_info_types.count);
+ }
+
+
TIME_SECTION("sort init and fini procedures");
check_sort_init_and_fini_procedures(c);
diff --git a/src/checker.hpp b/src/checker.hpp
index 438156f18..d3b2d7d89 100644
--- a/src/checker.hpp
+++ b/src/checker.hpp
@@ -140,6 +140,7 @@ struct AttributeContext {
bool instrumentation_enter : 1;
bool instrumentation_exit : 1;
bool rodata : 1;
+ bool ignore_duplicates : 1;
u32 optimization_mode; // ProcedureOptimizationMode
i64 foreign_import_priority_index;
String extra_linker_flags;
@@ -166,6 +167,7 @@ typedef DECL_ATTRIBUTE_PROC(DeclAttributeProc);
gb_internal void check_decl_attributes(CheckerContext *c, Array<Ast *> const &attributes, DeclAttributeProc *proc, AttributeContext *ac);
+#include "name_canonicalization.hpp"
enum ProcCheckedState : u8 {
ProcCheckedState_Unchecked,
@@ -220,13 +222,15 @@ struct DeclInfo {
RwMutex deps_mutex;
PtrSet<Entity *> deps;
- RwMutex type_info_deps_mutex;
- PtrSet<Type *> type_info_deps;
+ RwMutex type_info_deps_mutex;
+ TypeSet type_info_deps;
BlockingMutex type_and_value_mutex;
Array<BlockLabel> labels;
+ i32 scope_index;
+
Array<VariadicReuseData> variadic_reuses;
i64 variadic_reuse_max_bytes;
i64 variadic_reuse_max_align;
@@ -271,10 +275,14 @@ struct Scope {
std::atomic<Scope *> next;
std::atomic<Scope *> head_child;
+ i32 index; // within a procedure
+
RwMutex mutex;
StringMap<Entity *> elements;
PtrSet<Scope *> imported;
+ DeclInfo *decl_info;
+
i32 flags; // ScopeFlag
union {
AstPackage *pkg;
@@ -420,8 +428,10 @@ struct CheckerInfo {
Scope * init_scope;
Entity * entry_point;
PtrSet<Entity *> minimum_dependency_set;
- PtrMap</*type info index*/isize, /*min dep index*/isize> minimum_dependency_type_info_set;
-
+ BlockingMutex minimum_dependency_type_info_mutex;
+ PtrMap</*type info hash*/u64, /*min dep index*/isize> min_dep_type_info_index_map;
+ TypeSet min_dep_type_info_set;
+ Array<TypeInfoPair> type_info_types_hash_map; // 2 * type_info_types.count
Array<Entity *> testing_procedures;
@@ -449,9 +459,10 @@ struct CheckerInfo {
BlockingMutex gen_types_mutex;
PtrMap<Type *, GenTypesData *> gen_types;
- BlockingMutex type_info_mutex; // NOT recursive
- Array<Type *> type_info_types;
- PtrMap<Type *, isize> type_info_map;
+ // BlockingMutex type_info_mutex; // NOT recursive
+ // Array<TypeInfoPair> type_info_types;
+ // PtrMap<Type *, isize> type_info_map;
+ // TypeSet type_info_set;
BlockingMutex foreign_mutex; // NOT recursive
StringMap<Entity *> foreigns;
@@ -461,6 +472,7 @@ struct CheckerInfo {
MPSCQueue<Entity *> required_global_variable_queue;
MPSCQueue<Entity *> required_foreign_imports_through_force_queue;
MPSCQueue<Entity *> foreign_imports_to_check_fullpaths;
+ MPSCQueue<Entity *> foreign_decls_to_check;
MPSCQueue<Ast *> intrinsics_entry_point_usage;
@@ -521,6 +533,7 @@ struct CheckerContext {
bool in_enum_type;
bool collect_delayed_decls;
bool allow_polymorphic_types;
+ bool disallow_polymorphic_return_types; // NOTE(zen3ger): no poly type decl in return types
bool no_polymorphic_errors;
bool hide_polymorphic_errors;
bool in_polymorphic_specialization;
@@ -568,6 +581,7 @@ gb_internal DeclInfo * decl_info_of_entity (Entity * e);
gb_internal AstFile * ast_file_of_filename (CheckerInfo *i, String filename);
// IMPORTANT: Only to use once checking is done
gb_internal isize type_info_index (CheckerInfo *i, Type *type, bool error_on_failure);
+gb_internal isize type_info_index (CheckerInfo *info, TypeInfoPair pair, bool error_on_failure);
// Will return nullptr if not found
gb_internal Entity *entity_of_node(Ast *expr);
diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp
index 2dfd570e4..40dde8240 100644
--- a/src/checker_builtin_procs.hpp
+++ b/src/checker_builtin_procs.hpp
@@ -181,6 +181,9 @@ BuiltinProc__simd_begin,
BuiltinProc_simd_reduce_any,
BuiltinProc_simd_reduce_all,
+ BuiltinProc_simd_extract_lsbs,
+ BuiltinProc_simd_extract_msbs,
+
BuiltinProc_simd_shuffle,
BuiltinProc_simd_select,
@@ -523,6 +526,9 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
{STR_LIT("simd_reduce_any"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("simd_reduce_all"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
+ {STR_LIT("simd_extract_lsbs"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
+ {STR_LIT("simd_extract_msbs"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
+
{STR_LIT("simd_shuffle"), 2, true, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("simd_select"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
diff --git a/src/common.cpp b/src/common.cpp
index 0ef39bd10..ad1e5a851 100644
--- a/src/common.cpp
+++ b/src/common.cpp
@@ -134,9 +134,9 @@ gb_internal u32 fnv32a(void const *data, isize len) {
return h;
}
-gb_internal u64 fnv64a(void const *data, isize len) {
+gb_internal u64 fnv64a(void const *data, isize len, u64 seed=0xcbf29ce484222325ull) {
u8 const *bytes = cast(u8 const *)data;
- u64 h = 0xcbf29ce484222325ull;
+ u64 h = seed;
for (; len >= 8; len -= 8, bytes += 8) {
h = (h ^ bytes[0]) * 0x100000001b3ull;
diff --git a/src/docs_writer.cpp b/src/docs_writer.cpp
index 341b3fa6b..a92ffc7ad 100644
--- a/src/docs_writer.cpp
+++ b/src/docs_writer.cpp
@@ -16,6 +16,8 @@ gb_global char const* OdinDocWriterState_strings[] {
"writing ",
};
+gb_global std::atomic<bool> g_in_doc_writer;
+
struct OdinDocWriter {
CheckerInfo *info;
OdinDocWriterState state;
@@ -26,11 +28,10 @@ struct OdinDocWriter {
StringMap<OdinDocString> string_cache;
- OrderedInsertPtrMap<AstFile *, OdinDocFileIndex> file_cache;
- OrderedInsertPtrMap<AstPackage *, OdinDocPkgIndex> pkg_cache;
- OrderedInsertPtrMap<Entity *, OdinDocEntityIndex> entity_cache;
- OrderedInsertPtrMap<Type *, OdinDocTypeIndex> type_cache;
- OrderedInsertPtrMap<Type *, Type *> stable_type_cache;
+ OrderedInsertPtrMap<AstFile *, OdinDocFileIndex> file_cache;
+ OrderedInsertPtrMap<AstPackage *, OdinDocPkgIndex> pkg_cache;
+ OrderedInsertPtrMap<Entity *, OdinDocEntityIndex> entity_cache;
+ OrderedInsertPtrMap<u64/*type hash*/, OdinDocTypeIndex> type_cache;
OdinDocWriterItemTracker<OdinDocFile> files;
OdinDocWriterItemTracker<OdinDocPkg> pkgs;
@@ -61,7 +62,6 @@ gb_internal void odin_doc_writer_prepare(OdinDocWriter *w) {
map_init(&w->pkg_cache, 1<<10);
map_init(&w->entity_cache, 1<<18);
map_init(&w->type_cache, 1<<18);
- map_init(&w->stable_type_cache, 1<<18);
odin_doc_writer_item_tracker_init(&w->files, 1);
odin_doc_writer_item_tracker_init(&w->pkgs, 1);
@@ -81,7 +81,6 @@ gb_internal void odin_doc_writer_destroy(OdinDocWriter *w) {
map_destroy(&w->pkg_cache);
map_destroy(&w->entity_cache);
map_destroy(&w->type_cache);
- map_destroy(&w->stable_type_cache);
}
@@ -492,55 +491,18 @@ gb_internal OdinDocTypeIndex odin_doc_type(OdinDocWriter *w, Type *type) {
}
}
- // Type **mapped_type = map_get(&w->stable_type_cache, type); // may map to itself
- // if (mapped_type && *mapped_type) {
- // type = *mapped_type;
- // }
-
- OdinDocTypeIndex *found = map_get(&w->type_cache, type);
+ u64 type_hash = type_hash_canonical_type(type);
+ OdinDocTypeIndex *found = map_get(&w->type_cache, type_hash);
if (found) {
return *found;
}
- for (auto const &entry : w->type_cache) {
- // NOTE(bill): THIS IS SLOW
- Type *x = type;
- Type *y = entry.key;
-
- if (x == y) {
- goto do_set;
- }
-
- if (!x | !y) {
- continue;
- }
- if (y->kind == Type_Named) {
- Entity *e = y->Named.type_name;
- if (e->TypeName.is_type_alias) {
- y = y->Named.base;
- }
- }
- if (x->kind != y->kind) {
- continue;
- }
-
- if (!are_types_identical_internal(x, y, true)) {
- continue;
- }
-
- do_set:
- OdinDocTypeIndex index = entry.value;
- map_set(&w->type_cache, type, index);
- map_set(&w->stable_type_cache, type, entry.key);
- return index;
- }
OdinDocType *dst = nullptr;
OdinDocType doc_type = {};
OdinDocTypeIndex type_index = 0;
type_index = odin_doc_write_item(w, &w->types, &doc_type, &dst);
- map_set(&w->type_cache, type, type_index);
- map_set(&w->stable_type_cache, type, type);
+ map_set(&w->type_cache, type_hash, type_index);
switch (type->kind) {
case Type_Basic:
@@ -1177,6 +1139,8 @@ gb_internal void odin_doc_write_to_file(OdinDocWriter *w, char const *filename)
}
gb_internal void odin_doc_write(CheckerInfo *info, char const *filename) {
+ g_in_doc_writer.store(true);
+
OdinDocWriter w_ = {};
OdinDocWriter *w = &w_;
defer (odin_doc_writer_destroy(w));
@@ -1192,4 +1156,11 @@ gb_internal void odin_doc_write(CheckerInfo *info, char const *filename) {
odin_doc_writer_end_writing(w);
odin_doc_write_to_file(w, filename);
+
+ g_in_doc_writer.store(false);
}
+
+
+gb_internal bool is_in_doc_writer(void) {
+ return g_in_doc_writer.load();
+} \ No newline at end of file
diff --git a/src/entity.cpp b/src/entity.cpp
index 0c4a20df4..b2148aa7b 100644
--- a/src/entity.cpp
+++ b/src/entity.cpp
@@ -256,6 +256,8 @@ struct Entity {
bool entry_point_only : 1;
bool has_instrumentation : 1;
bool is_memcpy_like : 1;
+ bool uses_branch_location : 1;
+ bool is_anonymous : 1;
} Procedure;
struct {
Array<Entity *> entities;
@@ -273,6 +275,7 @@ struct Entity {
Slice<String> paths;
String name;
i64 priority_index;
+ bool ignore_duplicates;
String extra_linker_flags;
} LibraryName;
i32 Nil;
diff --git a/src/exact_value.cpp b/src/exact_value.cpp
index 5d6016ecc..ceaed84c1 100644
--- a/src/exact_value.cpp
+++ b/src/exact_value.cpp
@@ -370,7 +370,11 @@ gb_internal ExactValue exact_value_from_basic_literal(TokenKind kind, String con
}
case Token_Rune: {
Rune r = GB_RUNE_INVALID;
- utf8_decode(string.text, string.len, &r);
+ if (string.len == 1) {
+ r = cast(Rune)string.text[0];
+ } else {
+ utf8_decode(string.text, string.len, &r);
+ }
return exact_value_i64(r);
}
}
diff --git a/src/gb/gb.h b/src/gb/gb.h
index f74026c7d..98c362e93 100644
--- a/src/gb/gb.h
+++ b/src/gb/gb.h
@@ -5837,15 +5837,26 @@ gb_inline isize gb_printf_err_va(char const *fmt, va_list va) {
}
gb_inline isize gb_fprintf_va(struct gbFile *f, char const *fmt, va_list va) {
- gb_local_persist char buf[4096];
+ char buf[4096];
isize len = gb_snprintf_va(buf, gb_size_of(buf), fmt, va);
+ char *new_buf = NULL;
+ isize n = gb_size_of(buf);
+ while (len < 0) {
+ n <<= 1;
+ gb_free(gb_heap_allocator(), new_buf);
+ new_buf = gb_alloc_array(gb_heap_allocator(), char, n);;
+ len = gb_snprintf_va(new_buf, n, fmt, va);
+ }
gb_file_write(f, buf, len-1); // NOTE(bill): prevent extra whitespace
+ if (new_buf != NULL) {
+ gb_free(gb_heap_allocator(), new_buf);
+ }
return len;
}
gb_inline char *gb_bprintf_va(char const *fmt, va_list va) {
- gb_local_persist char buffer[4096];
+ gb_thread_local gb_local_persist char buffer[4096];
gb_snprintf_va(buffer, gb_size_of(buffer), fmt, va);
return buffer;
}
diff --git a/src/linker.cpp b/src/linker.cpp
index 261d6e7a4..cf2ef638d 100644
--- a/src/linker.cpp
+++ b/src/linker.cpp
@@ -449,6 +449,26 @@ gb_internal i32 linker_stage(LinkerData *gen) {
if (extra_linker_flags.len != 0) {
lib_str = gb_string_append_fmt(lib_str, " %.*s", LIT(extra_linker_flags));
}
+
+ if (build_context.metrics.os == TargetOs_darwin) {
+ // Print frameworks first
+ for (String lib : e->LibraryName.paths) {
+ lib = string_trim_whitespace(lib);
+ if (lib.len == 0) {
+ continue;
+ }
+ if (string_ends_with(lib, str_lit(".framework"))) {
+ if (string_set_update(&min_libs_set, lib)) {
+ continue;
+ }
+
+ String lib_name = lib;
+ lib_name = remove_extension_from_path(lib_name);
+ lib_str = gb_string_append_fmt(lib_str, " -framework %.*s ", LIT(lib_name));
+ }
+ }
+ }
+
for (String lib : e->LibraryName.paths) {
lib = string_trim_whitespace(lib);
if (lib.len == 0) {
@@ -536,7 +556,18 @@ gb_internal i32 linker_stage(LinkerData *gen) {
}
array_add(&gen->output_object_paths, obj_file);
} else {
- if (string_set_update(&min_libs_set, lib) && build_context.min_link_libs) {
+ bool short_circuit = false;
+ if (string_ends_with(lib, str_lit(".framework"))) {
+ short_circuit = true;
+ } else if (string_ends_with(lib, str_lit(".dylib"))) {
+ short_circuit = true;
+ } else if (string_ends_with(lib, str_lit(".so"))) {
+ short_circuit = true;
+ } else if (e->LibraryName.ignore_duplicates) {
+ short_circuit = true;
+ }
+
+ if (string_set_update(&min_libs_set, lib) && (build_context.min_link_libs || short_circuit)) {
continue;
}
diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp
index 01ded321e..88e099930 100644
--- a/src/llvm_backend.cpp
+++ b/src/llvm_backend.cpp
@@ -24,7 +24,7 @@
#include "llvm_backend_stmt.cpp"
#include "llvm_backend_proc.cpp"
-String get_default_microarchitecture() {
+gb_internal String get_default_microarchitecture() {
String default_march = str_lit("generic");
if (build_context.metrics.arch == TargetArch_amd64) {
// NOTE(bill): x86-64-v2 is more than enough for everyone
@@ -47,7 +47,7 @@ String get_default_microarchitecture() {
return default_march;
}
-String get_final_microarchitecture() {
+gb_internal String get_final_microarchitecture() {
BuildContext *bc = &build_context;
String microarch = bc->microarch;
@@ -169,11 +169,17 @@ gb_internal void lb_correct_entity_linkage(lbGenerator *gen) {
other_global = LLVMGetNamedGlobal(ec.other_module->mod, ec.cname);
if (other_global) {
LLVMSetLinkage(other_global, LLVMWeakAnyLinkage);
+ if (!ec.e->Variable.is_export && !ec.e->Variable.is_foreign) {
+ LLVMSetVisibility(other_global, LLVMHiddenVisibility);
+ }
}
} else if (ec.e->kind == Entity_Procedure) {
other_global = LLVMGetNamedFunction(ec.other_module->mod, ec.cname);
if (other_global) {
LLVMSetLinkage(other_global, LLVMWeakAnyLinkage);
+ if (!ec.e->Procedure.is_export && !ec.e->Procedure.is_foreign) {
+ LLVMSetVisibility(other_global, LLVMHiddenVisibility);
+ }
}
}
}
@@ -227,6 +233,16 @@ gb_internal lbContextData *lb_push_context_onto_stack(lbProcedure *p, lbAddr ctx
}
+gb_internal String lb_internal_gen_name_from_type(char const *prefix, Type *type) {
+ gbString str = gb_string_make(permanent_allocator(), prefix);
+ u64 hash = type_hash_canonical_type(type);
+ str = gb_string_appendc(str, "-");
+ str = gb_string_append_fmt(str, "%llu", cast(unsigned long long)hash);
+ String proc_name = make_string(cast(u8 const *)str, gb_string_length(str));
+ return proc_name;
+}
+
+
gb_internal lbValue lb_equal_proc_for_type(lbModule *m, Type *type) {
type = base_type(type);
GB_ASSERT(is_type_comparable(type));
@@ -234,7 +250,8 @@ gb_internal lbValue lb_equal_proc_for_type(lbModule *m, Type *type) {
Type *pt = alloc_type_pointer(type);
LLVMTypeRef ptr_type = lb_type(m, pt);
- lbProcedure **found = map_get(&m->equal_procs, type);
+ String proc_name = lb_internal_gen_name_from_type("__$equal", type);
+ lbProcedure **found = string_map_get(&m->gen_procs, proc_name);
lbProcedure *compare_proc = nullptr;
if (found) {
compare_proc = *found;
@@ -242,17 +259,12 @@ gb_internal lbValue lb_equal_proc_for_type(lbModule *m, Type *type) {
return {compare_proc->value, compare_proc->type};
}
- static std::atomic<u32> proc_index;
-
- char buf[32] = {};
- isize n = gb_snprintf(buf, 32, "__$equal%u", 1+proc_index.fetch_add(1));
- char *str = gb_alloc_str_len(permanent_allocator(), buf, n-1);
- String proc_name = make_string_c(str);
lbProcedure *p = lb_create_dummy_procedure(m, proc_name, t_equal_proc);
- map_set(&m->equal_procs, type, p);
+ string_map_set(&m->gen_procs, proc_name, p);
lb_begin_procedure_body(p);
+ LLVMSetLinkage(p->value, LLVMInternalLinkage);
// lb_add_attribute_to_proc(m, p->value, "readonly");
lb_add_attribute_to_proc(m, p->value, "nounwind");
@@ -404,24 +416,19 @@ gb_internal lbValue lb_hasher_proc_for_type(lbModule *m, Type *type) {
Type *pt = alloc_type_pointer(type);
- lbProcedure **found = map_get(&m->hasher_procs, type);
+ String proc_name = lb_internal_gen_name_from_type("__$hasher", type);
+ lbProcedure **found = string_map_get(&m->gen_procs, proc_name);
if (found) {
GB_ASSERT(*found != nullptr);
return {(*found)->value, (*found)->type};
}
- static std::atomic<u32> proc_index;
-
- char buf[32] = {};
- isize n = gb_snprintf(buf, 32, "__$hasher%u", 1+proc_index.fetch_add(1));
- char *str = gb_alloc_str_len(permanent_allocator(), buf, n-1);
- String proc_name = make_string_c(str);
-
lbProcedure *p = lb_create_dummy_procedure(m, proc_name, t_hasher_proc);
- map_set(&m->hasher_procs, type, p);
+ string_map_set(&m->gen_procs, proc_name, p);
lb_begin_procedure_body(p);
defer (lb_end_procedure_body(p));
+ LLVMSetLinkage(p->value, LLVMInternalLinkage);
// lb_add_attribute_to_proc(m, p->value, "readonly");
lb_add_attribute_to_proc(m, p->value, "nounwind");
@@ -571,21 +578,15 @@ gb_internal lbValue lb_map_get_proc_for_type(lbModule *m, Type *type) {
type = base_type(type);
GB_ASSERT(type->kind == Type_Map);
-
- lbProcedure **found = map_get(&m->map_get_procs, type);
+ String proc_name = lb_internal_gen_name_from_type("__$map_get", type);
+ lbProcedure **found = string_map_get(&m->gen_procs, proc_name);
if (found) {
GB_ASSERT(*found != nullptr);
return {(*found)->value, (*found)->type};
}
- static std::atomic<u32> proc_index;
-
- char buf[32] = {};
- isize n = gb_snprintf(buf, 32, "__$map_get-%u", 1+proc_index.fetch_add(1));
- char *str = gb_alloc_str_len(permanent_allocator(), buf, n-1);
- String proc_name = make_string_c(str);
lbProcedure *p = lb_create_dummy_procedure(m, proc_name, t_map_get_proc);
- map_set(&m->map_get_procs, type, p);
+ string_map_set(&m->gen_procs, proc_name, p);
lb_begin_procedure_body(p);
defer (lb_end_procedure_body(p));
@@ -752,21 +753,15 @@ gb_internal lbValue lb_map_set_proc_for_type(lbModule *m, Type *type) {
type = base_type(type);
GB_ASSERT(type->kind == Type_Map);
-
- lbProcedure **found = map_get(&m->map_set_procs, type);
+ String proc_name = lb_internal_gen_name_from_type("__$map_set", type);
+ lbProcedure **found = string_map_get(&m->gen_procs, proc_name);
if (found) {
GB_ASSERT(*found != nullptr);
return {(*found)->value, (*found)->type};
}
- static std::atomic<u32> proc_index;
-
- char buf[32] = {};
- isize n = gb_snprintf(buf, 32, "__$map_set-%u", 1+proc_index.fetch_add(1));
- char *str = gb_alloc_str_len(permanent_allocator(), buf, n-1);
- String proc_name = make_string_c(str);
lbProcedure *p = lb_create_dummy_procedure(m, proc_name, t_map_set_proc);
- map_set(&m->map_set_procs, type, p);
+ string_map_set(&m->gen_procs, proc_name, p);
lb_begin_procedure_body(p);
defer (lb_end_procedure_body(p));
@@ -911,7 +906,7 @@ gb_internal lbValue lb_gen_map_cell_info_ptr(lbModule *m, Type *type) {
LLVMValueRef llvm_res = llvm_const_named_struct(m, t_map_cell_info, const_values, gb_count_of(const_values));
lbValue res = {llvm_res, t_map_cell_info};
- lbAddr addr = lb_add_global_generated(m, t_map_cell_info, res, nullptr);
+ lbAddr addr = lb_add_global_generated_with_name(m, t_map_cell_info, res, lb_internal_gen_name_from_type("ggv$map_cell_info", type));
lb_make_global_private_const(addr);
map_set(&m->map_cell_info_map, type, addr);
@@ -942,7 +937,7 @@ gb_internal lbValue lb_gen_map_info_ptr(lbModule *m, Type *map_type) {
LLVMValueRef llvm_res = llvm_const_named_struct(m, t_map_info, const_values, gb_count_of(const_values));
lbValue res = {llvm_res, t_map_info};
- lbAddr addr = lb_add_global_generated(m, t_map_info, res, nullptr);
+ lbAddr addr = lb_add_global_generated_with_name(m, t_map_info, res, lb_internal_gen_name_from_type("ggv$map_info", map_type));
lb_make_global_private_const(addr);
map_set(&m->map_info_map, map_type, addr);
@@ -1096,8 +1091,6 @@ gb_internal void lb_internal_dynamic_map_set(lbProcedure *p, lbValue const &map_
}
gb_internal lbValue lb_dynamic_map_reserve(lbProcedure *p, lbValue const &map_ptr, isize const capacity, TokenPos const &pos) {
- GB_ASSERT(!build_context.no_dynamic_literals);
-
TEMPORARY_ALLOCATOR_GUARD();
String proc_name = {};
@@ -1149,14 +1142,14 @@ gb_internal void lb_finalize_objc_names(lbProcedure *p) {
String name = entry.key;
args[0] = lb_const_value(m, t_cstring, exact_value_string(name));
lbValue ptr = lb_emit_runtime_call(p, "objc_lookUpClass", args);
- lb_addr_store(p, entry.value, ptr);
+ lb_addr_store(p, entry.value.local_module_addr, ptr);
}
for (auto const &entry : m->objc_selectors) {
String name = entry.key;
args[0] = lb_const_value(m, t_cstring, exact_value_string(name));
lbValue ptr = lb_emit_runtime_call(p, "sel_registerName", args);
- lb_addr_store(p, entry.value, ptr);
+ lb_addr_store(p, entry.value.local_module_addr, ptr);
}
lb_end_procedure_body(p);
@@ -1280,7 +1273,10 @@ gb_internal lbProcedure *lb_create_startup_runtime(lbModule *main_module, lbProc
if (is_type_any(t)) {
// NOTE(bill): Edge case for 'any' type
Type *var_type = default_type(var.init.type);
- lbAddr g = lb_add_global_generated(main_module, var_type, var.init);
+ gbString var_name = gb_string_make(permanent_allocator(), "__$global_any::");
+ gbString e_str = string_canonical_entity_name(temporary_allocator(), e);
+ var_name = gb_string_append_length(var_name, e_str, gb_strlen(e_str));
+ lbAddr g = lb_add_global_generated_with_name(main_module, var_type, var.init, make_string_c(var_name));
lb_addr_store(p, g, var.init);
lbValue gp = lb_addr_get_ptr(p, g);
@@ -1559,21 +1555,13 @@ gb_internal WORKER_TASK_PROC(lb_llvm_function_pass_per_module) {
}
}
- for (auto const &entry : m->equal_procs) {
+ for (auto const &entry : m->gen_procs) {
lbProcedure *p = entry.value;
- lb_llvm_function_pass_per_function_internal(m, p);
- }
- for (auto const &entry : m->hasher_procs) {
- lbProcedure *p = entry.value;
- lb_llvm_function_pass_per_function_internal(m, p);
- }
- for (auto const &entry : m->map_get_procs) {
- lbProcedure *p = entry.value;
- lb_llvm_function_pass_per_function_internal(m, p, lbFunctionPassManager_none);
- }
- for (auto const &entry : m->map_set_procs) {
- lbProcedure *p = entry.value;
- lb_llvm_function_pass_per_function_internal(m, p, lbFunctionPassManager_none);
+ if (string_starts_with(p->name, str_lit("__$map"))) {
+ lb_llvm_function_pass_per_function_internal(m, p, lbFunctionPassManager_none);
+ } else {
+ lb_llvm_function_pass_per_function_internal(m, p);
+ }
}
return 0;
@@ -2571,17 +2559,16 @@ gb_internal String lb_filepath_ll_for_module(lbModule *m) {
build_context.build_paths[BuildPath_Output].name
);
- if (m->file) {
- char buf[32] = {};
- isize n = gb_snprintf(buf, gb_size_of(buf), "-%u", m->file->id);
- String suffix = make_string((u8 *)buf, n-1);
- path = concatenate_strings(permanent_allocator(), path, suffix);
- } else if (m->pkg) {
- path = concatenate3_strings(permanent_allocator(), path, STR_LIT("-"), m->pkg->name);
- } else if (USE_SEPARATE_MODULES) {
- path = concatenate_strings(permanent_allocator(), path, STR_LIT("-builtin"));
+ GB_ASSERT(m->module_name != nullptr);
+ String s = make_string_c(m->module_name);
+ String prefix = str_lit("odin_package-");
+ if (string_starts_with(s, prefix)) {
+ s.text += prefix.len;
+ s.len -= prefix.len;
}
- path = concatenate_strings(permanent_allocator(), path, STR_LIT(".ll"));
+
+ path = concatenate_strings(permanent_allocator(), path, s);
+ path = concatenate_strings(permanent_allocator(), s, STR_LIT(".ll"));
return path;
}
@@ -2604,17 +2591,21 @@ gb_internal String lb_filepath_obj_for_module(lbModule *m) {
path = gb_string_appendc(path, "/");
path = gb_string_append_length(path, name.text, name.len);
- if (m->file) {
- char buf[32] = {};
- isize n = gb_snprintf(buf, gb_size_of(buf), "-%u", m->file->id);
- String suffix = make_string((u8 *)buf, n-1);
- path = gb_string_append_length(path, suffix.text, suffix.len);
- } else if (m->pkg) {
- path = gb_string_appendc(path, "-");
- path = gb_string_append_length(path, m->pkg->name.text, m->pkg->name.len);
+ {
+
+ GB_ASSERT(m->module_name != nullptr);
+ String s = make_string_c(m->module_name);
+ String prefix = str_lit("odin_package");
+ if (string_starts_with(s, prefix)) {
+ s.text += prefix.len;
+ s.len -= prefix.len;
+ }
+
+ path = gb_string_append_length(path, s.text, s.len);
}
if (use_temporary_directory) {
+ // NOTE(bill): this must be suffixed to ensure it is not conflicting with anything else in the temporary directory
path = gb_string_append_fmt(path, "-%p", m);
}
@@ -2821,7 +2812,7 @@ gb_internal lbProcedure *lb_create_main_procedure(lbModule *m, lbProcedure *star
Type *t_Internal_Test = find_type_in_pkg(m->info, str_lit("testing"), str_lit("Internal_Test"));
Type *array_type = alloc_type_array(t_Internal_Test, m->info->testing_procedures.count);
Type *slice_type = alloc_type_slice(t_Internal_Test);
- lbAddr all_tests_array_addr = lb_add_global_generated(p->module, array_type, {});
+ lbAddr all_tests_array_addr = lb_add_global_generated_with_name(p->module, array_type, {}, str_lit("__$all_tests_array"));
lbValue all_tests_array = lb_addr_get_ptr(p, all_tests_array_addr);
LLVMValueRef indices[2] = {};
@@ -3150,7 +3141,10 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
lbModule *m = default_module;
{ // Add type info data
- isize max_type_info_count = info->minimum_dependency_type_info_set.count+1;
+ // GB_ASSERT_MSG(info->minimum_dependency_type_info_index_map.count == info->type_info_types.count, "%tu vs %tu", info->minimum_dependency_type_info_index_map.count, info->type_info_types.count);
+
+ // isize max_type_info_count = info->minimum_dependency_type_info_index_map.count+1;
+ isize max_type_info_count = info->type_info_types_hash_map.count;
Type *t = alloc_type_array(t_type_info_ptr, max_type_info_count);
// IMPORTANT NOTE(bill): As LLVM does not have a union type, an array of unions cannot be initialized
@@ -3162,7 +3156,7 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
LLVMValueRef g = LLVMAddGlobal(m->mod, internal_llvm_type, LB_TYPE_INFO_DATA_NAME);
LLVMSetInitializer(g, LLVMConstNull(internal_llvm_type));
LLVMSetLinkage(g, USE_SEPARATE_MODULES ? LLVMExternalLinkage : LLVMInternalLinkage);
- LLVMSetUnnamedAddress(g, LLVMGlobalUnnamedAddr);
+ // LLVMSetUnnamedAddress(g, LLVMGlobalUnnamedAddr);
LLVMSetGlobalConstant(g, true);
lbValue value = {};
@@ -3178,7 +3172,11 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
isize count = 0;
isize offsets_extra = 0;
- for (Type *t : m->info->type_info_types) {
+ for (auto const &tt : m->info->type_info_types_hash_map) {
+ Type *t = tt.type;
+ if (t == nullptr) {
+ continue;
+ }
isize index = lb_type_info_index(m->info, t, false);
if (index < 0) {
continue;
diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp
index e84ffd1cd..4fd1b8d1a 100644
--- a/src/llvm_backend.hpp
+++ b/src/llvm_backend.hpp
@@ -143,6 +143,11 @@ struct lbPadType {
LLVMTypeRef type;
};
+struct lbObjcRef {
+ Entity * entity;
+ lbAddr local_module_addr;
+};
+
struct lbModule {
LLVMModuleRef mod;
LLVMContextRef ctx;
@@ -155,15 +160,17 @@ struct lbModule {
AstFile *file; // possibly associated
char const *module_name;
- PtrMap<Type *, LLVMTypeRef> types; // mutex: types_mutex
+ PtrMap<u64/*type hash*/, LLVMTypeRef> types; // mutex: types_mutex
PtrMap<void *, lbStructFieldRemapping> struct_field_remapping; // Key: LLVMTypeRef or Type *, mutex: types_mutex
- PtrMap<Type *, LLVMTypeRef> func_raw_types; // mutex: func_raw_types_mutex
- RecursiveMutex types_mutex;
- RecursiveMutex func_raw_types_mutex;
+ PtrMap<u64/*type hash*/, LLVMTypeRef> func_raw_types; // mutex: func_raw_types_mutex
+ RecursiveMutex types_mutex;
+ RecursiveMutex func_raw_types_mutex;
i32 internal_type_level;
RwMutex values_mutex;
+ std::atomic<u32> global_array_index;
+
PtrMap<Entity *, lbValue> values;
PtrMap<Entity *, lbAddr> soa_values;
StringMap<lbValue> members;
@@ -173,14 +180,9 @@ struct lbModule {
StringMap<LLVMValueRef> const_strings;
- PtrMap<Type *, struct lbFunctionType *> function_type_map;
-
- PtrMap<Type *, lbProcedure *> equal_procs;
- PtrMap<Type *, lbProcedure *> hasher_procs;
- PtrMap<Type *, lbProcedure *> map_get_procs;
- PtrMap<Type *, lbProcedure *> map_set_procs;
+ PtrMap<u64/*type hash*/, struct lbFunctionType *> function_type_map;
- std::atomic<u32> nested_type_name_guid;
+ StringMap<lbProcedure *> gen_procs; // key is the canonicalized name
Array<lbProcedure *> procedures_to_generate;
Array<Entity *> global_procedures_to_create;
@@ -196,11 +198,11 @@ struct lbModule {
RecursiveMutex debug_values_mutex;
PtrMap<void *, LLVMMetadataRef> debug_values;
- StringMap<lbAddr> objc_classes;
- StringMap<lbAddr> objc_selectors;
+ StringMap<lbObjcRef> objc_classes;
+ StringMap<lbObjcRef> objc_selectors;
- PtrMap<Type *, lbAddr> map_cell_info_map; // address of runtime.Map_Info
- PtrMap<Type *, lbAddr> map_info_map; // address of runtime.Map_Cell_Info
+ PtrMap<u64/*type hash*/, lbAddr> map_cell_info_map; // address of runtime.Map_Info
+ PtrMap<u64/*type hash*/, lbAddr> map_info_map; // address of runtime.Map_Cell_Info
PtrMap<Ast *, lbAddr> exact_value_compound_literal_addr_map; // Key: Ast_CompoundLit
@@ -226,9 +228,6 @@ struct lbGenerator : LinkerData {
RecursiveMutex anonymous_proc_lits_mutex;
PtrMap<Ast *, lbProcedure *> anonymous_proc_lits;
- std::atomic<u32> global_array_index;
- std::atomic<u32> global_generated_index;
-
isize used_module_count;
lbProcedure *startup_runtime;
@@ -359,6 +358,12 @@ struct lbProcedure {
bool in_multi_assignment;
Array<LLVMValueRef> raw_input_parameters;
+ u32 global_generated_index;
+
+ bool uses_branch_location;
+ TokenPos branch_location_pos;
+ TokenPos curr_token_pos;
+
Array<lbVariadicReuseSlices> variadic_reuses;
lbAddr variadic_reuse_base_array_ptr;
@@ -390,7 +395,7 @@ struct lbProcedure {
gb_internal bool lb_init_generator(lbGenerator *gen, Checker *c);
gb_internal String lb_mangle_name(Entity *e);
-gb_internal String lb_get_entity_name(lbModule *m, Entity *e, String name = {});
+gb_internal String lb_get_entity_name(lbModule *m, Entity *e);
gb_internal LLVMAttributeRef lb_create_enum_attribute(LLVMContextRef ctx, char const *name, u64 value=0);
gb_internal LLVMAttributeRef lb_create_enum_attribute_with_type(LLVMContextRef ctx, char const *name, LLVMTypeRef type);
@@ -444,7 +449,8 @@ gb_internal lbValue lb_emit_matrix_ev(lbProcedure *p, lbValue s, isize row, isiz
gb_internal lbValue lb_emit_arith(lbProcedure *p, TokenKind op, lbValue lhs, lbValue rhs, Type *type);
gb_internal lbValue lb_emit_byte_swap(lbProcedure *p, lbValue value, Type *end_type);
-gb_internal void lb_emit_defer_stmts(lbProcedure *p, lbDeferExitKind kind, lbBlock *block);
+gb_internal void lb_emit_defer_stmts(lbProcedure *p, lbDeferExitKind kind, lbBlock *block, TokenPos pos);
+gb_internal void lb_emit_defer_stmts(lbProcedure *p, lbDeferExitKind kind, lbBlock *block, Ast *node);
gb_internal lbValue lb_emit_transmute(lbProcedure *p, lbValue value, Type *t);
gb_internal lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left, lbValue right);
gb_internal lbValue lb_emit_call(lbProcedure *p, lbValue value, Array<lbValue> const &args, ProcInlining inlining = ProcInlining_none);
@@ -463,7 +469,8 @@ gb_internal lbContextData *lb_push_context_onto_stack(lbProcedure *p, lbAddr ctx
gb_internal lbContextData *lb_push_context_onto_stack_from_implicit_parameter(lbProcedure *p);
-gb_internal lbAddr lb_add_global_generated(lbModule *m, Type *type, lbValue value={}, Entity **entity_=nullptr);
+gb_internal lbAddr lb_add_global_generated_from_procedure(lbProcedure *p, Type *type, lbValue value={});
+gb_internal lbAddr lb_add_global_generated_with_name(lbModule *m, Type *type, lbValue value, String name, Entity **entity_=nullptr);
gb_internal lbAddr lb_add_local(lbProcedure *p, Type *type, Entity *e=nullptr, bool zero_init=true, bool force_no_init=false);
gb_internal void lb_add_foreign_library_path(lbModule *m, Entity *e);
@@ -600,6 +607,9 @@ gb_internal LLVMTypeRef llvm_array_type(LLVMTypeRef ElementType, uint64_t Elemen
}
+gb_internal String lb_internal_gen_name_from_type(char const *prefix, Type *type);
+
+
gb_internal void lb_set_metadata_custom_u64(lbModule *m, LLVMValueRef v_ref, String name, u64 value);
gb_internal u64 lb_get_metadata_custom_u64(lbModule *m, LLVMValueRef v_ref, String name);
@@ -742,3 +752,5 @@ gb_global char const *llvm_linkage_strings[] = {
};
#define ODIN_METADATA_IS_PACKED str_lit("odin-is-packed")
+#define ODIN_METADATA_MIN_ALIGN str_lit("odin-min-align")
+#define ODIN_METADATA_MAX_ALIGN str_lit("odin-max-align")
diff --git a/src/llvm_backend_const.cpp b/src/llvm_backend_const.cpp
index 754bbfca2..b916c0017 100644
--- a/src/llvm_backend_const.cpp
+++ b/src/llvm_backend_const.cpp
@@ -330,31 +330,57 @@ gb_internal lbValue lb_emit_source_code_location_const(lbProcedure *p, Ast *node
return lb_emit_source_code_location_const(p, proc_name, pos);
}
+gb_internal String lb_source_code_location_gen_name(String const &procedure, TokenPos const &pos) {
+ gbString s = gb_string_make(permanent_allocator(), "scl$[");
+
+ s = gb_string_append_length(s, procedure.text, procedure.len);
+ if (pos.offset != 0) {
+ s = gb_string_append_fmt(s, "%d", pos.offset);
+ } else {
+ s = gb_string_append_fmt(s, "%d_%d", pos.line, pos.column);
+ }
+ s = gb_string_appendc(s, "]");
+
+ return make_string(cast(u8 const *)s, gb_string_length(s));
+}
+
+gb_internal String lb_source_code_location_gen_name(lbProcedure *p, Ast *node) {
+ String proc_name = {};
+ if (p->entity) {
+ proc_name = p->entity->token.string;
+ }
+ TokenPos pos = {};
+ if (node) {
+ pos = ast_token(node).pos;
+ }
+ return lb_source_code_location_gen_name(proc_name, pos);
+}
+
+
gb_internal lbValue lb_emit_source_code_location_as_global_ptr(lbProcedure *p, String const &procedure, TokenPos const &pos) {
lbValue loc = lb_emit_source_code_location_const(p, procedure, pos);
- lbAddr addr = lb_add_global_generated(p->module, loc.type, loc, nullptr);
+ lbAddr addr = lb_add_global_generated_with_name(p->module, loc.type, loc, lb_source_code_location_gen_name(procedure, pos));
lb_make_global_private_const(addr);
return addr.addr;
}
gb_internal lbValue lb_const_source_code_location_as_global_ptr(lbModule *m, String const &procedure, TokenPos const &pos) {
lbValue loc = lb_const_source_code_location_const(m, procedure, pos);
- lbAddr addr = lb_add_global_generated(m, loc.type, loc, nullptr);
+ lbAddr addr = lb_add_global_generated_with_name(m, loc.type, loc, lb_source_code_location_gen_name(procedure, pos));
lb_make_global_private_const(addr);
return addr.addr;
}
-
-
-
gb_internal lbValue lb_emit_source_code_location_as_global_ptr(lbProcedure *p, Ast *node) {
lbValue loc = lb_emit_source_code_location_const(p, node);
- lbAddr addr = lb_add_global_generated(p->module, loc.type, loc, nullptr);
+ lbAddr addr = lb_add_global_generated_with_name(p->module, loc.type, loc, lb_source_code_location_gen_name(p, node));
lb_make_global_private_const(addr);
return addr.addr;
}
+
+
gb_internal lbValue lb_emit_source_code_location_as_global(lbProcedure *p, String const &procedure, TokenPos const &pos) {
return lb_emit_load(p, lb_emit_source_code_location_as_global_ptr(p, procedure, pos));
}
@@ -562,12 +588,12 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo
return lb_addr_load(p, slice);
}
} else {
- isize max_len = 7+8+1;
- char *str = gb_alloc_array(permanent_allocator(), char, max_len);
- u32 id = m->gen->global_array_index.fetch_add(1);
- isize len = gb_snprintf(str, max_len, "csba$%x", id);
+ u32 id = m->global_array_index.fetch_add(1);
+ gbString str = gb_string_make(temporary_allocator(), "csba$");
+ str = gb_string_appendc(str, m->module_name);
+ str = gb_string_append_fmt(str, "$%x", id);
- String name = make_string(cast(u8 *)str, len-1);
+ String name = make_string(cast(u8 const *)str, gb_string_length(str));
Entity *e = alloc_entity_constant(nullptr, make_token_ident(name), t, value);
array_data = LLVMAddGlobal(m->mod, lb_type(m, t), str);
diff --git a/src/llvm_backend_debug.cpp b/src/llvm_backend_debug.cpp
index 464f7065c..067004bc1 100644
--- a/src/llvm_backend_debug.cpp
+++ b/src/llvm_backend_debug.cpp
@@ -408,13 +408,18 @@ gb_internal LLVMMetadataRef lb_debug_union(lbModule *m, Type *type, String name,
lb_set_llvm_metadata(m, type, temp_forward_decl);
isize index_offset = 1;
+ isize variant_offset = 1;
if (is_type_union_maybe_pointer(bt)) {
index_offset = 0;
+ variant_offset = 0;
+ } else if (bt->Union.kind == UnionType_no_nil) {
+ variant_offset = 0;
}
LLVMMetadataRef member_scope = lb_get_llvm_metadata(m, bt->Union.scope);
unsigned element_count = cast(unsigned)bt->Union.variants.count;
if (index_offset > 0) {
+ GB_ASSERT(index_offset == 1);
element_count += 1;
}
@@ -437,13 +442,11 @@ gb_internal LLVMMetadataRef lb_debug_union(lbModule *m, Type *type, String name,
for_array(j, bt->Union.variants) {
Type *variant = bt->Union.variants[j];
- unsigned field_index = cast(unsigned)(index_offset+j);
-
- char name[16] = {};
- gb_snprintf(name, gb_size_of(name), "v%u", field_index);
+ char name[32] = {};
+ gb_snprintf(name, gb_size_of(name), "v%td", variant_offset+j);
isize name_len = gb_strlen(name);
- elements[field_index] = LLVMDIBuilderCreateMemberType(
+ elements[index_offset+j] = LLVMDIBuilderCreateMemberType(
m->debug_builder, member_scope,
name, name_len,
file, line,
@@ -840,7 +843,7 @@ gb_internal LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) {
8*cast(unsigned)type_align_of(type),
lb_debug_type(m, type->EnumeratedArray.elem),
subscripts, gb_count_of(subscripts));
- gbString name = type_to_string(type, temporary_allocator());
+ gbString name = temp_canonical_string(type);
return LLVMDIBuilderCreateTypedef(m->debug_builder, array_type, name, gb_string_length(name), nullptr, 0, nullptr, cast(u32)(8*type_align_of(type)));
}
@@ -849,16 +852,16 @@ gb_internal LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) {
Type *bt = base_type(type->Map.debug_metadata_type);
GB_ASSERT(bt->kind == Type_Struct);
- return lb_debug_struct(m, type, bt, make_string_c(type_to_string(type, temporary_allocator())), nullptr, nullptr, 0);
+ return lb_debug_struct(m, type, bt, type_to_canonical_string(temporary_allocator(), type), nullptr, nullptr, 0);
}
- case Type_Struct: return lb_debug_struct( m, type, type, make_string_c(type_to_string(type, temporary_allocator())), nullptr, nullptr, 0);
- case Type_Slice: return lb_debug_slice( m, type, make_string_c(type_to_string(type, temporary_allocator())), nullptr, nullptr, 0);
- case Type_DynamicArray: return lb_debug_dynamic_array(m, type, make_string_c(type_to_string(type, temporary_allocator())), nullptr, nullptr, 0);
- case Type_Union: return lb_debug_union( m, type, make_string_c(type_to_string(type, temporary_allocator())), nullptr, nullptr, 0);
- case Type_BitSet: return lb_debug_bitset( m, type, make_string_c(type_to_string(type, temporary_allocator())), nullptr, nullptr, 0);
- case Type_Enum: return lb_debug_enum( m, type, make_string_c(type_to_string(type, temporary_allocator())), nullptr, nullptr, 0);
- case Type_BitField: return lb_debug_bitfield( m, type, make_string_c(type_to_string(type, temporary_allocator())), nullptr, nullptr, 0);
+ case Type_Struct: return lb_debug_struct( m, type, type, type_to_canonical_string(temporary_allocator(), type), nullptr, nullptr, 0);
+ case Type_Slice: return lb_debug_slice( m, type, type_to_canonical_string(temporary_allocator(), type), nullptr, nullptr, 0);
+ case Type_DynamicArray: return lb_debug_dynamic_array(m, type, type_to_canonical_string(temporary_allocator(), type), nullptr, nullptr, 0);
+ case Type_Union: return lb_debug_union( m, type, type_to_canonical_string(temporary_allocator(), type), nullptr, nullptr, 0);
+ case Type_BitSet: return lb_debug_bitset( m, type, type_to_canonical_string(temporary_allocator(), type), nullptr, nullptr, 0);
+ case Type_Enum: return lb_debug_enum( m, type, type_to_canonical_string(temporary_allocator(), type), nullptr, nullptr, 0);
+ case Type_BitField: return lb_debug_bitfield( m, type, type_to_canonical_string(temporary_allocator(), type), nullptr, nullptr, 0);
case Type_Tuple:
if (type->Tuple.variables.count == 1) {
@@ -901,7 +904,7 @@ gb_internal LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) {
{
LLVMMetadataRef proc_underlying_type = lb_debug_type_internal_proc(m, type);
LLVMMetadataRef pointer_type = LLVMDIBuilderCreatePointerType(m->debug_builder, proc_underlying_type, ptr_bits, ptr_bits, 0, nullptr, 0);
- gbString name = type_to_string(type, temporary_allocator());
+ gbString name = temp_canonical_string(type);
return LLVMDIBuilderCreateTypedef(m->debug_builder, pointer_type, name, gb_string_length(name), nullptr, 0, nullptr, cast(u32)(8*type_align_of(type)));
}
break;
@@ -984,10 +987,7 @@ gb_internal LLVMMetadataRef lb_debug_type(lbModule *m, Type *type) {
line = cast(unsigned)e->token.pos.line;
}
- String name = type->Named.name;
- if (type->Named.type_name && type->Named.type_name->pkg && type->Named.type_name->pkg->name.len != 0) {
- name = concatenate3_strings(temporary_allocator(), type->Named.type_name->pkg->name, str_lit("."), type->Named.name);
- }
+ String name = type_to_canonical_string(temporary_allocator(), type);
Type *bt = base_type(type->Named.base);
@@ -1184,8 +1184,8 @@ gb_internal void lb_add_debug_context_variable(lbProcedure *p, lbAddr const &ctx
gb_internal String debug_info_mangle_constant_name(Entity *e, gbAllocator const &allocator, bool *did_allocate_) {
String name = e->token.string;
if (e->pkg && e->pkg->name.len > 0) {
- // NOTE(bill): C++ NONSENSE FOR DEBUG SHITE!
- name = concatenate3_strings(allocator, e->pkg->name, str_lit("::"), name);
+ gbString s = string_canonical_entity_name(allocator, e);
+ name = make_string(cast(u8 const *)s, gb_string_length(s));
if (did_allocate_) *did_allocate_ = true;
}
return name;
diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp
index 1247eed76..56c7b45ec 100644
--- a/src/llvm_backend_expr.cpp
+++ b/src/llvm_backend_expr.cpp
@@ -1554,7 +1554,7 @@ gb_internal lbValue lb_build_binary_expr(lbProcedure *p, Ast *expr) {
lbValue cmp = lb_emit_comp_against_nil(p, be->op.kind, right);
Type *type = default_type(tv.type);
return lb_emit_conv(p, cmp, type);
- } else if (lb_is_empty_string_constant(be->right)) {
+ } else if (lb_is_empty_string_constant(be->right) && !is_type_union(be->left->tav.type)) {
// `x == ""` or `x != ""`
lbValue s = lb_build_expr(p, be->left);
s = lb_emit_conv(p, s, t_string);
@@ -1562,7 +1562,7 @@ gb_internal lbValue lb_build_binary_expr(lbProcedure *p, Ast *expr) {
lbValue cmp = lb_emit_comp(p, be->op.kind, len, lb_const_int(p->module, t_int, 0));
Type *type = default_type(tv.type);
return lb_emit_conv(p, cmp, type);
- } else if (lb_is_empty_string_constant(be->left)) {
+ } else if (lb_is_empty_string_constant(be->left) && !is_type_union(be->right->tav.type)) {
// `"" == x` or `"" != x`
lbValue s = lb_build_expr(p, be->right);
s = lb_emit_conv(p, s, t_string);
@@ -2312,9 +2312,9 @@ gb_internal lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) {
lbValue array_const_value = {};
array_const_value.type = t;
array_const_value.value = LLVMConstArray(lb_type(m, elem), values, cast(unsigned)index_count);
- v = lb_add_global_generated(m, t, array_const_value);
+ v = lb_add_global_generated_from_procedure(p, t, array_const_value);
} else {
- v = lb_add_global_generated(m, t);
+ v = lb_add_global_generated_from_procedure(p, t);
}
lb_make_global_private_const(v);
@@ -2817,6 +2817,12 @@ gb_internal lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left
Type *it = bit_set_to_int(a);
lbValue lhs = lb_emit_transmute(p, left, it);
lbValue rhs = lb_emit_transmute(p, right, it);
+ if (is_type_different_to_arch_endianness(it)) {
+ it = integer_endian_type_to_platform_type(it);
+ lhs = lb_emit_byte_swap(p, lhs, it);
+ rhs = lb_emit_byte_swap(p, rhs, it);
+ }
+
lbValue res = lb_emit_arith(p, Token_And, lhs, rhs, it);
if (op_kind == Token_Lt || op_kind == Token_LtEq) {
@@ -2914,6 +2920,12 @@ gb_internal lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left
}
}
+ if (is_type_different_to_arch_endianness(left.type)) {
+ Type *pt = integer_endian_type_to_platform_type(left.type);
+ lhs = lb_emit_byte_swap(p, {lhs, pt}, pt).value;
+ rhs = lb_emit_byte_swap(p, {rhs, pt}, pt).value;
+ }
+
res.value = LLVMBuildICmp(p->builder, pred, lhs, rhs, "");
} else if (is_type_float(a)) {
LLVMRealPredicate pred = {};
@@ -2925,6 +2937,13 @@ gb_internal lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left
case Token_LtEq: pred = LLVMRealOLE; break;
case Token_NotEq: pred = LLVMRealONE; break;
}
+
+ if (is_type_different_to_arch_endianness(left.type)) {
+ Type *pt = integer_endian_type_to_platform_type(left.type);
+ left = lb_emit_byte_swap(p, left, pt);
+ right = lb_emit_byte_swap(p, right, pt);
+ }
+
res.value = LLVMBuildFCmp(p->builder, pred, left.value, right.value, "");
} else if (is_type_typeid(a)) {
LLVMIntPredicate pred = {};
@@ -2985,7 +3004,16 @@ gb_internal lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left
LLVMTypeRef mask_int_type = LLVMIntTypeInContext(p->module->ctx, cast(unsigned)(8*type_size_of(a)));
LLVMValueRef mask_int = LLVMBuildBitCast(p->builder, mask, mask_int_type, "");
- res.value = LLVMBuildICmp(p->builder, LLVMIntNE, mask_int, LLVMConstNull(LLVMTypeOf(mask_int)), "");
+
+ switch (op_kind) {
+ case Token_CmpEq:
+ res.value = LLVMBuildICmp(p->builder, LLVMIntEQ, mask_int, LLVMConstInt(mask_int_type, U64_MAX, true), "");
+ break;
+ case Token_NotEq:
+ res.value = LLVMBuildICmp(p->builder, LLVMIntNE, mask_int, LLVMConstNull(mask_int_type), "");
+ break;
+ }
+
return res;
} else {
@@ -3236,7 +3264,7 @@ gb_internal lbValue lb_build_unary_and(lbProcedure *p, Ast *expr) {
Type *type = v.type;
lbAddr addr = {};
if (p->is_startup) {
- addr = lb_add_global_generated(p->module, type, v);
+ addr = lb_add_global_generated_from_procedure(p, type, v);
} else {
addr = lb_add_local_generated(p, type, false);
}
@@ -3345,9 +3373,7 @@ gb_internal lbValue lb_build_unary_and(lbProcedure *p, Ast *expr) {
auto args = array_make<lbValue>(permanent_allocator(), arg_count);
args[0] = ok;
- args[1] = lb_find_or_add_entity_string(p->module, get_file_path_string(pos.file_id));
- args[2] = lb_const_int(p->module, t_i32, pos.line);
- args[3] = lb_const_int(p->module, t_i32, pos.column);
+ lb_set_file_line_col(p, array_slice(args, 1, args.count), pos);
if (!build_context.no_rtti) {
args[4] = lb_typeid(p->module, src_type);
@@ -3374,9 +3400,7 @@ gb_internal lbValue lb_build_unary_and(lbProcedure *p, Ast *expr) {
auto args = array_make<lbValue>(permanent_allocator(), 6);
args[0] = ok;
- args[1] = lb_find_or_add_entity_string(p->module, get_file_path_string(pos.file_id));
- args[2] = lb_const_int(p->module, t_i32, pos.line);
- args[3] = lb_const_int(p->module, t_i32, pos.column);
+ lb_set_file_line_col(p, array_slice(args, 1, args.count), pos);
args[4] = any_id;
args[5] = id;
@@ -3483,7 +3507,13 @@ gb_internal lbValue lb_build_expr_internal(lbProcedure *p, Ast *expr) {
case_ast_node(bd, BasicDirective, expr);
TokenPos pos = bd->token.pos;
- GB_PANIC("Non-constant basic literal %s - %.*s", token_pos_to_string(pos), LIT(bd->name.string));
+ String name = bd->name.string;
+ if (name == "branch_location") {
+ GB_ASSERT(p->uses_branch_location);
+ String proc_name = p->entity->token.string;
+ return lb_emit_source_code_location_as_global(p, proc_name, p->branch_location_pos);
+ }
+ GB_PANIC("Non-constant basic literal %s - %.*s", token_pos_to_string(pos), LIT(name));
case_end;
case_ast_node(i, Implicit, expr);
@@ -3649,7 +3679,7 @@ gb_internal lbValue lb_build_expr_internal(lbProcedure *p, Ast *expr) {
lb_emit_if(p, lb_emit_try_has_value(p, rhs), then, else_);
lb_start_block(p, else_);
- lb_emit_defer_stmts(p, lbDeferExit_Branch, block);
+ lb_emit_defer_stmts(p, lbDeferExit_Branch, block, expr);
lb_emit_jump(p, block);
lb_start_block(p, then);
@@ -3821,7 +3851,7 @@ gb_internal lbAddr lb_build_addr_from_entity(lbProcedure *p, Entity *e, Ast *exp
Type *t = default_type(type_of_expr(expr));
lbValue v = lb_const_value(p->module, t, e->Constant.value);
if (LLVMIsConstant(v.value)) {
- lbAddr g = lb_add_global_generated(p->module, t, v);
+ lbAddr g = lb_add_global_generated_from_procedure(p, t, v);
return g;
}
GB_ASSERT(LLVMIsALoadInst(v.value));
@@ -4269,6 +4299,17 @@ gb_internal lbAddr lb_build_addr_index_expr(lbProcedure *p, Ast *expr) {
gb_internal lbAddr lb_build_addr_slice_expr(lbProcedure *p, Ast *expr) {
ast_node(se, SliceExpr, expr);
+ lbAddr addr = lb_build_addr(p, se->expr);
+ lbValue base = lb_addr_load(p, addr);
+ Type *type = base_type(base.type);
+
+ if (is_type_pointer(type)) {
+ type = base_type(type_deref(type));
+ addr = lb_addr(base);
+ base = lb_addr_load(p, addr);
+ }
+
+
lbValue low = lb_const_int(p->module, t_int, 0);
lbValue high = {};
@@ -4281,16 +4322,6 @@ gb_internal lbAddr lb_build_addr_slice_expr(lbProcedure *p, Ast *expr) {
bool no_indices = se->low == nullptr && se->high == nullptr;
- lbAddr addr = lb_build_addr(p, se->expr);
- lbValue base = lb_addr_load(p, addr);
- Type *type = base_type(base.type);
-
- if (is_type_pointer(type)) {
- type = base_type(type_deref(type));
- addr = lb_addr(base);
- base = lb_addr_load(p, addr);
- }
-
switch (type->kind) {
case Type_Slice: {
Type *slice_type = type;
@@ -4788,7 +4819,7 @@ gb_internal lbAddr lb_build_addr_compound_lit(lbProcedure *p, Ast *expr) {
if (cl->elems.count == 0) {
break;
}
- GB_ASSERT(!build_context.no_dynamic_literals);
+ GB_ASSERT(expr->file()->feature_flags & OptInFeatureFlag_DynamicLiterals);
lbValue err = lb_dynamic_map_reserve(p, v.addr, 2*cl->elems.count, pos);
gb_unused(err);
@@ -4877,7 +4908,7 @@ gb_internal lbAddr lb_build_addr_compound_lit(lbProcedure *p, Ast *expr) {
if (cl->elems.count == 0) {
break;
}
- GB_ASSERT(!build_context.no_dynamic_literals);
+ GB_ASSERT(expr->file()->feature_flags & OptInFeatureFlag_DynamicLiterals);
Type *et = bt->DynamicArray.elem;
lbValue size = lb_const_int(p->module, t_int, type_size_of(et));
@@ -5474,7 +5505,7 @@ gb_internal lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) {
lb_emit_if(p, lb_emit_try_has_value(p, rhs), then, else_);
lb_start_block(p, else_);
- lb_emit_defer_stmts(p, lbDeferExit_Branch, block);
+ lb_emit_defer_stmts(p, lbDeferExit_Branch, block, expr);
lb_emit_jump(p, block);
lb_start_block(p, then);
diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp
index 9dc603993..0705e2e93 100644
--- a/src/llvm_backend_general.cpp
+++ b/src/llvm_backend_general.cpp
@@ -15,13 +15,18 @@ gb_global isize lb_global_type_info_member_offsets_index = 0;
gb_global isize lb_global_type_info_member_usings_index = 0;
gb_global isize lb_global_type_info_member_tags_index = 0;
-
gb_internal void lb_init_module(lbModule *m, Checker *c) {
m->info = &c->info;
gbString module_name = gb_string_make(heap_allocator(), "odin_package");
if (m->file) {
- module_name = gb_string_append_fmt(module_name, "-%u", m->file->id+1);
+ if (m->pkg) {
+ module_name = gb_string_appendc(module_name, "-");
+ module_name = gb_string_append_length(module_name, m->pkg->name.text, m->pkg->name.len);
+ }
+ module_name = gb_string_appendc(module_name, "-");
+ String filename = filename_from_path(m->file->filename);
+ module_name = gb_string_append_length(module_name, filename.text, filename.len);
} else if (m->pkg) {
module_name = gb_string_appendc(module_name, "-");
module_name = gb_string_append_length(module_name, m->pkg->name.text, m->pkg->name.len);
@@ -68,10 +73,7 @@ gb_internal void lb_init_module(lbModule *m, Checker *c) {
string_map_init(&m->procedures);
string_map_init(&m->const_strings);
map_init(&m->function_type_map);
- map_init(&m->equal_procs);
- map_init(&m->hasher_procs);
- map_init(&m->map_get_procs);
- map_init(&m->map_set_procs);
+ string_map_init(&m->gen_procs);
if (USE_SEPARATE_MODULES) {
array_init(&m->procedures_to_generate, a, 0, 1<<10);
map_init(&m->procedure_values, 1<<11);
@@ -219,7 +221,7 @@ gb_internal void lb_loop_end(lbProcedure *p, lbLoopData const &data) {
gb_internal void lb_make_global_private_const(LLVMValueRef global_data) {
LLVMSetLinkage(global_data, LLVMLinkerPrivateLinkage);
- LLVMSetUnnamedAddress(global_data, LLVMGlobalUnnamedAddr);
+ // LLVMSetUnnamedAddress(global_data, LLVMGlobalUnnamedAddr);
LLVMSetGlobalConstant(global_data, true);
}
gb_internal void lb_make_global_private_const(lbAddr const &addr) {
@@ -540,6 +542,22 @@ gb_internal lbValue lb_build_addr_ptr(lbProcedure *p, Ast *expr) {
return lb_addr_get_ptr(p, addr);
}
+gb_internal void lb_set_file_line_col(lbProcedure *p, Array<lbValue> arr, TokenPos pos) {
+ String file = get_file_path_string(pos.file_id);
+ i32 line = pos.line;
+ i32 col = pos.column;
+
+ if (build_context.obfuscate_source_code_locations) {
+ file = obfuscate_string(file, "F");
+ line = obfuscate_i32(line);
+ col = obfuscate_i32(col);
+ }
+
+ arr[0] = lb_find_or_add_entity_string(p->module, file);
+ arr[1] = lb_const_int(p->module, t_i32, line);
+ arr[2] = lb_const_int(p->module, t_i32, col);
+}
+
gb_internal void lb_emit_bounds_check(lbProcedure *p, Token token, lbValue index, lbValue len) {
if (build_context.no_bounds_check) {
return;
@@ -553,14 +571,8 @@ gb_internal void lb_emit_bounds_check(lbProcedure *p, Token token, lbValue index
index = lb_emit_conv(p, index, t_int);
len = lb_emit_conv(p, len, t_int);
- lbValue file = lb_find_or_add_entity_string(p->module, get_file_path_string(token.pos.file_id));
- lbValue line = lb_const_int(p->module, t_i32, token.pos.line);
- lbValue column = lb_const_int(p->module, t_i32, token.pos.column);
-
auto args = array_make<lbValue>(temporary_allocator(), 5);
- args[0] = file;
- args[1] = line;
- args[2] = column;
+ lb_set_file_line_col(p, args, token.pos);
args[3] = index;
args[4] = len;
@@ -582,14 +594,8 @@ gb_internal void lb_emit_matrix_bounds_check(lbProcedure *p, Token token, lbValu
row_count = lb_emit_conv(p, row_count, t_int);
column_count = lb_emit_conv(p, column_count, t_int);
- lbValue file = lb_find_or_add_entity_string(p->module, get_file_path_string(token.pos.file_id));
- lbValue line = lb_const_int(p->module, t_i32, token.pos.line);
- lbValue column = lb_const_int(p->module, t_i32, token.pos.column);
-
auto args = array_make<lbValue>(temporary_allocator(), 7);
- args[0] = file;
- args[1] = line;
- args[2] = column;
+ lb_set_file_line_col(p, args, token.pos);
args[3] = row_index;
args[4] = column_index;
args[5] = row_count;
@@ -610,14 +616,8 @@ gb_internal void lb_emit_multi_pointer_slice_bounds_check(lbProcedure *p, Token
low = lb_emit_conv(p, low, t_int);
high = lb_emit_conv(p, high, t_int);
- lbValue file = lb_find_or_add_entity_string(p->module, get_file_path_string(token.pos.file_id));
- lbValue line = lb_const_int(p->module, t_i32, token.pos.line);
- lbValue column = lb_const_int(p->module, t_i32, token.pos.column);
-
auto args = array_make<lbValue>(permanent_allocator(), 5);
- args[0] = file;
- args[1] = line;
- args[2] = column;
+ lb_set_file_line_col(p, args, token.pos);
args[3] = low;
args[4] = high;
@@ -632,16 +632,11 @@ gb_internal void lb_emit_slice_bounds_check(lbProcedure *p, Token token, lbValue
return;
}
- lbValue file = lb_find_or_add_entity_string(p->module, get_file_path_string(token.pos.file_id));
- lbValue line = lb_const_int(p->module, t_i32, token.pos.line);
- lbValue column = lb_const_int(p->module, t_i32, token.pos.column);
high = lb_emit_conv(p, high, t_int);
if (!lower_value_used) {
auto args = array_make<lbValue>(permanent_allocator(), 5);
- args[0] = file;
- args[1] = line;
- args[2] = column;
+ lb_set_file_line_col(p, args, token.pos);
args[3] = high;
args[4] = len;
@@ -651,9 +646,7 @@ gb_internal void lb_emit_slice_bounds_check(lbProcedure *p, Token token, lbValue
low = lb_emit_conv(p, low, t_int);
auto args = array_make<lbValue>(permanent_allocator(), 6);
- args[0] = file;
- args[1] = line;
- args[2] = column;
+ lb_set_file_line_col(p, args, token.pos);
args[3] = low;
args[4] = high;
args[5] = len;
@@ -734,6 +727,17 @@ gb_internal LLVMValueRef OdinLLVMBuildLoad(lbProcedure *p, LLVMTypeRef type, LLV
if (is_packed != 0) {
LLVMSetAlignment(result, 1);
}
+ u64 align = LLVMGetAlignment(result);
+ u64 align_min = lb_get_metadata_custom_u64(p->module, value, ODIN_METADATA_MIN_ALIGN);
+ u64 align_max = lb_get_metadata_custom_u64(p->module, value, ODIN_METADATA_MAX_ALIGN);
+ if (align_min != 0 && align < align_min) {
+ align = align_min;
+ }
+ if (align_max != 0 && align > align_max) {
+ align = align_max;
+ }
+ GB_ASSERT(align <= UINT_MAX);
+ LLVMSetAlignment(result, (unsigned int)align);
}
return result;
@@ -1009,7 +1013,7 @@ gb_internal void lb_emit_store(lbProcedure *p, lbValue ptr, lbValue value) {
LLVMConstInt(LLVMInt64TypeInContext(p->module->ctx), lb_sizeof(LLVMTypeOf(value.value)), false));
return;
} else if (LLVMIsConstant(value.value)) {
- lbAddr addr = lb_add_global_generated(p->module, value.type, value, nullptr);
+ lbAddr addr = lb_add_global_generated_from_procedure(p, value.type, value);
lb_make_global_private_const(addr);
LLVMValueRef dst_ptr = ptr.value;
@@ -1442,148 +1446,30 @@ gb_internal void lb_clone_struct_type(LLVMTypeRef dst, LLVMTypeRef src) {
LLVMStructSetBody(dst, fields, field_count, LLVMIsPackedStruct(src));
}
-gb_internal String lb_mangle_name(Entity *e) {
- String name = e->token.string;
-
- AstPackage *pkg = e->pkg;
- GB_ASSERT_MSG(pkg != nullptr, "Missing package for '%.*s'", LIT(name));
- String pkgn = pkg->name;
- GB_ASSERT(!rune_is_digit(pkgn[0]));
- if (pkgn == "llvm") {
- pkgn = str_lit("llvm$");
- }
-
- isize max_len = pkgn.len + 1 + name.len + 1;
- bool require_suffix_id = is_type_polymorphic(e->type, true);
-
- if ((e->scope->flags & (ScopeFlag_File | ScopeFlag_Pkg)) == 0) {
- require_suffix_id = true;
- } else if (is_blank_ident(e->token)) {
- require_suffix_id = true;
- }if (e->flags & EntityFlag_NotExported) {
- require_suffix_id = true;
- }
-
- if (require_suffix_id) {
- max_len += 21;
- }
-
- char *new_name = gb_alloc_array(permanent_allocator(), char, max_len);
- isize new_name_len = gb_snprintf(
- new_name, max_len,
- "%.*s" ABI_PKG_NAME_SEPARATOR "%.*s", LIT(pkgn), LIT(name)
- );
- if (require_suffix_id) {
- char *str = new_name + new_name_len-1;
- isize len = max_len-new_name_len;
- isize extra = gb_snprintf(str, len, "-%llu", cast(unsigned long long)e->id);
- new_name_len += extra-1;
- }
-
- String mangled_name = make_string((u8 const *)new_name, new_name_len-1);
- return mangled_name;
-}
-
-gb_internal String lb_set_nested_type_name_ir_mangled_name(Entity *e, lbProcedure *p, lbModule *module) {
- // NOTE(bill, 2020-03-08): A polymorphic procedure may take a nested type declaration
- // and as a result, the declaration does not have time to determine what it should be
-
- GB_ASSERT(e != nullptr && e->kind == Entity_TypeName);
- if (e->TypeName.ir_mangled_name.len != 0) {
- return e->TypeName.ir_mangled_name;
- }
- GB_ASSERT((e->scope->flags & ScopeFlag_File) == 0);
-
- if (p == nullptr) {
- Entity *proc = nullptr;
- if (e->parent_proc_decl != nullptr) {
- proc = e->parent_proc_decl->entity;
- } else {
- Scope *scope = e->scope;
- while (scope != nullptr && (scope->flags & ScopeFlag_Proc) == 0) {
- scope = scope->parent;
- }
- GB_ASSERT(scope != nullptr);
- GB_ASSERT(scope->flags & ScopeFlag_Proc);
- proc = scope->procedure_entity;
- }
- if (proc != nullptr) {
- GB_ASSERT(proc->kind == Entity_Procedure);
- if (proc->code_gen_procedure != nullptr) {
- p = proc->code_gen_procedure;
- }
- }
- }
-
- // NOTE(bill): Generate a new name
- // parent_proc.name-guid
- String ts_name = e->token.string;
-
- if (p != nullptr) {
- isize name_len = p->name.len + 1 + ts_name.len + 1 + 10 + 1;
- char *name_text = gb_alloc_array(permanent_allocator(), char, name_len);
- u32 guid = 1+p->module->nested_type_name_guid.fetch_add(1);
- name_len = gb_snprintf(name_text, name_len, "%.*s" ABI_PKG_NAME_SEPARATOR "%.*s-%u", LIT(p->name), LIT(ts_name), guid);
-
- String name = make_string(cast(u8 *)name_text, name_len-1);
- e->TypeName.ir_mangled_name = name;
- return name;
- } else {
- // NOTE(bill): a nested type be required before its parameter procedure exists. Just give it a temp name for now
- isize name_len = 9 + 1 + ts_name.len + 1 + 10 + 1;
- char *name_text = gb_alloc_array(permanent_allocator(), char, name_len);
- static std::atomic<u32> guid;
- name_len = gb_snprintf(name_text, name_len, "_internal" ABI_PKG_NAME_SEPARATOR "%.*s-%u", LIT(ts_name), 1+guid.fetch_add(1));
-
- String name = make_string(cast(u8 *)name_text, name_len-1);
- e->TypeName.ir_mangled_name = name;
- return name;
- }
-}
-
-gb_internal String lb_get_entity_name(lbModule *m, Entity *e, String default_name) {
+gb_internal String lb_get_entity_name(lbModule *m, Entity *e) {
GB_ASSERT(m != nullptr);
- if (e != nullptr && e->kind == Entity_TypeName && e->TypeName.ir_mangled_name.len != 0) {
+ GB_ASSERT(e != nullptr);
+ if (e->kind == Entity_TypeName && e->TypeName.ir_mangled_name.len != 0) {
return e->TypeName.ir_mangled_name;
+ } else if (e->kind == Entity_Procedure && e->Procedure.link_name.len != 0) {
+ return e->Procedure.link_name;
}
- GB_ASSERT(e != nullptr);
if (e->pkg == nullptr) {
return e->token.string;
}
- if (e->kind == Entity_TypeName && (e->scope->flags & ScopeFlag_File) == 0) {
- return lb_set_nested_type_name_ir_mangled_name(e, nullptr, m);
- }
+ gbString w = string_canonical_entity_name(heap_allocator(), e);
+ defer (gb_string_free(w));
- String name = {};
-
- bool no_name_mangle = false;
-
- if (e->kind == Entity_Variable) {
- bool is_foreign = e->Variable.is_foreign;
- bool is_export = e->Variable.is_export;
- no_name_mangle = e->Variable.link_name.len > 0 || is_foreign || is_export;
- if (e->Variable.link_name.len > 0) {
- return e->Variable.link_name;
- }
- } else if (e->kind == Entity_Procedure && e->Procedure.link_name.len > 0) {
- return e->Procedure.link_name;
- } else if (e->kind == Entity_Procedure && e->Procedure.is_export) {
- no_name_mangle = true;
- }
-
- if (!no_name_mangle) {
- name = lb_mangle_name(e);
- }
- if (name.len == 0) {
- name = e->token.string;
- }
+ String name = copy_string(permanent_allocator(), make_string(cast(u8 const *)w, gb_string_length(w)));
if (e->kind == Entity_TypeName) {
e->TypeName.ir_mangled_name = name;
} else if (e->kind == Entity_Procedure) {
e->Procedure.link_name = name;
+ } else if (e->kind == Entity_Variable) {
+ e->Variable.link_name = name;
}
return name;
@@ -1901,15 +1787,24 @@ gb_internal LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
return type;
}
type = LLVMStructCreateNamed(ctx, name);
- LLVMTypeRef fields[2] = {
- lb_type(m, t_rawptr),
- lb_type(m, t_typeid),
- };
- LLVMStructSetBody(type, fields, 2, false);
+ if (build_context.ptr_size == 4) {
+ LLVMTypeRef fields[3] = {
+ lb_type(m, t_rawptr),
+ lb_type_padding_filler(m, build_context.ptr_size, build_context.ptr_size), // padding
+ lb_type(m, t_typeid),
+ };
+ LLVMStructSetBody(type, fields, 3, false);
+ } else {
+ LLVMTypeRef fields[2] = {
+ lb_type(m, t_rawptr),
+ lb_type(m, t_typeid),
+ };
+ LLVMStructSetBody(type, fields, 2, false);
+ }
return type;
}
- case Basic_typeid: return LLVMIntTypeInContext(m->ctx, 8*cast(unsigned)build_context.ptr_size);
+ case Basic_typeid: return LLVMIntTypeInContext(m->ctx, 64);
// Endian Specific Types
case Basic_i16le: return LLVMInt16TypeInContext(ctx);
@@ -2121,6 +2016,7 @@ gb_internal LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
}
i64 prev_offset = 0;
+ bool requires_packing = type->Struct.is_packed;
for (i32 field_index : struct_fields_index_by_increasing_offset(temporary_allocator(), type)) {
Entity *field = type->Struct.fields[field_index];
i64 offset = type->Struct.offsets[field_index];
@@ -2141,6 +2037,10 @@ gb_internal LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
field_type = t_rawptr;
}
+ // max_field_align might misalign items in a way that requires packing
+ // so check the alignment of all fields to see if packing is required.
+ requires_packing = requires_packing || ((offset % type_align_of(field_type)) != 0);
+
array_add(&fields, lb_type(m, field_type));
prev_offset = offset + type_size_of(field->type);
@@ -2155,7 +2055,7 @@ gb_internal LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
GB_ASSERT(fields[i] != nullptr);
}
- LLVMTypeRef struct_type = LLVMStructTypeInContext(ctx, fields.data, cast(unsigned)fields.count, type->Struct.is_packed);
+ LLVMTypeRef struct_type = LLVMStructTypeInContext(ctx, fields.data, cast(unsigned)fields.count, requires_packing);
map_set(&m->struct_field_remapping, cast(void *)struct_type, field_remapping);
map_set(&m->struct_field_remapping, cast(void *)type, field_remapping);
#if 0
@@ -2601,7 +2501,7 @@ general_end:;
GB_ASSERT(p->decl_block != p->curr_block);
i64 max_align = gb_max(lb_alignof(src_type), lb_alignof(dst_type));
- max_align = gb_max(max_align, 4);
+ max_align = gb_max(max_align, 16);
LLVMValueRef ptr = llvm_alloca(p, dst_type, max_align);
@@ -2627,12 +2527,10 @@ gb_internal LLVMValueRef lb_find_or_add_entity_string_ptr(lbModule *m, String co
false);
- isize max_len = 7+8+1;
- char *name = gb_alloc_array(permanent_allocator(), char, max_len);
-
- u32 id = m->gen->global_array_index.fetch_add(1);
- isize len = gb_snprintf(name, max_len, "csbs$%x", id);
- len -= 1;
+ u32 id = m->global_array_index.fetch_add(1);
+ gbString name = gb_string_make(temporary_allocator(), "csbs$");
+ name = gb_string_appendc(name, m->module_name);
+ name = gb_string_append_fmt(name, "$%x", id);
LLVMTypeRef type = LLVMTypeOf(data);
LLVMValueRef global_data = LLVMAddGlobal(m->mod, type, name);
@@ -2670,14 +2568,11 @@ gb_internal lbValue lb_find_or_add_entity_string_byte_slice_with_type(lbModule *
false);
- char *name = nullptr;
- {
- isize max_len = 7+8+1;
- name = gb_alloc_array(permanent_allocator(), char, max_len);
- u32 id = m->gen->global_array_index.fetch_add(1);
- isize len = gb_snprintf(name, max_len, "csbs$%x", id);
- len -= 1;
- }
+ u32 id = m->global_array_index.fetch_add(1);
+ gbString name = gb_string_make(temporary_allocator(), "csba$");
+ name = gb_string_appendc(name, m->module_name);
+ name = gb_string_append_fmt(name, "$%x", id);
+
LLVMTypeRef type = LLVMTypeOf(data);
LLVMValueRef global_data = LLVMAddGlobal(m->mod, type, name);
LLVMSetInitializer(global_data, data);
@@ -2863,6 +2758,8 @@ gb_internal lbValue lb_generate_anonymous_proc_lit(lbModule *m, String const &pr
pl->decl->code_gen_module = m;
e->decl_info = pl->decl;
pl->decl->entity = e;
+ e->parent_proc_decl = pl->decl->parent;
+ e->Procedure.is_anonymous = true;
e->flags |= EntityFlag_ProcBodyChecked;
lbProcedure *p = lb_create_procedure(m, e);
@@ -2883,17 +2780,14 @@ gb_internal lbValue lb_generate_anonymous_proc_lit(lbModule *m, String const &pr
}
-gb_internal lbAddr lb_add_global_generated(lbModule *m, Type *type, lbValue value, Entity **entity_) {
+gb_internal lbAddr lb_add_global_generated_with_name(lbModule *m, Type *type, lbValue value, String name, Entity **entity_) {
+ GB_ASSERT(name.len != 0);
GB_ASSERT(type != nullptr);
type = default_type(type);
- isize max_len = 7+8+1;
- u8 *str = cast(u8 *)gb_alloc_array(permanent_allocator(), u8, max_len);
-
- u32 id = m->gen->global_generated_index.fetch_add(1);
-
- isize len = gb_snprintf(cast(char *)str, max_len, "ggv$%x", id);
- String name = make_string(str, len-1);
+ u8 *str = cast(u8 *)gb_alloc_array(temporary_allocator(), u8, name.len);
+ memcpy(str, name.text, name.len);
+ str[name.len] = 0;
Scope *scope = nullptr;
Entity *e = alloc_entity_variable(scope, make_token_ident(name), type);
@@ -2915,6 +2809,25 @@ gb_internal lbAddr lb_add_global_generated(lbModule *m, Type *type, lbValue valu
return lb_addr(g);
}
+
+gb_internal lbAddr lb_add_global_generated_from_procedure(lbProcedure *p, Type *type, lbValue value) {
+ GB_ASSERT(type != nullptr);
+ type = default_type(type);
+
+ u32 index = ++p->global_generated_index;
+
+ gbString s = gb_string_make(temporary_allocator(), "ggv$");
+ // s = gb_string_appendc(s, p->module->module_name);
+ // s = gb_string_appendc(s, "$");
+ s = gb_string_append_length(s, p->name.text, p->name.len);
+ s = gb_string_append_fmt(s, "$%u", index);
+
+ String name = make_string(cast(u8 const *)s, gb_string_length(s));
+ return lb_add_global_generated_with_name(p->module, type, value, name);
+}
+
+
+
gb_internal lbValue lb_find_runtime_value(lbModule *m, String const &name) {
AstPackage *p = m->info->runtime_package;
Entity *e = scope_lookup_current(p->scope, name);
@@ -3022,7 +2935,7 @@ gb_internal lbValue lb_generate_global_array(lbModule *m, Type *elem_type, i64 c
g.type = alloc_type_pointer(t);
LLVMSetInitializer(g.value, LLVMConstNull(lb_type(m, t)));
LLVMSetLinkage(g.value, LLVMPrivateLinkage);
- LLVMSetUnnamedAddress(g.value, LLVMGlobalUnnamedAddr);
+ // LLVMSetUnnamedAddress(g.value, LLVMGlobalUnnamedAddr);
string_map_set(&m->members, s, g);
return g;
}
diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp
index 5aee5b639..a835ae2c8 100644
--- a/src/llvm_backend_proc.cpp
+++ b/src/llvm_backend_proc.cpp
@@ -125,6 +125,10 @@ gb_internal lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool i
// map_init(&p->selector_addr, 0);
// map_init(&p->tuple_fix_map, 0);
+ if (p->entity != nullptr && p->entity->Procedure.uses_branch_location) {
+ p->uses_branch_location = true;
+ }
+
if (p->is_foreign) {
lb_add_foreign_library_path(p->module, entity->Procedure.foreign_library);
}
@@ -579,6 +583,8 @@ gb_internal void lb_begin_procedure_body(lbProcedure *p) {
p->raw_input_parameters = array_make<LLVMValueRef>(permanent_allocator(), raw_input_parameters_count);
LLVMGetParams(p->value, p->raw_input_parameters.data);
+ bool is_odin_cc = is_calling_convention_odin(ft->calling_convention);
+
unsigned param_index = 0;
for_array(i, params->variables) {
Entity *e = params->variables[i];
@@ -613,9 +619,26 @@ gb_internal void lb_begin_procedure_body(lbProcedure *p) {
}
} else if (arg_type->kind == lbArg_Indirect) {
if (e->token.string.len != 0 && !is_blank_ident(e->token.string)) {
+ i64 sz = type_size_of(e->type);
+ bool do_callee_copy = false;
+
+ if (is_odin_cc) {
+ do_callee_copy = sz <= 16;
+ if (build_context.internal_by_value) {
+ do_callee_copy = true;
+ }
+ }
+
lbValue ptr = {};
ptr.value = LLVMGetParam(p->value, param_offset+param_index);
ptr.type = alloc_type_pointer(e->type);
+
+ if (do_callee_copy) {
+ lbValue new_ptr = lb_add_local_generated(p, e->type, false).addr;
+ lb_mem_copy_non_overlapping(p, new_ptr, ptr, lb_const_int(p->module, t_uint, sz));
+ ptr = new_ptr;
+ }
+
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);
}
@@ -738,7 +761,7 @@ gb_internal void lb_end_procedure_body(lbProcedure *p) {
if (p->type->Proc.result_count == 0) {
instr = LLVMGetLastInstruction(p->curr_block->block);
if (!lb_is_instr_terminating(instr)) {
- lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr);
+ lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr, p->body);
lb_set_debug_position_to_procedure_end(p);
LLVMBuildRetVoid(p->builder);
}
@@ -1096,7 +1119,7 @@ gb_internal lbValue lb_emit_call(lbProcedure *p, lbValue value, Array<lbValue> c
if (LLVMIsConstant(x.value)) {
// NOTE(bill): if the value is already constant, then just it as a global variable
// and pass it by pointer
- lbAddr addr = lb_add_global_generated(p->module, original_type, x);
+ lbAddr addr = lb_add_global_generated_from_procedure(p, original_type, x);
lb_make_global_private_const(addr);
ptr = addr.addr;
} else {
@@ -1117,10 +1140,6 @@ gb_internal lbValue lb_emit_call(lbProcedure *p, lbValue value, Array<lbValue> c
}
}
- if (inlining == ProcInlining_none) {
- inlining = p->inlining;
- }
-
Type *rt = reduce_tuple_to_single_type(results);
Type *original_rt = rt;
if (split_returns) {
@@ -1545,6 +1564,34 @@ gb_internal lbValue lb_build_builtin_simd_proc(lbProcedure *p, Ast *expr, TypeAn
return res;
}
+ case BuiltinProc_simd_extract_lsbs:
+ case BuiltinProc_simd_extract_msbs:
+ {
+ Type *vt = arg0.type;
+ GB_ASSERT(vt->kind == Type_SimdVector);
+
+ i64 elem_bits = 8*type_size_of(elem);
+ i64 num_elems = get_array_type_count(vt);
+
+ LLVMValueRef broadcast_value = arg0.value;
+ if (builtin_id == BuiltinProc_simd_extract_msbs) {
+ LLVMTypeRef word_type = lb_type(m, elem);
+ LLVMValueRef shift_value = llvm_splat_int(num_elems, word_type, elem_bits - 1);
+ broadcast_value = LLVMBuildAShr(p->builder, broadcast_value, shift_value, "");
+ }
+
+ LLVMTypeRef bitvec_type = LLVMVectorType(LLVMInt1TypeInContext(m->ctx), (unsigned)num_elems);
+ LLVMValueRef bitvec_value = LLVMBuildTrunc(p->builder, broadcast_value, bitvec_type, "");
+
+ LLVMTypeRef mask_type = LLVMIntTypeInContext(m->ctx, (unsigned)num_elems);
+ LLVMValueRef mask_value = LLVMBuildBitCast(p->builder, bitvec_value, mask_type, "");
+
+ LLVMTypeRef result_type = lb_type(m, res.type);
+ res.value = LLVMBuildZExtOrBitCast(p->builder, mask_value, result_type, "");
+
+ return res;
+ }
+
case BuiltinProc_simd_shuffle:
{
@@ -1827,7 +1874,7 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu
LLVMValueRef backing_array = llvm_const_array(lb_type(m, t_load_directory_file), elements, count);
Type *array_type = alloc_type_array(t_load_directory_file, count);
- lbAddr backing_array_addr = lb_add_global_generated(m, array_type, {backing_array, array_type}, nullptr);
+ lbAddr backing_array_addr = lb_add_global_generated_from_procedure(p, array_type, {backing_array, array_type});
lb_make_global_private_const(backing_array_addr);
LLVMValueRef backing_array_ptr = backing_array_addr.addr.value;
@@ -1835,7 +1882,7 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu
LLVMValueRef const_slice = llvm_const_slice_internal(m, backing_array_ptr, LLVMConstInt(lb_type(m, t_int), count, false));
- lbAddr addr = lb_add_global_generated(p->module, tv.type, {const_slice, t_load_directory_file_slice}, nullptr);
+ lbAddr addr = lb_add_global_generated_from_procedure(p, tv.type, {const_slice, t_load_directory_file_slice});
lb_make_global_private_const(addr);
return lb_addr_load(p, addr);
@@ -2155,7 +2202,32 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu
case 128: return lb_emit_runtime_call(p, "abs_complex128", args);
}
GB_PANIC("Unknown complex type");
+ } else if (is_type_float(t)) {
+ bool little = is_type_endian_little(t) || (is_type_endian_platform(t) && build_context.endian_kind == TargetEndian_Little);
+ Type *t_unsigned = nullptr;
+ lbValue mask = {0};
+ switch (type_size_of(t)) {
+ case 2:
+ t_unsigned = t_u16;
+ mask = lb_const_int(p->module, t_unsigned, little ? 0x7FFF : 0xFF7F);
+ break;
+ case 4:
+ t_unsigned = t_u32;
+ mask = lb_const_int(p->module, t_unsigned, little ? 0x7FFFFFFF : 0xFFFFFF7F);
+ break;
+ case 8:
+ t_unsigned = t_u64;
+ mask = lb_const_int(p->module, t_unsigned, little ? 0x7FFFFFFFFFFFFFFF : 0xFFFFFFFFFFFFFF7F);
+ break;
+ default:
+ GB_PANIC("abs: unhandled float size");
+ }
+
+ lbValue as_unsigned = lb_emit_transmute(p, x, t_unsigned);
+ lbValue abs = lb_emit_arith(p, Token_And, as_unsigned, mask, t_unsigned);
+ return lb_emit_transmute(p, abs, t);
}
+
lbValue zero = lb_const_nil(p->module, t);
lbValue cond = lb_emit_comp(p, Token_Lt, x, zero);
lbValue neg = lb_emit_unary_arith(p, Token_Sub, x, t);
@@ -2504,8 +2576,8 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu
}
case BuiltinProc_ptr_sub:
{
- Type *elem0 = type_deref(type_of_expr(ce->args[0]));
- Type *elem1 = type_deref(type_of_expr(ce->args[1]));
+ Type *elem0 = type_deref(type_of_expr(ce->args[0]), true);
+ Type *elem1 = type_deref(type_of_expr(ce->args[1]), true);
GB_ASSERT(are_types_identical(elem0, elem1));
Type *elem = elem0;
@@ -3236,13 +3308,14 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu
{
isize max_len = 7+8+1;
name = gb_alloc_array(permanent_allocator(), char, max_len);
- u32 id = m->gen->global_array_index.fetch_add(1);
+ u32 id = m->global_array_index.fetch_add(1);
isize len = gb_snprintf(name, max_len, "csbs$%x", id);
len -= 1;
}
LLVMTypeRef type = LLVMTypeOf(array);
LLVMValueRef global_data = LLVMAddGlobal(m->mod, type, name);
LLVMSetInitializer(global_data, array);
+ LLVMSetUnnamedAddress(global_data, LLVMGlobalUnnamedAddr);
LLVMSetLinkage(global_data, LLVMInternalLinkage);
diff --git a/src/llvm_backend_stmt.cpp b/src/llvm_backend_stmt.cpp
index 9a5f25712..758cd353f 100644
--- a/src/llvm_backend_stmt.cpp
+++ b/src/llvm_backend_stmt.cpp
@@ -5,8 +5,6 @@ gb_internal void lb_build_constant_value_decl(lbProcedure *p, AstValueDecl *vd)
auto *min_dep_set = &p->module->info->minimum_dependency_set;
- static i32 global_guid = 0;
-
for (Ast *ident : vd->names) {
GB_ASSERT(ident->kind == Ast_Ident);
Entity *e = entity_of_node(ident);
@@ -32,7 +30,8 @@ gb_internal void lb_build_constant_value_decl(lbProcedure *p, AstValueDecl *vd)
continue;
}
- lb_set_nested_type_name_ir_mangled_name(e, p, p->module);
+ String name = lb_get_entity_name(p->module, e);
+ gb_unused(name);
}
for_array(i, vd->names) {
@@ -208,8 +207,8 @@ gb_internal void lb_open_scope(lbProcedure *p, Scope *s) {
}
-gb_internal void lb_close_scope(lbProcedure *p, lbDeferExitKind kind, lbBlock *block, bool pop_stack=true) {
- lb_emit_defer_stmts(p, kind, block);
+gb_internal void lb_close_scope(lbProcedure *p, lbDeferExitKind kind, lbBlock *block, Ast *node, bool pop_stack=true) {
+ lb_emit_defer_stmts(p, kind, block, node);
GB_ASSERT(p->scope_index > 0);
// NOTE(bill): Remove `context`s made in that scope
@@ -256,7 +255,7 @@ gb_internal void lb_build_when_stmt(lbProcedure *p, AstWhenStmt *ws) {
gb_internal void lb_build_range_indexed(lbProcedure *p, lbValue expr, Type *val_type, lbValue count_ptr,
lbValue *val_, lbValue *idx_, lbBlock **loop_, lbBlock **done_,
- bool is_reverse) {
+ bool is_reverse, i64 unroll_count=0) {
lbModule *m = p->module;
lbValue count = {};
@@ -721,7 +720,7 @@ gb_internal void lb_build_range_interval(lbProcedure *p, AstBinaryExpr *node,
lb_build_stmt(p, rs->body);
- lb_close_scope(p, lbDeferExit_Default, nullptr);
+ lb_close_scope(p, lbDeferExit_Default, nullptr, node->left);
lb_pop_target_list(p);
if (check != nullptr) {
@@ -854,7 +853,7 @@ gb_internal void lb_build_range_tuple(lbProcedure *p, AstRangeStmt *rs, Scope *s
lb_build_stmt(p, rs->body);
- lb_close_scope(p, lbDeferExit_Default, nullptr);
+ lb_close_scope(p, lbDeferExit_Default, nullptr, rs->body);
lb_pop_target_list(p);
lb_emit_jump(p, loop);
lb_start_block(p, done);
@@ -976,7 +975,7 @@ gb_internal void lb_build_range_stmt_struct_soa(lbProcedure *p, AstRangeStmt *rs
lb_build_stmt(p, rs->body);
- lb_close_scope(p, lbDeferExit_Default, nullptr);
+ lb_close_scope(p, lbDeferExit_Default, nullptr, rs->body);
lb_pop_target_list(p);
lb_emit_jump(p, loop);
lb_start_block(p, done);
@@ -1192,7 +1191,7 @@ gb_internal void lb_build_range_stmt(lbProcedure *p, AstRangeStmt *rs, Scope *sc
lb_build_stmt(p, rs->body);
- lb_close_scope(p, lbDeferExit_Default, nullptr);
+ lb_close_scope(p, lbDeferExit_Default, nullptr, rs->body);
lb_pop_target_list(p);
lb_emit_jump(p, loop);
lb_start_block(p, done);
@@ -1230,7 +1229,6 @@ gb_internal void lb_build_unroll_range_stmt(lbProcedure *p, AstUnrollRangeStmt *
TypeAndValue tav = type_and_value_of_expr(expr);
if (is_ast_range(expr)) {
-
lbAddr val0_addr = {};
lbAddr val1_addr = {};
if (val0_type) val0_addr = lb_build_addr(p, val0);
@@ -1268,7 +1266,6 @@ gb_internal void lb_build_unroll_range_stmt(lbProcedure *p, AstUnrollRangeStmt *
}
}
-
} else if (tav.mode == Addressing_Type) {
GB_ASSERT(is_type_enum(type_deref(tav.type)));
Type *et = type_deref(tav.type);
@@ -1293,77 +1290,208 @@ gb_internal void lb_build_unroll_range_stmt(lbProcedure *p, AstUnrollRangeStmt *
if (val0_type) val0_addr = lb_build_addr(p, val0);
if (val1_type) val1_addr = lb_build_addr(p, val1);
- GB_ASSERT(expr->tav.mode == Addressing_Constant);
+ ExactValue unroll_count_ev = {};
+ if (rs->args.count != 0) {
+ unroll_count_ev = rs->args[0]->tav.value;
+ }
- Type *t = base_type(expr->tav.type);
+ if (unroll_count_ev.kind == ExactValue_Invalid) {
+ GB_ASSERT(expr->tav.mode == Addressing_Constant);
- switch (t->kind) {
- case Type_Basic:
- GB_ASSERT(is_type_string(t));
- {
- ExactValue value = expr->tav.value;
- GB_ASSERT(value.kind == ExactValue_String);
- String str = value.value_string;
- Rune codepoint = 0;
- isize offset = 0;
- do {
- isize width = utf8_decode(str.text+offset, str.len-offset, &codepoint);
- if (val0_type) lb_addr_store(p, val0_addr, lb_const_value(m, val0_type, exact_value_i64(codepoint)));
- if (val1_type) lb_addr_store(p, val1_addr, lb_const_value(m, val1_type, exact_value_i64(offset)));
- lb_build_stmt(p, rs->body);
+ Type *t = base_type(expr->tav.type);
- offset += width;
- } while (offset < str.len);
- }
- break;
- case Type_Array:
- if (t->Array.count > 0) {
- lbValue val = lb_build_expr(p, expr);
- lbValue val_addr = lb_address_from_load_or_generate_local(p, val);
-
- for (i64 i = 0; i < t->Array.count; i++) {
- if (val0_type) {
- // NOTE(bill): Due to weird legacy issues in LLVM, this needs to be an i32
- lbValue elem = lb_emit_array_epi(p, val_addr, cast(i32)i);
- lb_addr_store(p, val0_addr, lb_emit_load(p, elem));
- }
- if (val1_type) lb_addr_store(p, val1_addr, lb_const_value(m, val1_type, exact_value_i64(i)));
+ switch (t->kind) {
+ case Type_Basic:
+ GB_ASSERT(is_type_string(t));
+ {
+ ExactValue value = expr->tav.value;
+ GB_ASSERT(value.kind == ExactValue_String);
+ String str = value.value_string;
+ Rune codepoint = 0;
+ isize offset = 0;
+ do {
+ isize width = utf8_decode(str.text+offset, str.len-offset, &codepoint);
+ if (val0_type) lb_addr_store(p, val0_addr, lb_const_value(m, val0_type, exact_value_i64(codepoint)));
+ if (val1_type) lb_addr_store(p, val1_addr, lb_const_value(m, val1_type, exact_value_i64(offset)));
+ lb_build_stmt(p, rs->body);
- lb_build_stmt(p, rs->body);
+ offset += width;
+ } while (offset < str.len);
}
+ break;
+ case Type_Array:
+ if (t->Array.count > 0) {
+ lbValue val = lb_build_expr(p, expr);
+ lbValue val_addr = lb_address_from_load_or_generate_local(p, val);
+
+ for (i64 i = 0; i < t->Array.count; i++) {
+ if (val0_type) {
+ // NOTE(bill): Due to weird legacy issues in LLVM, this needs to be an i32
+ lbValue elem = lb_emit_array_epi(p, val_addr, cast(i32)i);
+ lb_addr_store(p, val0_addr, lb_emit_load(p, elem));
+ }
+ if (val1_type) lb_addr_store(p, val1_addr, lb_const_value(m, val1_type, exact_value_i64(i)));
- }
- break;
- case Type_EnumeratedArray:
- if (t->EnumeratedArray.count > 0) {
- lbValue val = lb_build_expr(p, expr);
- lbValue val_addr = lb_address_from_load_or_generate_local(p, val);
-
- for (i64 i = 0; i < t->EnumeratedArray.count; i++) {
- if (val0_type) {
- // NOTE(bill): Due to weird legacy issues in LLVM, this needs to be an i32
- lbValue elem = lb_emit_array_epi(p, val_addr, cast(i32)i);
- lb_addr_store(p, val0_addr, lb_emit_load(p, elem));
+ lb_build_stmt(p, rs->body);
}
- if (val1_type) {
- ExactValue idx = exact_value_add(exact_value_i64(i), *t->EnumeratedArray.min_value);
- lb_addr_store(p, val1_addr, lb_const_value(m, val1_type, idx));
+
+ }
+ break;
+ case Type_EnumeratedArray:
+ if (t->EnumeratedArray.count > 0) {
+ lbValue val = lb_build_expr(p, expr);
+ lbValue val_addr = lb_address_from_load_or_generate_local(p, val);
+
+ for (i64 i = 0; i < t->EnumeratedArray.count; i++) {
+ if (val0_type) {
+ // NOTE(bill): Due to weird legacy issues in LLVM, this needs to be an i32
+ lbValue elem = lb_emit_array_epi(p, val_addr, cast(i32)i);
+ lb_addr_store(p, val0_addr, lb_emit_load(p, elem));
+ }
+ if (val1_type) {
+ ExactValue idx = exact_value_add(exact_value_i64(i), *t->EnumeratedArray.min_value);
+ lb_addr_store(p, val1_addr, lb_const_value(m, val1_type, idx));
+ }
+
+ lb_build_stmt(p, rs->body);
}
- lb_build_stmt(p, rs->body);
}
+ break;
+ default:
+ GB_PANIC("Invalid '#unroll for' type");
+ break;
+ }
+ } else {
+
+ ////////////////////////////////
+ // //
+ // #unroll(N) logic //
+ // //
+ ////////////////////////////////
+
+
+ i64 unroll_count = exact_value_to_i64(unroll_count_ev);
+ gb_unused(unroll_count);
+
+ Type *t = base_type(expr->tav.type);
+ lbValue data_ptr = {};
+ lbValue count_ptr = {};
+
+ switch (t->kind) {
+ case Type_Slice:
+ case Type_DynamicArray: {
+ lbValue slice = lb_build_expr(p, expr);
+ if (is_type_pointer(slice.type)) {
+ count_ptr = lb_emit_struct_ep(p, slice, 1);
+ slice = lb_emit_load(p, slice);
+ } else {
+ count_ptr = lb_add_local_generated(p, t_int, false).addr;
+ lb_emit_store(p, count_ptr, lb_slice_len(p, slice));
+ }
+ data_ptr = lb_emit_struct_ev(p, slice, 0);
+ break;
}
- break;
- default:
- GB_PANIC("Invalid '#unroll for' type");
- break;
+
+ case Type_Array: {
+ lbValue array = lb_build_expr(p, expr);
+ count_ptr = lb_add_local_generated(p, t_int, false).addr;
+ lb_emit_store(p, count_ptr, lb_const_int(p->module, t_int, t->Array.count));
+
+ if (!is_type_pointer(array.type)) {
+ array = lb_address_from_load_or_generate_local(p, array);
+ }
+
+ GB_ASSERT(is_type_pointer(array.type));
+ data_ptr = lb_emit_conv(p, array, alloc_type_pointer(t->Array.elem));
+ break;
+ }
+
+ default:
+ GB_PANIC("Invalid '#unroll for' type");
+ break;
+ }
+
+ data_ptr.type = alloc_type_multi_pointer_to_pointer(data_ptr.type);
+
+ lbBlock *loop_top = lb_create_block(p, "for.unroll.loop.top");
+
+ lbBlock *body_top = lb_create_block(p, "for.unroll.body.top");
+ lbBlock *body_bot = lb_create_block(p, "for.unroll.body.bot");
+
+ lbBlock *done = lb_create_block(p, "for.unroll.done");
+
+ lbBlock *loop_bot = unroll_count > 1 ? lb_create_block(p, "for.unroll.loop.bot") : done;
+
+ /*
+ i := 0
+ for ; i+N <= len(array); i += N {
+ body
+ }
+ for ; i < len(array); i += 1 {
+ body
+ }
+ */
+
+ Entity *val_entity = val0 ? entity_of_node(val0) : nullptr;
+ Entity *idx_entity = val1 ? entity_of_node(val1) : nullptr;
+
+ lbAddr val_addr = lb_add_local(p, type_deref(data_ptr.type, true), val_entity);
+ lbAddr idx_addr = lb_add_local(p, t_int, idx_entity);
+ lb_addr_store(p, idx_addr, lb_const_nil(p->module, t_int));
+
+ lb_emit_jump(p, loop_top);
+ lb_start_block(p, loop_top);
+
+ lbValue idx_add_n = lb_addr_load(p, idx_addr);
+ idx_add_n = lb_emit_arith(p, Token_Add, idx_add_n, lb_const_int(p->module, t_int, unroll_count), t_int);
+
+ lbValue cond_top = lb_emit_comp(p, Token_LtEq, idx_add_n, lb_emit_load(p, count_ptr));
+ lb_emit_if(p, cond_top, body_top, loop_bot);
+
+ lb_start_block(p, body_top);
+ for (i64 top = 0; top < unroll_count; top++) {
+ lbValue idx = lb_addr_load(p, idx_addr);
+ lbValue val = lb_emit_load(p, lb_emit_ptr_offset(p, data_ptr, idx));
+ lb_addr_store(p, val_addr, val);
+
+ lb_build_stmt(p, rs->body);
+
+ lb_emit_increment(p, lb_addr_get_ptr(p, idx_addr));
+ }
+ lb_emit_jump(p, loop_top);
+
+ if (unroll_count > 1) {
+ lb_start_block(p, loop_bot);
+
+ lbValue cond_bot = lb_emit_comp(p, Token_Lt, lb_addr_load(p, idx_addr), lb_emit_load(p, count_ptr));
+ lb_emit_if(p, cond_bot, body_bot, done);
+
+ lb_start_block(p, body_bot);
+ {
+ lbValue idx = lb_addr_load(p, idx_addr);
+ lbValue val = lb_emit_load(p, lb_emit_ptr_offset(p, data_ptr, idx));
+ lb_addr_store(p, val_addr, val);
+
+ lb_build_stmt(p, rs->body);
+
+ lb_emit_increment(p, lb_addr_get_ptr(p, idx_addr));
+ }
+ lb_emit_jump(p, loop_bot);
+ }
+
+ lb_close_scope(p, lbDeferExit_Default, nullptr, rs->body);
+ lb_emit_jump(p, done);
+ lb_start_block(p, done);
+
+ return;
}
}
- lb_close_scope(p, lbDeferExit_Default, nullptr);
+ lb_close_scope(p, lbDeferExit_Default, nullptr, rs->body);
}
gb_internal bool lb_switch_stmt_can_be_trivial_jump_table(AstSwitchStmt *ss, bool *default_found_) {
@@ -1433,6 +1561,7 @@ gb_internal void lb_build_switch_stmt(lbProcedure *p, AstSwitchStmt *ss, Scope *
ast_node(body, BlockStmt, ss->body);
isize case_count = body->stmts.count;
+ Ast *default_clause = nullptr;
Slice<Ast *> default_stmts = {};
lbBlock *default_fall = nullptr;
lbBlock *default_block = nullptr;
@@ -1482,6 +1611,7 @@ gb_internal void lb_build_switch_stmt(lbProcedure *p, AstSwitchStmt *ss, Scope *
if (cc->list.count == 0) {
// default case
+ default_clause = clause;
default_stmts = cc->stmts;
default_fall = fall;
if (switch_instr == nullptr) {
@@ -1552,7 +1682,7 @@ gb_internal void lb_build_switch_stmt(lbProcedure *p, AstSwitchStmt *ss, Scope *
lb_push_target_list(p, ss->label, done, nullptr, fall);
lb_open_scope(p, body->scope);
lb_build_stmt_list(p, cc->stmts);
- lb_close_scope(p, lbDeferExit_Default, body);
+ lb_close_scope(p, lbDeferExit_Default, body, clause);
lb_pop_target_list(p);
lb_emit_jump(p, done);
@@ -1570,13 +1700,13 @@ gb_internal void lb_build_switch_stmt(lbProcedure *p, AstSwitchStmt *ss, Scope *
lb_push_target_list(p, ss->label, done, nullptr, default_fall);
lb_open_scope(p, default_block->scope);
lb_build_stmt_list(p, default_stmts);
- lb_close_scope(p, lbDeferExit_Default, default_block);
+ lb_close_scope(p, lbDeferExit_Default, default_block, default_clause);
lb_pop_target_list(p);
}
lb_emit_jump(p, done);
lb_start_block(p, done);
- lb_close_scope(p, lbDeferExit_Default, done);
+ lb_close_scope(p, lbDeferExit_Default, done, ss->body);
}
gb_internal void lb_store_type_case_implicit(lbProcedure *p, Ast *clause, lbValue value, bool is_default_case) {
@@ -1627,7 +1757,7 @@ gb_internal void lb_type_case_body(lbProcedure *p, Ast *label, Ast *clause, lbBl
lb_push_target_list(p, label, done, nullptr, nullptr);
lb_build_stmt_list(p, cc->stmts);
- lb_close_scope(p, lbDeferExit_Default, body);
+ lb_close_scope(p, lbDeferExit_Default, body, clause);
lb_pop_target_list(p);
lb_emit_jump(p, done);
@@ -1835,7 +1965,7 @@ gb_internal void lb_build_type_switch_stmt(lbProcedure *p, AstTypeSwitchStmt *ss
lb_emit_jump(p, done);
lb_start_block(p, done);
- lb_close_scope(p, lbDeferExit_Default, done);
+ lb_close_scope(p, lbDeferExit_Default, done, ss->body);
}
@@ -1959,7 +2089,7 @@ gb_internal void lb_build_assignment(lbProcedure *p, Array<lbAddr> &lvals, Slice
p->in_multi_assignment = prev_in_assignment;
}
-gb_internal void lb_build_return_stmt_internal(lbProcedure *p, lbValue res) {
+gb_internal void lb_build_return_stmt_internal(lbProcedure *p, lbValue res, TokenPos pos) {
lbFunctionType *ft = lb_get_function_type(p->module, p->type);
bool return_by_pointer = ft->ret.kind == lbArg_Indirect;
bool split_returns = ft->multiple_return_original_type != nullptr;
@@ -1982,7 +2112,7 @@ gb_internal void lb_build_return_stmt_internal(lbProcedure *p, lbValue res) {
LLVMBuildStore(p->builder, LLVMConstNull(p->abi_function_type->ret.type), p->return_ptr.addr.value);
}
- lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr);
+ lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr, pos);
// Check for terminator in the defer stmts
LLVMValueRef instr = LLVMGetLastInstruction(p->curr_block->block);
@@ -2012,7 +2142,7 @@ gb_internal void lb_build_return_stmt_internal(lbProcedure *p, lbValue res) {
ret_val = OdinLLVMBuildTransmute(p, ret_val, ret_type);
}
- lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr);
+ lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr, pos);
// Check for terminator in the defer stmts
LLVMValueRef instr = LLVMGetLastInstruction(p->curr_block->block);
@@ -2021,7 +2151,7 @@ gb_internal void lb_build_return_stmt_internal(lbProcedure *p, lbValue res) {
}
}
}
-gb_internal void lb_build_return_stmt(lbProcedure *p, Slice<Ast *> const &return_results) {
+gb_internal void lb_build_return_stmt(lbProcedure *p, Slice<Ast *> const &return_results, TokenPos pos) {
lb_ensure_abi_function_type(p->module, p);
isize return_count = p->type->Proc.result_count;
@@ -2029,7 +2159,7 @@ gb_internal void lb_build_return_stmt(lbProcedure *p, Slice<Ast *> const &return
if (return_count == 0) {
// No return values
- lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr);
+ lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr, pos);
// Check for terminator in the defer stmts
LLVMValueRef instr = LLVMGetLastInstruction(p->curr_block->block);
@@ -2138,11 +2268,11 @@ gb_internal void lb_build_return_stmt(lbProcedure *p, Slice<Ast *> const &return
GB_ASSERT(result_values.count-1 == result_eps.count);
lb_addr_store(p, p->return_ptr, result_values[result_values.count-1]);
- lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr);
+ lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr, pos);
LLVMBuildRetVoid(p->builder);
return;
} else {
- return lb_build_return_stmt_internal(p, result_values[result_values.count-1]);
+ return lb_build_return_stmt_internal(p, result_values[result_values.count-1], pos);
}
} else {
@@ -2169,7 +2299,7 @@ gb_internal void lb_build_return_stmt(lbProcedure *p, Slice<Ast *> const &return
}
if (return_by_pointer) {
- lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr);
+ lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr, pos);
LLVMBuildRetVoid(p->builder);
return;
}
@@ -2177,13 +2307,13 @@ gb_internal void lb_build_return_stmt(lbProcedure *p, Slice<Ast *> const &return
res = lb_emit_load(p, res);
}
}
- lb_build_return_stmt_internal(p, res);
+ lb_build_return_stmt_internal(p, res, pos);
}
gb_internal void lb_build_if_stmt(lbProcedure *p, Ast *node) {
ast_node(is, IfStmt, node);
lb_open_scope(p, is->scope); // Scope #1
- defer (lb_close_scope(p, lbDeferExit_Default, nullptr));
+ defer (lb_close_scope(p, lbDeferExit_Default, nullptr, node));
lbBlock *then = lb_create_block(p, "if.then");
lbBlock *done = lb_create_block(p, "if.done");
@@ -2234,7 +2364,7 @@ gb_internal void lb_build_if_stmt(lbProcedure *p, Ast *node) {
lb_open_scope(p, scope_of_node(is->else_stmt));
lb_build_stmt(p, is->else_stmt);
- lb_close_scope(p, lbDeferExit_Default, nullptr);
+ lb_close_scope(p, lbDeferExit_Default, nullptr, is->else_stmt);
}
lb_emit_jump(p, done);
@@ -2251,7 +2381,7 @@ gb_internal void lb_build_if_stmt(lbProcedure *p, Ast *node) {
lb_open_scope(p, scope_of_node(is->else_stmt));
lb_build_stmt(p, is->else_stmt);
- lb_close_scope(p, lbDeferExit_Default, nullptr);
+ lb_close_scope(p, lbDeferExit_Default, nullptr, is->else_stmt);
lb_emit_jump(p, done);
}
@@ -2322,7 +2452,7 @@ gb_internal void lb_build_for_stmt(lbProcedure *p, Ast *node) {
}
lb_start_block(p, done);
- lb_close_scope(p, lbDeferExit_Default, nullptr);
+ lb_close_scope(p, lbDeferExit_Default, nullptr, node);
}
gb_internal void lb_build_assign_stmt_array(lbProcedure *p, TokenKind op, lbAddr const &lhs, lbValue const &value) {
@@ -2588,7 +2718,7 @@ gb_internal void lb_build_stmt(lbProcedure *p, Ast *node) {
lb_open_scope(p, bs->scope);
lb_build_stmt_list(p, bs->stmts);
- lb_close_scope(p, lbDeferExit_Default, nullptr);
+ lb_close_scope(p, lbDeferExit_Default, nullptr, node);
if (done != nullptr) {
lb_emit_jump(p, done);
@@ -2702,7 +2832,7 @@ gb_internal void lb_build_stmt(lbProcedure *p, Ast *node) {
case_end;
case_ast_node(rs, ReturnStmt, node);
- lb_build_return_stmt(p, rs->results);
+ lb_build_return_stmt(p, rs->results, ast_token(node).pos);
case_end;
case_ast_node(is, IfStmt, node);
@@ -2755,7 +2885,7 @@ gb_internal void lb_build_stmt(lbProcedure *p, Ast *node) {
}
}
if (block != nullptr) {
- lb_emit_defer_stmts(p, lbDeferExit_Branch, block);
+ lb_emit_defer_stmts(p, lbDeferExit_Branch, block, node);
}
lb_emit_jump(p, block);
lb_start_block(p, lb_create_block(p, "unreachable"));
@@ -2795,7 +2925,13 @@ gb_internal void lb_build_defer_stmt(lbProcedure *p, lbDefer const &d) {
}
}
-gb_internal void lb_emit_defer_stmts(lbProcedure *p, lbDeferExitKind kind, lbBlock *block) {
+gb_internal void lb_emit_defer_stmts(lbProcedure *p, lbDeferExitKind kind, lbBlock *block, TokenPos pos) {
+ TokenPos prev_token_pos = p->branch_location_pos;
+ if (p->uses_branch_location) {
+ p->branch_location_pos = pos;
+ }
+ defer (p->branch_location_pos = prev_token_pos);
+
isize count = p->defer_stmts.count;
isize i = count;
while (i --> 0) {
@@ -2822,6 +2958,21 @@ gb_internal void lb_emit_defer_stmts(lbProcedure *p, lbDeferExitKind kind, lbBlo
}
}
+gb_internal void lb_emit_defer_stmts(lbProcedure *p, lbDeferExitKind kind, lbBlock *block, Ast *node) {
+ TokenPos pos = {};
+ if (node) {
+ if (node->kind == Ast_BlockStmt) {
+ pos = ast_end_token(node).pos;
+ } else if (node->kind == Ast_CaseClause) {
+ pos = ast_end_token(node).pos;
+ } else {
+ pos = ast_token(node).pos;
+ }
+ }
+ return lb_emit_defer_stmts(p, kind, block, pos);
+}
+
+
gb_internal void lb_add_defer_node(lbProcedure *p, isize scope_index, Ast *stmt) {
Type *pt = base_type(p->type);
GB_ASSERT(pt->kind == Type_Proc);
diff --git a/src/llvm_backend_type.cpp b/src/llvm_backend_type.cpp
index 6c12b37be..ad4250f3c 100644
--- a/src/llvm_backend_type.cpp
+++ b/src/llvm_backend_type.cpp
@@ -1,24 +1,24 @@
-gb_internal isize lb_type_info_index(CheckerInfo *info, Type *type, bool err_on_not_found=true) {
- auto *set = &info->minimum_dependency_type_info_set;
- isize index = type_info_index(info, type, err_on_not_found);
+
+gb_internal isize lb_type_info_index(CheckerInfo *info, TypeInfoPair pair, bool err_on_not_found=true) {
+ isize index = type_info_index(info, pair, err_on_not_found);
if (index >= 0) {
- auto *found = map_get(set, index+1);
- if (found) {
- GB_ASSERT(*found >= 0);
- return *found + 1;
- }
+ return index;
}
if (err_on_not_found) {
- gb_printf_err("NOT FOUND lb_type_info_index:\n\t%s\n\t@ index %td\n\tmax count: %u\nFound:\n", type_to_string(type), index, set->count);
- for (auto const &entry : *set) {
+ gb_printf_err("NOT FOUND lb_type_info_index:\n\t%s\n\t@ index %td\n\tmax count: %u\nFound:\n", type_to_string(pair.type), index, info->min_dep_type_info_index_map.count);
+ for (auto const &entry : info->min_dep_type_info_index_map) {
isize type_info_index = entry.key;
- gb_printf_err("\t%s\n", type_to_string(info->type_info_types[type_info_index]));
+ gb_printf_err("\t%s\n", type_to_string(info->type_info_types_hash_map[type_info_index].type));
}
GB_PANIC("NOT FOUND");
}
return -1;
}
+gb_internal isize lb_type_info_index(CheckerInfo *info, Type *type, bool err_on_not_found=true) {
+ return lb_type_info_index(info, {type, type_hash_canonical_type(type)}, err_on_not_found);
+}
+
gb_internal u64 lb_typeid_kind(lbModule *m, Type *type, u64 id=0) {
GB_ASSERT(!build_context.no_rtti);
@@ -73,37 +73,8 @@ gb_internal lbValue lb_typeid(lbModule *m, Type *type) {
type = default_type(type);
- u64 id = cast(u64)lb_type_info_index(m->info, type);
- GB_ASSERT(id >= 0);
-
- u64 kind = lb_typeid_kind(m, type, id);
- u64 named = is_type_named(type) && type->kind != Type_Basic;
- u64 special = 0;
- u64 reserved = 0;
-
- if (is_type_cstring(type)) {
- special = 1;
- } else if (is_type_integer(type) && !is_type_unsigned(type)) {
- special = 1;
- }
-
- u64 data = 0;
- if (build_context.ptr_size == 4) {
- GB_ASSERT(id <= (1u<<24u));
- data |= (id &~ (1u<<24)) << 0u; // index
- data |= (kind &~ (1u<<5)) << 24u; // kind
- data |= (named &~ (1u<<1)) << 29u; // named
- data |= (special &~ (1u<<1)) << 30u; // special
- data |= (reserved &~ (1u<<1)) << 31u; // reserved
- } else {
- GB_ASSERT(build_context.ptr_size == 8);
- GB_ASSERT(id <= (1ull<<56u));
- data |= (id &~ (1ull<<56)) << 0ul; // index
- data |= (kind &~ (1ull<<5)) << 56ull; // kind
- data |= (named &~ (1ull<<1)) << 61ull; // named
- data |= (special &~ (1ull<<1)) << 62ull; // special
- data |= (reserved &~ (1ull<<1)) << 63ull; // reserved
- }
+ u64 data = type_hash_canonical_type(type);
+ GB_ASSERT(data != 0);
lbValue res = {};
res.value = LLVMConstInt(lb_type(m, t_typeid), data, false);
@@ -279,13 +250,14 @@ gb_internal void lb_setup_type_info_data_giant_array(lbModule *m, i64 global_typ
LLVMTypeRef *modified_types = lb_setup_modified_types_for_type_info(m, global_type_info_data_entity_count);
defer (gb_free(heap_allocator(), modified_types));
- for_array(type_info_type_index, info->type_info_types) {
- Type *t = info->type_info_types[type_info_type_index];
+ for_array(type_info_type_index, info->type_info_types_hash_map) {
+ auto const &tt = info->type_info_types_hash_map[type_info_type_index];
+ Type *t = tt.type;
if (t == nullptr || t == t_invalid) {
continue;
}
- isize entry_index = lb_type_info_index(info, t, false);
+ isize entry_index = lb_type_info_index(info, tt, false);
if (entry_index <= 0) {
continue;
}
@@ -342,8 +314,8 @@ gb_internal void lb_setup_type_info_data_giant_array(lbModule *m, i64 global_typ
return giant_const_values[index];
};
- for_array(type_info_type_index, info->type_info_types) {
- Type *t = info->type_info_types[type_info_type_index];
+ for_array(type_info_type_index, info->type_info_types_hash_map) {
+ Type *t = info->type_info_types_hash_map[type_info_type_index].type;
if (t == nullptr || t == t_invalid) {
continue;
}
@@ -1071,7 +1043,12 @@ gb_internal void lb_setup_type_info_data_giant_array(lbModule *m, i64 global_typ
LLVMSetInitializer(giant_const_values[entry_index], LLVMConstNamedStruct(stype, small_const_values, variant_index+1));
}
for (isize i = 0; i < global_type_info_data_entity_count; i++) {
- giant_const_values[i] = LLVMConstPointerCast(giant_const_values[i], lb_type(m, t_type_info_ptr));
+ auto *ptr = &giant_const_values[i];
+ if (*ptr != nullptr) {
+ *ptr = LLVMConstPointerCast(*ptr, lb_type(m, t_type_info_ptr));
+ } else {
+ *ptr = LLVMConstNull(lb_type(m, t_type_info_ptr));
+ }
}
diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp
index a2a0ba4cc..c876169f3 100644
--- a/src/llvm_backend_utility.cpp
+++ b/src/llvm_backend_utility.cpp
@@ -476,8 +476,8 @@ gb_internal lbValue lb_emit_or_else(lbProcedure *p, Ast *arg, Ast *else_expr, Ty
}
}
-gb_internal void lb_build_return_stmt(lbProcedure *p, Slice<Ast *> const &return_results);
-gb_internal void lb_build_return_stmt_internal(lbProcedure *p, lbValue res);
+gb_internal void lb_build_return_stmt(lbProcedure *p, Slice<Ast *> const &return_results, TokenPos pos);
+gb_internal void lb_build_return_stmt_internal(lbProcedure *p, lbValue res, TokenPos pos);
gb_internal lbValue lb_emit_or_return(lbProcedure *p, Ast *arg, TypeAndValue const &tv) {
lbValue lhs = {};
@@ -506,10 +506,10 @@ gb_internal lbValue lb_emit_or_return(lbProcedure *p, Ast *arg, TypeAndValue con
lbValue found = map_must_get(&p->module->values, end_entity);
lb_emit_store(p, found, rhs);
- lb_build_return_stmt(p, {});
+ lb_build_return_stmt(p, {}, ast_token(arg).pos);
} else {
GB_ASSERT(tuple->variables.count == 1);
- lb_build_return_stmt_internal(p, rhs);
+ lb_build_return_stmt_internal(p, rhs, ast_token(arg).pos);
}
}
lb_start_block(p, continue_block);
@@ -771,9 +771,7 @@ gb_internal lbValue lb_emit_union_cast(lbProcedure *p, lbValue value, Type *type
auto args = array_make<lbValue>(permanent_allocator(), arg_count);
args[0] = ok;
- args[1] = lb_const_string(m, get_file_path_string(pos.file_id));
- args[2] = lb_const_int(m, t_i32, pos.line);
- args[3] = lb_const_int(m, t_i32, pos.column);
+ lb_set_file_line_col(p, array_slice(args, 1, args.count), pos);
if (!build_context.no_rtti) {
args[4] = lb_typeid(m, src_type);
@@ -847,9 +845,7 @@ gb_internal lbAddr lb_emit_any_cast_addr(lbProcedure *p, lbValue value, Type *ty
auto args = array_make<lbValue>(permanent_allocator(), arg_count);
args[0] = ok;
- args[1] = lb_const_string(m, get_file_path_string(pos.file_id));
- args[2] = lb_const_int(m, t_i32, pos.line);
- args[3] = lb_const_int(m, t_i32, pos.column);
+ lb_set_file_line_col(p, array_slice(args, 1, args.count), pos);
if (!build_context.no_rtti) {
args[4] = any_typeid;
@@ -975,6 +971,13 @@ gb_internal i32 lb_convert_struct_index(lbModule *m, Type *t, i32 index) {
if (t->kind == Type_Struct) {
auto field_remapping = lb_get_struct_remapping(m, t);
return field_remapping[index];
+ } else if (is_type_any(t) && build_context.ptr_size == 4) {
+ GB_ASSERT(t->kind == Type_Basic);
+ GB_ASSERT(t->Basic.kind == Basic_any);
+ switch (index) {
+ case 0: return 0; // data
+ case 1: return 2; // id
+ }
} else if (build_context.ptr_size != build_context.int_size) {
switch (t->kind) {
case Type_Basic:
@@ -1200,9 +1203,22 @@ gb_internal lbValue lb_emit_struct_ep(lbProcedure *p, lbValue s, i32 index) {
lbValue gep = lb_emit_struct_ep_internal(p, s, index, result_type);
Type *bt = base_type(t);
- if (bt->kind == Type_Struct && bt->Struct.is_packed) {
- lb_set_metadata_custom_u64(p->module, gep.value, ODIN_METADATA_IS_PACKED, 1);
- GB_ASSERT(lb_get_metadata_custom_u64(p->module, gep.value, ODIN_METADATA_IS_PACKED) == 1);
+ if (bt->kind == Type_Struct) {
+ if (bt->Struct.is_packed) {
+ lb_set_metadata_custom_u64(p->module, gep.value, ODIN_METADATA_IS_PACKED, 1);
+ GB_ASSERT(lb_get_metadata_custom_u64(p->module, gep.value, ODIN_METADATA_IS_PACKED) == 1);
+ }
+ u64 align_max = bt->Struct.custom_max_field_align;
+ u64 align_min = bt->Struct.custom_min_field_align;
+ GB_ASSERT(align_min == 0 || align_max == 0 || align_min <= align_max);
+ if (align_max) {
+ lb_set_metadata_custom_u64(p->module, gep.value, ODIN_METADATA_MAX_ALIGN, align_max);
+ GB_ASSERT(lb_get_metadata_custom_u64(p->module, gep.value, ODIN_METADATA_MAX_ALIGN) == align_max);
+ }
+ if (align_min) {
+ lb_set_metadata_custom_u64(p->module, gep.value, ODIN_METADATA_MIN_ALIGN, align_min);
+ GB_ASSERT(lb_get_metadata_custom_u64(p->module, gep.value, ODIN_METADATA_MIN_ALIGN) == align_min);
+ }
}
return gep;
@@ -2080,23 +2096,40 @@ gb_internal void lb_set_wasm_export_attributes(LLVMValueRef value, String export
gb_internal lbAddr lb_handle_objc_find_or_register_selector(lbProcedure *p, String const &name) {
- lbAddr *found = string_map_get(&p->module->objc_selectors, name);
+ lbObjcRef *found = string_map_get(&p->module->objc_selectors, name);
if (found) {
- return *found;
- } else {
- lbModule *default_module = &p->module->gen->default_module;
- Entity *e = nullptr;
- lbAddr default_addr = lb_add_global_generated(default_module, t_objc_SEL, {}, &e);
+ return found->local_module_addr;
+ }
- lbValue ptr = lb_find_value_from_entity(p->module, e);
- lbAddr local_addr = lb_addr(ptr);
+ lbModule *default_module = &p->module->gen->default_module;
+ Entity *entity = {};
- string_map_set(&default_module->objc_selectors, name, default_addr);
- if (default_module != p->module) {
- string_map_set(&p->module->objc_selectors, name, local_addr);
+ if (default_module != p->module) {
+ found = string_map_get(&default_module->objc_selectors, name);
+ if (found) {
+ entity = found->entity;
}
- return local_addr;
}
+
+ if (!entity) {
+ gbString global_name = gb_string_make(temporary_allocator(), "__$objc_SEL$");
+ global_name = gb_string_append_length(global_name, name.text, name.len);
+
+ lbAddr default_addr = lb_add_global_generated_with_name(
+ default_module, t_objc_SEL, {},
+ make_string(cast(u8 const *)global_name, gb_string_length(global_name)),
+ &entity);
+ string_map_set(&default_module->objc_selectors, name, lbObjcRef{entity, default_addr});
+ }
+
+ lbValue ptr = lb_find_value_from_entity(p->module, entity);
+ lbAddr local_addr = lb_addr(ptr);
+
+ if (default_module != p->module) {
+ string_map_set(&p->module->objc_selectors, name, lbObjcRef{entity, local_addr});
+ }
+
+ return local_addr;
}
gb_internal lbValue lb_handle_objc_find_selector(lbProcedure *p, Ast *expr) {
@@ -2126,23 +2159,39 @@ gb_internal lbValue lb_handle_objc_register_selector(lbProcedure *p, Ast *expr)
}
gb_internal lbAddr lb_handle_objc_find_or_register_class(lbProcedure *p, String const &name) {
- lbAddr *found = string_map_get(&p->module->objc_classes, name);
+ lbObjcRef *found = string_map_get(&p->module->objc_classes, name);
if (found) {
- return *found;
- } else {
- lbModule *default_module = &p->module->gen->default_module;
- Entity *e = nullptr;
- lbAddr default_addr = lb_add_global_generated(default_module, t_objc_SEL, {}, &e);
+ return found->local_module_addr;
+ }
- lbValue ptr = lb_find_value_from_entity(p->module, e);
- lbAddr local_addr = lb_addr(ptr);
+ lbModule *default_module = &p->module->gen->default_module;
+ Entity *entity = {};
- string_map_set(&default_module->objc_classes, name, default_addr);
- if (default_module != p->module) {
- string_map_set(&p->module->objc_classes, name, local_addr);
+ if (default_module != p->module) {
+ found = string_map_get(&default_module->objc_classes, name);
+ if (found) {
+ entity = found->entity;
}
- return local_addr;
}
+
+ if (!entity) {
+ gbString global_name = gb_string_make(temporary_allocator(), "__$objc_Class$");
+ global_name = gb_string_append_length(global_name, name.text, name.len);
+
+ lbAddr default_addr = lb_add_global_generated_with_name(default_module, t_objc_Class, {},
+ make_string(cast(u8 const *)global_name, gb_string_length(global_name)),
+ &entity);
+ string_map_set(&default_module->objc_classes, name, lbObjcRef{entity, default_addr});
+ }
+
+ lbValue ptr = lb_find_value_from_entity(p->module, entity);
+ lbAddr local_addr = lb_addr(ptr);
+
+ if (default_module != p->module) {
+ string_map_set(&p->module->objc_classes, name, lbObjcRef{entity, local_addr});
+ }
+
+ return local_addr;
}
gb_internal lbValue lb_handle_objc_find_class(lbProcedure *p, Ast *expr) {
@@ -2183,23 +2232,7 @@ gb_internal lbValue lb_handle_objc_id(lbProcedure *p, Ast *expr) {
GB_ASSERT(e->kind == Entity_TypeName);
String name = e->TypeName.objc_class_name;
- lbAddr *found = string_map_get(&p->module->objc_classes, name);
- if (found) {
- return lb_addr_load(p, *found);
- } else {
- lbModule *default_module = &p->module->gen->default_module;
- Entity *e = nullptr;
- lbAddr default_addr = lb_add_global_generated(default_module, t_objc_Class, {}, &e);
-
- lbValue ptr = lb_find_value_from_entity(p->module, e);
- lbAddr local_addr = lb_addr(ptr);
-
- string_map_set(&default_module->objc_classes, name, default_addr);
- if (default_module != p->module) {
- string_map_set(&p->module->objc_classes, name, local_addr);
- }
- return lb_addr_load(p, local_addr);
- }
+ return lb_addr_load(p, lb_handle_objc_find_or_register_class(p, name));
}
return lb_build_expr(p, expr);
diff --git a/src/main.cpp b/src/main.cpp
index 015269438..0a24d64a6 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -331,6 +331,7 @@ enum BuildFlagKind {
BuildFlag_UseRADLink,
BuildFlag_Linker,
BuildFlag_UseSeparateModules,
+ BuildFlag_UseSingleModule,
BuildFlag_NoThreadedChecker,
BuildFlag_ShowDebugMessages,
@@ -401,6 +402,7 @@ enum BuildFlagKind {
BuildFlag_InternalModulePerFile,
BuildFlag_InternalCached,
BuildFlag_InternalNoInline,
+ BuildFlag_InternalByValue,
BuildFlag_Tilde,
@@ -544,6 +546,7 @@ gb_internal bool parse_build_flags(Array<String> args) {
add_flag(&build_flags, BuildFlag_UseRADLink, str_lit("radlink"), BuildFlagParam_None, Command__does_build);
add_flag(&build_flags, BuildFlag_Linker, str_lit("linker"), BuildFlagParam_String, Command__does_build);
add_flag(&build_flags, BuildFlag_UseSeparateModules, str_lit("use-separate-modules"), BuildFlagParam_None, Command__does_build);
+ add_flag(&build_flags, BuildFlag_UseSingleModule, str_lit("use-single-module"), BuildFlagParam_None, Command__does_build);
add_flag(&build_flags, BuildFlag_NoThreadedChecker, str_lit("no-threaded-checker"), BuildFlagParam_None, Command__does_check);
add_flag(&build_flags, BuildFlag_ShowDebugMessages, str_lit("show-debug-messages"), BuildFlagParam_None, Command_all);
@@ -612,6 +615,7 @@ gb_internal bool parse_build_flags(Array<String> args) {
add_flag(&build_flags, BuildFlag_InternalModulePerFile, str_lit("internal-module-per-file"), BuildFlagParam_None, Command_all);
add_flag(&build_flags, BuildFlag_InternalCached, str_lit("internal-cached"), BuildFlagParam_None, Command_all);
add_flag(&build_flags, BuildFlag_InternalNoInline, str_lit("internal-no-inline"), BuildFlagParam_None, Command_all);
+ add_flag(&build_flags, BuildFlag_InternalByValue, str_lit("internal-by-value"), BuildFlagParam_None, Command_all);
#if ALLOW_TILDE
add_flag(&build_flags, BuildFlag_Tilde, str_lit("tilde"), BuildFlagParam_None, Command__does_build);
@@ -1190,7 +1194,7 @@ gb_internal bool parse_build_flags(Array<String> args) {
build_context.no_type_assert = true;
break;
case BuildFlag_NoDynamicLiterals:
- build_context.no_dynamic_literals = true;
+ gb_printf_err("Warning: Use of -no-dynamic-literals is now redundant\n");
break;
case BuildFlag_NoCRT:
build_context.no_crt = true;
@@ -1238,8 +1242,19 @@ gb_internal bool parse_build_flags(Array<String> args) {
case BuildFlag_UseSeparateModules:
+ if (build_context.use_single_module) {
+ gb_printf_err("-use-separate-modules cannot be used with -use-single-module\n");
+ bad_flags = true;
+ }
build_context.use_separate_modules = true;
break;
+ case BuildFlag_UseSingleModule:
+ if (build_context.use_separate_modules) {
+ gb_printf_err("-use-single-module cannot be used with -use-separate-modules\n");
+ bad_flags = true;
+ }
+ build_context.use_single_module = true;
+ break;
case BuildFlag_NoThreadedChecker:
build_context.no_threaded_checker = true;
break;
@@ -1508,6 +1523,9 @@ gb_internal bool parse_build_flags(Array<String> args) {
case BuildFlag_InternalNoInline:
build_context.internal_no_inline = true;
break;
+ case BuildFlag_InternalByValue:
+ build_context.internal_by_value = true;
+ break;
case BuildFlag_Tilde:
build_context.tilde_backend = true;
@@ -1796,7 +1814,10 @@ gb_internal void check_defines(BuildContext *bc, Checker *c) {
if (!found) {
ERROR_BLOCK();
warning(nullptr, "given -define:%.*s is unused in the project", LIT(name));
- error_line("\tSuggestion: use the -show-defineables flag for an overview of the possible defines\n");
+
+ if (!global_ignore_warnings()) {
+ error_line("\tSuggestion: use the -show-defineables flag for an overview of the possible defines\n");
+ }
}
}
}
@@ -2115,7 +2136,7 @@ gb_internal void export_dependencies(Checker *c) {
for_array(i, files) {
AstFile *file = files[i];
gb_fprintf(&f, "\t\t\"%.*s\"", LIT(file->fullpath));
- if (i+1 == files.count) {
+ if (i+1 < files.count) {
gb_fprintf(&f, ",");
}
gb_fprintf(&f, "\n");
@@ -2128,7 +2149,7 @@ gb_internal void export_dependencies(Checker *c) {
for_array(i, load_files) {
LoadFileCache *cache = load_files[i];
gb_fprintf(&f, "\t\t\"%.*s\"", LIT(cache->path));
- if (i+1 == load_files.count) {
+ if (i+1 < load_files.count) {
gb_fprintf(&f, ",");
}
gb_fprintf(&f, "\n");
@@ -2326,6 +2347,10 @@ gb_internal void print_show_help(String const arg0, String command, String optio
print_usage_line(2, "Sets the default allocator to be the nil_allocator, an allocator which does nothing.");
}
+ if (print_flag("-default-to-panic-allocator")) {
+ print_usage_line(2, "Sets the default allocator to be the panic_allocator, an allocator which calls panic() on any allocation attempt.");
+ }
+
if (print_flag("-define:<name>=<value>")) {
print_usage_line(2, "Defines a scalar boolean, integer or string as global constant.");
print_usage_line(2, "Example: -define:SPAM=123");
@@ -2705,8 +2730,12 @@ gb_internal void print_show_help(String const arg0, String command, String optio
if (run_or_build) {
if (print_flag("-use-separate-modules")) {
print_usage_line(2, "The backend generates multiple build units which are then linked together.");
- print_usage_line(2, "Normally, a single build unit is generated for a standard project.");
- print_usage_line(2, "This is the default behaviour on Windows for '-o:none' and '-o:minimal' builds.");
+ print_usage_line(2, "This is the default behaviour for '-o:none' and '-o:minimal' builds.");
+ print_usage_line(2, "Normally, a single build unit is generated for a standard project for '-o:speed' or '-o:size'.");
+ }
+ if (print_flag("-use-single-module")) {
+ print_usage_line(2, "The backend generates only a single build unit.");
+ print_usage_line(2, "This is the default behaviour for '-o:speed' or '-o:size'.");
}
}
@@ -3564,10 +3593,15 @@ int main(int arg_count, char const **arg_ptr) {
}
if (build_context.generate_docs) {
+ MAIN_TIME_SECTION("generate documentation");
if (global_error_collector.count != 0) {
return 1;
}
generate_documentation(checker);
+
+ if (build_context.show_timings) {
+ show_timings(checker, &global_timings);
+ }
return 0;
}
diff --git a/src/name_canonicalization.cpp b/src/name_canonicalization.cpp
new file mode 100644
index 000000000..a80dc1996
--- /dev/null
+++ b/src/name_canonicalization.cpp
@@ -0,0 +1,752 @@
+gb_internal GB_COMPARE_PROC(type_info_pair_cmp) {
+ TypeInfoPair *x = cast(TypeInfoPair *)a;
+ TypeInfoPair *y = cast(TypeInfoPair *)b;
+ if (x->hash == y->hash) {
+ return 0;
+ }
+ return x->hash < y->hash ? -1 : +1;
+}
+
+
+gb_internal gbAllocator type_set_allocator(void) {
+ return heap_allocator();
+}
+
+gb_internal TypeSetIterator begin(TypeSet &set) noexcept {
+ usize index = 0;
+ while (index < set.capacity) {
+ TypeInfoPair key = set.keys[index];
+ if (key.hash != 0 && key.hash != TYPE_SET_TOMBSTONE) {
+ break;
+ }
+ index++;
+ }
+ return TypeSetIterator{&set, index};
+}
+gb_internal TypeSetIterator end(TypeSet &set) noexcept {
+ return TypeSetIterator{&set, set.capacity};
+}
+
+
+gb_internal void type_set_init(TypeSet *s, isize capacity) {
+ GB_ASSERT(s->keys == nullptr);
+ if (capacity != 0) {
+ capacity = next_pow2_isize(gb_max(16, capacity));
+ s->keys = gb_alloc_array(type_set_allocator(), TypeInfoPair, capacity);
+ // This memory will be zeroed, no need to explicitly zero it
+ }
+ s->count = 0;
+ s->capacity = capacity;
+}
+
+gb_internal void type_set_destroy(TypeSet *s) {
+ gb_free(type_set_allocator(), s->keys);
+ s->keys = nullptr;
+ s->count = 0;
+ s->capacity = 0;
+}
+
+
+gb_internal isize type_set__find(TypeSet *s, TypeInfoPair pair) {
+ GB_ASSERT(pair.type != nullptr);
+ GB_ASSERT(pair.hash != 0);
+ if (s->count != 0) {
+ usize hash = pair.hash;
+ usize mask = s->capacity-1;
+ usize hash_index = cast(usize)hash & mask;
+ for (usize i = 0; i < s->capacity; i++) {
+ Type *key = s->keys[hash_index].type;
+ if (are_types_identical_unique_tuples(key, pair.type)) {
+ return hash_index;
+ } else if (key == 0) {
+ return -1;
+ }
+ hash_index = (hash_index+1)&mask;
+ }
+ }
+ return -1;
+}
+gb_internal isize type_set__find(TypeSet *s, Type *ptr) {
+ GB_ASSERT(ptr != 0);
+ if (s->count != 0) {
+ usize hash = cast(usize)type_hash_canonical_type(ptr);
+ usize mask = s->capacity-1;
+ usize hash_index = cast(usize)hash & mask;
+ for (usize i = 0; i < s->capacity; i++) {
+ Type *key = s->keys[hash_index].type;
+ if (are_types_identical_unique_tuples(key, ptr)) {
+ return hash_index;
+ } else if (key == 0) {
+ return -1;
+ }
+ hash_index = (hash_index+1)&mask;
+ }
+ }
+ return -1;
+}
+
+gb_internal bool type_set__full(TypeSet *s) {
+ return 0.75f * s->capacity <= s->count;
+}
+
+gb_internal gb_inline void type_set_grow(TypeSet *old_set) {
+ if (old_set->capacity == 0) {
+ type_set_init(old_set);
+ return;
+ }
+
+ TypeSet new_set = {};
+ type_set_init(&new_set, gb_max(old_set->capacity<<1, 16));
+
+ for (TypeInfoPair const &set : *old_set) {
+ bool was_new = type_set_update(&new_set, set);
+ GB_ASSERT(!was_new);
+ }
+ GB_ASSERT(old_set->count == new_set.count);
+
+ type_set_destroy(old_set);
+
+ *old_set = new_set;
+}
+
+
+gb_internal gb_inline bool type_set_exists(TypeSet *s, Type *ptr) {
+ return type_set__find(s, ptr) >= 0;
+}
+gb_internal gb_inline bool type_set_exists(TypeSet *s, TypeInfoPair pair) {
+ return type_set__find(s, pair) >= 0;
+}
+gb_internal gb_inline TypeInfoPair *type_set_retrieve(TypeSet *s, Type *type) {
+ isize index = type_set__find(s, type);
+ if (index >= 0) {
+ return &s->keys[index];
+ }
+ return nullptr;
+}
+
+
+gb_internal bool type_set_update(TypeSet *s, TypeInfoPair pair) { // returns true if it previously existsed
+ if (type_set_exists(s, pair)) {
+ return true;
+ }
+
+ if (s->keys == nullptr) {
+ type_set_init(s);
+ } else if (type_set__full(s)) {
+ type_set_grow(s);
+ }
+ GB_ASSERT(s->count < s->capacity);
+ GB_ASSERT(s->capacity >= 0);
+
+ usize mask = s->capacity-1;
+ usize hash = cast(usize)pair.hash;
+ usize hash_index = (cast(usize)hash) & mask;
+ GB_ASSERT(hash_index < s->capacity);
+ for (usize i = 0; i < s->capacity; i++) {
+ TypeInfoPair *key = &s->keys[hash_index];
+ GB_ASSERT(!are_types_identical_unique_tuples(key->type, pair.type));
+ if (key->hash == TYPE_SET_TOMBSTONE || key->hash == 0) {
+ *key = pair;
+ s->count++;
+ return false;
+ }
+ hash_index = (hash_index+1)&mask;
+ }
+
+ GB_PANIC("ptr set out of memory");
+ return false;
+}
+
+gb_internal bool type_set_update(TypeSet *s, Type *ptr) { // returns true if it previously existsed
+ TypeInfoPair pair = {ptr, type_hash_canonical_type(ptr)};
+ return type_set_update(s, pair);
+}
+
+
+gb_internal Type *type_set_add(TypeSet *s, Type *ptr) {
+ type_set_update(s, ptr);
+ return ptr;
+}
+
+gb_internal Type *type_set_add(TypeSet *s, TypeInfoPair pair) {
+ type_set_update(s, pair);
+ return pair.type;
+}
+
+
+
+gb_internal void type_set_remove(TypeSet *s, Type *ptr) {
+ isize index = type_set__find(s, ptr);
+ if (index >= 0) {
+ GB_ASSERT(s->count > 0);
+ s->keys[index].type = nullptr;
+ s->keys[index].hash = TYPE_SET_TOMBSTONE;
+ s->count--;
+ }
+}
+
+gb_internal gb_inline void type_set_clear(TypeSet *s) {
+ s->count = 0;
+ gb_zero_size(s->keys, s->capacity*gb_size_of(*s->keys));
+}
+
+
+#define TYPE_WRITER_PROC(name) bool name(TypeWriter *w, void const *ptr, isize len)
+typedef TYPE_WRITER_PROC(TypeWriterProc);
+
+
+struct TypeWriter {
+ TypeWriterProc *proc;
+ void *user_data;
+};
+
+bool type_writer_append(TypeWriter *w, void const *ptr, isize len) {
+ return w->proc(w, ptr, len);
+}
+
+bool type_writer_appendb(TypeWriter *w, char b) {
+ return w->proc(w, &b, 1);
+}
+
+bool type_writer_appendc(TypeWriter *w, char const *str) {
+ isize len = gb_strlen(str);
+ return w->proc(w, str, len);
+}
+
+bool type_writer_append_fmt(TypeWriter *w, char const *fmt, ...) {
+ va_list va;
+ char *str;
+ va_start(va, fmt);
+ str = gb_bprintf_va(fmt, va);
+ va_end(va);
+
+ return type_writer_appendc(w, str);
+}
+
+
+
+TYPE_WRITER_PROC(type_writer_string_writer_proc) {
+ gbString *s = cast(gbString *)&w->user_data;
+ *s = gb_string_append_length(*s, ptr, len);
+ return true;
+}
+
+void type_writer_make_string(TypeWriter *w, gbAllocator allocator) {
+ w->user_data = gb_string_make(allocator, "");
+ w->proc = type_writer_string_writer_proc;
+}
+
+void type_writer_destroy_string(TypeWriter *w) {
+ gb_string_free(cast(gbString)w->user_data);
+}
+
+
+TYPE_WRITER_PROC(type_writer_hasher_writer_proc) {
+ u64 *seed = cast(u64 *)w->user_data;
+ *seed = fnv64a(ptr, len, *seed);
+ return true;
+}
+
+void type_writer_make_hasher(TypeWriter *w, u64 *hash) {
+ w->user_data = hash;
+ w->proc = type_writer_hasher_writer_proc;
+}
+
+
+
+
+gb_internal void write_canonical_params(TypeWriter *w, Type *params) {
+ type_writer_appendc(w, "(");
+ defer (type_writer_appendc(w, ")"));
+
+ if (params == nullptr) {
+ return;
+ }
+ GB_ASSERT(params->kind == Type_Tuple);
+ for_array(i, params->Tuple.variables) {
+ Entity *v = params->Tuple.variables[i];
+ if (i > 0) {
+ type_writer_appendc(w, CANONICAL_PARAM_SEPARATOR);
+ }
+ type_writer_append(w, v->token.string.text, v->token.string.len);
+ type_writer_appendc(w, CANONICAL_TYPE_SEPARATOR);
+
+ switch (v->kind) {
+ case Entity_Variable:
+ if (v->flags&EntityFlag_CVarArg) {
+ type_writer_appendc(w, CANONICAL_PARAM_C_VARARG);
+ }
+ if (v->flags&EntityFlag_Ellipsis) {
+ Type *slice = base_type(v->type);
+ type_writer_appendc(w, CANONICAL_PARAM_VARARG);
+ GB_ASSERT(v->type->kind == Type_Slice);
+ write_type_to_canonical_string(w, slice->Slice.elem);
+ } else {
+ write_type_to_canonical_string(w, v->type);
+ }
+ break;
+ case Entity_TypeName:
+ type_writer_appendc(w, CANONICAL_PARAM_TYPEID);
+ write_type_to_canonical_string(w, v->type);
+ break;
+ case Entity_Constant:
+ {
+ type_writer_appendc(w, CANONICAL_PARAM_CONST);
+ gbString s = exact_value_to_string(v->Constant.value, 1<<16);
+ type_writer_append(w, s, gb_string_length(s));
+ gb_string_free(s);
+ }
+ break;
+ default:
+ GB_PANIC("TODO(bill): handle non type/const parapoly parameter values");
+ break;
+ }
+ }
+ return;
+}
+
+gb_internal u64 type_hash_canonical_type(Type *type) {
+ if (type == nullptr) {
+ return 0;
+ }
+ u64 hash = fnv64a(nullptr, 0);
+ TypeWriter w = {};
+ type_writer_make_hasher(&w, &hash);
+ write_type_to_canonical_string(&w, type);
+
+ return hash ? hash : 1;
+}
+
+gb_internal String type_to_canonical_string(gbAllocator allocator, Type *type) {
+ TypeWriter w = {};
+ type_writer_make_string(&w, allocator);
+ write_type_to_canonical_string(&w, type);
+
+ gbString s = cast(gbString)w.user_data;
+ return make_string(cast(u8 const *)s, gb_string_length(s));
+}
+
+gb_internal gbString temp_canonical_string(Type *type) {
+ TypeWriter w = {};
+ type_writer_make_string(&w, temporary_allocator());
+ write_type_to_canonical_string(&w, type);
+
+ return cast(gbString)w.user_data;
+}
+
+gb_internal gbString string_canonical_entity_name(gbAllocator allocator, Entity *e) {
+ TypeWriter w = {};
+ type_writer_make_string(&w, allocator);
+ write_canonical_entity_name(&w, e);
+ return cast(gbString)w.user_data;
+}
+
+
+
+gb_internal void write_canonical_parent_prefix(TypeWriter *w, Entity *e) {
+ GB_ASSERT(e != nullptr);
+ if (e->kind == Entity_Procedure || e->kind == Entity_TypeName) {
+ if (e->kind == Entity_Procedure && (e->Procedure.is_export || e->Procedure.is_foreign)) {
+ // no prefix
+ return;
+ }
+ if (e->parent_proc_decl) {
+ Entity *p = e->parent_proc_decl->entity;
+ write_canonical_parent_prefix(w, p);
+ type_writer_append(w, p->token.string.text, p->token.string.len);
+ if (is_type_polymorphic(p->type)) {
+ type_writer_appendc(w, CANONICAL_TYPE_SEPARATOR);
+ write_type_to_canonical_string(w, p->type);
+ }
+ type_writer_appendc(w, CANONICAL_NAME_SEPARATOR);
+
+ } else if (e->pkg && (scope_lookup_current(e->pkg->scope, e->token.string) == e)) {
+ type_writer_append(w, e->pkg->name.text, e->pkg->name.len);
+ if (e->pkg->name == "llvm") {
+ type_writer_appendc(w, "$");
+ }
+ type_writer_appendc(w, CANONICAL_NAME_SEPARATOR);
+ } else {
+ String file_name = filename_without_directory(e->file->fullpath);
+ type_writer_append(w, e->pkg->name.text, e->pkg->name.len);
+ if (e->pkg->name == "llvm") {
+ type_writer_appendc(w, "$");
+ }
+ type_writer_append_fmt(w, CANONICAL_NAME_SEPARATOR "%.*s" CANONICAL_NAME_SEPARATOR, LIT(file_name));
+ }
+ } else {
+ GB_PANIC("TODO(bill): handle entity kind: %d", e->kind);
+ }
+ if (e->kind == Entity_Procedure && e->Procedure.is_anonymous) {
+ String file_name = filename_without_directory(e->file->fullpath);
+ type_writer_append_fmt(w, CANONICAL_ANON_PREFIX "_%.*s:%d", LIT(file_name), e->token.pos.offset);
+ } else {
+ type_writer_append(w, e->token.string.text, e->token.string.len);
+ }
+
+ if (is_type_polymorphic(e->type)) {
+ type_writer_appendc(w, CANONICAL_TYPE_SEPARATOR);
+ write_type_to_canonical_string(w, e->type);
+ }
+ type_writer_appendc(w, CANONICAL_NAME_SEPARATOR);
+
+ return;
+}
+
+gb_internal void write_canonical_entity_name(TypeWriter *w, Entity *e) {
+ GB_ASSERT(e != nullptr);
+
+ if (e->token.string == "_") {
+ GB_PANIC("_ string");
+ }
+ if (e->token.string.len == 0) {
+ GB_PANIC("empty string");
+ }
+
+ if (e->kind == Entity_Variable) {
+ bool is_foreign = e->Variable.is_foreign;
+ bool is_export = e->Variable.is_export;
+ if (e->Variable.link_name.len > 0) {
+ type_writer_append(w, e->Variable.link_name.text, e->Variable.link_name.len);
+ return;
+ } else if (is_foreign || is_export) {
+ type_writer_append(w, e->token.string.text, e->token.string.len);
+ return;
+ }
+ } else if (e->kind == Entity_Procedure && e->Procedure.link_name.len > 0) {
+ type_writer_append(w, e->Procedure.link_name.text, e->Procedure.link_name.len);
+ return;
+ } else if (e->kind == Entity_Procedure && e->Procedure.is_export) {
+ type_writer_append(w, e->token.string.text, e->token.string.len);
+ return;
+ }
+
+ bool write_scope_index_suffix = false;
+
+ if (e->scope->flags & (ScopeFlag_Builtin)) {
+ goto write_base_name;
+ } else if ((e->scope->flags & (ScopeFlag_File | ScopeFlag_Pkg)) == 0 ||
+ e->flags & EntityFlag_NotExported) {
+ Scope *s = e->scope;
+
+ while ((s->flags & (ScopeFlag_Proc|ScopeFlag_File)) == 0 && s->decl_info == nullptr) {
+ if (s->parent == nullptr) {
+ break;
+ }
+ s = s->parent;
+ }
+
+ if (s->decl_info != nullptr && s->decl_info->entity) {
+ Entity *parent = s->decl_info->entity;
+ write_canonical_parent_prefix(w, parent);
+ if (e->scope->index > 0) {
+ write_scope_index_suffix = true;
+ }
+
+ goto write_base_name;
+ } else if ((s->flags & ScopeFlag_File) && s->file != nullptr) {
+ String file_name = filename_without_directory(s->file->fullpath);
+ type_writer_append(w, e->pkg->name.text, e->pkg->name.len);
+ if (e->pkg->name == "llvm") {
+ type_writer_appendc(w, "$");
+ }
+ type_writer_appendc(w, gb_bprintf(CANONICAL_NAME_SEPARATOR "[%.*s]" CANONICAL_NAME_SEPARATOR, LIT(file_name)));
+ goto write_base_name;
+ } else if (s->flags & (ScopeFlag_Builtin)) {
+ goto write_base_name;
+ }
+ gb_printf_err("%s WEIRD ENTITY TYPE %s %u %p\n", token_pos_to_string(e->token.pos), type_to_string(e->type), s->flags, s->decl_info);
+
+ auto const print_scope_flags = [](Scope *s) {
+ if (s->flags & ScopeFlag_Pkg) gb_printf_err("Pkg ");
+ if (s->flags & ScopeFlag_Builtin) gb_printf_err("Builtin ");
+ if (s->flags & ScopeFlag_Global) gb_printf_err("Global ");
+ if (s->flags & ScopeFlag_File) gb_printf_err("File ");
+ if (s->flags & ScopeFlag_Init) gb_printf_err("Init ");
+ if (s->flags & ScopeFlag_Proc) gb_printf_err("Proc ");
+ if (s->flags & ScopeFlag_Type) gb_printf_err("Type ");
+ if (s->flags & ScopeFlag_HasBeenImported) gb_printf_err("HasBeenImported ");
+ if (s->flags & ScopeFlag_ContextDefined) gb_printf_err("ContextDefined ");
+ gb_printf_err("\n");
+ };
+
+ print_scope_flags(s);
+ GB_PANIC("weird entity %.*s", LIT(e->token.string));
+ }
+ if (e->pkg != nullptr) {
+ type_writer_append(w, e->pkg->name.text, e->pkg->name.len);
+ type_writer_appendc(w, CANONICAL_NAME_SEPARATOR);
+ }
+
+write_base_name:
+
+ switch (e->kind) {
+ case Entity_TypeName:
+ {
+
+ Type *params = nullptr;
+ Entity *parent = type_get_polymorphic_parent(e->type, &params);
+ if (parent && (parent->token.string == e->token.string)) {
+ type_writer_append(w, parent->token.string.text, parent->token.string.len);
+ write_canonical_params(w, params);
+ } else {
+ type_writer_append(w, e->token.string.text, e->token.string.len);
+ }
+ }
+ break;
+
+ case Entity_Constant:
+ // For debug symbols only
+ /*fallthrough*/
+ case Entity_Procedure:
+ case Entity_Variable:
+ type_writer_append(w, e->token.string.text, e->token.string.len);
+ if (is_type_polymorphic(e->type)) {
+ type_writer_appendc(w, CANONICAL_TYPE_SEPARATOR);
+ write_type_to_canonical_string(w, e->type);
+ }
+ break;
+
+ default:
+ GB_PANIC("TODO(bill): entity kind %d", e->kind);
+ break;
+ }
+
+ if (write_scope_index_suffix) {
+ GB_ASSERT(e != nullptr && e->scope != nullptr);
+ type_writer_append_fmt(w, CANONICAL_NAME_SEPARATOR "$%d", e->scope->index);
+ }
+
+ return;
+}
+
+gb_internal bool is_in_doc_writer(void);
+
+// NOTE(bill): This exists so that we deterministically hash a type by serializing it to a canonical string
+gb_internal void write_type_to_canonical_string(TypeWriter *w, Type *type) {
+ if (type == nullptr) {
+ type_writer_appendc(w, CANONICAL_NONE_TYPE); // none/void type
+ return;
+ }
+
+ type = default_type(type);
+ GB_ASSERT(!is_type_untyped(type));
+
+ switch (type->kind) {
+ case Type_Basic:
+ type_writer_append(w, type->Basic.name.text, type->Basic.name.len);
+ return;
+ case Type_Pointer:
+ type_writer_appendb(w, '^');
+ write_type_to_canonical_string(w, type->Pointer.elem);
+ return;
+ case Type_MultiPointer:
+ type_writer_appendc(w, "[^]");
+ write_type_to_canonical_string(w, type->Pointer.elem);
+ return;
+ case Type_SoaPointer:
+ type_writer_appendc(w, "#soa^");
+ write_type_to_canonical_string(w, type->Pointer.elem);
+ return;
+ case Type_EnumeratedArray:
+ if (type->EnumeratedArray.is_sparse) {
+ type_writer_appendc(w, "#sparse");
+ }
+ type_writer_appendb(w, '[');
+ write_type_to_canonical_string(w, type->EnumeratedArray.index);
+ type_writer_appendb(w, ']');
+ write_type_to_canonical_string(w, type->EnumeratedArray.elem);
+ return;
+ case Type_Array:
+ type_writer_append_fmt(w, "[%lld]", cast(long long)type->Array.count);
+ write_type_to_canonical_string(w, type->Array.elem);
+ return;
+ case Type_Slice:
+ type_writer_appendc(w, "[]");
+ write_type_to_canonical_string(w, type->Array.elem);
+ return;
+ case Type_DynamicArray:
+ type_writer_appendc(w, "[dynamic]");
+ write_type_to_canonical_string(w, type->DynamicArray.elem);
+ return;
+ case Type_SimdVector:
+ type_writer_append_fmt(w, "#simd[%lld]", cast(long long)type->SimdVector.count);
+ write_type_to_canonical_string(w, type->SimdVector.elem);
+ return;
+ case Type_Matrix:
+ if (type->Matrix.is_row_major) {
+ type_writer_appendc(w, "#row_major ");
+ }
+ type_writer_append_fmt(w, "matrix[%lld, %lld]", cast(long long)type->Matrix.row_count, cast(long long)type->Matrix.column_count);
+ write_type_to_canonical_string(w, type->Matrix.elem);
+ return;
+ case Type_Map:
+ type_writer_appendc(w, "map[");
+ write_type_to_canonical_string(w, type->Map.key);
+ type_writer_appendc(w, "]");
+ write_type_to_canonical_string(w, type->Map.value);
+ return;
+
+ case Type_Enum:
+ type_writer_appendc(w, "enum");
+ if (type->Enum.base_type != nullptr) {
+ type_writer_appendb(w, ' ');
+ write_type_to_canonical_string(w, type->Enum.base_type);
+ type_writer_appendb(w, ' ');
+ }
+ type_writer_appendb(w, '{');
+ for_array(i, type->Enum.fields) {
+ Entity *f = type->Enum.fields[i];
+ GB_ASSERT(f->kind == Entity_Constant);
+ if (i > 0) {
+ type_writer_appendc(w, CANONICAL_FIELD_SEPARATOR);
+ }
+ type_writer_append(w, f->token.string.text, f->token.string.len);
+ type_writer_appendc(w, "=");
+
+ gbString s = exact_value_to_string(f->Constant.value, 1<<16);
+ type_writer_append(w, s, gb_string_length(s));
+ gb_string_free(s);
+ }
+ type_writer_appendb(w, '}');
+ return;
+ case Type_BitSet:
+ type_writer_appendc(w, "bit_set[");
+ if (type->BitSet.elem == nullptr) {
+ type_writer_appendc(w, CANONICAL_NONE_TYPE);
+ } else if (is_type_enum(type->BitSet.elem)) {
+ write_type_to_canonical_string(w, type->BitSet.elem);
+ } else {
+ type_writer_append_fmt(w, "%lld", type->BitSet.lower);
+ type_writer_append_fmt(w, CANONICAL_RANGE_OPERATOR);
+ type_writer_append_fmt(w, "%lld", type->BitSet.upper);
+ }
+ if (type->BitSet.underlying != nullptr) {
+ type_writer_appendc(w, ";");
+ write_type_to_canonical_string(w, type->BitSet.underlying);
+ }
+ type_writer_appendc(w, "]");
+ return;
+
+ case Type_Union:
+ type_writer_appendc(w, "union");
+
+ switch (type->Union.kind) {
+ case UnionType_no_nil: type_writer_appendc(w, "#no_nil"); break;
+ case UnionType_shared_nil: type_writer_appendc(w, "#shared_nil"); break;
+ }
+ if (type->Union.custom_align != 0) {
+ type_writer_append_fmt(w, "#align(%lld)", cast(long long)type->Union.custom_align);
+ }
+ type_writer_appendc(w, "{");
+ for_array(i, type->Union.variants) {
+ Type *t = type->Union.variants[i];
+ if (i > 0) type_writer_appendc(w, CANONICAL_FIELD_SEPARATOR);
+ write_type_to_canonical_string(w, t);
+ }
+ type_writer_appendc(w, "}");
+ return;
+ case Type_Struct:
+ if (type->Struct.soa_kind != StructSoa_None) {
+ switch (type->Struct.soa_kind) {
+ case StructSoa_Fixed: type_writer_append_fmt(w, "#soa[%lld]", cast(long long)type->Struct.soa_count); break;
+ case StructSoa_Slice: type_writer_appendc(w, "#soa[]"); break;
+ case StructSoa_Dynamic: type_writer_appendc(w, "#soa[dynamic]"); break;
+ default: GB_PANIC("Unknown StructSoaKind"); break;
+ }
+ return write_type_to_canonical_string(w, type->Struct.soa_elem);
+ }
+
+ type_writer_appendc(w, "struct");
+ if (type->Struct.is_packed) type_writer_appendc(w, "#packed");
+ if (type->Struct.is_raw_union) type_writer_appendc(w, "#raw_union");
+ if (type->Struct.is_no_copy) type_writer_appendc(w, "#no_copy");
+ if (type->Struct.custom_min_field_align != 0) type_writer_append_fmt(w, "#min_field_align(%lld)", cast(long long)type->Struct.custom_min_field_align);
+ if (type->Struct.custom_max_field_align != 0) type_writer_append_fmt(w, "#max_field_align(%lld)", cast(long long)type->Struct.custom_max_field_align);
+ if (type->Struct.custom_align != 0) type_writer_append_fmt(w, "#align(%lld)", cast(long long)type->Struct.custom_align);
+ type_writer_appendb(w, '{');
+ for_array(i, type->Struct.fields) {
+ Entity *f = type->Struct.fields[i];
+ GB_ASSERT(f->kind == Entity_Variable);
+ if (i > 0) {
+ type_writer_appendc(w, CANONICAL_FIELD_SEPARATOR);
+ }
+ type_writer_append(w, f->token.string.text, f->token.string.len);
+ type_writer_appendc(w, CANONICAL_TYPE_SEPARATOR);
+ write_type_to_canonical_string(w, f->type);
+ String tag = {};
+ if (type->Struct.tags != nullptr) {
+ tag = type->Struct.tags[i];
+ }
+ if (tag.len != 0) {
+ String s = quote_to_ascii(heap_allocator(), tag);
+ type_writer_append(w, s.text, s.len);
+ gb_free(heap_allocator(), s.text);
+ }
+ }
+ type_writer_appendb(w, '}');
+ return;
+
+ case Type_BitField:
+ type_writer_appendc(w, "bit_field");
+ write_type_to_canonical_string(w, type->BitField.backing_type);
+ type_writer_appendc(w, " {");
+ for (isize i = 0; i < type->BitField.fields.count; i++) {
+ Entity *f = type->BitField.fields[i];
+ if (i > 0) {
+ type_writer_appendc(w, CANONICAL_FIELD_SEPARATOR);
+ }
+ type_writer_append(w, f->token.string.text, f->token.string.len);
+ type_writer_appendc(w, CANONICAL_TYPE_SEPARATOR);
+ write_type_to_canonical_string(w, f->type);
+ type_writer_appendc(w, CANONICAL_BIT_FIELD_SEPARATOR);
+ type_writer_append_fmt(w, "%u", type->BitField.bit_sizes[i]);
+ }
+ type_writer_appendc(w, " }");
+ return;
+
+ case Type_Proc:
+ type_writer_appendc(w, "proc");
+ if (default_calling_convention() != type->Proc.calling_convention) {
+ type_writer_appendc(w, "\"");
+ type_writer_appendc(w, proc_calling_convention_strings[type->Proc.calling_convention]);
+ type_writer_appendc(w, "\"");
+ }
+
+ write_canonical_params(w, type->Proc.params);
+ if (type->Proc.result_count > 0) {
+ type_writer_appendc(w, "->");
+ write_canonical_params(w, type->Proc.results);
+ }
+ return;
+
+ case Type_Generic:
+ if (is_in_doc_writer()) {
+ type_writer_appendc(w, "$");
+ type_writer_append(w, type->Generic.name.text, type->Generic.name.len);
+ type_writer_append_fmt(w, "%lld", cast(long long)type->Generic.id);
+ } else {
+ GB_PANIC("Type_Generic should never be hit");
+ }
+ return;
+
+ case Type_Named:
+ if (type->Named.type_name != nullptr) {
+ write_canonical_entity_name(w, type->Named.type_name);
+ return;
+ } else {
+ type_writer_append(w, type->Named.name.text, type->Named.name.len);
+ }
+ return;
+
+ case Type_Tuple:
+ type_writer_appendc(w, "params");
+ write_canonical_params(w, type);
+ return;
+ default:
+ GB_PANIC("unknown type kind %d %.*s", type->kind, LIT(type_strings[type->kind]));
+ break;
+ }
+
+ return;
+} \ No newline at end of file
diff --git a/src/name_canonicalization.hpp b/src/name_canonicalization.hpp
new file mode 100644
index 000000000..304aff42e
--- /dev/null
+++ b/src/name_canonicalization.hpp
@@ -0,0 +1,128 @@
+/*
+ General Rules for canonical name mangling
+
+ * No spaces between any values
+
+ * normal declarations - pkg::name
+ * builtin names - just their normal name e.g. `i32` or `string`
+ * nested (zero level) - pkg::parent1::parent2::name
+ * nested (more scopes) - pkg::parent1::parent2::name[4]
+ * [4] indicates the 4th scope within a procedure numbered in depth-first order
+ * file private - pkg::[file_name]::name
+ * Example: `pkg::[file.odin]::Type`
+ * polymorphic procedure/type - pkg::foo:TYPE
+ * naming convention for parameters
+ * type
+ * $typeid_based_name
+ * $$constant_parameter
+ * Example: `foo::to_thing:proc(u64)->([]u8)`
+ * nested decl in polymorphic procedure - pkg::foo:TYPE::name
+ * anonymous procedures - pkg::foo::$anon[file.odin:123]
+ * 123 is the file offset in bytes
+*/
+
+#define CANONICAL_TYPE_SEPARATOR ":"
+#define CANONICAL_NAME_SEPARATOR "::"
+// #define CANONICAL_NAME_SEPARATOR "·"
+
+#define CANONICAL_BIT_FIELD_SEPARATOR "|"
+
+#define CANONICAL_PARAM_SEPARATOR ","
+
+#define CANONICAL_PARAM_TYPEID "$"
+#define CANONICAL_PARAM_CONST "$$"
+
+#define CANONICAL_PARAM_C_VARARG "#c_vararg"
+#define CANONICAL_PARAM_VARARG ".."
+
+#define CANONICAL_FIELD_SEPARATOR ","
+
+#define CANONICAL_ANON_PREFIX "$anon"
+
+#define CANONICAL_NONE_TYPE "<>"
+
+#define CANONICAL_RANGE_OPERATOR "..="
+
+struct TypeWriter;
+
+gb_internal void write_type_to_canonical_string(TypeWriter *w, Type *type);
+gb_internal void write_canonical_entity_name(TypeWriter *w, Entity *e);
+gb_internal u64 type_hash_canonical_type(Type *type);
+gb_internal String type_to_canonical_string(gbAllocator allocator, Type *type);
+gb_internal gbString temp_canonical_string(Type *type);
+
+
+gb_internal GB_COMPARE_PROC(type_info_pair_cmp);
+
+
+struct TypeInfoPair {
+ Type *type;
+ u64 hash; // see: type_hash_canonical_type
+};
+
+struct TypeSet {
+ TypeInfoPair *keys;
+ usize count;
+ usize capacity;
+};
+
+static constexpr u64 TYPE_SET_TOMBSTONE = ~(u64)(0ull);
+
+struct TypeSetIterator {
+ TypeSet *set;
+ usize index;
+
+ TypeSetIterator &operator++() noexcept {
+ for (;;) {
+ ++index;
+ if (set->capacity == index) {
+ return *this;
+ }
+ TypeInfoPair key = set->keys[index];
+ if (key.hash != 0 && key.hash != TYPE_SET_TOMBSTONE) {
+ return *this;
+ }
+ }
+ }
+
+ bool operator==(TypeSetIterator const &other) const noexcept {
+ return this->set == other.set && this->index == other.index;
+ }
+
+
+ operator TypeInfoPair *() const {
+ return &set->keys[index];
+ }
+};
+
+
+gb_internal void type_set_init (TypeSet *s, isize capacity = 16);
+gb_internal void type_set_destroy(TypeSet *s);
+gb_internal Type *type_set_add (TypeSet *s, Type *ptr);
+gb_internal Type *type_set_add (TypeSet *s, TypeInfoPair pair);
+gb_internal bool type_set_update (TypeSet *s, Type *ptr); // returns true if it previously existed
+gb_internal bool type_set_update (TypeSet *s, TypeInfoPair pair); // returns true if it previously existed
+gb_internal bool type_set_exists (TypeSet *s, Type *ptr);
+gb_internal void type_set_remove (TypeSet *s, Type *ptr);
+gb_internal void type_set_clear (TypeSet *s);
+gb_internal TypeInfoPair *type_set_retrieve(TypeSet *s, Type *ptr);
+
+gb_internal TypeSetIterator begin(TypeSet &set) noexcept;
+gb_internal TypeSetIterator end(TypeSet &set) noexcept;
+
+
+template <typename V>
+gb_internal gb_inline V *map_get(PtrMap<u64, V> *h, Type *key) {
+ return map_get(h, type_hash_canonical_type(key));
+}
+template <typename V>
+gb_internal gb_inline void map_set(PtrMap<u64, V> *h, Type *key, V const &value) {
+ map_set(h, type_hash_canonical_type(key), value);
+}
+
+template <typename V>
+gb_internal gb_inline V &map_must_get(PtrMap<u64, V> *h, Type *key) {
+ V *ptr = map_get(h, type_hash_canonical_type(key));
+ GB_ASSERT(ptr != nullptr);
+ return *ptr;
+} \ No newline at end of file
diff --git a/src/parser.cpp b/src/parser.cpp
index aa90651d3..f38f79607 100644
--- a/src/parser.cpp
+++ b/src/parser.cpp
@@ -348,10 +348,11 @@ gb_internal Ast *clone_ast(Ast *node, AstFile *f) {
n->RangeStmt.body = clone_ast(n->RangeStmt.body, f);
break;
case Ast_UnrollRangeStmt:
- n->UnrollRangeStmt.val0 = clone_ast(n->UnrollRangeStmt.val0, f);
- n->UnrollRangeStmt.val1 = clone_ast(n->UnrollRangeStmt.val1, f);
- n->UnrollRangeStmt.expr = clone_ast(n->UnrollRangeStmt.expr, f);
- n->UnrollRangeStmt.body = clone_ast(n->UnrollRangeStmt.body, f);
+ n->UnrollRangeStmt.args = clone_ast_array(n->UnrollRangeStmt.args, f);
+ n->UnrollRangeStmt.val0 = clone_ast(n->UnrollRangeStmt.val0, f);
+ n->UnrollRangeStmt.val1 = clone_ast(n->UnrollRangeStmt.val1, f);
+ n->UnrollRangeStmt.expr = clone_ast(n->UnrollRangeStmt.expr, f);
+ n->UnrollRangeStmt.body = clone_ast(n->UnrollRangeStmt.body, f);
break;
case Ast_CaseClause:
n->CaseClause.list = clone_ast_array(n->CaseClause.list, f);
@@ -1037,15 +1038,16 @@ gb_internal Ast *ast_range_stmt(AstFile *f, Token token, Slice<Ast *> vals, Toke
return result;
}
-gb_internal Ast *ast_unroll_range_stmt(AstFile *f, Token unroll_token, Token for_token, Ast *val0, Ast *val1, Token in_token, Ast *expr, Ast *body) {
+gb_internal Ast *ast_unroll_range_stmt(AstFile *f, Token unroll_token, Slice<Ast *> args, Token for_token, Ast *val0, Ast *val1, Token in_token, Ast *expr, Ast *body) {
Ast *result = alloc_ast_node(f, Ast_UnrollRangeStmt);
result->UnrollRangeStmt.unroll_token = unroll_token;
+ result->UnrollRangeStmt.args = args;
result->UnrollRangeStmt.for_token = for_token;
- result->UnrollRangeStmt.val0 = val0;
- result->UnrollRangeStmt.val1 = val1;
- result->UnrollRangeStmt.in_token = in_token;
- result->UnrollRangeStmt.expr = expr;
- result->UnrollRangeStmt.body = body;
+ result->UnrollRangeStmt.val0 = val0;
+ result->UnrollRangeStmt.val1 = val1;
+ result->UnrollRangeStmt.in_token = in_token;
+ result->UnrollRangeStmt.expr = expr;
+ result->UnrollRangeStmt.body = body;
return result;
}
@@ -3014,9 +3016,10 @@ gb_internal Ast *parse_operand(AstFile *f, bool lhs) {
syntax_error(token, "Expected a type or range, got nothing");
}
- if (allow_token(f, Token_Semicolon)) {
+ if (f->curr_token.kind == Token_Semicolon && f->curr_token.string == ";") {
+ expect_token(f, Token_Semicolon);
underlying = parse_type(f);
- } else if (allow_token(f, Token_Comma)) {
+ } else if (allow_token(f, Token_Comma) || allow_token(f, Token_Semicolon)) {
String p = token_to_string(f->prev_token);
syntax_error(token_end_of_line(f, f->prev_token), "Expected a semicolon, got a %.*s", LIT(p));
@@ -4340,30 +4343,132 @@ gb_internal Ast *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_fl
}
- if (f->curr_token.kind == Token_Colon) {
- Array<Ast *> names = convert_to_ident_list(f, list, true, allow_poly_names); // Copy for semantic reasons
+ if (f->curr_token.kind != Token_Colon) {
+ // NOTE(bill): proc(Type, Type, Type)
+ for (AstAndFlags const &item : list) {
+ Ast *type = item.node;
+ Token token = blank_token;
+ if (allowed_flags&FieldFlag_Results) {
+ // NOTE(bill): Make this nothing and not `_`
+ token.string = str_lit("");
+ }
+
+ auto names = array_make<Ast *>(ast_allocator(f), 1);
+ token.pos = ast_token(type).pos;
+ names[0] = ast_ident(f, token);
+ u32 flags = check_field_prefixes(f, list.count, allowed_flags, item.flags);
+ Token tag = {};
+ Ast *param = ast_field(f, names, item.node, nullptr, flags, tag, docs, f->line_comment);
+ array_add(&params, param);
+ }
+
+ if (name_count_) *name_count_ = total_name_count;
+ return ast_field_list(f, start_token, params);
+ }
+
+ // NOTE(bill): proc(ident, ident, ident: Type)
+
+ if (f->prev_token.kind == Token_Comma) {
+ syntax_error(f->prev_token, "Trailing comma before a colon is not allowed");
+ }
+ Array<Ast *> names = convert_to_ident_list(f, list, true, allow_poly_names); // Copy for semantic reasons
+ if (names.count == 0) {
+ syntax_error(f->curr_token, "Empty field declaration");
+ }
+ bool any_polymorphic_names = check_procedure_name_list(names);
+ u32 set_flags = 0;
+ if (list.count > 0) {
+ set_flags = list[0].flags;
+ }
+ set_flags = check_field_prefixes(f, names.count, allowed_flags, set_flags);
+ total_name_count += names.count;
+
+ Ast *type = nullptr;
+ Ast *default_value = nullptr;
+ Token tag = {};
+
+ expect_token_after(f, Token_Colon, "field list");
+ if (f->curr_token.kind != Token_Eq) {
+ type = parse_var_type(f, allow_ellipsis, allow_typeid_token);
+ Ast *tt = unparen_expr(type);
+ if (tt == nullptr) {
+ syntax_error(f->prev_token, "Invalid type expression in field list");
+ } else if (is_signature && !any_polymorphic_names && tt->kind == Ast_TypeidType && tt->TypeidType.specialization != nullptr) {
+ syntax_error(type, "Specialization of typeid is not allowed without polymorphic names");
+ }
+ }
+
+ if (allow_token(f, Token_Eq)) {
+ default_value = parse_expr(f, false);
+ if (!allow_default_parameters) {
+ syntax_error(f->curr_token, "Default parameters are only allowed for procedures");
+ default_value = nullptr;
+ }
+ }
+
+ if (default_value != nullptr && names.count > 1) {
+ syntax_error(f->curr_token, "Default parameters can only be applied to single values");
+ }
+
+ if (allowed_flags == FieldFlag_Struct && default_value != nullptr) {
+ syntax_error(default_value, "Default parameters are not allowed for structs");
+ default_value = nullptr;
+ }
+
+ if (type != nullptr && type->kind == Ast_Ellipsis) {
+ if (seen_ellipsis) syntax_error(type, "Extra variadic parameter after ellipsis");
+ seen_ellipsis = true;
+ if (names.count != 1) {
+ syntax_error(type, "Variadic parameters can only have one field name");
+ }
+ } else if (seen_ellipsis && default_value == nullptr) {
+ syntax_error(f->curr_token, "Extra parameter after ellipsis without a default value");
+ }
+
+ if (type != nullptr && default_value == nullptr) {
+ if (f->curr_token.kind == Token_String) {
+ tag = expect_token(f, Token_String);
+ if ((allowed_flags & FieldFlag_Tags) == 0) {
+ syntax_error(tag, "Field tags are only allowed within structures");
+ }
+ }
+ }
+
+ bool more_fields = allow_field_separator(f);
+ Ast *param = ast_field(f, names, type, default_value, set_flags, tag, docs, f->line_comment);
+ array_add(&params, param);
+
+ if (!more_fields) {
+ if (name_count_) *name_count_ = total_name_count;
+ return ast_field_list(f, start_token, params);
+ }
+
+ while (f->curr_token.kind != follow &&
+ f->curr_token.kind != Token_EOF &&
+ f->curr_token.kind != Token_Semicolon) {
+ CommentGroup *docs = f->lead_comment;
+
+ if (!is_signature) parse_enforce_tabs(f);
+ u32 set_flags = parse_field_prefixes(f);
+ Token tag = {};
+ Array<Ast *> names = parse_ident_list(f, allow_poly_names);
if (names.count == 0) {
syntax_error(f->curr_token, "Empty field declaration");
+ break;
}
bool any_polymorphic_names = check_procedure_name_list(names);
- u32 set_flags = 0;
- if (list.count > 0) {
- set_flags = list[0].flags;
- }
set_flags = check_field_prefixes(f, names.count, allowed_flags, set_flags);
total_name_count += names.count;
Ast *type = nullptr;
Ast *default_value = nullptr;
- Token tag = {};
-
expect_token_after(f, Token_Colon, "field list");
if (f->curr_token.kind != Token_Eq) {
type = parse_var_type(f, allow_ellipsis, allow_typeid_token);
Ast *tt = unparen_expr(type);
- if (tt == nullptr) {
- syntax_error(f->prev_token, "Invalid type expression in field list");
- } else if (is_signature && !any_polymorphic_names && tt->kind == Ast_TypeidType && tt->TypeidType.specialization != nullptr) {
+ if (is_signature && !any_polymorphic_names &&
+ tt != nullptr &&
+ tt->kind == Ast_TypeidType && tt->TypeidType.specialization != nullptr) {
syntax_error(type, "Specialization of typeid is not allowed without polymorphic names");
}
}
@@ -4380,11 +4485,6 @@ gb_internal Ast *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_fl
syntax_error(f->curr_token, "Default parameters can only be applied to single values");
}
- if (allowed_flags == FieldFlag_Struct && default_value != nullptr) {
- syntax_error(default_value, "Default parameters are not allowed for structs");
- default_value = nullptr;
- }
-
if (type != nullptr && type->kind == Ast_Ellipsis) {
if (seen_ellipsis) syntax_error(type, "Extra variadic parameter after ellipsis");
seen_ellipsis = true;
@@ -4404,105 +4504,14 @@ gb_internal Ast *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_fl
}
}
- bool more_fields = allow_field_separator(f);
+
+ bool ok = allow_field_separator(f);
Ast *param = ast_field(f, names, type, default_value, set_flags, tag, docs, f->line_comment);
array_add(&params, param);
- if (!more_fields) {
- if (name_count_) *name_count_ = total_name_count;
- return ast_field_list(f, start_token, params);
- }
-
- while (f->curr_token.kind != follow &&
- f->curr_token.kind != Token_EOF &&
- f->curr_token.kind != Token_Semicolon) {
- CommentGroup *docs = f->lead_comment;
-
- if (!is_signature) parse_enforce_tabs(f);
- u32 set_flags = parse_field_prefixes(f);
- Token tag = {};
- Array<Ast *> names = parse_ident_list(f, allow_poly_names);
- if (names.count == 0) {
- syntax_error(f->curr_token, "Empty field declaration");
- break;
- }
- bool any_polymorphic_names = check_procedure_name_list(names);
- set_flags = check_field_prefixes(f, names.count, allowed_flags, set_flags);
- total_name_count += names.count;
-
- Ast *type = nullptr;
- Ast *default_value = nullptr;
- expect_token_after(f, Token_Colon, "field list");
- if (f->curr_token.kind != Token_Eq) {
- type = parse_var_type(f, allow_ellipsis, allow_typeid_token);
- Ast *tt = unparen_expr(type);
- if (is_signature && !any_polymorphic_names &&
- tt != nullptr &&
- tt->kind == Ast_TypeidType && tt->TypeidType.specialization != nullptr) {
- syntax_error(type, "Specialization of typeid is not allowed without polymorphic names");
- }
- }
-
- if (allow_token(f, Token_Eq)) {
- default_value = parse_expr(f, false);
- if (!allow_default_parameters) {
- syntax_error(f->curr_token, "Default parameters are only allowed for procedures");
- default_value = nullptr;
- }
- }
-
- if (default_value != nullptr && names.count > 1) {
- syntax_error(f->curr_token, "Default parameters can only be applied to single values");
- }
-
- if (type != nullptr && type->kind == Ast_Ellipsis) {
- if (seen_ellipsis) syntax_error(type, "Extra variadic parameter after ellipsis");
- seen_ellipsis = true;
- if (names.count != 1) {
- syntax_error(type, "Variadic parameters can only have one field name");
- }
- } else if (seen_ellipsis && default_value == nullptr) {
- syntax_error(f->curr_token, "Extra parameter after ellipsis without a default value");
- }
-
- if (type != nullptr && default_value == nullptr) {
- if (f->curr_token.kind == Token_String) {
- tag = expect_token(f, Token_String);
- if ((allowed_flags & FieldFlag_Tags) == 0) {
- syntax_error(tag, "Field tags are only allowed within structures");
- }
- }
- }
-
-
- bool ok = allow_field_separator(f);
- Ast *param = ast_field(f, names, type, default_value, set_flags, tag, docs, f->line_comment);
- array_add(&params, param);
-
- if (!ok) {
- break;
- }
- }
-
- if (name_count_) *name_count_ = total_name_count;
- return ast_field_list(f, start_token, params);
- }
-
- for (AstAndFlags const &item : list) {
- Ast *type = item.node;
- Token token = blank_token;
- if (allowed_flags&FieldFlag_Results) {
- // NOTE(bill): Make this nothing and not `_`
- token.string = str_lit("");
+ if (!ok) {
+ break;
}
-
- auto names = array_make<Ast *>(ast_allocator(f), 1);
- token.pos = ast_token(type).pos;
- names[0] = ast_ident(f, token);
- u32 flags = check_field_prefixes(f, list.count, allowed_flags, item.flags);
- Token tag = {};
- Ast *param = ast_field(f, names, item.node, nullptr, flags, tag, docs, f->line_comment);
- array_add(&params, param);
}
if (name_count_) *name_count_ = total_name_count;
@@ -4570,6 +4579,9 @@ gb_internal Ast *parse_do_body(AstFile *f, Token const &token, char const *msg)
gb_internal bool parse_control_statement_semicolon_separator(AstFile *f) {
Token tok = peek_token(f);
if (tok.kind != Token_OpenBrace) {
+ if (f->curr_token.kind == Token_Semicolon && f->curr_token.string != ";") {
+ syntax_error(token_end_of_line(f, f->prev_token), "Expected ';', got newline");
+ }
return allow_token(f, Token_Semicolon);
}
if (f->curr_token.string == ";") {
@@ -5137,6 +5149,40 @@ gb_internal Ast *parse_attribute(AstFile *f, Token token, TokenKind open_kind, T
gb_internal Ast *parse_unrolled_for_loop(AstFile *f, Token unroll_token) {
+ Array<Ast *> args = {};
+
+ if (allow_token(f, Token_OpenParen)) {
+ f->expr_level++;
+ if (f->curr_token.kind == Token_CloseParen) {
+ syntax_error(f->curr_token, "#unroll expected at least 1 argument, got 0");
+ } else {
+ args = array_make<Ast *>(ast_allocator(f));
+ while (f->curr_token.kind != Token_CloseParen &&
+ f->curr_token.kind != Token_EOF) {
+ Ast *arg = nullptr;
+ arg = parse_value(f);
+
+ if (f->curr_token.kind == Token_Eq) {
+ Token eq = expect_token(f, Token_Eq);
+ if (arg != nullptr && arg->kind != Ast_Ident) {
+ syntax_error(arg, "Expected an identifier for 'key=value'");
+ }
+ Ast *value = parse_value(f);
+ arg = ast_field_value(f, arg, value, eq);
+ }
+
+ array_add(&args, arg);
+
+ if (!allow_field_separator(f)) {
+ break;
+ }
+ }
+ }
+ f->expr_level--;
+ Token close = expect_closing(f, Token_CloseParen, str_lit("#unroll"));
+ gb_unused(close);
+ }
+
Token for_token = expect_token(f, Token_for);
Ast *val0 = nullptr;
Ast *val1 = nullptr;
@@ -5180,7 +5226,7 @@ gb_internal Ast *parse_unrolled_for_loop(AstFile *f, Token unroll_token) {
if (bad_stmt) {
return ast_bad_stmt(f, unroll_token, f->curr_token);
}
- return ast_unroll_range_stmt(f, unroll_token, for_token, val0, val1, in_token, expr, body);
+ return ast_unroll_range_stmt(f, unroll_token, slice_from_array(args), for_token, val0, val1, in_token, expr, body);
}
gb_internal Ast *parse_stmt(AstFile *f) {
@@ -6265,10 +6311,16 @@ gb_internal u64 parse_vet_tag(Token token_for_pos, String s) {
syntax_error(token_for_pos, "Invalid vet flag name: %.*s", LIT(p));
error_line("\tExpected one of the following\n");
error_line("\tunused\n");
+ error_line("\tunused-variables\n");
+ error_line("\tunused-imports\n");
+ error_line("\tunused-procedures\n");
error_line("\tshadowing\n");
error_line("\tusing-stmt\n");
error_line("\tusing-param\n");
+ error_line("\tstyle\n");
error_line("\textra\n");
+ error_line("\tcast\n");
+ error_line("\ttabs\n");
return build_context.vet_flags;
}
}
@@ -6286,6 +6338,63 @@ gb_internal u64 parse_vet_tag(Token token_for_pos, String s) {
return vet_flags &~ vet_not_flags;
}
+gb_internal u64 parse_feature_tag(Token token_for_pos, String s) {
+ String const prefix = str_lit("feature");
+ GB_ASSERT(string_starts_with(s, prefix));
+ s = string_trim_whitespace(substring(s, prefix.len, s.len));
+
+ if (s.len == 0) {
+ return OptInFeatureFlag_NONE;
+ }
+
+ u64 feature_flags = 0;
+ u64 feature_not_flags = 0;
+
+ while (s.len > 0) {
+ String p = string_trim_whitespace(vet_tag_get_token(s, &s));
+ if (p.len == 0) {
+ break;
+ }
+
+ bool is_notted = false;
+ if (p[0] == '!') {
+ is_notted = true;
+ p = substring(p, 1, p.len);
+ if (p.len == 0) {
+ syntax_error(token_for_pos, "Expected a feature flag name after '!'");
+ return OptInFeatureFlag_NONE;
+ }
+ }
+
+ u64 flag = get_feature_flag_from_name(p);
+ if (flag != OptInFeatureFlag_NONE) {
+ if (is_notted) {
+ feature_not_flags |= flag;
+ } else {
+ feature_flags |= flag;
+ }
+ } else {
+ ERROR_BLOCK();
+ syntax_error(token_for_pos, "Invalid feature flag name: %.*s", LIT(p));
+ error_line("\tExpected one of the following\n");
+ error_line("\tdynamic-literals\n");
+ return OptInFeatureFlag_NONE;
+ }
+ }
+
+ if (feature_flags == 0 && feature_not_flags == 0) {
+ return OptInFeatureFlag_NONE;
+ }
+ if (feature_flags == 0 && feature_not_flags != 0) {
+ return OptInFeatureFlag_NONE &~ feature_not_flags;
+ }
+ if (feature_flags != 0 && feature_not_flags == 0) {
+ return feature_flags;
+ }
+ GB_ASSERT(feature_flags != 0 && feature_not_flags != 0);
+ return feature_flags &~ feature_not_flags;
+}
+
gb_internal String dir_from_path(String path) {
String base_dir = path;
for (isize i = path.len-1; i >= 0; i--) {
@@ -6399,6 +6508,9 @@ gb_internal bool parse_file_tag(const String &lc, const Token &tok, AstFile *f)
} else if (command == "file") {
f->flags |= AstFile_IsPrivateFile;
}
+ } else if (string_starts_with(lc, str_lit("feature"))) {
+ f->feature_flags |= parse_feature_tag(tok, lc);
+ f->feature_flags_set = true;
} else if (lc == "lazy") {
if (build_context.ignore_lazy) {
// Ignore
@@ -6493,9 +6605,7 @@ gb_internal bool parse_file(Parser *p, AstFile *f) {
}
f->package_name = package_name.string;
- // TODO: Shouldn't single file only matter for build tags? no-instrumentation for example
- // should be respected even when in single file mode.
- if (!f->pkg->is_single_file) {
+ {
if (docs != nullptr && docs->list.count > 0) {
for (Token const &tok : docs->list) {
GB_ASSERT(tok.kind == Token_Comment);
diff --git a/src/parser.hpp b/src/parser.hpp
index e332fed50..d2dd22667 100644
--- a/src/parser.hpp
+++ b/src/parser.hpp
@@ -108,7 +108,9 @@ struct AstFile {
String package_name;
u64 vet_flags;
+ u64 feature_flags;
bool vet_flags_set;
+ bool feature_flags_set;
// >= 0: In Expression
// < 0: In Control Clause
@@ -561,6 +563,7 @@ AST_KIND(_ComplexStmtBegin, "", bool) \
AST_KIND(UnrollRangeStmt, "#unroll range statement", struct { \
Scope *scope; \
Token unroll_token; \
+ Slice<Ast *> args; \
Token for_token; \
Ast *val0; \
Ast *val1; \
diff --git a/src/ptr_set.cpp b/src/ptr_set.cpp
index ff4befc37..5097e2bb6 100644
--- a/src/ptr_set.cpp
+++ b/src/ptr_set.cpp
@@ -42,7 +42,7 @@ gb_internal void ptr_set_destroy(PtrSet<T> *s) {
template <typename T>
gb_internal isize ptr_set__find(PtrSet<T> *s, T ptr) {
- GB_ASSERT(ptr != nullptr);
+ GB_ASSERT(ptr != 0);
if (s->count != 0) {
#if 0
for (usize i = 0; i < s->capacity; i++) {
@@ -58,7 +58,7 @@ gb_internal isize ptr_set__find(PtrSet<T> *s, T ptr) {
T key = s->keys[hash_index];
if (key == ptr) {
return hash_index;
- } else if (key == nullptr) {
+ } else if (key == 0) {
return -1;
}
hash_index = (hash_index+1)&mask;
@@ -122,7 +122,7 @@ gb_internal bool ptr_set_update(PtrSet<T> *s, T ptr) { // returns true if it pre
for (usize i = 0; i < s->capacity; i++) {
T *key = &s->keys[hash_index];
GB_ASSERT(*key != ptr);
- if (*key == (T)PtrSet<T>::TOMBSTONE || *key == nullptr) {
+ if (*key == (T)PtrSet<T>::TOMBSTONE || *key == 0) {
*key = ptr;
s->count++;
return false;
@@ -169,7 +169,7 @@ struct PtrSetIterator {
return *this;
}
T key = set->keys[index];
- if (key != nullptr && key != (T)PtrSet<T>::TOMBSTONE) {
+ if (key != 0 && key != (T)PtrSet<T>::TOMBSTONE) {
return *this;
}
}
@@ -191,7 +191,7 @@ gb_internal PtrSetIterator<T> begin(PtrSet<T> &set) noexcept {
usize index = 0;
while (index < set.capacity) {
T key = set.keys[index];
- if (key != nullptr && key != (T)PtrSet<T>::TOMBSTONE) {
+ if (key != 0 && key != (T)PtrSet<T>::TOMBSTONE) {
break;
}
index++;
diff --git a/src/string.cpp b/src/string.cpp
index f8ee6c53e..b001adf0e 100644
--- a/src/string.cpp
+++ b/src/string.cpp
@@ -718,12 +718,12 @@ gb_internal bool unquote_char(String s, u8 quote, Rune *rune, bool *multiple_byt
Rune r = -1;
isize size = utf8_decode(s.text, s.len, &r);
*rune = r;
- *multiple_bytes = true;
- *tail_string = make_string(s.text+size, s.len-size);
+ if (multiple_bytes) *multiple_bytes = true;
+ if (tail_string) *tail_string = make_string(s.text+size, s.len-size);
return true;
} else if (s[0] != '\\') {
*rune = s[0];
- *tail_string = make_string(s.text+1, s.len-1);
+ if (tail_string) *tail_string = make_string(s.text+1, s.len-1);
return true;
}
@@ -809,10 +809,10 @@ gb_internal bool unquote_char(String s, u8 quote, Rune *rune, bool *multiple_byt
return false;
}
*rune = r;
- *multiple_bytes = true;
+ if (multiple_bytes) *multiple_bytes = true;
} break;
}
- *tail_string = s;
+ if (tail_string) *tail_string = s;
return true;
}
diff --git a/src/types.cpp b/src/types.cpp
index 4b43662f5..43fe625f2 100644
--- a/src/types.cpp
+++ b/src/types.cpp
@@ -1,5 +1,5 @@
-struct Scope;
struct Ast;
+struct Scope;
struct Entity;
enum BasicKind {
@@ -161,10 +161,10 @@ struct TypeStruct {
struct TypeUnion {
Slice<Type *> variants;
-
+
Ast * node;
Scope * scope;
-
+
i64 variant_block_size;
i64 custom_align;
Type * polymorphic_params; // Type_Tuple
@@ -503,9 +503,9 @@ gb_global Type basic_types[] = {
{Type_Basic, {Basic_rawptr, BasicFlag_Pointer, -1, STR_LIT("rawptr")}},
{Type_Basic, {Basic_string, BasicFlag_String, -1, STR_LIT("string")}},
{Type_Basic, {Basic_cstring, BasicFlag_String, -1, STR_LIT("cstring")}},
- {Type_Basic, {Basic_any, 0, -1, STR_LIT("any")}},
+ {Type_Basic, {Basic_any, 0, 16, STR_LIT("any")}},
- {Type_Basic, {Basic_typeid, 0, -1, STR_LIT("typeid")}},
+ {Type_Basic, {Basic_typeid, 0, 8, STR_LIT("typeid")}},
// Endian
{Type_Basic, {Basic_i16le, BasicFlag_Integer | BasicFlag_EndianLittle, 2, STR_LIT("i16le")}},
@@ -856,40 +856,6 @@ gb_internal void type_path_pop(TypePath *tp) {
#define FAILURE_SIZE 0
#define FAILURE_ALIGNMENT 0
-gb_internal bool type_ptr_set_exists(PtrSet<Type *> *s, Type *t);
-
-gb_internal bool type_ptr_set_update(PtrSet<Type *> *s, Type *t) {
- if (t == nullptr) {
- return true;
- }
- if (type_ptr_set_exists(s, t)) {
- return true;
- }
- ptr_set_add(s, t);
- return false;
-}
-
-gb_internal bool type_ptr_set_exists(PtrSet<Type *> *s, Type *t) {
- if (t == nullptr) {
- return true;
- }
-
- if (ptr_set_exists(s, t)) {
- return true;
- }
-
- // TODO(bill, 2019-10-05): This is very slow and it's probably a lot
- // faster to cache types correctly
- for (Type *f : *s) {
- if (are_types_identical(t, f)) {
- ptr_set_add(s, t);
- return true;
- }
- }
-
- return false;
-}
-
gb_internal Type *base_type(Type *t) {
for (;;) {
if (t == nullptr) {
@@ -1438,7 +1404,7 @@ gb_internal bool is_type_matrix(Type *t) {
gb_internal i64 matrix_align_of(Type *t, struct TypePath *tp) {
t = base_type(t);
GB_ASSERT(t->kind == Type_Matrix);
-
+
Type *elem = t->Matrix.elem;
i64 row_count = gb_max(t->Matrix.row_count, 1);
i64 column_count = gb_max(t->Matrix.column_count, 1);
@@ -1450,15 +1416,15 @@ gb_internal i64 matrix_align_of(Type *t, struct TypePath *tp) {
i64 elem_align = type_align_of_internal(elem, tp);
if (pop) type_path_pop(tp);
-
+
i64 elem_size = type_size_of(elem);
-
+
// NOTE(bill, 2021-10-25): The alignment strategy here is to have zero padding
// It would be better for performance to pad each column so that each column
// could be maximally aligned but as a compromise, having no padding will be
// beneficial to third libraries that assume no padding
-
+
i64 total_expected_size = row_count*column_count*elem_size;
// i64 min_alignment = prev_pow2(elem_align * row_count);
i64 min_alignment = prev_pow2(total_expected_size);
@@ -1466,7 +1432,7 @@ gb_internal i64 matrix_align_of(Type *t, struct TypePath *tp) {
min_alignment >>= 1;
}
min_alignment = gb_max(min_alignment, elem_align);
-
+
i64 align = gb_min(min_alignment, build_context.max_simd_align);
return align;
}
@@ -1480,7 +1446,7 @@ gb_internal i64 matrix_type_stride_in_bytes(Type *t, struct TypePath *tp) {
} else if (t->Matrix.row_count == 0) {
return 0;
}
-
+
i64 elem_size;
if (tp != nullptr) {
elem_size = type_size_of_internal(t->Matrix.elem, tp);
@@ -1489,7 +1455,7 @@ gb_internal i64 matrix_type_stride_in_bytes(Type *t, struct TypePath *tp) {
}
i64 stride_in_bytes = 0;
-
+
// NOTE(bill, 2021-10-25): The alignment strategy here is to have zero padding
// It would be better for performance to pad each column/row so that each column/row
// could be maximally aligned but as a compromise, having no padding will be
@@ -1545,7 +1511,7 @@ gb_internal i64 matrix_row_major_index_to_offset(Type *t, i64 index) {
gb_internal i64 matrix_column_major_index_to_offset(Type *t, i64 index) {
t = base_type(t);
GB_ASSERT(t->kind == Type_Matrix);
-
+
i64 row_index = index%t->Matrix.row_count;
i64 column_index = index/t->Matrix.row_count;
return matrix_indices_to_offset(t, row_index, column_index);
@@ -1566,7 +1532,7 @@ gb_internal bool is_type_valid_for_matrix_elems(Type *t) {
return true;
} else if (is_type_complex(t)) {
return true;
- }
+ }
if (t->kind == Type_Generic) {
return true;
}
@@ -1801,6 +1767,27 @@ gb_internal bool is_type_union_maybe_pointer_original_alignment(Type *t) {
}
+enum TypeEndianKind {
+ TypeEndian_Platform,
+ TypeEndian_Little,
+ TypeEndian_Big,
+};
+
+gb_internal TypeEndianKind type_endian_kind_of(Type *t) {
+ t = core_type(t);
+ if (t->kind == Type_Basic) {
+ if (t->Basic.flags & BasicFlag_EndianLittle) {
+ return TypeEndian_Little;
+ }
+ if (t->Basic.flags & BasicFlag_EndianBig) {
+ return TypeEndian_Big;
+ }
+ } else if (t->kind == Type_BitSet) {
+ return type_endian_kind_of(bit_set_to_int(t));
+ }
+ return TypeEndian_Platform;
+}
+
gb_internal bool is_type_endian_big(Type *t) {
t = core_type(t);
@@ -2098,6 +2085,26 @@ gb_internal bool is_type_sliceable(Type *t) {
return false;
}
+gb_internal Entity *type_get_polymorphic_parent(Type *t, Type **params_) {
+ t = base_type(t);
+ if (t == nullptr) {
+ return nullptr;
+ }
+ Type *parent = nullptr;
+ if (t->kind == Type_Struct) {
+ parent = t->Struct.polymorphic_parent;
+ if (params_) *params_ = t->Struct.polymorphic_params;
+ } else if (t->kind == Type_Union) {
+ parent = t->Union.polymorphic_parent;
+ if (params_) *params_ = t->Union.polymorphic_params;
+ }
+ if (parent != nullptr) {
+ GB_ASSERT(parent->kind == Type_Named);
+
+ return parent->Named.type_name;
+ }
+ return nullptr;
+}
gb_internal bool is_type_polymorphic_record(Type *t) {
t = base_type(t);
@@ -2464,7 +2471,7 @@ gb_internal bool is_type_simple_compare(Type *t) {
case Type_Proc:
case Type_BitSet:
return true;
-
+
case Type_Matrix:
return is_type_simple_compare(t->Matrix.elem);
@@ -2711,7 +2718,7 @@ gb_internal bool are_types_identical_internal(Type *x, Type *y, bool check_tuple
case Type_Array:
return (x->Array.count == y->Array.count) && are_types_identical(x->Array.elem, y->Array.elem);
-
+
case Type_Matrix:
return x->Matrix.row_count == y->Matrix.row_count &&
x->Matrix.column_count == y->Matrix.column_count &&
@@ -2736,7 +2743,37 @@ gb_internal bool are_types_identical_internal(Type *x, Type *y, bool check_tuple
case Type_Enum:
- return x == y; // NOTE(bill): All enums are unique
+ if (x == y) {
+ return true;
+ }
+ if (x->Enum.fields.count != y->Enum.fields.count) {
+ return false;
+ }
+ if (!are_types_identical(x->Enum.base_type, y->Enum.base_type)) {
+ return false;
+ }
+ if (x->Enum.min_value_index != y->Enum.min_value_index) {
+ return false;
+ }
+ if (x->Enum.max_value_index != y->Enum.max_value_index) {
+ return false;
+ }
+
+ for (isize i = 0; i < x->Enum.fields.count; i++) {
+ Entity *a = x->Enum.fields[i];
+ Entity *b = y->Enum.fields[i];
+ if (a->token.string != b->token.string) {
+ return false;
+ }
+ GB_ASSERT(a->kind == b->kind);
+ GB_ASSERT(a->kind == Entity_Constant);
+ bool same = compare_exact_values(Token_CmpEq, a->Constant.value, b->Constant.value);
+ if (!same) {
+ return false;
+ }
+ }
+
+ return true;
case Type_Union:
if (x->Union.variants.count == y->Union.variants.count &&
@@ -2794,7 +2831,9 @@ gb_internal bool are_types_identical_internal(Type *x, Type *y, bool check_tuple
return false;
}
}
- return are_types_identical(x->Struct.polymorphic_params, y->Struct.polymorphic_params);
+ // TODO(bill): Which is the correct logic here?
+ // return are_types_identical(x->Struct.polymorphic_params, y->Struct.polymorphic_params);
+ return true;
}
break;
@@ -3571,7 +3610,7 @@ gb_internal bool are_struct_fields_reordered(Type *type) {
return false;
}
GB_ASSERT(type->Struct.offsets != nullptr);
-
+
i64 prev_offset = 0;
for_array(i, type->Struct.fields) {
i64 offset = type->Struct.offsets[i];
@@ -3592,9 +3631,9 @@ gb_internal Slice<i32> struct_fields_index_by_increasing_offset(gbAllocator allo
return {};
}
GB_ASSERT(type->Struct.offsets != nullptr);
-
+
auto indices = slice_make<i32>(allocator, type->Struct.fields.count);
-
+
i64 prev_offset = 0;
bool is_ordered = true;
for_array(i, indices) {
@@ -3609,14 +3648,14 @@ gb_internal Slice<i32> struct_fields_index_by_increasing_offset(gbAllocator allo
isize n = indices.count;
for (isize i = 1; i < n; i++) {
isize j = i;
-
+
while (j > 0 && type->Struct.offsets[indices[j-1]] > type->Struct.offsets[indices[j]]) {
gb_swap(i32, indices[j-1], indices[j]);
j -= 1;
- }
+ }
}
}
-
+
return indices;
}
@@ -3664,8 +3703,8 @@ gb_internal i64 type_size_of(Type *t) {
switch (t->Basic.kind) {
case Basic_string: size = 2*build_context.int_size; break;
case Basic_cstring: size = build_context.ptr_size; break;
- case Basic_any: size = 2*build_context.ptr_size; break;
- case Basic_typeid: size = build_context.ptr_size; break;
+ case Basic_any: size = 16; break;
+ case Basic_typeid: size = 8; break;
case Basic_int: case Basic_uint:
size = build_context.int_size;
@@ -3727,8 +3766,8 @@ gb_internal i64 type_align_of_internal(Type *t, TypePath *path) {
switch (t->Basic.kind) {
case Basic_string: return build_context.int_size;
case Basic_cstring: return build_context.ptr_size;
- case Basic_any: return build_context.ptr_size;
- case Basic_typeid: return build_context.ptr_size;
+ case Basic_any: return 8;
+ case Basic_typeid: return 8;
case Basic_int: case Basic_uint:
return build_context.int_size;
@@ -3866,8 +3905,8 @@ gb_internal i64 type_align_of_internal(Type *t, TypePath *path) {
// IMPORTANT TODO(bill): Figure out the alignment of vector types
return gb_clamp(next_pow2(type_size_of_internal(t, path)), 1, build_context.max_simd_align*2);
}
-
- case Type_Matrix:
+
+ case Type_Matrix:
return matrix_align_of(t, path);
case Type_SoaPointer:
@@ -3888,6 +3927,10 @@ gb_internal i64 *type_set_offsets_of(Slice<Entity *> const &fields, bool is_pack
min_field_align = 1;
}
+ TypePath path{};
+ type_path_init(&path);
+ defer (type_path_free(&path));
+
if (is_raw_union) {
for_array(i, fields) {
offsets[i] = 0;
@@ -3897,7 +3940,7 @@ gb_internal i64 *type_set_offsets_of(Slice<Entity *> const &fields, bool is_pack
if (fields[i]->kind != Entity_Variable) {
offsets[i] = -1;
} else {
- i64 size = type_size_of(fields[i]->type);
+ i64 size = type_size_of_internal(fields[i]->type, &path);
offsets[i] = curr_offset;
curr_offset += size;
}
@@ -3908,11 +3951,11 @@ gb_internal i64 *type_set_offsets_of(Slice<Entity *> const &fields, bool is_pack
offsets[i] = -1;
} else {
Type *t = fields[i]->type;
- i64 align = gb_max(type_align_of(t), min_field_align);
+ i64 align = gb_max(type_align_of_internal(t, &path), min_field_align);
if (max_field_align > min_field_align) {
align = gb_min(align, max_field_align);
}
- i64 size = gb_max(type_size_of( t), 0);
+ i64 size = gb_max(type_size_of_internal(t, &path), 0);
curr_offset = align_formula(curr_offset, align);
offsets[i] = curr_offset;
curr_offset += size;
@@ -3925,15 +3968,13 @@ gb_internal i64 *type_set_offsets_of(Slice<Entity *> const &fields, bool is_pack
gb_internal bool type_set_offsets(Type *t) {
t = base_type(t);
if (t->kind == Type_Struct) {
- if (mutex_try_lock(&t->Struct.offset_mutex)) {
- defer (mutex_unlock(&t->Struct.offset_mutex));
- if (!t->Struct.are_offsets_set) {
- t->Struct.are_offsets_being_processed = true;
- t->Struct.offsets = type_set_offsets_of(t->Struct.fields, t->Struct.is_packed, t->Struct.is_raw_union, t->Struct.custom_min_field_align, t->Struct.custom_max_field_align);
- t->Struct.are_offsets_being_processed = false;
- t->Struct.are_offsets_set = true;
- return true;
- }
+ MUTEX_GUARD(&t->Struct.offset_mutex);
+ if (!t->Struct.are_offsets_set) {
+ t->Struct.are_offsets_being_processed = true;
+ t->Struct.offsets = type_set_offsets_of(t->Struct.fields, t->Struct.is_packed, t->Struct.is_raw_union, t->Struct.custom_min_field_align, t->Struct.custom_max_field_align);
+ t->Struct.are_offsets_being_processed = false;
+ t->Struct.are_offsets_set = true;
+ return true;
}
} else if (is_type_tuple(t)) {
MUTEX_GUARD(&t->Tuple.mutex);
@@ -3976,8 +4017,8 @@ gb_internal i64 type_size_of_internal(Type *t, TypePath *path) {
switch (kind) {
case Basic_string: return 2*build_context.int_size;
case Basic_cstring: return build_context.ptr_size;
- case Basic_any: return 2*build_context.ptr_size;
- case Basic_typeid: return build_context.ptr_size;
+ case Basic_any: return 16;
+ case Basic_typeid: return 8;
case Basic_int: case Basic_uint:
return build_context.int_size;
@@ -4152,7 +4193,7 @@ gb_internal i64 type_size_of_internal(Type *t, TypePath *path) {
Type *elem = t->SimdVector.elem;
return count * type_size_of_internal(elem, path);
}
-
+
case Type_Matrix: {
i64 stride_in_bytes = matrix_type_stride_in_bytes(t, path);
if (t->Matrix.is_row_major) {
@@ -4213,7 +4254,7 @@ gb_internal i64 type_offset_of(Type *t, i64 index, Type **field_type_) {
return 0; // data
case 1:
if (field_type_) *field_type_ = t_typeid;
- return build_context.ptr_size; // id
+ return 8; // id
}
}
break;
@@ -4284,8 +4325,8 @@ gb_internal i64 type_offset_of_from_selection(Type *type, Selection sel) {
}
} else if (t->Basic.kind == Basic_any) {
switch (index) {
- case 0: t = t_type_info_ptr; break;
- case 1: t = t_rawptr; break;
+ case 0: t = t_rawptr; break;
+ case 1: t = t_typeid; break;
}
}
break;
@@ -4557,7 +4598,7 @@ gb_internal gbString write_type_to_string(gbString str, Type *type, bool shortha
break;
case Type_Array:
- str = gb_string_appendc(str, gb_bprintf("[%d]", cast(int)type->Array.count));
+ str = gb_string_appendc(str, gb_bprintf("[%lld]", cast(long long)type->Array.count));
str = write_type_to_string(str, type->Array.elem);
break;
@@ -4730,10 +4771,10 @@ gb_internal gbString write_type_to_string(gbString str, Type *type, bool shortha
}
break;
case ProcCC_CDecl:
- str = gb_string_appendc(str, " \"cdecl\" ");
+ str = gb_string_appendc(str, " \"c\" ");
break;
case ProcCC_StdCall:
- str = gb_string_appendc(str, " \"stdcall\" ");
+ str = gb_string_appendc(str, " \"std\" ");
break;
case ProcCC_FastCall:
str = gb_string_appendc(str, " \"fastcall\" ");
@@ -4771,7 +4812,9 @@ gb_internal gbString write_type_to_string(gbString str, Type *type, bool shortha
case Type_BitSet:
str = gb_string_appendc(str, "bit_set[");
- if (is_type_enum(type->BitSet.elem)) {
+ if (type->BitSet.elem == nullptr) {
+ str = gb_string_appendc(str, "<unresolved>");
+ } else if (is_type_enum(type->BitSet.elem)) {
str = write_type_to_string(str, type->BitSet.elem);
} else {
str = gb_string_append_fmt(str, "%lld", type->BitSet.lower);
@@ -4789,7 +4832,7 @@ gb_internal gbString write_type_to_string(gbString str, Type *type, bool shortha
str = gb_string_append_fmt(str, "#simd[%d]", cast(int)type->SimdVector.count);
str = write_type_to_string(str, type->SimdVector.elem);
break;
-
+
case Type_Matrix:
if (type->Matrix.is_row_major) {
str = gb_string_appendc(str, "#row_major ");
@@ -4830,6 +4873,3 @@ gb_internal gbString type_to_string(Type *type, bool shorthand) {
gb_internal gbString type_to_string_shorthand(Type *type) {
return type_to_string(type, true);
}
-
-
-