diff options
author | Peter Collingbourne <peter@pcc.me.uk> | 2018-07-21 00:17:11 +0000 |
---|---|---|
committer | Peter Collingbourne <peter@pcc.me.uk> | 2018-07-21 00:17:11 +0000 |
commit | 37f25a24bbf1fdb384c1e2559f033952f934a6e1 (patch) | |
tree | e3d3524213f8ff3a4de5ca0d2532b3f6001f66fa | |
parent | 960246dbee67c827eb4339b0fe68b7534b5a79d8 (diff) | |
download | bcm5719-llvm-37f25a24bbf1fdb384c1e2559f033952f934a6e1.tar.gz bcm5719-llvm-37f25a24bbf1fdb384c1e2559f033952f934a6e1.zip |
ELF: Make sections with KeepUnique bit eligible for ICF.
The only restriction is that we cannot merge more than one KeepUnique
section together. This matches gold's behaviour and reduces code size
when using --icf=safe.
Differential Revision: https://reviews.llvm.org/D49622
llvm-svn: 337638
-rw-r--r-- | lld/ELF/ICF.cpp | 27 | ||||
-rw-r--r-- | lld/test/ELF/icf-keep-unique.s | 5 |
2 files changed, 27 insertions, 5 deletions
diff --git a/lld/ELF/ICF.cpp b/lld/ELF/ICF.cpp index f13a5049e01..191fa8e2b6e 100644 --- a/lld/ELF/ICF.cpp +++ b/lld/ELF/ICF.cpp @@ -163,7 +163,7 @@ template <class ELFT> static uint32_t getHash(InputSection *S) { // Returns true if section S is subject of ICF. static bool isEligible(InputSection *S) { - if (!S->Live || S->KeepUnique || !(S->Flags & SHF_ALLOC)) + if (!S->Live || !(S->Flags & SHF_ALLOC)) return false; // Don't merge writable sections. .data.rel.ro sections are marked as writable @@ -468,10 +468,29 @@ template <class ELFT> void ICF<ELFT>::run() { forEachClassRange(0, Sections.size(), [&](size_t Begin, size_t End) { if (End - Begin == 1) return; - print("selected section " + toString(Sections[Begin])); - for (size_t I = Begin + 1; I < End; ++I) { + InputSection *Target = nullptr; + bool SeenUnique = false, Replaced = false; + for (size_t I = Begin; I < End; ++I) { + // We aren't allowed to merge two KeepUnique sections as this would break + // the guarantees provided by --keep-unique and --icf=safe, but there's + // no reason why we can't merge a non-KeepUnique section with a KeepUnique + // section. We implement this by only considering the first KeepUnique + // section in the equivalence class for merging. If we see any more + // KeepUnique sections, we ignore them. + if (Sections[I]->KeepUnique) { + if (SeenUnique) + continue; + SeenUnique = true; + } + if (!Target) { + Target = Sections[I]; + continue; + } + if (!Replaced) + print("selected section " + toString(Target)); print(" removing identical section " + toString(Sections[I])); - Sections[Begin]->replace(Sections[I]); + Target->replace(Sections[I]); + Replaced = true; // At this point we know sections merged are fully identical and hence // we want to remove duplicate implicit dependencies such as link order diff --git a/lld/test/ELF/icf-keep-unique.s b/lld/test/ELF/icf-keep-unique.s index a6f883fc7b2..661d0e285f6 100644 --- a/lld/test/ELF/icf-keep-unique.s +++ b/lld/test/ELF/icf-keep-unique.s @@ -11,10 +11,13 @@ // CHECK-NEXT: removing identical section {{.*}}:(.text.f4) // CHECK-NEXT: removing identical section {{.*}}:(.text.f5) -// With --keep-unique f2, f4 and f5 we expect only f3 and f5 to be removed. +// With --keep-unique f2, f4 and f5 we expect only f2, f3 and f5 to be removed. +// f2 can be removed despite being --keep-unique because all sections that are +// merged into it are not --keep-unique. // f5 is not matched by --keep-unique as it is a local symbol. // CHECK-KEEP: warning: could not find symbol f5 to keep unique // CHECK-KEEP: selected section {{.*}}:(.text.f1) +// CHECK-KEEP-NEXT: removing identical section {{.*}}:(.text.f2) // CHECK-KEEP-NEXT: removing identical section {{.*}}:(.text.f3) // CHECK-KEEP-NEXT: removing identical section {{.*}}:(.text.f5) .globl _start, f1, f2, f3, f4 |