aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorgingerBill <gingerBill@users.noreply.github.com>2025-09-29 14:03:32 +0100
committergingerBill <gingerBill@users.noreply.github.com>2025-09-29 14:03:32 +0100
commit53f4fc1cbbd58396241264785dc1c8a75798f062 (patch)
tree119fd8f54f7958e4ccb6a80a5e921e271fb6f4c5 /src
parent11dc6680d2101a76e5fff8baedd8717501b625c0 (diff)
Add `-para-poly-diagnostics`
Diffstat (limited to 'src')
-rw-r--r--src/build_settings.cpp2
-rw-r--r--src/check_expr.cpp1
-rw-r--r--src/checker.hpp2
-rw-r--r--src/llvm_backend.cpp4
-rw-r--r--src/llvm_backend_utility.cpp180
-rw-r--r--src/main.cpp7
6 files changed, 196 insertions, 0 deletions
diff --git a/src/build_settings.cpp b/src/build_settings.cpp
index a8d74d1da..abf8e6809 100644
--- a/src/build_settings.cpp
+++ b/src/build_settings.cpp
@@ -548,6 +548,8 @@ struct BuildContext {
bool ignore_microsoft_magic;
bool linker_map_file;
+ bool para_poly_diagnostics;
+
bool use_single_module;
bool use_separate_modules;
bool module_per_file;
diff --git a/src/check_expr.cpp b/src/check_expr.cpp
index a59f145c7..2a22e5c48 100644
--- a/src/check_expr.cpp
+++ b/src/check_expr.cpp
@@ -587,6 +587,7 @@ gb_internal bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, E
d->proc_lit = proc_lit;
d->proc_checked_state = ProcCheckedState_Unchecked;
d->defer_use_checked = false;
+ d->para_poly_original = old_decl->entity;
Entity *entity = alloc_entity_procedure(nullptr, token, final_proc_type, tags);
entity->state.store(EntityState_Resolved);
diff --git a/src/checker.hpp b/src/checker.hpp
index 9693c3e38..bda7b2746 100644
--- a/src/checker.hpp
+++ b/src/checker.hpp
@@ -218,6 +218,8 @@ struct DeclInfo {
Ast * proc_lit; // Ast_ProcLit
Type * gen_proc_type; // Precalculated
+ Entity * para_poly_original;
+
bool is_using;
bool where_clauses_evaluated;
bool foreign_require_results;
diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp
index ec9630a47..b47e2788f 100644
--- a/src/llvm_backend.cpp
+++ b/src/llvm_backend.cpp
@@ -3556,6 +3556,10 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
TIME_SECTION("LLVM Correct Entity Linkage");
lb_correct_entity_linkage(gen);
+ if (build_context.para_poly_diagnostics) {
+ lb_do_para_poly_diagnostics(gen);
+ }
+
llvm_error = nullptr;
defer (LLVMDisposeMessage(llvm_error));
diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp
index f7807364a..fd3214f24 100644
--- a/src/llvm_backend_utility.cpp
+++ b/src/llvm_backend_utility.cpp
@@ -2787,3 +2787,183 @@ gb_internal LLVMAtomicOrdering llvm_atomic_ordering_from_odin(Ast *expr) {
ExactValue value = type_and_value_of_expr(expr).value;
return llvm_atomic_ordering_from_odin(value);
}
+
+
+
+struct lbParaPolyEntry {
+ Entity *entity;
+ String canonical_name;
+ isize count;
+ isize total_code_size;
+};
+
+gb_internal isize lb_total_code_size(lbProcedure *p) {
+ isize instruction_count = 0;
+
+ LLVMBasicBlockRef first = LLVMGetFirstBasicBlock(p->value);
+
+ for (LLVMBasicBlockRef block = first; block != nullptr; block = LLVMGetNextBasicBlock(block)) {
+ for (LLVMValueRef instr = LLVMGetFirstInstruction(block); instr != nullptr; instr = LLVMGetNextInstruction(instr)) {
+ instruction_count += 1;
+ }
+ }
+ return instruction_count;
+
+}
+
+gb_internal void lb_do_para_poly_diagnostics(lbGenerator *gen) {
+ PtrMap<Entity * /* Parent */, lbParaPolyEntry> procs = {};
+ map_init(&procs);
+ defer (map_destroy(&procs));
+
+ for (auto &entry : gen->modules) {
+ lbModule *m = entry.value;
+ for (lbProcedure *p : m->generated_procedures) {
+ Entity *e = p->entity;
+ if (e == nullptr) {
+ continue;
+ }
+ if (p->builder == nullptr) {
+ continue;
+ }
+
+ DeclInfo *d = e->decl_info;
+ Entity *para_poly_parent = d->para_poly_original;
+ if (para_poly_parent == nullptr) {
+ continue;
+ }
+
+ lbParaPolyEntry *entry = map_get(&procs, para_poly_parent);
+ if (entry == nullptr) {
+ lbParaPolyEntry entry = {};
+ entry.entity = para_poly_parent;
+ entry.count = 0;
+
+
+ gbString w = string_canonical_entity_name(permanent_allocator(), entry.entity);
+ String name = make_string_c(w);
+
+ for (isize i = 0; i < name.len; i++) {
+ String s = substring(name, i, name.len);
+ if (string_starts_with(s, str_lit(":proc"))) {
+ name = substring(name, 0, i);
+ break;
+ }
+ }
+
+ entry.canonical_name = name;
+
+ map_set(&procs, para_poly_parent, entry);
+ }
+ entry = map_get(&procs, para_poly_parent);
+ GB_ASSERT(entry != nullptr);
+ entry->count += 1;
+ entry->total_code_size += lb_total_code_size(p);
+ }
+ }
+
+
+ auto entries = array_make<lbParaPolyEntry>(heap_allocator(), 0, procs.count);
+ defer (array_free(&entries));
+
+ for (auto &entry : procs) {
+ array_add(&entries, entry.value);
+ }
+
+ array_sort(entries, [](void const *a, void const *b) -> int {
+ lbParaPolyEntry *x = cast(lbParaPolyEntry *)a;
+ lbParaPolyEntry *y = cast(lbParaPolyEntry *)b;
+ if (x->total_code_size > y->total_code_size) {
+ return -1;
+ }
+ if (x->total_code_size < y->total_code_size) {
+ return +1;
+ }
+ return string_compare(x->canonical_name, y->canonical_name);
+ });
+
+
+ gb_printf("Parametric Polymorphic Procedure Diagnostics\n");
+ gb_printf("------------------------------------------------------------------------------------------\n");
+
+ gb_printf("Sorted by Total Instruction Count Descending (Top 100)\n\n");
+ gb_printf("Total Instruction Count | Instantiation Count | Average Instruction Count | Procedure Name\n");
+
+ isize max_count = 100;
+ for (auto &entry : entries) {
+ isize code_size = entry.total_code_size;
+ isize count = entry.count;
+ String name = entry.canonical_name;
+
+ f64 average = cast(f64)code_size / cast(f64)gb_max(count, 1);
+
+ gb_printf("%23td | %19d | %25.2f | %.*s\n", code_size, count, average, LIT(name));
+ if (max_count-- <= 0) {
+ break;
+ }
+ }
+
+ gb_printf("------------------------------------------------------------------------------------------\n");
+
+ array_sort(entries, [](void const *a, void const *b) -> int {
+ lbParaPolyEntry *x = cast(lbParaPolyEntry *)a;
+ lbParaPolyEntry *y = cast(lbParaPolyEntry *)b;
+ if (x->count > y->count) {
+ return -1;
+ }
+ if (x->count < y->count) {
+ return +1;
+ }
+
+ return string_compare(x->canonical_name, y->canonical_name);
+ });
+
+ gb_printf("Sorted by Total Instantiation Count Descending (Top 100)\n\n");
+ gb_printf("Instantiation Count | Total Instruction Count | Average Instruction Count | Procedure Name\n");
+
+ max_count = 100;
+ for (auto &entry : entries) {
+ isize code_size = entry.total_code_size;
+ isize count = entry.count;
+ String name = entry.canonical_name;
+
+
+ f64 average = cast(f64)code_size / cast(f64)gb_max(count, 1);
+
+ gb_printf("%19d | %23td | %25.2f | %.*s\n", count, code_size, average, LIT(name));
+ if (max_count-- <= 0) {
+ break;
+ }
+ }
+
+ gb_printf("------------------------------------------------------------------------------------------\n");
+
+
+ array_sort(entries, [](void const *a, void const *b) -> int {
+ lbParaPolyEntry *x = cast(lbParaPolyEntry *)a;
+ lbParaPolyEntry *y = cast(lbParaPolyEntry *)b;
+ if (x->count < y->count) {
+ return -1;
+ }
+ if (x->count > y->count) {
+ return +1;
+ }
+
+ return string_compare(x->canonical_name, y->canonical_name);
+ });
+
+ gb_printf("Single Instanced Parametric Polymorphic Procedures\n\n");
+ gb_printf("Instruction Count | Procedure Name\n");
+ for (auto &entry : entries) {
+ isize code_size = entry.total_code_size;
+ isize count = entry.count;
+ String name = entry.canonical_name;
+ if (count != 1) {
+ break;
+ }
+
+ gb_printf("%17td | %.*s\n", code_size, LIT(name));
+ }
+
+ gb_printf("------------------------------------------------------------------------------------------\n");
+}
diff --git a/src/main.cpp b/src/main.cpp
index acc4773c0..707b85232 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -394,6 +394,8 @@ enum BuildFlagKind {
BuildFlag_IntegerDivisionByZero,
+ BuildFlag_ParaPolyDiagnostics,
+
// internal use only
BuildFlag_InternalFastISel,
BuildFlag_InternalIgnoreLazy,
@@ -619,6 +621,7 @@ gb_internal bool parse_build_flags(Array<String> args) {
add_flag(&build_flags, BuildFlag_IntegerDivisionByZero, str_lit("integer-division-by-zero"), BuildFlagParam_String, Command__does_check);
+ add_flag(&build_flags, BuildFlag_ParaPolyDiagnostics, str_lit("para-poly-diagnostics"), BuildFlagParam_None, Command__does_build);
add_flag(&build_flags, BuildFlag_InternalFastISel, str_lit("internal-fast-isel"), BuildFlagParam_None, Command_all);
add_flag(&build_flags, BuildFlag_InternalIgnoreLazy, str_lit("internal-ignore-lazy"), BuildFlagParam_None, Command_all);
@@ -1562,6 +1565,10 @@ gb_internal bool parse_build_flags(Array<String> args) {
}
break;
+ case BuildFlag_ParaPolyDiagnostics:
+ build_context.para_poly_diagnostics = true;
+ break;
+
case BuildFlag_InternalFastISel:
build_context.fast_isel = true;
break;