diff --git a/lld/ELF/ICF.cpp b/lld/ELF/ICF.cpp --- a/lld/ELF/ICF.cpp +++ b/lld/ELF/ICF.cpp @@ -102,7 +102,7 @@ void run(); private: - void segregate(size_t begin, size_t end, bool constant); + void segregate(size_t begin, size_t end, uint32_t eqClassBase, bool constant); template bool constantEq(const InputSection *a, ArrayRef relsA, @@ -197,7 +197,8 @@ // Split an equivalence class into smaller classes. template -void ICF::segregate(size_t begin, size_t end, bool constant) { +void ICF::segregate(size_t begin, size_t end, uint32_t eqClassBase, + bool constant) { // This loop rearranges sections in [Begin, End) so that all sections // that are equal in terms of equals{Constant,Variable} are contiguous // in [Begin, End). @@ -219,10 +220,11 @@ size_t mid = bound - sections.begin(); // Now we split [Begin, End) into [Begin, Mid) and [Mid, End) by - // updating the sections in [Begin, Mid). We use Mid as an equivalence - // class ID because every group ends with a unique index. + // updating the sections in [Begin, Mid). We use Mid as the basis for + // the equivalence class ID because every group ends with a unique index. + // Add this to eqClassBase to avoid equality with unique IDs. for (size_t i = begin; i < mid; ++i) - sections[i]->eqClass[next] = mid; + sections[i]->eqClass[next] = eqClassBase + mid; // If we created a group, we need to iterate the main loop again. if (mid != end) @@ -353,8 +355,8 @@ continue; auto *y = cast(db->section); - // Ineligible sections are in the special equivalence class 0. - // They can never be the same in terms of the equivalence class. + // Sections that are in the special equivalence class 0, can never be the + // same in terms of the equivalence class. if (x->eqClass[current] == 0) return false; if (x->eqClass[current] != y->eqClass[current]) @@ -443,7 +445,7 @@ if (auto *relSec = dyn_cast_or_null(d->section)) hash += relSec->eqClass[cnt % 2]; } - // Set MSB to 1 to avoid collisions with non-hash IDs. + // Set MSB to 1 to avoid collisions with unique IDs. isec->eqClass[(cnt + 1) % 2] = hash | (1U << 31); } @@ -471,18 +473,26 @@ uint32_t uniqueId = 0; for (Partition &part : partitions) part.ehFrame->iterateFDEWithLSDA( - [&](InputSection &s) { s.eqClass[0] = ++uniqueId; }); + [&](InputSection &s) { s.eqClass[0] = s.eqClass[1] = ++uniqueId; }); // Collect sections to merge. for (InputSectionBase *sec : inputSections) { auto *s = cast(sec); - if (isEligible(s) && s->eqClass[0] == 0) - sections.push_back(s); + if (s->eqClass[0] == 0) { + if (isEligible(s)) + sections.push_back(s); + else + // Ineligible sections are assigned unique IDs, i.e. each section + // belongs to an equivalence class of its own. + s->eqClass[0] = s->eqClass[1] = ++uniqueId; + } } // Initially, we use hash values to partition sections. - parallelForEach( - sections, [&](InputSection *s) { s->eqClass[0] = xxHash64(s->data()); }); + parallelForEach(sections, [&](InputSection *s) { + // Set MSB to 1 to avoid collisions with unique IDs. + s->eqClass[0] = xxHash64(s->data()) | (1U << 31); + }); // Perform 2 rounds of relocation hash propagation. 2 is an empirical value to // reduce the average sizes of equivalence classes, i.e. segregate() which has @@ -502,14 +512,20 @@ return a->eqClass[0] < b->eqClass[0]; }); - // Compare static contents and assign unique IDs for each static content. - forEachClass([&](size_t begin, size_t end) { segregate(begin, end, true); }); + // Compare static contents and assign unique equivalence class IDs for each + // static content. Use a base offset for these IDs to ensure no overlap with + // the unique IDs already assigned. + uint32_t eqClassBase = ++uniqueId; + forEachClass([&](size_t begin, size_t end) { + segregate(begin, end, eqClassBase, true); + }); // Split groups by comparing relocations until convergence is obtained. do { repeat = false; - forEachClass( - [&](size_t begin, size_t end) { segregate(begin, end, false); }); + forEachClass([&](size_t begin, size_t end) { + segregate(begin, end, eqClassBase, false); + }); } while (repeat); log("ICF needed " + Twine(cnt) + " iterations"); diff --git a/lld/test/ELF/icf-ineligible.s b/lld/test/ELF/icf-ineligible.s new file mode 100644 --- /dev/null +++ b/lld/test/ELF/icf-ineligible.s @@ -0,0 +1,44 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o +# RUN: ld.lld %t.o -o /dev/null --keep-unique fu --icf=all --print-icf-sections | FileCheck %s + +## Check that ICF is able to merge equivalent sections with relocations to +## different symbols, e.g. aliases, that refer to the same section which is +## ineligible for ICF. + +# CHECK: selected section {{.*}}:(.text.f1) +# CHECK: removing identical section {{.*}}:(.text.f2) +# CHECK: removing identical section {{.*}}:(.text.f3) +# CHECK: selected section {{.*}}:(.text.f4) +# CHECK: removing identical section {{.*}}:(.text.f5) + +.globl d, d_alias, fu, f1, f2, f3, f4, f5 + +.section .data.d,"aw",@progbits +d: +d_alias: +.long 42 + +.section .text.fu,"ax",@progbits +fu: + nop + +.section .text.f1,"ax",@progbits +f1: +.quad d + +.section .text.f2,"ax",@progbits +f2: +.quad d_alias + +.section .text.f3,"ax",@progbits +f3: +.quad .data.d + +.section .text.f4,"ax",@progbits +f4: +.quad fu + +.section .text.f5,"ax",@progbits +f5: +.quad .text.fu