From e2ba8ff6e6fdbd23a10dcaf8b04f85960b8aa7c3 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 2 Dec 2024 11:23:55 +0000 Subject: Fix #4530 --- src/exact_value.cpp | 6 +++++- src/string.cpp | 10 +++++----- 2 files changed, 10 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/exact_value.cpp b/src/exact_value.cpp index 5d6016ecc..ceaed84c1 100644 --- a/src/exact_value.cpp +++ b/src/exact_value.cpp @@ -370,7 +370,11 @@ gb_internal ExactValue exact_value_from_basic_literal(TokenKind kind, String con } case Token_Rune: { Rune r = GB_RUNE_INVALID; - utf8_decode(string.text, string.len, &r); + if (string.len == 1) { + r = cast(Rune)string.text[0]; + } else { + utf8_decode(string.text, string.len, &r); + } return exact_value_i64(r); } } diff --git a/src/string.cpp b/src/string.cpp index f8ee6c53e..b001adf0e 100644 --- a/src/string.cpp +++ b/src/string.cpp @@ -718,12 +718,12 @@ gb_internal bool unquote_char(String s, u8 quote, Rune *rune, bool *multiple_byt Rune r = -1; isize size = utf8_decode(s.text, s.len, &r); *rune = r; - *multiple_bytes = true; - *tail_string = make_string(s.text+size, s.len-size); + if (multiple_bytes) *multiple_bytes = true; + if (tail_string) *tail_string = make_string(s.text+size, s.len-size); return true; } else if (s[0] != '\\') { *rune = s[0]; - *tail_string = make_string(s.text+1, s.len-1); + if (tail_string) *tail_string = make_string(s.text+1, s.len-1); return true; } @@ -809,10 +809,10 @@ gb_internal bool unquote_char(String s, u8 quote, Rune *rune, bool *multiple_byt return false; } *rune = r; - *multiple_bytes = true; + if (multiple_bytes) *multiple_bytes = true; } break; } - *tail_string = s; + if (tail_string) *tail_string = s; return true; } -- cgit v1.2.3 From 65de0256ce173b92ff90c9ea9629aeadc9bb8538 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 2 Dec 2024 15:57:08 +0000 Subject: Fix #4535 --- src/check_expr.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index dd0820fee..cc9483187 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -4980,8 +4980,12 @@ gb_internal ExactValue get_constant_field_single(CheckerContext *c, ExactValue v if (success_) *success_ = true; if (finish_) *finish_ = false; return tav.value; + } else if (is_type_proc(tav.type)) { + if (success_) *success_ = true; + if (finish_) *finish_ = false; + return tav.value; } else { - GB_ASSERT(is_type_untyped_nil(tav.type)); + GB_ASSERT_MSG(is_type_untyped_nil(tav.type), "%s", type_to_string(tav.type)); if (success_) *success_ = true; if (finish_) *finish_ = false; return tav.value; -- cgit v1.2.3 From b94247988658f875bfaed6717b3f888d75d5e660 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 2 Dec 2024 15:57:20 +0000 Subject: Minor improvement to type handing on failures --- src/types.cpp | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/types.cpp b/src/types.cpp index 4b43662f5..233f903a3 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -3888,6 +3888,10 @@ gb_internal i64 *type_set_offsets_of(Slice const &fields, bool is_pack min_field_align = 1; } + TypePath path{}; + type_path_init(&path); + defer (type_path_free(&path)); + if (is_raw_union) { for_array(i, fields) { offsets[i] = 0; @@ -3897,7 +3901,7 @@ gb_internal i64 *type_set_offsets_of(Slice const &fields, bool is_pack if (fields[i]->kind != Entity_Variable) { offsets[i] = -1; } else { - i64 size = type_size_of(fields[i]->type); + i64 size = type_size_of_internal(fields[i]->type, &path); offsets[i] = curr_offset; curr_offset += size; } @@ -3908,11 +3912,11 @@ gb_internal i64 *type_set_offsets_of(Slice const &fields, bool is_pack offsets[i] = -1; } else { Type *t = fields[i]->type; - i64 align = gb_max(type_align_of(t), min_field_align); + i64 align = gb_max(type_align_of_internal(t, &path), min_field_align); if (max_field_align > min_field_align) { align = gb_min(align, max_field_align); } - i64 size = gb_max(type_size_of( t), 0); + i64 size = gb_max(type_size_of_internal(t, &path), 0); curr_offset = align_formula(curr_offset, align); offsets[i] = curr_offset; curr_offset += size; @@ -3925,15 +3929,13 @@ gb_internal i64 *type_set_offsets_of(Slice const &fields, bool is_pack gb_internal bool type_set_offsets(Type *t) { t = base_type(t); if (t->kind == Type_Struct) { - if (mutex_try_lock(&t->Struct.offset_mutex)) { - defer (mutex_unlock(&t->Struct.offset_mutex)); - if (!t->Struct.are_offsets_set) { - t->Struct.are_offsets_being_processed = true; - t->Struct.offsets = type_set_offsets_of(t->Struct.fields, t->Struct.is_packed, t->Struct.is_raw_union, t->Struct.custom_min_field_align, t->Struct.custom_max_field_align); - t->Struct.are_offsets_being_processed = false; - t->Struct.are_offsets_set = true; - return true; - } + MUTEX_GUARD(&t->Struct.offset_mutex); + if (!t->Struct.are_offsets_set) { + t->Struct.are_offsets_being_processed = true; + t->Struct.offsets = type_set_offsets_of(t->Struct.fields, t->Struct.is_packed, t->Struct.is_raw_union, t->Struct.custom_min_field_align, t->Struct.custom_max_field_align); + t->Struct.are_offsets_being_processed = false; + t->Struct.are_offsets_set = true; + return true; } } else if (is_type_tuple(t)) { MUTEX_GUARD(&t->Tuple.mutex); -- cgit v1.2.3 From b36a81ef535b55afa3630eda6ff0b94f77f6c11e Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 5 Dec 2024 10:44:53 +0000 Subject: ABI change: for indirect parameters size_of <= 16, do callee stack copy --- src/build_settings.cpp | 1 + src/llvm_backend_proc.cpp | 19 +++++++++++++++++++ src/main.cpp | 5 +++++ 3 files changed, 25 insertions(+) (limited to 'src') diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 50fae93b8..15cc4f71d 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -467,6 +467,7 @@ struct BuildContext { BuildCacheData build_cache_data; bool internal_no_inline; + bool internal_by_value; bool no_threaded_checker; diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 5aee5b639..fee825a2f 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -579,6 +579,8 @@ gb_internal void lb_begin_procedure_body(lbProcedure *p) { p->raw_input_parameters = array_make(permanent_allocator(), raw_input_parameters_count); LLVMGetParams(p->value, p->raw_input_parameters.data); + bool is_odin_cc = is_calling_convention_odin(ft->calling_convention); + unsigned param_index = 0; for_array(i, params->variables) { Entity *e = params->variables[i]; @@ -613,9 +615,26 @@ gb_internal void lb_begin_procedure_body(lbProcedure *p) { } } else if (arg_type->kind == lbArg_Indirect) { if (e->token.string.len != 0 && !is_blank_ident(e->token.string)) { + i64 sz = type_size_of(e->type); + bool do_callee_copy = false; + + if (is_odin_cc) { + do_callee_copy = sz <= 16; + if (build_context.internal_by_value) { + do_callee_copy = true; + } + } + lbValue ptr = {}; ptr.value = LLVMGetParam(p->value, param_offset+param_index); ptr.type = alloc_type_pointer(e->type); + + if (do_callee_copy) { + lbValue new_ptr = lb_add_local_generated(p, e->type, false).addr; + lb_mem_copy_non_overlapping(p, new_ptr, ptr, lb_const_int(p->module, t_uint, sz)); + ptr = new_ptr; + } + lb_add_entity(p->module, e, ptr); lb_add_debug_param_variable(p, ptr.value, e->type, e->token, param_index+1, p->decl_block); } diff --git a/src/main.cpp b/src/main.cpp index 015269438..4d85a9e72 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -401,6 +401,7 @@ enum BuildFlagKind { BuildFlag_InternalModulePerFile, BuildFlag_InternalCached, BuildFlag_InternalNoInline, + BuildFlag_InternalByValue, BuildFlag_Tilde, @@ -612,6 +613,7 @@ gb_internal bool parse_build_flags(Array args) { add_flag(&build_flags, BuildFlag_InternalModulePerFile, str_lit("internal-module-per-file"), BuildFlagParam_None, Command_all); add_flag(&build_flags, BuildFlag_InternalCached, str_lit("internal-cached"), BuildFlagParam_None, Command_all); add_flag(&build_flags, BuildFlag_InternalNoInline, str_lit("internal-no-inline"), BuildFlagParam_None, Command_all); + add_flag(&build_flags, BuildFlag_InternalByValue, str_lit("internal-by-value"), BuildFlagParam_None, Command_all); #if ALLOW_TILDE add_flag(&build_flags, BuildFlag_Tilde, str_lit("tilde"), BuildFlagParam_None, Command__does_build); @@ -1508,6 +1510,9 @@ gb_internal bool parse_build_flags(Array args) { case BuildFlag_InternalNoInline: build_context.internal_no_inline = true; break; + case BuildFlag_InternalByValue: + build_context.internal_by_value = true; + break; case BuildFlag_Tilde: build_context.tilde_backend = true; -- cgit v1.2.3 From f5b16aa42aae8dd53f6138cc8593f7937733dc90 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 5 Dec 2024 15:27:41 +0000 Subject: Fix #4561 --- src/check_stmt.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index 2418fcc5c..e2d6f68fa 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -2612,6 +2612,7 @@ gb_internal void check_for_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) { } else if (cond && cond->kind == Ast_BinaryExpr && cond->BinaryExpr.left && cond->BinaryExpr.right && cond->BinaryExpr.op.kind == Token_LtEq && + type_of_expr(cond->BinaryExpr.right) != nullptr && is_type_unsigned(type_of_expr(cond->BinaryExpr.right)) && cond->BinaryExpr.left->tav.value.kind == ExactValue_Integer && is_exact_value_zero(cond->BinaryExpr.left->tav.value)) { -- cgit v1.2.3 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') 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 e3b16464908f2d6e85b7569ad4da6a802e3283c3 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 5 Dec 2024 15:46:35 +0000 Subject: Fix #4552 --- src/check_stmt.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index e2d6f68fa..02ad72388 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -2605,6 +2605,7 @@ gb_internal void check_for_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) { if (cond && cond->kind == Ast_BinaryExpr && cond->BinaryExpr.left && cond->BinaryExpr.right && cond->BinaryExpr.op.kind == Token_GtEq && + type_of_expr(cond->BinaryExpr.left) != nullptr && is_type_unsigned(type_of_expr(cond->BinaryExpr.left)) && cond->BinaryExpr.right->tav.value.kind == ExactValue_Integer && is_exact_value_zero(cond->BinaryExpr.right->tav.value)) { -- cgit v1.2.3 From 676fe34863c9332a49e2b5e659960caa5aa4d325 Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Fri, 6 Dec 2024 19:38:53 +0100 Subject: fix #4547 - wasm -out without file extension --- src/build_settings.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 15cc4f71d..4c3f4b782 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -2054,7 +2054,7 @@ gb_internal bool init_build_paths(String init_filename) { // Do we have an extension? We might not if the output filename was supplied. if (bc->build_paths[BuildPath_Output].ext.len == 0) { - if (build_context.metrics.os == TargetOs_windows || build_context.build_mode != BuildMode_Executable) { + if (build_context.metrics.os == TargetOs_windows || is_arch_wasm() || build_context.build_mode != BuildMode_Executable) { bc->build_paths[BuildPath_Output].ext = copy_string(ha, output_extension); } } -- cgit v1.2.3 From c8f0d27ceecaaa4d9803ae7fd0fea69ca5aff227 Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Mon, 9 Dec 2024 19:12:42 +0100 Subject: compiler: remove viral `#force(_no)_inline` If a procedure was marked `#force_no_inline`, any procedure calls within it would also implicitly be. This is not expected for multiple reasons: 1. `#force(_no)_inline` on a call expr works differently than on a procedure literal. 2. Adding the attribute on it and every called proc blows up the amount of work for the inliner pass and may increase the time it takes. 3. Putting `#force_no_inline` on a procedure to keep executable size down (like we do for some map procedures), benchmark it, or find it in asm/ir has the added effect of slowing those procedures down significantly and not representing truth. --- src/llvm_backend_proc.cpp | 4 ---- 1 file changed, 4 deletions(-) (limited to 'src') diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index fee825a2f..712e13592 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -1136,10 +1136,6 @@ gb_internal lbValue lb_emit_call(lbProcedure *p, lbValue value, Array c } } - if (inlining == ProcInlining_none) { - inlining = p->inlining; - } - Type *rt = reduce_tuple_to_single_type(results); Type *original_rt = rt; if (split_returns) { -- cgit v1.2.3 From 0a29d36aa3ddaa9d56d2e31bfec1a6f65487b387 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 12 Dec 2024 15:44:49 +0000 Subject: Fix bug with comparisons with big endian types --- src/llvm_backend_expr.cpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'src') diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 1247eed76..9c325e088 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -2817,6 +2817,12 @@ gb_internal lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left Type *it = bit_set_to_int(a); lbValue lhs = lb_emit_transmute(p, left, it); lbValue rhs = lb_emit_transmute(p, right, it); + if (is_type_different_to_arch_endianness(it)) { + it = integer_endian_type_to_platform_type(it); + lhs = lb_emit_byte_swap(p, lhs, it); + rhs = lb_emit_byte_swap(p, rhs, it); + } + lbValue res = lb_emit_arith(p, Token_And, lhs, rhs, it); if (op_kind == Token_Lt || op_kind == Token_LtEq) { @@ -2914,6 +2920,12 @@ gb_internal lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left } } + if (is_type_different_to_arch_endianness(left.type)) { + Type *pt = integer_endian_type_to_platform_type(left.type); + lhs = lb_emit_byte_swap(p, {lhs, pt}, pt).value; + rhs = lb_emit_byte_swap(p, {rhs, pt}, pt).value; + } + res.value = LLVMBuildICmp(p->builder, pred, lhs, rhs, ""); } else if (is_type_float(a)) { LLVMRealPredicate pred = {}; @@ -2925,6 +2937,13 @@ gb_internal lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left case Token_LtEq: pred = LLVMRealOLE; break; case Token_NotEq: pred = LLVMRealONE; break; } + + if (is_type_different_to_arch_endianness(left.type)) { + Type *pt = integer_endian_type_to_platform_type(left.type); + left = lb_emit_byte_swap(p, left, pt); + right = lb_emit_byte_swap(p, right, pt); + } + res.value = LLVMBuildFCmp(p->builder, pred, left.value, right.value, ""); } else if (is_type_typeid(a)) { LLVMIntPredicate pred = {}; -- cgit v1.2.3 From 14216ebf5169581a738e9c235ef8119a95271b12 Mon Sep 17 00:00:00 2001 From: Barinzaya Date: Thu, 19 Dec 2024 20:07:04 -0500 Subject: Added some implicit broadcasting for #simd arrays. This covers broadcasting from untyped numbers when assigning, as well as when performing binary operations. SIMD intrinsics have not been adjusted --- src/check_expr.cpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'src') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index cc9483187..81e33a8e8 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -3672,6 +3672,13 @@ gb_internal bool check_binary_array_expr(CheckerContext *c, Token op, Operand *x } } } + if (is_type_simd_vector(x->type) && !is_type_simd_vector(y->type)) { + if (check_is_assignable_to(c, y, x->type)) { + if (check_binary_op(c, x, op)) { + return true; + } + } + } return false; } @@ -4556,6 +4563,19 @@ gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *tar break; } + case Type_SimdVector: { + Type *elem = base_array_type(t); + if (check_is_assignable_to(c, operand, elem)) { + operand->mode = Addressing_Value; + } else { + operand->mode = Addressing_Invalid; + convert_untyped_error(c, operand, target_type); + return; + } + + break; + } + case Type_Matrix: { Type *elem = base_array_type(t); if (check_is_assignable_to(c, operand, elem)) { -- cgit v1.2.3 From 26f9688c69caa1ea8211da7ef072ea6ec292d8f7 Mon Sep 17 00:00:00 2001 From: misomosi Date: Sat, 21 Dec 2024 16:53:31 -0500 Subject: Fix early overwrite of dst w/ exp_u64 --- src/big_int.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/big_int.cpp b/src/big_int.cpp index 8e476f090..0b0a9a400 100644 --- a/src/big_int.cpp +++ b/src/big_int.cpp @@ -251,7 +251,10 @@ gb_internal void big_int_from_string(BigInt *dst, String const &s, bool *success exp *= 10; exp += v; } - big_int_exp_u64(dst, &b, exp, success); + BigInt tmp = {}; + mp_init(&tmp); + big_int_exp_u64(&tmp, &b, exp, success); + big_int_mul_eq(dst, &tmp); } if (is_negative) { -- cgit v1.2.3 From f2f952b344b076c17281e0e77195a27d94f58919 Mon Sep 17 00:00:00 2001 From: Roland Kovacs Date: Sun, 22 Dec 2024 01:52:57 +0100 Subject: Fix crash when proc return type is undeclared parapoly variable Disallow the declaration of new parapoly variables in return types, when the procedure's parapoly scope is itself. This happens if e.g.: `foo :: proc() -> $T`. Closes #3949, #4294, #4563 --- src/check_type.cpp | 9 ++++++++- src/checker.hpp | 1 + 2 files changed, 9 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/check_type.cpp b/src/check_type.cpp index 13a6125ca..44108ccbe 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -2440,8 +2440,12 @@ gb_internal bool check_procedure_type(CheckerContext *ctx, Type *type, Ast *proc bool success = true; isize specialization_count = 0; Type *params = check_get_params(c, c->scope, pt->params, &variadic, &variadic_index, &success, &specialization_count, operands); - Type *results = check_get_results(c, c->scope, pt->results); + bool no_poly_return = c->disallow_polymorphic_return_types; + c->disallow_polymorphic_return_types = c->scope == c->polymorphic_scope; + // NOTE(zen3ger): if the parapoly scope is the current proc's scope, then the return types shall not declare new poly vars + Type *results = check_get_results(c, c->scope, pt->results); + c->disallow_polymorphic_return_types = no_poly_return; isize param_count = 0; isize result_count = 0; @@ -3383,6 +3387,9 @@ gb_internal bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, T } Type *t = alloc_type_generic(ctx->scope, 0, token.string, specific); if (ctx->allow_polymorphic_types) { + if (ctx->disallow_polymorphic_return_types) { + error(ident, "Undeclared polymorphic parameter '%.*s' in return type", LIT(token.string)); + } Scope *ps = ctx->polymorphic_scope; Scope *s = ctx->scope; Scope *entity_scope = s; diff --git a/src/checker.hpp b/src/checker.hpp index 438156f18..a4cb47521 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -521,6 +521,7 @@ struct CheckerContext { bool in_enum_type; bool collect_delayed_decls; bool allow_polymorphic_types; + bool disallow_polymorphic_return_types; // NOTE(zen3ger): no poly type decl in return types bool no_polymorphic_errors; bool hide_polymorphic_errors; bool in_polymorphic_specialization; -- cgit v1.2.3 From 9f77f7c4175a6202b01a984a692c0288ac6077ec Mon Sep 17 00:00:00 2001 From: Roland Kovacs Date: Sun, 22 Dec 2024 12:38:37 +0100 Subject: Fix crash on assignment of parapoly proc to variable --- src/check_decl.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 60eb030ff..d541426d3 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -94,12 +94,14 @@ gb_internal Type *check_init_variable(CheckerContext *ctx, Entity *e, Operand *o return nullptr; } if (e2->state.load() != EntityState_Resolved) { - gbString str = type_to_string(t); - defer (gb_string_free(str)); - error(e->token, "Invalid use of a polymorphic type '%s' in %.*s", str, LIT(context_name)); - e->type = t_invalid; + e->type = t; return nullptr; } + gbString str = type_to_string(t); + defer (gb_string_free(str)); + error(operand->expr, "Invalid use of a non-specialized polymorphic type '%s' in %.*s", str, LIT(context_name)); + e->type = t_invalid; + return nullptr; } else if (is_type_empty_union(t)) { gbString str = type_to_string(t); defer (gb_string_free(str)); -- 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') 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 6ff81b6e4c1f9880d92ee5a2ccae241431afb6ee Mon Sep 17 00:00:00 2001 From: fleandro <3987005+flga@users.noreply.github.com> Date: Mon, 23 Dec 2024 01:03:51 +0000 Subject: make -export-dependencies:json emit valid json --- src/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/main.cpp b/src/main.cpp index 4d85a9e72..0450c61ec 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2120,7 +2120,7 @@ gb_internal void export_dependencies(Checker *c) { for_array(i, files) { AstFile *file = files[i]; gb_fprintf(&f, "\t\t\"%.*s\"", LIT(file->fullpath)); - if (i+1 == files.count) { + if (i+1 < files.count) { gb_fprintf(&f, ","); } gb_fprintf(&f, "\n"); @@ -2133,7 +2133,7 @@ gb_internal void export_dependencies(Checker *c) { for_array(i, load_files) { LoadFileCache *cache = load_files[i]; gb_fprintf(&f, "\t\t\"%.*s\"", LIT(cache->path)); - if (i+1 == load_files.count) { + if (i+1 < load_files.count) { gb_fprintf(&f, ","); } gb_fprintf(&f, "\n"); -- cgit v1.2.3 From c8ad2a4245fb9f0f5a0975e394693333299eb2a7 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 1 Jan 2025 15:12:54 +0000 Subject: Support multiple paths for wasm in `foreign import` --- src/check_decl.cpp | 88 ++++++++++++++++++++++++++---------------------------- src/checker.cpp | 34 +++++++++++++++++++++ src/checker.hpp | 1 + 3 files changed, 77 insertions(+), 46 deletions(-) (limited to 'src') diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 60eb030ff..ced886bc9 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -971,6 +971,43 @@ gb_internal void check_objc_methods(CheckerContext *ctx, Entity *e, AttributeCon } } +gb_internal void check_foreign_procedure(CheckerContext *ctx, Entity *e, DeclInfo *d) { + GB_ASSERT(e != nullptr); + GB_ASSERT(e->kind == Entity_Procedure); + String name = e->Procedure.link_name; + + mutex_lock(&ctx->info->foreign_mutex); + + auto *fp = &ctx->info->foreigns; + StringHashKey key = string_hash_string(name); + Entity **found = string_map_get(fp, key); + if (found && e != *found) { + Entity *f = *found; + TokenPos pos = f->token.pos; + Type *this_type = base_type(e->type); + Type *other_type = base_type(f->type); + if (is_type_proc(this_type) && is_type_proc(other_type)) { + if (!are_signatures_similar_enough(this_type, other_type)) { + error(d->proc_lit, + "Redeclaration of foreign procedure '%.*s' with different type signatures\n" + "\tat %s", + LIT(name), token_pos_to_string(pos)); + } + } else if (!signature_parameter_similar_enough(this_type, other_type)) { + error(d->proc_lit, + "Foreign entity '%.*s' previously declared elsewhere with a different type\n" + "\tat %s", + LIT(name), token_pos_to_string(pos)); + } + } else if (name == "main") { + error(d->proc_lit, "The link name 'main' is reserved for internal use"); + } else { + string_map_set(fp, key, e); + } + + mutex_unlock(&ctx->info->foreign_mutex); +} + gb_internal void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) { GB_ASSERT(e->type == nullptr); if (d->proc_lit->kind != Ast_ProcLit) { @@ -1307,57 +1344,16 @@ gb_internal void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) { name = e->Procedure.link_name; } Entity *foreign_library = init_entity_foreign_library(ctx, e); - - if (is_arch_wasm() && foreign_library != nullptr) { - String module_name = str_lit("env"); - GB_ASSERT (foreign_library->kind == Entity_LibraryName); - if (foreign_library->LibraryName.paths.count != 1) { - error(foreign_library->token, "'foreign import' for '%.*s' architecture may only have one path, got %td", - LIT(target_arch_names[build_context.metrics.arch]), foreign_library->LibraryName.paths.count); - } - - if (foreign_library->LibraryName.paths.count >= 1) { - module_name = foreign_library->LibraryName.paths[0]; - } - - if (!string_ends_with(module_name, str_lit(".o"))) { - name = concatenate3_strings(permanent_allocator(), module_name, WASM_MODULE_NAME_SEPARATOR, name); - } - } - e->Procedure.is_foreign = true; e->Procedure.link_name = name; + e->Procedure.foreign_library = foreign_library; - mutex_lock(&ctx->info->foreign_mutex); - - auto *fp = &ctx->info->foreigns; - StringHashKey key = string_hash_string(name); - Entity **found = string_map_get(fp, key); - if (found && e != *found) { - Entity *f = *found; - TokenPos pos = f->token.pos; - Type *this_type = base_type(e->type); - Type *other_type = base_type(f->type); - if (is_type_proc(this_type) && is_type_proc(other_type)) { - if (!are_signatures_similar_enough(this_type, other_type)) { - error(d->proc_lit, - "Redeclaration of foreign procedure '%.*s' with different type signatures\n" - "\tat %s", - LIT(name), token_pos_to_string(pos)); - } - } else if (!signature_parameter_similar_enough(this_type, other_type)) { - error(d->proc_lit, - "Foreign entity '%.*s' previously declared elsewhere with a different type\n" - "\tat %s", - LIT(name), token_pos_to_string(pos)); - } - } else if (name == "main") { - error(d->proc_lit, "The link name 'main' is reserved for internal use"); + if (is_arch_wasm() && foreign_library != nullptr) { + // NOTE(bill): this must be delayed because the foreign import paths might not be evaluated yet until much later + mpsc_enqueue(&ctx->info->foreign_decls_to_check, e); } else { - string_map_set(fp, key, e); + check_foreign_procedure(ctx, e, d); } - - mutex_unlock(&ctx->info->foreign_mutex); } else { String name = e->token.string; if (e->Procedure.link_name.len > 0) { diff --git a/src/checker.cpp b/src/checker.cpp index b7cf343f8..7e0a64d75 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -1356,6 +1356,7 @@ gb_internal void init_checker_info(CheckerInfo *i) { mpsc_init(&i->required_global_variable_queue, a); // 1<<10); mpsc_init(&i->required_foreign_imports_through_force_queue, a); // 1<<10); mpsc_init(&i->foreign_imports_to_check_fullpaths, a); // 1<<10); + mpsc_init(&i->foreign_decls_to_check, a); // 1<<10); mpsc_init(&i->intrinsics_entry_point_usage, a); // 1<<10); // just waste some memory here, even if it probably never used string_map_init(&i->load_directory_cache); @@ -1382,6 +1383,7 @@ gb_internal void destroy_checker_info(CheckerInfo *i) { mpsc_destroy(&i->required_global_variable_queue); mpsc_destroy(&i->required_foreign_imports_through_force_queue); mpsc_destroy(&i->foreign_imports_to_check_fullpaths); + mpsc_destroy(&i->foreign_decls_to_check); map_destroy(&i->objc_msgSend_types); string_map_destroy(&i->load_file_cache); @@ -5094,6 +5096,38 @@ gb_internal void check_foreign_import_fullpaths(Checker *c) { e->LibraryName.paths = fl->fullpaths; } + + for (Entity *e = nullptr; mpsc_dequeue(&c->info.foreign_decls_to_check, &e); /**/) { + GB_ASSERT(e != nullptr); + if (e->kind != Entity_Procedure) { + continue; + } + if (!is_arch_wasm()) { + continue; + } + Entity *foreign_library = e->Procedure.foreign_library; + GB_ASSERT(foreign_library != nullptr); + + String name = e->Procedure.link_name; + + String module_name = str_lit("env"); + GB_ASSERT (foreign_library->kind == Entity_LibraryName); + if (foreign_library->LibraryName.paths.count != 1) { + error(foreign_library->token, "'foreign import' for '%.*s' architecture may only have one path, got %td", + LIT(target_arch_names[build_context.metrics.arch]), foreign_library->LibraryName.paths.count); + } + + if (foreign_library->LibraryName.paths.count >= 1) { + module_name = foreign_library->LibraryName.paths[0]; + } + + if (!string_ends_with(module_name, str_lit(".o"))) { + name = concatenate3_strings(permanent_allocator(), module_name, WASM_MODULE_NAME_SEPARATOR, name); + } + e->Procedure.link_name = name; + + check_foreign_procedure(&ctx, e, e->decl_info); + } } gb_internal void check_add_foreign_import_decl(CheckerContext *ctx, Ast *decl) { diff --git a/src/checker.hpp b/src/checker.hpp index 438156f18..036990f29 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -461,6 +461,7 @@ struct CheckerInfo { MPSCQueue required_global_variable_queue; MPSCQueue required_foreign_imports_through_force_queue; MPSCQueue foreign_imports_to_check_fullpaths; + MPSCQueue foreign_decls_to_check; MPSCQueue intrinsics_entry_point_usage; -- cgit v1.2.3 From 7b334d2bd9e881b450fb19e394d6d71840a62cf9 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 1 Jan 2025 17:26:15 +0000 Subject: Add `#branch_location` --- src/check_expr.cpp | 12 +++++++ src/entity.cpp | 1 + src/llvm_backend.hpp | 7 +++- src/llvm_backend_expr.cpp | 12 +++++-- src/llvm_backend_proc.cpp | 6 +++- src/llvm_backend_stmt.cpp | 81 ++++++++++++++++++++++++++++---------------- src/llvm_backend_utility.cpp | 8 ++--- 7 files changed, 89 insertions(+), 38 deletions(-) (limited to 'src') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index cc9483187..fba9b8dad 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -8725,6 +8725,18 @@ gb_internal ExprKind check_basic_directive_expr(CheckerContext *c, Operand *o, A error(node, "#caller_expression may only be used as a default argument parameter"); o->type = t_string; o->mode = Addressing_Value; + } else if (name == "branch_location") { + if (!c->in_defer) { + error(node, "#branch_location may only be used within a 'defer' statement"); + } else if (c->curr_proc_decl) { + Entity *e = c->curr_proc_decl->entity; + if (e != nullptr) { + GB_ASSERT(e->kind == Entity_Procedure); + e->Procedure.uses_branch_location = true; + } + } + o->type = t_source_code_location; + o->mode = Addressing_Value; } else { if (name == "location") { init_core_source_code_location(c->checker); diff --git a/src/entity.cpp b/src/entity.cpp index 0c4a20df4..802b381f9 100644 --- a/src/entity.cpp +++ b/src/entity.cpp @@ -256,6 +256,7 @@ struct Entity { bool entry_point_only : 1; bool has_instrumentation : 1; bool is_memcpy_like : 1; + bool uses_branch_location : 1; } Procedure; struct { Array entities; diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index e84ffd1cd..8ca11bf28 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -359,6 +359,10 @@ struct lbProcedure { bool in_multi_assignment; Array raw_input_parameters; + bool uses_branch_location; + TokenPos branch_location_pos; + TokenPos curr_token_pos; + Array variadic_reuses; lbAddr variadic_reuse_base_array_ptr; @@ -444,7 +448,8 @@ gb_internal lbValue lb_emit_matrix_ev(lbProcedure *p, lbValue s, isize row, isiz gb_internal lbValue lb_emit_arith(lbProcedure *p, TokenKind op, lbValue lhs, lbValue rhs, Type *type); gb_internal lbValue lb_emit_byte_swap(lbProcedure *p, lbValue value, Type *end_type); -gb_internal void lb_emit_defer_stmts(lbProcedure *p, lbDeferExitKind kind, lbBlock *block); +gb_internal void lb_emit_defer_stmts(lbProcedure *p, lbDeferExitKind kind, lbBlock *block, TokenPos pos); +gb_internal void lb_emit_defer_stmts(lbProcedure *p, lbDeferExitKind kind, lbBlock *block, Ast *node); gb_internal lbValue lb_emit_transmute(lbProcedure *p, lbValue value, Type *t); gb_internal lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left, lbValue right); gb_internal lbValue lb_emit_call(lbProcedure *p, lbValue value, Array const &args, ProcInlining inlining = ProcInlining_none); diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 9c325e088..3b238bcd8 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -3502,7 +3502,13 @@ gb_internal lbValue lb_build_expr_internal(lbProcedure *p, Ast *expr) { case_ast_node(bd, BasicDirective, expr); TokenPos pos = bd->token.pos; - GB_PANIC("Non-constant basic literal %s - %.*s", token_pos_to_string(pos), LIT(bd->name.string)); + String name = bd->name.string; + if (name == "branch_location") { + GB_ASSERT(p->uses_branch_location); + String proc_name = p->entity->token.string; + return lb_emit_source_code_location_as_global(p, proc_name, p->branch_location_pos); + } + GB_PANIC("Non-constant basic literal %s - %.*s", token_pos_to_string(pos), LIT(name)); case_end; case_ast_node(i, Implicit, expr); @@ -3668,7 +3674,7 @@ gb_internal lbValue lb_build_expr_internal(lbProcedure *p, Ast *expr) { lb_emit_if(p, lb_emit_try_has_value(p, rhs), then, else_); lb_start_block(p, else_); - lb_emit_defer_stmts(p, lbDeferExit_Branch, block); + lb_emit_defer_stmts(p, lbDeferExit_Branch, block, expr); lb_emit_jump(p, block); lb_start_block(p, then); @@ -5493,7 +5499,7 @@ gb_internal lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) { lb_emit_if(p, lb_emit_try_has_value(p, rhs), then, else_); lb_start_block(p, else_); - lb_emit_defer_stmts(p, lbDeferExit_Branch, block); + lb_emit_defer_stmts(p, lbDeferExit_Branch, block, expr); lb_emit_jump(p, block); lb_start_block(p, then); diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 712e13592..7e44a0046 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -125,6 +125,10 @@ gb_internal lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool i // map_init(&p->selector_addr, 0); // map_init(&p->tuple_fix_map, 0); + if (p->entity != nullptr && p->entity->Procedure.uses_branch_location) { + p->uses_branch_location = true; + } + if (p->is_foreign) { lb_add_foreign_library_path(p->module, entity->Procedure.foreign_library); } @@ -757,7 +761,7 @@ gb_internal void lb_end_procedure_body(lbProcedure *p) { if (p->type->Proc.result_count == 0) { instr = LLVMGetLastInstruction(p->curr_block->block); if (!lb_is_instr_terminating(instr)) { - lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr); + lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr, p->body); lb_set_debug_position_to_procedure_end(p); LLVMBuildRetVoid(p->builder); } diff --git a/src/llvm_backend_stmt.cpp b/src/llvm_backend_stmt.cpp index 9a5f25712..a2f0d2f4a 100644 --- a/src/llvm_backend_stmt.cpp +++ b/src/llvm_backend_stmt.cpp @@ -208,8 +208,8 @@ gb_internal void lb_open_scope(lbProcedure *p, Scope *s) { } -gb_internal void lb_close_scope(lbProcedure *p, lbDeferExitKind kind, lbBlock *block, bool pop_stack=true) { - lb_emit_defer_stmts(p, kind, block); +gb_internal void lb_close_scope(lbProcedure *p, lbDeferExitKind kind, lbBlock *block, Ast *node, bool pop_stack=true) { + lb_emit_defer_stmts(p, kind, block, node); GB_ASSERT(p->scope_index > 0); // NOTE(bill): Remove `context`s made in that scope @@ -721,7 +721,7 @@ gb_internal void lb_build_range_interval(lbProcedure *p, AstBinaryExpr *node, lb_build_stmt(p, rs->body); - lb_close_scope(p, lbDeferExit_Default, nullptr); + lb_close_scope(p, lbDeferExit_Default, nullptr, node->left); lb_pop_target_list(p); if (check != nullptr) { @@ -854,7 +854,7 @@ gb_internal void lb_build_range_tuple(lbProcedure *p, AstRangeStmt *rs, Scope *s lb_build_stmt(p, rs->body); - lb_close_scope(p, lbDeferExit_Default, nullptr); + lb_close_scope(p, lbDeferExit_Default, nullptr, rs->body); lb_pop_target_list(p); lb_emit_jump(p, loop); lb_start_block(p, done); @@ -976,7 +976,7 @@ gb_internal void lb_build_range_stmt_struct_soa(lbProcedure *p, AstRangeStmt *rs lb_build_stmt(p, rs->body); - lb_close_scope(p, lbDeferExit_Default, nullptr); + lb_close_scope(p, lbDeferExit_Default, nullptr, rs->body); lb_pop_target_list(p); lb_emit_jump(p, loop); lb_start_block(p, done); @@ -1192,7 +1192,7 @@ gb_internal void lb_build_range_stmt(lbProcedure *p, AstRangeStmt *rs, Scope *sc lb_build_stmt(p, rs->body); - lb_close_scope(p, lbDeferExit_Default, nullptr); + lb_close_scope(p, lbDeferExit_Default, nullptr, rs->body); lb_pop_target_list(p); lb_emit_jump(p, loop); lb_start_block(p, done); @@ -1363,7 +1363,7 @@ gb_internal void lb_build_unroll_range_stmt(lbProcedure *p, AstUnrollRangeStmt * } - lb_close_scope(p, lbDeferExit_Default, nullptr); + lb_close_scope(p, lbDeferExit_Default, nullptr, rs->body); } gb_internal bool lb_switch_stmt_can_be_trivial_jump_table(AstSwitchStmt *ss, bool *default_found_) { @@ -1433,6 +1433,7 @@ gb_internal void lb_build_switch_stmt(lbProcedure *p, AstSwitchStmt *ss, Scope * ast_node(body, BlockStmt, ss->body); isize case_count = body->stmts.count; + Ast *default_clause = nullptr; Slice default_stmts = {}; lbBlock *default_fall = nullptr; lbBlock *default_block = nullptr; @@ -1482,6 +1483,7 @@ gb_internal void lb_build_switch_stmt(lbProcedure *p, AstSwitchStmt *ss, Scope * if (cc->list.count == 0) { // default case + default_clause = clause; default_stmts = cc->stmts; default_fall = fall; if (switch_instr == nullptr) { @@ -1552,7 +1554,7 @@ gb_internal void lb_build_switch_stmt(lbProcedure *p, AstSwitchStmt *ss, Scope * lb_push_target_list(p, ss->label, done, nullptr, fall); lb_open_scope(p, body->scope); lb_build_stmt_list(p, cc->stmts); - lb_close_scope(p, lbDeferExit_Default, body); + lb_close_scope(p, lbDeferExit_Default, body, clause); lb_pop_target_list(p); lb_emit_jump(p, done); @@ -1570,13 +1572,13 @@ gb_internal void lb_build_switch_stmt(lbProcedure *p, AstSwitchStmt *ss, Scope * lb_push_target_list(p, ss->label, done, nullptr, default_fall); lb_open_scope(p, default_block->scope); lb_build_stmt_list(p, default_stmts); - lb_close_scope(p, lbDeferExit_Default, default_block); + lb_close_scope(p, lbDeferExit_Default, default_block, default_clause); lb_pop_target_list(p); } lb_emit_jump(p, done); lb_start_block(p, done); - lb_close_scope(p, lbDeferExit_Default, done); + lb_close_scope(p, lbDeferExit_Default, done, ss->body); } gb_internal void lb_store_type_case_implicit(lbProcedure *p, Ast *clause, lbValue value, bool is_default_case) { @@ -1627,7 +1629,7 @@ gb_internal void lb_type_case_body(lbProcedure *p, Ast *label, Ast *clause, lbBl lb_push_target_list(p, label, done, nullptr, nullptr); lb_build_stmt_list(p, cc->stmts); - lb_close_scope(p, lbDeferExit_Default, body); + lb_close_scope(p, lbDeferExit_Default, body, clause); lb_pop_target_list(p); lb_emit_jump(p, done); @@ -1835,7 +1837,7 @@ gb_internal void lb_build_type_switch_stmt(lbProcedure *p, AstTypeSwitchStmt *ss lb_emit_jump(p, done); lb_start_block(p, done); - lb_close_scope(p, lbDeferExit_Default, done); + lb_close_scope(p, lbDeferExit_Default, done, ss->body); } @@ -1959,7 +1961,7 @@ gb_internal void lb_build_assignment(lbProcedure *p, Array &lvals, Slice p->in_multi_assignment = prev_in_assignment; } -gb_internal void lb_build_return_stmt_internal(lbProcedure *p, lbValue res) { +gb_internal void lb_build_return_stmt_internal(lbProcedure *p, lbValue res, TokenPos pos) { lbFunctionType *ft = lb_get_function_type(p->module, p->type); bool return_by_pointer = ft->ret.kind == lbArg_Indirect; bool split_returns = ft->multiple_return_original_type != nullptr; @@ -1982,7 +1984,7 @@ gb_internal void lb_build_return_stmt_internal(lbProcedure *p, lbValue res) { LLVMBuildStore(p->builder, LLVMConstNull(p->abi_function_type->ret.type), p->return_ptr.addr.value); } - lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr); + lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr, pos); // Check for terminator in the defer stmts LLVMValueRef instr = LLVMGetLastInstruction(p->curr_block->block); @@ -2012,7 +2014,7 @@ gb_internal void lb_build_return_stmt_internal(lbProcedure *p, lbValue res) { ret_val = OdinLLVMBuildTransmute(p, ret_val, ret_type); } - lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr); + lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr, pos); // Check for terminator in the defer stmts LLVMValueRef instr = LLVMGetLastInstruction(p->curr_block->block); @@ -2021,7 +2023,7 @@ gb_internal void lb_build_return_stmt_internal(lbProcedure *p, lbValue res) { } } } -gb_internal void lb_build_return_stmt(lbProcedure *p, Slice const &return_results) { +gb_internal void lb_build_return_stmt(lbProcedure *p, Slice const &return_results, TokenPos pos) { lb_ensure_abi_function_type(p->module, p); isize return_count = p->type->Proc.result_count; @@ -2029,7 +2031,7 @@ gb_internal void lb_build_return_stmt(lbProcedure *p, Slice const &return if (return_count == 0) { // No return values - lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr); + lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr, pos); // Check for terminator in the defer stmts LLVMValueRef instr = LLVMGetLastInstruction(p->curr_block->block); @@ -2138,11 +2140,11 @@ gb_internal void lb_build_return_stmt(lbProcedure *p, Slice const &return GB_ASSERT(result_values.count-1 == result_eps.count); lb_addr_store(p, p->return_ptr, result_values[result_values.count-1]); - lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr); + lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr, pos); LLVMBuildRetVoid(p->builder); return; } else { - return lb_build_return_stmt_internal(p, result_values[result_values.count-1]); + return lb_build_return_stmt_internal(p, result_values[result_values.count-1], pos); } } else { @@ -2169,7 +2171,7 @@ gb_internal void lb_build_return_stmt(lbProcedure *p, Slice const &return } if (return_by_pointer) { - lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr); + lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr, pos); LLVMBuildRetVoid(p->builder); return; } @@ -2177,13 +2179,13 @@ gb_internal void lb_build_return_stmt(lbProcedure *p, Slice const &return res = lb_emit_load(p, res); } } - lb_build_return_stmt_internal(p, res); + lb_build_return_stmt_internal(p, res, pos); } gb_internal void lb_build_if_stmt(lbProcedure *p, Ast *node) { ast_node(is, IfStmt, node); lb_open_scope(p, is->scope); // Scope #1 - defer (lb_close_scope(p, lbDeferExit_Default, nullptr)); + defer (lb_close_scope(p, lbDeferExit_Default, nullptr, node)); lbBlock *then = lb_create_block(p, "if.then"); lbBlock *done = lb_create_block(p, "if.done"); @@ -2234,7 +2236,7 @@ gb_internal void lb_build_if_stmt(lbProcedure *p, Ast *node) { lb_open_scope(p, scope_of_node(is->else_stmt)); lb_build_stmt(p, is->else_stmt); - lb_close_scope(p, lbDeferExit_Default, nullptr); + lb_close_scope(p, lbDeferExit_Default, nullptr, is->else_stmt); } lb_emit_jump(p, done); @@ -2251,7 +2253,7 @@ gb_internal void lb_build_if_stmt(lbProcedure *p, Ast *node) { lb_open_scope(p, scope_of_node(is->else_stmt)); lb_build_stmt(p, is->else_stmt); - lb_close_scope(p, lbDeferExit_Default, nullptr); + lb_close_scope(p, lbDeferExit_Default, nullptr, is->else_stmt); lb_emit_jump(p, done); } @@ -2322,7 +2324,7 @@ gb_internal void lb_build_for_stmt(lbProcedure *p, Ast *node) { } lb_start_block(p, done); - lb_close_scope(p, lbDeferExit_Default, nullptr); + lb_close_scope(p, lbDeferExit_Default, nullptr, node); } gb_internal void lb_build_assign_stmt_array(lbProcedure *p, TokenKind op, lbAddr const &lhs, lbValue const &value) { @@ -2588,7 +2590,7 @@ gb_internal void lb_build_stmt(lbProcedure *p, Ast *node) { lb_open_scope(p, bs->scope); lb_build_stmt_list(p, bs->stmts); - lb_close_scope(p, lbDeferExit_Default, nullptr); + lb_close_scope(p, lbDeferExit_Default, nullptr, node); if (done != nullptr) { lb_emit_jump(p, done); @@ -2702,7 +2704,7 @@ gb_internal void lb_build_stmt(lbProcedure *p, Ast *node) { case_end; case_ast_node(rs, ReturnStmt, node); - lb_build_return_stmt(p, rs->results); + lb_build_return_stmt(p, rs->results, ast_token(node).pos); case_end; case_ast_node(is, IfStmt, node); @@ -2755,7 +2757,7 @@ gb_internal void lb_build_stmt(lbProcedure *p, Ast *node) { } } if (block != nullptr) { - lb_emit_defer_stmts(p, lbDeferExit_Branch, block); + lb_emit_defer_stmts(p, lbDeferExit_Branch, block, node); } lb_emit_jump(p, block); lb_start_block(p, lb_create_block(p, "unreachable")); @@ -2795,7 +2797,13 @@ gb_internal void lb_build_defer_stmt(lbProcedure *p, lbDefer const &d) { } } -gb_internal void lb_emit_defer_stmts(lbProcedure *p, lbDeferExitKind kind, lbBlock *block) { +gb_internal void lb_emit_defer_stmts(lbProcedure *p, lbDeferExitKind kind, lbBlock *block, TokenPos pos) { + TokenPos prev_token_pos = p->branch_location_pos; + if (p->uses_branch_location) { + p->branch_location_pos = pos; + } + defer (p->branch_location_pos = prev_token_pos); + isize count = p->defer_stmts.count; isize i = count; while (i --> 0) { @@ -2822,6 +2830,21 @@ gb_internal void lb_emit_defer_stmts(lbProcedure *p, lbDeferExitKind kind, lbBlo } } +gb_internal void lb_emit_defer_stmts(lbProcedure *p, lbDeferExitKind kind, lbBlock *block, Ast *node) { + TokenPos pos = {}; + if (node) { + if (node->kind == Ast_BlockStmt) { + pos = ast_end_token(node).pos; + } else if (node->kind == Ast_CaseClause) { + pos = ast_end_token(node).pos; + } else { + pos = ast_token(node).pos; + } + } + return lb_emit_defer_stmts(p, kind, block, pos); +} + + gb_internal void lb_add_defer_node(lbProcedure *p, isize scope_index, Ast *stmt) { Type *pt = base_type(p->type); GB_ASSERT(pt->kind == Type_Proc); diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp index a2a0ba4cc..3e4393a8f 100644 --- a/src/llvm_backend_utility.cpp +++ b/src/llvm_backend_utility.cpp @@ -476,8 +476,8 @@ gb_internal lbValue lb_emit_or_else(lbProcedure *p, Ast *arg, Ast *else_expr, Ty } } -gb_internal void lb_build_return_stmt(lbProcedure *p, Slice const &return_results); -gb_internal void lb_build_return_stmt_internal(lbProcedure *p, lbValue res); +gb_internal void lb_build_return_stmt(lbProcedure *p, Slice const &return_results, TokenPos pos); +gb_internal void lb_build_return_stmt_internal(lbProcedure *p, lbValue res, TokenPos pos); gb_internal lbValue lb_emit_or_return(lbProcedure *p, Ast *arg, TypeAndValue const &tv) { lbValue lhs = {}; @@ -506,10 +506,10 @@ gb_internal lbValue lb_emit_or_return(lbProcedure *p, Ast *arg, TypeAndValue con lbValue found = map_must_get(&p->module->values, end_entity); lb_emit_store(p, found, rhs); - lb_build_return_stmt(p, {}); + lb_build_return_stmt(p, {}, ast_token(arg).pos); } else { GB_ASSERT(tuple->variables.count == 1); - lb_build_return_stmt_internal(p, rhs); + lb_build_return_stmt_internal(p, rhs, ast_token(arg).pos); } } lb_start_block(p, continue_block); -- cgit v1.2.3 From 2efe4c2d68f486006e405ba7d30be03ec121ae6c Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 5 Jan 2025 13:19:10 +0000 Subject: Add `#+feature dynamic-literals` --- src/build_settings.cpp | 12 +++++++++ src/check_expr.cpp | 10 ++++++-- src/parser.cpp | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/parser.hpp | 2 ++ 4 files changed, 88 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 4c3f4b782..a8261612e 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -324,6 +324,18 @@ u64 get_vet_flag_from_name(String const &name) { return VetFlag_NONE; } +enum OptInFeatureFlags : u64 { + OptInFeatureFlag_NONE = 0, + OptInFeatureFlag_DynamicLiterals = 1u<<0, +}; + +u64 get_feature_flag_from_name(String const &name) { + if (name == "dynamic-literals") { + return OptInFeatureFlag_DynamicLiterals; + } + return OptInFeatureFlag_NONE; +} + enum SanitizerFlags : u32 { SanitizerFlag_NONE = 0, diff --git a/src/check_expr.cpp b/src/check_expr.cpp index fba9b8dad..fb3040e71 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -9730,8 +9730,11 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * if (t->kind == Type_DynamicArray) { - if (build_context.no_dynamic_literals && cl->elems.count) { + if (build_context.no_dynamic_literals && cl->elems.count && (node->file()->feature_flags & OptInFeatureFlag_DynamicLiterals) != 0) { + ERROR_BLOCK(); error(node, "Compound literals of dynamic types have been disabled"); + error_line("\tSuggestion: If you want to enable them for this specific file, use '#+feature dynamic-literals' at the top of the file\n"); + error_line("\tWarning: Please understand that dynamic literals will implicitly allocate using the current 'context.allocator' in that scope\n"); } } @@ -10120,8 +10123,11 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * } } - if (build_context.no_dynamic_literals && cl->elems.count) { + if (build_context.no_dynamic_literals && cl->elems.count && (node->file()->feature_flags & OptInFeatureFlag_DynamicLiterals) != 0) { + ERROR_BLOCK(); error(node, "Compound literals of dynamic types have been disabled"); + error_line("\tSuggestion: If you want to enable them for this specific file, use '#+feature dynamic-literals' at the top of the file\n"); + error_line("\tWarning: Please understand that dynamic literals will implicitly allocate using the current 'context.allocator' in that scope\n"); } else { add_map_reserve_dependencies(c); add_map_set_dependencies(c); diff --git a/src/parser.cpp b/src/parser.cpp index aa90651d3..01ed46ebc 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -6265,10 +6265,16 @@ gb_internal u64 parse_vet_tag(Token token_for_pos, String s) { syntax_error(token_for_pos, "Invalid vet flag name: %.*s", LIT(p)); error_line("\tExpected one of the following\n"); error_line("\tunused\n"); + error_line("\tunused-variables\n"); + error_line("\tunused-imports\n"); + error_line("\tunused-procedures\n"); error_line("\tshadowing\n"); error_line("\tusing-stmt\n"); error_line("\tusing-param\n"); + error_line("\tstyle\n"); error_line("\textra\n"); + error_line("\tcast\n"); + error_line("\ttabs\n"); return build_context.vet_flags; } } @@ -6286,6 +6292,63 @@ gb_internal u64 parse_vet_tag(Token token_for_pos, String s) { return vet_flags &~ vet_not_flags; } +gb_internal u64 parse_feature_tag(Token token_for_pos, String s) { + String const prefix = str_lit("feature"); + GB_ASSERT(string_starts_with(s, prefix)); + s = string_trim_whitespace(substring(s, prefix.len, s.len)); + + if (s.len == 0) { + return OptInFeatureFlag_NONE; + } + + u64 feature_flags = 0; + u64 feature_not_flags = 0; + + while (s.len > 0) { + String p = string_trim_whitespace(vet_tag_get_token(s, &s)); + if (p.len == 0) { + break; + } + + bool is_notted = false; + if (p[0] == '!') { + is_notted = true; + p = substring(p, 1, p.len); + if (p.len == 0) { + syntax_error(token_for_pos, "Expected a feature flag name after '!'"); + return OptInFeatureFlag_NONE; + } + } + + u64 flag = get_vet_flag_from_name(p); + if (flag != OptInFeatureFlag_NONE) { + if (is_notted) { + feature_not_flags |= flag; + } else { + feature_flags |= flag; + } + } else { + ERROR_BLOCK(); + syntax_error(token_for_pos, "Invalid feature flag name: %.*s", LIT(p)); + error_line("\tExpected one of the following\n"); + error_line("\tdynamic-literals\n"); + return OptInFeatureFlag_NONE; + } + } + + if (feature_flags == 0 && feature_not_flags == 0) { + return OptInFeatureFlag_NONE; + } + if (feature_flags == 0 && feature_not_flags != 0) { + return OptInFeatureFlag_NONE &~ feature_not_flags; + } + if (feature_flags != 0 && feature_not_flags == 0) { + return feature_flags; + } + GB_ASSERT(feature_flags != 0 && feature_not_flags != 0); + return feature_flags &~ feature_not_flags; +} + gb_internal String dir_from_path(String path) { String base_dir = path; for (isize i = path.len-1; i >= 0; i--) { @@ -6409,6 +6472,9 @@ gb_internal bool parse_file_tag(const String &lc, const Token &tok, AstFile *f) } } else if (lc == "no-instrumentation") { f->flags |= AstFile_NoInstrumentation; + } else if (string_starts_with(lc, str_lit("feature"))) { + f->feature_flags = parse_feature_tag(tok, lc); + f->feature_flags_set = true; } else { error(tok, "Unknown tag '%.*s'", LIT(lc)); } diff --git a/src/parser.hpp b/src/parser.hpp index e332fed50..bbf70d03e 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -108,7 +108,9 @@ struct AstFile { String package_name; u64 vet_flags; + u64 feature_flags; bool vet_flags_set; + bool feature_flags_set; // >= 0: In Expression // < 0: In Control Clause -- cgit v1.2.3 From bca08d3b85f59c35f4eb43731099bc96730b12cd Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 5 Jan 2025 13:22:27 +0000 Subject: Make `-no-dynamic-literals` the default now --- examples/demo/demo.odin | 1 + src/build_settings.cpp | 6 ------ src/check_expr.cpp | 37 +++++++++++++++++++++---------------- src/checker.cpp | 18 +++++++++++++++++- src/llvm_backend.cpp | 2 -- src/llvm_backend_expr.cpp | 4 ++-- src/main.cpp | 2 +- src/parser.cpp | 4 ++-- 8 files changed, 44 insertions(+), 30 deletions(-) (limited to 'src') diff --git a/examples/demo/demo.odin b/examples/demo/demo.odin index 36d1359ca..82b047103 100644 --- a/examples/demo/demo.odin +++ b/examples/demo/demo.odin @@ -1,4 +1,5 @@ #+vet !using-stmt !using-param +#+feature dynamic-literals package main import "core:fmt" diff --git a/src/build_settings.cpp b/src/build_settings.cpp index a8261612e..93168cf77 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -441,7 +441,6 @@ struct BuildContext { bool ignore_unknown_attributes; bool no_bounds_check; bool no_type_assert; - bool no_dynamic_literals; bool no_output_files; bool no_crt; bool no_rpath; @@ -1867,11 +1866,6 @@ gb_internal bool init_build_paths(String init_filename) { produces_output_file = true; } - if (build_context.ODIN_DEFAULT_TO_NIL_ALLOCATOR || - build_context.ODIN_DEFAULT_TO_PANIC_ALLOCATOR) { - bc->no_dynamic_literals = true; - } - if (!produces_output_file) { // Command doesn't produce output files. We're done. return true; diff --git a/src/check_expr.cpp b/src/check_expr.cpp index fb3040e71..ba021a98c 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -9351,6 +9351,23 @@ gb_internal bool is_expr_inferred_fixed_array(Ast *type_expr) { return false; } +gb_internal bool check_for_dynamic_literals(CheckerContext *c, Ast *node, AstCompoundLit *cl) { + if (cl->elems.count > 0 && (check_feature_flags(c, node) & OptInFeatureFlag_DynamicLiterals) == 0) { + ERROR_BLOCK(); + error(node, "Compound literals of dynamic types are disabled by default"); + error_line("\tSuggestion: If you want to enable them for this specific file, add '#+feature dynamic-literals' at the top of the file\n"); + error_line("\tWarning: Please understand that dynamic literals will implicitly allocate using the current 'context.allocator' in that scope\n"); + if (build_context.ODIN_DEFAULT_TO_NIL_ALLOCATOR) { + error_line("\tWarning: As '-default-to-panic-allocator' has been set, the dynamic compound literal may not be initialized as expected\n"); + } else if (build_context.ODIN_DEFAULT_TO_PANIC_ALLOCATOR) { + error_line("\tWarning: As '-default-to-panic-allocator' has been set, the dynamic compound literal may not be initialized as expected\n"); + } + return false; + } + + return cl->elems.count > 0; +} + gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *node, Type *type_hint) { ExprKind kind = Expr_Expr; ast_node(cl, CompoundLit, node); @@ -9551,11 +9568,6 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * elem_type = t->DynamicArray.elem; context_name = str_lit("dynamic array literal"); is_constant = false; - - if (!build_context.no_dynamic_literals) { - add_package_dependency(c, "runtime", "__dynamic_array_reserve"); - add_package_dependency(c, "runtime", "__dynamic_array_append"); - } } else if (t->kind == Type_SimdVector) { elem_type = t->SimdVector.elem; context_name = str_lit("simd vector literal"); @@ -9730,11 +9742,9 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * if (t->kind == Type_DynamicArray) { - if (build_context.no_dynamic_literals && cl->elems.count && (node->file()->feature_flags & OptInFeatureFlag_DynamicLiterals) != 0) { - ERROR_BLOCK(); - error(node, "Compound literals of dynamic types have been disabled"); - error_line("\tSuggestion: If you want to enable them for this specific file, use '#+feature dynamic-literals' at the top of the file\n"); - error_line("\tWarning: Please understand that dynamic literals will implicitly allocate using the current 'context.allocator' in that scope\n"); + if (check_for_dynamic_literals(c, node, cl)) { + add_package_dependency(c, "runtime", "__dynamic_array_reserve"); + add_package_dependency(c, "runtime", "__dynamic_array_append"); } } @@ -10123,12 +10133,7 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * } } - if (build_context.no_dynamic_literals && cl->elems.count && (node->file()->feature_flags & OptInFeatureFlag_DynamicLiterals) != 0) { - ERROR_BLOCK(); - error(node, "Compound literals of dynamic types have been disabled"); - error_line("\tSuggestion: If you want to enable them for this specific file, use '#+feature dynamic-literals' at the top of the file\n"); - error_line("\tWarning: Please understand that dynamic literals will implicitly allocate using the current 'context.allocator' in that scope\n"); - } else { + if (check_for_dynamic_literals(c, node, cl)) { add_map_reserve_dependencies(c); add_map_set_dependencies(c); } diff --git a/src/checker.cpp b/src/checker.cpp index 7e0a64d75..5d3263789 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -542,6 +542,23 @@ gb_internal u64 check_vet_flags(Ast *node) { return ast_file_vet_flags(file); } +gb_internal u64 check_feature_flags(CheckerContext *c, Ast *node) { + AstFile *file = c->file; + if (file == nullptr && + c->curr_proc_decl && + c->curr_proc_decl->proc_lit) { + file = c->curr_proc_decl->proc_lit->file(); + } + if (file == nullptr) { + file = node->file(); + } + if (file != nullptr && file->feature_flags_set) { + return file->feature_flags; + } + return 0; +} + + enum VettedEntityKind { VettedEntity_Invalid, @@ -1164,7 +1181,6 @@ gb_internal void init_universal(void) { add_global_bool_constant("ODIN_NO_BOUNDS_CHECK", build_context.no_bounds_check); add_global_bool_constant("ODIN_NO_TYPE_ASSERT", build_context.no_type_assert); add_global_bool_constant("ODIN_DEFAULT_TO_PANIC_ALLOCATOR", bc->ODIN_DEFAULT_TO_PANIC_ALLOCATOR); - add_global_bool_constant("ODIN_NO_DYNAMIC_LITERALS", bc->no_dynamic_literals); add_global_bool_constant("ODIN_NO_CRT", bc->no_crt); add_global_bool_constant("ODIN_USE_SEPARATE_MODULES", bc->use_separate_modules); add_global_bool_constant("ODIN_TEST", bc->command_kind == Command_test); diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 01ded321e..696ced0df 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -1096,8 +1096,6 @@ gb_internal void lb_internal_dynamic_map_set(lbProcedure *p, lbValue const &map_ } gb_internal lbValue lb_dynamic_map_reserve(lbProcedure *p, lbValue const &map_ptr, isize const capacity, TokenPos const &pos) { - GB_ASSERT(!build_context.no_dynamic_literals); - TEMPORARY_ALLOCATOR_GUARD(); String proc_name = {}; diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 3b238bcd8..df9dca801 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -4813,7 +4813,7 @@ gb_internal lbAddr lb_build_addr_compound_lit(lbProcedure *p, Ast *expr) { if (cl->elems.count == 0) { break; } - GB_ASSERT(!build_context.no_dynamic_literals); + GB_ASSERT(expr->file()->feature_flags & OptInFeatureFlag_DynamicLiterals); lbValue err = lb_dynamic_map_reserve(p, v.addr, 2*cl->elems.count, pos); gb_unused(err); @@ -4902,7 +4902,7 @@ gb_internal lbAddr lb_build_addr_compound_lit(lbProcedure *p, Ast *expr) { if (cl->elems.count == 0) { break; } - GB_ASSERT(!build_context.no_dynamic_literals); + GB_ASSERT(expr->file()->feature_flags & OptInFeatureFlag_DynamicLiterals); Type *et = bt->DynamicArray.elem; lbValue size = lb_const_int(p->module, t_int, type_size_of(et)); diff --git a/src/main.cpp b/src/main.cpp index 0450c61ec..41c7170f6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1192,7 +1192,7 @@ gb_internal bool parse_build_flags(Array args) { build_context.no_type_assert = true; break; case BuildFlag_NoDynamicLiterals: - build_context.no_dynamic_literals = true; + gb_printf_err("Warning: Use of -no-dynamic-literals is now redundant\n"); break; case BuildFlag_NoCRT: build_context.no_crt = true; diff --git a/src/parser.cpp b/src/parser.cpp index 01ed46ebc..e190bc5a5 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -6320,7 +6320,7 @@ gb_internal u64 parse_feature_tag(Token token_for_pos, String s) { } } - u64 flag = get_vet_flag_from_name(p); + u64 flag = get_feature_flag_from_name(p); if (flag != OptInFeatureFlag_NONE) { if (is_notted) { feature_not_flags |= flag; @@ -6473,7 +6473,7 @@ gb_internal bool parse_file_tag(const String &lc, const Token &tok, AstFile *f) } else if (lc == "no-instrumentation") { f->flags |= AstFile_NoInstrumentation; } else if (string_starts_with(lc, str_lit("feature"))) { - f->feature_flags = parse_feature_tag(tok, lc); + f->feature_flags |= parse_feature_tag(tok, lc); f->feature_flags_set = true; } else { error(tok, "Unknown tag '%.*s'", LIT(lc)); -- cgit v1.2.3 From 7da7d4e4103d20d757a371f614d3343f8fd15c85 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 5 Jan 2025 15:41:51 +0000 Subject: Allow `#+` tags on single files --- src/parser.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/parser.cpp b/src/parser.cpp index e190bc5a5..03c5a5962 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -6462,6 +6462,9 @@ gb_internal bool parse_file_tag(const String &lc, const Token &tok, AstFile *f) } else if (command == "file") { f->flags |= AstFile_IsPrivateFile; } + } else if (string_starts_with(lc, str_lit("feature"))) { + f->feature_flags |= parse_feature_tag(tok, lc); + f->feature_flags_set = true; } else if (lc == "lazy") { if (build_context.ignore_lazy) { // Ignore @@ -6472,9 +6475,6 @@ gb_internal bool parse_file_tag(const String &lc, const Token &tok, AstFile *f) } } else if (lc == "no-instrumentation") { f->flags |= AstFile_NoInstrumentation; - } else if (string_starts_with(lc, str_lit("feature"))) { - f->feature_flags |= parse_feature_tag(tok, lc); - f->feature_flags_set = true; } else { error(tok, "Unknown tag '%.*s'", LIT(lc)); } @@ -6559,9 +6559,7 @@ gb_internal bool parse_file(Parser *p, AstFile *f) { } f->package_name = package_name.string; - // TODO: Shouldn't single file only matter for build tags? no-instrumentation for example - // should be respected even when in single file mode. - if (!f->pkg->is_single_file) { + { if (docs != nullptr && docs->list.count > 0) { for (Token const &tok : docs->list) { GB_ASSERT(tok.kind == Token_Comment); -- cgit v1.2.3 From 2aae4cfd461860bd10dcb922f867c98212a11449 Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Wed, 8 Jan 2025 18:46:25 +0100 Subject: fix #no_nil in debug info Fixes #4664 --- src/llvm_backend_debug.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/llvm_backend_debug.cpp b/src/llvm_backend_debug.cpp index 464f7065c..3951fc977 100644 --- a/src/llvm_backend_debug.cpp +++ b/src/llvm_backend_debug.cpp @@ -415,6 +415,7 @@ gb_internal LLVMMetadataRef lb_debug_union(lbModule *m, Type *type, String name, LLVMMetadataRef member_scope = lb_get_llvm_metadata(m, bt->Union.scope); unsigned element_count = cast(unsigned)bt->Union.variants.count; if (index_offset > 0) { + GB_ASSERT(index_offset == 1); element_count += 1; } @@ -437,13 +438,11 @@ gb_internal LLVMMetadataRef lb_debug_union(lbModule *m, Type *type, String name, for_array(j, bt->Union.variants) { Type *variant = bt->Union.variants[j]; - unsigned field_index = cast(unsigned)(index_offset+j); - - char name[16] = {}; - gb_snprintf(name, gb_size_of(name), "v%u", field_index); + char name[32] = {}; + gb_snprintf(name, gb_size_of(name), "v%td", j); isize name_len = gb_strlen(name); - elements[field_index] = LLVMDIBuilderCreateMemberType( + elements[index_offset+j] = LLVMDIBuilderCreateMemberType( m->debug_builder, member_scope, name, name_len, file, line, -- cgit v1.2.3 From 7185a93a8631060958565d6e3fba03b4b6eeccce Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Wed, 8 Jan 2025 20:22:59 +0100 Subject: actually fix #no_nil debug info Fixes #4664 --- src/llvm_backend_debug.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/llvm_backend_debug.cpp b/src/llvm_backend_debug.cpp index 3951fc977..6740cd1a2 100644 --- a/src/llvm_backend_debug.cpp +++ b/src/llvm_backend_debug.cpp @@ -438,8 +438,13 @@ gb_internal LLVMMetadataRef lb_debug_union(lbModule *m, Type *type, String name, for_array(j, bt->Union.variants) { Type *variant = bt->Union.variants[j]; + ptrdiff_t variant_index = j; + if (bt->Union.kind == UnionType_no_nil) { + variant_index += 1; + } + char name[32] = {}; - gb_snprintf(name, gb_size_of(name), "v%td", j); + gb_snprintf(name, gb_size_of(name), "v%td", variant_index); isize name_len = gb_strlen(name); elements[index_offset+j] = LLVMDIBuilderCreateMemberType( -- cgit v1.2.3 From b3c359557e7c3a1a298ac5b46af122415e43bf77 Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Wed, 8 Jan 2025 21:24:22 +0100 Subject: `#no_nil` third time's the charm --- src/llvm_backend_debug.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/llvm_backend_debug.cpp b/src/llvm_backend_debug.cpp index 6740cd1a2..2252c4a31 100644 --- a/src/llvm_backend_debug.cpp +++ b/src/llvm_backend_debug.cpp @@ -439,7 +439,7 @@ gb_internal LLVMMetadataRef lb_debug_union(lbModule *m, Type *type, String name, Type *variant = bt->Union.variants[j]; ptrdiff_t variant_index = j; - if (bt->Union.kind == UnionType_no_nil) { + if (bt->Union.kind != UnionType_no_nil) { variant_index += 1; } -- cgit v1.2.3 From 2620721128b2835826faa5d224bf9373a92b1998 Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Wed, 8 Jan 2025 21:45:59 +0100 Subject: '#no_nil' I am actually disappointed in myself --- src/llvm_backend_debug.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/llvm_backend_debug.cpp b/src/llvm_backend_debug.cpp index 2252c4a31..fbb25960a 100644 --- a/src/llvm_backend_debug.cpp +++ b/src/llvm_backend_debug.cpp @@ -408,8 +408,12 @@ gb_internal LLVMMetadataRef lb_debug_union(lbModule *m, Type *type, String name, lb_set_llvm_metadata(m, type, temp_forward_decl); isize index_offset = 1; + isize variant_offset = 1; if (is_type_union_maybe_pointer(bt)) { index_offset = 0; + variant_offset = 0; + } else if (bt->Union.kind == UnionType_no_nil) { + variant_offset = 0; } LLVMMetadataRef member_scope = lb_get_llvm_metadata(m, bt->Union.scope); @@ -438,13 +442,8 @@ gb_internal LLVMMetadataRef lb_debug_union(lbModule *m, Type *type, String name, for_array(j, bt->Union.variants) { Type *variant = bt->Union.variants[j]; - ptrdiff_t variant_index = j; - if (bt->Union.kind != UnionType_no_nil) { - variant_index += 1; - } - char name[32] = {}; - gb_snprintf(name, gb_size_of(name), "v%td", variant_index); + gb_snprintf(name, gb_size_of(name), "v%td", variant_offset+j); isize name_len = gb_strlen(name); elements[index_offset+j] = LLVMDIBuilderCreateMemberType( -- cgit v1.2.3 From 328d893cb58d4b96f12207eb49da01273deda6ce Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 10 Jan 2025 12:14:43 +0000 Subject: `#unroll(N) for` --- core/odin/ast/ast.odin | 7 +- core/odin/ast/clone.odin | 3 +- core/odin/parser/parser.odin | 43 +++++++- src/check_stmt.cpp | 65 ++++++++++-- src/llvm_backend_stmt.cpp | 241 +++++++++++++++++++++++++++++++++---------- src/parser.cpp | 58 +++++++++-- src/parser.hpp | 1 + 7 files changed, 340 insertions(+), 78 deletions(-) (limited to 'src') diff --git a/core/odin/ast/ast.odin b/core/odin/ast/ast.odin index f62feec8c..3b8998b31 100644 --- a/core/odin/ast/ast.odin +++ b/core/odin/ast/ast.odin @@ -432,10 +432,13 @@ Range_Stmt :: struct { reverse: bool, } -Inline_Range_Stmt :: struct { +Inline_Range_Stmt :: Unroll_Range_Stmt + +Unroll_Range_Stmt :: struct { using node: Stmt, label: ^Expr, - inline_pos: tokenizer.Pos, + unroll_pos: tokenizer.Pos, + args: []^Expr, for_pos: tokenizer.Pos, val0: ^Expr, val1: ^Expr, diff --git a/core/odin/ast/clone.odin b/core/odin/ast/clone.odin index 67f7ffa95..b7501e6ca 100644 --- a/core/odin/ast/clone.odin +++ b/core/odin/ast/clone.odin @@ -242,8 +242,9 @@ clone_node :: proc(node: ^Node) -> ^Node { r.vals = clone(r.vals) r.expr = clone(r.expr) r.body = clone(r.body) - case ^Inline_Range_Stmt: + case ^Unroll_Range_Stmt: r.label = clone(r.label) + r.args = clone(r.args) r.val0 = clone(r.val0) r.val1 = clone(r.val1) r.expr = clone(r.expr) diff --git a/core/odin/parser/parser.odin b/core/odin/parser/parser.odin index 5a7440339..63c7e388f 100644 --- a/core/odin/parser/parser.odin +++ b/core/odin/parser/parser.odin @@ -1262,11 +1262,49 @@ parse_foreign_decl :: proc(p: ^Parser) -> ^ast.Decl { parse_unrolled_for_loop :: proc(p: ^Parser, inline_tok: tokenizer.Token) -> ^ast.Stmt { - for_tok := expect_token(p, .For) val0, val1: ^ast.Expr in_tok: tokenizer.Token expr: ^ast.Expr body: ^ast.Stmt + args: [dynamic]^ast.Expr + + if allow_token(p, .Open_Paren) { + p.expr_level += 1 + if p.curr_tok.kind == .Close_Paren { + error(p, p.curr_tok.pos, "#unroll expected at least 1 argument, got 0") + } else { + args = make([dynamic]^ast.Expr) + for p.curr_tok.kind != .Close_Paren && + p.curr_tok.kind != .EOF { + arg := parse_value(p) + + if p.curr_tok.kind == .Eq { + eq := expect_token(p, .Eq) + if arg != nil { + if _, ok := arg.derived.(^ast.Ident); !ok { + error(p, arg.pos, "expected an identifier for 'key=value'") + } + } + value := parse_value(p) + fv := ast.new(ast.Field_Value, arg.pos, value) + fv.field = arg + fv.sep = eq.pos + fv.value = value + + arg = fv + } + + append(&args, arg) + + allow_token(p, .Comma) or_break + } + } + + p.expr_level -= 1 + _ = expect_token_after(p, .Close_Paren, "#unroll") + } + + for_tok := expect_token(p, .For) bad_stmt := false @@ -1309,7 +1347,8 @@ parse_unrolled_for_loop :: proc(p: ^Parser, inline_tok: tokenizer.Token) -> ^ast } range_stmt := ast.new(ast.Inline_Range_Stmt, inline_tok.pos, body) - range_stmt.inline_pos = inline_tok.pos + range_stmt.unroll_pos = inline_tok.pos + range_stmt.args = args[:] range_stmt.for_pos = for_tok.pos range_stmt.val0 = val0 range_stmt.val1 = val1 diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index 02ad72388..1708f7c81 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -894,15 +894,49 @@ gb_internal void error_var_decl_identifier(Ast *name) { } } -gb_internal void check_inline_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) { +gb_internal void check_unroll_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) { ast_node(irs, UnrollRangeStmt, node); check_open_scope(ctx, node); + defer (check_close_scope(ctx)); Type *val0 = nullptr; Type *val1 = nullptr; Entity *entities[2] = {}; isize entity_count = 0; + i64 unroll_count = -1; + + if (irs->args.count > 0) { + if (irs->args.count > 1) { + error(irs->args[1], "#unroll only supports a single argument for the unroll per loop amount"); + } + Ast *arg = irs->args[0]; + if (arg->kind == Ast_FieldValue) { + error(arg, "#unroll does not yet support named arguments"); + arg = arg->FieldValue.value; + } + + Operand x = {}; + check_expr(ctx, &x, arg); + if (x.mode != Addressing_Constant || !is_type_integer(x.type)) { + gbString s = expr_to_string(x.expr); + error(x.expr, "Expected a constant integer for #unroll, got '%s'", s); + gb_string_free(s); + } else { + ExactValue value = exact_value_to_integer(x.value); + i64 v = exact_value_to_i64(value); + if (v < 1) { + error(x.expr, "Expected a constant integer >= 1 for #unroll, got %lld", cast(long long)v); + } else { + unroll_count = v; + if (v > 1024) { + error(x.expr, "Too large of a value for #unroll, got %lld, expected <= 1024", cast(long long)v); + } + } + + } + } + Ast *expr = unparen_expr(irs->expr); ExactValue inline_for_depth = exact_value_i64(0); @@ -946,18 +980,39 @@ gb_internal void check_inline_range_stmt(CheckerContext *ctx, Ast *node, u32 mod val0 = t_rune; val1 = t_int; inline_for_depth = exact_value_i64(operand.value.value_string.len); + if (unroll_count > 0) { + error(node, "#unroll(%lld) does not support strings", cast(long long)unroll_count); + } } break; case Type_Array: val0 = t->Array.elem; val1 = t_int; - inline_for_depth = exact_value_i64(t->Array.count); + inline_for_depth = unroll_count > 0 ? exact_value_i64(unroll_count) : exact_value_i64(t->Array.count); break; case Type_EnumeratedArray: val0 = t->EnumeratedArray.elem; val1 = t->EnumeratedArray.index; + if (unroll_count > 0) { + error(node, "#unroll(%lld) does not support enumerated arrays", cast(long long)unroll_count); + } inline_for_depth = exact_value_i64(t->EnumeratedArray.count); break; + + case Type_Slice: + if (unroll_count > 0) { + val0 = t->Slice.elem; + val1 = t_int; + inline_for_depth = exact_value_i64(unroll_count); + } + break; + case Type_DynamicArray: + if (unroll_count > 0) { + val0 = t->DynamicArray.elem; + val1 = t_int; + inline_for_depth = exact_value_i64(unroll_count); + } + break; } } @@ -967,7 +1022,7 @@ gb_internal void check_inline_range_stmt(CheckerContext *ctx, Ast *node, u32 mod error(operand.expr, "Cannot iterate over '%s' of type '%s' in an '#unroll for' statement", s, t); gb_string_free(t); gb_string_free(s); - } else if (operand.mode != Addressing_Constant) { + } else if (operand.mode != Addressing_Constant && unroll_count <= 0) { error(operand.expr, "An '#unroll for' expression must be known at compile time"); } } @@ -1050,8 +1105,6 @@ gb_internal void check_inline_range_stmt(CheckerContext *ctx, Ast *node, u32 mod check_stmt(ctx, irs->body, mod_flags); - - check_close_scope(ctx); } gb_internal void check_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) { @@ -2679,7 +2732,7 @@ gb_internal void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) case_end; case_ast_node(irs, UnrollRangeStmt, node); - check_inline_range_stmt(ctx, node, mod_flags); + check_unroll_range_stmt(ctx, node, mod_flags); case_end; case_ast_node(ss, SwitchStmt, node); diff --git a/src/llvm_backend_stmt.cpp b/src/llvm_backend_stmt.cpp index a2f0d2f4a..b05df0b46 100644 --- a/src/llvm_backend_stmt.cpp +++ b/src/llvm_backend_stmt.cpp @@ -256,7 +256,7 @@ gb_internal void lb_build_when_stmt(lbProcedure *p, AstWhenStmt *ws) { gb_internal void lb_build_range_indexed(lbProcedure *p, lbValue expr, Type *val_type, lbValue count_ptr, lbValue *val_, lbValue *idx_, lbBlock **loop_, lbBlock **done_, - bool is_reverse) { + bool is_reverse, i64 unroll_count=0) { lbModule *m = p->module; lbValue count = {}; @@ -1230,7 +1230,6 @@ gb_internal void lb_build_unroll_range_stmt(lbProcedure *p, AstUnrollRangeStmt * TypeAndValue tav = type_and_value_of_expr(expr); if (is_ast_range(expr)) { - lbAddr val0_addr = {}; lbAddr val1_addr = {}; if (val0_type) val0_addr = lb_build_addr(p, val0); @@ -1268,7 +1267,6 @@ gb_internal void lb_build_unroll_range_stmt(lbProcedure *p, AstUnrollRangeStmt * } } - } else if (tav.mode == Addressing_Type) { GB_ASSERT(is_type_enum(type_deref(tav.type))); Type *et = type_deref(tav.type); @@ -1293,72 +1291,203 @@ gb_internal void lb_build_unroll_range_stmt(lbProcedure *p, AstUnrollRangeStmt * if (val0_type) val0_addr = lb_build_addr(p, val0); if (val1_type) val1_addr = lb_build_addr(p, val1); - GB_ASSERT(expr->tav.mode == Addressing_Constant); + ExactValue unroll_count_ev = {}; + if (rs->args.count != 0) { + unroll_count_ev = rs->args[0]->tav.value; + } - Type *t = base_type(expr->tav.type); + if (unroll_count_ev.kind == ExactValue_Invalid) { + GB_ASSERT(expr->tav.mode == Addressing_Constant); - switch (t->kind) { - case Type_Basic: - GB_ASSERT(is_type_string(t)); - { - ExactValue value = expr->tav.value; - GB_ASSERT(value.kind == ExactValue_String); - String str = value.value_string; - Rune codepoint = 0; - isize offset = 0; - do { - isize width = utf8_decode(str.text+offset, str.len-offset, &codepoint); - if (val0_type) lb_addr_store(p, val0_addr, lb_const_value(m, val0_type, exact_value_i64(codepoint))); - if (val1_type) lb_addr_store(p, val1_addr, lb_const_value(m, val1_type, exact_value_i64(offset))); - lb_build_stmt(p, rs->body); + Type *t = base_type(expr->tav.type); - offset += width; - } while (offset < str.len); - } - break; - case Type_Array: - if (t->Array.count > 0) { - lbValue val = lb_build_expr(p, expr); - lbValue val_addr = lb_address_from_load_or_generate_local(p, val); - - for (i64 i = 0; i < t->Array.count; i++) { - if (val0_type) { - // NOTE(bill): Due to weird legacy issues in LLVM, this needs to be an i32 - lbValue elem = lb_emit_array_epi(p, val_addr, cast(i32)i); - lb_addr_store(p, val0_addr, lb_emit_load(p, elem)); - } - if (val1_type) lb_addr_store(p, val1_addr, lb_const_value(m, val1_type, exact_value_i64(i))); + switch (t->kind) { + case Type_Basic: + GB_ASSERT(is_type_string(t)); + { + ExactValue value = expr->tav.value; + GB_ASSERT(value.kind == ExactValue_String); + String str = value.value_string; + Rune codepoint = 0; + isize offset = 0; + do { + isize width = utf8_decode(str.text+offset, str.len-offset, &codepoint); + if (val0_type) lb_addr_store(p, val0_addr, lb_const_value(m, val0_type, exact_value_i64(codepoint))); + if (val1_type) lb_addr_store(p, val1_addr, lb_const_value(m, val1_type, exact_value_i64(offset))); + lb_build_stmt(p, rs->body); - lb_build_stmt(p, rs->body); + offset += width; + } while (offset < str.len); } + break; + case Type_Array: + if (t->Array.count > 0) { + lbValue val = lb_build_expr(p, expr); + lbValue val_addr = lb_address_from_load_or_generate_local(p, val); + + for (i64 i = 0; i < t->Array.count; i++) { + if (val0_type) { + // NOTE(bill): Due to weird legacy issues in LLVM, this needs to be an i32 + lbValue elem = lb_emit_array_epi(p, val_addr, cast(i32)i); + lb_addr_store(p, val0_addr, lb_emit_load(p, elem)); + } + if (val1_type) lb_addr_store(p, val1_addr, lb_const_value(m, val1_type, exact_value_i64(i))); - } - break; - case Type_EnumeratedArray: - if (t->EnumeratedArray.count > 0) { - lbValue val = lb_build_expr(p, expr); - lbValue val_addr = lb_address_from_load_or_generate_local(p, val); - - for (i64 i = 0; i < t->EnumeratedArray.count; i++) { - if (val0_type) { - // NOTE(bill): Due to weird legacy issues in LLVM, this needs to be an i32 - lbValue elem = lb_emit_array_epi(p, val_addr, cast(i32)i); - lb_addr_store(p, val0_addr, lb_emit_load(p, elem)); + lb_build_stmt(p, rs->body); } - if (val1_type) { - ExactValue idx = exact_value_add(exact_value_i64(i), *t->EnumeratedArray.min_value); - lb_addr_store(p, val1_addr, lb_const_value(m, val1_type, idx)); + + } + break; + case Type_EnumeratedArray: + if (t->EnumeratedArray.count > 0) { + lbValue val = lb_build_expr(p, expr); + lbValue val_addr = lb_address_from_load_or_generate_local(p, val); + + for (i64 i = 0; i < t->EnumeratedArray.count; i++) { + if (val0_type) { + // NOTE(bill): Due to weird legacy issues in LLVM, this needs to be an i32 + lbValue elem = lb_emit_array_epi(p, val_addr, cast(i32)i); + lb_addr_store(p, val0_addr, lb_emit_load(p, elem)); + } + if (val1_type) { + ExactValue idx = exact_value_add(exact_value_i64(i), *t->EnumeratedArray.min_value); + lb_addr_store(p, val1_addr, lb_const_value(m, val1_type, idx)); + } + + lb_build_stmt(p, rs->body); } - lb_build_stmt(p, rs->body); } + break; + default: + GB_PANIC("Invalid '#unroll for' type"); + break; + } + } else { + + //////////////////////////////// + // // + // #unroll(N) logic // + // // + //////////////////////////////// + + + i64 unroll_count = exact_value_to_i64(unroll_count_ev); + gb_unused(unroll_count); + + Type *t = base_type(expr->tav.type); + + lbValue data_ptr = {}; + lbValue count_ptr = {}; + switch (t->kind) { + case Type_Slice: + case Type_DynamicArray: { + lbValue slice = lb_build_expr(p, expr); + if (is_type_pointer(slice.type)) { + count_ptr = lb_emit_struct_ep(p, slice, 1); + slice = lb_emit_load(p, slice); + } else { + count_ptr = lb_add_local_generated(p, t_int, false).addr; + lb_emit_store(p, count_ptr, lb_slice_len(p, slice)); + } + data_ptr = lb_emit_struct_ev(p, slice, 0); + break; } - break; - default: - GB_PANIC("Invalid '#unroll for' type"); - break; + + case Type_Array: { + lbValue array = lb_build_expr(p, expr); + count_ptr = lb_add_local_generated(p, t_int, false).addr; + lb_emit_store(p, count_ptr, lb_const_int(p->module, t_int, t->Array.count)); + + if (!is_type_pointer(array.type)) { + array = lb_address_from_load_or_generate_local(p, array); + } + + GB_ASSERT(is_type_pointer(array.type)); + data_ptr = lb_emit_conv(p, array, alloc_type_pointer(t->Array.elem)); + break; + } + + default: + GB_PANIC("Invalid '#unroll for' type"); + break; + } + + data_ptr.type = alloc_type_multi_pointer_to_pointer(data_ptr.type); + + lbBlock *loop_top = lb_create_block(p, "for.unroll.loop.top"); + + lbBlock *body_top = lb_create_block(p, "for.unroll.body.top"); + lbBlock *body_bot = lb_create_block(p, "for.unroll.body.bot"); + + lbBlock *done = lb_create_block(p, "for.unroll.done"); + + lbBlock *loop_bot = unroll_count > 1 ? lb_create_block(p, "for.unroll.loop.bot") : done; + + /* + i := 0 + for ; i+N <= len(array); i += N { + body + } + for ; i < len(array); i += 1 { + body + } + */ + + Entity *val_entity = val0 ? entity_of_node(val0) : nullptr; + Entity *idx_entity = val1 ? entity_of_node(val1) : nullptr; + + lbAddr val_addr = lb_add_local(p, type_deref(data_ptr.type, true), val_entity); + lbAddr idx_addr = lb_add_local(p, t_int, idx_entity); + lb_addr_store(p, idx_addr, lb_const_nil(p->module, t_int)); + + lb_emit_jump(p, loop_top); + lb_start_block(p, loop_top); + + lbValue idx_add_n = lb_addr_load(p, idx_addr); + idx_add_n = lb_emit_arith(p, Token_Add, idx_add_n, lb_const_int(p->module, t_int, unroll_count), t_int); + + lbValue cond_top = lb_emit_comp(p, Token_LtEq, idx_add_n, lb_emit_load(p, count_ptr)); + lb_emit_if(p, cond_top, body_top, loop_bot); + + lb_start_block(p, body_top); + for (i64 top = 0; top < unroll_count; top++) { + lbValue idx = lb_addr_load(p, idx_addr); + lbValue val = lb_emit_load(p, lb_emit_ptr_offset(p, data_ptr, idx)); + lb_addr_store(p, val_addr, val); + + lb_build_stmt(p, rs->body); + + lb_emit_increment(p, lb_addr_get_ptr(p, idx_addr)); + } + lb_emit_jump(p, loop_top); + + if (unroll_count > 1) { + lb_start_block(p, loop_bot); + + lbValue cond_bot = lb_emit_comp(p, Token_Lt, lb_addr_load(p, idx_addr), lb_emit_load(p, count_ptr)); + lb_emit_if(p, cond_bot, body_bot, done); + + lb_start_block(p, body_bot); + { + lbValue idx = lb_addr_load(p, idx_addr); + lbValue val = lb_emit_load(p, lb_emit_ptr_offset(p, data_ptr, idx)); + lb_addr_store(p, val_addr, val); + + lb_build_stmt(p, rs->body); + + lb_emit_increment(p, lb_addr_get_ptr(p, idx_addr)); + } + lb_emit_jump(p, loop_bot); + } + + lb_close_scope(p, lbDeferExit_Default, nullptr, rs->body); + lb_emit_jump(p, done); + lb_start_block(p, done); + + return; } } diff --git a/src/parser.cpp b/src/parser.cpp index 03c5a5962..94f8fd42c 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -348,10 +348,11 @@ gb_internal Ast *clone_ast(Ast *node, AstFile *f) { n->RangeStmt.body = clone_ast(n->RangeStmt.body, f); break; case Ast_UnrollRangeStmt: - n->UnrollRangeStmt.val0 = clone_ast(n->UnrollRangeStmt.val0, f); - n->UnrollRangeStmt.val1 = clone_ast(n->UnrollRangeStmt.val1, f); - n->UnrollRangeStmt.expr = clone_ast(n->UnrollRangeStmt.expr, f); - n->UnrollRangeStmt.body = clone_ast(n->UnrollRangeStmt.body, f); + n->UnrollRangeStmt.args = clone_ast_array(n->UnrollRangeStmt.args, f); + n->UnrollRangeStmt.val0 = clone_ast(n->UnrollRangeStmt.val0, f); + n->UnrollRangeStmt.val1 = clone_ast(n->UnrollRangeStmt.val1, f); + n->UnrollRangeStmt.expr = clone_ast(n->UnrollRangeStmt.expr, f); + n->UnrollRangeStmt.body = clone_ast(n->UnrollRangeStmt.body, f); break; case Ast_CaseClause: n->CaseClause.list = clone_ast_array(n->CaseClause.list, f); @@ -1037,15 +1038,16 @@ gb_internal Ast *ast_range_stmt(AstFile *f, Token token, Slice vals, Toke return result; } -gb_internal Ast *ast_unroll_range_stmt(AstFile *f, Token unroll_token, Token for_token, Ast *val0, Ast *val1, Token in_token, Ast *expr, Ast *body) { +gb_internal Ast *ast_unroll_range_stmt(AstFile *f, Token unroll_token, Slice args, Token for_token, Ast *val0, Ast *val1, Token in_token, Ast *expr, Ast *body) { Ast *result = alloc_ast_node(f, Ast_UnrollRangeStmt); result->UnrollRangeStmt.unroll_token = unroll_token; + result->UnrollRangeStmt.args = args; result->UnrollRangeStmt.for_token = for_token; - result->UnrollRangeStmt.val0 = val0; - result->UnrollRangeStmt.val1 = val1; - result->UnrollRangeStmt.in_token = in_token; - result->UnrollRangeStmt.expr = expr; - result->UnrollRangeStmt.body = body; + result->UnrollRangeStmt.val0 = val0; + result->UnrollRangeStmt.val1 = val1; + result->UnrollRangeStmt.in_token = in_token; + result->UnrollRangeStmt.expr = expr; + result->UnrollRangeStmt.body = body; return result; } @@ -5137,6 +5139,40 @@ gb_internal Ast *parse_attribute(AstFile *f, Token token, TokenKind open_kind, T gb_internal Ast *parse_unrolled_for_loop(AstFile *f, Token unroll_token) { + Array args = {}; + + if (allow_token(f, Token_OpenParen)) { + f->expr_level++; + if (f->curr_token.kind == Token_CloseParen) { + syntax_error(f->curr_token, "#unroll expected at least 1 argument, got 0"); + } else { + args = array_make(ast_allocator(f)); + while (f->curr_token.kind != Token_CloseParen && + f->curr_token.kind != Token_EOF) { + Ast *arg = nullptr; + arg = parse_value(f); + + if (f->curr_token.kind == Token_Eq) { + Token eq = expect_token(f, Token_Eq); + if (arg != nullptr && arg->kind != Ast_Ident) { + syntax_error(arg, "Expected an identifier for 'key=value'"); + } + Ast *value = parse_value(f); + arg = ast_field_value(f, arg, value, eq); + } + + array_add(&args, arg); + + if (!allow_field_separator(f)) { + break; + } + } + } + f->expr_level--; + Token close = expect_closing(f, Token_CloseParen, str_lit("#unroll")); + gb_unused(close); + } + Token for_token = expect_token(f, Token_for); Ast *val0 = nullptr; Ast *val1 = nullptr; @@ -5180,7 +5216,7 @@ gb_internal Ast *parse_unrolled_for_loop(AstFile *f, Token unroll_token) { if (bad_stmt) { return ast_bad_stmt(f, unroll_token, f->curr_token); } - return ast_unroll_range_stmt(f, unroll_token, for_token, val0, val1, in_token, expr, body); + return ast_unroll_range_stmt(f, unroll_token, slice_from_array(args), for_token, val0, val1, in_token, expr, body); } gb_internal Ast *parse_stmt(AstFile *f) { diff --git a/src/parser.hpp b/src/parser.hpp index bbf70d03e..d2dd22667 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -563,6 +563,7 @@ AST_KIND(_ComplexStmtBegin, "", bool) \ AST_KIND(UnrollRangeStmt, "#unroll range statement", struct { \ Scope *scope; \ Token unroll_token; \ + Slice args; \ Token for_token; \ Ast *val0; \ Ast *val1; \ -- cgit v1.2.3 From 794e812932fb291e5dc8157e06e8a132c8231e17 Mon Sep 17 00:00:00 2001 From: Harold Brenes Date: Wed, 15 Jan 2025 02:04:49 -0500 Subject: Fixes crash when unused defines are used in conjunction with `-ignore-warnings`. --- src/main.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/main.cpp b/src/main.cpp index 41c7170f6..1de5d987b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1801,7 +1801,10 @@ gb_internal void check_defines(BuildContext *bc, Checker *c) { if (!found) { ERROR_BLOCK(); warning(nullptr, "given -define:%.*s is unused in the project", LIT(name)); - error_line("\tSuggestion: use the -show-defineables flag for an overview of the possible defines\n"); + + if (!global_ignore_warnings()) { + error_line("\tSuggestion: use the -show-defineables flag for an overview of the possible defines\n"); + } } } } -- cgit v1.2.3 From aa3f0b86c143802d9e81122698e38361751c7a68 Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Wed, 15 Jan 2025 20:14:23 +0100 Subject: compiler: fix align error check --- src/check_type.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/check_type.cpp b/src/check_type.cpp index 44108ccbe..4d9101c6c 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -685,7 +685,8 @@ gb_internal void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast * ST_ALIGN(min_field_align); ST_ALIGN(max_field_align); ST_ALIGN(align); - if (struct_type->Struct.custom_align < struct_type->Struct.custom_min_field_align) { + if (struct_type->Struct.custom_align != 0 && + struct_type->Struct.custom_align < struct_type->Struct.custom_min_field_align) { error(st->align, "#align(%lld) is defined to be less than #min_field_align(%lld)", cast(long long)struct_type->Struct.custom_align, cast(long long)struct_type->Struct.custom_min_field_align); -- cgit v1.2.3 From 87b590c99bb30066f47683f2481b44b8d8226a37 Mon Sep 17 00:00:00 2001 From: flysand7 Date: Thu, 16 Jan 2025 20:07:56 +0300 Subject: Do not warn about stack overflow in range loops 'by reference' --- src/checker.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/checker.cpp b/src/checker.cpp index 5d3263789..85077a5c5 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -749,9 +749,15 @@ gb_internal void check_scope_usage_internal(Checker *c, Scope *scope, u64 vet_fl // TODO(bill): When is a good size warn? // Is >256 KiB good enough? if (sz > 1ll<<18) { - gbString type_str = type_to_string(e->type); - warning(e->token, "Declaration of '%.*s' may cause a stack overflow due to its type '%s' having a size of %lld bytes", LIT(e->token.string), type_str, cast(long long)sz); - gb_string_free(type_str); + bool is_ref = false; + if((e->flags & EntityFlag_ForValue) != 0) { + is_ref = type_deref(e->Variable.for_loop_parent_type) != NULL; + } + if(!is_ref) { + gbString type_str = type_to_string(e->type); + warning(e->token, "Declaration of '%.*s' may cause a stack overflow due to its type '%s' having a size of %lld bytes", LIT(e->token.string), type_str, cast(long long)sz); + gb_string_free(type_str); + } } } } -- cgit v1.2.3 From 4f0206ce08593628bf9458b623f61c2989558f69 Mon Sep 17 00:00:00 2001 From: flysand7 Date: Fri, 17 Jan 2025 01:12:23 +0300 Subject: Added compile-time checks for thread locals with -no-crt Now using any thread-local variables with -no-crt enabled will cause a compiler error, unless -no-thread-local is given. Also fixed a minor typo in a comment. --- src/build_settings.cpp | 16 +++++++++++++++- src/check_expr.cpp | 15 ++++++++++++++- src/main.cpp | 4 ++++ 3 files changed, 33 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 93168cf77..b3321637f 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -2133,7 +2133,21 @@ gb_internal bool init_build_paths(String init_filename) { case TargetOs_openbsd: case TargetOs_netbsd: case TargetOs_haiku: - gb_printf_err("-no-crt on unix systems requires either -default-to-nil-allocator or -default-to-panic-allocator to also be present because the default allocator requires crt\n"); + gb_printf_err("-no-crt on unix systems requires either -default-to-nil-allocator or -default-to-panic-allocator to also be present, because the default allocator requires crt\n"); + return false; + } + } + + if (build_context.no_crt && !build_context.no_thread_local && !build_context.ODIN_DEFAULT_TO_NIL_ALLOCATOR) { + switch (build_context.metrics.os) { + case TargetOs_linux: + case TargetOs_darwin: + case TargetOs_essence: + case TargetOs_freebsd: + case TargetOs_openbsd: + case TargetOs_netbsd: + case TargetOs_haiku: + gb_printf_err("-no-crt on unix systems requires either -default-to-nil-allocator or -no-thread-local to also be present, because the temporary allocator is a thread local, which are inaccessible without CRT initializing TLS\n"); return false; } } diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 231ece2f4..7574c20a7 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -1044,7 +1044,7 @@ gb_internal AstPackage *get_package_of_type(Type *type) { } -// NOTE(bill): 'content_name' is for debugging and error messages +// NOTE(bill): 'context_name' is for debugging and error messages gb_internal void check_assignment(CheckerContext *c, Operand *operand, Type *type, String context_name) { check_not_tuple(c, operand); if (operand->mode == Addressing_Invalid) { @@ -1822,6 +1822,19 @@ gb_internal Entity *check_ident(CheckerContext *c, Operand *o, Ast *n, Type *nam break; case Entity_Variable: + if (e->kind == Entity_Variable && build_context.no_crt && !build_context.no_thread_local && e->Variable.thread_local_model != "") { + switch (build_context.metrics.os) { + case TargetOs_linux: + case TargetOs_darwin: + case TargetOs_essence: + case TargetOs_freebsd: + case TargetOs_openbsd: + case TargetOs_netbsd: + case TargetOs_haiku: + Token token = ast_token(n); + error(token, "Illegal usage of thread locals: '%.*s'", LIT(e->token.string)); + } + } e->flags |= EntityFlag_Used; if (type == t_invalid) { o->type = t_invalid; diff --git a/src/main.cpp b/src/main.cpp index 1de5d987b..24e33850e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2334,6 +2334,10 @@ gb_internal void print_show_help(String const arg0, String command, String optio print_usage_line(2, "Sets the default allocator to be the nil_allocator, an allocator which does nothing."); } + if (print_flag("-default-to-panic-allocator")) { + print_usage_line(2, "Sets the default allocator to be the panic_allocator, an allocator which calls panic() on any allocation attempt."); + } + if (print_flag("-define:=")) { print_usage_line(2, "Defines a scalar boolean, integer or string as global constant."); print_usage_line(2, "Example: -define:SPAM=123"); -- cgit v1.2.3 From 3f20b6324353cfb9e3ad27fe9ee5f8d07148911b Mon Sep 17 00:00:00 2001 From: flysand7 Date: Fri, 17 Jan 2025 02:15:30 +0300 Subject: Error if -no-thread-local is used in presence of -no-crt on Unix --- src/build_settings.cpp | 15 ++++++++++----- src/check_expr.cpp | 13 ------------- 2 files changed, 10 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/src/build_settings.cpp b/src/build_settings.cpp index b3321637f..a8d06d56d 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -2124,6 +2124,7 @@ gb_internal bool init_build_paths(String init_filename) { } } + bool no_crt_checks_failed = false; if (build_context.no_crt && !build_context.ODIN_DEFAULT_TO_NIL_ALLOCATOR && !build_context.ODIN_DEFAULT_TO_PANIC_ALLOCATOR) { switch (build_context.metrics.os) { case TargetOs_linux: @@ -2133,12 +2134,12 @@ gb_internal bool init_build_paths(String init_filename) { case TargetOs_openbsd: case TargetOs_netbsd: case TargetOs_haiku: - gb_printf_err("-no-crt on unix systems requires either -default-to-nil-allocator or -default-to-panic-allocator to also be present, because the default allocator requires crt\n"); - return false; + gb_printf_err("-no-crt on Unix systems requires either -default-to-nil-allocator or -default-to-panic-allocator to also be present, because the default allocator requires CRT\n"); + no_crt_checks_failed = true; } } - if (build_context.no_crt && !build_context.no_thread_local && !build_context.ODIN_DEFAULT_TO_NIL_ALLOCATOR) { + if (build_context.no_crt && !build_context.no_thread_local) { switch (build_context.metrics.os) { case TargetOs_linux: case TargetOs_darwin: @@ -2147,11 +2148,15 @@ gb_internal bool init_build_paths(String init_filename) { case TargetOs_openbsd: case TargetOs_netbsd: case TargetOs_haiku: - gb_printf_err("-no-crt on unix systems requires either -default-to-nil-allocator or -no-thread-local to also be present, because the temporary allocator is a thread local, which are inaccessible without CRT initializing TLS\n"); - return false; + gb_printf_err("-no-crt on Unix systems requires the -no-thread-local flag to also be present, because the TLS is inaccessible without CRT\n"); + no_crt_checks_failed = true; } } + if (no_crt_checks_failed) { + return false; + } + return true; } diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 7574c20a7..349c5dbae 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -1822,19 +1822,6 @@ gb_internal Entity *check_ident(CheckerContext *c, Operand *o, Ast *n, Type *nam break; case Entity_Variable: - if (e->kind == Entity_Variable && build_context.no_crt && !build_context.no_thread_local && e->Variable.thread_local_model != "") { - switch (build_context.metrics.os) { - case TargetOs_linux: - case TargetOs_darwin: - case TargetOs_essence: - case TargetOs_freebsd: - case TargetOs_openbsd: - case TargetOs_netbsd: - case TargetOs_haiku: - Token token = ast_token(n); - error(token, "Illegal usage of thread locals: '%.*s'", LIT(e->token.string)); - } - } e->flags |= EntityFlag_Used; if (type == t_invalid) { o->type = t_invalid; -- cgit v1.2.3 From 5951c25f71b7703d0bd70614a818c37ad82e6c37 Mon Sep 17 00:00:00 2001 From: David Rubin Date: Sat, 18 Jan 2025 02:04:35 -0800 Subject: fix inverted error messages --- src/check_expr.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 349c5dbae..8e4d60d8c 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -1973,10 +1973,10 @@ gb_internal bool check_binary_op(CheckerContext *c, Operand *o, Token op) { case Token_Quo: case Token_QuoEq: if (is_type_matrix(main_type)) { - error(op, "Operator '%.*s' is only allowed with matrix types", LIT(op.string)); + error(op, "Operator '%.*s' is not allowed with matrix types", LIT(op.string)); return false; } else if (is_type_simd_vector(main_type) && is_type_integer(type)) { - error(op, "Operator '%.*s' is only allowed with #simd types with integer elements", LIT(op.string)); + error(op, "Operator '%.*s' is not allowed with #simd types with integer elements", LIT(op.string)); return false; } /*fallthrough*/ @@ -2023,14 +2023,14 @@ gb_internal bool check_binary_op(CheckerContext *c, Operand *o, Token op) { case Token_ModEq: case Token_ModModEq: if (is_type_matrix(main_type)) { - error(op, "Operator '%.*s' is only allowed with matrix types", LIT(op.string)); + error(op, "Operator '%.*s' is not allowed with matrix types", LIT(op.string)); return false; } if (!is_type_integer(type)) { error(op, "Operator '%.*s' is only allowed with integers", LIT(op.string)); return false; } else if (is_type_simd_vector(main_type)) { - error(op, "Operator '%.*s' is only allowed with #simd types with integer elements", LIT(op.string)); + error(op, "Operator '%.*s' is not allowed with #simd types with integer elements", LIT(op.string)); return false; } break; -- cgit v1.2.3 From b25ca0bb11f64a2af887801d451bd8638dba9e76 Mon Sep 17 00:00:00 2001 From: jason Date: Tue, 21 Jan 2025 20:37:02 -0500 Subject: fixes compiler crash on syntax error (issue 4738) --- src/types.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/types.cpp b/src/types.cpp index 233f903a3..0b6e6d334 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -4773,7 +4773,9 @@ gb_internal gbString write_type_to_string(gbString str, Type *type, bool shortha case Type_BitSet: str = gb_string_appendc(str, "bit_set["); - if (is_type_enum(type->BitSet.elem)) { + if (type->BitSet.elem == nullptr) { + str = gb_string_appendc(str, ""); + } else if (is_type_enum(type->BitSet.elem)) { str = write_type_to_string(str, type->BitSet.elem); } else { str = gb_string_append_fmt(str, "%lld", type->BitSet.lower); -- cgit v1.2.3 From e85667c95cdd9c61dccd1e1b747aa07889edcd6a Mon Sep 17 00:00:00 2001 From: jason Date: Tue, 21 Jan 2025 20:48:11 -0500 Subject: fix grammar in error message --- src/check_decl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 1d792dad8..bf6e39bd2 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -60,7 +60,7 @@ gb_internal Type *check_init_variable(CheckerContext *ctx, Entity *e, Operand *o error(operand->expr, "Cannot assign a type '%s' to variable '%.*s'", t, LIT(e->token.string)); } if (e->type == nullptr) { - error_line("\tThe type of the variable '%.*s' cannot be inferred as a type does not have a default type\n", LIT(e->token.string)); + error_line("\tThe type of the variable '%.*s' cannot be inferred as a type and does not have a default type\n", LIT(e->token.string)); } e->type = operand->type; return nullptr; -- cgit v1.2.3 From d6633639dc820e564b41f8dd422b424b0a9dcbec Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 22 Jan 2025 13:01:06 +0000 Subject: Remove duplicates of .framework/.dynlib/.so in linker --- src/linker.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/linker.cpp b/src/linker.cpp index 261d6e7a4..59e6d8dc1 100644 --- a/src/linker.cpp +++ b/src/linker.cpp @@ -536,7 +536,16 @@ gb_internal i32 linker_stage(LinkerData *gen) { } array_add(&gen->output_object_paths, obj_file); } else { - if (string_set_update(&min_libs_set, lib) && build_context.min_link_libs) { + bool short_circuit = false; + if (string_ends_with(lib, str_lit(".framework"))) { + short_circuit = true; + } else if (string_ends_with(lib, str_lit(".dylib"))) { + short_circuit = true; + } else if (string_ends_with(lib, str_lit(".so"))) { + short_circuit = true; + } + + if (string_set_update(&min_libs_set, lib) && (build_context.min_link_libs || short_circuit)) { continue; } -- cgit v1.2.3 From d4e15074ea0591af908bf31bb5abf33c918c1bdf Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 22 Jan 2025 13:13:00 +0000 Subject: Enable `-use-separate-modules` as default for all platforms --- src/build_settings.cpp | 2 -- 1 file changed, 2 deletions(-) (limited to 'src') diff --git a/src/build_settings.cpp b/src/build_settings.cpp index a8d06d56d..ed314f9f6 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -1719,13 +1719,11 @@ gb_internal void init_build_context(TargetMetrics *cross_target, Subtarget subta bc->optimization_level = gb_clamp(bc->optimization_level, -1, 3); -#if defined(GB_SYSTEM_WINDOWS) if (bc->optimization_level <= 0) { if (!is_arch_wasm()) { bc->use_separate_modules = true; } } -#endif // TODO: Static map calls are bugged on `amd64sysv` abi. -- cgit v1.2.3 From 867af80bff2956178ac72d9afbc9327b67cd4ae8 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 22 Jan 2025 13:26:35 +0000 Subject: Add `-use-single-module` --- src/build_settings.cpp | 5 +++++ src/main.cpp | 21 +++++++++++++++++++-- 2 files changed, 24 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/build_settings.cpp b/src/build_settings.cpp index ed314f9f6..08df34c57 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -472,6 +472,7 @@ struct BuildContext { bool ignore_microsoft_magic; bool linker_map_file; + bool use_single_module; bool use_separate_modules; bool module_per_file; bool cached; @@ -1725,6 +1726,10 @@ gb_internal void init_build_context(TargetMetrics *cross_target, Subtarget subta } } + if (build_context.use_single_module) { + bc->use_separate_modules = false; + } + // TODO: Static map calls are bugged on `amd64sysv` abi. if (bc->metrics.os != TargetOs_windows && bc->metrics.arch == TargetArch_amd64) { diff --git a/src/main.cpp b/src/main.cpp index 24e33850e..e8336b292 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -331,6 +331,7 @@ enum BuildFlagKind { BuildFlag_UseRADLink, BuildFlag_Linker, BuildFlag_UseSeparateModules, + BuildFlag_UseSingleModule, BuildFlag_NoThreadedChecker, BuildFlag_ShowDebugMessages, @@ -545,6 +546,7 @@ gb_internal bool parse_build_flags(Array args) { add_flag(&build_flags, BuildFlag_UseRADLink, str_lit("radlink"), BuildFlagParam_None, Command__does_build); add_flag(&build_flags, BuildFlag_Linker, str_lit("linker"), BuildFlagParam_String, Command__does_build); add_flag(&build_flags, BuildFlag_UseSeparateModules, str_lit("use-separate-modules"), BuildFlagParam_None, Command__does_build); + add_flag(&build_flags, BuildFlag_UseSingleModule, str_lit("use-single-module"), BuildFlagParam_None, Command__does_build); add_flag(&build_flags, BuildFlag_NoThreadedChecker, str_lit("no-threaded-checker"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_ShowDebugMessages, str_lit("show-debug-messages"), BuildFlagParam_None, Command_all); @@ -1240,8 +1242,19 @@ gb_internal bool parse_build_flags(Array args) { case BuildFlag_UseSeparateModules: + if (build_context.use_single_module) { + gb_printf_err("-use-separate-modules cannot be used with -use-single-module\n"); + bad_flags = true; + } build_context.use_separate_modules = true; break; + case BuildFlag_UseSingleModule: + if (build_context.use_separate_modules) { + gb_printf_err("-use-single-module cannot be used with -use-separate-modules\n"); + bad_flags = true; + } + build_context.use_single_module = true; + break; case BuildFlag_NoThreadedChecker: build_context.no_threaded_checker = true; break; @@ -2717,8 +2730,12 @@ gb_internal void print_show_help(String const arg0, String command, String optio if (run_or_build) { if (print_flag("-use-separate-modules")) { print_usage_line(2, "The backend generates multiple build units which are then linked together."); - print_usage_line(2, "Normally, a single build unit is generated for a standard project."); - print_usage_line(2, "This is the default behaviour on Windows for '-o:none' and '-o:minimal' builds."); + print_usage_line(2, "This is the default behaviour for '-o:none' and '-o:minimal' builds."); + print_usage_line(2, "Normally, a single build unit is generated for a standard project for '-o:speed' or '-o:size'."); + } + if (print_flag("-use-single-module")) { + print_usage_line(2, "The backend generates only a single build unit."); + print_usage_line(2, "This is the default behaviour for '-o:speed' or '-o:size'."); } } -- cgit v1.2.3 From b2aaf90f88aa85e8893325f78260b3723dc4fe99 Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Fri, 24 Jan 2025 19:23:49 +0100 Subject: fix separate modules with objc code --- src/llvm_backend.cpp | 12 +++++- src/llvm_backend.hpp | 4 +- src/llvm_backend_utility.cpp | 92 ++++++++++++++++++++++++-------------------- 3 files changed, 63 insertions(+), 45 deletions(-) (limited to 'src') diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 696ced0df..277d0433e 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -1147,14 +1147,22 @@ gb_internal void lb_finalize_objc_names(lbProcedure *p) { String name = entry.key; args[0] = lb_const_value(m, t_cstring, exact_value_string(name)); lbValue ptr = lb_emit_runtime_call(p, "objc_lookUpClass", args); - lb_addr_store(p, entry.value, ptr); + + lbValue ptr_ = lb_find_value_from_entity(m, entry.value); + lbAddr local_addr = lb_addr(ptr_); + + lb_addr_store(p, local_addr, ptr); } for (auto const &entry : m->objc_selectors) { String name = entry.key; args[0] = lb_const_value(m, t_cstring, exact_value_string(name)); lbValue ptr = lb_emit_runtime_call(p, "sel_registerName", args); - lb_addr_store(p, entry.value, ptr); + + lbValue ptr_ = lb_find_value_from_entity(m, entry.value); + lbAddr local_addr = lb_addr(ptr_); + + lb_addr_store(p, local_addr, ptr); } lb_end_procedure_body(p); diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index 42d283a1e..dd56d56a3 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -196,8 +196,8 @@ struct lbModule { RecursiveMutex debug_values_mutex; PtrMap debug_values; - StringMap objc_classes; - StringMap objc_selectors; + StringMap objc_classes; + StringMap objc_selectors; PtrMap map_cell_info_map; // address of runtime.Map_Info PtrMap map_info_map; // address of runtime.Map_Cell_Info diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp index 7b7c9d6e9..61dafa1c0 100644 --- a/src/llvm_backend_utility.cpp +++ b/src/llvm_backend_utility.cpp @@ -2093,23 +2093,36 @@ gb_internal void lb_set_wasm_export_attributes(LLVMValueRef value, String export gb_internal lbAddr lb_handle_objc_find_or_register_selector(lbProcedure *p, String const &name) { - lbAddr *found = string_map_get(&p->module->objc_selectors, name); - if (found) { - return *found; - } else { - lbModule *default_module = &p->module->gen->default_module; - Entity *e = nullptr; - lbAddr default_addr = lb_add_global_generated(default_module, t_objc_SEL, {}, &e); + lbModule *default_module = &p->module->gen->default_module; + Entity *entity = {}; - lbValue ptr = lb_find_value_from_entity(p->module, e); - lbAddr local_addr = lb_addr(ptr); + Entity **found = string_map_get(&p->module->objc_selectors, name); + if (found) { + entity = *found; + } - string_map_set(&default_module->objc_selectors, name, default_addr); + if (!entity) { if (default_module != p->module) { - string_map_set(&p->module->objc_selectors, name, local_addr); + found = string_map_get(&default_module->objc_selectors, name); + if (found) { + entity = *found; + } + } + + if (!entity) { + lbAddr default_addr = lb_add_global_generated(default_module, t_objc_SEL, {}, &entity); + string_map_set(&default_module->objc_selectors, name, entity); } - return local_addr; } + + lbValue ptr = lb_find_value_from_entity(p->module, entity); + lbAddr local_addr = lb_addr(ptr); + + if (default_module != p->module) { + string_map_set(&p->module->objc_selectors, name, entity); + } + + return local_addr; } gb_internal lbValue lb_handle_objc_find_selector(lbProcedure *p, Ast *expr) { @@ -2139,23 +2152,36 @@ gb_internal lbValue lb_handle_objc_register_selector(lbProcedure *p, Ast *expr) } gb_internal lbAddr lb_handle_objc_find_or_register_class(lbProcedure *p, String const &name) { - lbAddr *found = string_map_get(&p->module->objc_classes, name); - if (found) { - return *found; - } else { - lbModule *default_module = &p->module->gen->default_module; - Entity *e = nullptr; - lbAddr default_addr = lb_add_global_generated(default_module, t_objc_SEL, {}, &e); + lbModule *default_module = &p->module->gen->default_module; + Entity *entity = {}; - lbValue ptr = lb_find_value_from_entity(p->module, e); - lbAddr local_addr = lb_addr(ptr); + Entity **found = string_map_get(&p->module->objc_classes, name); + if (found) { + entity = *found; + } - string_map_set(&default_module->objc_classes, name, default_addr); + if (!entity) { if (default_module != p->module) { - string_map_set(&p->module->objc_classes, name, local_addr); + found = string_map_get(&default_module->objc_classes, name); + if (found) { + entity = *found; + } + } + + if (!entity) { + lbAddr default_addr = lb_add_global_generated(default_module, t_objc_Class, {}, &entity); + string_map_set(&default_module->objc_classes, name, entity); } - return local_addr; } + + lbValue ptr = lb_find_value_from_entity(p->module, entity); + lbAddr local_addr = lb_addr(ptr); + + if (default_module != p->module) { + string_map_set(&p->module->objc_classes, name, entity); + } + + return local_addr; } gb_internal lbValue lb_handle_objc_find_class(lbProcedure *p, Ast *expr) { @@ -2196,23 +2222,7 @@ gb_internal lbValue lb_handle_objc_id(lbProcedure *p, Ast *expr) { GB_ASSERT(e->kind == Entity_TypeName); String name = e->TypeName.objc_class_name; - lbAddr *found = string_map_get(&p->module->objc_classes, name); - if (found) { - return lb_addr_load(p, *found); - } else { - lbModule *default_module = &p->module->gen->default_module; - Entity *e = nullptr; - lbAddr default_addr = lb_add_global_generated(default_module, t_objc_Class, {}, &e); - - lbValue ptr = lb_find_value_from_entity(p->module, e); - lbAddr local_addr = lb_addr(ptr); - - string_map_set(&default_module->objc_classes, name, default_addr); - if (default_module != p->module) { - string_map_set(&p->module->objc_classes, name, local_addr); - } - return lb_addr_load(p, local_addr); - } + return lb_addr_load(p, lb_handle_objc_find_or_register_class(p, name)); } return lb_build_expr(p, expr); -- cgit v1.2.3 From 9dc17f4c47471829b8360c9114ac382582e2b9b6 Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Fri, 24 Jan 2025 19:33:57 +0100 Subject: optimize fix --- src/llvm_backend.cpp | 12 ++-------- src/llvm_backend.hpp | 9 +++++-- src/llvm_backend_utility.cpp | 56 ++++++++++++++++++++------------------------ 3 files changed, 35 insertions(+), 42 deletions(-) (limited to 'src') diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 277d0433e..29fa67f3f 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -1147,22 +1147,14 @@ gb_internal void lb_finalize_objc_names(lbProcedure *p) { String name = entry.key; args[0] = lb_const_value(m, t_cstring, exact_value_string(name)); lbValue ptr = lb_emit_runtime_call(p, "objc_lookUpClass", args); - - lbValue ptr_ = lb_find_value_from_entity(m, entry.value); - lbAddr local_addr = lb_addr(ptr_); - - lb_addr_store(p, local_addr, ptr); + lb_addr_store(p, entry.value.local_module_addr, ptr); } for (auto const &entry : m->objc_selectors) { String name = entry.key; args[0] = lb_const_value(m, t_cstring, exact_value_string(name)); lbValue ptr = lb_emit_runtime_call(p, "sel_registerName", args); - - lbValue ptr_ = lb_find_value_from_entity(m, entry.value); - lbAddr local_addr = lb_addr(ptr_); - - lb_addr_store(p, local_addr, ptr); + lb_addr_store(p, entry.value.local_module_addr, ptr); } lb_end_procedure_body(p); diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index dd56d56a3..a0775ac3b 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -143,6 +143,11 @@ struct lbPadType { LLVMTypeRef type; }; +struct lbObjcRef { + Entity * entity; + lbAddr local_module_addr; +}; + struct lbModule { LLVMModuleRef mod; LLVMContextRef ctx; @@ -196,8 +201,8 @@ struct lbModule { RecursiveMutex debug_values_mutex; PtrMap debug_values; - StringMap objc_classes; - StringMap objc_selectors; + StringMap objc_classes; + StringMap objc_selectors; PtrMap map_cell_info_map; // address of runtime.Map_Info PtrMap map_info_map; // address of runtime.Map_Cell_Info diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp index 61dafa1c0..8910bd67a 100644 --- a/src/llvm_backend_utility.cpp +++ b/src/llvm_backend_utility.cpp @@ -2093,33 +2093,31 @@ gb_internal void lb_set_wasm_export_attributes(LLVMValueRef value, String export gb_internal lbAddr lb_handle_objc_find_or_register_selector(lbProcedure *p, String const &name) { + lbObjcRef *found = string_map_get(&p->module->objc_selectors, name); + if (found) { + return found->local_module_addr; + } + lbModule *default_module = &p->module->gen->default_module; Entity *entity = {}; - Entity **found = string_map_get(&p->module->objc_selectors, name); - if (found) { - entity = *found; + if (default_module != p->module) { + found = string_map_get(&default_module->objc_selectors, name); + if (found) { + entity = found->entity; + } } if (!entity) { - if (default_module != p->module) { - found = string_map_get(&default_module->objc_selectors, name); - if (found) { - entity = *found; - } - } - - if (!entity) { - lbAddr default_addr = lb_add_global_generated(default_module, t_objc_SEL, {}, &entity); - string_map_set(&default_module->objc_selectors, name, entity); - } + lbAddr default_addr = lb_add_global_generated(default_module, t_objc_SEL, {}, &entity); + string_map_set(&default_module->objc_selectors, name, lbObjcRef{entity, default_addr}); } lbValue ptr = lb_find_value_from_entity(p->module, entity); lbAddr local_addr = lb_addr(ptr); if (default_module != p->module) { - string_map_set(&p->module->objc_selectors, name, entity); + string_map_set(&p->module->objc_selectors, name, lbObjcRef{entity, local_addr}); } return local_addr; @@ -2152,33 +2150,31 @@ gb_internal lbValue lb_handle_objc_register_selector(lbProcedure *p, Ast *expr) } gb_internal lbAddr lb_handle_objc_find_or_register_class(lbProcedure *p, String const &name) { + lbObjcRef *found = string_map_get(&p->module->objc_classes, name); + if (found) { + return found->local_module_addr; + } + lbModule *default_module = &p->module->gen->default_module; Entity *entity = {}; - Entity **found = string_map_get(&p->module->objc_classes, name); - if (found) { - entity = *found; + if (default_module != p->module) { + found = string_map_get(&default_module->objc_classes, name); + if (found) { + entity = found->entity; + } } if (!entity) { - if (default_module != p->module) { - found = string_map_get(&default_module->objc_classes, name); - if (found) { - entity = *found; - } - } - - if (!entity) { - lbAddr default_addr = lb_add_global_generated(default_module, t_objc_Class, {}, &entity); - string_map_set(&default_module->objc_classes, name, entity); - } + lbAddr default_addr = lb_add_global_generated(default_module, t_objc_Class, {}, &entity); + string_map_set(&default_module->objc_classes, name, lbObjcRef{entity, default_addr}); } lbValue ptr = lb_find_value_from_entity(p->module, entity); lbAddr local_addr = lb_addr(ptr); if (default_module != p->module) { - string_map_set(&p->module->objc_classes, name, entity); + string_map_set(&p->module->objc_classes, name, lbObjcRef{entity, local_addr}); } return local_addr; -- cgit v1.2.3 From 868ab277209908a3857c874014bced9e0fae6949 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 28 Jan 2025 10:31:46 +0000 Subject: Add `@(ignore_duplicates)` for `foreign import` declarations --- src/checker.cpp | 9 +++++++++ src/checker.hpp | 1 + src/entity.cpp | 1 + vendor/sdl2/sdl2.odin | 2 ++ vendor/sdl2/sdl_audio.odin | 2 ++ vendor/sdl2/sdl_blendmode.odin | 2 ++ vendor/sdl2/sdl_cpuinfo.odin | 2 ++ vendor/sdl2/sdl_events.odin | 2 ++ vendor/sdl2/sdl_gamecontroller.odin | 2 ++ vendor/sdl2/sdl_gesture_haptic.odin | 2 ++ vendor/sdl2/sdl_hints.odin | 2 ++ vendor/sdl2/sdl_joystick.odin | 2 ++ vendor/sdl2/sdl_keyboard.odin | 2 ++ vendor/sdl2/sdl_log.odin | 2 ++ vendor/sdl2/sdl_messagebox.odin | 2 ++ vendor/sdl2/sdl_metal.odin | 2 ++ vendor/sdl2/sdl_mouse.odin | 2 ++ vendor/sdl2/sdl_mutex.odin | 2 ++ vendor/sdl2/sdl_pixels.odin | 2 ++ vendor/sdl2/sdl_rect.odin | 2 ++ vendor/sdl2/sdl_render.odin | 2 ++ vendor/sdl2/sdl_rwops.odin | 2 ++ vendor/sdl2/sdl_stdinc.odin | 2 ++ vendor/sdl2/sdl_surface.odin | 2 ++ vendor/sdl2/sdl_system.odin | 2 ++ vendor/sdl2/sdl_syswm.odin | 2 ++ vendor/sdl2/sdl_thread.odin | 2 ++ vendor/sdl2/sdl_timer.odin | 2 ++ vendor/sdl2/sdl_touch.odin | 2 ++ vendor/sdl2/sdl_video.odin | 2 ++ vendor/sdl2/sdl_vulkan.odin | 2 ++ 31 files changed, 67 insertions(+) (limited to 'src') diff --git a/src/checker.cpp b/src/checker.cpp index 85077a5c5..baa1e0d2b 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -5040,6 +5040,12 @@ gb_internal DECL_ATTRIBUTE_PROC(foreign_import_decl_attribute) { ac->extra_linker_flags = ev.value_string; } return true; + } else if (name == "ignore_duplicates") { + if (value != nullptr) { + error(elem, "Expected no parameter for '%.*s'", LIT(name)); + } + ac->ignore_duplicates = true; + return true; } return false; } @@ -5190,6 +5196,9 @@ gb_internal void check_add_foreign_import_decl(CheckerContext *ctx, Ast *decl) { if (ac.foreign_import_priority_index != 0) { e->LibraryName.priority_index = ac.foreign_import_priority_index; } + if (ac.ignore_duplicates) { + e->LibraryName.ignore_duplicates = true; + } String extra_linker_flags = string_trim_whitespace(ac.extra_linker_flags); if (extra_linker_flags.len != 0) { e->LibraryName.extra_linker_flags = extra_linker_flags; diff --git a/src/checker.hpp b/src/checker.hpp index 3951fcefe..4634047c0 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -140,6 +140,7 @@ struct AttributeContext { bool instrumentation_enter : 1; bool instrumentation_exit : 1; bool rodata : 1; + bool ignore_duplicates : 1; u32 optimization_mode; // ProcedureOptimizationMode i64 foreign_import_priority_index; String extra_linker_flags; diff --git a/src/entity.cpp b/src/entity.cpp index 802b381f9..d137a8674 100644 --- a/src/entity.cpp +++ b/src/entity.cpp @@ -274,6 +274,7 @@ struct Entity { Slice paths; String name; i64 priority_index; + bool ignore_duplicates; String extra_linker_flags; } LibraryName; i32 Nil; diff --git a/vendor/sdl2/sdl2.odin b/vendor/sdl2/sdl2.odin index b23389a64..5bc52b70e 100644 --- a/vendor/sdl2/sdl2.odin +++ b/vendor/sdl2/sdl2.odin @@ -26,8 +26,10 @@ import "core:c" import "base:intrinsics" when ODIN_OS == .Windows { + @(ignore_duplicates) foreign import lib "SDL2.lib" } else { + @(ignore_duplicates) foreign import lib "system:SDL2" } diff --git a/vendor/sdl2/sdl_audio.odin b/vendor/sdl2/sdl_audio.odin index 28a59d947..6ff9e93f4 100644 --- a/vendor/sdl2/sdl_audio.odin +++ b/vendor/sdl2/sdl_audio.odin @@ -3,8 +3,10 @@ package sdl2 import "core:c" when ODIN_OS == .Windows { + @(ignore_duplicates) foreign import lib "SDL2.lib" } else { + @(ignore_duplicates) foreign import lib "system:SDL2" } diff --git a/vendor/sdl2/sdl_blendmode.odin b/vendor/sdl2/sdl_blendmode.odin index 4fde5111b..3105ad72b 100644 --- a/vendor/sdl2/sdl_blendmode.odin +++ b/vendor/sdl2/sdl_blendmode.odin @@ -3,8 +3,10 @@ package sdl2 import "core:c" when ODIN_OS == .Windows { + @(ignore_duplicates) foreign import lib "SDL2.lib" } else { + @(ignore_duplicates) foreign import lib "system:SDL2" } diff --git a/vendor/sdl2/sdl_cpuinfo.odin b/vendor/sdl2/sdl_cpuinfo.odin index c5175e4d5..a98b6f8d3 100644 --- a/vendor/sdl2/sdl_cpuinfo.odin +++ b/vendor/sdl2/sdl_cpuinfo.odin @@ -3,8 +3,10 @@ package sdl2 import "core:c" when ODIN_OS == .Windows { + @(ignore_duplicates) foreign import lib "SDL2.lib" } else { + @(ignore_duplicates) foreign import lib "system:SDL2" } diff --git a/vendor/sdl2/sdl_events.odin b/vendor/sdl2/sdl_events.odin index b4c92683c..061eb964d 100644 --- a/vendor/sdl2/sdl_events.odin +++ b/vendor/sdl2/sdl_events.odin @@ -3,8 +3,10 @@ package sdl2 import "core:c" when ODIN_OS == .Windows { + @(ignore_duplicates) foreign import lib "SDL2.lib" } else { + @(ignore_duplicates) foreign import lib "system:SDL2" } diff --git a/vendor/sdl2/sdl_gamecontroller.odin b/vendor/sdl2/sdl_gamecontroller.odin index beb7d5ce7..be45d6520 100644 --- a/vendor/sdl2/sdl_gamecontroller.odin +++ b/vendor/sdl2/sdl_gamecontroller.odin @@ -3,8 +3,10 @@ package sdl2 import "core:c" when ODIN_OS == .Windows { + @(ignore_duplicates) foreign import lib "SDL2.lib" } else { + @(ignore_duplicates) foreign import lib "system:SDL2" } diff --git a/vendor/sdl2/sdl_gesture_haptic.odin b/vendor/sdl2/sdl_gesture_haptic.odin index a21e0df06..01d7a6da3 100644 --- a/vendor/sdl2/sdl_gesture_haptic.odin +++ b/vendor/sdl2/sdl_gesture_haptic.odin @@ -3,8 +3,10 @@ package sdl2 import "core:c" when ODIN_OS == .Windows { + @(ignore_duplicates) foreign import lib "SDL2.lib" } else { + @(ignore_duplicates) foreign import lib "system:SDL2" } diff --git a/vendor/sdl2/sdl_hints.odin b/vendor/sdl2/sdl_hints.odin index 913d4ea12..080dc6036 100644 --- a/vendor/sdl2/sdl_hints.odin +++ b/vendor/sdl2/sdl_hints.odin @@ -3,8 +3,10 @@ package sdl2 import "core:c" when ODIN_OS == .Windows { + @(ignore_duplicates) foreign import lib "SDL2.lib" } else { + @(ignore_duplicates) foreign import lib "system:SDL2" } diff --git a/vendor/sdl2/sdl_joystick.odin b/vendor/sdl2/sdl_joystick.odin index 35ca5cdcc..0725a3554 100644 --- a/vendor/sdl2/sdl_joystick.odin +++ b/vendor/sdl2/sdl_joystick.odin @@ -3,8 +3,10 @@ package sdl2 import "core:c" when ODIN_OS == .Windows { + @(ignore_duplicates) foreign import lib "SDL2.lib" } else { + @(ignore_duplicates) foreign import lib "system:SDL2" } diff --git a/vendor/sdl2/sdl_keyboard.odin b/vendor/sdl2/sdl_keyboard.odin index f880286aa..0d0557de9 100644 --- a/vendor/sdl2/sdl_keyboard.odin +++ b/vendor/sdl2/sdl_keyboard.odin @@ -3,8 +3,10 @@ package sdl2 import "core:c" when ODIN_OS == .Windows { + @(ignore_duplicates) foreign import lib "SDL2.lib" } else { + @(ignore_duplicates) foreign import lib "system:SDL2" } diff --git a/vendor/sdl2/sdl_log.odin b/vendor/sdl2/sdl_log.odin index 09b7eaef0..b7668ee1d 100644 --- a/vendor/sdl2/sdl_log.odin +++ b/vendor/sdl2/sdl_log.odin @@ -3,8 +3,10 @@ package sdl2 import "core:c" when ODIN_OS == .Windows { + @(ignore_duplicates) foreign import lib "SDL2.lib" } else { + @(ignore_duplicates) foreign import lib "system:SDL2" } diff --git a/vendor/sdl2/sdl_messagebox.odin b/vendor/sdl2/sdl_messagebox.odin index 6228704ac..edd8422e0 100644 --- a/vendor/sdl2/sdl_messagebox.odin +++ b/vendor/sdl2/sdl_messagebox.odin @@ -3,8 +3,10 @@ package sdl2 import "core:c" when ODIN_OS == .Windows { + @(ignore_duplicates) foreign import lib "SDL2.lib" } else { + @(ignore_duplicates) foreign import lib "system:SDL2" } diff --git a/vendor/sdl2/sdl_metal.odin b/vendor/sdl2/sdl_metal.odin index 1eccf7f5a..e8e650212 100644 --- a/vendor/sdl2/sdl_metal.odin +++ b/vendor/sdl2/sdl_metal.odin @@ -3,8 +3,10 @@ package sdl2 import "core:c" when ODIN_OS == .Windows { + @(ignore_duplicates) foreign import lib "SDL2.lib" } else { + @(ignore_duplicates) foreign import lib "system:SDL2" } diff --git a/vendor/sdl2/sdl_mouse.odin b/vendor/sdl2/sdl_mouse.odin index 0243b6623..8e782a5e3 100644 --- a/vendor/sdl2/sdl_mouse.odin +++ b/vendor/sdl2/sdl_mouse.odin @@ -3,8 +3,10 @@ package sdl2 import "core:c" when ODIN_OS == .Windows { + @(ignore_duplicates) foreign import lib "SDL2.lib" } else { + @(ignore_duplicates) foreign import lib "system:SDL2" } diff --git a/vendor/sdl2/sdl_mutex.odin b/vendor/sdl2/sdl_mutex.odin index 6ff7e5d2b..6eb096c81 100644 --- a/vendor/sdl2/sdl_mutex.odin +++ b/vendor/sdl2/sdl_mutex.odin @@ -3,8 +3,10 @@ package sdl2 import "core:c" when ODIN_OS == .Windows { + @(ignore_duplicates) foreign import lib "SDL2.lib" } else { + @(ignore_duplicates) foreign import lib "system:SDL2" } diff --git a/vendor/sdl2/sdl_pixels.odin b/vendor/sdl2/sdl_pixels.odin index 195f2920f..6a3d89f4e 100644 --- a/vendor/sdl2/sdl_pixels.odin +++ b/vendor/sdl2/sdl_pixels.odin @@ -3,8 +3,10 @@ package sdl2 import "core:c" when ODIN_OS == .Windows { + @(ignore_duplicates) foreign import lib "SDL2.lib" } else { + @(ignore_duplicates) foreign import lib "system:SDL2" } diff --git a/vendor/sdl2/sdl_rect.odin b/vendor/sdl2/sdl_rect.odin index 852309cd2..96cf7180e 100644 --- a/vendor/sdl2/sdl_rect.odin +++ b/vendor/sdl2/sdl_rect.odin @@ -3,8 +3,10 @@ package sdl2 import "core:c" when ODIN_OS == .Windows { + @(ignore_duplicates) foreign import lib "SDL2.lib" } else { + @(ignore_duplicates) foreign import lib "system:SDL2" } diff --git a/vendor/sdl2/sdl_render.odin b/vendor/sdl2/sdl_render.odin index cceebf3ac..5e913e5a3 100644 --- a/vendor/sdl2/sdl_render.odin +++ b/vendor/sdl2/sdl_render.odin @@ -3,8 +3,10 @@ package sdl2 import "core:c" when ODIN_OS == .Windows { + @(ignore_duplicates) foreign import lib "SDL2.lib" } else { + @(ignore_duplicates) foreign import lib "system:SDL2" } diff --git a/vendor/sdl2/sdl_rwops.odin b/vendor/sdl2/sdl_rwops.odin index 28d09511b..ca7fa0bea 100644 --- a/vendor/sdl2/sdl_rwops.odin +++ b/vendor/sdl2/sdl_rwops.odin @@ -3,8 +3,10 @@ package sdl2 import "core:c" when ODIN_OS == .Windows { + @(ignore_duplicates) foreign import lib "SDL2.lib" } else { + @(ignore_duplicates) foreign import lib "system:SDL2" } diff --git a/vendor/sdl2/sdl_stdinc.odin b/vendor/sdl2/sdl_stdinc.odin index 9136ae026..bf04a3f1f 100644 --- a/vendor/sdl2/sdl_stdinc.odin +++ b/vendor/sdl2/sdl_stdinc.odin @@ -3,8 +3,10 @@ package sdl2 import "core:c" when ODIN_OS == .Windows { + @(ignore_duplicates) foreign import lib "SDL2.lib" } else { + @(ignore_duplicates) foreign import lib "system:SDL2" } diff --git a/vendor/sdl2/sdl_surface.odin b/vendor/sdl2/sdl_surface.odin index f50de35f7..1502efbc7 100644 --- a/vendor/sdl2/sdl_surface.odin +++ b/vendor/sdl2/sdl_surface.odin @@ -3,8 +3,10 @@ package sdl2 import "core:c" when ODIN_OS == .Windows { + @(ignore_duplicates) foreign import lib "SDL2.lib" } else { + @(ignore_duplicates) foreign import lib "system:SDL2" } diff --git a/vendor/sdl2/sdl_system.odin b/vendor/sdl2/sdl_system.odin index d9b6b98df..1c34e557e 100644 --- a/vendor/sdl2/sdl_system.odin +++ b/vendor/sdl2/sdl_system.odin @@ -3,8 +3,10 @@ package sdl2 import "core:c" when ODIN_OS == .Windows { + @(ignore_duplicates) foreign import lib "SDL2.lib" } else { + @(ignore_duplicates) foreign import lib "system:SDL2" } diff --git a/vendor/sdl2/sdl_syswm.odin b/vendor/sdl2/sdl_syswm.odin index 62ca9d628..15501c222 100644 --- a/vendor/sdl2/sdl_syswm.odin +++ b/vendor/sdl2/sdl_syswm.odin @@ -3,8 +3,10 @@ package sdl2 import "core:c" when ODIN_OS == .Windows { + @(ignore_duplicates) foreign import lib "SDL2.lib" } else { + @(ignore_duplicates) foreign import lib "system:SDL2" } diff --git a/vendor/sdl2/sdl_thread.odin b/vendor/sdl2/sdl_thread.odin index 5d1c0bd37..84516e26b 100644 --- a/vendor/sdl2/sdl_thread.odin +++ b/vendor/sdl2/sdl_thread.odin @@ -3,8 +3,10 @@ package sdl2 import "core:c" when ODIN_OS == .Windows { + @(ignore_duplicates) foreign import lib "SDL2.lib" } else { + @(ignore_duplicates) foreign import lib "system:SDL2" } diff --git a/vendor/sdl2/sdl_timer.odin b/vendor/sdl2/sdl_timer.odin index d71ed2da5..50b5eb981 100644 --- a/vendor/sdl2/sdl_timer.odin +++ b/vendor/sdl2/sdl_timer.odin @@ -3,8 +3,10 @@ package sdl2 import "core:c" when ODIN_OS == .Windows { + @(ignore_duplicates) foreign import lib "SDL2.lib" } else { + @(ignore_duplicates) foreign import lib "system:SDL2" } diff --git a/vendor/sdl2/sdl_touch.odin b/vendor/sdl2/sdl_touch.odin index f0ca69333..44633aeb6 100644 --- a/vendor/sdl2/sdl_touch.odin +++ b/vendor/sdl2/sdl_touch.odin @@ -3,8 +3,10 @@ package sdl2 import "core:c" when ODIN_OS == .Windows { + @(ignore_duplicates) foreign import lib "SDL2.lib" } else { + @(ignore_duplicates) foreign import lib "system:SDL2" } diff --git a/vendor/sdl2/sdl_video.odin b/vendor/sdl2/sdl_video.odin index 86b564541..809735414 100644 --- a/vendor/sdl2/sdl_video.odin +++ b/vendor/sdl2/sdl_video.odin @@ -3,8 +3,10 @@ package sdl2 import "core:c" when ODIN_OS == .Windows { + @(ignore_duplicates) foreign import lib "SDL2.lib" } else { + @(ignore_duplicates) foreign import lib "system:SDL2" } diff --git a/vendor/sdl2/sdl_vulkan.odin b/vendor/sdl2/sdl_vulkan.odin index 33bb8e51c..4e0db0ffe 100644 --- a/vendor/sdl2/sdl_vulkan.odin +++ b/vendor/sdl2/sdl_vulkan.odin @@ -4,8 +4,10 @@ import "core:c" import vk "vendor:vulkan" when ODIN_OS == .Windows { + @(ignore_duplicates) foreign import lib "SDL2.lib" } else { + @(ignore_duplicates) foreign import lib "system:SDL2" } -- cgit v1.2.3 From 15ece42e74acd7d62fc65bbc611e6766ec34187a Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 28 Jan 2025 10:34:41 +0000 Subject: Print frameworks first on Darwin targets --- src/linker.cpp | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/linker.cpp b/src/linker.cpp index 59e6d8dc1..cf2ef638d 100644 --- a/src/linker.cpp +++ b/src/linker.cpp @@ -449,6 +449,26 @@ gb_internal i32 linker_stage(LinkerData *gen) { if (extra_linker_flags.len != 0) { lib_str = gb_string_append_fmt(lib_str, " %.*s", LIT(extra_linker_flags)); } + + if (build_context.metrics.os == TargetOs_darwin) { + // Print frameworks first + for (String lib : e->LibraryName.paths) { + lib = string_trim_whitespace(lib); + if (lib.len == 0) { + continue; + } + if (string_ends_with(lib, str_lit(".framework"))) { + if (string_set_update(&min_libs_set, lib)) { + continue; + } + + String lib_name = lib; + lib_name = remove_extension_from_path(lib_name); + lib_str = gb_string_append_fmt(lib_str, " -framework %.*s ", LIT(lib_name)); + } + } + } + for (String lib : e->LibraryName.paths) { lib = string_trim_whitespace(lib); if (lib.len == 0) { @@ -541,7 +561,9 @@ gb_internal i32 linker_stage(LinkerData *gen) { short_circuit = true; } else if (string_ends_with(lib, str_lit(".dylib"))) { short_circuit = true; - } else if (string_ends_with(lib, str_lit(".so"))) { + } else if (string_ends_with(lib, str_lit(".so"))) { + short_circuit = true; + } else if (e->LibraryName.ignore_duplicates) { short_circuit = true; } -- cgit v1.2.3 From 2656ecd4e17d448f1d972270bde87f75bc096d0d Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 29 Jan 2025 15:53:34 +0000 Subject: Fix #4773 - Change order of evaluation for slicing indices --- src/llvm_backend_expr.cpp | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index df9dca801..871536927 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -4294,6 +4294,17 @@ gb_internal lbAddr lb_build_addr_index_expr(lbProcedure *p, Ast *expr) { gb_internal lbAddr lb_build_addr_slice_expr(lbProcedure *p, Ast *expr) { ast_node(se, SliceExpr, expr); + lbAddr addr = lb_build_addr(p, se->expr); + lbValue base = lb_addr_load(p, addr); + Type *type = base_type(base.type); + + if (is_type_pointer(type)) { + type = base_type(type_deref(type)); + addr = lb_addr(base); + base = lb_addr_load(p, addr); + } + + lbValue low = lb_const_int(p->module, t_int, 0); lbValue high = {}; @@ -4306,16 +4317,6 @@ gb_internal lbAddr lb_build_addr_slice_expr(lbProcedure *p, Ast *expr) { bool no_indices = se->low == nullptr && se->high == nullptr; - lbAddr addr = lb_build_addr(p, se->expr); - lbValue base = lb_addr_load(p, addr); - Type *type = base_type(base.type); - - if (is_type_pointer(type)) { - type = base_type(type_deref(type)); - addr = lb_addr(base); - base = lb_addr_load(p, addr); - } - switch (type->kind) { case Type_Slice: { Type *slice_type = type; -- cgit v1.2.3 From b48f14ba82a99932e28fb12d85e20e26e6750612 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 30 Jan 2025 11:30:38 +0000 Subject: `@(export) foreign import` to be package scope level --- src/check_decl.cpp | 3 ++- src/checker.cpp | 11 ++++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/check_decl.cpp b/src/check_decl.cpp index bf6e39bd2..4e44aadaf 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -857,6 +857,7 @@ gb_internal Entity *init_entity_foreign_library(CheckerContext *ctx, Entity *e) } else { String name = ident->Ident.token.string; Entity *found = scope_lookup(ctx->scope, name); + if (found == nullptr) { if (is_blank_ident(name)) { // NOTE(bill): link against nothing @@ -864,7 +865,7 @@ gb_internal Entity *init_entity_foreign_library(CheckerContext *ctx, Entity *e) error(ident, "Undeclared name: %.*s", LIT(name)); } } else if (found->kind != Entity_LibraryName) { - error(ident, "'%.*s' cannot be used as a library name", LIT(name)); + error(ident, "'%.*s' cannot be used as a library name %d", LIT(name), found->kind); } else { // TODO(bill): Extra stuff to do with library names? *foreign_library = found; diff --git a/src/checker.cpp b/src/checker.cpp index baa1e0d2b..da2e0cda9 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -5016,6 +5016,9 @@ gb_internal DECL_ATTRIBUTE_PROC(foreign_import_decl_attribute) { error(elem, "Expected a string value for '%.*s'", LIT(name)); } return true; + } else if (name == "export") { + ac->is_export = true; + return true; } else if (name == "force" || name == "require") { if (value != nullptr) { error(elem, "Expected no parameter for '%.*s'", LIT(name)); @@ -5185,10 +5188,16 @@ gb_internal void check_add_foreign_import_decl(CheckerContext *ctx, Ast *decl) { fl->fullpaths, library_name); e->LibraryName.decl = decl; add_entity_flags_from_file(ctx, e, parent_scope); - add_entity(ctx, parent_scope, nullptr, e); AttributeContext ac = {}; check_decl_attributes(ctx, fl->attributes, foreign_import_decl_attribute, &ac); + + if (ac.is_export) { + add_entity(ctx, parent_scope->pkg->scope, nullptr, e); + } else { + add_entity(ctx, parent_scope, nullptr, e); + } + if (ac.require_declaration) { mpsc_enqueue(&ctx->info->required_foreign_imports_through_force_queue, e); add_entity_use(ctx, nullptr, e); -- cgit v1.2.3 From 4093026a9adad43f73f03b625bb40b0139a54525 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 30 Jan 2025 11:36:12 +0000 Subject: Clean up `@(export) foreign import` code --- src/checker.cpp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/checker.cpp b/src/checker.cpp index da2e0cda9..0ac787e00 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -5184,20 +5184,21 @@ gb_internal void check_add_foreign_import_decl(CheckerContext *ctx, Ast *decl) { GB_ASSERT(fl->library_name.pos.line != 0); fl->library_name.string = library_name; - Entity *e = alloc_entity_library_name(parent_scope, fl->library_name, t_invalid, - fl->fullpaths, library_name); - e->LibraryName.decl = decl; - add_entity_flags_from_file(ctx, e, parent_scope); - AttributeContext ac = {}; check_decl_attributes(ctx, fl->attributes, foreign_import_decl_attribute, &ac); + Scope *scope = parent_scope; if (ac.is_export) { - add_entity(ctx, parent_scope->pkg->scope, nullptr, e); - } else { - add_entity(ctx, parent_scope, nullptr, e); + scope = parent_scope->parent; } + Entity *e = alloc_entity_library_name(parent_scope, fl->library_name, t_invalid, + fl->fullpaths, library_name); + e->LibraryName.decl = decl; + add_entity_flags_from_file(ctx, e, parent_scope); + add_entity(ctx, scope, nullptr, e); + + if (ac.require_declaration) { mpsc_enqueue(&ctx->info->required_foreign_imports_through_force_queue, e); add_entity_use(ctx, nullptr, e); -- cgit v1.2.3 From 0cd20e61ab5989e7a759051df2a629facfb53f41 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 31 Jan 2025 08:34:15 +0000 Subject: Add `@(export) foreign import` --- src/checker.cpp | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/checker.cpp b/src/checker.cpp index baa1e0d2b..0ac787e00 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -5016,6 +5016,9 @@ gb_internal DECL_ATTRIBUTE_PROC(foreign_import_decl_attribute) { error(elem, "Expected a string value for '%.*s'", LIT(name)); } return true; + } else if (name == "export") { + ac->is_export = true; + return true; } else if (name == "force" || name == "require") { if (value != nullptr) { error(elem, "Expected no parameter for '%.*s'", LIT(name)); @@ -5181,14 +5184,21 @@ gb_internal void check_add_foreign_import_decl(CheckerContext *ctx, Ast *decl) { GB_ASSERT(fl->library_name.pos.line != 0); fl->library_name.string = library_name; + AttributeContext ac = {}; + check_decl_attributes(ctx, fl->attributes, foreign_import_decl_attribute, &ac); + + Scope *scope = parent_scope; + if (ac.is_export) { + scope = parent_scope->parent; + } + Entity *e = alloc_entity_library_name(parent_scope, fl->library_name, t_invalid, fl->fullpaths, library_name); e->LibraryName.decl = decl; add_entity_flags_from_file(ctx, e, parent_scope); - add_entity(ctx, parent_scope, nullptr, e); + add_entity(ctx, scope, nullptr, e); + - AttributeContext ac = {}; - check_decl_attributes(ctx, fl->attributes, foreign_import_decl_attribute, &ac); if (ac.require_declaration) { mpsc_enqueue(&ctx->info->required_foreign_imports_through_force_queue, e); add_entity_use(ctx, nullptr, e); -- cgit v1.2.3 From 2af60b8767d8675fa4a09d24bf661c9ac29cdc47 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 31 Jan 2025 09:30:15 +0000 Subject: Fix #4763 --- src/checker.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src') diff --git a/src/checker.cpp b/src/checker.cpp index 0ac787e00..bfcabe4fa 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -6319,6 +6319,10 @@ gb_internal void check_deferred_procedures(Checker *c) { continue; } + if (dst_params == nullptr) { + error(src->token, "Deferred procedure must have parameters for %s", attribute); + continue; + } GB_ASSERT(dst_params->kind == Type_Tuple); Type *tsrc = alloc_type_tuple(); -- cgit v1.2.3 From 05a2d1bfbf1387bc0cc53064f1635018034ae73a Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 31 Jan 2025 09:34:38 +0000 Subject: Fix #4750 --- src/check_expr.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 8e4d60d8c..83b6181c0 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -10375,7 +10375,7 @@ gb_internal ExprKind check_type_assertion(CheckerContext *c, Operand *o, Ast *no add_type_info_type(c, o->type); o->type = type_hint; o->mode = Addressing_OptionalOk; - return kind; + goto end; } } @@ -10440,6 +10440,8 @@ gb_internal ExprKind check_type_assertion(CheckerContext *c, Operand *o, Ast *no } } +end:; + if ((c->state_flags & StateFlag_no_type_assert) == 0) { add_package_dependency(c, "runtime", "type_assertion_check"); add_package_dependency(c, "runtime", "type_assertion_check2"); -- cgit v1.2.3 From a219da14ce8bbd15fec4ea962fd0ec175da0f0aa Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 31 Jan 2025 09:43:30 +0000 Subject: Fix `gb.h`'s `gb_fprintf_va` to allocate if the string is larger than the default buffer --- src/gb/gb.h | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/gb/gb.h b/src/gb/gb.h index f74026c7d..59611ceb6 100644 --- a/src/gb/gb.h +++ b/src/gb/gb.h @@ -5837,9 +5837,20 @@ gb_inline isize gb_printf_err_va(char const *fmt, va_list va) { } gb_inline isize gb_fprintf_va(struct gbFile *f, char const *fmt, va_list va) { - gb_local_persist char buf[4096]; + char buf[4096]; isize len = gb_snprintf_va(buf, gb_size_of(buf), fmt, va); + char *new_buf = NULL; + isize n = gb_size_of(buf); + while (len < 0) { + n <<= 1; + gb_free(gb_heap_allocator(), new_buf); + new_buf = gb_alloc_array(gb_heap_allocator(), char, n);; + len = gb_snprintf_va(new_buf, n, fmt, va); + } gb_file_write(f, buf, len-1); // NOTE(bill): prevent extra whitespace + if (new_buf != NULL) { + gb_free(gb_heap_allocator(), new_buf); + } return len; } -- cgit v1.2.3 From 1281303ff756ce4a83dcdb20be6154c7a72f278f Mon Sep 17 00:00:00 2001 From: korvahkh <92224397+korvahkh@users.noreply.github.com> Date: Mon, 3 Feb 2025 16:08:19 -0600 Subject: Preserve `#no_nil` in `intrinsics.type_convert_variants_to_pointers` Previously the newly returned type would not be marked as `#no_nil`. This caused `reflect.get_union_as_ptr_variants` to break on `#no_nil` unions. --- src/check_builtin.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index ea902387b..7d0ce3aef 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -5544,6 +5544,9 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As // NOTE(bill): Is this even correct? new_type->Union.node = operand->expr; new_type->Union.scope = bt->Union.scope; + if (bt->Union.kind == UnionType_no_nil) { + new_type->Union.kind = UnionType_no_nil; + } operand->type = new_type; } -- cgit v1.2.3 From ab469e657dcd975bbce3b7b211326363ce17ac92 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 5 Feb 2025 10:20:18 +0000 Subject: Remove debug code --- src/check_decl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 4e44aadaf..9084f15f0 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -865,7 +865,7 @@ gb_internal Entity *init_entity_foreign_library(CheckerContext *ctx, Entity *e) error(ident, "Undeclared name: %.*s", LIT(name)); } } else if (found->kind != Entity_LibraryName) { - error(ident, "'%.*s' cannot be used as a library name %d", LIT(name), found->kind); + error(ident, "'%.*s' cannot be used as a library name", LIT(name)); } else { // TODO(bill): Extra stuff to do with library names? *foreign_library = found; -- cgit v1.2.3 From f80bea5b1142c6b317f8f52bb9b3814afe5d3c1b Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 5 Feb 2025 10:27:17 +0000 Subject: Remove transmute suggestion with `-vet-cast` when transmuting native <-> endian-specific types --- src/check_expr.cpp | 3 ++- src/types.cpp | 21 +++++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 83b6181c0..550a7749c 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -3649,7 +3649,8 @@ gb_internal bool check_transmute(CheckerContext *c, Ast *node, Operand *o, Type gb_string_free(oper_str); gb_string_free(to_type); } else if (is_type_integer(src_t) && is_type_integer(dst_t) && - types_have_same_internal_endian(src_t, dst_t)) { + types_have_same_internal_endian(src_t, dst_t) && + type_endian_kind_of(src_t) == type_endian_kind_of(dst_t)) { gbString oper_type = type_to_string(src_t); gbString to_type = type_to_string(dst_t); error(o->expr, "Use of 'transmute' where 'cast' would be preferred since both are integers of the same endianness, from '%s' to '%s'", oper_type, to_type); diff --git a/src/types.cpp b/src/types.cpp index 0b6e6d334..412448cbc 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -1801,6 +1801,27 @@ gb_internal bool is_type_union_maybe_pointer_original_alignment(Type *t) { } +enum TypeEndianKind { + TypeEndian_Platform, + TypeEndian_Little, + TypeEndian_Big, +}; + +gb_internal TypeEndianKind type_endian_kind_of(Type *t) { + t = core_type(t); + if (t->kind == Type_Basic) { + if (t->Basic.flags & BasicFlag_EndianLittle) { + return TypeEndian_Little; + } + if (t->Basic.flags & BasicFlag_EndianBig) { + return TypeEndian_Big; + } + } else if (t->kind == Type_BitSet) { + return type_endian_kind_of(bit_set_to_int(t)); + } + return TypeEndian_Platform; +} + gb_internal bool is_type_endian_big(Type *t) { t = core_type(t); -- 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') 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 b86d2c30b600023ae643c4dcc2dcca10b08c29dc Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Wed, 5 Feb 2025 20:16:17 +0100 Subject: fix odin report macos version reporting unknown when release isn't a 3 point --- src/bug_report.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/bug_report.cpp b/src/bug_report.cpp index ca5d0a395..c44c4be33 100644 --- a/src/bug_report.cpp +++ b/src/bug_report.cpp @@ -532,9 +532,9 @@ gb_internal void report_os_info() { return; } - uint32_t major, minor, patch; + uint32_t major, minor, patch = 0; - if (sscanf(cast(const char *)sw_vers, "%u.%u.%u", &major, &minor, &patch) != 3) { + if (sscanf(cast(const char *)sw_vers, "%u.%u.%u", &major, &minor, &patch) < 1) { gb_printf("macOS Unknown\n"); return; } -- cgit v1.2.3 From b1068c7f2e71552b0d49b89945c7eabce4b5f878 Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Wed, 5 Feb 2025 21:17:48 +0100 Subject: improve abs() on floats for more correct and faster results --- src/llvm_backend_proc.cpp | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'src') diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 7e44a0046..2a6c1414e 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -2174,7 +2174,35 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu case 128: return lb_emit_runtime_call(p, "abs_complex128", args); } GB_PANIC("Unknown complex type"); + } else if (is_type_float(t)) { + Type *t_float; + Type *t_unsigned; + lbValue mask; + switch (type_size_of(t)) { + case 2: + t_float = t_f16; + t_unsigned = t_u16; + mask = lb_const_int(p->module, t_unsigned, 0x7FFF); + break; + case 4: + t_float = t_f32; + t_unsigned = t_u32; + mask = lb_const_int(p->module, t_unsigned, 0x7FFFFFFF); + break; + case 8: + t_float = t_f64; + t_unsigned = t_u64; + mask = lb_const_int(p->module, t_unsigned, 0x7FFFFFFFFFFFFFFF); + break; + default: + GB_PANIC("abs: unhandled float size"); + } + + lbValue as_unsigned = lb_emit_transmute(p, x, t_unsigned); + lbValue abs = lb_emit_arith(p, Token_And, as_unsigned, mask, t_unsigned); + return lb_emit_transmute(p, abs, t_float); } + lbValue zero = lb_const_nil(p->module, t); lbValue cond = lb_emit_comp(p, Token_Lt, x, zero); lbValue neg = lb_emit_unary_arith(p, Token_Sub, x, t); -- cgit v1.2.3 From 1053ec30518486e3feb523d1a37e814ce992e79c Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Thu, 6 Feb 2025 20:42:41 +0100 Subject: make corrected linkage with -use-separate-modules apply hidden visibility Fixes #4798 The DLL was using the type info of the host/exe, causing crashes. This PR tries fixing by applying hidden visibility to these corrected symbols which makes sure that the DLL can't see the type table of the host/exe. --- src/llvm_backend.cpp | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src') diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 29fa67f3f..0896ea8c7 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -169,11 +169,17 @@ gb_internal void lb_correct_entity_linkage(lbGenerator *gen) { other_global = LLVMGetNamedGlobal(ec.other_module->mod, ec.cname); if (other_global) { LLVMSetLinkage(other_global, LLVMWeakAnyLinkage); + if (!ec.e->Variable.is_export) { + LLVMSetVisibility(other_global, LLVMHiddenVisibility); + } } } else if (ec.e->kind == Entity_Procedure) { other_global = LLVMGetNamedFunction(ec.other_module->mod, ec.cname); if (other_global) { LLVMSetLinkage(other_global, LLVMWeakAnyLinkage); + if (!ec.e->Procedure.is_export) { + LLVMSetVisibility(other_global, LLVMHiddenVisibility); + } } } } -- cgit v1.2.3 From de83ad2a251ec126a02378b83e4cae5b853e34ac Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Thu, 6 Feb 2025 21:06:25 +0100 Subject: apply abs fix to constant system too --- src/check_builtin.cpp | 7 +++++-- src/llvm_backend_proc.cpp | 6 +++--- 2 files changed, 8 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index ea902387b..bf4c004d7 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -3488,9 +3488,12 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As case ExactValue_Integer: mp_abs(&operand->value.value_integer, &operand->value.value_integer); break; - case ExactValue_Float: - operand->value.value_float = gb_abs(operand->value.value_float); + case ExactValue_Float: { + u64 abs = bit_cast(operand->value.value_float); + abs &= 0x7FFFFFFFFFFFFFFF; + operand->value.value_float = bit_cast(abs); break; + } case ExactValue_Complex: { f64 r = operand->value.value_complex->real; f64 i = operand->value.value_complex->imag; diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 2a6c1414e..fe7a85fee 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -2175,9 +2175,9 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu } GB_PANIC("Unknown complex type"); } else if (is_type_float(t)) { - Type *t_float; - Type *t_unsigned; - lbValue mask; + Type *t_float = nullptr; + Type *t_unsigned = nullptr; + lbValue mask = {0}; switch (type_size_of(t)) { case 2: t_float = t_f16; -- cgit v1.2.3 From 5defddffd074b221cbb393bfdd9c3d50ffd7b499 Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Thu, 6 Feb 2025 21:44:34 +0100 Subject: reorganize tests and handle endian --- src/llvm_backend_proc.cpp | 13 ++--- tests/internal/test_abs.odin | 122 +++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 122 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index fe7a85fee..e5c04852c 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -2175,24 +2175,21 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu } GB_PANIC("Unknown complex type"); } else if (is_type_float(t)) { - Type *t_float = nullptr; + bool little = is_type_endian_little(t) || (is_type_endian_platform(t) && build_context.endian_kind == TargetEndian_Little); Type *t_unsigned = nullptr; lbValue mask = {0}; switch (type_size_of(t)) { case 2: - t_float = t_f16; t_unsigned = t_u16; - mask = lb_const_int(p->module, t_unsigned, 0x7FFF); + mask = lb_const_int(p->module, t_unsigned, little ? 0x7FFF : 0xFF7F); break; case 4: - t_float = t_f32; t_unsigned = t_u32; - mask = lb_const_int(p->module, t_unsigned, 0x7FFFFFFF); + mask = lb_const_int(p->module, t_unsigned, little ? 0x7FFFFFFF : 0xFFFFFF7F); break; case 8: - t_float = t_f64; t_unsigned = t_u64; - mask = lb_const_int(p->module, t_unsigned, 0x7FFFFFFFFFFFFFFF); + mask = lb_const_int(p->module, t_unsigned, little ? 0x7FFFFFFFFFFFFFFF : 0xFFFFFFFFFFFFFF7F); break; default: GB_PANIC("abs: unhandled float size"); @@ -2200,7 +2197,7 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu lbValue as_unsigned = lb_emit_transmute(p, x, t_unsigned); lbValue abs = lb_emit_arith(p, Token_And, as_unsigned, mask, t_unsigned); - return lb_emit_transmute(p, abs, t_float); + return lb_emit_transmute(p, abs, t); } lbValue zero = lb_const_nil(p->module, t); diff --git a/tests/internal/test_abs.odin b/tests/internal/test_abs.odin index 2f7b67862..56db10c09 100644 --- a/tests/internal/test_abs.odin +++ b/tests/internal/test_abs.odin @@ -2,26 +2,65 @@ package test_internal import "core:testing" -@(test) -test_abs_float :: proc(t: ^testing.T) { - not_const :: proc(v: $T) -> T { return v } +@(private="file") +not_const :: proc(v: $T) -> T { return v } +@(test) +abs_f16_const :: proc(t: ^testing.T) { // Constant f16 testing.expect_value(t, abs(f16(0.)), 0.) testing.expect_value(t, abs(f16(-0.)), 0.) testing.expect_value(t, abs(f16(-1.)), 1.) testing.expect_value(t, abs(min(f16)), max(f16)) testing.expect_value(t, abs(max(f16)), max(f16)) - testing.expect_value(t, abs(f16(-.12345)), .12345) + testing.expect_value(t, abs(f16(-.12)), .12) + + // Constant f16le + testing.expect_value(t, abs(f16le(0.)), 0.) + testing.expect_value(t, abs(f16le(-0.)), 0.) + testing.expect_value(t, abs(f16le(-1.)), 1.) + testing.expect_value(t, abs(min(f16le)), max(f16le)) + testing.expect_value(t, abs(max(f16le)), max(f16le)) + testing.expect_value(t, abs(f16le(-.12)), .12) + // Constant f16be + testing.expect_value(t, abs(f16be(0.)), 0.) + testing.expect_value(t, abs(f16be(-0.)), 0.) + testing.expect_value(t, abs(f16be(-1.)), 1.) + testing.expect_value(t, abs(min(f16be)), max(f16be)) + testing.expect_value(t, abs(max(f16be)), max(f16be)) + testing.expect_value(t, abs(f16be(-.12)), .12) +} + +@(test) +abs_f16_variable :: proc(t: ^testing.T) { // Variable f16 testing.expect_value(t, abs(not_const(f16(0.))), 0.) testing.expect_value(t, abs(not_const(f16(-0.))), 0.) testing.expect_value(t, abs(not_const(f16(-1.))), 1.) testing.expect_value(t, abs(not_const(min(f16))), max(f16)) testing.expect_value(t, abs(not_const(max(f16))), max(f16)) - testing.expect_value(t, abs(not_const(f16(-.12345))), .12345) + testing.expect_value(t, abs(not_const(f16(-.12))), .12) + // Variable f16le + testing.expect_value(t, abs(not_const(f16le(0.))), 0.) + testing.expect_value(t, abs(not_const(f16le(-0.))), 0.) + testing.expect_value(t, abs(not_const(f16le(-1.))), 1.) + testing.expect_value(t, abs(not_const(min(f16le))), max(f16le)) + testing.expect_value(t, abs(not_const(max(f16le))), max(f16le)) + testing.expect_value(t, abs(not_const(f16le(-.12))), .12) + + // Variable f16be + testing.expect_value(t, abs(not_const(f16be(0.))), 0.) + testing.expect_value(t, abs(not_const(f16be(-0.))), 0.) + testing.expect_value(t, abs(not_const(f16be(-1.))), 1.) + testing.expect_value(t, abs(not_const(min(f16be))), max(f16be)) + testing.expect_value(t, abs(not_const(max(f16be))), max(f16be)) + testing.expect_value(t, abs(not_const(f16be(-.12))), .12) +} + +@(test) +abs_f32_const :: proc(t: ^testing.T) { // Constant f32 testing.expect_value(t, abs(f32(0.)), 0.) testing.expect_value(t, abs(f32(-0.)), 0.) @@ -30,6 +69,25 @@ test_abs_float :: proc(t: ^testing.T) { testing.expect_value(t, abs(max(f32)), max(f32)) testing.expect_value(t, abs(f32(-.12345)), .12345) + // Constant f32le + testing.expect_value(t, abs(f32le(0.)), 0.) + testing.expect_value(t, abs(f32le(-0.)), 0.) + testing.expect_value(t, abs(f32le(-1.)), 1.) + testing.expect_value(t, abs(min(f32le)), max(f32le)) + testing.expect_value(t, abs(max(f32le)), max(f32le)) + testing.expect_value(t, abs(f32le(-.12345)), .12345) + + // Constant f32be + testing.expect_value(t, abs(f32be(0.)), 0.) + testing.expect_value(t, abs(f32be(-0.)), 0.) + testing.expect_value(t, abs(f32be(-1.)), 1.) + testing.expect_value(t, abs(min(f32be)), max(f32be)) + testing.expect_value(t, abs(max(f32be)), max(f32be)) + testing.expect_value(t, abs(f32be(-.12345)), .12345) +} + +@(test) +abs_f32_variable :: proc(t: ^testing.T) { // Variable f32 testing.expect_value(t, abs(not_const(f32(0.))), 0.) testing.expect_value(t, abs(not_const(f32(-0.))), 0.) @@ -38,6 +96,25 @@ test_abs_float :: proc(t: ^testing.T) { testing.expect_value(t, abs(not_const(max(f32))), max(f32)) testing.expect_value(t, abs(not_const(f32(-.12345))), .12345) + // Variable f32le + testing.expect_value(t, abs(not_const(f32le(0.))), 0.) + testing.expect_value(t, abs(not_const(f32le(-0.))), 0.) + testing.expect_value(t, abs(not_const(f32le(-1.))), 1.) + testing.expect_value(t, abs(not_const(min(f32le))), max(f32le)) + testing.expect_value(t, abs(not_const(max(f32le))), max(f32le)) + testing.expect_value(t, abs(not_const(f32le(-.12345))), .12345) + + // Variable f32be + testing.expect_value(t, abs(not_const(f32be(0.))), 0.) + testing.expect_value(t, abs(not_const(f32be(-0.))), 0.) + testing.expect_value(t, abs(not_const(f32be(-1.))), 1.) + testing.expect_value(t, abs(not_const(min(f32be))), max(f32be)) + testing.expect_value(t, abs(not_const(max(f32be))), max(f32be)) + testing.expect_value(t, abs(not_const(f32be(-.12345))), .12345) +} + +@(test) +abs_f64_const :: proc(t: ^testing.T) { // Constant f64 testing.expect_value(t, abs(f64(0.)), 0.) testing.expect_value(t, abs(f64(-0.)), 0.) @@ -46,6 +123,25 @@ test_abs_float :: proc(t: ^testing.T) { testing.expect_value(t, abs(max(f64)), max(f64)) testing.expect_value(t, abs(f64(-.12345)), .12345) + // Constant f64le + testing.expect_value(t, abs(f64le(0.)), 0.) + testing.expect_value(t, abs(f64le(-0.)), 0.) + testing.expect_value(t, abs(f64le(-1.)), 1.) + testing.expect_value(t, abs(min(f64le)), max(f64le)) + testing.expect_value(t, abs(max(f64le)), max(f64le)) + testing.expect_value(t, abs(f64le(-.12345)), .12345) + + // Constant f64be + testing.expect_value(t, abs(f64be(0.)), 0.) + testing.expect_value(t, abs(f64be(-0.)), 0.) + testing.expect_value(t, abs(f64be(-1.)), 1.) + testing.expect_value(t, abs(min(f64be)), max(f64be)) + testing.expect_value(t, abs(max(f64be)), max(f64be)) + testing.expect_value(t, abs(f64be(-.12345)), .12345) +} + +@(test) +abs_f64_variable :: proc(t: ^testing.T) { // Variable f64 testing.expect_value(t, abs(not_const(f64(0.))), 0.) testing.expect_value(t, abs(not_const(f64(-0.))), 0.) @@ -53,4 +149,20 @@ test_abs_float :: proc(t: ^testing.T) { testing.expect_value(t, abs(not_const(min(f64))), max(f64)) testing.expect_value(t, abs(not_const(max(f64))), max(f64)) testing.expect_value(t, abs(not_const(f64(-.12345))), .12345) + + // Variable f64le + testing.expect_value(t, abs(not_const(f64le(0.))), 0.) + testing.expect_value(t, abs(not_const(f64le(-0.))), 0.) + testing.expect_value(t, abs(not_const(f64le(-1.))), 1.) + testing.expect_value(t, abs(not_const(min(f64le))), max(f64le)) + testing.expect_value(t, abs(not_const(max(f64le))), max(f64le)) + testing.expect_value(t, abs(not_const(f64le(-.12345))), .12345) + + // Variable f64be + testing.expect_value(t, abs(not_const(f64be(0.))), 0.) + testing.expect_value(t, abs(not_const(f64be(-0.))), 0.) + testing.expect_value(t, abs(not_const(f64be(-1.))), 1.) + testing.expect_value(t, abs(not_const(min(f64be))), max(f64be)) + testing.expect_value(t, abs(not_const(max(f64be))), max(f64be)) + testing.expect_value(t, abs(not_const(f64be(-.12345))), .12345) } -- cgit v1.2.3 From 98201962e0cbf0448628b36e5b2bb78cfc25906c Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 14 Feb 2025 17:29:38 +0000 Subject: Begin work on producing a canonicalized type string for hashing types. --- src/types.cpp | 275 ++++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 248 insertions(+), 27 deletions(-) (limited to 'src') diff --git a/src/types.cpp b/src/types.cpp index 412448cbc..5df062677 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -1,5 +1,5 @@ -struct Scope; struct Ast; +struct Scope; struct Entity; enum BasicKind { @@ -161,10 +161,10 @@ struct TypeStruct { struct TypeUnion { Slice variants; - + Ast * node; Scope * scope; - + i64 variant_block_size; i64 custom_align; Type * polymorphic_params; // Type_Tuple @@ -1438,7 +1438,7 @@ gb_internal bool is_type_matrix(Type *t) { gb_internal i64 matrix_align_of(Type *t, struct TypePath *tp) { t = base_type(t); GB_ASSERT(t->kind == Type_Matrix); - + Type *elem = t->Matrix.elem; i64 row_count = gb_max(t->Matrix.row_count, 1); i64 column_count = gb_max(t->Matrix.column_count, 1); @@ -1450,15 +1450,15 @@ gb_internal i64 matrix_align_of(Type *t, struct TypePath *tp) { i64 elem_align = type_align_of_internal(elem, tp); if (pop) type_path_pop(tp); - + i64 elem_size = type_size_of(elem); - + // NOTE(bill, 2021-10-25): The alignment strategy here is to have zero padding // It would be better for performance to pad each column so that each column // could be maximally aligned but as a compromise, having no padding will be // beneficial to third libraries that assume no padding - + i64 total_expected_size = row_count*column_count*elem_size; // i64 min_alignment = prev_pow2(elem_align * row_count); i64 min_alignment = prev_pow2(total_expected_size); @@ -1466,7 +1466,7 @@ gb_internal i64 matrix_align_of(Type *t, struct TypePath *tp) { min_alignment >>= 1; } min_alignment = gb_max(min_alignment, elem_align); - + i64 align = gb_min(min_alignment, build_context.max_simd_align); return align; } @@ -1480,7 +1480,7 @@ gb_internal i64 matrix_type_stride_in_bytes(Type *t, struct TypePath *tp) { } else if (t->Matrix.row_count == 0) { return 0; } - + i64 elem_size; if (tp != nullptr) { elem_size = type_size_of_internal(t->Matrix.elem, tp); @@ -1489,7 +1489,7 @@ gb_internal i64 matrix_type_stride_in_bytes(Type *t, struct TypePath *tp) { } i64 stride_in_bytes = 0; - + // NOTE(bill, 2021-10-25): The alignment strategy here is to have zero padding // It would be better for performance to pad each column/row so that each column/row // could be maximally aligned but as a compromise, having no padding will be @@ -1545,7 +1545,7 @@ gb_internal i64 matrix_row_major_index_to_offset(Type *t, i64 index) { gb_internal i64 matrix_column_major_index_to_offset(Type *t, i64 index) { t = base_type(t); GB_ASSERT(t->kind == Type_Matrix); - + i64 row_index = index%t->Matrix.row_count; i64 column_index = index/t->Matrix.row_count; return matrix_indices_to_offset(t, row_index, column_index); @@ -1566,7 +1566,7 @@ gb_internal bool is_type_valid_for_matrix_elems(Type *t) { return true; } else if (is_type_complex(t)) { return true; - } + } if (t->kind == Type_Generic) { return true; } @@ -2119,6 +2119,23 @@ gb_internal bool is_type_sliceable(Type *t) { return false; } +gb_internal Entity *type_get_polymorphic_parent(Type *t, Type **params_) { + t = base_type(t); + Type *parent = nullptr; + if (t->kind == Type_Struct) { + parent = t->Struct.polymorphic_parent; + if (params_) *params_ = t->Struct.polymorphic_params; + } else if (t->kind == Type_Union) { + parent = t->Union.polymorphic_parent; + if (params_) *params_ = t->Union.polymorphic_params; + } + if (parent != nullptr) { + GB_ASSERT(parent->kind == Type_Named); + + return parent->Named.type_name; + } + return nullptr; +} gb_internal bool is_type_polymorphic_record(Type *t) { t = base_type(t); @@ -2485,7 +2502,7 @@ gb_internal bool is_type_simple_compare(Type *t) { case Type_Proc: case Type_BitSet: return true; - + case Type_Matrix: return is_type_simple_compare(t->Matrix.elem); @@ -2732,7 +2749,7 @@ gb_internal bool are_types_identical_internal(Type *x, Type *y, bool check_tuple case Type_Array: return (x->Array.count == y->Array.count) && are_types_identical(x->Array.elem, y->Array.elem); - + case Type_Matrix: return x->Matrix.row_count == y->Matrix.row_count && x->Matrix.column_count == y->Matrix.column_count && @@ -3592,7 +3609,7 @@ gb_internal bool are_struct_fields_reordered(Type *type) { return false; } GB_ASSERT(type->Struct.offsets != nullptr); - + i64 prev_offset = 0; for_array(i, type->Struct.fields) { i64 offset = type->Struct.offsets[i]; @@ -3613,9 +3630,9 @@ gb_internal Slice struct_fields_index_by_increasing_offset(gbAllocator allo return {}; } GB_ASSERT(type->Struct.offsets != nullptr); - + auto indices = slice_make(allocator, type->Struct.fields.count); - + i64 prev_offset = 0; bool is_ordered = true; for_array(i, indices) { @@ -3630,14 +3647,14 @@ gb_internal Slice struct_fields_index_by_increasing_offset(gbAllocator allo isize n = indices.count; for (isize i = 1; i < n; i++) { isize j = i; - + while (j > 0 && type->Struct.offsets[indices[j-1]] > type->Struct.offsets[indices[j]]) { gb_swap(i32, indices[j-1], indices[j]); j -= 1; - } + } } } - + return indices; } @@ -3887,8 +3904,8 @@ gb_internal i64 type_align_of_internal(Type *t, TypePath *path) { // IMPORTANT TODO(bill): Figure out the alignment of vector types return gb_clamp(next_pow2(type_size_of_internal(t, path)), 1, build_context.max_simd_align*2); } - - case Type_Matrix: + + case Type_Matrix: return matrix_align_of(t, path); case Type_SoaPointer: @@ -4175,7 +4192,7 @@ gb_internal i64 type_size_of_internal(Type *t, TypePath *path) { Type *elem = t->SimdVector.elem; return count * type_size_of_internal(elem, path); } - + case Type_Matrix: { i64 stride_in_bytes = matrix_type_stride_in_bytes(t, path); if (t->Matrix.is_row_major) { @@ -4580,7 +4597,7 @@ gb_internal gbString write_type_to_string(gbString str, Type *type, bool shortha break; case Type_Array: - str = gb_string_appendc(str, gb_bprintf("[%d]", cast(int)type->Array.count)); + str = gb_string_appendc(str, gb_bprintf("[%lld]", cast(long long)type->Array.count)); str = write_type_to_string(str, type->Array.elem); break; @@ -4753,10 +4770,10 @@ gb_internal gbString write_type_to_string(gbString str, Type *type, bool shortha } break; case ProcCC_CDecl: - str = gb_string_appendc(str, " \"cdecl\" "); + str = gb_string_appendc(str, " \"c\" "); break; case ProcCC_StdCall: - str = gb_string_appendc(str, " \"stdcall\" "); + str = gb_string_appendc(str, " \"std\" "); break; case ProcCC_FastCall: str = gb_string_appendc(str, " \"fastcall\" "); @@ -4814,7 +4831,7 @@ gb_internal gbString write_type_to_string(gbString str, Type *type, bool shortha str = gb_string_append_fmt(str, "#simd[%d]", cast(int)type->SimdVector.count); str = write_type_to_string(str, type->SimdVector.elem); break; - + case Type_Matrix: if (type->Matrix.is_row_major) { str = gb_string_appendc(str, "#row_major "); @@ -4856,5 +4873,209 @@ 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; +} + +// 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"); + return w; + case Type_Struct: + w = gb_string_appendc(w, "struct"); + return 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->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 2a5933513ca47d75c1f29efae2e9f948c3ae8103 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 15 Feb 2025 12:32:05 +0000 Subject: Fill in more canonical types --- src/types.cpp | 51 +++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 49 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/types.cpp b/src/types.cpp index 5df062677..c88878b9c 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -5010,10 +5010,57 @@ gb_internal gbString write_type_to_canonical_string(gbString w, Type *type) { case Type_Union: w = gb_string_appendc(w, "union"); - return w; + + 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"); - return w; + 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"); -- cgit v1.2.3 From 4eba3698aa1dde15abd22de1452229293282efee Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 17 Feb 2025 09:47:49 +0000 Subject: Begin work on nested declarations --- src/types.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'src') diff --git a/src/types.cpp b/src/types.cpp index c88878b9c..42530eccc 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -4919,6 +4919,12 @@ gb_internal u64 type_hash_canonical_type(Type *type) { 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) { @@ -5101,6 +5107,15 @@ gb_internal gbString write_type_to_canonical_string(gbString w, Type *type) { 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, "."); -- 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') 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') 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') 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') 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 b8f057951c47ccb07316fcd936dba9b71e052d1f Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 17 Feb 2025 13:46:17 +0000 Subject: Begin work on `TypeSet` --- src/checker.cpp | 21 ++-- src/checker.hpp | 21 +++- src/name_canonicalization.cpp | 221 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 246 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/checker.cpp b/src/checker.cpp index 054d6aeb0..6ceb31489 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -1363,6 +1363,7 @@ gb_internal void init_checker_info(CheckerInfo *i) { map_init(&i->gen_types); array_init(&i->type_info_types, a); map_init(&i->type_info_map); + type_set_init(&i->type_info_set); string_map_init(&i->files); string_map_init(&i->packages); array_init(&i->variable_init_order, a); @@ -1397,6 +1398,7 @@ gb_internal void destroy_checker_info(CheckerInfo *i) { map_destroy(&i->gen_types); array_free(&i->type_info_types); map_destroy(&i->type_info_map); + type_set_destroy(&i->type_info_set); string_map_destroy(&i->files); string_map_destroy(&i->packages); array_free(&i->variable_init_order); @@ -2040,7 +2042,7 @@ 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; - Type_Info_Type tt = {t, type_hash_canonical_type(t)}; + TypeInfoPair tt = {t, type_hash_canonical_type(t)}; array_add(&c->info->type_info_types, tt); } map_set(&c->checker->info.type_info_map, t, ti_index); @@ -2293,22 +2295,11 @@ gb_internal void add_min_dep_type_info(Checker *c, Type *t) { return; } - auto *set = &c->info.minimum_dependency_type_info_set; - - isize ti_index = type_info_index(&c->info, t, false); - if (ti_index < 0) { - add_type_info_type(&c->builtin_ctx, t); // Missing the type information - ti_index = type_info_index(&c->info, t, false); - } - GB_ASSERT(ti_index >= 0); - // IMPORTANT NOTE(bill): this must be copied as `map_set` takes a const ref - // and effectively assigns the `+1` of the value - isize const count = set->count; - if (map_set_if_not_previously_exists(set, ti_index+1, count)) { - // Type already exists; - return; + if (type_set_update(&c->info.type_info_set, t)) { + // return; } + // Add nested types if (t->kind == Type_Named) { // NOTE(bill): Just in case diff --git a/src/checker.hpp b/src/checker.hpp index c9a0c3302..725c1ccf5 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -409,11 +409,27 @@ struct Defineable { String pos_str; }; -struct Type_Info_Type { +struct TypeInfoPair { Type *type; u64 hash; // see: type_hash_canonical_type }; +struct TypeSet { + TypeInfoPair *keys; + usize count; + usize capacity; +}; + +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 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); + // CheckerInfo stores all the symbol information for a type-checked program struct CheckerInfo { Checker *checker; @@ -458,8 +474,9 @@ struct CheckerInfo { PtrMap gen_types; BlockingMutex type_info_mutex; // NOT recursive - Array type_info_types; + Array type_info_types; PtrMap type_info_map; + TypeSet type_info_set; BlockingMutex foreign_mutex; // NOT recursive StringMap foreigns; diff --git a/src/name_canonicalization.cpp b/src/name_canonicalization.cpp index 8edb5e968..b83441b19 100644 --- a/src/name_canonicalization.cpp +++ b/src/name_canonicalization.cpp @@ -44,6 +44,227 @@ 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; + +static constexpr u64 TYPE_SET_TOMBSTONE = ~(u64)(0ull); + +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 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(); +} + +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 TypeSetIterator begin(TypeSet &set) noexcept { + usize index = 0; + while (index < set.capacity) { + TypeInfoPair key = set.keys[index]; + if (key.hash != 0 && key.hash != TYPE_SET_TOMBSTONE) { + break; + } + index++; + } + return TypeSetIterator{&set, index}; +} +gb_internal TypeSetIterator end(TypeSet &set) noexcept { + return TypeSetIterator{&set, set.capacity}; +} + + +gb_internal void type_set_init(TypeSet *s, isize capacity) { + GB_ASSERT(s->keys == nullptr); + if (capacity != 0) { + capacity = next_pow2_isize(gb_max(16, capacity)); + s->keys = gb_alloc_array(type_set_allocator(), TypeInfoPair, capacity); + // This memory will be zeroed, no need to explicitly zero it + } + s->count = 0; + s->capacity = capacity; +} + +gb_internal void type_set_destroy(TypeSet *s) { + gb_free(type_set_allocator(), s->keys); + s->keys = nullptr; + s->count = 0; + s->capacity = 0; +} + + +gb_internal isize type_set__find(TypeSet *s, TypeInfoPair pair) { + GB_ASSERT(pair.type != nullptr); + GB_ASSERT(pair.hash != 0); + if (s->count != 0) { + usize hash = pair.hash; + usize mask = s->capacity-1; + usize hash_index = cast(usize)hash & mask; + for (usize i = 0; i < s->capacity; i++) { + Type *key = s->keys[hash_index].type; + if (are_types_identical(key, pair.type)) { + return hash_index; + } else if (key == 0) { + return -1; + } + hash_index = (hash_index+1)&mask; + } + } + return -1; +} +gb_internal isize type_set__find(TypeSet *s, Type *ptr) { + GB_ASSERT(ptr != 0); + if (s->count != 0) { + usize hash = cast(usize)type_hash_canonical_type(ptr); + usize mask = s->capacity-1; + usize hash_index = cast(usize)hash & mask; + for (usize i = 0; i < s->capacity; i++) { + Type *key = s->keys[hash_index].type; + if (are_types_identical(key, ptr)) { + return hash_index; + } else if (key == 0) { + return -1; + } + hash_index = (hash_index+1)&mask; + } + } + return -1; +} + +gb_internal bool type_set__full(TypeSet *s) { + return 0.75f * s->capacity <= s->count; +} + +gb_internal gb_inline void type_set_grow(TypeSet *old_set) { + if (old_set->capacity == 0) { + type_set_init(old_set); + return; + } + + TypeSet new_set = {}; + type_set_init(&new_set, gb_max(old_set->capacity<<1, 16)); + + for (TypeInfoPair const &set : *old_set) { + bool was_new = type_set_update(&new_set, set); + GB_ASSERT(!was_new); + } + GB_ASSERT(old_set->count == new_set.count); + + type_set_destroy(old_set); + + *old_set = new_set; +} + + +gb_internal gb_inline bool type_set_exists(TypeSet *s, Type *ptr) { + return type_set__find(s, ptr) >= 0; +} +gb_internal gb_inline bool type_set_exists(TypeSet *s, TypeInfoPair pair) { + return type_set__find(s, pair) >= 0; +} +gb_internal gb_inline TypeInfoPair *type_set_retrieve(TypeSet *s, Type *type) { + isize index = type_set__find(s, type); + if (index >= 0) { + return &s->keys[index]; + } + return nullptr; +} + + +gb_internal bool type_set_update(TypeSet *s, TypeInfoPair pair) { // returns true if it previously existsed + if (type_set_exists(s, pair)) { + return true; + } + + if (s->keys == nullptr) { + type_set_init(s); + } else if (type_set__full(s)) { + type_set_grow(s); + } + GB_ASSERT(s->count < s->capacity); + GB_ASSERT(s->capacity >= 0); + + usize mask = s->capacity-1; + usize hash = cast(usize)pair.hash; + usize hash_index = (cast(usize)hash) & mask; + GB_ASSERT(hash_index < s->capacity); + for (usize i = 0; i < s->capacity; i++) { + TypeInfoPair *key = &s->keys[hash_index]; + GB_ASSERT(!are_types_identical(key->type, pair.type)); + if (key->hash == TYPE_SET_TOMBSTONE || key->hash == 0) { + *key = pair; + s->count++; + return false; + } + hash_index = (hash_index+1)&mask; + } + + GB_PANIC("ptr set out of memory"); + return false; +} + +gb_internal bool type_set_update(TypeSet *s, Type *ptr) { // returns true if it previously existsed + TypeInfoPair pair = {ptr, type_hash_canonical_type(ptr)}; + return type_set_update(s, pair); +} + + +gb_internal Type *type_set_add(TypeSet *s, Type *ptr) { + type_set_update(s, ptr); + return ptr; +} + + +gb_internal void type_set_remove(TypeSet *s, Type *ptr) { + isize index = type_set__find(s, ptr); + if (index >= 0) { + GB_ASSERT(s->count > 0); + s->keys[index].type = nullptr; + s->keys[index].hash = TYPE_SET_TOMBSTONE; + s->count--; + } +} + +gb_internal gb_inline void type_set_clear(TypeSet *s) { + s->count = 0; + gb_zero_size(s->keys, s->capacity*gb_size_of(*s->keys)); +} + + gb_internal gbString write_canonical_params(gbString w, Type *params) { w = gb_string_appendc(w, "("); if (params) { -- cgit v1.2.3 From 4a29d9bb845050c483e537c7a0d6b2889af0f7bc Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 17 Feb 2025 16:29:42 +0000 Subject: Simplify type info table construction --- src/checker.cpp | 162 ++++++++++++++++++++++++++---------------- src/checker.hpp | 17 +++-- src/llvm_backend.cpp | 4 +- src/llvm_backend_type.cpp | 25 +++---- src/name_canonicalization.cpp | 23 ++++-- 5 files changed, 146 insertions(+), 85 deletions(-) (limited to 'src') diff --git a/src/checker.cpp b/src/checker.cpp index 6ceb31489..1c7126e9a 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -828,9 +828,15 @@ gb_internal void add_dependency(CheckerInfo *info, DeclInfo *d, Entity *e) { rw_mutex_unlock(&d->deps_mutex); } gb_internal void add_type_info_dependency(CheckerInfo *info, DeclInfo *d, Type *type) { - if (d == nullptr) { + if (d == nullptr || type == nullptr) { return; } + if (type->kind == Type_Named) { + Entity *e = type->Named.type_name; + if (e->TypeName.is_type_alias) { + type = type->Named.base; + } + } rw_mutex_lock(&d->type_info_deps_mutex); ptr_set_add(&d->type_info_deps, type); rw_mutex_unlock(&d->type_info_deps_mutex); @@ -1361,9 +1367,12 @@ gb_internal void init_checker_info(CheckerInfo *i) { string_map_init(&i->foreigns); // map_init(&i->gen_procs); map_init(&i->gen_types); + array_init(&i->type_info_types, a); - map_init(&i->type_info_map); - type_set_init(&i->type_info_set); + type_set_init(&i->min_dep_type_info_set); + map_init(&i->minimum_dependency_type_info_index_map); + + // map_init(&i->type_info_map); string_map_init(&i->files); string_map_init(&i->packages); array_init(&i->variable_init_order, a); @@ -1396,9 +1405,11 @@ gb_internal void destroy_checker_info(CheckerInfo *i) { string_map_destroy(&i->foreigns); // map_destroy(&i->gen_procs); map_destroy(&i->gen_types); + array_free(&i->type_info_types); - map_destroy(&i->type_info_map); - type_set_destroy(&i->type_info_set); + type_set_destroy(&i->min_dep_type_info_set); + map_destroy(&i->minimum_dependency_type_info_index_map); + string_map_destroy(&i->files); string_map_destroy(&i->packages); array_free(&i->variable_init_order); @@ -1632,41 +1643,36 @@ gb_internal void check_remove_expr_info(CheckerContext *c, Ast *e) { } } - -gb_internal isize type_info_index(CheckerInfo *info, Type *type, bool error_on_failure) { - type = default_type(type); - if (type == t_llvm_bool) { - type = t_bool; - } - - mutex_lock(&info->type_info_mutex); +gb_internal isize type_info_index(CheckerInfo *info, TypeInfoPair pair, bool error_on_failure) { + mutex_lock(&info->minimum_dependency_type_info_mutex); isize entry_index = -1; - isize *found_entry_index = map_get(&info->type_info_map, type); + uintptr hash = cast(uintptr)pair.hash; + isize *found_entry_index = map_get(&info->minimum_dependency_type_info_index_map, hash); if (found_entry_index) { entry_index = *found_entry_index; } - if (entry_index < 0) { - // NOTE(bill): Do manual linear search - for (auto const &e : info->type_info_map) { - if (are_types_identical_unique_tuples(e.key, type)) { - entry_index = e.value; - // NOTE(bill): Add it to the search map - map_set(&info->type_info_map, type, entry_index); - break; - } - } - } - - mutex_unlock(&info->type_info_mutex); + mutex_unlock(&info->minimum_dependency_type_info_mutex); if (error_on_failure && entry_index < 0) { - compiler_error("Type_Info for '%s' could not be found", type_to_string(type)); + compiler_error("Type_Info for '%s' could not be found", type_to_string(pair.type)); } return entry_index; } +gb_internal isize type_info_index(CheckerInfo *info, Type *type, bool error_on_failure) { + type = default_type(type); + if (type == t_llvm_bool) { + type = t_bool; + } + + u64 hash = type_hash_canonical_type(type); + return type_info_index(info, {type, hash}, error_on_failure); +} + + + gb_internal void add_untyped(CheckerContext *c, Ast *expr, AddressingMode mode, Type *type, ExactValue const &value) { if (expr == nullptr) { return; @@ -2018,8 +2024,12 @@ gb_internal void add_type_info_type_internal(CheckerContext *c, Type *t) { } add_type_info_dependency(c->info, c->decl, t); - +#if 0 MUTEX_GUARD_BLOCK(&c->info->type_info_mutex) { + if (type_set_update(&c->info->type_info_set, t)) { + // return; + } + auto found = map_get(&c->info->type_info_map, t); if (found != nullptr) { // Types have already been added @@ -2238,6 +2248,7 @@ gb_internal void add_type_info_type_internal(CheckerContext *c, Type *t) { GB_PANIC("Unhandled type: %*.s %d", LIT(type_strings[bt->kind]), bt->kind); break; } +#endif } @@ -2295,11 +2306,10 @@ gb_internal void add_min_dep_type_info(Checker *c, Type *t) { return; } - if (type_set_update(&c->info.type_info_set, t)) { - // return; + if (type_set_update(&c->info.min_dep_type_info_set, t)) { + return; } - // Add nested types if (t->kind == Type_Named) { // NOTE(bill): Just in case @@ -2697,7 +2707,6 @@ gb_internal void generate_minimum_dependency_set(Checker *c, Entity *start) { isize min_dep_set_cap = next_pow2_isize(entity_count*4); // empirically determined factor ptr_set_init(&c->info.minimum_dependency_set, min_dep_set_cap); - map_init(&c->info.minimum_dependency_type_info_set); #define FORCE_ADD_RUNTIME_ENTITIES(condition, ...) do { \ if (condition) { \ @@ -6720,39 +6729,70 @@ 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"); + TIME_SECTION("initilize type info array"); { - 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) - ); + for (auto const &tt : c->info.min_dep_type_info_set) { + array_add(&c->info.type_info_types, tt); + } + array_sort(c->info.type_info_types, type_info_pair_cmp); + + map_reserve(&c->info.minimum_dependency_type_info_index_map, c->info.type_info_types.count); + + for_array(i, c->info.type_info_types) { + auto const &tt = c->info.type_info_types[i]; + bool exists = map_set_if_not_previously_exists(&c->info.minimum_dependency_type_info_index_map, cast(uintptr)tt.hash, i); + if (exists) { + for (auto const &entry : c->info.minimum_dependency_type_info_index_map) { + if (entry.key == cast(uintptr)tt.hash) { + auto const &other = c->info.type_info_types[entry.value]; + if (!are_types_identical_unique_tuples(tt.type, other.type)) { + gbString t = temp_canonical_string(tt.type); + gbString o = temp_canonical_string(other.type); + GB_PANIC("%s (%s) %llu vs %s (%s) %llu", + type_to_string(tt.type, false), t, cast(unsigned long long)tt.hash, + type_to_string(other.type, false), o, cast(unsigned long long)other.hash); + } } } } } - } + + GB_ASSERT(c->info.minimum_dependency_type_info_index_map.count <= c->info.type_info_types.count); + } + + // 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) + // ); + // } + // } + // } + // } + // } diff --git a/src/checker.hpp b/src/checker.hpp index 725c1ccf5..52676d4ee 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -222,7 +222,7 @@ struct DeclInfo { PtrSet deps; RwMutex type_info_deps_mutex; - PtrSet type_info_deps; + PtrSet type_info_deps; // TODO(bill): Use TypeSet BlockingMutex type_and_value_mutex; @@ -444,8 +444,10 @@ struct CheckerInfo { Scope * init_scope; Entity * entry_point; PtrSet minimum_dependency_set; - PtrMap minimum_dependency_type_info_set; - + BlockingMutex minimum_dependency_type_info_mutex; + PtrMap minimum_dependency_type_info_index_map; + TypeSet min_dep_type_info_set; + Array type_info_types; // sorted after filled Array testing_procedures; @@ -473,10 +475,10 @@ struct CheckerInfo { BlockingMutex gen_types_mutex; PtrMap gen_types; - BlockingMutex type_info_mutex; // NOT recursive - Array type_info_types; - PtrMap type_info_map; - TypeSet type_info_set; + // BlockingMutex type_info_mutex; // NOT recursive + // Array type_info_types; + // PtrMap type_info_map; + // TypeSet type_info_set; BlockingMutex foreign_mutex; // NOT recursive StringMap foreigns; @@ -595,6 +597,7 @@ gb_internal DeclInfo * decl_info_of_entity (Entity * e); gb_internal AstFile * ast_file_of_filename (CheckerInfo *i, String filename); // IMPORTANT: Only to use once checking is done gb_internal isize type_info_index (CheckerInfo *i, Type *type, bool error_on_failure); +gb_internal isize type_info_index (CheckerInfo *info, TypeInfoPair pair, bool error_on_failure); // Will return nullptr if not found gb_internal Entity *entity_of_node(Ast *expr); diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 8cb480dd4..908117501 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -3154,7 +3154,9 @@ gb_internal bool lb_generate_code(lbGenerator *gen) { lbModule *m = default_module; { // Add type info data - isize max_type_info_count = info->minimum_dependency_type_info_set.count+1; + GB_ASSERT_MSG(info->minimum_dependency_type_info_index_map.count == info->type_info_types.count, "%tu vs %tu", info->minimum_dependency_type_info_index_map.count, info->type_info_types.count); + + isize max_type_info_count = info->minimum_dependency_type_info_index_map.count+1; Type *t = alloc_type_array(t_type_info_ptr, max_type_info_count); // IMPORTANT NOTE(bill): As LLVM does not have a union type, an array of unions cannot be initialized diff --git a/src/llvm_backend_type.cpp b/src/llvm_backend_type.cpp index 6f9f94fbd..8e0f15f35 100644 --- a/src/llvm_backend_type.cpp +++ b/src/llvm_backend_type.cpp @@ -1,16 +1,12 @@ -gb_internal isize lb_type_info_index(CheckerInfo *info, Type *type, bool err_on_not_found=true) { - auto *set = &info->minimum_dependency_type_info_set; - isize index = type_info_index(info, type, err_on_not_found); + +gb_internal isize lb_type_info_index(CheckerInfo *info, TypeInfoPair pair, bool err_on_not_found=true) { + isize index = type_info_index(info, pair, err_on_not_found); if (index >= 0) { - auto *found = map_get(set, index+1); - if (found) { - GB_ASSERT(*found >= 0); - return *found + 1; - } + return index+1; } if (err_on_not_found) { - gb_printf_err("NOT FOUND lb_type_info_index:\n\t%s\n\t@ index %td\n\tmax count: %u\nFound:\n", type_to_string(type), index, set->count); - for (auto const &entry : *set) { + gb_printf_err("NOT FOUND lb_type_info_index:\n\t%s\n\t@ index %td\n\tmax count: %u\nFound:\n", type_to_string(pair.type), index, info->minimum_dependency_type_info_index_map.count); + for (auto const &entry : info->minimum_dependency_type_info_index_map) { isize type_info_index = entry.key; gb_printf_err("\t%s\n", type_to_string(info->type_info_types[type_info_index].type)); } @@ -19,6 +15,10 @@ gb_internal isize lb_type_info_index(CheckerInfo *info, Type *type, bool err_on_ return -1; } +gb_internal isize lb_type_info_index(CheckerInfo *info, Type *type, bool err_on_not_found=true) { + return lb_type_info_index(info, {type, type_hash_canonical_type(type)}, err_on_not_found); +} + gb_internal u64 lb_typeid_kind(lbModule *m, Type *type, u64 id=0) { GB_ASSERT(!build_context.no_rtti); @@ -280,12 +280,13 @@ 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; + auto const &tt = info->type_info_types[type_info_type_index]; + Type *t = tt.type; if (t == nullptr || t == t_invalid) { continue; } - isize entry_index = lb_type_info_index(info, t, false); + isize entry_index = lb_type_info_index(info, tt, false); if (entry_index <= 0) { continue; } diff --git a/src/name_canonicalization.cpp b/src/name_canonicalization.cpp index b83441b19..de35312da 100644 --- a/src/name_canonicalization.cpp +++ b/src/name_canonicalization.cpp @@ -48,6 +48,15 @@ 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; + if (x->hash == y->hash) { + return 0; + } + return x->hash < y->hash ? -1 : +1; +} + static constexpr u64 TYPE_SET_TOMBSTONE = ~(u64)(0ull); gb_internal void type_set_init (TypeSet *s, isize capacity); @@ -136,7 +145,7 @@ gb_internal isize type_set__find(TypeSet *s, TypeInfoPair pair) { usize hash_index = cast(usize)hash & mask; for (usize i = 0; i < s->capacity; i++) { Type *key = s->keys[hash_index].type; - if (are_types_identical(key, pair.type)) { + if (are_types_identical_unique_tuples(key, pair.type)) { return hash_index; } else if (key == 0) { return -1; @@ -154,7 +163,7 @@ gb_internal isize type_set__find(TypeSet *s, Type *ptr) { usize hash_index = cast(usize)hash & mask; for (usize i = 0; i < s->capacity; i++) { Type *key = s->keys[hash_index].type; - if (are_types_identical(key, ptr)) { + if (are_types_identical_unique_tuples(key, ptr)) { return hash_index; } else if (key == 0) { return -1; @@ -224,7 +233,7 @@ gb_internal bool type_set_update(TypeSet *s, TypeInfoPair pair) { // returns tru GB_ASSERT(hash_index < s->capacity); for (usize i = 0; i < s->capacity; i++) { TypeInfoPair *key = &s->keys[hash_index]; - GB_ASSERT(!are_types_identical(key->type, pair.type)); + GB_ASSERT(!are_types_identical_unique_tuples(key->type, pair.type)); if (key->hash == TYPE_SET_TOMBSTONE || key->hash == 0) { *key = pair; s->count++; @@ -274,6 +283,9 @@ gb_internal gbString write_canonical_params(gbString w, Type *params) { if (i > 0) { w = gb_string_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); + if (v->kind == Entity_Variable) { if (v->flags&EntityFlag_CVarArg) { w = gb_string_appendc(w, CANONICAL_PARAM_C_VARARG); @@ -466,14 +478,17 @@ write_base_name: switch (e->kind) { case Entity_TypeName: { + Type *params = nullptr; Entity *parent = type_get_polymorphic_parent(e->type, ¶ms); - if (parent) { + 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); } else { w = gb_string_append_length(w, e->token.string.text, e->token.string.len); } + gb_unused(parent); + } // Handle parapoly stuff here? return w; -- cgit v1.2.3 From d69eb57cfa7a781e68b61307093e08790f95f640 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 18 Feb 2025 13:18:51 +0000 Subject: Fix typos --- src/checker.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/checker.cpp b/src/checker.cpp index 1c7126e9a..41adf0296 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -6729,7 +6729,7 @@ 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("initilize type info array"); + TIME_SECTION("initialize and check for collisions in type info array"); { for (auto const &tt : c->info.min_dep_type_info_set) { array_add(&c->info.type_info_types, tt); -- cgit v1.2.3 From 721bcf2249fe2f2f6dd462833fede983205d6c5a Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 18 Feb 2025 13:24:08 +0000 Subject: Minor code clean up --- src/checker.cpp | 62 ++++++++++++++------------------------------------------- 1 file changed, 15 insertions(+), 47 deletions(-) (limited to 'src') diff --git a/src/checker.cpp b/src/checker.cpp index 41adf0296..32e5ca405 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -6741,60 +6741,28 @@ gb_internal void check_parsed_files(Checker *c) { for_array(i, c->info.type_info_types) { auto const &tt = c->info.type_info_types[i]; bool exists = map_set_if_not_previously_exists(&c->info.minimum_dependency_type_info_index_map, cast(uintptr)tt.hash, i); - if (exists) { - for (auto const &entry : c->info.minimum_dependency_type_info_index_map) { - if (entry.key == cast(uintptr)tt.hash) { - auto const &other = c->info.type_info_types[entry.value]; - if (!are_types_identical_unique_tuples(tt.type, other.type)) { - gbString t = temp_canonical_string(tt.type); - gbString o = temp_canonical_string(other.type); - GB_PANIC("%s (%s) %llu vs %s (%s) %llu", - type_to_string(tt.type, false), t, cast(unsigned long long)tt.hash, - type_to_string(other.type, false), o, cast(unsigned long long)other.hash); - } - } + if (!exists) { + continue + } + for (auto const &entry : c->info.minimum_dependency_type_info_index_map) { + if (entry.key != cast(uintptr)tt.hash) { + continue; } + auto const &other = c->info.type_info_types[entry.value]; + if (are_types_identical_unique_tuples(tt.type, other.type)) { + continue; + } + gbString t = temp_canonical_string(tt.type); + gbString o = temp_canonical_string(other.type); + GB_PANIC("%s (%s) %llu vs %s (%s) %llu", + type_to_string(tt.type, false), t, cast(unsigned long long)tt.hash, + type_to_string(other.type, false), o, cast(unsigned long long)other.hash); } } GB_ASSERT(c->info.minimum_dependency_type_info_index_map.count <= c->info.type_info_types.count); } - // 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); -- cgit v1.2.3 From 19b59461b04f4b6b63fa24d70e9c9376b3dd3249 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 18 Feb 2025 13:31:34 +0000 Subject: Use `TypeSet` for DeclInfo deps --- src/check_decl.cpp | 4 +-- src/checker.cpp | 10 +++--- src/checker.hpp | 80 ++++++++++++++++++++++++++++++------------- src/name_canonicalization.cpp | 37 ++++---------------- 4 files changed, 71 insertions(+), 60 deletions(-) (limited to 'src') diff --git a/src/check_decl.cpp b/src/check_decl.cpp index d6f8e6fa7..5607ea725 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -1742,8 +1742,8 @@ gb_internal void add_deps_from_child_to_parent(DeclInfo *decl) { rw_mutex_shared_lock(&decl->type_info_deps_mutex); rw_mutex_lock(&decl->parent->type_info_deps_mutex); - for (Type *t : decl->type_info_deps) { - ptr_set_add(&decl->parent->type_info_deps, t); + for (auto const &tt : decl->type_info_deps) { + type_set_add(&decl->parent->type_info_deps, tt); } rw_mutex_unlock(&decl->parent->type_info_deps_mutex); diff --git a/src/checker.cpp b/src/checker.cpp index 32e5ca405..38da38b0c 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -173,7 +173,7 @@ gb_internal void init_decl_info(DeclInfo *d, Scope *scope, DeclInfo *parent) { d->parent = parent; d->scope = scope; ptr_set_init(&d->deps, 0); - ptr_set_init(&d->type_info_deps, 0); + type_set_init(&d->type_info_deps, 0); d->labels.allocator = heap_allocator(); d->variadic_reuses.allocator = heap_allocator(); d->variadic_reuse_max_bytes = 0; @@ -838,7 +838,7 @@ gb_internal void add_type_info_dependency(CheckerInfo *info, DeclInfo *d, Type * } } rw_mutex_lock(&d->type_info_deps_mutex); - ptr_set_add(&d->type_info_deps, type); + type_set_add(&d->type_info_deps, type); rw_mutex_unlock(&d->type_info_deps_mutex); } @@ -2506,8 +2506,8 @@ gb_internal void add_dependency_to_set(Checker *c, Entity *entity) { if (decl == nullptr) { return; } - for (Type *t : decl->type_info_deps) { - add_min_dep_type_info(c, t); + for (TypeInfoPair const tt : decl->type_info_deps) { + add_min_dep_type_info(c, tt.type); } for (Entity *e : decl->deps) { @@ -6742,7 +6742,7 @@ gb_internal void check_parsed_files(Checker *c) { auto const &tt = c->info.type_info_types[i]; bool exists = map_set_if_not_previously_exists(&c->info.minimum_dependency_type_info_index_map, cast(uintptr)tt.hash, i); if (!exists) { - continue + continue; } for (auto const &entry : c->info.minimum_dependency_type_info_index_map) { if (entry.key != cast(uintptr)tt.hash) { diff --git a/src/checker.hpp b/src/checker.hpp index 52676d4ee..b8878d745 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -167,6 +167,61 @@ 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; + enum ProcCheckedState : u8 { ProcCheckedState_Unchecked, @@ -221,8 +276,8 @@ struct DeclInfo { RwMutex deps_mutex; PtrSet deps; - RwMutex type_info_deps_mutex; - PtrSet type_info_deps; // TODO(bill): Use TypeSet + RwMutex type_info_deps_mutex; + TypeSet type_info_deps; BlockingMutex type_and_value_mutex; @@ -409,27 +464,6 @@ struct Defineable { String pos_str; }; -struct TypeInfoPair { - Type *type; - u64 hash; // see: type_hash_canonical_type -}; - -struct TypeSet { - TypeInfoPair *keys; - usize count; - usize capacity; -}; - -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 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); - // CheckerInfo stores all the symbol information for a type-checked program struct CheckerInfo { Checker *checker; diff --git a/src/name_canonicalization.cpp b/src/name_canonicalization.cpp index de35312da..ef0e23f38 100644 --- a/src/name_canonicalization.cpp +++ b/src/name_canonicalization.cpp @@ -57,11 +57,10 @@ gb_internal GB_COMPARE_PROC(type_info_pair_cmp) { return x->hash < y->hash ? -1 : +1; } -static constexpr u64 TYPE_SET_TOMBSTONE = ~(u64)(0ull); - 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); @@ -73,34 +72,6 @@ gb_internal gbAllocator type_set_allocator(void) { return heap_allocator(); } -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 TypeSetIterator begin(TypeSet &set) noexcept { usize index = 0; while (index < set.capacity) { @@ -257,6 +228,12 @@ gb_internal Type *type_set_add(TypeSet *s, Type *ptr) { return ptr; } +gb_internal Type *type_set_add(TypeSet *s, TypeInfoPair pair) { + type_set_update(s, pair); + return pair.type; +} + + gb_internal void type_set_remove(TypeSet *s, Type *ptr) { isize index = type_set__find(s, ptr); -- 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') 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 04c1ff61f43a34b9f3d0945eb02af1518cb1e230 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 18 Feb 2025 15:03:49 +0000 Subject: Update the comments --- src/name_canonicalization.cpp | 109 ++++++++++++++++++++++-------------------- src/name_canonicalization.hpp | 1 + 2 files changed, 59 insertions(+), 51 deletions(-) (limited to 'src') diff --git a/src/name_canonicalization.cpp b/src/name_canonicalization.cpp index 9c2858170..ed72bb2e2 100644 --- a/src/name_canonicalization.cpp +++ b/src/name_canonicalization.cpp @@ -3,19 +3,19 @@ * No spaces between any values - * normal declarations - pkg.name + * 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: `pkg.[file.odin].Type` - * polymorphic procedure/type - pkg.foo::TYPE + * nested - pkg::parent1::parent2::name + * file private - pkg::[file_name]::name + * Example: `pkg::[file.odin]::Type` + * polymorphic procedure/type - pkg::foo:TYPE * naming convention for parameters * type * $typeid_based_name * $$constant_parameter - * Example: `foo.to_thing::proc(u64)->([]u8)` - * nested decl in polymorphic procedure - pkg.foo::TYPE.name - * anonymous procedures - pkg.foo.$anon[file.odin:123] + * Example: `foo::to_thing:proc(u64)->([]u8)` + * nested decl in polymorphic procedure - pkg::foo:TYPE::name + * anonymous procedures - pkg::foo::$anon[file.odin:123] * 123 is the file offset in bytes @@ -280,42 +280,51 @@ void type_writer_make_hasher(TypeWriter *w, u64 *hash) { 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) { - type_writer_appendc(w, CANONICAL_PARAM_SEPARATOR); - } - type_writer_append(w, v->token.string.text, v->token.string.len); - type_writer_appendc(w, CANONICAL_TYPE_SEPARATOR); + defer (type_writer_appendc(w, ")")); - if (v->kind == Entity_Variable) { - if (v->flags&EntityFlag_CVarArg) { - type_writer_appendc(w, CANONICAL_PARAM_C_VARARG); - } - if (v->flags&EntityFlag_Ellipsis) { - Type *slice = base_type(v->type); - type_writer_appendc(w, CANONICAL_PARAM_VARARG); - GB_ASSERT(v->type->kind == Type_Slice); - write_type_to_canonical_string(w, slice->Slice.elem); - } else { - write_type_to_canonical_string(w, v->type); - } - } else if (v->kind == Entity_TypeName) { - type_writer_appendc(w, CANONICAL_PARAM_TYPEID); + if (params == nullptr) { + return; + } + GB_ASSERT(params->kind == Type_Tuple); + for_array(i, params->Tuple.variables) { + Entity *v = params->Tuple.variables[i]; + if (i > 0) { + type_writer_appendc(w, CANONICAL_PARAM_SEPARATOR); + } + type_writer_append(w, v->token.string.text, v->token.string.len); + type_writer_appendc(w, CANONICAL_TYPE_SEPARATOR); + + switch (v->kind) { + case Entity_Variable: + if (v->flags&EntityFlag_CVarArg) { + type_writer_appendc(w, CANONICAL_PARAM_C_VARARG); + } + if (v->flags&EntityFlag_Ellipsis) { + Type *slice = base_type(v->type); + type_writer_appendc(w, CANONICAL_PARAM_VARARG); + GB_ASSERT(v->type->kind == Type_Slice); + write_type_to_canonical_string(w, slice->Slice.elem); + } else { write_type_to_canonical_string(w, v->type); - } else if (v->kind == Entity_Constant) { + } + break; + case Entity_TypeName: + type_writer_appendc(w, CANONICAL_PARAM_TYPEID); + write_type_to_canonical_string(w, v->type); + break; + case Entity_Constant: + { type_writer_appendc(w, CANONICAL_PARAM_CONST); gbString s = exact_value_to_string(v->Constant.value, 1<<16); type_writer_append(w, s, gb_string_length(s)); gb_string_free(s); - } else { - GB_PANIC("TODO(bill): handle non type/const parapoly parameter values"); } + break; + default: + GB_PANIC("TODO(bill): handle non type/const parapoly parameter values"); + break; } } - type_writer_appendc(w, ")"); return; } @@ -348,19 +357,6 @@ gb_internal gbString temp_canonical_string(Type *type) { return cast(gbString)w.user_data; } -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 string_canonical_entity_name(gbAllocator allocator, Entity *e) { TypeWriter w = {}; type_writer_make_string(&w, allocator); @@ -477,6 +473,20 @@ gb_internal void write_canonical_entity_name(TypeWriter *w, Entity *e) { goto write_base_name; } gb_printf_err("%s WEIRD ENTITY TYPE %s %u %p\n", token_pos_to_string(e->token.pos), type_to_string(e->type), s->flags, s->decl_info); + + auto const print_scope_flags = [](Scope *s) { + if (s->flags & ScopeFlag_Pkg) gb_printf_err("Pkg "); + if (s->flags & ScopeFlag_Builtin) gb_printf_err("Builtin "); + if (s->flags & ScopeFlag_Global) gb_printf_err("Global "); + if (s->flags & ScopeFlag_File) gb_printf_err("File "); + if (s->flags & ScopeFlag_Init) gb_printf_err("Init "); + if (s->flags & ScopeFlag_Proc) gb_printf_err("Proc "); + if (s->flags & ScopeFlag_Type) gb_printf_err("Type "); + if (s->flags & ScopeFlag_HasBeenImported) gb_printf_err("HasBeenImported "); + if (s->flags & ScopeFlag_ContextDefined) gb_printf_err("ContextDefined "); + gb_printf_err("\n"); + }; + print_scope_flags(s); GB_PANIC("weird entity"); } @@ -499,10 +509,7 @@ write_base_name: } else { type_writer_append(w, e->token.string.text, e->token.string.len); } - gb_unused(parent); - } - // Handle parapoly stuff here? return; case Entity_Procedure: diff --git a/src/name_canonicalization.hpp b/src/name_canonicalization.hpp index 620665cd2..1820a90fb 100644 --- a/src/name_canonicalization.hpp +++ b/src/name_canonicalization.hpp @@ -1,6 +1,7 @@ #define CANONICAL_TYPE_SEPARATOR ":" #define CANONICAL_NAME_SEPARATOR "::" +// #define CANONICAL_NAME_SEPARATOR "·" #define CANONICAL_BIT_FIELD_SEPARATOR "|" -- 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') 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 e168cea67011f43209d752d52bad862a6416795e Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 18 Feb 2025 15:17:04 +0000 Subject: Add offset for nested things --- src/name_canonicalization.cpp | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/name_canonicalization.cpp b/src/name_canonicalization.cpp index ed72bb2e2..0e81ab12c 100644 --- a/src/name_canonicalization.cpp +++ b/src/name_canonicalization.cpp @@ -366,11 +366,10 @@ gb_internal gbString string_canonical_entity_name(gbAllocator allocator, Entity -gb_internal void write_canonical_parent_prefix(TypeWriter *w, Entity *e, bool ignore_final_dot=false) { +gb_internal void write_canonical_parent_prefix(TypeWriter *w, Entity *e) { GB_ASSERT(e != nullptr); - - if (e->kind == Entity_Procedure) { - if (e->Procedure.is_export || e->Procedure.is_foreign) { + if (e->kind == Entity_Procedure || e->kind == Entity_TypeName) { + if (e->kind == Entity_Procedure && (e->Procedure.is_export || e->Procedure.is_foreign)) { // no prefix return; } @@ -396,7 +395,7 @@ gb_internal void write_canonical_parent_prefix(TypeWriter *w, Entity *e, bool ig if (e->pkg->name == "llvm") { type_writer_appendc(w, "$"); } - type_writer_appendc(w, gb_bprintf(CANONICAL_NAME_SEPARATOR "[%.*s]" CANONICAL_NAME_SEPARATOR, LIT(file_name))); + type_writer_append_fmt(w, 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) { @@ -405,10 +404,9 @@ gb_internal void write_canonical_parent_prefix(TypeWriter *w, Entity *e, bool ig } GB_PANIC("TODO(bill): handle entity kind: %d", e->kind); } - if (e->kind == Entity_Procedure && e->Procedure.is_anonymous) { String file_name = filename_without_directory(e->file->fullpath); - type_writer_appendc(w, gb_bprintf(CANONICAL_ANON_PREFIX "[%.*s:%d]", LIT(file_name), e->token.pos.offset)); + type_writer_append_fmt(w, CANONICAL_ANON_PREFIX "[%.*s:%d]", LIT(file_name), e->token.pos.offset); } else { type_writer_append(w, e->token.string.text, e->token.string.len); } @@ -417,9 +415,7 @@ gb_internal void write_canonical_parent_prefix(TypeWriter *w, Entity *e, bool ig type_writer_appendc(w, CANONICAL_TYPE_SEPARATOR); write_type_to_canonical_string(w, e->type); } - if (!ignore_final_dot) { - type_writer_appendc(w, CANONICAL_NAME_SEPARATOR); - } + type_writer_appendc(w, CANONICAL_NAME_SEPARATOR); return; } @@ -461,7 +457,10 @@ gb_internal void write_canonical_entity_name(TypeWriter *w, Entity *e) { } if (s->decl_info != nullptr && s->decl_info->entity) { - write_canonical_parent_prefix(w, s->decl_info->entity); + Entity *parent = s->decl_info->entity; + write_canonical_parent_prefix(w, parent); + type_writer_append_fmt(w, CANONICAL_TYPE_SEPARATOR "[%d]", e->token.pos.offset); + goto write_base_name; } else if ((s->flags & ScopeFlag_File) && s->file != nullptr) { String file_name = filename_without_directory(s->file->fullpath); -- cgit v1.2.3 From 0482facdda4fd9257202fb89d9563d5a44e1499a Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 18 Feb 2025 15:26:59 +0000 Subject: Fix for weird builtin types --- src/name_canonicalization.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/name_canonicalization.cpp b/src/name_canonicalization.cpp index 0e81ab12c..6f092181c 100644 --- a/src/name_canonicalization.cpp +++ b/src/name_canonicalization.cpp @@ -448,11 +448,15 @@ gb_internal void write_canonical_entity_name(TypeWriter *w, Entity *e) { return; } - if ((e->scope->flags & (ScopeFlag_File | ScopeFlag_Pkg)) == 0 || - e->flags & EntityFlag_NotExported) { - + if (e->scope->flags & (ScopeFlag_Builtin)) { + // ignore + } else if ((e->scope->flags & (ScopeFlag_File | ScopeFlag_Pkg)) == 0) { Scope *s = e->scope; + while ((s->flags & (ScopeFlag_Proc|ScopeFlag_File)) == 0 && s->decl_info == nullptr) { + if (s->parent == nullptr) { + break; + } s = s->parent; } @@ -470,6 +474,8 @@ gb_internal void write_canonical_entity_name(TypeWriter *w, Entity *e) { } type_writer_appendc(w, gb_bprintf(CANONICAL_NAME_SEPARATOR "[%.*s]" CANONICAL_NAME_SEPARATOR, LIT(file_name))); goto write_base_name; + } else if (s->flags & (ScopeFlag_Builtin)) { + goto write_base_name; } gb_printf_err("%s WEIRD ENTITY TYPE %s %u %p\n", token_pos_to_string(e->token.pos), type_to_string(e->type), s->flags, s->decl_info); @@ -487,7 +493,7 @@ gb_internal void write_canonical_entity_name(TypeWriter *w, Entity *e) { }; print_scope_flags(s); - GB_PANIC("weird entity"); + GB_PANIC("weird entity %.*s", LIT(e->token.string)); } if (e->pkg != nullptr) { type_writer_append(w, e->pkg->name.text, e->pkg->name.len); -- cgit v1.2.3 From 827cd45f04f2f86c59c67c549dbc44b33e1f2863 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 18 Feb 2025 17:12:58 +0000 Subject: Add to check to fix crash --- src/name_canonicalization.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/name_canonicalization.cpp b/src/name_canonicalization.cpp index 6f092181c..fd4e4b50f 100644 --- a/src/name_canonicalization.cpp +++ b/src/name_canonicalization.cpp @@ -449,8 +449,9 @@ gb_internal void write_canonical_entity_name(TypeWriter *w, Entity *e) { } if (e->scope->flags & (ScopeFlag_Builtin)) { - // ignore - } else if ((e->scope->flags & (ScopeFlag_File | ScopeFlag_Pkg)) == 0) { + goto write_base_name; + } else if ((e->scope->flags & (ScopeFlag_File | ScopeFlag_Pkg)) == 0 || + e->flags & EntityFlag_NotExported) { Scope *s = e->scope; while ((s->flags & (ScopeFlag_Proc|ScopeFlag_File)) == 0 && s->decl_info == nullptr) { -- cgit v1.2.3 From 0bac34eec891080e2d0b9b4fc9e7b429a42064a3 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 19 Feb 2025 10:59:05 +0000 Subject: Number fields within procedures with a depth-first numbering system --- src/checker.cpp | 4 ++++ src/checker.hpp | 4 ++++ src/name_canonicalization.cpp | 5 ++++- 3 files changed, 12 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/checker.cpp b/src/checker.cpp index 38da38b0c..f1f1b2556 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -358,6 +358,10 @@ gb_internal void check_open_scope(CheckerContext *c, Ast *node) { scope->flags |= ScopeFlag_Type; break; } + if (c->decl && c->decl->proc_lit) { + // Number the scopes within a procedure body depth-first + scope->index = c->decl->scope_index++; + } c->scope = scope; c->state_flags |= StateFlag_bounds_check; } diff --git a/src/checker.hpp b/src/checker.hpp index 8850d5c3f..c89a1bc9c 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -229,6 +229,8 @@ struct DeclInfo { Array labels; + i32 scope_index; + Array variadic_reuses; i64 variadic_reuse_max_bytes; i64 variadic_reuse_max_align; @@ -273,6 +275,8 @@ struct Scope { std::atomic next; std::atomic head_child; + i32 index; // within a procedure + RwMutex mutex; StringMap elements; PtrSet imported; diff --git a/src/name_canonicalization.cpp b/src/name_canonicalization.cpp index fd4e4b50f..b24bf9126 100644 --- a/src/name_canonicalization.cpp +++ b/src/name_canonicalization.cpp @@ -464,7 +464,10 @@ gb_internal void write_canonical_entity_name(TypeWriter *w, Entity *e) { if (s->decl_info != nullptr && s->decl_info->entity) { Entity *parent = s->decl_info->entity; write_canonical_parent_prefix(w, parent); - type_writer_append_fmt(w, CANONICAL_TYPE_SEPARATOR "[%d]", e->token.pos.offset); + if (e->scope->index > 0) { + type_writer_append_fmt(w, CANONICAL_TYPE_SEPARATOR "[%d]", e->scope->index); + } + // type_writer_append_fmt(w, CANONICAL_TYPE_SEPARATOR "[%d]", e->token.pos.offset); goto write_base_name; } else if ((s->flags & ScopeFlag_File) && s->file != nullptr) { -- cgit v1.2.3 From 29456bcdea6e9567a9655e49a948f9e57920ff7a Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 19 Feb 2025 11:12:32 +0000 Subject: Move docs to the header --- src/name_canonicalization.cpp | 30 +----------------------------- src/name_canonicalization.hpp | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+), 29 deletions(-) (limited to 'src') diff --git a/src/name_canonicalization.cpp b/src/name_canonicalization.cpp index b24bf9126..043317ef0 100644 --- a/src/name_canonicalization.cpp +++ b/src/name_canonicalization.cpp @@ -1,26 +1,3 @@ -/* - 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: `pkg::[file.odin]::Type` - * polymorphic procedure/type - pkg::foo:TYPE - * naming convention for parameters - * type - * $typeid_based_name - * $$constant_parameter - * Example: `foo::to_thing:proc(u64)->([]u8)` - * nested decl in polymorphic procedure - pkg::foo:TYPE::name - * anonymous procedures - pkg::foo::$anon[file.odin:123] - * 123 is the file offset in bytes - - -*/ - gb_internal GB_COMPARE_PROC(type_info_pair_cmp) { TypeInfoPair *x = cast(TypeInfoPair *)a; TypeInfoPair *y = cast(TypeInfoPair *)b; @@ -397,11 +374,7 @@ gb_internal void write_canonical_parent_prefix(TypeWriter *w, Entity *e) { } type_writer_append_fmt(w, 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; - } + } else { GB_PANIC("TODO(bill): handle entity kind: %d", e->kind); } if (e->kind == Entity_Procedure && e->Procedure.is_anonymous) { @@ -467,7 +440,6 @@ gb_internal void write_canonical_entity_name(TypeWriter *w, Entity *e) { if (e->scope->index > 0) { type_writer_append_fmt(w, CANONICAL_TYPE_SEPARATOR "[%d]", e->scope->index); } - // type_writer_append_fmt(w, CANONICAL_TYPE_SEPARATOR "[%d]", e->token.pos.offset); goto write_base_name; } else if ((s->flags & ScopeFlag_File) && s->file != nullptr) { diff --git a/src/name_canonicalization.hpp b/src/name_canonicalization.hpp index 1820a90fb..e289ed5b2 100644 --- a/src/name_canonicalization.hpp +++ b/src/name_canonicalization.hpp @@ -1,3 +1,25 @@ +/* + General Rules for canonical name mangling + + * No spaces between any values + + * normal declarations - pkg::name + * builtin names - just their normal name e.g. `i32` or `string` + * nested (zero level) - pkg::parent1::parent2::name + * nested (more scopes) - pkg::parent1::parent2::name[4] + * [4] indicates the 4th scope within a procedure numbered in depth-first order + * file private - pkg::[file_name]::name + * Example: `pkg::[file.odin]::Type` + * polymorphic procedure/type - pkg::foo:TYPE + * naming convention for parameters + * type + * $typeid_based_name + * $$constant_parameter + * Example: `foo::to_thing:proc(u64)->([]u8)` + * nested decl in polymorphic procedure - pkg::foo:TYPE::name + * anonymous procedures - pkg::foo::$anon[file.odin:123] + * 123 is the file offset in bytes +*/ #define CANONICAL_TYPE_SEPARATOR ":" #define CANONICAL_NAME_SEPARATOR "::" -- cgit v1.2.3 From 90a973ccf6b3b42d8808e901c8a839183614f54d Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 20 Feb 2025 10:27:59 +0000 Subject: Make debug symbols use the new name canonicalization rules --- src/llvm_backend_debug.cpp | 29 +++++++++++++---------------- src/name_canonicalization.cpp | 22 ++++++++++++++++++---- 2 files changed, 31 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/src/llvm_backend_debug.cpp b/src/llvm_backend_debug.cpp index fbb25960a..067004bc1 100644 --- a/src/llvm_backend_debug.cpp +++ b/src/llvm_backend_debug.cpp @@ -843,7 +843,7 @@ gb_internal LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) { 8*cast(unsigned)type_align_of(type), lb_debug_type(m, type->EnumeratedArray.elem), subscripts, gb_count_of(subscripts)); - gbString name = type_to_string(type, temporary_allocator()); + gbString name = temp_canonical_string(type); return LLVMDIBuilderCreateTypedef(m->debug_builder, array_type, name, gb_string_length(name), nullptr, 0, nullptr, cast(u32)(8*type_align_of(type))); } @@ -852,16 +852,16 @@ gb_internal LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) { Type *bt = base_type(type->Map.debug_metadata_type); GB_ASSERT(bt->kind == Type_Struct); - return lb_debug_struct(m, type, bt, make_string_c(type_to_string(type, temporary_allocator())), nullptr, nullptr, 0); + return lb_debug_struct(m, type, bt, type_to_canonical_string(temporary_allocator(), type), nullptr, nullptr, 0); } - case Type_Struct: return lb_debug_struct( m, type, type, make_string_c(type_to_string(type, temporary_allocator())), nullptr, nullptr, 0); - case Type_Slice: return lb_debug_slice( m, type, make_string_c(type_to_string(type, temporary_allocator())), nullptr, nullptr, 0); - case Type_DynamicArray: return lb_debug_dynamic_array(m, type, make_string_c(type_to_string(type, temporary_allocator())), nullptr, nullptr, 0); - case Type_Union: return lb_debug_union( m, type, make_string_c(type_to_string(type, temporary_allocator())), nullptr, nullptr, 0); - case Type_BitSet: return lb_debug_bitset( m, type, make_string_c(type_to_string(type, temporary_allocator())), nullptr, nullptr, 0); - case Type_Enum: return lb_debug_enum( m, type, make_string_c(type_to_string(type, temporary_allocator())), nullptr, nullptr, 0); - case Type_BitField: return lb_debug_bitfield( m, type, make_string_c(type_to_string(type, temporary_allocator())), nullptr, nullptr, 0); + case Type_Struct: return lb_debug_struct( m, type, type, type_to_canonical_string(temporary_allocator(), type), nullptr, nullptr, 0); + case Type_Slice: return lb_debug_slice( m, type, type_to_canonical_string(temporary_allocator(), type), nullptr, nullptr, 0); + case Type_DynamicArray: return lb_debug_dynamic_array(m, type, type_to_canonical_string(temporary_allocator(), type), nullptr, nullptr, 0); + case Type_Union: return lb_debug_union( m, type, type_to_canonical_string(temporary_allocator(), type), nullptr, nullptr, 0); + case Type_BitSet: return lb_debug_bitset( m, type, type_to_canonical_string(temporary_allocator(), type), nullptr, nullptr, 0); + case Type_Enum: return lb_debug_enum( m, type, type_to_canonical_string(temporary_allocator(), type), nullptr, nullptr, 0); + case Type_BitField: return lb_debug_bitfield( m, type, type_to_canonical_string(temporary_allocator(), type), nullptr, nullptr, 0); case Type_Tuple: if (type->Tuple.variables.count == 1) { @@ -904,7 +904,7 @@ gb_internal LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) { { LLVMMetadataRef proc_underlying_type = lb_debug_type_internal_proc(m, type); LLVMMetadataRef pointer_type = LLVMDIBuilderCreatePointerType(m->debug_builder, proc_underlying_type, ptr_bits, ptr_bits, 0, nullptr, 0); - gbString name = type_to_string(type, temporary_allocator()); + gbString name = temp_canonical_string(type); return LLVMDIBuilderCreateTypedef(m->debug_builder, pointer_type, name, gb_string_length(name), nullptr, 0, nullptr, cast(u32)(8*type_align_of(type))); } break; @@ -987,10 +987,7 @@ gb_internal LLVMMetadataRef lb_debug_type(lbModule *m, Type *type) { line = cast(unsigned)e->token.pos.line; } - String name = type->Named.name; - if (type->Named.type_name && type->Named.type_name->pkg && type->Named.type_name->pkg->name.len != 0) { - name = concatenate3_strings(temporary_allocator(), type->Named.type_name->pkg->name, str_lit("."), type->Named.name); - } + String name = type_to_canonical_string(temporary_allocator(), type); Type *bt = base_type(type->Named.base); @@ -1187,8 +1184,8 @@ gb_internal void lb_add_debug_context_variable(lbProcedure *p, lbAddr const &ctx gb_internal String debug_info_mangle_constant_name(Entity *e, gbAllocator const &allocator, bool *did_allocate_) { String name = e->token.string; if (e->pkg && e->pkg->name.len > 0) { - // NOTE(bill): C++ NONSENSE FOR DEBUG SHITE! - name = concatenate3_strings(allocator, e->pkg->name, str_lit("::"), name); + gbString s = string_canonical_entity_name(allocator, e); + name = make_string(cast(u8 const *)s, gb_string_length(s)); if (did_allocate_) *did_allocate_ = true; } return name; diff --git a/src/name_canonicalization.cpp b/src/name_canonicalization.cpp index 043317ef0..548deb2cf 100644 --- a/src/name_canonicalization.cpp +++ b/src/name_canonicalization.cpp @@ -421,6 +421,8 @@ gb_internal void write_canonical_entity_name(TypeWriter *w, Entity *e) { return; } + bool write_scope_index_suffix = false; + if (e->scope->flags & (ScopeFlag_Builtin)) { goto write_base_name; } else if ((e->scope->flags & (ScopeFlag_File | ScopeFlag_Pkg)) == 0 || @@ -438,7 +440,7 @@ gb_internal void write_canonical_entity_name(TypeWriter *w, Entity *e) { Entity *parent = s->decl_info->entity; write_canonical_parent_prefix(w, parent); if (e->scope->index > 0) { - type_writer_append_fmt(w, CANONICAL_TYPE_SEPARATOR "[%d]", e->scope->index); + write_scope_index_suffix = true; } goto write_base_name; @@ -491,8 +493,11 @@ write_base_name: type_writer_append(w, e->token.string.text, e->token.string.len); } } - return; + break; + case Entity_Constant: + // For debug symbols only + /*fallthrough*/ case Entity_Procedure: case Entity_Variable: type_writer_append(w, e->token.string.text, e->token.string.len); @@ -500,12 +505,18 @@ write_base_name: type_writer_appendc(w, CANONICAL_TYPE_SEPARATOR); write_type_to_canonical_string(w, e->type); } - return; + break; default: GB_PANIC("TODO(bill): entity kind %d", e->kind); break; } + + if (write_scope_index_suffix) { + GB_ASSERT(e != nullptr && e->scope != nullptr); + type_writer_append_fmt(w, "[%d]", e->scope->index); + } + return; } @@ -661,7 +672,10 @@ gb_internal void write_type_to_canonical_string(TypeWriter *w, Type *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]; + String tag = {}; + if (type->Struct.tags != nullptr) { + tag = type->Struct.tags[i]; + } if (tag.len != 0) { String s = quote_to_ascii(heap_allocator(), tag); type_writer_append(w, s.text, s.len); -- cgit v1.2.3 From 0946f6b48bf829deea145f751a1beb6d7967cd58 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 20 Feb 2025 11:11:22 +0000 Subject: Improve name canonicalization for some debuggers --- src/name_canonicalization.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/name_canonicalization.cpp b/src/name_canonicalization.cpp index 548deb2cf..5d311068f 100644 --- a/src/name_canonicalization.cpp +++ b/src/name_canonicalization.cpp @@ -372,14 +372,14 @@ gb_internal void write_canonical_parent_prefix(TypeWriter *w, Entity *e) { if (e->pkg->name == "llvm") { type_writer_appendc(w, "$"); } - type_writer_append_fmt(w, CANONICAL_NAME_SEPARATOR "[%.*s]" CANONICAL_NAME_SEPARATOR, LIT(file_name)); + type_writer_append_fmt(w, CANONICAL_NAME_SEPARATOR "%.*s" CANONICAL_NAME_SEPARATOR, LIT(file_name)); } } else { GB_PANIC("TODO(bill): handle entity kind: %d", e->kind); } if (e->kind == Entity_Procedure && e->Procedure.is_anonymous) { String file_name = filename_without_directory(e->file->fullpath); - type_writer_append_fmt(w, CANONICAL_ANON_PREFIX "[%.*s:%d]", LIT(file_name), e->token.pos.offset); + type_writer_append_fmt(w, CANONICAL_ANON_PREFIX "_%.*s:%d", LIT(file_name), e->token.pos.offset); } else { type_writer_append(w, e->token.string.text, e->token.string.len); } @@ -514,7 +514,7 @@ write_base_name: if (write_scope_index_suffix) { GB_ASSERT(e != nullptr && e->scope != nullptr); - type_writer_append_fmt(w, "[%d]", e->scope->index); + type_writer_append_fmt(w, CANONICAL_NAME_SEPARATOR "$%d", e->scope->index); } return; -- cgit v1.2.3 From 0ab323012e4fd0303a7e41587a5919c9be028561 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 20 Feb 2025 11:12:59 +0000 Subject: Use `TypeSet` instead of `PtrSet` --- src/check_stmt.cpp | 8 ++++---- src/types.cpp | 34 ---------------------------------- 2 files changed, 4 insertions(+), 38 deletions(-) (limited to 'src') diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index 1708f7c81..e81996566 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -1446,8 +1446,8 @@ gb_internal void check_type_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_ Ast *nil_seen = nullptr; - PtrSet seen = {}; - defer (ptr_set_destroy(&seen)); + TypeSet seen = {}; + defer (type_set_destroy(&seen)); for (Ast *stmt : bs->stmts) { if (stmt->kind != Ast_CaseClause) { @@ -1515,7 +1515,7 @@ gb_internal void check_type_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_ GB_PANIC("Unknown type to type switch statement"); } - if (type_ptr_set_update(&seen, y.type)) { + if (type_set_update(&seen, y.type)) { TokenPos pos = cc->token.pos; gbString expr_str = expr_to_string(y.expr); error(y.expr, @@ -1569,7 +1569,7 @@ gb_internal void check_type_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_ auto unhandled = array_make(temporary_allocator(), 0, variants.count); for (Type *t : variants) { - if (!type_ptr_set_exists(&seen, t)) { + if (!type_set_exists(&seen, t)) { array_add(&unhandled, t); } } diff --git a/src/types.cpp b/src/types.cpp index 15e1bcf45..9b23fad0f 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -856,40 +856,6 @@ gb_internal void type_path_pop(TypePath *tp) { #define FAILURE_SIZE 0 #define FAILURE_ALIGNMENT 0 -gb_internal bool type_ptr_set_exists(PtrSet *s, Type *t); - -gb_internal bool type_ptr_set_update(PtrSet *s, Type *t) { - if (t == nullptr) { - return true; - } - if (type_ptr_set_exists(s, t)) { - return true; - } - ptr_set_add(s, t); - return false; -} - -gb_internal bool type_ptr_set_exists(PtrSet *s, Type *t) { - if (t == nullptr) { - return true; - } - - if (ptr_set_exists(s, t)) { - return true; - } - - // TODO(bill, 2019-10-05): This is very slow and it's probably a lot - // faster to cache types correctly - for (Type *f : *s) { - if (are_types_identical(t, f)) { - ptr_set_add(s, t); - return true; - } - } - - return false; -} - gb_internal Type *base_type(Type *t) { for (;;) { if (t == nullptr) { -- cgit v1.2.3 From 1d348318f216d28b8140c0f8dadf3a9607a52a9b Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 20 Feb 2025 13:23:23 +0000 Subject: Use `PtrMap` temporarily --- src/checker.cpp | 6 +++--- src/checker.hpp | 2 +- src/common.cpp | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/checker.cpp b/src/checker.cpp index f1f1b2556..678126094 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -1651,7 +1651,7 @@ gb_internal isize type_info_index(CheckerInfo *info, TypeInfoPair pair, bool err mutex_lock(&info->minimum_dependency_type_info_mutex); isize entry_index = -1; - uintptr hash = cast(uintptr)pair.hash; + u64 hash = pair.hash; isize *found_entry_index = map_get(&info->minimum_dependency_type_info_index_map, hash); if (found_entry_index) { entry_index = *found_entry_index; @@ -6744,12 +6744,12 @@ gb_internal void check_parsed_files(Checker *c) { for_array(i, c->info.type_info_types) { auto const &tt = c->info.type_info_types[i]; - bool exists = map_set_if_not_previously_exists(&c->info.minimum_dependency_type_info_index_map, cast(uintptr)tt.hash, i); + bool exists = map_set_if_not_previously_exists(&c->info.minimum_dependency_type_info_index_map, tt.hash, i); if (!exists) { continue; } for (auto const &entry : c->info.minimum_dependency_type_info_index_map) { - if (entry.key != cast(uintptr)tt.hash) { + if (entry.key != tt.hash) { continue; } auto const &other = c->info.type_info_types[entry.value]; diff --git a/src/checker.hpp b/src/checker.hpp index c89a1bc9c..3d1e5b6eb 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -429,7 +429,7 @@ struct CheckerInfo { Entity * entry_point; PtrSet minimum_dependency_set; BlockingMutex minimum_dependency_type_info_mutex; - PtrMap minimum_dependency_type_info_index_map; + PtrMap minimum_dependency_type_info_index_map; TypeSet min_dep_type_info_set; Array type_info_types; // sorted after filled diff --git a/src/common.cpp b/src/common.cpp index ad1e5a851..77a82a171 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -387,7 +387,7 @@ gb_global Arena string_intern_arena = {}; gb_internal char const *string_intern(char const *text, isize len) { u64 hash = gb_fnv64a(text, len); - uintptr key = cast(uintptr)(hash ? hash : 1); + u64 key = hash ? hash : 1; StringIntern **found = map_get(&string_intern_map, key); if (found) { for (StringIntern *it = *found; it != nullptr; it = it->next) { -- cgit v1.2.3 From c25ac939d4bd86d51c383e96232da1d241c6a504 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 20 Feb 2025 13:27:18 +0000 Subject: Add `cast` back --- src/common.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/common.cpp b/src/common.cpp index 77a82a171..ad1e5a851 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -387,7 +387,7 @@ gb_global Arena string_intern_arena = {}; gb_internal char const *string_intern(char const *text, isize len) { u64 hash = gb_fnv64a(text, len); - u64 key = hash ? hash : 1; + uintptr key = cast(uintptr)(hash ? hash : 1); StringIntern **found = map_get(&string_intern_map, key); if (found) { for (StringIntern *it = *found; it != nullptr; it = it->next) { -- cgit v1.2.3 From 5489a889832ac05e5edca7355b4601c1a82c2d27 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 20 Feb 2025 14:10:45 +0000 Subject: Change `typeid` definition to be based around the canonical type hash `typeid` used to be a fancy index with extra metadata stored on it. Now it is direct hash of the type. This is safe to do in practice since any possible collisions are checked at compile time AND the chances of having a 1% collision are around 1 in 600K (see the Birthday Paradox). Therefore accessing a `^Type_Info` is now a hash table lookup with linear probing. The table is twice the size than necessary so prevent too much probing due to an overly dense hash table. --- base/runtime/core.odin | 56 ++++++++-------------------------------------- odin.rdi | Bin 6593532 -> 0 bytes src/checker.cpp | 45 ++++++++++++++++++++++++------------- src/checker.hpp | 1 + src/llvm_backend.cpp | 5 +++-- src/llvm_backend_type.cpp | 52 ++++++++++++------------------------------ src/types.cpp | 16 ++++++------- 7 files changed, 64 insertions(+), 111 deletions(-) delete mode 100644 odin.rdi (limited to 'src') diff --git a/base/runtime/core.odin b/base/runtime/core.odin index e47f3ecbc..94a126082 100644 --- a/base/runtime/core.odin +++ b/base/runtime/core.odin @@ -239,47 +239,6 @@ Type_Info :: struct { }, } -// NOTE(bill): This must match the compiler's -Typeid_Kind :: enum u8 { - Invalid, - Integer, - Rune, - Float, - Complex, - Quaternion, - String, - Boolean, - Any, - Type_Id, - Pointer, - Multi_Pointer, - Procedure, - Array, - Enumerated_Array, - Dynamic_Array, - Slice, - Tuple, - Struct, - Union, - Enum, - Map, - Bit_Set, - Simd_Vector, - Matrix, - Soa_Pointer, - Bit_Field, -} -#assert(len(Typeid_Kind) < 32) - -Typeid_Bit_Field :: bit_field uintptr { - index: uintptr | 8*size_of(uintptr) - 8, - kind: Typeid_Kind | 5, // Typeid_Kind - named: bool | 1, - special: bool | 1, // signed, cstring, etc - reserved: bool | 1, -} -#assert(size_of(Typeid_Bit_Field) == size_of(uintptr)) - // NOTE(bill): only the ones that are needed (not all types) // This will be set by the compiler type_table: []^Type_Info @@ -686,13 +645,16 @@ type_info_core :: proc "contextless" (info: ^Type_Info) -> ^Type_Info { type_info_base_without_enum :: type_info_core __type_info_of :: proc "contextless" (id: typeid) -> ^Type_Info #no_bounds_check { - MASK :: 1<<(8*size_of(typeid) - 8) - 1 - data := transmute(uintptr)id - n := int(data & MASK) - if n < 0 || n >= len(type_table) { - n = 0 + n := u64(len(type_table)) + i := transmute(u64)id % n + for k in 0..info.type_info_types, type_info_pair_cmp); + array_init(&c->info.type_info_types_hash_map, heap_allocator(), c->info.type_info_types.count*2 + 1); map_reserve(&c->info.minimum_dependency_type_info_index_map, c->info.type_info_types.count); - for_array(i, c->info.type_info_types) { - auto const &tt = c->info.type_info_types[i]; - bool exists = map_set_if_not_previously_exists(&c->info.minimum_dependency_type_info_index_map, tt.hash, i); - if (!exists) { - continue; - } - for (auto const &entry : c->info.minimum_dependency_type_info_index_map) { - if (entry.key != tt.hash) { + isize hash_map_len = c->info.type_info_types_hash_map.count; + for (auto const &tt : c->info.type_info_types) { + isize index = tt.hash % hash_map_len; + // NOTE(bill): no need for a sanity check since there + // will always be enough space for the entries + for (;;) { + if (index == 0 || c->info.type_info_types_hash_map[index].hash != 0) { + index = (index+1) % hash_map_len; continue; } - auto const &other = c->info.type_info_types[entry.value]; - if (are_types_identical_unique_tuples(tt.type, other.type)) { - continue; + break; + } + c->info.type_info_types_hash_map[index] = tt; + + bool exists = map_set_if_not_previously_exists(&c->info.minimum_dependency_type_info_index_map, tt.hash, index); + if (exists) { + for (auto const &entry : c->info.minimum_dependency_type_info_index_map) { + if (entry.key != tt.hash) { + continue; + } + auto const &other = c->info.type_info_types[entry.value]; + if (are_types_identical_unique_tuples(tt.type, other.type)) { + continue; + } + gbString t = temp_canonical_string(tt.type); + gbString o = temp_canonical_string(other.type); + GB_PANIC("%s (%s) %llu vs %s (%s) %llu", + type_to_string(tt.type, false), t, cast(unsigned long long)tt.hash, + type_to_string(other.type, false), o, cast(unsigned long long)other.hash); } - gbString t = temp_canonical_string(tt.type); - gbString o = temp_canonical_string(other.type); - GB_PANIC("%s (%s) %llu vs %s (%s) %llu", - type_to_string(tt.type, false), t, cast(unsigned long long)tt.hash, - type_to_string(other.type, false), o, cast(unsigned long long)other.hash); } } + GB_ASSERT(c->info.minimum_dependency_type_info_index_map.count <= c->info.type_info_types.count); } diff --git a/src/checker.hpp b/src/checker.hpp index 3d1e5b6eb..d482f396c 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -432,6 +432,7 @@ struct CheckerInfo { PtrMap minimum_dependency_type_info_index_map; TypeSet min_dep_type_info_set; Array type_info_types; // sorted after filled + Array type_info_types_hash_map; // 2 * type_info_types.count Array testing_procedures; diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 908117501..4ebcf7578 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -3154,9 +3154,10 @@ gb_internal bool lb_generate_code(lbGenerator *gen) { lbModule *m = default_module; { // Add type info data - GB_ASSERT_MSG(info->minimum_dependency_type_info_index_map.count == info->type_info_types.count, "%tu vs %tu", info->minimum_dependency_type_info_index_map.count, info->type_info_types.count); + // GB_ASSERT_MSG(info->minimum_dependency_type_info_index_map.count == info->type_info_types.count, "%tu vs %tu", info->minimum_dependency_type_info_index_map.count, info->type_info_types.count); - isize max_type_info_count = info->minimum_dependency_type_info_index_map.count+1; + // isize max_type_info_count = info->minimum_dependency_type_info_index_map.count+1; + isize max_type_info_count = info->type_info_types_hash_map.count; Type *t = alloc_type_array(t_type_info_ptr, max_type_info_count); // IMPORTANT NOTE(bill): As LLVM does not have a union type, an array of unions cannot be initialized diff --git a/src/llvm_backend_type.cpp b/src/llvm_backend_type.cpp index 8e0f15f35..170da5b2b 100644 --- a/src/llvm_backend_type.cpp +++ b/src/llvm_backend_type.cpp @@ -2,13 +2,13 @@ gb_internal isize lb_type_info_index(CheckerInfo *info, TypeInfoPair pair, bool err_on_not_found=true) { isize index = type_info_index(info, pair, err_on_not_found); if (index >= 0) { - return index+1; + return index; } if (err_on_not_found) { gb_printf_err("NOT FOUND lb_type_info_index:\n\t%s\n\t@ index %td\n\tmax count: %u\nFound:\n", type_to_string(pair.type), index, info->minimum_dependency_type_info_index_map.count); for (auto const &entry : info->minimum_dependency_type_info_index_map) { isize type_info_index = entry.key; - gb_printf_err("\t%s\n", type_to_string(info->type_info_types[type_info_index].type)); + gb_printf_err("\t%s\n", type_to_string(info->type_info_types_hash_map[type_info_index].type)); } GB_PANIC("NOT FOUND"); } @@ -73,37 +73,8 @@ gb_internal lbValue lb_typeid(lbModule *m, Type *type) { type = default_type(type); - u64 id = cast(u64)lb_type_info_index(m->info, type); - GB_ASSERT(id >= 0); - - u64 kind = lb_typeid_kind(m, type, id); - u64 named = is_type_named(type) && type->kind != Type_Basic; - u64 special = 0; - u64 reserved = 0; - - if (is_type_cstring(type)) { - special = 1; - } else if (is_type_integer(type) && !is_type_unsigned(type)) { - special = 1; - } - - u64 data = 0; - if (build_context.ptr_size == 4) { - GB_ASSERT(id <= (1u<<24u)); - data |= (id &~ (1u<<24)) << 0u; // index - data |= (kind &~ (1u<<5)) << 24u; // kind - data |= (named &~ (1u<<1)) << 29u; // named - data |= (special &~ (1u<<1)) << 30u; // special - data |= (reserved &~ (1u<<1)) << 31u; // reserved - } else { - GB_ASSERT(build_context.ptr_size == 8); - GB_ASSERT(id <= (1ull<<56u)); - data |= (id &~ (1ull<<56)) << 0ul; // index - data |= (kind &~ (1ull<<5)) << 56ull; // kind - data |= (named &~ (1ull<<1)) << 61ull; // named - data |= (special &~ (1ull<<1)) << 62ull; // special - data |= (reserved &~ (1ull<<1)) << 63ull; // reserved - } + u64 data = type_hash_canonical_type(type); + GB_ASSERT(data != 0); lbValue res = {}; res.value = LLVMConstInt(lb_type(m, t_typeid), data, false); @@ -279,8 +250,8 @@ 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) { - auto const &tt = info->type_info_types[type_info_type_index]; + for_array(type_info_type_index, info->type_info_types_hash_map) { + auto const &tt = info->type_info_types_hash_map[type_info_type_index]; Type *t = tt.type; if (t == nullptr || t == t_invalid) { continue; @@ -343,8 +314,8 @@ gb_internal void lb_setup_type_info_data_giant_array(lbModule *m, i64 global_typ return giant_const_values[index]; }; - for_array(type_info_type_index, info->type_info_types) { - Type *t = info->type_info_types[type_info_type_index].type; + for_array(type_info_type_index, info->type_info_types_hash_map) { + Type *t = info->type_info_types_hash_map[type_info_type_index].type; if (t == nullptr || t == t_invalid) { continue; } @@ -1072,7 +1043,12 @@ gb_internal void lb_setup_type_info_data_giant_array(lbModule *m, i64 global_typ LLVMSetInitializer(giant_const_values[entry_index], LLVMConstNamedStruct(stype, small_const_values, variant_index+1)); } for (isize i = 0; i < global_type_info_data_entity_count; i++) { - giant_const_values[i] = LLVMConstPointerCast(giant_const_values[i], lb_type(m, t_type_info_ptr)); + auto *ptr = &giant_const_values[i]; + if (*ptr != nullptr) { + *ptr = LLVMConstPointerCast(*ptr, lb_type(m, t_type_info_ptr)); + } else { + *ptr = LLVMConstNull(lb_type(m, t_type_info_ptr)); + } } diff --git a/src/types.cpp b/src/types.cpp index 9b23fad0f..fedb85230 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -503,9 +503,9 @@ gb_global Type basic_types[] = { {Type_Basic, {Basic_rawptr, BasicFlag_Pointer, -1, STR_LIT("rawptr")}}, {Type_Basic, {Basic_string, BasicFlag_String, -1, STR_LIT("string")}}, {Type_Basic, {Basic_cstring, BasicFlag_String, -1, STR_LIT("cstring")}}, - {Type_Basic, {Basic_any, 0, -1, STR_LIT("any")}}, + {Type_Basic, {Basic_any, 0, 16, STR_LIT("any")}}, - {Type_Basic, {Basic_typeid, 0, -1, STR_LIT("typeid")}}, + {Type_Basic, {Basic_typeid, 0, 8, STR_LIT("typeid")}}, // Endian {Type_Basic, {Basic_i16le, BasicFlag_Integer | BasicFlag_EndianLittle, 2, STR_LIT("i16le")}}, @@ -3700,7 +3700,7 @@ gb_internal i64 type_size_of(Type *t) { switch (t->Basic.kind) { case Basic_string: size = 2*build_context.int_size; break; case Basic_cstring: size = build_context.ptr_size; break; - case Basic_any: size = 2*build_context.ptr_size; break; + case Basic_any: size = 16; break; case Basic_typeid: size = build_context.ptr_size; break; case Basic_int: case Basic_uint: @@ -3763,7 +3763,7 @@ gb_internal i64 type_align_of_internal(Type *t, TypePath *path) { switch (t->Basic.kind) { case Basic_string: return build_context.int_size; case Basic_cstring: return build_context.ptr_size; - case Basic_any: return build_context.ptr_size; + case Basic_any: return 8; case Basic_typeid: return build_context.ptr_size; case Basic_int: case Basic_uint: @@ -4014,7 +4014,7 @@ gb_internal i64 type_size_of_internal(Type *t, TypePath *path) { switch (kind) { case Basic_string: return 2*build_context.int_size; case Basic_cstring: return build_context.ptr_size; - case Basic_any: return 2*build_context.ptr_size; + case Basic_any: return 16; case Basic_typeid: return build_context.ptr_size; case Basic_int: case Basic_uint: @@ -4251,7 +4251,7 @@ gb_internal i64 type_offset_of(Type *t, i64 index, Type **field_type_) { return 0; // data case 1: if (field_type_) *field_type_ = t_typeid; - return build_context.ptr_size; // id + return 8; // id } } break; @@ -4322,8 +4322,8 @@ gb_internal i64 type_offset_of_from_selection(Type *type, Selection sel) { } } else if (t->Basic.kind == Basic_any) { switch (index) { - case 0: t = t_type_info_ptr; break; - case 1: t = t_rawptr; break; + case 0: t = t_rawptr; break; + case 1: t = t_typeid; break; } } break; -- cgit v1.2.3 From 614c0dd7401271f7ddad5eaeb4de234021fe387c Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 20 Feb 2025 17:09:28 +0000 Subject: Fix `typeid` size for 32-bit platforms --- base/runtime/core.odin | 2 ++ src/types.cpp | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/base/runtime/core.odin b/base/runtime/core.odin index 285883c2b..db5e4d698 100644 --- a/base/runtime/core.odin +++ b/base/runtime/core.odin @@ -442,10 +442,12 @@ Raw_Any :: struct { data: rawptr, id: typeid, } +#assert(size_of(Raw_Any) == size_of(any)) Raw_Cstring :: struct { data: [^]byte, } +#assert(size_of(Raw_Cstring) == size_of(cstring)) Raw_Soa_Pointer :: struct { data: rawptr, diff --git a/src/types.cpp b/src/types.cpp index fedb85230..056737af5 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -3701,7 +3701,7 @@ gb_internal i64 type_size_of(Type *t) { case Basic_string: size = 2*build_context.int_size; break; case Basic_cstring: size = build_context.ptr_size; break; case Basic_any: size = 16; break; - case Basic_typeid: size = build_context.ptr_size; break; + case Basic_typeid: size = 8; break; case Basic_int: case Basic_uint: size = build_context.int_size; @@ -3764,7 +3764,7 @@ gb_internal i64 type_align_of_internal(Type *t, TypePath *path) { case Basic_string: return build_context.int_size; case Basic_cstring: return build_context.ptr_size; case Basic_any: return 8; - case Basic_typeid: return build_context.ptr_size; + case Basic_typeid: return 8; case Basic_int: case Basic_uint: return build_context.int_size; @@ -4015,7 +4015,7 @@ gb_internal i64 type_size_of_internal(Type *t, TypePath *path) { case Basic_string: return 2*build_context.int_size; case Basic_cstring: return build_context.ptr_size; case Basic_any: return 16; - case Basic_typeid: return build_context.ptr_size; + case Basic_typeid: return 8; case Basic_int: case Basic_uint: return build_context.int_size; -- 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') 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') 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 266e84103ef92464e6f31dda91f3aa6587d8efea Mon Sep 17 00:00:00 2001 From: Barinzaya Date: Thu, 20 Feb 2025 17:05:07 -0500 Subject: Fixed an issue with SIMD vector equality. Comparing SIMD vectors with `==` was checking that the mask of elements that matched was not 0, meaning it succeeded if *any* element was equal, rather than if *all* elements were equal. --- src/llvm_backend_expr.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 693f2e225..9e115b9ca 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -3004,7 +3004,16 @@ gb_internal lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left LLVMTypeRef mask_int_type = LLVMIntTypeInContext(p->module->ctx, cast(unsigned)(8*type_size_of(a))); LLVMValueRef mask_int = LLVMBuildBitCast(p->builder, mask, mask_int_type, ""); - res.value = LLVMBuildICmp(p->builder, LLVMIntNE, mask_int, LLVMConstNull(LLVMTypeOf(mask_int)), ""); + + switch (op_kind) { + case Token_CmpEq: + res.value = LLVMBuildICmp(p->builder, LLVMIntEQ, mask_int, LLVMConstInt(mask_int_type, U64_MAX, true), ""); + break; + case Token_NotEq: + res.value = LLVMBuildICmp(p->builder, LLVMIntNE, mask_int, LLVMConstNull(mask_int_type), ""); + break; + } + return res; } else { -- cgit v1.2.3 From 748a771dad72c912b48ad2601e459078c7fd1db7 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 21 Feb 2025 12:38:40 +0000 Subject: Allow indirection for swizzling on procedure parameters --- src/check_expr.cpp | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index f0021e67f..bd1c34044 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -5509,6 +5509,11 @@ gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *nod case Addressing_SwizzleVariable: operand->mode = Addressing_SwizzleVariable; break; + case Addressing_Value: + if (is_type_pointer(original_type)) { + operand->mode = Addressing_SwizzleVariable; + } + break; } if (array_type->kind == Type_SimdVector) { -- cgit v1.2.3 From 5bd43b94ec9bf70194ebe7c15bc51a93d135d51d Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 22 Feb 2025 17:50:37 +0000 Subject: Improve error message for matrices with no rows or columns --- src/check_type.cpp | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/check_type.cpp b/src/check_type.cpp index 4d9101c6c..9d4defbb2 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -2859,15 +2859,23 @@ gb_internal void check_matrix_type(CheckerContext *ctx, Type **type, Ast *node) } if (generic_row == nullptr && row_count < MATRIX_ELEMENT_COUNT_MIN) { - gbString s = expr_to_string(row.expr); - error(row.expr, "Invalid matrix row count, expected %d+ rows, got %s", MATRIX_ELEMENT_COUNT_MIN, s); - gb_string_free(s); + if (row.expr == nullptr) { + error(node, "Invalid matrix row count, got nothing"); + } else { + gbString s = expr_to_string(row.expr); + error(row.expr, "Invalid matrix row count, expected %d+ rows, got %s", MATRIX_ELEMENT_COUNT_MIN, s); + gb_string_free(s); + } } if (generic_column == nullptr && column_count < MATRIX_ELEMENT_COUNT_MIN) { - gbString s = expr_to_string(column.expr); - error(column.expr, "Invalid matrix column count, expected %d+ rows, got %s", MATRIX_ELEMENT_COUNT_MIN, s); - gb_string_free(s); + if (column.expr == nullptr) { + error(node, "Invalid matrix column count, got nothing"); + } else { + gbString s = expr_to_string(column.expr); + error(column.expr, "Invalid matrix column count, expected %d+ rows, got %s", MATRIX_ELEMENT_COUNT_MIN, s); + gb_string_free(s); + } } if ((generic_row == nullptr && generic_column == nullptr) && row_count*column_count > MATRIX_ELEMENT_COUNT_MAX) { -- cgit v1.2.3 From 875dbf3140935d43bd996443fbe5bb05a5044395 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 22 Feb 2025 17:56:42 +0000 Subject: Disallow syntax: `proc(x,:T)` --- src/parser.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/parser.cpp b/src/parser.cpp index 94f8fd42c..a3e95f451 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -4343,6 +4343,9 @@ gb_internal Ast *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_fl if (f->curr_token.kind == Token_Colon) { + if (f->prev_token.kind == Token_Comma) { + syntax_error(f->prev_token, "Trailing comma before a colon is not allowed"); + } Array names = convert_to_ident_list(f, list, true, allow_poly_names); // Copy for semantic reasons if (names.count == 0) { syntax_error(f->curr_token, "Empty field declaration"); -- cgit v1.2.3 From de755f95ecd5574f291d03b9488b5c4b8f07042c Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 22 Feb 2025 17:58:14 +0000 Subject: Minor rearrange for parsing field lists --- src/parser.cpp | 229 +++++++++++++++++++++++++++++---------------------------- 1 file changed, 116 insertions(+), 113 deletions(-) (limited to 'src') diff --git a/src/parser.cpp b/src/parser.cpp index a3e95f451..f09590a55 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -4342,33 +4342,132 @@ gb_internal Ast *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_fl } - if (f->curr_token.kind == Token_Colon) { - if (f->prev_token.kind == Token_Comma) { - syntax_error(f->prev_token, "Trailing comma before a colon is not allowed"); + if (f->curr_token.kind != Token_Colon) { + // NOTE(bill): proc(Type, Type, Type) + for (AstAndFlags const &item : list) { + Ast *type = item.node; + Token token = blank_token; + if (allowed_flags&FieldFlag_Results) { + // NOTE(bill): Make this nothing and not `_` + token.string = str_lit(""); + } + + auto names = array_make(ast_allocator(f), 1); + token.pos = ast_token(type).pos; + names[0] = ast_ident(f, token); + u32 flags = check_field_prefixes(f, list.count, allowed_flags, item.flags); + Token tag = {}; + Ast *param = ast_field(f, names, item.node, nullptr, flags, tag, docs, f->line_comment); + array_add(¶ms, param); + } + + if (name_count_) *name_count_ = total_name_count; + return ast_field_list(f, start_token, params); + } + + // NOTE(bill): proc(ident, ident, ident: Type) + + if (f->prev_token.kind == Token_Comma) { + syntax_error(f->prev_token, "Trailing comma before a colon is not allowed"); + } + Array names = convert_to_ident_list(f, list, true, allow_poly_names); // Copy for semantic reasons + if (names.count == 0) { + syntax_error(f->curr_token, "Empty field declaration"); + } + bool any_polymorphic_names = check_procedure_name_list(names); + u32 set_flags = 0; + if (list.count > 0) { + set_flags = list[0].flags; + } + set_flags = check_field_prefixes(f, names.count, allowed_flags, set_flags); + total_name_count += names.count; + + Ast *type = nullptr; + Ast *default_value = nullptr; + Token tag = {}; + + expect_token_after(f, Token_Colon, "field list"); + if (f->curr_token.kind != Token_Eq) { + type = parse_var_type(f, allow_ellipsis, allow_typeid_token); + Ast *tt = unparen_expr(type); + if (tt == nullptr) { + syntax_error(f->prev_token, "Invalid type expression in field list"); + } else if (is_signature && !any_polymorphic_names && tt->kind == Ast_TypeidType && tt->TypeidType.specialization != nullptr) { + syntax_error(type, "Specialization of typeid is not allowed without polymorphic names"); + } + } + + if (allow_token(f, Token_Eq)) { + default_value = parse_expr(f, false); + if (!allow_default_parameters) { + syntax_error(f->curr_token, "Default parameters are only allowed for procedures"); + default_value = nullptr; + } + } + + if (default_value != nullptr && names.count > 1) { + syntax_error(f->curr_token, "Default parameters can only be applied to single values"); + } + + if (allowed_flags == FieldFlag_Struct && default_value != nullptr) { + syntax_error(default_value, "Default parameters are not allowed for structs"); + default_value = nullptr; + } + + if (type != nullptr && type->kind == Ast_Ellipsis) { + if (seen_ellipsis) syntax_error(type, "Extra variadic parameter after ellipsis"); + seen_ellipsis = true; + if (names.count != 1) { + syntax_error(type, "Variadic parameters can only have one field name"); } - Array names = convert_to_ident_list(f, list, true, allow_poly_names); // Copy for semantic reasons + } else if (seen_ellipsis && default_value == nullptr) { + syntax_error(f->curr_token, "Extra parameter after ellipsis without a default value"); + } + + if (type != nullptr && default_value == nullptr) { + if (f->curr_token.kind == Token_String) { + tag = expect_token(f, Token_String); + if ((allowed_flags & FieldFlag_Tags) == 0) { + syntax_error(tag, "Field tags are only allowed within structures"); + } + } + } + + bool more_fields = allow_field_separator(f); + Ast *param = ast_field(f, names, type, default_value, set_flags, tag, docs, f->line_comment); + array_add(¶ms, param); + + if (!more_fields) { + if (name_count_) *name_count_ = total_name_count; + return ast_field_list(f, start_token, params); + } + + while (f->curr_token.kind != follow && + f->curr_token.kind != Token_EOF && + f->curr_token.kind != Token_Semicolon) { + CommentGroup *docs = f->lead_comment; + + if (!is_signature) parse_enforce_tabs(f); + u32 set_flags = parse_field_prefixes(f); + Token tag = {}; + Array names = parse_ident_list(f, allow_poly_names); if (names.count == 0) { syntax_error(f->curr_token, "Empty field declaration"); + break; } bool any_polymorphic_names = check_procedure_name_list(names); - u32 set_flags = 0; - if (list.count > 0) { - set_flags = list[0].flags; - } set_flags = check_field_prefixes(f, names.count, allowed_flags, set_flags); total_name_count += names.count; Ast *type = nullptr; Ast *default_value = nullptr; - Token tag = {}; - expect_token_after(f, Token_Colon, "field list"); if (f->curr_token.kind != Token_Eq) { type = parse_var_type(f, allow_ellipsis, allow_typeid_token); Ast *tt = unparen_expr(type); - if (tt == nullptr) { - syntax_error(f->prev_token, "Invalid type expression in field list"); - } else if (is_signature && !any_polymorphic_names && tt->kind == Ast_TypeidType && tt->TypeidType.specialization != nullptr) { + if (is_signature && !any_polymorphic_names && + tt != nullptr && + tt->kind == Ast_TypeidType && tt->TypeidType.specialization != nullptr) { syntax_error(type, "Specialization of typeid is not allowed without polymorphic names"); } } @@ -4385,11 +4484,6 @@ gb_internal Ast *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_fl syntax_error(f->curr_token, "Default parameters can only be applied to single values"); } - if (allowed_flags == FieldFlag_Struct && default_value != nullptr) { - syntax_error(default_value, "Default parameters are not allowed for structs"); - default_value = nullptr; - } - if (type != nullptr && type->kind == Ast_Ellipsis) { if (seen_ellipsis) syntax_error(type, "Extra variadic parameter after ellipsis"); seen_ellipsis = true; @@ -4409,105 +4503,14 @@ gb_internal Ast *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_fl } } - bool more_fields = allow_field_separator(f); + + bool ok = allow_field_separator(f); Ast *param = ast_field(f, names, type, default_value, set_flags, tag, docs, f->line_comment); array_add(¶ms, param); - if (!more_fields) { - if (name_count_) *name_count_ = total_name_count; - return ast_field_list(f, start_token, params); - } - - while (f->curr_token.kind != follow && - f->curr_token.kind != Token_EOF && - f->curr_token.kind != Token_Semicolon) { - CommentGroup *docs = f->lead_comment; - - if (!is_signature) parse_enforce_tabs(f); - u32 set_flags = parse_field_prefixes(f); - Token tag = {}; - Array names = parse_ident_list(f, allow_poly_names); - if (names.count == 0) { - syntax_error(f->curr_token, "Empty field declaration"); - break; - } - bool any_polymorphic_names = check_procedure_name_list(names); - set_flags = check_field_prefixes(f, names.count, allowed_flags, set_flags); - total_name_count += names.count; - - Ast *type = nullptr; - Ast *default_value = nullptr; - expect_token_after(f, Token_Colon, "field list"); - if (f->curr_token.kind != Token_Eq) { - type = parse_var_type(f, allow_ellipsis, allow_typeid_token); - Ast *tt = unparen_expr(type); - if (is_signature && !any_polymorphic_names && - tt != nullptr && - tt->kind == Ast_TypeidType && tt->TypeidType.specialization != nullptr) { - syntax_error(type, "Specialization of typeid is not allowed without polymorphic names"); - } - } - - if (allow_token(f, Token_Eq)) { - default_value = parse_expr(f, false); - if (!allow_default_parameters) { - syntax_error(f->curr_token, "Default parameters are only allowed for procedures"); - default_value = nullptr; - } - } - - if (default_value != nullptr && names.count > 1) { - syntax_error(f->curr_token, "Default parameters can only be applied to single values"); - } - - if (type != nullptr && type->kind == Ast_Ellipsis) { - if (seen_ellipsis) syntax_error(type, "Extra variadic parameter after ellipsis"); - seen_ellipsis = true; - if (names.count != 1) { - syntax_error(type, "Variadic parameters can only have one field name"); - } - } else if (seen_ellipsis && default_value == nullptr) { - syntax_error(f->curr_token, "Extra parameter after ellipsis without a default value"); - } - - if (type != nullptr && default_value == nullptr) { - if (f->curr_token.kind == Token_String) { - tag = expect_token(f, Token_String); - if ((allowed_flags & FieldFlag_Tags) == 0) { - syntax_error(tag, "Field tags are only allowed within structures"); - } - } - } - - - bool ok = allow_field_separator(f); - Ast *param = ast_field(f, names, type, default_value, set_flags, tag, docs, f->line_comment); - array_add(¶ms, param); - - if (!ok) { - break; - } - } - - if (name_count_) *name_count_ = total_name_count; - return ast_field_list(f, start_token, params); - } - - for (AstAndFlags const &item : list) { - Ast *type = item.node; - Token token = blank_token; - if (allowed_flags&FieldFlag_Results) { - // NOTE(bill): Make this nothing and not `_` - token.string = str_lit(""); + if (!ok) { + break; } - - auto names = array_make(ast_allocator(f), 1); - token.pos = ast_token(type).pos; - names[0] = ast_ident(f, token); - u32 flags = check_field_prefixes(f, list.count, allowed_flags, item.flags); - Token tag = {}; - Ast *param = ast_field(f, names, item.node, nullptr, flags, tag, docs, f->line_comment); - array_add(¶ms, param); } if (name_count_) *name_count_ = total_name_count; -- cgit v1.2.3 From ebda946d61d4b7447348afeccd16a6e5786fa91b Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 22 Feb 2025 18:12:43 +0000 Subject: Move temporary array out of `CheckerInfo` --- src/checker.cpp | 30 ++++++++++++++++-------------- src/checker.hpp | 5 ++--- src/llvm_backend.cpp | 5 ++++- src/llvm_backend_type.cpp | 4 ++-- 4 files changed, 24 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/src/checker.cpp b/src/checker.cpp index 056eef3b2..bee3f1efe 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -1372,9 +1372,8 @@ gb_internal void init_checker_info(CheckerInfo *i) { // map_init(&i->gen_procs); map_init(&i->gen_types); - array_init(&i->type_info_types, a); type_set_init(&i->min_dep_type_info_set); - map_init(&i->minimum_dependency_type_info_index_map); + map_init(&i->min_dep_type_info_index_map); // map_init(&i->type_info_map); string_map_init(&i->files); @@ -1410,9 +1409,8 @@ gb_internal void destroy_checker_info(CheckerInfo *i) { // map_destroy(&i->gen_procs); map_destroy(&i->gen_types); - array_free(&i->type_info_types); type_set_destroy(&i->min_dep_type_info_set); - map_destroy(&i->minimum_dependency_type_info_index_map); + map_destroy(&i->min_dep_type_info_index_map); string_map_destroy(&i->files); string_map_destroy(&i->packages); @@ -1652,7 +1650,7 @@ gb_internal isize type_info_index(CheckerInfo *info, TypeInfoPair pair, bool err isize entry_index = -1; u64 hash = pair.hash; - isize *found_entry_index = map_get(&info->minimum_dependency_type_info_index_map, hash); + isize *found_entry_index = map_get(&info->min_dep_type_info_index_map, hash); if (found_entry_index) { entry_index = *found_entry_index; } @@ -6735,16 +6733,20 @@ gb_internal void check_parsed_files(Checker *c) { TIME_SECTION("initialize and check for collisions in type info array"); { + Array type_info_types; // sorted after filled + array_init(&type_info_types, heap_allocator()); + defer (array_free(&type_info_types)); + for (auto const &tt : c->info.min_dep_type_info_set) { - array_add(&c->info.type_info_types, tt); + array_add(&type_info_types, tt); } - array_sort(c->info.type_info_types, type_info_pair_cmp); + array_sort(type_info_types, type_info_pair_cmp); - array_init(&c->info.type_info_types_hash_map, heap_allocator(), c->info.type_info_types.count*2 + 1); - map_reserve(&c->info.minimum_dependency_type_info_index_map, c->info.type_info_types.count); + array_init(&c->info.type_info_types_hash_map, heap_allocator(), type_info_types.count*2 + 1); + map_reserve(&c->info.min_dep_type_info_index_map, type_info_types.count); isize hash_map_len = c->info.type_info_types_hash_map.count; - for (auto const &tt : c->info.type_info_types) { + for (auto const &tt : type_info_types) { isize index = tt.hash % hash_map_len; // NOTE(bill): no need for a sanity check since there // will always be enough space for the entries @@ -6757,13 +6759,13 @@ gb_internal void check_parsed_files(Checker *c) { } c->info.type_info_types_hash_map[index] = tt; - bool exists = map_set_if_not_previously_exists(&c->info.minimum_dependency_type_info_index_map, tt.hash, index); + bool exists = map_set_if_not_previously_exists(&c->info.min_dep_type_info_index_map, tt.hash, index); if (exists) { - for (auto const &entry : c->info.minimum_dependency_type_info_index_map) { + for (auto const &entry : c->info.min_dep_type_info_index_map) { if (entry.key != tt.hash) { continue; } - auto const &other = c->info.type_info_types[entry.value]; + auto const &other = type_info_types[entry.value]; if (are_types_identical_unique_tuples(tt.type, other.type)) { continue; } @@ -6777,7 +6779,7 @@ gb_internal void check_parsed_files(Checker *c) { } - GB_ASSERT(c->info.minimum_dependency_type_info_index_map.count <= c->info.type_info_types.count); + GB_ASSERT(c->info.min_dep_type_info_index_map.count <= type_info_types.count); } diff --git a/src/checker.hpp b/src/checker.hpp index d482f396c..d3b2d7d89 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -429,9 +429,8 @@ struct CheckerInfo { Entity * entry_point; PtrSet minimum_dependency_set; BlockingMutex minimum_dependency_type_info_mutex; - PtrMap minimum_dependency_type_info_index_map; - TypeSet min_dep_type_info_set; - Array type_info_types; // sorted after filled + PtrMap min_dep_type_info_index_map; + TypeSet min_dep_type_info_set; Array type_info_types_hash_map; // 2 * type_info_types.count diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 4ebcf7578..d8e1af062 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -3185,8 +3185,11 @@ gb_internal bool lb_generate_code(lbGenerator *gen) { isize count = 0; isize offsets_extra = 0; - for (auto const &tt : m->info->type_info_types) { + for (auto const &tt : m->info->type_info_types_hash_map) { Type *t = tt.type; + if (t == nullptr) { + continue; + } isize index = lb_type_info_index(m->info, t, false); if (index < 0) { continue; diff --git a/src/llvm_backend_type.cpp b/src/llvm_backend_type.cpp index 170da5b2b..ad4250f3c 100644 --- a/src/llvm_backend_type.cpp +++ b/src/llvm_backend_type.cpp @@ -5,8 +5,8 @@ gb_internal isize lb_type_info_index(CheckerInfo *info, TypeInfoPair pair, bool return index; } if (err_on_not_found) { - gb_printf_err("NOT FOUND lb_type_info_index:\n\t%s\n\t@ index %td\n\tmax count: %u\nFound:\n", type_to_string(pair.type), index, info->minimum_dependency_type_info_index_map.count); - for (auto const &entry : info->minimum_dependency_type_info_index_map) { + gb_printf_err("NOT FOUND lb_type_info_index:\n\t%s\n\t@ index %td\n\tmax count: %u\nFound:\n", type_to_string(pair.type), index, info->min_dep_type_info_index_map.count); + for (auto const &entry : info->min_dep_type_info_index_map) { isize type_info_index = entry.key; gb_printf_err("\t%s\n", type_to_string(info->type_info_types_hash_map[type_info_index].type)); } -- cgit v1.2.3 From d23453811d3b8f5518845b412b9044a5bb5e92fb Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 24 Feb 2025 13:13:36 +0000 Subject: Improve semicolon checking rules when parsing --- src/parser.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/parser.cpp b/src/parser.cpp index f09590a55..f38f79607 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -3016,9 +3016,10 @@ gb_internal Ast *parse_operand(AstFile *f, bool lhs) { syntax_error(token, "Expected a type or range, got nothing"); } - if (allow_token(f, Token_Semicolon)) { + if (f->curr_token.kind == Token_Semicolon && f->curr_token.string == ";") { + expect_token(f, Token_Semicolon); underlying = parse_type(f); - } else if (allow_token(f, Token_Comma)) { + } else if (allow_token(f, Token_Comma) || allow_token(f, Token_Semicolon)) { String p = token_to_string(f->prev_token); syntax_error(token_end_of_line(f, f->prev_token), "Expected a semicolon, got a %.*s", LIT(p)); @@ -4578,6 +4579,9 @@ gb_internal Ast *parse_do_body(AstFile *f, Token const &token, char const *msg) gb_internal bool parse_control_statement_semicolon_separator(AstFile *f) { Token tok = peek_token(f); if (tok.kind != Token_OpenBrace) { + if (f->curr_token.kind == Token_Semicolon && f->curr_token.string != ";") { + syntax_error(token_end_of_line(f, f->prev_token), "Expected ';', got newline"); + } return allow_token(f, Token_Semicolon); } if (f->curr_token.string == ";") { -- cgit v1.2.3 From 33a3aab7914fbed9abb0abfa696590ae25d03f4f Mon Sep 17 00:00:00 2001 From: Barinzaya Date: Tue, 15 Oct 2024 18:13:35 -0400 Subject: Added simd_extract_msbs intrinsic. --- base/intrinsics/intrinsics.odin | 2 ++ core/simd/simd.odin | 2 ++ src/check_builtin.cpp | 32 ++++++++++++++++++++++++++++++++ src/checker_builtin_procs.hpp | 4 ++++ src/llvm_backend_proc.cpp | 24 ++++++++++++++++++++++++ 5 files changed, 64 insertions(+) (limited to 'src') diff --git a/base/intrinsics/intrinsics.odin b/base/intrinsics/intrinsics.odin index ee0d357e4..64fc08a30 100644 --- a/base/intrinsics/intrinsics.odin +++ b/base/intrinsics/intrinsics.odin @@ -285,6 +285,8 @@ simd_reduce_xor :: proc(a: #simd[N]T) -> T where type_is_integer(T) || t simd_reduce_any :: proc(a: #simd[N]T) -> T where type_is_boolean(T) --- simd_reduce_all :: proc(a: #simd[N]T) -> T where type_is_boolean(T) --- +simd_extract_msbs :: proc(a: #simd[N]T) -> bit_set[0.. #simd[N]T where type_is_integer(U) || type_is_boolean(U) --- simd_scatter :: proc(ptr: #simd[N]rawptr, val: #simd[N]T, mask: #simd[N]U) where type_is_integer(U) || type_is_boolean(U) --- diff --git a/core/simd/simd.odin b/core/simd/simd.odin index 01d11dfbe..517cef656 100644 --- a/core/simd/simd.odin +++ b/core/simd/simd.odin @@ -135,6 +135,8 @@ reduce_xor :: intrinsics.simd_reduce_xor reduce_any :: intrinsics.simd_reduce_any reduce_all :: intrinsics.simd_reduce_all +extract_msbs :: intrinsics.simd_extract_msbs + // swizzle :: proc(a: #simd[N]T, indices: ..int) -> #simd[len(indices)]T swizzle :: builtin.swizzle diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 5aa4cf027..12124096f 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -888,6 +888,38 @@ gb_internal bool check_builtin_simd_operation(CheckerContext *c, Operand *operan return true; } + case BuiltinProc_simd_extract_msbs: + { + Operand x = {}; + check_expr(c, &x, ce->args[0]); if (x.mode == Addressing_Invalid) return false; + + if (!is_type_simd_vector(x.type)) { + gbString xs = type_to_string(x.type); + error(x.expr, "'%.*s' expected a simd vector type, got '%s'", LIT(builtin_name), xs); + gb_string_free(xs); + return false; + } + + Type *elem = base_array_type(x.type); + if (!is_type_integer_like(elem)) { + gbString xs = type_to_string(x.type); + error(x.expr, "'%.*s' expected a #simd type with integer or boolean elements, got '%s'", LIT(builtin_name), xs); + gb_string_free(xs); + return false; + } + + i64 num_elems = get_array_type_count(x.type); + + Type *result_type = alloc_type_bit_set(); + result_type->BitSet.elem = t_int; + result_type->BitSet.lower = 0; + result_type->BitSet.upper = num_elems - 1; + + operand->mode = Addressing_Value; + operand->type = result_type; + return true; + } + case BuiltinProc_simd_shuffle: { diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index 2dfd570e4..92f9f1602 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -181,6 +181,8 @@ BuiltinProc__simd_begin, BuiltinProc_simd_reduce_any, BuiltinProc_simd_reduce_all, + BuiltinProc_simd_extract_msbs, + BuiltinProc_simd_shuffle, BuiltinProc_simd_select, @@ -523,6 +525,8 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("simd_reduce_any"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("simd_reduce_all"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("simd_extract_msbs"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("simd_shuffle"), 2, true, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("simd_select"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index e5c04852c..eea0fe03e 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -1564,6 +1564,30 @@ gb_internal lbValue lb_build_builtin_simd_proc(lbProcedure *p, Ast *expr, TypeAn return res; } + case BuiltinProc_simd_extract_msbs: + { + Type *vt = arg0.type; + GB_ASSERT(vt->kind == Type_SimdVector); + + i64 elem_bits = 8*type_size_of(elem); + i64 num_elems = get_array_type_count(vt); + + LLVMTypeRef word_type = lb_type(m, elem); + LLVMValueRef shift_value = llvm_splat_int(num_elems, word_type, elem_bits - 1); + LLVMValueRef broadcast_value = LLVMBuildAShr(p->builder, arg0.value, shift_value, ""); + + LLVMTypeRef bitvec_type = LLVMVectorType(LLVMInt1TypeInContext(m->ctx), (unsigned)num_elems); + LLVMValueRef bitvec_value = LLVMBuildTrunc(p->builder, broadcast_value, bitvec_type, ""); + + LLVMTypeRef mask_type = LLVMIntTypeInContext(m->ctx, (unsigned)num_elems); + LLVMValueRef mask_value = LLVMBuildBitCast(p->builder, bitvec_value, mask_type, ""); + + LLVMTypeRef result_type = lb_type(m, res.type); + res.value = LLVMBuildZExtOrBitCast(p->builder, mask_value, result_type, ""); + + return res; + } + case BuiltinProc_simd_shuffle: { -- cgit v1.2.3 From 4afedbc051e92647c9003d33b1a231330fe3b025 Mon Sep 17 00:00:00 2001 From: Barinzaya Date: Mon, 24 Feb 2025 08:49:57 -0500 Subject: Added simd_extract_lsbs intrinsic as well. Equivalent to the simd_extract_msbs intrinsic, except it extracts the least significant bit of each element instead. --- base/intrinsics/intrinsics.odin | 1 + core/simd/simd.odin | 1 + src/check_builtin.cpp | 1 + src/checker_builtin_procs.hpp | 2 ++ src/llvm_backend_proc.cpp | 10 +++++++--- 5 files changed, 12 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/base/intrinsics/intrinsics.odin b/base/intrinsics/intrinsics.odin index 64fc08a30..bec452007 100644 --- a/base/intrinsics/intrinsics.odin +++ b/base/intrinsics/intrinsics.odin @@ -285,6 +285,7 @@ simd_reduce_xor :: proc(a: #simd[N]T) -> T where type_is_integer(T) || t simd_reduce_any :: proc(a: #simd[N]T) -> T where type_is_boolean(T) --- simd_reduce_all :: proc(a: #simd[N]T) -> T where type_is_boolean(T) --- +simd_extract_lsbs :: proc(a: #simd[N]T) -> bit_set[0.. bit_set[0.. #simd[len(indices)]T diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 12124096f..023aeff73 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -888,6 +888,7 @@ gb_internal bool check_builtin_simd_operation(CheckerContext *c, Operand *operan return true; } + case BuiltinProc_simd_extract_lsbs: case BuiltinProc_simd_extract_msbs: { Operand x = {}; diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index 92f9f1602..40dde8240 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -181,6 +181,7 @@ BuiltinProc__simd_begin, BuiltinProc_simd_reduce_any, BuiltinProc_simd_reduce_all, + BuiltinProc_simd_extract_lsbs, BuiltinProc_simd_extract_msbs, BuiltinProc_simd_shuffle, @@ -525,6 +526,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("simd_reduce_any"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("simd_reduce_all"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("simd_extract_lsbs"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("simd_extract_msbs"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index eea0fe03e..b41f4723c 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -1564,6 +1564,7 @@ gb_internal lbValue lb_build_builtin_simd_proc(lbProcedure *p, Ast *expr, TypeAn return res; } + case BuiltinProc_simd_extract_lsbs: case BuiltinProc_simd_extract_msbs: { Type *vt = arg0.type; @@ -1572,9 +1573,12 @@ gb_internal lbValue lb_build_builtin_simd_proc(lbProcedure *p, Ast *expr, TypeAn i64 elem_bits = 8*type_size_of(elem); i64 num_elems = get_array_type_count(vt); - LLVMTypeRef word_type = lb_type(m, elem); - LLVMValueRef shift_value = llvm_splat_int(num_elems, word_type, elem_bits - 1); - LLVMValueRef broadcast_value = LLVMBuildAShr(p->builder, arg0.value, shift_value, ""); + LLVMValueRef broadcast_value = arg0.value; + if (builtin_id == BuiltinProc_simd_extract_msbs) { + LLVMTypeRef word_type = lb_type(m, elem); + LLVMValueRef shift_value = llvm_splat_int(num_elems, word_type, elem_bits - 1); + broadcast_value = LLVMBuildAShr(p->builder, broadcast_value, shift_value, ""); + } LLVMTypeRef bitvec_type = LLVMVectorType(LLVMInt1TypeInContext(m->ctx), (unsigned)num_elems); LLVMValueRef bitvec_value = LLVMBuildTrunc(p->builder, broadcast_value, bitvec_type, ""); -- cgit v1.2.3 From c2cafcbe14566f4de4829dce95a5e5c95ec78d52 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 24 Feb 2025 14:07:39 +0000 Subject: Fix #4819 --- src/llvm_backend_expr.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 9e115b9ca..b4e5c2a44 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -1554,7 +1554,7 @@ gb_internal lbValue lb_build_binary_expr(lbProcedure *p, Ast *expr) { lbValue cmp = lb_emit_comp_against_nil(p, be->op.kind, right); Type *type = default_type(tv.type); return lb_emit_conv(p, cmp, type); - } else if (lb_is_empty_string_constant(be->right)) { + } else if (lb_is_empty_string_constant(be->right) && !is_type_union(be->left->tav.type)) { // `x == ""` or `x != ""` lbValue s = lb_build_expr(p, be->left); s = lb_emit_conv(p, s, t_string); @@ -1562,7 +1562,7 @@ gb_internal lbValue lb_build_binary_expr(lbProcedure *p, Ast *expr) { lbValue cmp = lb_emit_comp(p, be->op.kind, len, lb_const_int(p->module, t_int, 0)); Type *type = default_type(tv.type); return lb_emit_conv(p, cmp, type); - } else if (lb_is_empty_string_constant(be->left)) { + } else if (lb_is_empty_string_constant(be->left) && !is_type_union(be->right->tav.type)) { // `"" == x` or `"" != x` lbValue s = lb_build_expr(p, be->right); s = lb_emit_conv(p, s, t_string); -- cgit v1.2.3 From 533f82da24f2736f0e133cab51772712d6526e84 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 24 Feb 2025 14:11:47 +0000 Subject: Fix #4822 --- src/llvm_backend_proc.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index b41f4723c..7efed98b4 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -2576,8 +2576,8 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu } case BuiltinProc_ptr_sub: { - Type *elem0 = type_deref(type_of_expr(ce->args[0])); - Type *elem1 = type_deref(type_of_expr(ce->args[1])); + Type *elem0 = type_deref(type_of_expr(ce->args[0]), true); + Type *elem1 = type_deref(type_of_expr(ce->args[1]), true); GB_ASSERT(are_types_identical(elem0, elem1)); Type *elem = elem0; -- cgit v1.2.3 From 46a8991d0fae4fb119e9934d62959e5a1729a636 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 24 Feb 2025 14:19:02 +0000 Subject: Canonicalize generated procedures --- src/llvm_backend.cpp | 39 ++++++++++++++------------------------- src/llvm_backend.hpp | 3 +++ src/llvm_backend_stmt.cpp | 2 -- 3 files changed, 17 insertions(+), 27 deletions(-) (limited to 'src') diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index d8e1af062..9bbcc2184 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -233,6 +233,16 @@ 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) { + 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)); + String proc_name = make_string(cast(u8 const *)str, gb_string_length(str)); + return proc_name; +} + + gb_internal lbValue lb_equal_proc_for_type(lbModule *m, Type *type) { type = base_type(type); GB_ASSERT(is_type_comparable(type)); @@ -248,16 +258,8 @@ gb_internal lbValue lb_equal_proc_for_type(lbModule *m, Type *type) { return {compare_proc->value, compare_proc->type}; } - static std::atomic proc_index; - char buf[32] = {}; - isize n = gb_snprintf(buf, 32, "__$equal%u", 1+proc_index.fetch_add(1)); - char *str = gb_alloc_str_len(permanent_allocator(), buf, n-1); - String proc_name = make_string_c(str); - - lbProcedure *p = lb_create_dummy_procedure(m, proc_name, t_equal_proc); - map_set(&m->equal_procs, type, p); - lb_begin_procedure_body(p); + String proc_name = lb_internal_gen_proc_name_from_type("__$equal", type); // lb_add_attribute_to_proc(m, p->value, "readonly"); lb_add_attribute_to_proc(m, p->value, "nounwind"); @@ -416,12 +418,7 @@ gb_internal lbValue lb_hasher_proc_for_type(lbModule *m, Type *type) { return {(*found)->value, (*found)->type}; } - static std::atomic proc_index; - - char buf[32] = {}; - isize n = gb_snprintf(buf, 32, "__$hasher%u", 1+proc_index.fetch_add(1)); - char *str = gb_alloc_str_len(permanent_allocator(), buf, n-1); - String proc_name = make_string_c(str); + String proc_name = lb_internal_gen_proc_name_from_type("__$hasher", type); lbProcedure *p = lb_create_dummy_procedure(m, proc_name, t_hasher_proc); map_set(&m->hasher_procs, type, p); @@ -583,12 +580,8 @@ gb_internal lbValue lb_map_get_proc_for_type(lbModule *m, Type *type) { GB_ASSERT(*found != nullptr); return {(*found)->value, (*found)->type}; } - static std::atomic proc_index; - char buf[32] = {}; - isize n = gb_snprintf(buf, 32, "__$map_get-%u", 1+proc_index.fetch_add(1)); - char *str = gb_alloc_str_len(permanent_allocator(), buf, n-1); - String proc_name = make_string_c(str); + String proc_name = lb_internal_gen_proc_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); @@ -764,12 +757,8 @@ gb_internal lbValue lb_map_set_proc_for_type(lbModule *m, Type *type) { GB_ASSERT(*found != nullptr); return {(*found)->value, (*found)->type}; } - static std::atomic proc_index; - char buf[32] = {}; - isize n = gb_snprintf(buf, 32, "__$map_set-%u", 1+proc_index.fetch_add(1)); - char *str = gb_alloc_str_len(permanent_allocator(), buf, n-1); - String proc_name = make_string_c(str); + String proc_name = lb_internal_gen_proc_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); diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index dd6f1a083..d596c2d5c 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -610,6 +610,9 @@ 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 void lb_set_metadata_custom_u64(lbModule *m, LLVMValueRef v_ref, String name, u64 value); gb_internal u64 lb_get_metadata_custom_u64(lbModule *m, LLVMValueRef v_ref, String name); diff --git a/src/llvm_backend_stmt.cpp b/src/llvm_backend_stmt.cpp index b83472075..758cd353f 100644 --- a/src/llvm_backend_stmt.cpp +++ b/src/llvm_backend_stmt.cpp @@ -5,8 +5,6 @@ gb_internal void lb_build_constant_value_decl(lbProcedure *p, AstValueDecl *vd) auto *min_dep_set = &p->module->info->minimum_dependency_set; - static i32 global_guid = 0; - for (Ast *ident : vd->names) { GB_ASSERT(ident->kind == Ast_Ident); Entity *e = entity_of_node(ident); -- 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') 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 2c86fadee1df955127abf8b4aa73708a35d9d43a Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 24 Feb 2025 14:28:24 +0000 Subject: More name canonicalization for globals --- src/llvm_backend.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index fc56044d3..4c4dc4c51 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -910,8 +910,6 @@ gb_internal lbValue lb_gen_map_cell_info_ptr(lbModule *m, Type *type) { lbValue res = {llvm_res, t_map_cell_info}; 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); @@ -1278,7 +1276,10 @@ gb_internal lbProcedure *lb_create_startup_runtime(lbModule *main_module, lbProc if (is_type_any(t)) { // NOTE(bill): Edge case for 'any' type Type *var_type = default_type(var.init.type); - lbAddr g = lb_add_global_generated(main_module, var_type, var.init); + gbString var_name = gb_string_make(permanent_allocator(), "__$global_any::"); + gbString e_str = string_canonical_entity_name(temporary_allocator(), e); + var_name = gb_string_append_length(var_name, e_str, gb_strlen(e_str)); + lbAddr g = lb_add_global_generated_with_name(main_module, var_type, var.init, make_string_c(var_name)); lb_addr_store(p, g, var.init); lbValue gp = lb_addr_get_ptr(p, g); @@ -2819,7 +2820,7 @@ gb_internal lbProcedure *lb_create_main_procedure(lbModule *m, lbProcedure *star Type *t_Internal_Test = find_type_in_pkg(m->info, str_lit("testing"), str_lit("Internal_Test")); Type *array_type = alloc_type_array(t_Internal_Test, m->info->testing_procedures.count); Type *slice_type = alloc_type_slice(t_Internal_Test); - lbAddr all_tests_array_addr = lb_add_global_generated(p->module, array_type, {}); + lbAddr all_tests_array_addr = lb_add_global_generated_with_name(p->module, array_type, {}, str_lit("__$all_tests_array")); lbValue all_tests_array = lb_addr_get_ptr(p, all_tests_array_addr); LLVMValueRef indices[2] = {}; -- cgit v1.2.3 From 68731b2b50799509afa1fa4ceea2c34d41d2ff4b Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 24 Feb 2025 14:36:19 +0000 Subject: Canonicalize global source code locations --- src/llvm_backend_const.cpp | 38 ++++++++++++++++++++++++++++++++------ 1 file changed, 32 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/llvm_backend_const.cpp b/src/llvm_backend_const.cpp index 754bbfca2..cee960bf3 100644 --- a/src/llvm_backend_const.cpp +++ b/src/llvm_backend_const.cpp @@ -330,31 +330,57 @@ gb_internal lbValue lb_emit_source_code_location_const(lbProcedure *p, Ast *node return lb_emit_source_code_location_const(p, proc_name, pos); } +gb_internal String lb_source_code_location_gen_name(String const &procedure, TokenPos const &pos) { + gbString s = gb_string_make(permanent_allocator(), "scl$["); + + s = gb_string_append_length(s, procedure.text, procedure.len); + if (pos.offset != 0) { + s = gb_string_append_fmt(s, "%d", pos.offset); + } else { + s = gb_string_append_fmt(s, "%d_%d", pos.line, pos.column); + } + s = gb_string_appendc(s, "]"); + + return make_string(cast(u8 const *)s, gb_string_length(s)); +} + +gb_internal String lb_source_code_location_gen_name(lbProcedure *p, Ast *node) { + String proc_name = {}; + if (p->entity) { + proc_name = p->entity->token.string; + } + TokenPos pos = {}; + if (node) { + pos = ast_token(node).pos; + } + return lb_source_code_location_gen_name(proc_name, pos); +} + + gb_internal lbValue lb_emit_source_code_location_as_global_ptr(lbProcedure *p, String const &procedure, TokenPos const &pos) { lbValue loc = lb_emit_source_code_location_const(p, procedure, pos); - lbAddr addr = lb_add_global_generated(p->module, loc.type, loc, nullptr); + lbAddr addr = lb_add_global_generated_with_name(p->module, loc.type, loc, lb_source_code_location_gen_name(procedure, pos)); lb_make_global_private_const(addr); return addr.addr; } gb_internal lbValue lb_const_source_code_location_as_global_ptr(lbModule *m, String const &procedure, TokenPos const &pos) { lbValue loc = lb_const_source_code_location_const(m, procedure, pos); - lbAddr addr = lb_add_global_generated(m, loc.type, loc, nullptr); + lbAddr addr = lb_add_global_generated_with_name(m, loc.type, loc, lb_source_code_location_gen_name(procedure, pos)); lb_make_global_private_const(addr); return addr.addr; } - - - gb_internal lbValue lb_emit_source_code_location_as_global_ptr(lbProcedure *p, Ast *node) { lbValue loc = lb_emit_source_code_location_const(p, node); - lbAddr addr = lb_add_global_generated(p->module, loc.type, loc, nullptr); + lbAddr addr = lb_add_global_generated_with_name(p->module, loc.type, loc, lb_source_code_location_gen_name(p, node)); lb_make_global_private_const(addr); return addr.addr; } + + gb_internal lbValue lb_emit_source_code_location_as_global(lbProcedure *p, String const &procedure, TokenPos const &pos) { return lb_emit_load(p, lb_emit_source_code_location_as_global_ptr(p, procedure, pos)); } -- 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') 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 de70e6faa04444a1ea6e8f5f72e7b6ce00dcec7e Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 24 Feb 2025 15:33:35 +0000 Subject: Use more type hashes where possible --- src/llvm_backend.hpp | 14 +++++++------- src/name_canonicalization.hpp | 17 +++++++++++++++++ 2 files changed, 24 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index 3617c267f..d0f68b73e 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -160,11 +160,11 @@ struct lbModule { AstFile *file; // possibly associated char const *module_name; - PtrMap types; // mutex: types_mutex + PtrMap types; // mutex: types_mutex PtrMap struct_field_remapping; // Key: LLVMTypeRef or Type *, mutex: types_mutex - PtrMap func_raw_types; // mutex: func_raw_types_mutex - RecursiveMutex types_mutex; - RecursiveMutex func_raw_types_mutex; + PtrMap func_raw_types; // mutex: func_raw_types_mutex + RecursiveMutex types_mutex; + RecursiveMutex func_raw_types_mutex; i32 internal_type_level; RwMutex values_mutex; @@ -178,7 +178,7 @@ struct lbModule { StringMap const_strings; - PtrMap function_type_map; + PtrMap function_type_map; StringMap gen_procs; // key is the canonicalized name @@ -201,8 +201,8 @@ struct lbModule { StringMap objc_classes; StringMap objc_selectors; - PtrMap map_cell_info_map; // address of runtime.Map_Info - PtrMap map_info_map; // address of runtime.Map_Cell_Info + PtrMap map_cell_info_map; // address of runtime.Map_Info + PtrMap map_info_map; // address of runtime.Map_Cell_Info PtrMap exact_value_compound_literal_addr_map; // Key: Ast_CompoundLit diff --git a/src/name_canonicalization.hpp b/src/name_canonicalization.hpp index e289ed5b2..304aff42e 100644 --- a/src/name_canonicalization.hpp +++ b/src/name_canonicalization.hpp @@ -109,3 +109,20 @@ gb_internal TypeInfoPair *type_set_retrieve(TypeSet *s, Type *ptr); gb_internal TypeSetIterator begin(TypeSet &set) noexcept; gb_internal TypeSetIterator end(TypeSet &set) noexcept; + + +template +gb_internal gb_inline V *map_get(PtrMap *h, Type *key) { + return map_get(h, type_hash_canonical_type(key)); +} +template +gb_internal gb_inline void map_set(PtrMap *h, Type *key, V const &value) { + map_set(h, type_hash_canonical_type(key), value); +} + +template +gb_internal gb_inline V &map_must_get(PtrMap *h, Type *key) { + V *ptr = map_get(h, type_hash_canonical_type(key)); + GB_ASSERT(ptr != nullptr); + return *ptr; +} \ No newline at end of file -- cgit v1.2.3 From f56a0a80d3b606b1cbefb973b03b9ddae88bbf48 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 24 Feb 2025 15:37:54 +0000 Subject: Use type hash for doc writer --- src/docs_writer.cpp | 54 +++++++--------------------------------------------- src/llvm_backend.hpp | 10 +++++----- 2 files changed, 12 insertions(+), 52 deletions(-) (limited to 'src') diff --git a/src/docs_writer.cpp b/src/docs_writer.cpp index 341b3fa6b..5401e5f76 100644 --- a/src/docs_writer.cpp +++ b/src/docs_writer.cpp @@ -26,11 +26,10 @@ struct OdinDocWriter { StringMap string_cache; - OrderedInsertPtrMap file_cache; - OrderedInsertPtrMap pkg_cache; - OrderedInsertPtrMap entity_cache; - OrderedInsertPtrMap type_cache; - OrderedInsertPtrMap stable_type_cache; + OrderedInsertPtrMap file_cache; + OrderedInsertPtrMap pkg_cache; + OrderedInsertPtrMap entity_cache; + OrderedInsertPtrMap type_cache; OdinDocWriterItemTracker files; OdinDocWriterItemTracker pkgs; @@ -61,7 +60,6 @@ gb_internal void odin_doc_writer_prepare(OdinDocWriter *w) { map_init(&w->pkg_cache, 1<<10); map_init(&w->entity_cache, 1<<18); map_init(&w->type_cache, 1<<18); - map_init(&w->stable_type_cache, 1<<18); odin_doc_writer_item_tracker_init(&w->files, 1); odin_doc_writer_item_tracker_init(&w->pkgs, 1); @@ -81,7 +79,6 @@ gb_internal void odin_doc_writer_destroy(OdinDocWriter *w) { map_destroy(&w->pkg_cache); map_destroy(&w->entity_cache); map_destroy(&w->type_cache); - map_destroy(&w->stable_type_cache); } @@ -492,55 +489,18 @@ gb_internal OdinDocTypeIndex odin_doc_type(OdinDocWriter *w, Type *type) { } } - // Type **mapped_type = map_get(&w->stable_type_cache, type); // may map to itself - // if (mapped_type && *mapped_type) { - // type = *mapped_type; - // } - - OdinDocTypeIndex *found = map_get(&w->type_cache, type); + u64 type_hash = type_hash_canonical_type(type); + OdinDocTypeIndex *found = map_get(&w->type_cache, type_hash); if (found) { return *found; } - for (auto const &entry : w->type_cache) { - // NOTE(bill): THIS IS SLOW - Type *x = type; - Type *y = entry.key; - - if (x == y) { - goto do_set; - } - - if (!x | !y) { - continue; - } - if (y->kind == Type_Named) { - Entity *e = y->Named.type_name; - if (e->TypeName.is_type_alias) { - y = y->Named.base; - } - } - if (x->kind != y->kind) { - continue; - } - - if (!are_types_identical_internal(x, y, true)) { - continue; - } - - do_set: - OdinDocTypeIndex index = entry.value; - map_set(&w->type_cache, type, index); - map_set(&w->stable_type_cache, type, entry.key); - return index; - } OdinDocType *dst = nullptr; OdinDocType doc_type = {}; OdinDocTypeIndex type_index = 0; type_index = odin_doc_write_item(w, &w->types, &doc_type, &dst); - map_set(&w->type_cache, type, type_index); - map_set(&w->stable_type_cache, type, type); + map_set(&w->type_cache, type_hash, type_index); switch (type->kind) { case Type_Basic: diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index d0f68b73e..b455bf4e8 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -160,9 +160,9 @@ struct lbModule { AstFile *file; // possibly associated char const *module_name; - PtrMap types; // mutex: types_mutex + PtrMap types; // mutex: types_mutex PtrMap struct_field_remapping; // Key: LLVMTypeRef or Type *, mutex: types_mutex - PtrMap func_raw_types; // mutex: func_raw_types_mutex + PtrMap func_raw_types; // mutex: func_raw_types_mutex RecursiveMutex types_mutex; RecursiveMutex func_raw_types_mutex; i32 internal_type_level; @@ -178,7 +178,7 @@ struct lbModule { StringMap const_strings; - PtrMap function_type_map; + PtrMap function_type_map; StringMap gen_procs; // key is the canonicalized name @@ -201,8 +201,8 @@ struct lbModule { StringMap objc_classes; StringMap objc_selectors; - PtrMap map_cell_info_map; // address of runtime.Map_Info - PtrMap map_info_map; // address of runtime.Map_Cell_Info + PtrMap map_cell_info_map; // address of runtime.Map_Info + PtrMap map_info_map; // address of runtime.Map_Cell_Info PtrMap exact_value_compound_literal_addr_map; // Key: Ast_CompoundLit -- cgit v1.2.3 From 344eb6cb42a635f36d669fee8fc25dc37c852ba1 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 24 Feb 2025 15:44:38 +0000 Subject: Fix name canonicalization for doc writer --- src/docs_writer.cpp | 11 +++++++++++ src/name_canonicalization.cpp | 10 +++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/docs_writer.cpp b/src/docs_writer.cpp index 5401e5f76..a92ffc7ad 100644 --- a/src/docs_writer.cpp +++ b/src/docs_writer.cpp @@ -16,6 +16,8 @@ gb_global char const* OdinDocWriterState_strings[] { "writing ", }; +gb_global std::atomic g_in_doc_writer; + struct OdinDocWriter { CheckerInfo *info; OdinDocWriterState state; @@ -1137,6 +1139,8 @@ gb_internal void odin_doc_write_to_file(OdinDocWriter *w, char const *filename) } gb_internal void odin_doc_write(CheckerInfo *info, char const *filename) { + g_in_doc_writer.store(true); + OdinDocWriter w_ = {}; OdinDocWriter *w = &w_; defer (odin_doc_writer_destroy(w)); @@ -1152,4 +1156,11 @@ gb_internal void odin_doc_write(CheckerInfo *info, char const *filename) { odin_doc_writer_end_writing(w); odin_doc_write_to_file(w, filename); + + g_in_doc_writer.store(false); } + + +gb_internal bool is_in_doc_writer(void) { + return g_in_doc_writer.load(); +} \ No newline at end of file diff --git a/src/name_canonicalization.cpp b/src/name_canonicalization.cpp index 5d311068f..a80dc1996 100644 --- a/src/name_canonicalization.cpp +++ b/src/name_canonicalization.cpp @@ -520,6 +520,8 @@ write_base_name: return; } +gb_internal bool is_in_doc_writer(void); + // NOTE(bill): This exists so that we deterministically hash a type by serializing it to a canonical string gb_internal void write_type_to_canonical_string(TypeWriter *w, Type *type) { if (type == nullptr) { @@ -719,7 +721,13 @@ gb_internal void write_type_to_canonical_string(TypeWriter *w, Type *type) { return; case Type_Generic: - GB_PANIC("Type_Generic should never be hit"); + if (is_in_doc_writer()) { + type_writer_appendc(w, "$"); + type_writer_append(w, type->Generic.name.text, type->Generic.name.len); + type_writer_append_fmt(w, "%lld", cast(long long)type->Generic.id); + } else { + GB_PANIC("Type_Generic should never be hit"); + } return; case Type_Named: -- cgit v1.2.3 From d0d5cf800eb0dc039c124cc62cea74589b6e2f6c Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 24 Feb 2025 15:49:49 +0000 Subject: Fix `nullptr` check --- src/types.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/types.cpp b/src/types.cpp index 056737af5..43fe625f2 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -2087,6 +2087,9 @@ gb_internal bool is_type_sliceable(Type *t) { gb_internal Entity *type_get_polymorphic_parent(Type *t, Type **params_) { t = base_type(t); + if (t == nullptr) { + return nullptr; + } Type *parent = nullptr; if (t->kind == Type_Struct) { parent = t->Struct.polymorphic_parent; -- cgit v1.2.3 From faaa05536f070093802fbdc4f7f62e7bd8439b64 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 24 Feb 2025 17:42:21 +0000 Subject: Support `-show-timings` for `odin doc` --- src/main.cpp | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src') diff --git a/src/main.cpp b/src/main.cpp index e8336b292..0a24d64a6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3593,10 +3593,15 @@ int main(int arg_count, char const **arg_ptr) { } if (build_context.generate_docs) { + MAIN_TIME_SECTION("generate documentation"); if (global_error_collector.count != 0) { return 1; } generate_documentation(checker); + + if (build_context.show_timings) { + show_timings(checker, &global_timings); + } return 0; } -- 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') 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') 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') 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') 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') 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') 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 From 66540b75f50315e372a74545de7fe91d04b1be62 Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Sat, 1 Mar 2025 16:06:32 +0100 Subject: fix hidden linkage applied to foreign symbols --- src/llvm_backend.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 9cf996e84..f21ca9f75 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -169,7 +169,7 @@ gb_internal void lb_correct_entity_linkage(lbGenerator *gen) { other_global = LLVMGetNamedGlobal(ec.other_module->mod, ec.cname); if (other_global) { LLVMSetLinkage(other_global, LLVMWeakAnyLinkage); - if (!ec.e->Variable.is_export) { + if (!ec.e->Variable.is_export && !ec.e->Variable.is_foreign) { LLVMSetVisibility(other_global, LLVMHiddenVisibility); } } @@ -177,7 +177,7 @@ gb_internal void lb_correct_entity_linkage(lbGenerator *gen) { other_global = LLVMGetNamedFunction(ec.other_module->mod, ec.cname); if (other_global) { LLVMSetLinkage(other_global, LLVMWeakAnyLinkage); - if (!ec.e->Procedure.is_export) { + if (!ec.e->Procedure.is_export && !ec.e->Procedure.is_foreign) { LLVMSetVisibility(other_global, LLVMHiddenVisibility); } } -- cgit v1.2.3 From 211680569f93db8896fafa9693158725925138fd Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 1 Mar 2025 15:19:46 +0000 Subject: Fix for `-use-single-module` --- src/llvm_backend.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 9cf996e84..a9cca2695 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -2562,9 +2562,10 @@ gb_internal String lb_filepath_ll_for_module(lbModule *m) { 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; + if (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")); @@ -2595,14 +2596,16 @@ gb_internal String lb_filepath_obj_for_module(lbModule *m) { 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; + if (string_starts_with(s, prefix)) { + s.text += prefix.len; + s.len -= prefix.len; + } path = gb_string_append_length(path, s.text, s.len); } if (use_temporary_directory) { + // NOTE(bill): this must be suffixed to ensure it is not conflicting with anything else in the temporary directory path = gb_string_append_fmt(path, "-%p", m); } -- cgit v1.2.3