use cycle tracking only on weak and undefined symbols

* profile of /OPT:REF shows that early push to seen_hm dominates the pass;
  cost: 74.23ms -> 6.81ms (-90.8%)
This commit is contained in:
Nikita Smith
2026-07-27 14:47:26 -07:00
committed by Ryan Fleury
parent fcee35f3e9
commit a73e3e0790
+20 -21
View File
@@ -2648,38 +2648,37 @@ lnk_obj_indices_from_section_counts(Arena *arena, U64 worker_count, LNK_Obj **ob
internal B32 internal B32
lnk_resolve_reloc_target_symbol(Arena *arena, LNK_SymbolTable *symtab, LNK_ObjSymbolRef symbol, String8 pass_name, LNK_ObjSymbolRef *resolved_symbol_out) lnk_resolve_reloc_target_symbol(Arena *arena, LNK_SymbolTable *symtab, LNK_ObjSymbolRef symbol, String8 pass_name, LNK_ObjSymbolRef *resolved_symbol_out)
{ {
B32 is_resolved = 1;
Temp temp = temp_begin(arena); Temp temp = temp_begin(arena);
B32 is_resolved = 1;
HashMap seen_hm = {0}; HashMap seen_hm = {0};
B32 keep_walking = 1;
LNK_ObjSymbolRef result = symbol; LNK_ObjSymbolRef result = symbol;
do { for (;;) {
// detect cyclic chains
U64 symbol_key = ((U64)result.obj->input_idx << 32ull) | (U64)result.symbol_idx;
if (hash_map_search_u64_u64(&seen_hm, symbol_key) == 0) {
hash_map_push_u64_u64(temp.arena, &seen_hm, symbol_key, 1);
} else {
COFF_ParsedSymbol symbol_parsed = lnk_parsed_symbol_from_coff_symbol_idx(symbol.obj, symbol.symbol_idx);
lnk_error_obj(LNK_Warning_CyclicSymbol, symbol.obj, "symbol %S forms a cyclic chain (%S)", symbol_parsed.name, pass_name);
MemoryZeroStruct(&result);
is_resolved = 0;
break;
}
// unpack symbol // unpack symbol
COFF_ParsedSymbol result_parsed = lnk_parsed_symbol_from_coff_symbol_idx_no_name(result.obj, result.symbol_idx); COFF_ParsedSymbol result_parsed = lnk_parsed_symbol_from_coff_symbol_idx_no_name(result.obj, result.symbol_idx);
COFF_SymbolValueInterpType result_interp = coff_interp_from_parsed_symbol(result_parsed); COFF_SymbolValueInterpType result_interp = coff_interp_from_parsed_symbol(result_parsed);
// resolve symbol // resolve symbol
LNK_ObjSymbolRef next_ref = {0}; LNK_ObjSymbolRef next_ref = {0};
if (lnk_resolve_symbol(symtab, result, &next_ref)) { if (!lnk_resolve_symbol(symtab, result, &next_ref)) {
keep_walking = (result_interp == COFF_SymbolValueInterp_Weak || result_interp == COFF_SymbolValueInterp_Undefined); break;
}
if (result_interp != COFF_SymbolValueInterp_Weak && result_interp != COFF_SymbolValueInterp_Undefined) {
result = next_ref; result = next_ref;
} else { break;
keep_walking = 0; }
// most relocations resolve in one step; only allocate cycle tracking for chains
U64 symbol_key = ((U64)result.obj->input_idx << 32ull) | (U64)result.symbol_idx;
if (hash_map_search_u64_u64(&seen_hm, symbol_key) != 0) {
COFF_ParsedSymbol symbol_parsed = lnk_parsed_symbol_from_coff_symbol_idx(symbol.obj, symbol.symbol_idx);
lnk_error_obj(LNK_Warning_CyclicSymbol, symbol.obj, "symbol %S forms a cyclic chain (%S)", symbol_parsed.name, pass_name);
MemoryZeroStruct(&result);
is_resolved = 0;
break;
}
hash_map_push_u64_u64(temp.arena, &seen_hm, symbol_key, 1);
result = next_ref;
} }
} while (keep_walking);
if (resolved_symbol_out) { if (resolved_symbol_out) {
*resolved_symbol_out = result; *resolved_symbol_out = result;