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/checker.cpp | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) (limited to 'src/checker.cpp') 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) { -- 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/checker.cpp') 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 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/checker.cpp') 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 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/checker.cpp') 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 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/checker.cpp') 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/checker.cpp') 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 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/checker.cpp') diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 9084f15f0..d6f8e6fa7 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -1784,6 +1784,10 @@ gb_internal bool check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *de ctx->curr_proc_sig = type; ctx->curr_proc_calling_convention = type->Proc.calling_convention; + if (decl->parent && decl->entity && decl->parent->entity) { + decl->entity->parent_proc_decl = decl->parent; + } + if (ctx->pkg->name != "runtime") { switch (type->Proc.calling_convention) { case ProcCC_None: @@ -1873,6 +1877,8 @@ gb_internal bool check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *de check_open_scope(ctx, body); { + ctx->scope->decl_info = decl; + for (auto const &entry : using_entities) { Entity *uvar = entry.uvar; Entity *prev = scope_insert(ctx->scope, uvar); diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 550a7749c..f0021e67f 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -345,7 +345,7 @@ gb_internal void check_scope_decls(CheckerContext *c, Slice const &nodes, check_collect_entities(c, nodes); for (auto const &entry : s->elements) { - Entity *e = entry.value; + Entity *e = entry.value;\ switch (e->kind) { case Entity_Constant: case Entity_TypeName: diff --git a/src/checker.cpp b/src/checker.cpp index bfcabe4fa..c74a72a14 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -3894,6 +3894,7 @@ gb_internal DECL_ATTRIBUTE_PROC(type_decl_attribute) { #include "check_expr.cpp" #include "check_builtin.cpp" #include "check_type.cpp" +#include "name_canonicalization.cpp" #include "check_decl.cpp" #include "check_stmt.cpp" diff --git a/src/checker.hpp b/src/checker.hpp index 4634047c0..472ab8e50 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -276,6 +276,8 @@ struct Scope { StringMap elements; PtrSet imported; + DeclInfo *decl_info; + i32 flags; // ScopeFlag union { AstPackage *pkg; diff --git a/src/entity.cpp b/src/entity.cpp index d137a8674..b2148aa7b 100644 --- a/src/entity.cpp +++ b/src/entity.cpp @@ -257,6 +257,7 @@ struct Entity { bool has_instrumentation : 1; bool is_memcpy_like : 1; bool uses_branch_location : 1; + bool is_anonymous : 1; } Procedure; struct { Array entities; diff --git a/src/gb/gb.h b/src/gb/gb.h index 59611ceb6..98c362e93 100644 --- a/src/gb/gb.h +++ b/src/gb/gb.h @@ -5856,7 +5856,7 @@ gb_inline isize gb_fprintf_va(struct gbFile *f, char const *fmt, va_list va) { gb_inline char *gb_bprintf_va(char const *fmt, va_list va) { - gb_local_persist char buffer[4096]; + gb_thread_local gb_local_persist char buffer[4096]; gb_snprintf_va(buffer, gb_size_of(buffer), fmt, va); return buffer; } diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index a0775ac3b..dd6f1a083 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -399,7 +399,7 @@ struct lbProcedure { gb_internal bool lb_init_generator(lbGenerator *gen, Checker *c); gb_internal String lb_mangle_name(Entity *e); -gb_internal String lb_get_entity_name(lbModule *m, Entity *e, String name = {}); +gb_internal String lb_get_entity_name(lbModule *m, Entity *e); gb_internal LLVMAttributeRef lb_create_enum_attribute(LLVMContextRef ctx, char const *name, u64 value=0); gb_internal LLVMAttributeRef lb_create_enum_attribute_with_type(LLVMContextRef ctx, char const *name, LLVMTypeRef type); diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index 7425b9fd7..dc212e51d 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -1444,6 +1444,7 @@ gb_internal void lb_clone_struct_type(LLVMTypeRef dst, LLVMTypeRef src) { } gb_internal String lb_mangle_name(Entity *e) { +#if 1 String name = e->token.string; AstPackage *pkg = e->pkg; @@ -1483,9 +1484,18 @@ gb_internal String lb_mangle_name(Entity *e) { String mangled_name = make_string((u8 const *)new_name, new_name_len-1); return mangled_name; +#else + gbString w = gb_string_make(gb_heap_allocator(), ""); + w = write_canonical_entity_name(w, e); + gb_printf_err(">> %s\n", w); + + String mangled_name = make_string(cast(u8 const *)w, gb_string_length(w)); + return mangled_name; +#endif } gb_internal String lb_set_nested_type_name_ir_mangled_name(Entity *e, lbProcedure *p, lbModule *module) { +#if 0 // NOTE(bill, 2020-03-08): A polymorphic procedure may take a nested type declaration // and as a result, the declaration does not have time to determine what it should be @@ -1516,6 +1526,7 @@ gb_internal String lb_set_nested_type_name_ir_mangled_name(Entity *e, lbProcedur } } + // NOTE(bill): Generate a new name // parent_proc.name-guid String ts_name = e->token.string; @@ -1528,6 +1539,12 @@ gb_internal String lb_set_nested_type_name_ir_mangled_name(Entity *e, lbProcedur String name = make_string(cast(u8 *)name_text, name_len-1); e->TypeName.ir_mangled_name = name; + + { + String s = type_to_canonical_string(temporary_allocator(), e->type); + gb_printf_err("1) %.*s\n", LIT(s)); + gb_printf_err("2) %.*s\n", LIT(name)); + } return name; } else { // NOTE(bill): a nested type be required before its parameter procedure exists. Just give it a temp name for now @@ -1538,11 +1555,18 @@ gb_internal String lb_set_nested_type_name_ir_mangled_name(Entity *e, lbProcedur String name = make_string(cast(u8 *)name_text, name_len-1); e->TypeName.ir_mangled_name = name; + + { + String s = type_to_canonical_string(temporary_allocator(), e->type); + gb_printf_err("3) %.*s\n", LIT(s)); + gb_printf_err("4) %.*s\n", LIT(name)); + } return name; } +#endif } -gb_internal String lb_get_entity_name(lbModule *m, Entity *e, String default_name) { +gb_internal String lb_get_entity_name(lbModule *m, Entity *e) { GB_ASSERT(m != nullptr); if (e != nullptr && e->kind == Entity_TypeName && e->TypeName.ir_mangled_name.len != 0) { return e->TypeName.ir_mangled_name; @@ -1553,6 +1577,13 @@ gb_internal String lb_get_entity_name(lbModule *m, Entity *e, String default_nam return e->token.string; } +#if 1 + gbString w = gb_string_make(heap_allocator(), ""); + w = write_canonical_entity_name(w, e); + defer (gb_string_free(w)); + + String name = copy_string(permanent_allocator(), make_string(cast(u8 const *)w, gb_string_length(w))); +#else if (e->kind == Entity_TypeName && (e->scope->flags & ScopeFlag_File) == 0) { return lb_set_nested_type_name_ir_mangled_name(e, nullptr, m); } @@ -1576,11 +1607,17 @@ gb_internal String lb_get_entity_name(lbModule *m, Entity *e, String default_nam if (!no_name_mangle) { name = lb_mangle_name(e); + + gbString w = gb_string_make(gb_heap_allocator(), ""); + w = write_canonical_entity_name(w, e); + if (w[0] == 0) { + gb_printf_err(">> %s %.*s\n", w, LIT(name)); + } } if (name.len == 0) { name = e->token.string; } - +#endif if (e->kind == Entity_TypeName) { e->TypeName.ir_mangled_name = name; } else if (e->kind == Entity_Procedure) { @@ -2869,6 +2906,8 @@ gb_internal lbValue lb_generate_anonymous_proc_lit(lbModule *m, String const &pr pl->decl->code_gen_module = m; e->decl_info = pl->decl; pl->decl->entity = e; + e->parent_proc_decl = pl->decl->parent; + e->Procedure.is_anonymous = true; e->flags |= EntityFlag_ProcBodyChecked; lbProcedure *p = lb_create_procedure(m, e); diff --git a/src/llvm_backend_stmt.cpp b/src/llvm_backend_stmt.cpp index b05df0b46..b83472075 100644 --- a/src/llvm_backend_stmt.cpp +++ b/src/llvm_backend_stmt.cpp @@ -32,7 +32,8 @@ gb_internal void lb_build_constant_value_decl(lbProcedure *p, AstValueDecl *vd) continue; } - lb_set_nested_type_name_ir_mangled_name(e, p, p->module); + String name = lb_get_entity_name(p->module, e); + gb_unused(name); } for_array(i, vd->names) { diff --git a/src/name_canonicalization.cpp b/src/name_canonicalization.cpp new file mode 100644 index 000000000..fa09f27c0 --- /dev/null +++ b/src/name_canonicalization.cpp @@ -0,0 +1,419 @@ +gb_internal gbString write_type_to_canonical_string(gbString w, Type *type); +gb_internal gbString write_canonical_params(gbString w, Type *params) { + w = gb_string_appendc(w, "("); + if (params) { + GB_ASSERT(params->kind == Type_Tuple); + for_array(i, params->Tuple.variables) { + Entity *v = params->Tuple.variables[i]; + if (i > 0) { + w = gb_string_appendc(w, ","); + } + if (v->kind == Entity_Variable) { + if (v->flags&EntityFlag_CVarArg) { + w = gb_string_appendc(w, "#c_vararg"); + } + if (v->flags&EntityFlag_Ellipsis) { + Type *slice = base_type(v->type); + w = gb_string_appendc(w, ".."); + GB_ASSERT(v->type->kind == Type_Slice); + w = write_type_to_canonical_string(w, slice->Slice.elem); + } else { + w = write_type_to_canonical_string(w, v->type); + } + } else if (v->kind == Entity_TypeName) { + w = gb_string_appendc(w, "$"); + w = write_type_to_canonical_string(w, v->type); + } else if (v->kind == Entity_Constant) { + w = gb_string_appendc(w, "$$"); + w = write_exact_value_to_string(w, v->Constant.value); + } else { + GB_PANIC("TODO(bill): handle non type/const parapoly parameter values"); + } + } + } + return gb_string_appendc(w, ")"); +} + +gb_internal u64 type_hash_canonical_type(Type *type) { + if (type == nullptr) { + return 0; + } + TEMPORARY_ALLOCATOR_GUARD(); + gbString w = write_type_to_canonical_string(gb_string_make(temporary_allocator(), ""), type); + u64 hash = fnv64a(w, gb_string_length(w)); + return hash; +} + +gb_internal String type_to_canonical_string(gbAllocator allocator, Type *type) { + gbString w = gb_string_make(allocator, ""); + w = write_type_to_canonical_string(w, type); + return make_string(cast(u8 const *)w, gb_string_length(w)); +} + +gb_internal void print_scope_flags(Scope *s) { + if (s->flags & ScopeFlag_Pkg) gb_printf_err("Pkg "); + if (s->flags & ScopeFlag_Builtin) gb_printf_err("Builtin "); + if (s->flags & ScopeFlag_Global) gb_printf_err("Global "); + if (s->flags & ScopeFlag_File) gb_printf_err("File "); + if (s->flags & ScopeFlag_Init) gb_printf_err("Init "); + if (s->flags & ScopeFlag_Proc) gb_printf_err("Proc "); + if (s->flags & ScopeFlag_Type) gb_printf_err("Type "); + if (s->flags & ScopeFlag_HasBeenImported) gb_printf_err("HasBeenImported "); + if (s->flags & ScopeFlag_ContextDefined) gb_printf_err("ContextDefined "); + gb_printf_err("\n"); +} + + + +gb_internal gbString write_canonical_parent_prefix(gbString w, Entity *e, bool ignore_final_dot=false) { + GB_ASSERT(e != nullptr); + + // auto const &parent_entity = [](Scope *s) -> Entity* { + // while ((s->flags & (ScopeFlag_Proc|ScopeFlag_File)) == 0 && s->decl_info == nullptr) { + // s = s->parent; + // } + // if (s->decl_info && s->decl_info->entity) { + // return s->decl_info->entity; + // } + // return nullptr; + // }; + + if (e->kind == Entity_Procedure) { + if (e->Procedure.is_export || e->Procedure.is_foreign) { + // no prefix + return w; + } + if (e->parent_proc_decl) { + Entity *p = e->parent_proc_decl->entity; + w = write_canonical_parent_prefix(w, p); + w = gb_string_append_length(w, p->token.string.text, p->token.string.len); + if (is_type_polymorphic(p->type)) { + w = gb_string_appendc(w, "::"); + w = write_type_to_canonical_string(w, p->type); + } + w = gb_string_appendc(w, "."); + + } else if (e->pkg && (scope_lookup_current(e->pkg->scope, e->token.string) == e)) { + w = gb_string_append_length(w, e->pkg->name.text, e->pkg->name.len); + if (e->pkg->name == "llvm") { + gb_string_appendc(w, "$"); + } + w = gb_string_appendc(w, "."); + } else { + String file_name = filename_without_directory(e->file->fullpath); + w = gb_string_append_length(w, e->pkg->name.text, e->pkg->name.len); + if (e->pkg->name == "llvm") { + gb_string_appendc(w, "$"); + } + w = gb_string_appendc(w, gb_bprintf(".[%.*s].", LIT(file_name))); + } + } else if (e->kind == Entity_Procedure) { + if (e->Procedure.is_export || e->Procedure.is_foreign) { + // no prefix + return w; + } + GB_PANIC("TODO(bill): handle entity kind: %d", e->kind); + } + + if (e->kind == Entity_Procedure && e->Procedure.is_anonymous) { + w = gb_string_appendc(w, gb_bprintf("$anon%d", e->token.pos.offset)); + } else { + w = gb_string_append_length(w, e->token.string.text, e->token.string.len); + } + + if (is_type_polymorphic(e->type)) { + w = gb_string_appendc(w, "::"); + w = write_type_to_canonical_string(w, e->type); + } + if (!ignore_final_dot) { + w = gb_string_appendc(w, "."); + } + + return w; +} + +gb_internal gbString write_canonical_entity_name(gbString w, Entity *e) { + GB_ASSERT(e != nullptr); + + if (e->token.string == "_") { + GB_PANIC("_ string"); + } + if (e->token.string.len == 0) { + GB_PANIC("empty string"); + } + + if (e->kind == Entity_Variable) { + bool is_foreign = e->Variable.is_foreign; + bool is_export = e->Variable.is_export; + if (e->Variable.link_name.len > 0) { + w = gb_string_append_length(w, e->Variable.link_name.text, e->Variable.link_name.len); + return w; + } else if (is_foreign || is_export) { + w = gb_string_append_length(w, e->token.string.text, e->token.string.len); + return w; + } + } else if (e->kind == Entity_Procedure && e->Procedure.link_name.len > 0) { + w = gb_string_append_length(w, e->Procedure.link_name.text, e->Procedure.link_name.len); + return w; + } else if (e->kind == Entity_Procedure && e->Procedure.is_export) { + w = gb_string_append_length(w, e->token.string.text, e->token.string.len); + return w; + } + + if ((e->scope->flags & (ScopeFlag_File | ScopeFlag_Pkg)) == 0 || + e->flags & EntityFlag_NotExported) { + + Scope *s = e->scope; + while ((s->flags & (ScopeFlag_Proc|ScopeFlag_File)) == 0 && s->decl_info == nullptr) { + s = s->parent; + } + + if (s->decl_info != nullptr && s->decl_info->entity) { + w = write_canonical_parent_prefix(w, s->decl_info->entity); + goto write_base_name; + } else if ((s->flags & ScopeFlag_File) && s->file != nullptr) { + String file_name = filename_without_directory(s->file->fullpath); + w = gb_string_append_length(w, e->pkg->name.text, e->pkg->name.len); + if (e->pkg->name == "llvm") { + gb_string_appendc(w, "$"); + } + w = gb_string_appendc(w, gb_bprintf(".[%.*s].", LIT(file_name))); + goto write_base_name; + } + gb_printf_err("%s HERE %s %u %p\n", token_pos_to_string(e->token.pos), type_to_string(e->type), s->flags, s->decl_info); + print_scope_flags(s); + GB_PANIC("weird entity"); + } + if (e->pkg != nullptr) { + w = gb_string_append_length(w, e->pkg->name.text, e->pkg->name.len); + w = gb_string_appendc(w, "."); + } + +write_base_name: + + switch (e->kind) { + case Entity_TypeName: + { + Type *params = nullptr; + Entity *parent = type_get_polymorphic_parent(e->type, ¶ms); + if (parent) { + w = gb_string_append_length(w, parent->token.string.text, parent->token.string.len); + w = write_canonical_params(w, params); + } else { + w = gb_string_append_length(w, e->token.string.text, e->token.string.len); + } + } + // Handle parapoly stuff here? + return w; + + case Entity_Procedure: + case Entity_Variable: + w = gb_string_append_length(w, e->token.string.text, e->token.string.len); + if (is_type_polymorphic(e->type)) { + w = gb_string_appendc(w, "::"); + w = write_type_to_canonical_string(w, e->type); + } + return w; + + default: + GB_PANIC("TODO(bill): entity kind %d", e->kind); + break; + } + return w; +} + +// NOTE(bill): This exists so that we deterministically hash a type by serializing it to a canonical string +gb_internal gbString write_type_to_canonical_string(gbString w, Type *type) { + if (type == nullptr) { + return gb_string_appendc(w, "<>"); // none/void type + } + + type = default_type(type); + GB_ASSERT(!is_type_untyped(type)); + + switch (type->kind) { + case Type_Basic: + return gb_string_append_length(w, type->Basic.name.text, type->Basic.name.len); + case Type_Pointer: + w = gb_string_append_rune(w, '^'); + return write_type_to_canonical_string(w, type->Pointer.elem); + case Type_MultiPointer: + w = gb_string_appendc(w, "[^]"); + return write_type_to_canonical_string(w, type->Pointer.elem); + case Type_SoaPointer: + w = gb_string_appendc(w, "#soa^"); + return write_type_to_canonical_string(w, type->Pointer.elem); + case Type_EnumeratedArray: + if (type->EnumeratedArray.is_sparse) { + w = gb_string_appendc(w, "#sparse"); + } + w = gb_string_append_rune(w, '['); + w = write_type_to_canonical_string(w, type->EnumeratedArray.index); + w = gb_string_append_rune(w, ']'); + return write_type_to_canonical_string(w, type->EnumeratedArray.elem); + case Type_Array: + w = gb_string_appendc(w, gb_bprintf("[%lld]", cast(long long)type->Array.count)); + return write_type_to_canonical_string(w, type->Array.elem); + case Type_Slice: + w = gb_string_appendc(w, "[]"); + return write_type_to_canonical_string(w, type->Array.elem); + case Type_DynamicArray: + w = gb_string_appendc(w, "[dynamic]"); + return write_type_to_canonical_string(w, type->DynamicArray.elem); + case Type_SimdVector: + w = gb_string_appendc(w, gb_bprintf("#simd[%lld]", cast(long long)type->SimdVector.count)); + return write_type_to_canonical_string(w, type->SimdVector.elem); + case Type_Matrix: + if (type->Matrix.is_row_major) { + w = gb_string_appendc(w, "#row_major "); + } + w = gb_string_appendc(w, gb_bprintf("matrix[%lld, %lld]", cast(long long)type->Matrix.row_count, cast(long long)type->Matrix.column_count)); + return write_type_to_canonical_string(w, type->Matrix.elem); + case Type_Map: + w = gb_string_appendc(w, "map["); + w = write_type_to_canonical_string(w, type->Map.key); + w = gb_string_appendc(w, "]"); + return write_type_to_canonical_string(w, type->Map.value); + + case Type_Enum: + w = gb_string_appendc(w, "enum"); + if (type->Enum.base_type != nullptr) { + w = gb_string_append_rune(w, ' '); + w = write_type_to_canonical_string(w, type->Enum.base_type); + w = gb_string_append_rune(w, ' '); + } + w = gb_string_append_rune(w, '{'); + for_array(i, type->Enum.fields) { + Entity *f = type->Enum.fields[i]; + GB_ASSERT(f->kind == Entity_Constant); + if (i > 0) { + w = gb_string_appendc(w, ","); + } + w = gb_string_append_length(w, f->token.string.text, f->token.string.len); + w = gb_string_appendc(w, "="); + w = write_exact_value_to_string(w, f->Constant.value); + } + return gb_string_append_rune(w, '}'); + case Type_BitSet: + w = gb_string_appendc(w, "bit_set["); + if (type->BitSet.elem == nullptr) { + w = write_type_to_canonical_string(w, type->BitSet.elem); + } else if (is_type_enum(type->BitSet.elem)) { + w = write_type_to_canonical_string(w, type->BitSet.elem); + } else { + w = gb_string_append_fmt(w, "%lld", type->BitSet.lower); + w = gb_string_append_fmt(w, "..="); + w = gb_string_append_fmt(w, "%lld", type->BitSet.upper); + } + if (type->BitSet.underlying != nullptr) { + w = gb_string_appendc(w, ";"); + w = write_type_to_canonical_string(w, type->BitSet.underlying); + } + return gb_string_appendc(w, "]"); + + case Type_Union: + w = gb_string_appendc(w, "union"); + + switch (type->Union.kind) { + case UnionType_no_nil: w = gb_string_appendc(w, "#no_nil"); break; + case UnionType_shared_nil: w = gb_string_appendc(w, "#shared_nil"); break; + } + if (type->Union.custom_align != 0) { + w = gb_string_append_fmt(w, "#align(%lld)", cast(long long)type->Union.custom_align); + } + w = gb_string_appendc(w, "{"); + for_array(i, type->Union.variants) { + Type *t = type->Union.variants[i]; + if (i > 0) w = gb_string_appendc(w, ", "); + w = write_type_to_canonical_string(w, t); + } + return gb_string_appendc(w, "}"); + case Type_Struct: + if (type->Struct.soa_kind != StructSoa_None) { + switch (type->Struct.soa_kind) { + case StructSoa_Fixed: w = gb_string_append_fmt(w, "#soa[%lld]", cast(long long)type->Struct.soa_count); break; + case StructSoa_Slice: w = gb_string_appendc(w, "#soa[]"); break; + case StructSoa_Dynamic: w = gb_string_appendc(w, "#soa[dynamic]"); break; + default: GB_PANIC("Unknown StructSoaKind"); break; + } + return write_type_to_canonical_string(w, type->Struct.soa_elem); + } + + w = gb_string_appendc(w, "struct"); + if (type->Struct.is_packed) w = gb_string_appendc(w, "#packed"); + if (type->Struct.is_raw_union) w = gb_string_appendc(w, "#raw_union"); + if (type->Struct.is_no_copy) w = gb_string_appendc(w, "#no_copy"); + if (type->Struct.custom_min_field_align != 0) w = gb_string_append_fmt(w, "#min_field_align(%lld)", cast(long long)type->Struct.custom_min_field_align); + if (type->Struct.custom_max_field_align != 0) w = gb_string_append_fmt(w, "#max_field_align(%lld)", cast(long long)type->Struct.custom_max_field_align); + if (type->Struct.custom_align != 0) w = gb_string_append_fmt(w, "#align(%lld)", cast(long long)type->Struct.custom_align); + w = gb_string_appendc(w, "{"); + for_array(i, type->Struct.fields) { + Entity *f = type->Struct.fields[i]; + GB_ASSERT(f->kind == Entity_Variable); + if (i > 0) { + w = gb_string_appendc(w, ","); + } + w = gb_string_append_length (w, f->token.string.text, f->token.string.len); + w = gb_string_appendc (w, ":"); + w = write_type_to_canonical_string(w, f->type); + String tag = type->Struct.tags[i]; + if (tag.len != 0) { + String s = quote_to_ascii(heap_allocator(), tag); + w = gb_string_append_length(w, s.text, s.len); + gb_free(heap_allocator(), s.text); + } + } + return gb_string_appendc(w, "}"); + + case Type_BitField: + w = gb_string_appendc(w, "bit_field"); + w = write_type_to_canonical_string(w, type->BitField.backing_type); + w = gb_string_appendc(w, " {"); + for (isize i = 0; i < type->BitField.fields.count; i++) { + Entity *f = type->BitField.fields[i]; + if (i > 0) { + w = gb_string_appendc(w, ","); + } + w = gb_string_append_length(w, f->token.string.text, f->token.string.len); + w = gb_string_appendc(w, ":"); + w = write_type_to_canonical_string(w, f->type); + w = gb_string_appendc(w, "|"); + w = gb_string_appendc(w, gb_bprintf("%u", type->BitField.bit_sizes[i])); + } + return gb_string_appendc(w, " }"); + + case Type_Proc: + w = gb_string_appendc(w, "proc"); + if (default_calling_convention() != type->Proc.calling_convention) { + w = gb_string_appendc(w, "\""); + w = gb_string_appendc(w, proc_calling_convention_strings[type->Proc.calling_convention]); + w = gb_string_appendc(w, "\""); + } + + w = write_canonical_params(w, type->Proc.params); + if (type->Proc.result_count > 0) { + w = gb_string_appendc(w, "->"); + w = write_canonical_params(w, type->Proc.results); + } + return w; + + case Type_Generic: + GB_PANIC("Type_Generic should never be hit"); + return w; + + case Type_Named: + if (type->Named.type_name != nullptr) { + return write_canonical_entity_name(w, type->Named.type_name); + } else { + w = gb_string_append_length(w, type->Named.name.text, type->Named.name.len); + } + // Handle parapoly stuff here? + return w; + + default: + GB_PANIC("unknown type kind %d", type->kind); + break; + } + + return w; +} \ No newline at end of file diff --git a/src/types.cpp b/src/types.cpp index 42530eccc..d6dea56ad 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -4872,272 +4872,3 @@ gb_internal gbString type_to_string(Type *type, bool shorthand) { gb_internal gbString type_to_string_shorthand(Type *type) { return type_to_string(type, true); } - -gb_internal gbString write_type_to_canonical_string(gbString w, Type *type); -gb_internal gbString write_canonical_params(gbString w, Type *params) { - w = gb_string_appendc(w, "("); - if (params) { - GB_ASSERT(params->kind == Type_Tuple); - for_array(i, params->Tuple.variables) { - Entity *v = params->Tuple.variables[i]; - if (i > 0) { - w = gb_string_appendc(w, ","); - } - if (v->kind == Entity_Variable) { - if (v->flags&EntityFlag_CVarArg) { - w = gb_string_appendc(w, "#c_vararg"); - } - if (v->flags&EntityFlag_Ellipsis) { - Type *slice = base_type(v->type); - w = gb_string_appendc(w, ".."); - GB_ASSERT(v->type->kind == Type_Slice); - w = write_type_to_canonical_string(w, slice->Slice.elem); - } else { - w = write_type_to_canonical_string(w, v->type); - } - } else if (v->kind == Entity_TypeName) { - w = gb_string_appendc(w, "$"); - w = write_type_to_canonical_string(w, v->type); - } else if (v->kind == Entity_Constant) { - w = gb_string_appendc(w, "$$"); - w = write_exact_value_to_string(w, v->Constant.value); - } else { - GB_PANIC("TODO(bill): handle non type/const parapoly parameter values"); - } - } - } - return gb_string_appendc(w, ")"); -} - -gb_internal u64 type_hash_canonical_type(Type *type) { - if (type == nullptr) { - return 0; - } - TEMPORARY_ALLOCATOR_GUARD(); - gbString w = write_type_to_canonical_string(gb_string_make(temporary_allocator(), ""), type); - u64 hash = fnv64a(w, gb_string_length(w)); - return hash; -} - -gb_internal String type_to_canonical_string(gbAllocator allocator, Type *type) { - gbString w = gb_string_make(allocator, ""); - w = write_type_to_canonical_string(w, type); - return make_string(cast(u8 const *)w, gb_string_length(w)); -} - -// NOTE(bill): This exists so that we deterministically hash a type by serializing it to a canonical string -gb_internal gbString write_type_to_canonical_string(gbString w, Type *type) { - if (type == nullptr) { - return gb_string_appendc(w, "<>"); // none/void type - } - - type = default_type(type); - GB_ASSERT(!is_type_untyped(type)); - - switch (type->kind) { - case Type_Basic: - return gb_string_append_length(w, type->Basic.name.text, type->Basic.name.len); - case Type_Pointer: - w = gb_string_append_rune(w, '^'); - return write_type_to_canonical_string(w, type->Pointer.elem); - case Type_MultiPointer: - w = gb_string_appendc(w, "[^]"); - return write_type_to_canonical_string(w, type->Pointer.elem); - case Type_SoaPointer: - w = gb_string_appendc(w, "#soa^"); - return write_type_to_canonical_string(w, type->Pointer.elem); - case Type_EnumeratedArray: - if (type->EnumeratedArray.is_sparse) { - w = gb_string_appendc(w, "#sparse"); - } - w = gb_string_append_rune(w, '['); - w = write_type_to_canonical_string(w, type->EnumeratedArray.index); - w = gb_string_append_rune(w, ']'); - return write_type_to_canonical_string(w, type->EnumeratedArray.elem); - case Type_Array: - w = gb_string_appendc(w, gb_bprintf("[%lld]", cast(long long)type->Array.count)); - return write_type_to_canonical_string(w, type->Array.elem); - case Type_Slice: - w = gb_string_appendc(w, "[]"); - return write_type_to_canonical_string(w, type->Array.elem); - case Type_DynamicArray: - w = gb_string_appendc(w, "[dynamic]"); - return write_type_to_canonical_string(w, type->DynamicArray.elem); - case Type_SimdVector: - w = gb_string_appendc(w, gb_bprintf("#simd[%lld]", cast(long long)type->SimdVector.count)); - return write_type_to_canonical_string(w, type->SimdVector.elem); - case Type_Matrix: - if (type->Matrix.is_row_major) { - w = gb_string_appendc(w, "#row_major "); - } - w = gb_string_appendc(w, gb_bprintf("matrix[%lld, %lld]", cast(long long)type->Matrix.row_count, cast(long long)type->Matrix.column_count)); - return write_type_to_canonical_string(w, type->Matrix.elem); - case Type_Map: - w = gb_string_appendc(w, "map["); - w = write_type_to_canonical_string(w, type->Map.key); - w = gb_string_appendc(w, "]"); - return write_type_to_canonical_string(w, type->Map.value); - - case Type_Enum: - w = gb_string_appendc(w, "enum"); - if (type->Enum.base_type != nullptr) { - w = gb_string_append_rune(w, ' '); - w = write_type_to_canonical_string(w, type->Enum.base_type); - w = gb_string_append_rune(w, ' '); - } - w = gb_string_append_rune(w, '{'); - for_array(i, type->Enum.fields) { - Entity *f = type->Enum.fields[i]; - GB_ASSERT(f->kind == Entity_Constant); - if (i > 0) { - w = gb_string_appendc(w, ","); - } - w = gb_string_append_length(w, f->token.string.text, f->token.string.len); - w = gb_string_appendc(w, "="); - w = write_exact_value_to_string(w, f->Constant.value); - } - return gb_string_append_rune(w, '}'); - case Type_BitSet: - w = gb_string_appendc(w, "bit_set["); - if (type->BitSet.elem == nullptr) { - w = write_type_to_canonical_string(w, type->BitSet.elem); - } else if (is_type_enum(type->BitSet.elem)) { - w = write_type_to_canonical_string(w, type->BitSet.elem); - } else { - w = gb_string_append_fmt(w, "%lld", type->BitSet.lower); - w = gb_string_append_fmt(w, "..="); - w = gb_string_append_fmt(w, "%lld", type->BitSet.upper); - } - if (type->BitSet.underlying != nullptr) { - w = gb_string_appendc(w, ";"); - w = write_type_to_canonical_string(w, type->BitSet.underlying); - } - return gb_string_appendc(w, "]"); - - case Type_Union: - w = gb_string_appendc(w, "union"); - - switch (type->Union.kind) { - case UnionType_no_nil: w = gb_string_appendc(w, "#no_nil"); break; - case UnionType_shared_nil: w = gb_string_appendc(w, "#shared_nil"); break; - } - if (type->Union.custom_align != 0) { - w = gb_string_append_fmt(w, "#align(%lld)", cast(long long)type->Union.custom_align); - } - w = gb_string_appendc(w, "{"); - for_array(i, type->Union.variants) { - Type *t = type->Union.variants[i]; - if (i > 0) w = gb_string_appendc(w, ", "); - w = write_type_to_canonical_string(w, t); - } - return gb_string_appendc(w, "}"); - case Type_Struct: - if (type->Struct.soa_kind != StructSoa_None) { - switch (type->Struct.soa_kind) { - case StructSoa_Fixed: w = gb_string_append_fmt(w, "#soa[%lld]", cast(long long)type->Struct.soa_count); break; - case StructSoa_Slice: w = gb_string_appendc(w, "#soa[]"); break; - case StructSoa_Dynamic: w = gb_string_appendc(w, "#soa[dynamic]"); break; - default: GB_PANIC("Unknown StructSoaKind"); break; - } - return write_type_to_canonical_string(w, type->Struct.soa_elem); - } - - w = gb_string_appendc(w, "struct"); - if (type->Struct.is_packed) w = gb_string_appendc(w, "#packed"); - if (type->Struct.is_raw_union) w = gb_string_appendc(w, "#raw_union"); - if (type->Struct.is_no_copy) w = gb_string_appendc(w, "#no_copy"); - if (type->Struct.custom_min_field_align != 0) w = gb_string_append_fmt(w, "#min_field_align(%lld)", cast(long long)type->Struct.custom_min_field_align); - if (type->Struct.custom_max_field_align != 0) w = gb_string_append_fmt(w, "#max_field_align(%lld)", cast(long long)type->Struct.custom_max_field_align); - if (type->Struct.custom_align != 0) w = gb_string_append_fmt(w, "#align(%lld)", cast(long long)type->Struct.custom_align); - w = gb_string_appendc(w, "{"); - for_array(i, type->Struct.fields) { - Entity *f = type->Struct.fields[i]; - GB_ASSERT(f->kind == Entity_Variable); - if (i > 0) { - w = gb_string_appendc(w, ","); - } - w = gb_string_append_length (w, f->token.string.text, f->token.string.len); - w = gb_string_appendc (w, ":"); - w = write_type_to_canonical_string(w, f->type); - String tag = type->Struct.tags[i]; - if (tag.len != 0) { - String s = quote_to_ascii(heap_allocator(), tag); - w = gb_string_append_length(w, s.text, s.len); - gb_free(heap_allocator(), s.text); - } - } - return gb_string_appendc(w, "}"); - - case Type_BitField: - w = gb_string_appendc(w, "bit_field"); - w = write_type_to_canonical_string(w, type->BitField.backing_type); - w = gb_string_appendc(w, " {"); - for (isize i = 0; i < type->BitField.fields.count; i++) { - Entity *f = type->BitField.fields[i]; - if (i > 0) { - w = gb_string_appendc(w, ","); - } - w = gb_string_append_length(w, f->token.string.text, f->token.string.len); - w = gb_string_appendc(w, ":"); - w = write_type_to_canonical_string(w, f->type); - w = gb_string_appendc(w, "|"); - w = gb_string_appendc(w, gb_bprintf("%u", type->BitField.bit_sizes[i])); - } - return gb_string_appendc(w, " }"); - - case Type_Proc: - w = gb_string_appendc(w, "proc"); - if (default_calling_convention() != type->Proc.calling_convention) { - w = gb_string_appendc(w, "\""); - w = gb_string_appendc(w, proc_calling_convention_strings[type->Proc.calling_convention]); - w = gb_string_appendc(w, "\""); - } - - w = write_canonical_params(w, type->Proc.params); - if (type->Proc.result_count > 0) { - w = gb_string_appendc(w, "->"); - w = write_canonical_params(w, type->Proc.results); - } - return w; - - case Type_Generic: - GB_PANIC("Type_Generic should never be hit"); - return w; - - case Type_Named: - if (type->Named.type_name != nullptr) { - Entity *e = type->Named.type_name; - - if ((e->scope->flags & (ScopeFlag_File | ScopeFlag_Pkg)) == 0 || - e->flags & EntityFlag_NotExported) { - if (e->scope->flags & ScopeFlag_Proc) { - GB_PANIC("NESTED IN PROC\n"); - } else if (e->scope->flags & ScopeFlag_File) { - GB_PANIC("PRIVATE TO FILE\n"); - } - } - if (e->pkg != nullptr) { - w = gb_string_append_length(w, e->pkg->name.text, e->pkg->name.len); - w = gb_string_appendc(w, "."); - } - Type *params = nullptr; - Entity *parent = type_get_polymorphic_parent(type, ¶ms); - if (parent) { - w = gb_string_append_length(w, parent->token.string.text, parent->token.string.len); - w = write_canonical_params(w, params); - } else { - w = gb_string_append_length(w, e->token.string.text, e->token.string.len); - } - } else { - w = gb_string_append_length(w, type->Named.name.text, type->Named.name.len); - } - // Handle parapoly stuff here? - return w; - - default: - GB_PANIC("unknown type kind %d", type->kind); - break; - } - - return w; -} \ No newline at end of file -- cgit v1.2.3 From 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/checker.cpp') diff --git a/src/checker.cpp b/src/checker.cpp index c74a72a14..054d6aeb0 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -3,7 +3,10 @@ #include "entity.cpp" #include "types.cpp" -String get_final_microarchitecture(); + +gb_internal u64 type_hash_canonical_type(Type *type); + +gb_internal String get_final_microarchitecture(); gb_internal void check_expr(CheckerContext *c, Operand *operand, Ast *expression); gb_internal void check_expr_or_type(CheckerContext *c, Operand *operand, Ast *expression, Type *type_hint=nullptr); @@ -2037,7 +2040,8 @@ gb_internal void add_type_info_type_internal(CheckerContext *c, Type *t) { // Unique entry // NOTE(bill): map entries grow linearly and in order ti_index = c->info->type_info_types.count; - array_add(&c->info->type_info_types, t); + Type_Info_Type tt = {t, type_hash_canonical_type(t)}; + array_add(&c->info->type_info_types, tt); } map_set(&c->checker->info.type_info_map, t, ti_index); @@ -6725,6 +6729,42 @@ gb_internal void check_parsed_files(Checker *c) { add_type_and_value(&c->builtin_ctx, u.expr, u.info->mode, u.info->type, u.info->value); } + TIME_SECTION("check for type hash collisions"); + { + PtrSet found = {}; + ptr_set_init(&found, c->info.type_info_types.count); + defer (ptr_set_destroy(&found)); + for (auto const &tt : c->info.type_info_types) { + if (ptr_set_update(&found, cast(uintptr)tt.hash)) { + Type *other_type = nullptr; + for (auto const &other : c->info.type_info_types) { + if (&tt == &other) { + continue; + } + if (cast(uintptr)other.hash == cast(uintptr)tt.hash && + !are_types_identical(tt.type, other.type)) { + other_type = other.type; + break; + } + } + if (other_type != nullptr) { + String ts = type_to_canonical_string(temporary_allocator(), tt.type); + String os = type_to_canonical_string(temporary_allocator(), other_type); + if (ts != os) { + compiler_error("%s found type hash collision with %s (hash = %llu)\n" + "%s vs %s\n", + type_to_string(tt.type), type_to_string(other_type), cast(unsigned long long)tt.hash, + temp_canonical_string(tt.type), + temp_canonical_string(other_type) + ); + } + } + } + } + } + + + TIME_SECTION("sort init and fini procedures"); check_sort_init_and_fini_procedures(c); diff --git a/src/checker.hpp b/src/checker.hpp index 472ab8e50..c9a0c3302 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -409,6 +409,11 @@ struct Defineable { String pos_str; }; +struct Type_Info_Type { + Type *type; + u64 hash; // see: type_hash_canonical_type +}; + // CheckerInfo stores all the symbol information for a type-checked program struct CheckerInfo { Checker *checker; @@ -453,7 +458,7 @@ struct CheckerInfo { PtrMap gen_types; BlockingMutex type_info_mutex; // NOT recursive - Array type_info_types; + Array type_info_types; PtrMap type_info_map; BlockingMutex foreign_mutex; // NOT recursive diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 0896ea8c7..8cb480dd4 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -24,7 +24,7 @@ #include "llvm_backend_stmt.cpp" #include "llvm_backend_proc.cpp" -String get_default_microarchitecture() { +gb_internal String get_default_microarchitecture() { String default_march = str_lit("generic"); if (build_context.metrics.arch == TargetArch_amd64) { // NOTE(bill): x86-64-v2 is more than enough for everyone @@ -47,7 +47,7 @@ String get_default_microarchitecture() { return default_march; } -String get_final_microarchitecture() { +gb_internal String get_final_microarchitecture() { BuildContext *bc = &build_context; String microarch = bc->microarch; @@ -3182,7 +3182,8 @@ gb_internal bool lb_generate_code(lbGenerator *gen) { isize count = 0; isize offsets_extra = 0; - for (Type *t : m->info->type_info_types) { + for (auto const &tt : m->info->type_info_types) { + Type *t = tt.type; isize index = lb_type_info_index(m->info, t, false); if (index < 0) { continue; diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index 7fdfa0bb2..b9ae3d254 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -1460,8 +1460,6 @@ gb_internal String lb_get_entity_name(lbModule *m, Entity *e) { w = write_canonical_entity_name(w, e); defer (gb_string_free(w)); - gb_printf_err("%s\n", w); - String name = copy_string(permanent_allocator(), make_string(cast(u8 const *)w, gb_string_length(w))); if (e->kind == Entity_TypeName) { diff --git a/src/llvm_backend_type.cpp b/src/llvm_backend_type.cpp index 6c12b37be..6f9f94fbd 100644 --- a/src/llvm_backend_type.cpp +++ b/src/llvm_backend_type.cpp @@ -12,7 +12,7 @@ gb_internal isize lb_type_info_index(CheckerInfo *info, Type *type, bool err_on_ gb_printf_err("NOT FOUND lb_type_info_index:\n\t%s\n\t@ index %td\n\tmax count: %u\nFound:\n", type_to_string(type), index, set->count); for (auto const &entry : *set) { isize type_info_index = entry.key; - gb_printf_err("\t%s\n", type_to_string(info->type_info_types[type_info_index])); + gb_printf_err("\t%s\n", type_to_string(info->type_info_types[type_info_index].type)); } GB_PANIC("NOT FOUND"); } @@ -280,7 +280,7 @@ gb_internal void lb_setup_type_info_data_giant_array(lbModule *m, i64 global_typ LLVMTypeRef *modified_types = lb_setup_modified_types_for_type_info(m, global_type_info_data_entity_count); defer (gb_free(heap_allocator(), modified_types)); for_array(type_info_type_index, info->type_info_types) { - Type *t = info->type_info_types[type_info_type_index]; + Type *t = info->type_info_types[type_info_type_index].type; if (t == nullptr || t == t_invalid) { continue; } @@ -343,7 +343,7 @@ gb_internal void lb_setup_type_info_data_giant_array(lbModule *m, i64 global_typ }; for_array(type_info_type_index, info->type_info_types) { - Type *t = info->type_info_types[type_info_type_index]; + Type *t = info->type_info_types[type_info_type_index].type; if (t == nullptr || t == t_invalid) { continue; } diff --git a/src/name_canonicalization.cpp b/src/name_canonicalization.cpp index 3910c573d..8edb5e968 100644 --- a/src/name_canonicalization.cpp +++ b/src/name_canonicalization.cpp @@ -7,7 +7,7 @@ * builtin names - just their normal name e.g. `i32` or `string` * nested - pkg.parent1.parent2.name * file private - pkg.[file_name].name - * Example: `foo.[bar.odin].Type` + * Example: `pkg.[file.odin].Type` * polymorphic procedure/type - pkg.foo::TYPE * naming convention for parameters * type @@ -15,7 +15,7 @@ * $$constant_parameter * Example: `foo.to_thing::proc(u64)->([]u8)` * nested decl in polymorphic procedure - pkg.foo::TYPE.name - * anonymous procedures - pkg.foo.$anon123 + * anonymous procedures - pkg.foo.$anon[file.odin:123] * 123 is the file offset in bytes @@ -38,7 +38,12 @@ #define CANONICAL_NONE_TYPE "<>" + gb_internal gbString write_type_to_canonical_string(gbString w, Type *type); +gb_internal u64 type_hash_canonical_type(Type *type); +gb_internal String type_to_canonical_string(gbAllocator allocator, Type *type); +gb_internal gbString temp_canonical_string(Type *type); + gb_internal gbString write_canonical_params(gbString w, Type *params) { w = gb_string_appendc(w, "("); if (params) { @@ -81,7 +86,7 @@ gb_internal u64 type_hash_canonical_type(Type *type) { TEMPORARY_ALLOCATOR_GUARD(); gbString w = write_type_to_canonical_string(gb_string_make(temporary_allocator(), ""), type); u64 hash = fnv64a(w, gb_string_length(w)); - return hash; + return hash ? hash : 1; } gb_internal String type_to_canonical_string(gbAllocator allocator, Type *type) { @@ -90,6 +95,11 @@ gb_internal String type_to_canonical_string(gbAllocator allocator, Type *type) { return make_string(cast(u8 const *)w, gb_string_length(w)); } +gb_internal gbString temp_canonical_string(Type *type) { + gbString w = gb_string_make(temporary_allocator(), ""); + return write_type_to_canonical_string(w, type); +} + gb_internal void print_scope_flags(Scope *s) { if (s->flags & ScopeFlag_Pkg) gb_printf_err("Pkg "); if (s->flags & ScopeFlag_Builtin) gb_printf_err("Builtin "); @@ -156,7 +166,8 @@ gb_internal gbString write_canonical_parent_prefix(gbString w, Entity *e, bool i } if (e->kind == Entity_Procedure && e->Procedure.is_anonymous) { - w = gb_string_appendc(w, gb_bprintf(CANONICAL_ANON_PREFIX "%d", e->token.pos.offset)); + String file_name = filename_without_directory(e->file->fullpath); + w = gb_string_appendc(w, gb_bprintf(CANONICAL_ANON_PREFIX "[%.*s:%d]", LIT(file_name), e->token.pos.offset)); } else { w = gb_string_append_length(w, e->token.string.text, e->token.string.len); } @@ -449,8 +460,12 @@ gb_internal gbString write_type_to_canonical_string(gbString w, Type *type) { } return w; + case Type_Tuple: + w = gb_string_appendc(w, "params"); + w = write_canonical_params(w, type); + return w; default: - GB_PANIC("unknown type kind %d", type->kind); + GB_PANIC("unknown type kind %d %.*s", type->kind, LIT(type_strings[type->kind])); break; } diff --git a/src/ptr_set.cpp b/src/ptr_set.cpp index ff4befc37..5097e2bb6 100644 --- a/src/ptr_set.cpp +++ b/src/ptr_set.cpp @@ -42,7 +42,7 @@ gb_internal void ptr_set_destroy(PtrSet *s) { template gb_internal isize ptr_set__find(PtrSet *s, T ptr) { - GB_ASSERT(ptr != nullptr); + GB_ASSERT(ptr != 0); if (s->count != 0) { #if 0 for (usize i = 0; i < s->capacity; i++) { @@ -58,7 +58,7 @@ gb_internal isize ptr_set__find(PtrSet *s, T ptr) { T key = s->keys[hash_index]; if (key == ptr) { return hash_index; - } else if (key == nullptr) { + } else if (key == 0) { return -1; } hash_index = (hash_index+1)&mask; @@ -122,7 +122,7 @@ gb_internal bool ptr_set_update(PtrSet *s, T ptr) { // returns true if it pre for (usize i = 0; i < s->capacity; i++) { T *key = &s->keys[hash_index]; GB_ASSERT(*key != ptr); - if (*key == (T)PtrSet::TOMBSTONE || *key == nullptr) { + if (*key == (T)PtrSet::TOMBSTONE || *key == 0) { *key = ptr; s->count++; return false; @@ -169,7 +169,7 @@ struct PtrSetIterator { return *this; } T key = set->keys[index]; - if (key != nullptr && key != (T)PtrSet::TOMBSTONE) { + if (key != 0 && key != (T)PtrSet::TOMBSTONE) { return *this; } } @@ -191,7 +191,7 @@ gb_internal PtrSetIterator begin(PtrSet &set) noexcept { usize index = 0; while (index < set.capacity) { T key = set.keys[index]; - if (key != nullptr && key != (T)PtrSet::TOMBSTONE) { + if (key != 0 && key != (T)PtrSet::TOMBSTONE) { break; } index++; diff --git a/src/types.cpp b/src/types.cpp index d6dea56ad..15e1bcf45 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -2774,7 +2774,37 @@ gb_internal bool are_types_identical_internal(Type *x, Type *y, bool check_tuple case Type_Enum: - return x == y; // NOTE(bill): All enums are unique + if (x == y) { + return true; + } + if (x->Enum.fields.count != y->Enum.fields.count) { + return false; + } + if (!are_types_identical(x->Enum.base_type, y->Enum.base_type)) { + return false; + } + if (x->Enum.min_value_index != y->Enum.min_value_index) { + return false; + } + if (x->Enum.max_value_index != y->Enum.max_value_index) { + return false; + } + + for (isize i = 0; i < x->Enum.fields.count; i++) { + Entity *a = x->Enum.fields[i]; + Entity *b = y->Enum.fields[i]; + if (a->token.string != b->token.string) { + return false; + } + GB_ASSERT(a->kind == b->kind); + GB_ASSERT(a->kind == Entity_Constant); + bool same = compare_exact_values(Token_CmpEq, a->Constant.value, b->Constant.value); + if (!same) { + return false; + } + } + + return true; case Type_Union: if (x->Union.variants.count == y->Union.variants.count && @@ -2832,7 +2862,9 @@ gb_internal bool are_types_identical_internal(Type *x, Type *y, bool check_tuple return false; } } - return are_types_identical(x->Struct.polymorphic_params, y->Struct.polymorphic_params); + // TODO(bill): Which is the correct logic here? + // return are_types_identical(x->Struct.polymorphic_params, y->Struct.polymorphic_params); + return true; } break; -- cgit v1.2.3 From 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/checker.cpp') 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/checker.cpp') 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/checker.cpp') 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/checker.cpp') 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/checker.cpp') 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 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/checker.cpp') 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 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/checker.cpp') 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 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/checker.cpp') 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 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/checker.cpp') 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 55317b0987a7f197db3e50e13d67fd3bd6afee05 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 6 Mar 2025 11:15:27 +0000 Subject: Fix #4914 --- src/checker.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src/checker.cpp') diff --git a/src/checker.cpp b/src/checker.cpp index bee3f1efe..9d822073f 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -2645,6 +2645,10 @@ gb_internal void generate_minimum_dependency_set_internal(Checker *c, Entity *st is_init = false; } + if (is_blank_ident(e->token)) { + error(e->token, "An @(init) procedure must not use a blank identifier as its name"); + } + if (is_init) { add_dependency_to_set(c, e); array_add(&c->info.init_procedures, e); @@ -2667,6 +2671,10 @@ gb_internal void generate_minimum_dependency_set_internal(Checker *c, Entity *st is_fini = false; } + if (is_blank_ident(e->token)) { + error(e->token, "An @(fini) procedure must not use a blank identifier as its name"); + } + if (is_fini) { add_dependency_to_set(c, e); array_add(&c->info.fini_procedures, e); -- cgit v1.2.3 From e6718fcfcc979cedcdb01294003431519e7785f3 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 26 Mar 2025 13:09:39 +0000 Subject: Very very rudimentary support for `-target:linux_arm64 -subtarget:android` --- src/build_settings.cpp | 39 +++++++++++- src/checker.cpp | 1 + src/linker.cpp | 167 ++++++++++++++++++++++++++++++++++++++++++++++--- src/main.cpp | 5 +- 4 files changed, 199 insertions(+), 13 deletions(-) (limited to 'src/checker.cpp') diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 6bee10674..30e29ab73 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -171,6 +171,7 @@ struct TargetMetrics { enum Subtarget : u32 { Subtarget_Default, Subtarget_iOS, + Subtarget_Android, Subtarget_COUNT, }; @@ -178,6 +179,7 @@ enum Subtarget : u32 { gb_global String subtarget_strings[Subtarget_COUNT] = { str_lit(""), str_lit("ios"), + str_lit("android"), }; @@ -946,6 +948,14 @@ gb_internal bool is_arch_x86(void) { gb_global String const WIN32_SEPARATOR_STRING = {cast(u8 *)"\\", 1}; gb_global String const NIX_SEPARATOR_STRING = {cast(u8 *)"/", 1}; +gb_global String const SEPARATOR_STRING = +#if defined(GB_SYSTEM_WINDOWS) + WIN32_SEPARATOR_STRING; +#else + NIX_SEPARATOR_STRING; +#endif + + gb_global String const WASM_MODULE_NAME_SEPARATOR = str_lit(".."); gb_internal String internal_odin_root_dir(void); @@ -1652,6 +1662,15 @@ gb_internal void init_build_context(TargetMetrics *cross_target, Subtarget subta default: GB_PANIC("Unknown architecture for darwin"); } + } else if (metrics->os == TargetOs_linux && subtarget == Subtarget_Android) { + switch (metrics->arch) { + case TargetArch_arm64: + bc->metrics.target_triplet = str_lit("aarch64-none-linux-android"); + bc->reloc_mode = RelocMode_PIC; + break; + default: + GB_PANIC("Unknown architecture for darwin"); + } } if (bc->metrics.os == TargetOs_windows) { @@ -1749,6 +1768,22 @@ gb_internal void init_build_context(TargetMetrics *cross_target, Subtarget subta if (bc->metrics.os == TargetOs_freestanding) { bc->ODIN_DEFAULT_TO_NIL_ALLOCATOR = !bc->ODIN_DEFAULT_TO_PANIC_ALLOCATOR; } + + if (subtarget == Subtarget_Android) { + switch (build_context.build_mode) { + case BuildMode_DynamicLibrary: + break; + case BuildMode_Executable: + case BuildMode_StaticLibrary: + case BuildMode_Object: + case BuildMode_Assembly: + case BuildMode_LLVM_IR: + gb_printf_err("Unsupported -build-mode for -target:android\n"); + gb_printf_err("\tCurrently only supporting -build-mode:shared\n"); + gb_exit(1); + break; + } + } } #if defined(GB_SYSTEM_WINDOWS) @@ -1947,7 +1982,9 @@ gb_internal bool init_build_paths(String init_filename) { output_extension = make_string(nullptr, 0); String const single_file_extension = str_lit(".odin"); - if (build_context.metrics.os == TargetOs_windows) { + if (selected_subtarget == Subtarget_Android) { + output_extension = STR_LIT("bin"); + } else if (build_context.metrics.os == TargetOs_windows) { output_extension = STR_LIT("exe"); } else if (build_context.cross_compiling && selected_target_metrics->metrics == &target_essence_amd64) { // Do nothing: we don't want the .bin extension diff --git a/src/checker.cpp b/src/checker.cpp index 9d822073f..c44c6ce5b 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -1149,6 +1149,7 @@ gb_internal void init_universal(void) { GlobalEnumValue values[Subtarget_COUNT] = { {"Default", Subtarget_Default}, {"iOS", Subtarget_iOS}, + {"Android", Subtarget_Android}, }; auto fields = add_global_enum_type(str_lit("Odin_Platform_Subtarget_Type"), values, gb_count_of(values)); diff --git a/src/linker.cpp b/src/linker.cpp index 1568d049e..5e2720eeb 100644 --- a/src/linker.cpp +++ b/src/linker.cpp @@ -130,6 +130,9 @@ gb_internal i32 linker_stage(LinkerData *gen) { return result; } + bool is_cross_linking = false; + bool is_android = false; + if (build_context.cross_compiling && selected_target_metrics->metrics == &target_essence_amd64) { #if defined(GB_SYSTEM_UNIX) result = system_exec_command_line_app("linker", "x86_64-essence-gcc \"%.*s.o\" -o \"%.*s\" %.*s %.*s", @@ -141,12 +144,22 @@ gb_internal i32 linker_stage(LinkerData *gen) { ); #endif } else if (build_context.cross_compiling && build_context.different_os) { - gb_printf_err("Linking for cross compilation for this platform is not yet supported (%.*s %.*s)\n", - LIT(target_os_names[build_context.metrics.os]), - LIT(target_arch_names[build_context.metrics.arch]) - ); - build_context.keep_object_files = true; + switch (selected_subtarget) { + case Subtarget_Android: + is_cross_linking = true; + is_android = true; + goto try_cross_linking; + default: + gb_printf_err("Linking for cross compilation for this platform is not yet supported (%.*s %.*s)\n", + LIT(target_os_names[build_context.metrics.os]), + LIT(target_arch_names[build_context.metrics.arch]) + ); + build_context.keep_object_files = true; + break; + } } else { +try_cross_linking:; + #if defined(GB_SYSTEM_WINDOWS) bool is_windows = build_context.metrics.os == TargetOs_windows; #else @@ -155,6 +168,7 @@ gb_internal i32 linker_stage(LinkerData *gen) { bool is_osx = build_context.metrics.os == TargetOs_darwin; + if (is_windows) { String section_name = str_lit("msvc-link"); switch (build_context.linker_choice) { @@ -404,6 +418,44 @@ gb_internal i32 linker_stage(LinkerData *gen) { } else { timings_start_section(timings, str_lit("ld-link")); + String ODIN_ANDROID_NDK_PATH = normalize_path(permanent_allocator(), make_string_c(gb_get_env("ODIN_ANDROID_NDK_PATH", permanent_allocator())), NIX_SEPARATOR_STRING); + String ODIN_ANDROID_NDK_TOOLCHAIN_PATH = normalize_path(permanent_allocator(), make_string_c(gb_get_env("ODIN_ANDROID_NDK_TOOLCHAIN_PATH", permanent_allocator())), NIX_SEPARATOR_STRING); + + int ODIN_ANDROID_API_LEVEL = 34; + if (char const *found = gb_get_env("ODIN_ANDROID_API_LEVEL", permanent_allocator())) { + int new_level = atoi(found); + if (new_level >= 34) { + ODIN_ANDROID_API_LEVEL = new_level; + } else { + gb_printf_err("Warning: Invalid ODIN_ANDROID_API_LEVEL '%s', defaulting to %d\n", found, ODIN_ANDROID_API_LEVEL); + } + } + + String ODIN_ANDROID_NDK_TOOLCHAIN_LIB_PATH = {}; + String ODIN_ANDROID_NDK_TOOLCHAIN_LIB_LEVEL_PATH = {}; + String ODIN_ANDROID_NDK_TOOLCHAIN_SYSROOT_PATH = {}; + + if (is_android) { + if (ODIN_ANDROID_NDK_PATH.len == 0) { + gb_printf_err("Error: ODIN_ANDROID_NDK_PATH not set"); + return 1; + } + + if (ODIN_ANDROID_NDK_TOOLCHAIN_PATH.len == 0) { + gb_printf_err("Error: ODIN_ANDROID_NDK_PATH not set"); + return 1; + } + + ODIN_ANDROID_NDK_TOOLCHAIN_LIB_PATH = concatenate_strings(permanent_allocator(), ODIN_ANDROID_NDK_TOOLCHAIN_PATH, str_lit("sysroot/usr/lib/aarch64-linux-android/")); + + char buf[32] = {}; + gb_snprintf(buf, gb_size_of(buf), "%d/", ODIN_ANDROID_API_LEVEL); + ODIN_ANDROID_NDK_TOOLCHAIN_LIB_LEVEL_PATH = concatenate_strings(permanent_allocator(), ODIN_ANDROID_NDK_TOOLCHAIN_LIB_PATH, make_string_c(buf)); + + ODIN_ANDROID_NDK_TOOLCHAIN_SYSROOT_PATH = concatenate_strings(permanent_allocator(), ODIN_ANDROID_NDK_TOOLCHAIN_PATH, str_lit("sysroot/")); + } + + // Link using `clang`, unless overridden by `ODIN_CLANG_PATH` environment variable. const char* clang_path = gb_get_env("ODIN_CLANG_PATH", permanent_allocator()); if (clang_path == NULL) { @@ -412,8 +464,11 @@ gb_internal i32 linker_stage(LinkerData *gen) { // NOTE(vassvik): needs to add the root to the library search paths, so that the full filenames of the library // files can be passed with -l: - gbString lib_str = gb_string_make(heap_allocator(), "-L/"); + gbString lib_str = gb_string_make(heap_allocator(), ""); defer (gb_string_free(lib_str)); + #if !defined(GB_SYSTEM_WINDOWS) + lib_str = gb_string_appendc(lib_str, "-L/ "); + #endif StringSet asm_files = {}; string_set_init(&asm_files, 64); @@ -602,6 +657,74 @@ gb_internal i32 linker_stage(LinkerData *gen) { gbString object_files = gb_string_make(heap_allocator(), ""); defer (gb_string_free(object_files)); + + + if (is_android) { // NOTE(bill): glue code needed for Android + String android_glue_object = {}; + String android_glue_static_lib = {}; + + char hash_buf[64] = {}; + gb_snprintf(hash_buf, gb_size_of(hash_buf), "%p", &hash_buf); + String hash = make_string_c(hash_buf); + + String temp_dir = normalize_path(temporary_allocator(), temporary_directory(temporary_allocator()), NIX_SEPARATOR_STRING); + android_glue_object = concatenate4_strings(temporary_allocator(), temp_dir, str_lit("android_native_app_glue-"), hash, str_lit(".o")); + android_glue_static_lib = concatenate4_strings(permanent_allocator(), temp_dir, str_lit("libandroid_native_app_glue-"), hash, str_lit(".a")); + + gbString glue = gb_string_make(heap_allocator(), clang_path); + defer (gb_string_free(glue)); + + glue = gb_string_append_fmt(glue, " --target=aarch64-linux-android%d ", ODIN_ANDROID_API_LEVEL); + glue = gb_string_appendc(glue, "-c \""); + glue = gb_string_append_length(glue, ODIN_ANDROID_NDK_PATH.text, ODIN_ANDROID_NDK_PATH.len); + glue = gb_string_appendc(glue, "sources/android/native_app_glue/android_native_app_glue.c"); + glue = gb_string_appendc(glue, "\" "); + glue = gb_string_appendc(glue, "-o \""); + glue = gb_string_append_length(glue, android_glue_object.text, android_glue_object.len); + glue = gb_string_appendc(glue, "\" "); + + glue = gb_string_appendc(glue, "\"-I"); + glue = gb_string_append_length(glue, ODIN_ANDROID_NDK_TOOLCHAIN_PATH.text, ODIN_ANDROID_NDK_TOOLCHAIN_PATH.len); + glue = gb_string_appendc(glue, "sysroot/usr/include/"); + glue = gb_string_appendc(glue, "\" "); + + glue = gb_string_appendc(glue, "\"-I"); + glue = gb_string_append_length(glue, ODIN_ANDROID_NDK_TOOLCHAIN_PATH.text, ODIN_ANDROID_NDK_TOOLCHAIN_PATH.len); + glue = gb_string_appendc(glue, "sysroot/usr/include/aarch64-linux-android/"); + glue = gb_string_appendc(glue, "\" "); + + + glue = gb_string_appendc(glue, "-Wno-macro-redefined "); + + result = system_exec_command_line_app("android-native-app-glue-compile", glue); + if (result) { + return result; + } + + gbString ar = gb_string_make_length(heap_allocator(), ODIN_ANDROID_NDK_TOOLCHAIN_PATH.text, ODIN_ANDROID_NDK_TOOLCHAIN_PATH.len); + defer (gb_string_free(ar)); + + ar = gb_string_appendc(ar, "bin/llvm-ar"); + + ar = gb_string_appendc(ar, " rcs "); + + ar = gb_string_appendc(ar, "\""); + ar = gb_string_append_length(ar, android_glue_static_lib.text, android_glue_static_lib.len); + ar = gb_string_appendc(ar, "\" "); + + ar = gb_string_appendc(ar, "\""); + ar = gb_string_append_length(ar, android_glue_object.text, android_glue_object.len); + ar = gb_string_appendc(ar, "\" "); + + result = system_exec_command_line_app("android-native-app-glue-ar", ar); + if (result) { + return result; + } + + object_files = gb_string_append_fmt(object_files, "\"%.*s\" ", LIT(android_glue_static_lib)); + } + + for (String object_path : gen->output_object_paths) { object_files = gb_string_append_fmt(object_files, "\"%.*s\" ", LIT(object_path)); } @@ -654,6 +777,7 @@ gb_internal i32 linker_stage(LinkerData *gen) { if (build_context.metrics.os != TargetOs_openbsd && build_context.metrics.os != TargetOs_haiku && build_context.metrics.arch != TargetArch_riscv64 + && !is_android ) { // OpenBSD and Haiku default to PIE executable. do not pass -no-pie for it. link_settings = gb_string_appendc(link_settings, "-no-pie "); @@ -687,30 +811,53 @@ gb_internal i32 linker_stage(LinkerData *gen) { } } + if (is_android) { + GB_ASSERT(ODIN_ANDROID_NDK_TOOLCHAIN_LIB_PATH.len != 0); + GB_ASSERT(ODIN_ANDROID_NDK_TOOLCHAIN_LIB_LEVEL_PATH.len != 0); + GB_ASSERT(ODIN_ANDROID_NDK_TOOLCHAIN_SYSROOT_PATH.len != 0); + + platform_lib_str = gb_string_appendc(platform_lib_str, "\"-L"); + platform_lib_str = gb_string_append_length(platform_lib_str, ODIN_ANDROID_NDK_TOOLCHAIN_LIB_LEVEL_PATH.text, ODIN_ANDROID_NDK_TOOLCHAIN_LIB_LEVEL_PATH.len); + platform_lib_str = gb_string_appendc(platform_lib_str, "\" "); + + platform_lib_str = gb_string_appendc(platform_lib_str, "\"--sysroot="); + platform_lib_str = gb_string_append_length(platform_lib_str, ODIN_ANDROID_NDK_TOOLCHAIN_SYSROOT_PATH.text, ODIN_ANDROID_NDK_TOOLCHAIN_SYSROOT_PATH.len); + platform_lib_str = gb_string_appendc(platform_lib_str, "\" "); + + link_settings = gb_string_appendc(link_settings, "-u ANativeActivity_onCreate "); + } + if (!build_context.no_rpath) { // Set the rpath to the $ORIGIN/@loader_path (the path of the executable), // so that dynamic libraries are looked for at that path. if (build_context.metrics.os == TargetOs_darwin) { link_settings = gb_string_appendc(link_settings, "-Wl,-rpath,@loader_path "); } else { - link_settings = gb_string_appendc(link_settings, "-Wl,-rpath,\\$ORIGIN "); + if (is_android) { + // ignore + } else { + link_settings = gb_string_appendc(link_settings, "-Wl,-rpath,\\$ORIGIN "); + } } } if (!build_context.no_crt) { - platform_lib_str = gb_string_appendc(platform_lib_str, "-lm "); + lib_str = gb_string_appendc(lib_str, "-lm "); if (build_context.metrics.os == TargetOs_darwin) { // NOTE: adding this causes a warning about duplicate libraries, I think it is // automatically assumed/added by clang when you don't do `-nostdlib`. - // platform_lib_str = gb_string_appendc(platform_lib_str, "-lSystem "); + // lib_str = gb_string_appendc(lib_str, "-lSystem "); } else { - platform_lib_str = gb_string_appendc(platform_lib_str, "-lc "); + lib_str = gb_string_appendc(lib_str, "-lc "); } } gbString link_command_line = gb_string_make(heap_allocator(), clang_path); defer (gb_string_free(link_command_line)); + if (is_android) { + link_command_line = gb_string_append_fmt(link_command_line, " --target=aarch64-linux-android%d ", ODIN_ANDROID_API_LEVEL); + } link_command_line = gb_string_appendc(link_command_line, " -Wno-unused-command-line-argument "); link_command_line = gb_string_appendc(link_command_line, object_files); link_command_line = gb_string_append_fmt(link_command_line, " -o \"%.*s\" ", LIT(output_filename)); diff --git a/src/main.cpp b/src/main.cpp index 289a6150a..3549eb277 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1105,8 +1105,9 @@ gb_internal bool parse_build_flags(Array args) { String str = value.value_string; bool found = false; - if (selected_target_metrics->metrics->os != TargetOs_darwin) { - gb_printf_err("-subtarget can only be used with darwin based targets at the moment\n"); + if (selected_target_metrics->metrics->os != TargetOs_darwin && + selected_target_metrics->metrics->os != TargetOs_linux ) { + gb_printf_err("-subtarget can only be used with darwin and linux based targets at the moment\n"); bad_flags = true; break; } -- cgit v1.2.3 From a66ea9bf4a0b6435614a6fe5a3386dfbb47c85ce Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 9 Apr 2025 13:23:15 +0100 Subject: Remove warning on struct field parameters being too big for the stack --- src/checker.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/checker.cpp') diff --git a/src/checker.cpp b/src/checker.cpp index c44c6ce5b..5a5ec9706 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -751,7 +751,7 @@ gb_internal void check_scope_usage_internal(Checker *c, Scope *scope, u64 vet_fl array_add(&vetted_entities, ve_unused); } else if (is_shadowed) { array_add(&vetted_entities, ve_shadowed); - } else if (e->kind == Entity_Variable && (e->flags & (EntityFlag_Param|EntityFlag_Using|EntityFlag_Static)) == 0 && !e->Variable.is_global) { + } else if (e->kind == Entity_Variable && (e->flags & (EntityFlag_Param|EntityFlag_Using|EntityFlag_Static|EntityFlag_Field)) == 0 && !e->Variable.is_global) { i64 sz = type_size_of(e->type); // TODO(bill): When is a good size warn? // Is >256 KiB good enough? -- cgit v1.2.3