Skip to content

Commit 635d348

Browse files
committed
use equivalence classes to simplify and handle more cases
1 parent 35489bf commit 635d348

File tree

4 files changed

+46
-21
lines changed

4 files changed

+46
-21
lines changed

lld/ELF/ICF.cpp

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@
8080
#include "SymbolTable.h"
8181
#include "Symbols.h"
8282
#include "SyntheticSections.h"
83+
#include "llvm/ADT/EquivalenceClasses.h"
8384
#include "llvm/BinaryFormat/ELF.h"
8485
#include "llvm/Object/ELF.h"
8586
#include "llvm/Support/Parallel.h"
@@ -558,7 +559,7 @@ template <class ELFT> void ICF<ELFT>::run() {
558559
return {ctx, ctx.arg.printIcfSections ? DiagLevel::Msg : DiagLevel::None};
559560
};
560561

561-
DenseMap<Symbol *, Symbol *> symbolMap;
562+
EquivalenceClasses<Symbol *> symbolEquivalence;
562563
// Merge sections by the equivalence class.
563564
// Merge symbols identified as equivalent during ICF
564565
forEachClassRange(0, sections.size(), [&](size_t begin, size_t end) {
@@ -577,14 +578,7 @@ template <class ELFT> void ICF<ELFT>::run() {
577578
if (syms[i] == replacedSyms[i] || !syms[i]->isGlobal() ||
578579
!replacedSyms[i]->isGlobal())
579580
continue;
580-
auto [it, inserted] =
581-
symbolMap.insert(std::make_pair(replacedSyms[i], syms[i]));
582-
print() << " selected symbol: " << syms[i]->getName().data()
583-
<< "; replaced symbol: " << replacedSyms[i]->getName().data();
584-
if (!inserted) {
585-
print() << " replacement already exists: "
586-
<< it->getSecond()->getName().data();
587-
}
581+
symbolEquivalence.unionSets(syms[i], replacedSyms[i]);
588582
}
589583

590584
// At this point we know sections merged are fully identical and hence
@@ -606,15 +600,23 @@ template <class ELFT> void ICF<ELFT>::run() {
606600
};
607601
for (Symbol *sym : ctx.symtab->getSymbols()) {
608602
fold(sym);
609-
if (Symbol *s = symbolMap.lookup(sym))
610-
ctx.symtab->redirect(sym, s);
603+
auto it = symbolEquivalence.findLeader(sym);
604+
if (it != symbolEquivalence.member_end() && *it != sym) {
605+
print() << "Redirecting " << sym->getName() << " to " << (*it)->getName();
606+
ctx.symtab->redirect(sym, *it);
607+
}
611608
}
612609
parallelForEach(ctx.objectFiles, [&](ELFFileBase *file) {
613610
for (Symbol *sym : file->getLocalSymbols())
614611
fold(sym);
615-
for (Symbol *&sym : file->getMutableGlobalSymbols())
616-
if (Symbol *s = symbolMap.lookup(sym))
617-
sym = s;
612+
for (Symbol *&sym : file->getMutableGlobalSymbols()) {
613+
auto it = symbolEquivalence.findLeader(sym);
614+
if (it != symbolEquivalence.member_end() && *it != sym) {
615+
print() << "Redirecting " << sym->getName() << " to "
616+
<< (*it)->getName();
617+
sym = *it;
618+
}
619+
}
618620
});
619621

620622
// InputSectionDescription::sections is populated by processSectionCommands().

lld/ELF/SymbolTable.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ using namespace lld::elf;
3232
void SymbolTable::redirect(Symbol *from, Symbol *to) {
3333
int &fromIdx = symMap[CachedHashStringRef(from->getName())];
3434
const int toIdx = symMap[CachedHashStringRef(to->getName())];
35-
3635
fromIdx = toIdx;
3736
}
3837

lld/test/ELF/aarch64-got-merging-icf.s

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
# EXE: {{.*}}.got 00000010{{.*}}
1212

1313
## When symbols are preemptible in DSO mode, GOT entries wouldn't be merged
14-
# DSO: {{.*}}.got 00000020{{.*}}
14+
# DSO: {{.*}}.got 00000028{{.*}}
1515

1616
.addrsig
1717

@@ -50,11 +50,36 @@ bl f1_\index
5050

5151
.endm
5252

53+
# another set of sections merging: g1 <- g2
54+
55+
.section .text.t1_0,"ax",@progbits
56+
t1_0:
57+
adrp x2, :got:g1
58+
mov x3, #1
59+
b t2_0
60+
61+
.section .text.t2_0,"ax",@progbits
62+
t2_0:
63+
ldr x2, [x2, :got_lo12:g1]
64+
b callee
65+
66+
.section .text.t1_1,"ax",@progbits
67+
t1_1:
68+
adrp x2, :got:g2
69+
mov x3, #2
70+
b t2_1
71+
72+
.section .text.t2_1,"ax",@progbits
73+
t2_1:
74+
ldr x2, [x2, :got_lo12:g2]
75+
b callee
76+
5377
.section .text._start,"ax",@progbits
5478
.globl _start
5579
_start:
5680

5781
f 0 1
5882
f 1 1
5983
f 2 1
60-
f 3
84+
f 3 1
85+
f 4

lld/test/ELF/icf-preemptible.s

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,15 @@
1111
# EXE-NOT: {{.}}
1212
# EXE: selected section {{.*}}:(.text.g1)
1313
# EXE-NEXT: removing identical section {{.*}}:(.text.g2)
14-
# EXE-NEXT: selected symbol: f1; replaced symbol: f2
1514
# EXE-NEXT: removing identical section {{.*}}:(.text.g3)
1615
# EXE-NEXT: selected section {{.*}}:(.text.f1)
1716
# EXE-NEXT: removing identical section {{.*}}:(.text.f2)
1817
# EXE-NEXT: selected section {{.*}}:(.text.h1)
1918
# EXE-NEXT: removing identical section {{.*}}:(.text.h2)
20-
# EXE-NEXT: selected symbol: g1; replaced symbol: g2
2119
# EXE-NEXT: removing identical section {{.*}}:(.text.h3)
22-
# EXE-NEXT: selected symbol: g1; replaced symbol: g3
23-
# EXE-NOT: {{.}}
20+
# EXE-NEXT: Redirecting f2 to f1
21+
# EXE-NEXT: Redirecting g2 to g1
22+
# EXE-NEXT: Redirecting g3 to g1
2423

2524
## Definitions are preemptible in a DSO. Only leaf functions can be folded.
2625
# DSO-NOT: {{.}}

0 commit comments

Comments
 (0)