From dd8e6e884c181b6d6775eedcfc3bad1365405f4f Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 5 Dec 2024 15:45:01 +0000 Subject: Try to fix #4553 --- src/llvm_backend_general.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/llvm_backend_general.cpp') diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index 9dc603993..bab330da7 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -2601,7 +2601,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); -- cgit v1.2.3 From fdf510b7b35119739d6e41170abd46204356d58b Mon Sep 17 00:00:00 2001 From: misomosi Date: Sat, 21 Dec 2024 19:59:31 -0500 Subject: Pack struct when needed, use field_align metadata --- src/llvm_backend.hpp | 2 ++ src/llvm_backend_general.cpp | 18 +++++++++++++++++- src/llvm_backend_utility.cpp | 19 ++++++++++++++++--- 3 files changed, 35 insertions(+), 4 deletions(-) (limited to 'src/llvm_backend_general.cpp') diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index e84ffd1cd..3bbd97e4b 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -742,3 +742,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_general.cpp b/src/llvm_backend_general.cpp index bab330da7..762256258 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -734,6 +734,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; @@ -2121,6 +2132,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 +2153,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 +2171,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 diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp index a2a0ba4cc..b86d0773b 100644 --- a/src/llvm_backend_utility.cpp +++ b/src/llvm_backend_utility.cpp @@ -1200,9 +1200,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; -- cgit v1.2.3 From b77430bea8ea29263750d0356343cee36808d8f3 Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Wed, 5 Feb 2025 19:42:20 +0100 Subject: -obfuscate-source-code-locations on bounds checks and type assertions --- src/llvm_backend_expr.cpp | 8 ++----- src/llvm_backend_general.cpp | 52 ++++++++++++++++++-------------------------- src/llvm_backend_utility.cpp | 8 ++----- 3 files changed, 25 insertions(+), 43 deletions(-) (limited to 'src/llvm_backend_general.cpp') diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 871536927..693f2e225 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -3364,9 +3364,7 @@ gb_internal lbValue lb_build_unary_and(lbProcedure *p, Ast *expr) { auto args = array_make(permanent_allocator(), arg_count); args[0] = ok; - args[1] = lb_find_or_add_entity_string(p->module, get_file_path_string(pos.file_id)); - args[2] = lb_const_int(p->module, t_i32, pos.line); - args[3] = lb_const_int(p->module, t_i32, pos.column); + lb_set_file_line_col(p, array_slice(args, 1, args.count), pos); if (!build_context.no_rtti) { args[4] = lb_typeid(p->module, src_type); @@ -3393,9 +3391,7 @@ gb_internal lbValue lb_build_unary_and(lbProcedure *p, Ast *expr) { auto args = array_make(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; diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index 762256258..7425b9fd7 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -15,7 +15,6 @@ 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; @@ -540,6 +539,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 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 +568,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(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 +591,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(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 +613,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(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 +629,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(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 +643,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(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; diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp index 8910bd67a..aa425a9d5 100644 --- a/src/llvm_backend_utility.cpp +++ b/src/llvm_backend_utility.cpp @@ -771,9 +771,7 @@ gb_internal lbValue lb_emit_union_cast(lbProcedure *p, lbValue value, Type *type auto args = array_make(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(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; -- cgit v1.2.3 From 99d91ccd31366e78c7ec0e94b5e3d473806721ed Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 17 Feb 2025 11:32:49 +0000 Subject: Work on making name mangling deterministic --- src/check_decl.cpp | 6 + src/check_expr.cpp | 2 +- src/checker.cpp | 1 + src/checker.hpp | 2 + src/entity.cpp | 1 + src/gb/gb.h | 2 +- src/llvm_backend.hpp | 2 +- src/llvm_backend_general.cpp | 43 ++++- src/llvm_backend_stmt.cpp | 3 +- src/name_canonicalization.cpp | 419 ++++++++++++++++++++++++++++++++++++++++++ src/types.cpp | 269 --------------------------- 11 files changed, 475 insertions(+), 275 deletions(-) create mode 100644 src/name_canonicalization.cpp (limited to 'src/llvm_backend_general.cpp') diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 9084f15f0..d6f8e6fa7 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -1784,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: @@ -1873,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 550a7749c..f0021e67f 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -345,7 +345,7 @@ gb_internal void check_scope_decls(CheckerContext *c, Slice 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: diff --git a/src/checker.cpp b/src/checker.cpp index bfcabe4fa..c74a72a14 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -3894,6 +3894,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" diff --git a/src/checker.hpp b/src/checker.hpp index 4634047c0..472ab8e50 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -276,6 +276,8 @@ struct Scope { StringMap elements; PtrSet imported; + DeclInfo *decl_info; + i32 flags; // ScopeFlag union { AstPackage *pkg; diff --git a/src/entity.cpp b/src/entity.cpp index d137a8674..b2148aa7b 100644 --- a/src/entity.cpp +++ b/src/entity.cpp @@ -257,6 +257,7 @@ struct Entity { bool has_instrumentation : 1; bool is_memcpy_like : 1; bool uses_branch_location : 1; + bool is_anonymous : 1; } Procedure; struct { Array entities; diff --git a/src/gb/gb.h b/src/gb/gb.h index 59611ceb6..98c362e93 100644 --- a/src/gb/gb.h +++ b/src/gb/gb.h @@ -5856,7 +5856,7 @@ gb_inline isize gb_fprintf_va(struct gbFile *f, char const *fmt, va_list va) { 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/llvm_backend.hpp b/src/llvm_backend.hpp index a0775ac3b..dd6f1a083 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -399,7 +399,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); diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index 7425b9fd7..dc212e51d 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -1444,6 +1444,7 @@ gb_internal void lb_clone_struct_type(LLVMTypeRef dst, LLVMTypeRef src) { } gb_internal String lb_mangle_name(Entity *e) { +#if 1 String name = e->token.string; AstPackage *pkg = e->pkg; @@ -1483,9 +1484,18 @@ gb_internal String lb_mangle_name(Entity *e) { String mangled_name = make_string((u8 const *)new_name, new_name_len-1); return mangled_name; +#else + gbString w = gb_string_make(gb_heap_allocator(), ""); + w = write_canonical_entity_name(w, e); + gb_printf_err(">> %s\n", w); + + String mangled_name = make_string(cast(u8 const *)w, gb_string_length(w)); + return mangled_name; +#endif } gb_internal String lb_set_nested_type_name_ir_mangled_name(Entity *e, lbProcedure *p, lbModule *module) { +#if 0 // 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 @@ -1516,6 +1526,7 @@ gb_internal String lb_set_nested_type_name_ir_mangled_name(Entity *e, lbProcedur } } + // NOTE(bill): Generate a new name // parent_proc.name-guid String ts_name = e->token.string; @@ -1528,6 +1539,12 @@ gb_internal String lb_set_nested_type_name_ir_mangled_name(Entity *e, lbProcedur String name = make_string(cast(u8 *)name_text, name_len-1); e->TypeName.ir_mangled_name = name; + + { + String s = type_to_canonical_string(temporary_allocator(), e->type); + gb_printf_err("1) %.*s\n", LIT(s)); + gb_printf_err("2) %.*s\n", LIT(name)); + } return name; } else { // NOTE(bill): a nested type be required before its parameter procedure exists. Just give it a temp name for now @@ -1538,11 +1555,18 @@ gb_internal String lb_set_nested_type_name_ir_mangled_name(Entity *e, lbProcedur String name = make_string(cast(u8 *)name_text, name_len-1); e->TypeName.ir_mangled_name = name; + + { + String s = type_to_canonical_string(temporary_allocator(), e->type); + gb_printf_err("3) %.*s\n", LIT(s)); + gb_printf_err("4) %.*s\n", LIT(name)); + } return name; } +#endif } -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) { return e->TypeName.ir_mangled_name; @@ -1553,6 +1577,13 @@ gb_internal String lb_get_entity_name(lbModule *m, Entity *e, String default_nam return e->token.string; } +#if 1 + gbString w = gb_string_make(heap_allocator(), ""); + w = write_canonical_entity_name(w, e); + defer (gb_string_free(w)); + + String name = copy_string(permanent_allocator(), make_string(cast(u8 const *)w, gb_string_length(w))); +#else if (e->kind == Entity_TypeName && (e->scope->flags & ScopeFlag_File) == 0) { return lb_set_nested_type_name_ir_mangled_name(e, nullptr, m); } @@ -1576,11 +1607,17 @@ gb_internal String lb_get_entity_name(lbModule *m, Entity *e, String default_nam if (!no_name_mangle) { name = lb_mangle_name(e); + + gbString w = gb_string_make(gb_heap_allocator(), ""); + w = write_canonical_entity_name(w, e); + if (w[0] == 0) { + gb_printf_err(">> %s %.*s\n", w, LIT(name)); + } } if (name.len == 0) { name = e->token.string; } - +#endif if (e->kind == Entity_TypeName) { e->TypeName.ir_mangled_name = name; } else if (e->kind == Entity_Procedure) { @@ -2869,6 +2906,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); diff --git a/src/llvm_backend_stmt.cpp b/src/llvm_backend_stmt.cpp index b05df0b46..b83472075 100644 --- a/src/llvm_backend_stmt.cpp +++ b/src/llvm_backend_stmt.cpp @@ -32,7 +32,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) { diff --git a/src/name_canonicalization.cpp b/src/name_canonicalization.cpp new file mode 100644 index 000000000..fa09f27c0 --- /dev/null +++ b/src/name_canonicalization.cpp @@ -0,0 +1,419 @@ +gb_internal gbString write_type_to_canonical_string(gbString w, Type *type); +gb_internal gbString write_canonical_params(gbString w, Type *params) { + w = gb_string_appendc(w, "("); + if (params) { + GB_ASSERT(params->kind == Type_Tuple); + for_array(i, params->Tuple.variables) { + Entity *v = params->Tuple.variables[i]; + if (i > 0) { + w = gb_string_appendc(w, ","); + } + if (v->kind == Entity_Variable) { + if (v->flags&EntityFlag_CVarArg) { + w = gb_string_appendc(w, "#c_vararg"); + } + if (v->flags&EntityFlag_Ellipsis) { + Type *slice = base_type(v->type); + w = gb_string_appendc(w, ".."); + GB_ASSERT(v->type->kind == Type_Slice); + w = write_type_to_canonical_string(w, slice->Slice.elem); + } else { + w = write_type_to_canonical_string(w, v->type); + } + } else if (v->kind == Entity_TypeName) { + w = gb_string_appendc(w, "$"); + w = write_type_to_canonical_string(w, v->type); + } else if (v->kind == Entity_Constant) { + w = gb_string_appendc(w, "$$"); + w = write_exact_value_to_string(w, v->Constant.value); + } else { + GB_PANIC("TODO(bill): handle non type/const parapoly parameter values"); + } + } + } + return gb_string_appendc(w, ")"); +} + +gb_internal u64 type_hash_canonical_type(Type *type) { + if (type == nullptr) { + return 0; + } + TEMPORARY_ALLOCATOR_GUARD(); + gbString w = write_type_to_canonical_string(gb_string_make(temporary_allocator(), ""), type); + u64 hash = fnv64a(w, gb_string_length(w)); + return hash; +} + +gb_internal String type_to_canonical_string(gbAllocator allocator, Type *type) { + gbString w = gb_string_make(allocator, ""); + w = write_type_to_canonical_string(w, type); + return make_string(cast(u8 const *)w, gb_string_length(w)); +} + +gb_internal void 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"); +} + + + +gb_internal gbString write_canonical_parent_prefix(gbString w, Entity *e, bool ignore_final_dot=false) { + GB_ASSERT(e != nullptr); + + // auto const &parent_entity = [](Scope *s) -> Entity* { + // while ((s->flags & (ScopeFlag_Proc|ScopeFlag_File)) == 0 && s->decl_info == nullptr) { + // s = s->parent; + // } + // if (s->decl_info && s->decl_info->entity) { + // return s->decl_info->entity; + // } + // return nullptr; + // }; + + if (e->kind == Entity_Procedure) { + if (e->Procedure.is_export || e->Procedure.is_foreign) { + // no prefix + return w; + } + if (e->parent_proc_decl) { + Entity *p = e->parent_proc_decl->entity; + w = write_canonical_parent_prefix(w, p); + w = gb_string_append_length(w, p->token.string.text, p->token.string.len); + if (is_type_polymorphic(p->type)) { + w = gb_string_appendc(w, "::"); + w = write_type_to_canonical_string(w, p->type); + } + w = gb_string_appendc(w, "."); + + } else if (e->pkg && (scope_lookup_current(e->pkg->scope, e->token.string) == e)) { + w = gb_string_append_length(w, e->pkg->name.text, e->pkg->name.len); + if (e->pkg->name == "llvm") { + gb_string_appendc(w, "$"); + } + w = gb_string_appendc(w, "."); + } else { + String file_name = filename_without_directory(e->file->fullpath); + w = gb_string_append_length(w, e->pkg->name.text, e->pkg->name.len); + if (e->pkg->name == "llvm") { + gb_string_appendc(w, "$"); + } + w = gb_string_appendc(w, gb_bprintf(".[%.*s].", LIT(file_name))); + } + } else if (e->kind == Entity_Procedure) { + if (e->Procedure.is_export || e->Procedure.is_foreign) { + // no prefix + return w; + } + GB_PANIC("TODO(bill): handle entity kind: %d", e->kind); + } + + if (e->kind == Entity_Procedure && e->Procedure.is_anonymous) { + w = gb_string_appendc(w, gb_bprintf("$anon%d", e->token.pos.offset)); + } else { + w = gb_string_append_length(w, e->token.string.text, e->token.string.len); + } + + if (is_type_polymorphic(e->type)) { + w = gb_string_appendc(w, "::"); + w = write_type_to_canonical_string(w, e->type); + } + if (!ignore_final_dot) { + w = gb_string_appendc(w, "."); + } + + return w; +} + +gb_internal gbString write_canonical_entity_name(gbString 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) { + w = gb_string_append_length(w, e->Variable.link_name.text, e->Variable.link_name.len); + return w; + } else if (is_foreign || is_export) { + w = gb_string_append_length(w, e->token.string.text, e->token.string.len); + return w; + } + } else if (e->kind == Entity_Procedure && e->Procedure.link_name.len > 0) { + w = gb_string_append_length(w, e->Procedure.link_name.text, e->Procedure.link_name.len); + return w; + } else if (e->kind == Entity_Procedure && e->Procedure.is_export) { + w = gb_string_append_length(w, e->token.string.text, e->token.string.len); + return w; + } + + 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) { + s = s->parent; + } + + if (s->decl_info != nullptr && s->decl_info->entity) { + w = write_canonical_parent_prefix(w, s->decl_info->entity); + goto write_base_name; + } else if ((s->flags & ScopeFlag_File) && s->file != nullptr) { + String file_name = filename_without_directory(s->file->fullpath); + w = gb_string_append_length(w, e->pkg->name.text, e->pkg->name.len); + if (e->pkg->name == "llvm") { + gb_string_appendc(w, "$"); + } + w = gb_string_appendc(w, gb_bprintf(".[%.*s].", LIT(file_name))); + goto write_base_name; + } + gb_printf_err("%s HERE %s %u %p\n", token_pos_to_string(e->token.pos), type_to_string(e->type), s->flags, s->decl_info); + print_scope_flags(s); + GB_PANIC("weird entity"); + } + if (e->pkg != nullptr) { + w = gb_string_append_length(w, e->pkg->name.text, e->pkg->name.len); + w = gb_string_appendc(w, "."); + } + +write_base_name: + + switch (e->kind) { + case Entity_TypeName: + { + Type *params = nullptr; + Entity *parent = type_get_polymorphic_parent(e->type, ¶ms); + if (parent) { + w = gb_string_append_length(w, parent->token.string.text, parent->token.string.len); + w = write_canonical_params(w, params); + } else { + w = gb_string_append_length(w, e->token.string.text, e->token.string.len); + } + } + // Handle parapoly stuff here? + return w; + + case Entity_Procedure: + case Entity_Variable: + w = gb_string_append_length(w, e->token.string.text, e->token.string.len); + if (is_type_polymorphic(e->type)) { + w = gb_string_appendc(w, "::"); + w = write_type_to_canonical_string(w, e->type); + } + return w; + + default: + GB_PANIC("TODO(bill): entity kind %d", e->kind); + break; + } + return w; +} + +// NOTE(bill): This exists so that we deterministically hash a type by serializing it to a canonical string +gb_internal gbString write_type_to_canonical_string(gbString w, Type *type) { + if (type == nullptr) { + return gb_string_appendc(w, "<>"); // none/void type + } + + type = default_type(type); + GB_ASSERT(!is_type_untyped(type)); + + switch (type->kind) { + case Type_Basic: + return gb_string_append_length(w, type->Basic.name.text, type->Basic.name.len); + case Type_Pointer: + w = gb_string_append_rune(w, '^'); + return write_type_to_canonical_string(w, type->Pointer.elem); + case Type_MultiPointer: + w = gb_string_appendc(w, "[^]"); + return write_type_to_canonical_string(w, type->Pointer.elem); + case Type_SoaPointer: + w = gb_string_appendc(w, "#soa^"); + return write_type_to_canonical_string(w, type->Pointer.elem); + case Type_EnumeratedArray: + if (type->EnumeratedArray.is_sparse) { + w = gb_string_appendc(w, "#sparse"); + } + w = gb_string_append_rune(w, '['); + w = write_type_to_canonical_string(w, type->EnumeratedArray.index); + w = gb_string_append_rune(w, ']'); + return write_type_to_canonical_string(w, type->EnumeratedArray.elem); + case Type_Array: + w = gb_string_appendc(w, gb_bprintf("[%lld]", cast(long long)type->Array.count)); + return write_type_to_canonical_string(w, type->Array.elem); + case Type_Slice: + w = gb_string_appendc(w, "[]"); + return write_type_to_canonical_string(w, type->Array.elem); + case Type_DynamicArray: + w = gb_string_appendc(w, "[dynamic]"); + return write_type_to_canonical_string(w, type->DynamicArray.elem); + case Type_SimdVector: + w = gb_string_appendc(w, gb_bprintf("#simd[%lld]", cast(long long)type->SimdVector.count)); + return write_type_to_canonical_string(w, type->SimdVector.elem); + case Type_Matrix: + if (type->Matrix.is_row_major) { + w = gb_string_appendc(w, "#row_major "); + } + w = gb_string_appendc(w, gb_bprintf("matrix[%lld, %lld]", cast(long long)type->Matrix.row_count, cast(long long)type->Matrix.column_count)); + return write_type_to_canonical_string(w, type->Matrix.elem); + case Type_Map: + w = gb_string_appendc(w, "map["); + w = write_type_to_canonical_string(w, type->Map.key); + w = gb_string_appendc(w, "]"); + return write_type_to_canonical_string(w, type->Map.value); + + case Type_Enum: + w = gb_string_appendc(w, "enum"); + if (type->Enum.base_type != nullptr) { + w = gb_string_append_rune(w, ' '); + w = write_type_to_canonical_string(w, type->Enum.base_type); + w = gb_string_append_rune(w, ' '); + } + w = gb_string_append_rune(w, '{'); + for_array(i, type->Enum.fields) { + Entity *f = type->Enum.fields[i]; + GB_ASSERT(f->kind == Entity_Constant); + if (i > 0) { + w = gb_string_appendc(w, ","); + } + w = gb_string_append_length(w, f->token.string.text, f->token.string.len); + w = gb_string_appendc(w, "="); + w = write_exact_value_to_string(w, f->Constant.value); + } + return gb_string_append_rune(w, '}'); + case Type_BitSet: + w = gb_string_appendc(w, "bit_set["); + if (type->BitSet.elem == nullptr) { + w = write_type_to_canonical_string(w, type->BitSet.elem); + } else if (is_type_enum(type->BitSet.elem)) { + w = write_type_to_canonical_string(w, type->BitSet.elem); + } else { + w = gb_string_append_fmt(w, "%lld", type->BitSet.lower); + w = gb_string_append_fmt(w, "..="); + w = gb_string_append_fmt(w, "%lld", type->BitSet.upper); + } + if (type->BitSet.underlying != nullptr) { + w = gb_string_appendc(w, ";"); + w = write_type_to_canonical_string(w, type->BitSet.underlying); + } + return gb_string_appendc(w, "]"); + + case Type_Union: + w = gb_string_appendc(w, "union"); + + switch (type->Union.kind) { + case UnionType_no_nil: w = gb_string_appendc(w, "#no_nil"); break; + case UnionType_shared_nil: w = gb_string_appendc(w, "#shared_nil"); break; + } + if (type->Union.custom_align != 0) { + w = gb_string_append_fmt(w, "#align(%lld)", cast(long long)type->Union.custom_align); + } + w = gb_string_appendc(w, "{"); + for_array(i, type->Union.variants) { + Type *t = type->Union.variants[i]; + if (i > 0) w = gb_string_appendc(w, ", "); + w = write_type_to_canonical_string(w, t); + } + return gb_string_appendc(w, "}"); + case Type_Struct: + if (type->Struct.soa_kind != StructSoa_None) { + switch (type->Struct.soa_kind) { + case StructSoa_Fixed: w = gb_string_append_fmt(w, "#soa[%lld]", cast(long long)type->Struct.soa_count); break; + case StructSoa_Slice: w = gb_string_appendc(w, "#soa[]"); break; + case StructSoa_Dynamic: w = gb_string_appendc(w, "#soa[dynamic]"); break; + default: GB_PANIC("Unknown StructSoaKind"); break; + } + return write_type_to_canonical_string(w, type->Struct.soa_elem); + } + + w = gb_string_appendc(w, "struct"); + if (type->Struct.is_packed) w = gb_string_appendc(w, "#packed"); + if (type->Struct.is_raw_union) w = gb_string_appendc(w, "#raw_union"); + if (type->Struct.is_no_copy) w = gb_string_appendc(w, "#no_copy"); + if (type->Struct.custom_min_field_align != 0) w = gb_string_append_fmt(w, "#min_field_align(%lld)", cast(long long)type->Struct.custom_min_field_align); + if (type->Struct.custom_max_field_align != 0) w = gb_string_append_fmt(w, "#max_field_align(%lld)", cast(long long)type->Struct.custom_max_field_align); + if (type->Struct.custom_align != 0) w = gb_string_append_fmt(w, "#align(%lld)", cast(long long)type->Struct.custom_align); + w = gb_string_appendc(w, "{"); + for_array(i, type->Struct.fields) { + Entity *f = type->Struct.fields[i]; + GB_ASSERT(f->kind == Entity_Variable); + if (i > 0) { + w = gb_string_appendc(w, ","); + } + w = gb_string_append_length (w, f->token.string.text, f->token.string.len); + w = gb_string_appendc (w, ":"); + w = write_type_to_canonical_string(w, f->type); + String tag = type->Struct.tags[i]; + if (tag.len != 0) { + String s = quote_to_ascii(heap_allocator(), tag); + w = gb_string_append_length(w, s.text, s.len); + gb_free(heap_allocator(), s.text); + } + } + return gb_string_appendc(w, "}"); + + case Type_BitField: + w = gb_string_appendc(w, "bit_field"); + w = write_type_to_canonical_string(w, type->BitField.backing_type); + w = gb_string_appendc(w, " {"); + for (isize i = 0; i < type->BitField.fields.count; i++) { + Entity *f = type->BitField.fields[i]; + if (i > 0) { + w = gb_string_appendc(w, ","); + } + w = gb_string_append_length(w, f->token.string.text, f->token.string.len); + w = gb_string_appendc(w, ":"); + w = write_type_to_canonical_string(w, f->type); + w = gb_string_appendc(w, "|"); + w = gb_string_appendc(w, gb_bprintf("%u", type->BitField.bit_sizes[i])); + } + return gb_string_appendc(w, " }"); + + case Type_Proc: + w = gb_string_appendc(w, "proc"); + if (default_calling_convention() != type->Proc.calling_convention) { + w = gb_string_appendc(w, "\""); + w = gb_string_appendc(w, proc_calling_convention_strings[type->Proc.calling_convention]); + w = gb_string_appendc(w, "\""); + } + + w = write_canonical_params(w, type->Proc.params); + if (type->Proc.result_count > 0) { + w = gb_string_appendc(w, "->"); + w = write_canonical_params(w, type->Proc.results); + } + return w; + + case Type_Generic: + GB_PANIC("Type_Generic should never be hit"); + return w; + + case Type_Named: + if (type->Named.type_name != nullptr) { + return write_canonical_entity_name(w, type->Named.type_name); + } else { + w = gb_string_append_length(w, type->Named.name.text, type->Named.name.len); + } + // Handle parapoly stuff here? + return w; + + default: + GB_PANIC("unknown type kind %d", type->kind); + break; + } + + return w; +} \ No newline at end of file diff --git a/src/types.cpp b/src/types.cpp index 42530eccc..d6dea56ad 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -4872,272 +4872,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); } - -gb_internal gbString write_type_to_canonical_string(gbString w, Type *type); -gb_internal gbString write_canonical_params(gbString w, Type *params) { - w = gb_string_appendc(w, "("); - if (params) { - GB_ASSERT(params->kind == Type_Tuple); - for_array(i, params->Tuple.variables) { - Entity *v = params->Tuple.variables[i]; - if (i > 0) { - w = gb_string_appendc(w, ","); - } - if (v->kind == Entity_Variable) { - if (v->flags&EntityFlag_CVarArg) { - w = gb_string_appendc(w, "#c_vararg"); - } - if (v->flags&EntityFlag_Ellipsis) { - Type *slice = base_type(v->type); - w = gb_string_appendc(w, ".."); - GB_ASSERT(v->type->kind == Type_Slice); - w = write_type_to_canonical_string(w, slice->Slice.elem); - } else { - w = write_type_to_canonical_string(w, v->type); - } - } else if (v->kind == Entity_TypeName) { - w = gb_string_appendc(w, "$"); - w = write_type_to_canonical_string(w, v->type); - } else if (v->kind == Entity_Constant) { - w = gb_string_appendc(w, "$$"); - w = write_exact_value_to_string(w, v->Constant.value); - } else { - GB_PANIC("TODO(bill): handle non type/const parapoly parameter values"); - } - } - } - return gb_string_appendc(w, ")"); -} - -gb_internal u64 type_hash_canonical_type(Type *type) { - if (type == nullptr) { - return 0; - } - TEMPORARY_ALLOCATOR_GUARD(); - gbString w = write_type_to_canonical_string(gb_string_make(temporary_allocator(), ""), type); - u64 hash = fnv64a(w, gb_string_length(w)); - return hash; -} - -gb_internal String type_to_canonical_string(gbAllocator allocator, Type *type) { - gbString w = gb_string_make(allocator, ""); - w = write_type_to_canonical_string(w, type); - return make_string(cast(u8 const *)w, gb_string_length(w)); -} - -// NOTE(bill): This exists so that we deterministically hash a type by serializing it to a canonical string -gb_internal gbString write_type_to_canonical_string(gbString w, Type *type) { - if (type == nullptr) { - return gb_string_appendc(w, "<>"); // none/void type - } - - type = default_type(type); - GB_ASSERT(!is_type_untyped(type)); - - switch (type->kind) { - case Type_Basic: - return gb_string_append_length(w, type->Basic.name.text, type->Basic.name.len); - case Type_Pointer: - w = gb_string_append_rune(w, '^'); - return write_type_to_canonical_string(w, type->Pointer.elem); - case Type_MultiPointer: - w = gb_string_appendc(w, "[^]"); - return write_type_to_canonical_string(w, type->Pointer.elem); - case Type_SoaPointer: - w = gb_string_appendc(w, "#soa^"); - return write_type_to_canonical_string(w, type->Pointer.elem); - case Type_EnumeratedArray: - if (type->EnumeratedArray.is_sparse) { - w = gb_string_appendc(w, "#sparse"); - } - w = gb_string_append_rune(w, '['); - w = write_type_to_canonical_string(w, type->EnumeratedArray.index); - w = gb_string_append_rune(w, ']'); - return write_type_to_canonical_string(w, type->EnumeratedArray.elem); - case Type_Array: - w = gb_string_appendc(w, gb_bprintf("[%lld]", cast(long long)type->Array.count)); - return write_type_to_canonical_string(w, type->Array.elem); - case Type_Slice: - w = gb_string_appendc(w, "[]"); - return write_type_to_canonical_string(w, type->Array.elem); - case Type_DynamicArray: - w = gb_string_appendc(w, "[dynamic]"); - return write_type_to_canonical_string(w, type->DynamicArray.elem); - case Type_SimdVector: - w = gb_string_appendc(w, gb_bprintf("#simd[%lld]", cast(long long)type->SimdVector.count)); - return write_type_to_canonical_string(w, type->SimdVector.elem); - case Type_Matrix: - if (type->Matrix.is_row_major) { - w = gb_string_appendc(w, "#row_major "); - } - w = gb_string_appendc(w, gb_bprintf("matrix[%lld, %lld]", cast(long long)type->Matrix.row_count, cast(long long)type->Matrix.column_count)); - return write_type_to_canonical_string(w, type->Matrix.elem); - case Type_Map: - w = gb_string_appendc(w, "map["); - w = write_type_to_canonical_string(w, type->Map.key); - w = gb_string_appendc(w, "]"); - return write_type_to_canonical_string(w, type->Map.value); - - case Type_Enum: - w = gb_string_appendc(w, "enum"); - if (type->Enum.base_type != nullptr) { - w = gb_string_append_rune(w, ' '); - w = write_type_to_canonical_string(w, type->Enum.base_type); - w = gb_string_append_rune(w, ' '); - } - w = gb_string_append_rune(w, '{'); - for_array(i, type->Enum.fields) { - Entity *f = type->Enum.fields[i]; - GB_ASSERT(f->kind == Entity_Constant); - if (i > 0) { - w = gb_string_appendc(w, ","); - } - w = gb_string_append_length(w, f->token.string.text, f->token.string.len); - w = gb_string_appendc(w, "="); - w = write_exact_value_to_string(w, f->Constant.value); - } - return gb_string_append_rune(w, '}'); - case Type_BitSet: - w = gb_string_appendc(w, "bit_set["); - if (type->BitSet.elem == nullptr) { - w = write_type_to_canonical_string(w, type->BitSet.elem); - } else if (is_type_enum(type->BitSet.elem)) { - w = write_type_to_canonical_string(w, type->BitSet.elem); - } else { - w = gb_string_append_fmt(w, "%lld", type->BitSet.lower); - w = gb_string_append_fmt(w, "..="); - w = gb_string_append_fmt(w, "%lld", type->BitSet.upper); - } - if (type->BitSet.underlying != nullptr) { - w = gb_string_appendc(w, ";"); - w = write_type_to_canonical_string(w, type->BitSet.underlying); - } - return gb_string_appendc(w, "]"); - - case Type_Union: - w = gb_string_appendc(w, "union"); - - switch (type->Union.kind) { - case UnionType_no_nil: w = gb_string_appendc(w, "#no_nil"); break; - case UnionType_shared_nil: w = gb_string_appendc(w, "#shared_nil"); break; - } - if (type->Union.custom_align != 0) { - w = gb_string_append_fmt(w, "#align(%lld)", cast(long long)type->Union.custom_align); - } - w = gb_string_appendc(w, "{"); - for_array(i, type->Union.variants) { - Type *t = type->Union.variants[i]; - if (i > 0) w = gb_string_appendc(w, ", "); - w = write_type_to_canonical_string(w, t); - } - return gb_string_appendc(w, "}"); - case Type_Struct: - if (type->Struct.soa_kind != StructSoa_None) { - switch (type->Struct.soa_kind) { - case StructSoa_Fixed: w = gb_string_append_fmt(w, "#soa[%lld]", cast(long long)type->Struct.soa_count); break; - case StructSoa_Slice: w = gb_string_appendc(w, "#soa[]"); break; - case StructSoa_Dynamic: w = gb_string_appendc(w, "#soa[dynamic]"); break; - default: GB_PANIC("Unknown StructSoaKind"); break; - } - return write_type_to_canonical_string(w, type->Struct.soa_elem); - } - - w = gb_string_appendc(w, "struct"); - if (type->Struct.is_packed) w = gb_string_appendc(w, "#packed"); - if (type->Struct.is_raw_union) w = gb_string_appendc(w, "#raw_union"); - if (type->Struct.is_no_copy) w = gb_string_appendc(w, "#no_copy"); - if (type->Struct.custom_min_field_align != 0) w = gb_string_append_fmt(w, "#min_field_align(%lld)", cast(long long)type->Struct.custom_min_field_align); - if (type->Struct.custom_max_field_align != 0) w = gb_string_append_fmt(w, "#max_field_align(%lld)", cast(long long)type->Struct.custom_max_field_align); - if (type->Struct.custom_align != 0) w = gb_string_append_fmt(w, "#align(%lld)", cast(long long)type->Struct.custom_align); - w = gb_string_appendc(w, "{"); - for_array(i, type->Struct.fields) { - Entity *f = type->Struct.fields[i]; - GB_ASSERT(f->kind == Entity_Variable); - if (i > 0) { - w = gb_string_appendc(w, ","); - } - w = gb_string_append_length (w, f->token.string.text, f->token.string.len); - w = gb_string_appendc (w, ":"); - w = write_type_to_canonical_string(w, f->type); - String tag = type->Struct.tags[i]; - if (tag.len != 0) { - String s = quote_to_ascii(heap_allocator(), tag); - w = gb_string_append_length(w, s.text, s.len); - gb_free(heap_allocator(), s.text); - } - } - return gb_string_appendc(w, "}"); - - case Type_BitField: - w = gb_string_appendc(w, "bit_field"); - w = write_type_to_canonical_string(w, type->BitField.backing_type); - w = gb_string_appendc(w, " {"); - for (isize i = 0; i < type->BitField.fields.count; i++) { - Entity *f = type->BitField.fields[i]; - if (i > 0) { - w = gb_string_appendc(w, ","); - } - w = gb_string_append_length(w, f->token.string.text, f->token.string.len); - w = gb_string_appendc(w, ":"); - w = write_type_to_canonical_string(w, f->type); - w = gb_string_appendc(w, "|"); - w = gb_string_appendc(w, gb_bprintf("%u", type->BitField.bit_sizes[i])); - } - return gb_string_appendc(w, " }"); - - case Type_Proc: - w = gb_string_appendc(w, "proc"); - if (default_calling_convention() != type->Proc.calling_convention) { - w = gb_string_appendc(w, "\""); - w = gb_string_appendc(w, proc_calling_convention_strings[type->Proc.calling_convention]); - w = gb_string_appendc(w, "\""); - } - - w = write_canonical_params(w, type->Proc.params); - if (type->Proc.result_count > 0) { - w = gb_string_appendc(w, "->"); - w = write_canonical_params(w, type->Proc.results); - } - return w; - - case Type_Generic: - GB_PANIC("Type_Generic should never be hit"); - return w; - - case Type_Named: - if (type->Named.type_name != nullptr) { - Entity *e = type->Named.type_name; - - if ((e->scope->flags & (ScopeFlag_File | ScopeFlag_Pkg)) == 0 || - e->flags & EntityFlag_NotExported) { - if (e->scope->flags & ScopeFlag_Proc) { - GB_PANIC("NESTED IN PROC\n"); - } else if (e->scope->flags & ScopeFlag_File) { - GB_PANIC("PRIVATE TO FILE\n"); - } - } - if (e->pkg != nullptr) { - w = gb_string_append_length(w, e->pkg->name.text, e->pkg->name.len); - w = gb_string_appendc(w, "."); - } - Type *params = nullptr; - Entity *parent = type_get_polymorphic_parent(type, ¶ms); - if (parent) { - w = gb_string_append_length(w, parent->token.string.text, parent->token.string.len); - w = write_canonical_params(w, params); - } else { - w = gb_string_append_length(w, e->token.string.text, e->token.string.len); - } - } else { - w = gb_string_append_length(w, type->Named.name.text, type->Named.name.len); - } - // Handle parapoly stuff here? - return w; - - default: - GB_PANIC("unknown type kind %d", type->kind); - break; - } - - return w; -} \ No newline at end of file -- cgit v1.2.3 From b5cf776830151870730d32323502084d069668c3 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 17 Feb 2025 11:48:54 +0000 Subject: Use new name canonicalization approach --- src/llvm_backend_general.cpp | 6 ++++-- src/name_canonicalization.cpp | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'src/llvm_backend_general.cpp') diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index dc212e51d..6ff166899 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -1568,10 +1568,12 @@ gb_internal String lb_set_nested_type_name_ir_mangled_name(Entity *e, lbProcedur 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; diff --git a/src/name_canonicalization.cpp b/src/name_canonicalization.cpp index fa09f27c0..48f7a18cb 100644 --- a/src/name_canonicalization.cpp +++ b/src/name_canonicalization.cpp @@ -180,7 +180,7 @@ gb_internal gbString write_canonical_entity_name(gbString w, Entity *e) { w = gb_string_appendc(w, gb_bprintf(".[%.*s].", LIT(file_name))); goto write_base_name; } - gb_printf_err("%s HERE %s %u %p\n", token_pos_to_string(e->token.pos), type_to_string(e->type), s->flags, s->decl_info); + 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); print_scope_flags(s); GB_PANIC("weird entity"); } -- cgit v1.2.3 From 043f9aea614b7fe5e1f62014ea34c7d3c155b0cb Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 17 Feb 2025 12:40:43 +0000 Subject: Clean up rules for name mangling --- src/llvm_backend_general.cpp | 162 ++---------------------------------------- src/name_canonicalization.cpp | 81 +++++++++++++++------ 2 files changed, 64 insertions(+), 179 deletions(-) (limited to 'src/llvm_backend_general.cpp') diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index 6ff166899..7fdfa0bb2 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -1443,129 +1443,6 @@ 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) { -#if 1 - 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; -#else - gbString w = gb_string_make(gb_heap_allocator(), ""); - w = write_canonical_entity_name(w, e); - gb_printf_err(">> %s\n", w); - - String mangled_name = make_string(cast(u8 const *)w, gb_string_length(w)); - return mangled_name; -#endif -} - -gb_internal String lb_set_nested_type_name_ir_mangled_name(Entity *e, lbProcedure *p, lbModule *module) { -#if 0 - // 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; - - { - String s = type_to_canonical_string(temporary_allocator(), e->type); - gb_printf_err("1) %.*s\n", LIT(s)); - gb_printf_err("2) %.*s\n", LIT(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 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; - - { - String s = type_to_canonical_string(temporary_allocator(), e->type); - gb_printf_err("3) %.*s\n", LIT(s)); - gb_printf_err("4) %.*s\n", LIT(name)); - } - return name; - } -#endif -} - gb_internal String lb_get_entity_name(lbModule *m, Entity *e) { GB_ASSERT(m != nullptr); GB_ASSERT(e != nullptr); @@ -1579,51 +1456,20 @@ gb_internal String lb_get_entity_name(lbModule *m, Entity *e) { return e->token.string; } -#if 1 gbString w = gb_string_make(heap_allocator(), ""); w = write_canonical_entity_name(w, e); defer (gb_string_free(w)); - String name = copy_string(permanent_allocator(), make_string(cast(u8 const *)w, gb_string_length(w))); -#else - if (e->kind == Entity_TypeName && (e->scope->flags & ScopeFlag_File) == 0) { - return lb_set_nested_type_name_ir_mangled_name(e, nullptr, m); - } - - String name = {}; + gb_printf_err("%s\n", w); - bool no_name_mangle = false; - - if (e->kind == Entity_Variable) { - bool is_foreign = e->Variable.is_foreign; - bool is_export = e->Variable.is_export; - no_name_mangle = e->Variable.link_name.len > 0 || is_foreign || is_export; - if (e->Variable.link_name.len > 0) { - return e->Variable.link_name; - } - } else if (e->kind == Entity_Procedure && e->Procedure.link_name.len > 0) { - return e->Procedure.link_name; - } else if (e->kind == Entity_Procedure && e->Procedure.is_export) { - no_name_mangle = true; - } - - if (!no_name_mangle) { - name = lb_mangle_name(e); + String name = copy_string(permanent_allocator(), make_string(cast(u8 const *)w, gb_string_length(w))); - gbString w = gb_string_make(gb_heap_allocator(), ""); - w = write_canonical_entity_name(w, e); - if (w[0] == 0) { - gb_printf_err(">> %s %.*s\n", w, LIT(name)); - } - } - if (name.len == 0) { - name = e->token.string; - } -#endif 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; diff --git a/src/name_canonicalization.cpp b/src/name_canonicalization.cpp index 48f7a18cb..3910c573d 100644 --- a/src/name_canonicalization.cpp +++ b/src/name_canonicalization.cpp @@ -1,3 +1,43 @@ +/* + 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 - pkg.parent1.parent2.name + * file private - pkg.[file_name].name + * Example: `foo.[bar.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.$anon123 + * 123 is the file offset in bytes + + +*/ + +#define CANONICAL_TYPE_SEPARATOR ":" +#define CANONICAL_NAME_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 "<>" + gb_internal gbString write_type_to_canonical_string(gbString w, Type *type); gb_internal gbString write_canonical_params(gbString w, Type *params) { w = gb_string_appendc(w, "("); @@ -6,25 +46,25 @@ gb_internal gbString write_canonical_params(gbString w, Type *params) { for_array(i, params->Tuple.variables) { Entity *v = params->Tuple.variables[i]; if (i > 0) { - w = gb_string_appendc(w, ","); + w = gb_string_appendc(w, CANONICAL_PARAM_SEPARATOR); } if (v->kind == Entity_Variable) { if (v->flags&EntityFlag_CVarArg) { - w = gb_string_appendc(w, "#c_vararg"); + w = gb_string_appendc(w, CANONICAL_PARAM_C_VARARG); } if (v->flags&EntityFlag_Ellipsis) { Type *slice = base_type(v->type); - w = gb_string_appendc(w, ".."); + w = gb_string_appendc(w, CANONICAL_PARAM_VARARG); GB_ASSERT(v->type->kind == Type_Slice); w = write_type_to_canonical_string(w, slice->Slice.elem); } else { w = write_type_to_canonical_string(w, v->type); } } else if (v->kind == Entity_TypeName) { - w = gb_string_appendc(w, "$"); + w = gb_string_appendc(w, CANONICAL_PARAM_TYPEID); w = write_type_to_canonical_string(w, v->type); } else if (v->kind == Entity_Constant) { - w = gb_string_appendc(w, "$$"); + w = gb_string_appendc(w, CANONICAL_PARAM_CONST); w = write_exact_value_to_string(w, v->Constant.value); } else { GB_PANIC("TODO(bill): handle non type/const parapoly parameter values"); @@ -88,24 +128,24 @@ gb_internal gbString write_canonical_parent_prefix(gbString w, Entity *e, bool i w = write_canonical_parent_prefix(w, p); w = gb_string_append_length(w, p->token.string.text, p->token.string.len); if (is_type_polymorphic(p->type)) { - w = gb_string_appendc(w, "::"); + w = gb_string_appendc(w, CANONICAL_TYPE_SEPARATOR); w = write_type_to_canonical_string(w, p->type); } - w = gb_string_appendc(w, "."); + w = gb_string_appendc(w, CANONICAL_NAME_SEPARATOR); } else if (e->pkg && (scope_lookup_current(e->pkg->scope, e->token.string) == e)) { w = gb_string_append_length(w, e->pkg->name.text, e->pkg->name.len); if (e->pkg->name == "llvm") { gb_string_appendc(w, "$"); } - w = gb_string_appendc(w, "."); + w = gb_string_appendc(w, CANONICAL_NAME_SEPARATOR); } else { String file_name = filename_without_directory(e->file->fullpath); w = gb_string_append_length(w, e->pkg->name.text, e->pkg->name.len); if (e->pkg->name == "llvm") { gb_string_appendc(w, "$"); } - w = gb_string_appendc(w, gb_bprintf(".[%.*s].", LIT(file_name))); + w = gb_string_appendc(w, gb_bprintf(CANONICAL_NAME_SEPARATOR "[%.*s]" CANONICAL_NAME_SEPARATOR, LIT(file_name))); } } else if (e->kind == Entity_Procedure) { if (e->Procedure.is_export || e->Procedure.is_foreign) { @@ -116,17 +156,17 @@ gb_internal gbString write_canonical_parent_prefix(gbString w, Entity *e, bool i } if (e->kind == Entity_Procedure && e->Procedure.is_anonymous) { - w = gb_string_appendc(w, gb_bprintf("$anon%d", e->token.pos.offset)); + w = gb_string_appendc(w, gb_bprintf(CANONICAL_ANON_PREFIX "%d", e->token.pos.offset)); } else { w = gb_string_append_length(w, e->token.string.text, e->token.string.len); } if (is_type_polymorphic(e->type)) { - w = gb_string_appendc(w, "::"); + w = gb_string_appendc(w, CANONICAL_TYPE_SEPARATOR); w = write_type_to_canonical_string(w, e->type); } if (!ignore_final_dot) { - w = gb_string_appendc(w, "."); + w = gb_string_appendc(w, CANONICAL_NAME_SEPARATOR); } return w; @@ -177,7 +217,7 @@ gb_internal gbString write_canonical_entity_name(gbString w, Entity *e) { if (e->pkg->name == "llvm") { gb_string_appendc(w, "$"); } - w = gb_string_appendc(w, gb_bprintf(".[%.*s].", LIT(file_name))); + w = gb_string_appendc(w, gb_bprintf(CANONICAL_NAME_SEPARATOR "[%.*s]" CANONICAL_NAME_SEPARATOR, LIT(file_name))); 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); @@ -186,7 +226,7 @@ gb_internal gbString write_canonical_entity_name(gbString w, Entity *e) { } if (e->pkg != nullptr) { w = gb_string_append_length(w, e->pkg->name.text, e->pkg->name.len); - w = gb_string_appendc(w, "."); + w = gb_string_appendc(w, CANONICAL_NAME_SEPARATOR); } write_base_name: @@ -210,7 +250,7 @@ write_base_name: case Entity_Variable: w = gb_string_append_length(w, e->token.string.text, e->token.string.len); if (is_type_polymorphic(e->type)) { - w = gb_string_appendc(w, "::"); + w = gb_string_appendc(w, CANONICAL_TYPE_SEPARATOR); w = write_type_to_canonical_string(w, e->type); } return w; @@ -225,7 +265,7 @@ write_base_name: // NOTE(bill): This exists so that we deterministically hash a type by serializing it to a canonical string gb_internal gbString write_type_to_canonical_string(gbString w, Type *type) { if (type == nullptr) { - return gb_string_appendc(w, "<>"); // none/void type + return gb_string_appendc(w, CANONICAL_NONE_TYPE); // none/void type } type = default_type(type); @@ -287,7 +327,7 @@ gb_internal gbString write_type_to_canonical_string(gbString w, Type *type) { Entity *f = type->Enum.fields[i]; GB_ASSERT(f->kind == Entity_Constant); if (i > 0) { - w = gb_string_appendc(w, ","); + w = gb_string_appendc(w, CANONICAL_FIELD_SEPARATOR); } w = gb_string_append_length(w, f->token.string.text, f->token.string.len); w = gb_string_appendc(w, "="); @@ -324,7 +364,7 @@ gb_internal gbString write_type_to_canonical_string(gbString w, Type *type) { w = gb_string_appendc(w, "{"); for_array(i, type->Union.variants) { Type *t = type->Union.variants[i]; - if (i > 0) w = gb_string_appendc(w, ", "); + if (i > 0) w = gb_string_appendc(w, CANONICAL_FIELD_SEPARATOR); w = write_type_to_canonical_string(w, t); } return gb_string_appendc(w, "}"); @@ -351,7 +391,7 @@ gb_internal gbString write_type_to_canonical_string(gbString w, Type *type) { Entity *f = type->Struct.fields[i]; GB_ASSERT(f->kind == Entity_Variable); if (i > 0) { - w = gb_string_appendc(w, ","); + w = gb_string_appendc(w, CANONICAL_FIELD_SEPARATOR); } w = gb_string_append_length (w, f->token.string.text, f->token.string.len); w = gb_string_appendc (w, ":"); @@ -372,7 +412,7 @@ gb_internal gbString write_type_to_canonical_string(gbString w, Type *type) { for (isize i = 0; i < type->BitField.fields.count; i++) { Entity *f = type->BitField.fields[i]; if (i > 0) { - w = gb_string_appendc(w, ","); + w = gb_string_appendc(w, CANONICAL_FIELD_SEPARATOR); } w = gb_string_append_length(w, f->token.string.text, f->token.string.len); w = gb_string_appendc(w, ":"); @@ -407,7 +447,6 @@ gb_internal gbString write_type_to_canonical_string(gbString w, Type *type) { } else { w = gb_string_append_length(w, type->Named.name.text, type->Named.name.len); } - // Handle parapoly stuff here? return w; default: -- cgit v1.2.3 From 9b26bb2e6a1e32e17102550b481c6909549b87e5 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 17 Feb 2025 13:10:38 +0000 Subject: Begin work on hash types --- src/checker.cpp | 44 +++++++++++++++++++++++++++++++++++++++++-- src/checker.hpp | 7 ++++++- src/llvm_backend.cpp | 7 ++++--- src/llvm_backend_general.cpp | 2 -- src/llvm_backend_type.cpp | 6 +++--- src/name_canonicalization.cpp | 25 +++++++++++++++++++----- src/ptr_set.cpp | 10 +++++----- src/types.cpp | 36 +++++++++++++++++++++++++++++++++-- 8 files changed, 114 insertions(+), 23 deletions(-) (limited to 'src/llvm_backend_general.cpp') diff --git a/src/checker.cpp b/src/checker.cpp index c74a72a14..054d6aeb0 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); @@ -2037,7 +2040,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); + Type_Info_Type 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); @@ -6725,6 +6729,42 @@ 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("check for type hash collisions"); + { + PtrSet found = {}; + ptr_set_init(&found, c->info.type_info_types.count); + defer (ptr_set_destroy(&found)); + for (auto const &tt : c->info.type_info_types) { + if (ptr_set_update(&found, cast(uintptr)tt.hash)) { + Type *other_type = nullptr; + for (auto const &other : c->info.type_info_types) { + if (&tt == &other) { + continue; + } + if (cast(uintptr)other.hash == cast(uintptr)tt.hash && + !are_types_identical(tt.type, other.type)) { + other_type = other.type; + break; + } + } + if (other_type != nullptr) { + String ts = type_to_canonical_string(temporary_allocator(), tt.type); + String os = type_to_canonical_string(temporary_allocator(), other_type); + if (ts != os) { + compiler_error("%s found type hash collision with %s (hash = %llu)\n" + "%s vs %s\n", + type_to_string(tt.type), type_to_string(other_type), cast(unsigned long long)tt.hash, + temp_canonical_string(tt.type), + temp_canonical_string(other_type) + ); + } + } + } + } + } + + + 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 472ab8e50..c9a0c3302 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -409,6 +409,11 @@ struct Defineable { String pos_str; }; +struct Type_Info_Type { + Type *type; + u64 hash; // see: type_hash_canonical_type +}; + // CheckerInfo stores all the symbol information for a type-checked program struct CheckerInfo { Checker *checker; @@ -453,7 +458,7 @@ struct CheckerInfo { PtrMap gen_types; BlockingMutex type_info_mutex; // NOT recursive - Array type_info_types; + Array type_info_types; PtrMap type_info_map; BlockingMutex foreign_mutex; // NOT recursive diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 0896ea8c7..8cb480dd4 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; @@ -3182,7 +3182,8 @@ 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) { + Type *t = tt.type; isize index = lb_type_info_index(m->info, t, false); if (index < 0) { continue; diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index 7fdfa0bb2..b9ae3d254 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -1460,8 +1460,6 @@ gb_internal String lb_get_entity_name(lbModule *m, Entity *e) { w = write_canonical_entity_name(w, e); defer (gb_string_free(w)); - gb_printf_err("%s\n", w); - String name = copy_string(permanent_allocator(), make_string(cast(u8 const *)w, gb_string_length(w))); if (e->kind == Entity_TypeName) { diff --git a/src/llvm_backend_type.cpp b/src/llvm_backend_type.cpp index 6c12b37be..6f9f94fbd 100644 --- a/src/llvm_backend_type.cpp +++ b/src/llvm_backend_type.cpp @@ -12,7 +12,7 @@ gb_internal isize lb_type_info_index(CheckerInfo *info, Type *type, bool err_on_ 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) { 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[type_info_index].type)); } GB_PANIC("NOT FOUND"); } @@ -280,7 +280,7 @@ 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]; + Type *t = info->type_info_types[type_info_type_index].type; if (t == nullptr || t == t_invalid) { continue; } @@ -343,7 +343,7 @@ gb_internal void lb_setup_type_info_data_giant_array(lbModule *m, i64 global_typ }; for_array(type_info_type_index, info->type_info_types) { - Type *t = info->type_info_types[type_info_type_index]; + Type *t = info->type_info_types[type_info_type_index].type; if (t == nullptr || t == t_invalid) { continue; } diff --git a/src/name_canonicalization.cpp b/src/name_canonicalization.cpp index 3910c573d..8edb5e968 100644 --- a/src/name_canonicalization.cpp +++ b/src/name_canonicalization.cpp @@ -7,7 +7,7 @@ * builtin names - just their normal name e.g. `i32` or `string` * nested - pkg.parent1.parent2.name * file private - pkg.[file_name].name - * Example: `foo.[bar.odin].Type` + * Example: `pkg.[file.odin].Type` * polymorphic procedure/type - pkg.foo::TYPE * naming convention for parameters * type @@ -15,7 +15,7 @@ * $$constant_parameter * Example: `foo.to_thing::proc(u64)->([]u8)` * nested decl in polymorphic procedure - pkg.foo::TYPE.name - * anonymous procedures - pkg.foo.$anon123 + * anonymous procedures - pkg.foo.$anon[file.odin:123] * 123 is the file offset in bytes @@ -38,7 +38,12 @@ #define CANONICAL_NONE_TYPE "<>" + gb_internal gbString write_type_to_canonical_string(gbString w, Type *type); +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 gbString write_canonical_params(gbString w, Type *params) { w = gb_string_appendc(w, "("); if (params) { @@ -81,7 +86,7 @@ gb_internal u64 type_hash_canonical_type(Type *type) { TEMPORARY_ALLOCATOR_GUARD(); gbString w = write_type_to_canonical_string(gb_string_make(temporary_allocator(), ""), type); u64 hash = fnv64a(w, gb_string_length(w)); - return hash; + return hash ? hash : 1; } gb_internal String type_to_canonical_string(gbAllocator allocator, Type *type) { @@ -90,6 +95,11 @@ gb_internal String type_to_canonical_string(gbAllocator allocator, Type *type) { return make_string(cast(u8 const *)w, gb_string_length(w)); } +gb_internal gbString temp_canonical_string(Type *type) { + gbString w = gb_string_make(temporary_allocator(), ""); + return write_type_to_canonical_string(w, type); +} + gb_internal void print_scope_flags(Scope *s) { if (s->flags & ScopeFlag_Pkg) gb_printf_err("Pkg "); if (s->flags & ScopeFlag_Builtin) gb_printf_err("Builtin "); @@ -156,7 +166,8 @@ gb_internal gbString write_canonical_parent_prefix(gbString w, Entity *e, bool i } if (e->kind == Entity_Procedure && e->Procedure.is_anonymous) { - w = gb_string_appendc(w, gb_bprintf(CANONICAL_ANON_PREFIX "%d", e->token.pos.offset)); + String file_name = filename_without_directory(e->file->fullpath); + w = gb_string_appendc(w, gb_bprintf(CANONICAL_ANON_PREFIX "[%.*s:%d]", LIT(file_name), e->token.pos.offset)); } else { w = gb_string_append_length(w, e->token.string.text, e->token.string.len); } @@ -449,8 +460,12 @@ gb_internal gbString write_type_to_canonical_string(gbString w, Type *type) { } return w; + case Type_Tuple: + w = gb_string_appendc(w, "params"); + w = write_canonical_params(w, type); + return w; default: - GB_PANIC("unknown type kind %d", type->kind); + GB_PANIC("unknown type kind %d %.*s", type->kind, LIT(type_strings[type->kind])); break; } 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 *s) { template gb_internal isize ptr_set__find(PtrSet *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 *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 *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::TOMBSTONE || *key == nullptr) { + if (*key == (T)PtrSet::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::TOMBSTONE) { + if (key != 0 && key != (T)PtrSet::TOMBSTONE) { return *this; } } @@ -191,7 +191,7 @@ gb_internal PtrSetIterator begin(PtrSet &set) noexcept { usize index = 0; while (index < set.capacity) { T key = set.keys[index]; - if (key != nullptr && key != (T)PtrSet::TOMBSTONE) { + if (key != 0 && key != (T)PtrSet::TOMBSTONE) { break; } index++; diff --git a/src/types.cpp b/src/types.cpp index d6dea56ad..15e1bcf45 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -2774,7 +2774,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 && @@ -2832,7 +2862,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; -- cgit v1.2.3 From 23efd1bd02703e12a4d97c2d7194d1175a28d56c Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 18 Feb 2025 14:21:40 +0000 Subject: Add `TypeWriter` stream to allow for in-place hashing and string generation --- src/checker.hpp | 56 +---- src/common.cpp | 4 +- src/llvm_backend_general.cpp | 4 +- src/name_canonicalization.cpp | 480 +++++++++++++++++++++++------------------- src/name_canonicalization.hpp | 88 ++++++++ 5 files changed, 361 insertions(+), 271 deletions(-) create mode 100644 src/name_canonicalization.hpp (limited to 'src/llvm_backend_general.cpp') diff --git a/src/checker.hpp b/src/checker.hpp index b8878d745..8850d5c3f 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -167,61 +167,7 @@ typedef DECL_ATTRIBUTE_PROC(DeclAttributeProc); gb_internal void check_decl_attributes(CheckerContext *c, Array const &attributes, DeclAttributeProc *proc, AttributeContext *ac); -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; - +#include "name_canonicalization.hpp" enum ProcCheckedState : u8 { ProcCheckedState_Unchecked, 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/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index b9ae3d254..233448ece 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -1456,11 +1456,11 @@ gb_internal String lb_get_entity_name(lbModule *m, Entity *e) { return e->token.string; } - gbString w = gb_string_make(heap_allocator(), ""); - w = write_canonical_entity_name(w, e); + gbString w = string_canonical_entity_name(heap_allocator(), e); defer (gb_string_free(w)); String name = copy_string(permanent_allocator(), make_string(cast(u8 const *)w, gb_string_length(w))); + gb_printf_err("%.*s\n", LIT(name)); if (e->kind == Entity_TypeName) { e->TypeName.ir_mangled_name = name; diff --git a/src/name_canonicalization.cpp b/src/name_canonicalization.cpp index ef0e23f38..9c2858170 100644 --- a/src/name_canonicalization.cpp +++ b/src/name_canonicalization.cpp @@ -21,33 +21,6 @@ */ -#define CANONICAL_TYPE_SEPARATOR ":" -#define CANONICAL_NAME_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 "<>" - - -gb_internal gbString write_type_to_canonical_string(gbString w, Type *type); -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); - - -struct TypeInfoPair; -struct TypeSet; - gb_internal GB_COMPARE_PROC(type_info_pair_cmp) { TypeInfoPair *x = cast(TypeInfoPair *)a; TypeInfoPair *y = cast(TypeInfoPair *)b; @@ -57,16 +30,6 @@ gb_internal GB_COMPARE_PROC(type_info_pair_cmp) { return x->hash < y->hash ? -1 : +1; } -gb_internal void type_set_init (TypeSet *s, isize capacity); -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 gbAllocator type_set_allocator(void) { return heap_allocator(); @@ -251,63 +214,138 @@ gb_internal gb_inline void type_set_clear(TypeSet *s) { } -gb_internal gbString write_canonical_params(gbString w, Type *params) { - w = gb_string_appendc(w, "("); +#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, "("); if (params) { GB_ASSERT(params->kind == Type_Tuple); for_array(i, params->Tuple.variables) { Entity *v = params->Tuple.variables[i]; if (i > 0) { - w = gb_string_appendc(w, CANONICAL_PARAM_SEPARATOR); + type_writer_appendc(w, CANONICAL_PARAM_SEPARATOR); } - w = gb_string_append_length(w, v->token.string.text, v->token.string.len); - w = gb_string_appendc(w, CANONICAL_TYPE_SEPARATOR); + type_writer_append(w, v->token.string.text, v->token.string.len); + type_writer_appendc(w, CANONICAL_TYPE_SEPARATOR); if (v->kind == Entity_Variable) { if (v->flags&EntityFlag_CVarArg) { - w = gb_string_appendc(w, CANONICAL_PARAM_C_VARARG); + type_writer_appendc(w, CANONICAL_PARAM_C_VARARG); } if (v->flags&EntityFlag_Ellipsis) { Type *slice = base_type(v->type); - w = gb_string_appendc(w, CANONICAL_PARAM_VARARG); + type_writer_appendc(w, CANONICAL_PARAM_VARARG); GB_ASSERT(v->type->kind == Type_Slice); - w = write_type_to_canonical_string(w, slice->Slice.elem); + write_type_to_canonical_string(w, slice->Slice.elem); } else { - w = write_type_to_canonical_string(w, v->type); + write_type_to_canonical_string(w, v->type); } } else if (v->kind == Entity_TypeName) { - w = gb_string_appendc(w, CANONICAL_PARAM_TYPEID); - w = write_type_to_canonical_string(w, v->type); + type_writer_appendc(w, CANONICAL_PARAM_TYPEID); + write_type_to_canonical_string(w, v->type); } else if (v->kind == Entity_Constant) { - w = gb_string_appendc(w, CANONICAL_PARAM_CONST); - w = write_exact_value_to_string(w, v->Constant.value); + 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); } else { GB_PANIC("TODO(bill): handle non type/const parapoly parameter values"); } } } - return gb_string_appendc(w, ")"); + type_writer_appendc(w, ")"); + return; } gb_internal u64 type_hash_canonical_type(Type *type) { if (type == nullptr) { return 0; } - TEMPORARY_ALLOCATOR_GUARD(); - gbString w = write_type_to_canonical_string(gb_string_make(temporary_allocator(), ""), type); - u64 hash = fnv64a(w, gb_string_length(w)); + 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) { - gbString w = gb_string_make(allocator, ""); - w = write_type_to_canonical_string(w, type); - return make_string(cast(u8 const *)w, gb_string_length(w)); + 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) { - gbString w = gb_string_make(temporary_allocator(), ""); - return write_type_to_canonical_string(w, 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 void print_scope_flags(Scope *s) { @@ -323,77 +361,74 @@ gb_internal void print_scope_flags(Scope *s) { gb_printf_err("\n"); } +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 gbString write_canonical_parent_prefix(gbString w, Entity *e, bool ignore_final_dot=false) { +gb_internal void write_canonical_parent_prefix(TypeWriter *w, Entity *e, bool ignore_final_dot=false) { GB_ASSERT(e != nullptr); - // auto const &parent_entity = [](Scope *s) -> Entity* { - // while ((s->flags & (ScopeFlag_Proc|ScopeFlag_File)) == 0 && s->decl_info == nullptr) { - // s = s->parent; - // } - // if (s->decl_info && s->decl_info->entity) { - // return s->decl_info->entity; - // } - // return nullptr; - // }; - if (e->kind == Entity_Procedure) { if (e->Procedure.is_export || e->Procedure.is_foreign) { // no prefix - return w; + return; } if (e->parent_proc_decl) { Entity *p = e->parent_proc_decl->entity; - w = write_canonical_parent_prefix(w, p); - w = gb_string_append_length(w, p->token.string.text, p->token.string.len); + write_canonical_parent_prefix(w, p); + type_writer_append(w, p->token.string.text, p->token.string.len); if (is_type_polymorphic(p->type)) { - w = gb_string_appendc(w, CANONICAL_TYPE_SEPARATOR); - w = write_type_to_canonical_string(w, p->type); + type_writer_appendc(w, CANONICAL_TYPE_SEPARATOR); + write_type_to_canonical_string(w, p->type); } - w = gb_string_appendc(w, CANONICAL_NAME_SEPARATOR); + type_writer_appendc(w, CANONICAL_NAME_SEPARATOR); } else if (e->pkg && (scope_lookup_current(e->pkg->scope, e->token.string) == e)) { - w = gb_string_append_length(w, e->pkg->name.text, e->pkg->name.len); + type_writer_append(w, e->pkg->name.text, e->pkg->name.len); if (e->pkg->name == "llvm") { - gb_string_appendc(w, "$"); + type_writer_appendc(w, "$"); } - w = gb_string_appendc(w, CANONICAL_NAME_SEPARATOR); + type_writer_appendc(w, CANONICAL_NAME_SEPARATOR); } else { String file_name = filename_without_directory(e->file->fullpath); - w = gb_string_append_length(w, e->pkg->name.text, e->pkg->name.len); + type_writer_append(w, e->pkg->name.text, e->pkg->name.len); if (e->pkg->name == "llvm") { - gb_string_appendc(w, "$"); + type_writer_appendc(w, "$"); } - w = gb_string_appendc(w, gb_bprintf(CANONICAL_NAME_SEPARATOR "[%.*s]" CANONICAL_NAME_SEPARATOR, LIT(file_name))); + type_writer_appendc(w, gb_bprintf(CANONICAL_NAME_SEPARATOR "[%.*s]" CANONICAL_NAME_SEPARATOR, LIT(file_name))); } } else if (e->kind == Entity_Procedure) { if (e->Procedure.is_export || e->Procedure.is_foreign) { // no prefix - return w; + return; } 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); - w = gb_string_appendc(w, gb_bprintf(CANONICAL_ANON_PREFIX "[%.*s:%d]", LIT(file_name), e->token.pos.offset)); + type_writer_appendc(w, gb_bprintf(CANONICAL_ANON_PREFIX "[%.*s:%d]", LIT(file_name), e->token.pos.offset)); } else { - w = gb_string_append_length(w, e->token.string.text, e->token.string.len); + type_writer_append(w, e->token.string.text, e->token.string.len); } if (is_type_polymorphic(e->type)) { - w = gb_string_appendc(w, CANONICAL_TYPE_SEPARATOR); - w = write_type_to_canonical_string(w, e->type); + type_writer_appendc(w, CANONICAL_TYPE_SEPARATOR); + write_type_to_canonical_string(w, e->type); } if (!ignore_final_dot) { - w = gb_string_appendc(w, CANONICAL_NAME_SEPARATOR); + type_writer_appendc(w, CANONICAL_NAME_SEPARATOR); } - return w; + return; } -gb_internal gbString write_canonical_entity_name(gbString w, Entity *e) { +gb_internal void write_canonical_entity_name(TypeWriter *w, Entity *e) { GB_ASSERT(e != nullptr); if (e->token.string == "_") { @@ -407,18 +442,18 @@ gb_internal gbString write_canonical_entity_name(gbString w, Entity *e) { bool is_foreign = e->Variable.is_foreign; bool is_export = e->Variable.is_export; if (e->Variable.link_name.len > 0) { - w = gb_string_append_length(w, e->Variable.link_name.text, e->Variable.link_name.len); - return w; + type_writer_append(w, e->Variable.link_name.text, e->Variable.link_name.len); + return; } else if (is_foreign || is_export) { - w = gb_string_append_length(w, e->token.string.text, e->token.string.len); - return w; + 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) { - w = gb_string_append_length(w, e->Procedure.link_name.text, e->Procedure.link_name.len); - return w; + 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) { - w = gb_string_append_length(w, e->token.string.text, e->token.string.len); - return w; + type_writer_append(w, e->token.string.text, e->token.string.len); + return; } if ((e->scope->flags & (ScopeFlag_File | ScopeFlag_Pkg)) == 0 || @@ -430,15 +465,15 @@ gb_internal gbString write_canonical_entity_name(gbString w, Entity *e) { } if (s->decl_info != nullptr && s->decl_info->entity) { - w = write_canonical_parent_prefix(w, s->decl_info->entity); + write_canonical_parent_prefix(w, s->decl_info->entity); goto write_base_name; } else if ((s->flags & ScopeFlag_File) && s->file != nullptr) { String file_name = filename_without_directory(s->file->fullpath); - w = gb_string_append_length(w, e->pkg->name.text, e->pkg->name.len); + type_writer_append(w, e->pkg->name.text, e->pkg->name.len); if (e->pkg->name == "llvm") { - gb_string_appendc(w, "$"); + type_writer_appendc(w, "$"); } - w = gb_string_appendc(w, gb_bprintf(CANONICAL_NAME_SEPARATOR "[%.*s]" CANONICAL_NAME_SEPARATOR, LIT(file_name))); + type_writer_appendc(w, gb_bprintf(CANONICAL_NAME_SEPARATOR "[%.*s]" CANONICAL_NAME_SEPARATOR, LIT(file_name))); 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); @@ -446,8 +481,8 @@ gb_internal gbString write_canonical_entity_name(gbString w, Entity *e) { GB_PANIC("weird entity"); } if (e->pkg != nullptr) { - w = gb_string_append_length(w, e->pkg->name.text, e->pkg->name.len); - w = gb_string_appendc(w, CANONICAL_NAME_SEPARATOR); + type_writer_append(w, e->pkg->name.text, e->pkg->name.len); + type_writer_appendc(w, CANONICAL_NAME_SEPARATOR); } write_base_name: @@ -459,37 +494,38 @@ write_base_name: Type *params = nullptr; Entity *parent = type_get_polymorphic_parent(e->type, ¶ms); if (parent && (parent->token.string == e->token.string)) { - w = gb_string_append_length(w, parent->token.string.text, parent->token.string.len); - w = write_canonical_params(w, params); + type_writer_append(w, parent->token.string.text, parent->token.string.len); + write_canonical_params(w, params); } else { - w = gb_string_append_length(w, e->token.string.text, e->token.string.len); + type_writer_append(w, e->token.string.text, e->token.string.len); } gb_unused(parent); } // Handle parapoly stuff here? - return w; + return; case Entity_Procedure: case Entity_Variable: - w = gb_string_append_length(w, e->token.string.text, e->token.string.len); + type_writer_append(w, e->token.string.text, e->token.string.len); if (is_type_polymorphic(e->type)) { - w = gb_string_appendc(w, CANONICAL_TYPE_SEPARATOR); - w = write_type_to_canonical_string(w, e->type); + type_writer_appendc(w, CANONICAL_TYPE_SEPARATOR); + write_type_to_canonical_string(w, e->type); } - return w; + return; default: GB_PANIC("TODO(bill): entity kind %d", e->kind); break; } - return w; + return; } // NOTE(bill): This exists so that we deterministically hash a type by serializing it to a canonical string -gb_internal gbString write_type_to_canonical_string(gbString w, Type *type) { +gb_internal void write_type_to_canonical_string(TypeWriter *w, Type *type) { if (type == nullptr) { - return gb_string_appendc(w, CANONICAL_NONE_TYPE); // none/void type + type_writer_appendc(w, CANONICAL_NONE_TYPE); // none/void type + return; } type = default_type(type); @@ -497,190 +533,210 @@ gb_internal gbString write_type_to_canonical_string(gbString w, Type *type) { switch (type->kind) { case Type_Basic: - return gb_string_append_length(w, type->Basic.name.text, type->Basic.name.len); + type_writer_append(w, type->Basic.name.text, type->Basic.name.len); + return; case Type_Pointer: - w = gb_string_append_rune(w, '^'); - return write_type_to_canonical_string(w, type->Pointer.elem); + type_writer_appendb(w, '^'); + write_type_to_canonical_string(w, type->Pointer.elem); + return; case Type_MultiPointer: - w = gb_string_appendc(w, "[^]"); - return write_type_to_canonical_string(w, type->Pointer.elem); + type_writer_appendc(w, "[^]"); + write_type_to_canonical_string(w, type->Pointer.elem); + return; case Type_SoaPointer: - w = gb_string_appendc(w, "#soa^"); - return write_type_to_canonical_string(w, type->Pointer.elem); + type_writer_appendc(w, "#soa^"); + write_type_to_canonical_string(w, type->Pointer.elem); + return; case Type_EnumeratedArray: if (type->EnumeratedArray.is_sparse) { - w = gb_string_appendc(w, "#sparse"); + type_writer_appendc(w, "#sparse"); } - w = gb_string_append_rune(w, '['); - w = write_type_to_canonical_string(w, type->EnumeratedArray.index); - w = gb_string_append_rune(w, ']'); - return write_type_to_canonical_string(w, type->EnumeratedArray.elem); + 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: - w = gb_string_appendc(w, gb_bprintf("[%lld]", cast(long long)type->Array.count)); - return write_type_to_canonical_string(w, type->Array.elem); + 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: - w = gb_string_appendc(w, "[]"); - return write_type_to_canonical_string(w, type->Array.elem); + type_writer_appendc(w, "[]"); + write_type_to_canonical_string(w, type->Array.elem); + return; case Type_DynamicArray: - w = gb_string_appendc(w, "[dynamic]"); - return write_type_to_canonical_string(w, type->DynamicArray.elem); + type_writer_appendc(w, "[dynamic]"); + write_type_to_canonical_string(w, type->DynamicArray.elem); + return; case Type_SimdVector: - w = gb_string_appendc(w, gb_bprintf("#simd[%lld]", cast(long long)type->SimdVector.count)); - return write_type_to_canonical_string(w, type->SimdVector.elem); + 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) { - w = gb_string_appendc(w, "#row_major "); + type_writer_appendc(w, "#row_major "); } - w = gb_string_appendc(w, gb_bprintf("matrix[%lld, %lld]", cast(long long)type->Matrix.row_count, cast(long long)type->Matrix.column_count)); - return write_type_to_canonical_string(w, type->Matrix.elem); + 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: - w = gb_string_appendc(w, "map["); - w = write_type_to_canonical_string(w, type->Map.key); - w = gb_string_appendc(w, "]"); - return write_type_to_canonical_string(w, type->Map.value); + 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: - w = gb_string_appendc(w, "enum"); + type_writer_appendc(w, "enum"); if (type->Enum.base_type != nullptr) { - w = gb_string_append_rune(w, ' '); - w = write_type_to_canonical_string(w, type->Enum.base_type); - w = gb_string_append_rune(w, ' '); + type_writer_appendb(w, ' '); + write_type_to_canonical_string(w, type->Enum.base_type); + type_writer_appendb(w, ' '); } - w = gb_string_append_rune(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) { - w = gb_string_appendc(w, CANONICAL_FIELD_SEPARATOR); + type_writer_appendc(w, CANONICAL_FIELD_SEPARATOR); } - w = gb_string_append_length(w, f->token.string.text, f->token.string.len); - w = gb_string_appendc(w, "="); - w = write_exact_value_to_string(w, f->Constant.value); + 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); } - return gb_string_append_rune(w, '}'); + type_writer_appendb(w, '}'); + return; case Type_BitSet: - w = gb_string_appendc(w, "bit_set["); + type_writer_appendc(w, "bit_set["); if (type->BitSet.elem == nullptr) { - w = write_type_to_canonical_string(w, type->BitSet.elem); + type_writer_appendc(w, CANONICAL_NONE_TYPE); } else if (is_type_enum(type->BitSet.elem)) { - w = write_type_to_canonical_string(w, type->BitSet.elem); + write_type_to_canonical_string(w, type->BitSet.elem); } else { - w = gb_string_append_fmt(w, "%lld", type->BitSet.lower); - w = gb_string_append_fmt(w, "..="); - w = gb_string_append_fmt(w, "%lld", type->BitSet.upper); + 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) { - w = gb_string_appendc(w, ";"); - w = write_type_to_canonical_string(w, type->BitSet.underlying); + type_writer_appendc(w, ";"); + write_type_to_canonical_string(w, type->BitSet.underlying); } - return gb_string_appendc(w, "]"); + type_writer_appendc(w, "]"); + return; case Type_Union: - w = gb_string_appendc(w, "union"); + type_writer_appendc(w, "union"); switch (type->Union.kind) { - case UnionType_no_nil: w = gb_string_appendc(w, "#no_nil"); break; - case UnionType_shared_nil: w = gb_string_appendc(w, "#shared_nil"); break; + 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) { - w = gb_string_append_fmt(w, "#align(%lld)", cast(long long)type->Union.custom_align); + type_writer_append_fmt(w, "#align(%lld)", cast(long long)type->Union.custom_align); } - w = gb_string_appendc(w, "{"); + type_writer_appendc(w, "{"); for_array(i, type->Union.variants) { Type *t = type->Union.variants[i]; - if (i > 0) w = gb_string_appendc(w, CANONICAL_FIELD_SEPARATOR); - w = write_type_to_canonical_string(w, t); + if (i > 0) type_writer_appendc(w, CANONICAL_FIELD_SEPARATOR); + write_type_to_canonical_string(w, t); } - return gb_string_appendc(w, "}"); + type_writer_appendc(w, "}"); + return; case Type_Struct: if (type->Struct.soa_kind != StructSoa_None) { switch (type->Struct.soa_kind) { - case StructSoa_Fixed: w = gb_string_append_fmt(w, "#soa[%lld]", cast(long long)type->Struct.soa_count); break; - case StructSoa_Slice: w = gb_string_appendc(w, "#soa[]"); break; - case StructSoa_Dynamic: w = gb_string_appendc(w, "#soa[dynamic]"); break; + 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); } - w = gb_string_appendc(w, "struct"); - if (type->Struct.is_packed) w = gb_string_appendc(w, "#packed"); - if (type->Struct.is_raw_union) w = gb_string_appendc(w, "#raw_union"); - if (type->Struct.is_no_copy) w = gb_string_appendc(w, "#no_copy"); - if (type->Struct.custom_min_field_align != 0) w = gb_string_append_fmt(w, "#min_field_align(%lld)", cast(long long)type->Struct.custom_min_field_align); - if (type->Struct.custom_max_field_align != 0) w = gb_string_append_fmt(w, "#max_field_align(%lld)", cast(long long)type->Struct.custom_max_field_align); - if (type->Struct.custom_align != 0) w = gb_string_append_fmt(w, "#align(%lld)", cast(long long)type->Struct.custom_align); - w = gb_string_appendc(w, "{"); + 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) { - w = gb_string_appendc(w, CANONICAL_FIELD_SEPARATOR); + type_writer_appendc(w, CANONICAL_FIELD_SEPARATOR); } - w = gb_string_append_length (w, f->token.string.text, f->token.string.len); - w = gb_string_appendc (w, ":"); - w = write_type_to_canonical_string(w, f->type); + 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 = type->Struct.tags[i]; if (tag.len != 0) { String s = quote_to_ascii(heap_allocator(), tag); - w = gb_string_append_length(w, s.text, s.len); + type_writer_append(w, s.text, s.len); gb_free(heap_allocator(), s.text); } } - return gb_string_appendc(w, "}"); + type_writer_appendb(w, '}'); + return; case Type_BitField: - w = gb_string_appendc(w, "bit_field"); - w = write_type_to_canonical_string(w, type->BitField.backing_type); - w = gb_string_appendc(w, " {"); + 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) { - w = gb_string_appendc(w, CANONICAL_FIELD_SEPARATOR); + type_writer_appendc(w, CANONICAL_FIELD_SEPARATOR); } - w = gb_string_append_length(w, f->token.string.text, f->token.string.len); - w = gb_string_appendc(w, ":"); - w = write_type_to_canonical_string(w, f->type); - w = gb_string_appendc(w, "|"); - w = gb_string_appendc(w, gb_bprintf("%u", type->BitField.bit_sizes[i])); + 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]); } - return gb_string_appendc(w, " }"); + type_writer_appendc(w, " }"); + return; case Type_Proc: - w = gb_string_appendc(w, "proc"); + type_writer_appendc(w, "proc"); if (default_calling_convention() != type->Proc.calling_convention) { - w = gb_string_appendc(w, "\""); - w = gb_string_appendc(w, proc_calling_convention_strings[type->Proc.calling_convention]); - w = gb_string_appendc(w, "\""); + type_writer_appendc(w, "\""); + type_writer_appendc(w, proc_calling_convention_strings[type->Proc.calling_convention]); + type_writer_appendc(w, "\""); } - w = write_canonical_params(w, type->Proc.params); + write_canonical_params(w, type->Proc.params); if (type->Proc.result_count > 0) { - w = gb_string_appendc(w, "->"); - w = write_canonical_params(w, type->Proc.results); + type_writer_appendc(w, "->"); + write_canonical_params(w, type->Proc.results); } - return w; + return; case Type_Generic: GB_PANIC("Type_Generic should never be hit"); - return w; + return; case Type_Named: if (type->Named.type_name != nullptr) { - return write_canonical_entity_name(w, type->Named.type_name); + write_canonical_entity_name(w, type->Named.type_name); + return; } else { - w = gb_string_append_length(w, type->Named.name.text, type->Named.name.len); + type_writer_append(w, type->Named.name.text, type->Named.name.len); } - return w; + return; case Type_Tuple: - w = gb_string_appendc(w, "params"); - w = write_canonical_params(w, type); - return w; + 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 w; + 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..620665cd2 --- /dev/null +++ b/src/name_canonicalization.hpp @@ -0,0 +1,88 @@ + +#define CANONICAL_TYPE_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; -- cgit v1.2.3 From 481745784f82c36b8233985768570b5a992656f5 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 18 Feb 2025 15:04:02 +0000 Subject: Remove debug print --- src/llvm_backend_general.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'src/llvm_backend_general.cpp') diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index 233448ece..4f6fcb88e 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -1460,7 +1460,6 @@ gb_internal String lb_get_entity_name(lbModule *m, Entity *e) { defer (gb_string_free(w)); String name = copy_string(permanent_allocator(), make_string(cast(u8 const *)w, gb_string_length(w))); - gb_printf_err("%.*s\n", LIT(name)); if (e->kind == Entity_TypeName) { e->TypeName.ir_mangled_name = name; -- cgit v1.2.3 From e8c38e74274b57a5de71d983ce9231bb7d27458e Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 20 Feb 2025 17:50:56 +0000 Subject: Handle `any` correctly for 32-bit systems --- src/llvm_backend_general.cpp | 19 ++++++++++++++----- src/llvm_backend_utility.cpp | 7 +++++++ 2 files changed, 21 insertions(+), 5 deletions(-) (limited to 'src/llvm_backend_general.cpp') diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index 4f6fcb88e..49e2ba9e8 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -1784,11 +1784,20 @@ 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; } diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp index aa425a9d5..0ba95bb1e 100644 --- a/src/llvm_backend_utility.cpp +++ b/src/llvm_backend_utility.cpp @@ -971,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: -- cgit v1.2.3 From bf9f2e43bf46cc1898352fceb8ee90660dafbcac Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 20 Feb 2025 18:47:41 +0000 Subject: Fix typeid size in LLVM --- src/llvm_backend_general.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/llvm_backend_general.cpp') diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index 49e2ba9e8..94a9023d1 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -1801,7 +1801,7 @@ gb_internal LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { 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); -- cgit v1.2.3 From f0f395c510a7b0c625b0a222d00ddbe4c63a496b Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 24 Feb 2025 14:24:06 +0000 Subject: Fix canonicalization --- src/llvm_backend.cpp | 19 ++++++++++++------- src/llvm_backend.hpp | 2 +- src/llvm_backend_general.cpp | 26 ++++++++++++++++++++++++++ 3 files changed, 39 insertions(+), 8 deletions(-) (limited to 'src/llvm_backend_general.cpp') diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 9bbcc2184..fc56044d3 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -233,7 +233,7 @@ gb_internal lbContextData *lb_push_context_onto_stack(lbProcedure *p, lbAddr ctx } -gb_internal String lb_internal_gen_proc_name_from_type(char const *prefix, Type *type) { +gb_internal String lb_internal_gen_name_from_type(char const *prefix, Type *type) { gbString str = gb_string_make(permanent_allocator(), prefix); gbString tcs = temp_canonical_string(type); str = gb_string_appendc(str, CANONICAL_TYPE_SEPARATOR); @@ -259,7 +259,10 @@ gb_internal lbValue lb_equal_proc_for_type(lbModule *m, Type *type) { } - String proc_name = lb_internal_gen_proc_name_from_type("__$equal", type); + String proc_name = lb_internal_gen_name_from_type("__$equal", type); + lbProcedure *p = lb_create_dummy_procedure(m, proc_name, t_equal_proc); + map_set(&m->equal_procs, type, p); + lb_begin_procedure_body(p); // lb_add_attribute_to_proc(m, p->value, "readonly"); lb_add_attribute_to_proc(m, p->value, "nounwind"); @@ -418,7 +421,7 @@ gb_internal lbValue lb_hasher_proc_for_type(lbModule *m, Type *type) { return {(*found)->value, (*found)->type}; } - String proc_name = lb_internal_gen_proc_name_from_type("__$hasher", type); + String proc_name = lb_internal_gen_name_from_type("__$hasher", type); lbProcedure *p = lb_create_dummy_procedure(m, proc_name, t_hasher_proc); map_set(&m->hasher_procs, type, p); @@ -581,7 +584,7 @@ gb_internal lbValue lb_map_get_proc_for_type(lbModule *m, Type *type) { return {(*found)->value, (*found)->type}; } - String proc_name = lb_internal_gen_proc_name_from_type("__$map_get", type); + String proc_name = lb_internal_gen_name_from_type("__$map_get", type); lbProcedure *p = lb_create_dummy_procedure(m, proc_name, t_map_get_proc); map_set(&m->map_get_procs, type, p); @@ -758,7 +761,7 @@ gb_internal lbValue lb_map_set_proc_for_type(lbModule *m, Type *type) { return {(*found)->value, (*found)->type}; } - String proc_name = lb_internal_gen_proc_name_from_type("__$map_set", type); + String proc_name = lb_internal_gen_name_from_type("__$map_set", type); lbProcedure *p = lb_create_dummy_procedure(m, proc_name, t_map_set_proc); map_set(&m->map_set_procs, type, p); @@ -906,7 +909,9 @@ 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_add_global_generated(m, t_map_cell_info, res, nullptr); lb_make_global_private_const(addr); map_set(&m->map_cell_info_map, type, addr); @@ -937,7 +942,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); diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index d596c2d5c..60ae91f9b 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -610,7 +610,7 @@ gb_internal LLVMTypeRef llvm_array_type(LLVMTypeRef ElementType, uint64_t Elemen } -gb_internal String lb_internal_gen_proc_name_from_type(char const *prefix, Type *type); +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); diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index 94a9023d1..96572437c 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -2814,6 +2814,32 @@ gb_internal lbAddr lb_add_global_generated(lbModule *m, Type *type, lbValue valu return lb_addr(g); } +gb_internal lbAddr lb_add_global_generated_with_name(lbModule *m, Type *type, lbValue value, String name) { + 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); + + Scope *scope = nullptr; + Entity *e = alloc_entity_variable(scope, make_token_ident(name), type); + lbValue g = {}; + g.type = alloc_type_pointer(type); + g.value = LLVMAddGlobal(m->mod, lb_type(m, type), cast(char const *)str); + if (value.value != nullptr) { + GB_ASSERT_MSG(LLVMIsConstant(value.value), LLVMPrintValueToString(value.value)); + LLVMSetInitializer(g.value, value.value); + } else { + LLVMSetInitializer(g.value, LLVMConstNull(lb_type(m, type))); + } + + lb_add_entity(m, e, g); + lb_add_member(m, name, g); + + return lb_addr(g); +} + + 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); -- cgit v1.2.3 From 83f1c879ecce5ca586f99c89d9d6b89c22555921 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 24 Feb 2025 15:18:27 +0000 Subject: Canonicalize generated procedures (hasher/equal/map) --- src/llvm_backend.cpp | 57 ++++++++++++++++++-------------------------- src/llvm_backend.hpp | 5 +--- src/llvm_backend_general.cpp | 5 +--- 3 files changed, 25 insertions(+), 42 deletions(-) (limited to 'src/llvm_backend_general.cpp') diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 4c4dc4c51..24807a9ba 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -235,9 +235,9 @@ 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); - gbString tcs = temp_canonical_string(type); - str = gb_string_appendc(str, CANONICAL_TYPE_SEPARATOR); - str = gb_string_append_length(str, tcs, gb_string_length(tcs)); + 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; } @@ -250,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; @@ -259,11 +260,11 @@ gb_internal lbValue lb_equal_proc_for_type(lbModule *m, Type *type) { } - String proc_name = lb_internal_gen_name_from_type("__$equal", type); 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"); @@ -415,19 +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}; } - String proc_name = lb_internal_gen_name_from_type("__$hasher", type); - 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"); @@ -577,17 +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}; } - String proc_name = lb_internal_gen_name_from_type("__$map_get", type); - 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)); @@ -754,17 +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}; } - String proc_name = lb_internal_gen_name_from_type("__$map_set", type); - 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)); @@ -1558,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; diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index 60ae91f9b..3617c267f 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -180,10 +180,7 @@ struct lbModule { PtrMap function_type_map; - PtrMap equal_procs; - PtrMap hasher_procs; - PtrMap map_get_procs; - PtrMap map_set_procs; + StringMap gen_procs; // key is the canonicalized name std::atomic nested_type_name_guid; diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index 96572437c..80856ac8c 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -67,10 +67,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); -- cgit v1.2.3 From f9d85a731161c2285844be520e48f8cf8d41bc78 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 25 Feb 2025 14:29:14 +0000 Subject: Try to make globally generated variables deterministic in name --- src/llvm_backend.hpp | 5 ++++- src/llvm_backend_expr.cpp | 8 ++++---- src/llvm_backend_general.cpp | 35 +++++++++++------------------------ src/llvm_backend_proc.cpp | 6 +++--- src/llvm_backend_utility.cpp | 15 +++++++++++++-- 5 files changed, 35 insertions(+), 34 deletions(-) (limited to 'src/llvm_backend_general.cpp') diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index b455bf4e8..d18395127 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -361,6 +361,8 @@ struct lbProcedure { bool in_multi_assignment; Array raw_input_parameters; + u32 global_generated_index; + bool uses_branch_location; TokenPos branch_location_pos; TokenPos curr_token_pos; @@ -470,7 +472,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); diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index b4e5c2a44..56c7b45ec 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -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); @@ -3264,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); } @@ -3851,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)); diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index 80856ac8c..54c1f5c38 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -1007,7 +1007,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; @@ -2779,18 +2779,13 @@ 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(type != nullptr); type = default_type(type); isize max_len = 7+8+1; u8 *str = cast(u8 *)gb_alloc_array(permanent_allocator(), u8, max_len); - u32 id = m->gen->global_generated_index.fetch_add(1); - - isize len = gb_snprintf(cast(char *)str, max_len, "ggv$%x", id); - String name = make_string(str, len-1); - Scope *scope = nullptr; Entity *e = alloc_entity_variable(scope, make_token_ident(name), type); lbValue g = {}; @@ -2811,32 +2806,24 @@ gb_internal lbAddr lb_add_global_generated(lbModule *m, Type *type, lbValue valu return lb_addr(g); } -gb_internal lbAddr lb_add_global_generated_with_name(lbModule *m, Type *type, lbValue value, String name) { + +gb_internal lbAddr lb_add_global_generated_from_procedure(lbProcedure *p, Type *type, lbValue value) { 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 index = ++p->global_generated_index; - Scope *scope = nullptr; - Entity *e = alloc_entity_variable(scope, make_token_ident(name), type); - lbValue g = {}; - g.type = alloc_type_pointer(type); - g.value = LLVMAddGlobal(m->mod, lb_type(m, type), cast(char const *)str); - if (value.value != nullptr) { - GB_ASSERT_MSG(LLVMIsConstant(value.value), LLVMPrintValueToString(value.value)); - LLVMSetInitializer(g.value, value.value); - } else { - LLVMSetInitializer(g.value, LLVMConstNull(lb_type(m, type))); - } + gbString s = gb_string_make(temporary_allocator(), "ggv$"); + s = gb_string_append_length(s, p->name.text, p->name.len); + s = gb_string_append_fmt(s, "$%u", index); - lb_add_entity(m, e, g); - lb_add_member(m, name, g); - return lb_addr(g); + 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); diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 7efed98b4..3cfdf00f5 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -1119,7 +1119,7 @@ gb_internal lbValue lb_emit_call(lbProcedure *p, lbValue value, Array 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 { @@ -1874,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; @@ -1882,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); diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp index 0ba95bb1e..9624a78e6 100644 --- a/src/llvm_backend_utility.cpp +++ b/src/llvm_backend_utility.cpp @@ -2112,7 +2112,13 @@ gb_internal lbAddr lb_handle_objc_find_or_register_selector(lbProcedure *p, Stri } if (!entity) { - lbAddr default_addr = lb_add_global_generated(default_module, t_objc_SEL, {}, &entity); + gbString global_name = gb_string_make(temporary_allocator(), "__$objc_selector-"); + 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}); } @@ -2169,7 +2175,12 @@ gb_internal lbAddr lb_handle_objc_find_or_register_class(lbProcedure *p, String } if (!entity) { - lbAddr default_addr = lb_add_global_generated(default_module, t_objc_Class, {}, &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}); } -- cgit v1.2.3 From 5aafbc7f3000d1a24e3097ae37ac3900ffd9d187 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 25 Feb 2025 14:35:54 +0000 Subject: Use more deterministic module names --- src/llvm_backend.hpp | 3 --- src/llvm_backend_general.cpp | 11 +++++++++-- 2 files changed, 9 insertions(+), 5 deletions(-) (limited to 'src/llvm_backend_general.cpp') diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index d18395127..02b8094a1 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -182,8 +182,6 @@ struct lbModule { StringMap gen_procs; // key is the canonicalized name - std::atomic nested_type_name_guid; - Array procedures_to_generate; Array global_procedures_to_create; Array global_types_to_create; @@ -229,7 +227,6 @@ struct lbGenerator : LinkerData { PtrMap anonymous_proc_lits; std::atomic global_array_index; - std::atomic global_generated_index; isize used_module_count; diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index 54c1f5c38..b994ec330 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -20,7 +20,13 @@ gb_internal void lb_init_module(lbModule *m, Checker *c) { 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); @@ -2814,10 +2820,11 @@ gb_internal lbAddr lb_add_global_generated_from_procedure(lbProcedure *p, 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); } -- cgit v1.2.3 From fd6d7d412dbf666bbd10eddc98b04e1af3ef9f81 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 25 Feb 2025 14:55:33 +0000 Subject: Use more predictable object name --- src/llvm_backend.cpp | 40 ++++++++++++++++++++-------------------- src/llvm_backend_general.cpp | 15 +++++++++------ src/llvm_backend_utility.cpp | 4 ++-- 3 files changed, 31 insertions(+), 28 deletions(-) (limited to 'src/llvm_backend_general.cpp') diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 24807a9ba..9cf996e84 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -2559,17 +2559,15 @@ 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")); - } - path = concatenate_strings(permanent_allocator(), path, STR_LIT(".ll")); + GB_ASSERT(m->module_name != nullptr); + String s = make_string_c(m->module_name); + String prefix = str_lit("odin_package-"); + GB_ASSERT(string_starts_with(s, prefix)); + s.text += prefix.len; + s.len -= prefix.len; + + path = concatenate_strings(permanent_allocator(), path, s); + path = concatenate_strings(permanent_allocator(), s, STR_LIT(".ll")); return path; } @@ -2592,14 +2590,16 @@ 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"); + GB_ASSERT(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) { @@ -3153,7 +3153,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 = {}; diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index b994ec330..2d19097c7 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -221,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) { @@ -2786,6 +2786,7 @@ gb_internal lbValue lb_generate_anonymous_proc_lit(lbModule *m, String const &pr 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); @@ -2817,12 +2818,14 @@ gb_internal lbAddr lb_add_global_generated_from_procedure(lbProcedure *p, Type * GB_ASSERT(type != nullptr); type = default_type(type); - u32 index = ++p->global_generated_index; + static std::atomic global_index; + u32 index = ++global_index; + // 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_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)); @@ -2938,7 +2941,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_utility.cpp b/src/llvm_backend_utility.cpp index 9624a78e6..c876169f3 100644 --- a/src/llvm_backend_utility.cpp +++ b/src/llvm_backend_utility.cpp @@ -2112,7 +2112,7 @@ gb_internal lbAddr lb_handle_objc_find_or_register_selector(lbProcedure *p, Stri } if (!entity) { - gbString global_name = gb_string_make(temporary_allocator(), "__$objc_selector-"); + 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( @@ -2175,7 +2175,7 @@ gb_internal lbAddr lb_handle_objc_find_or_register_class(lbProcedure *p, String } if (!entity) { - gbString global_name = gb_string_make(temporary_allocator(), "__$objc_class-"); + 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, {}, -- cgit v1.2.3 From 46c0910a772ddad7d1cef4e9b71cd8d35bc2b563 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 25 Feb 2025 14:59:59 +0000 Subject: Fix `lb_add_global_generated_with_name` --- src/llvm_backend_general.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src/llvm_backend_general.cpp') diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index 2d19097c7..b9cf61a17 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -2790,8 +2790,9 @@ gb_internal lbAddr lb_add_global_generated_with_name(lbModule *m, Type *type, lb 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); + 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); -- cgit v1.2.3 From 92f6d2745bebe5576bdbacacedae3bd9217f4ba2 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 25 Feb 2025 15:01:12 +0000 Subject: Make `lb_add_global_generated_from_procedure` not use a global index but local to procedure --- src/llvm_backend_general.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'src/llvm_backend_general.cpp') diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index b9cf61a17..e980754ce 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -2819,14 +2819,10 @@ gb_internal lbAddr lb_add_global_generated_from_procedure(lbProcedure *p, Type * GB_ASSERT(type != nullptr); type = default_type(type); - static std::atomic global_index; - u32 index = ++global_index; - // u32 index = ++p->global_generated_index; + 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_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)); -- cgit v1.2.3 From 400348c925519cb98f3ba202a133501d10c4fcc7 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 25 Feb 2025 15:06:13 +0000 Subject: Improve global array index to be on a per module basis --- src/llvm_backend.hpp | 4 ++-- src/llvm_backend_const.cpp | 10 +++++----- src/llvm_backend_general.cpp | 25 +++++++++++-------------- src/llvm_backend_proc.cpp | 3 ++- 4 files changed, 20 insertions(+), 22 deletions(-) (limited to 'src/llvm_backend_general.cpp') diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index 02b8094a1..4fd1b8d1a 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -169,6 +169,8 @@ struct lbModule { RwMutex values_mutex; + std::atomic global_array_index; + PtrMap values; PtrMap soa_values; StringMap members; @@ -226,8 +228,6 @@ struct lbGenerator : LinkerData { RecursiveMutex anonymous_proc_lits_mutex; PtrMap anonymous_proc_lits; - std::atomic global_array_index; - isize used_module_count; lbProcedure *startup_runtime; diff --git a/src/llvm_backend_const.cpp b/src/llvm_backend_const.cpp index cee960bf3..b916c0017 100644 --- a/src/llvm_backend_const.cpp +++ b/src/llvm_backend_const.cpp @@ -588,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_general.cpp b/src/llvm_backend_general.cpp index e980754ce..0705e2e93 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -2527,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); @@ -2570,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); @@ -2822,6 +2817,8 @@ gb_internal lbAddr lb_add_global_generated_from_procedure(lbProcedure *p, 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); diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 3cfdf00f5..a835ae2c8 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -3308,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); -- cgit v1.2.3