forked from OSchip/llvm-project
[lld-macho] Move ICF members from InputSection to ConcatInputSection
`icfEqClass` only makes sense on ConcatInputSections since (in contrast to literal sections) they are deduplicated as an atomic unit. Similarly, `hasPersonality` and `replacement` don't make sense on literal sections. This mirrors LLD-ELF, which stores `icfEqClass` only on non-mergeable sections. Reviewed By: #lld-macho, gkm Differential Revision: https://reviews.llvm.org/D104670
This commit is contained in:
parent
b904574b3d
commit
8aa17d1eae
|
@ -108,10 +108,19 @@ static bool equalsVariable(const ConcatInputSection *ia,
|
|||
return false;
|
||||
if (da->isAbsolute() != db->isAbsolute())
|
||||
return false;
|
||||
if (da->isec)
|
||||
if (da->isec->icfEqClass[icfPass % 2] !=
|
||||
db->isec->icfEqClass[icfPass % 2])
|
||||
if (da->isec) {
|
||||
if (da->isec->kind() != db->isec->kind())
|
||||
return false;
|
||||
if (const auto *isecA = dyn_cast<ConcatInputSection>(da->isec)) {
|
||||
const auto *isecB = cast<ConcatInputSection>(db->isec);
|
||||
if (isecA->icfEqClass[icfPass % 2] !=
|
||||
isecB->icfEqClass[icfPass % 2])
|
||||
return false;
|
||||
} else {
|
||||
// FIXME: implement ICF for other InputSection kinds
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else if (isa<DylibSymbol>(sa)) {
|
||||
// There is one DylibSymbol per gotIndex and we already checked for
|
||||
// symbol equality, thus we know that these must be different.
|
||||
|
@ -122,8 +131,16 @@ static bool equalsVariable(const ConcatInputSection *ia,
|
|||
} else {
|
||||
const auto *sa = ra.referent.get<InputSection *>();
|
||||
const auto *sb = rb.referent.get<InputSection *>();
|
||||
if (sa->icfEqClass[icfPass % 2] != sb->icfEqClass[icfPass % 2])
|
||||
if (sa->kind() != sb->kind())
|
||||
return false;
|
||||
if (const auto *isecA = dyn_cast<ConcatInputSection>(sa)) {
|
||||
const auto *isecB = cast<ConcatInputSection>(sb);
|
||||
if (isecA->icfEqClass[icfPass % 2] != isecB->icfEqClass[icfPass % 2])
|
||||
return false;
|
||||
} else {
|
||||
// FIXME: implement ICF for other InputSection kinds
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
@ -183,17 +200,19 @@ void ICF::forEachClass(std::function<void(size_t, size_t)> func) {
|
|||
void ICF::run() {
|
||||
// Into each origin-section hash, combine all reloc referent section hashes.
|
||||
for (icfPass = 0; icfPass < 2; ++icfPass) {
|
||||
parallelForEach(icfInputs, [&](InputSection *isec) {
|
||||
parallelForEach(icfInputs, [&](ConcatInputSection *isec) {
|
||||
uint64_t hash = isec->icfEqClass[icfPass % 2];
|
||||
for (const Reloc &r : isec->relocs) {
|
||||
if (auto *sym = r.referent.dyn_cast<Symbol *>()) {
|
||||
if (auto *dylibSym = dyn_cast<DylibSymbol>(sym))
|
||||
hash += dylibSym->stubsHelperIndex;
|
||||
else if (auto *defined = dyn_cast<Defined>(sym))
|
||||
hash +=
|
||||
defined->value +
|
||||
(defined->isec ? defined->isec->icfEqClass[icfPass % 2] : 0);
|
||||
else
|
||||
else if (auto *defined = dyn_cast<Defined>(sym)) {
|
||||
hash += defined->value;
|
||||
if (defined->isec)
|
||||
if (auto *isec = cast<ConcatInputSection>(defined->isec))
|
||||
hash += isec->icfEqClass[icfPass % 2];
|
||||
// FIXME: implement ICF for other InputSection kinds
|
||||
} else
|
||||
llvm_unreachable("foldIdenticalSections symbol kind");
|
||||
}
|
||||
}
|
||||
|
@ -202,10 +221,10 @@ void ICF::run() {
|
|||
});
|
||||
}
|
||||
|
||||
llvm::stable_sort(icfInputs,
|
||||
[](const InputSection *a, const InputSection *b) {
|
||||
return a->icfEqClass[0] < b->icfEqClass[0];
|
||||
});
|
||||
llvm::stable_sort(
|
||||
icfInputs, [](const ConcatInputSection *a, const ConcatInputSection *b) {
|
||||
return a->icfEqClass[0] < b->icfEqClass[0];
|
||||
});
|
||||
forEachClass(
|
||||
[&](size_t begin, size_t end) { segregate(begin, end, equalsConstant); });
|
||||
|
||||
|
|
|
@ -47,10 +47,9 @@ static uint64_t resolveSymbolVA(const Symbol *sym, uint8_t type) {
|
|||
|
||||
// ICF needs to hash any section that might potentially be duplicated so
|
||||
// that it can match on content rather than identity.
|
||||
bool InputSection::isHashableForICF(bool isText) const {
|
||||
if (auto const *concatIsec = dyn_cast<ConcatInputSection>(this))
|
||||
if (concatIsec->shouldOmitFromOutput())
|
||||
return false;
|
||||
bool ConcatInputSection::isHashableForICF(bool isText) const {
|
||||
if (shouldOmitFromOutput())
|
||||
return false;
|
||||
switch (sectionType(flags)) {
|
||||
case S_REGULAR:
|
||||
if (isText)
|
||||
|
@ -63,10 +62,9 @@ bool InputSection::isHashableForICF(bool isText) const {
|
|||
case S_8BYTE_LITERALS:
|
||||
case S_16BYTE_LITERALS:
|
||||
case S_LITERAL_POINTERS:
|
||||
// FIXME(gkm): once literal sections are deduplicated, their content and
|
||||
// identity correlate, so we can assign unique IDs to them rather than hash
|
||||
// them.
|
||||
return true;
|
||||
// FIXME(jezng): We should not have any ConcatInputSections of these types
|
||||
// when running ICF.
|
||||
return false;
|
||||
case S_ZEROFILL:
|
||||
case S_GB_ZEROFILL:
|
||||
case S_NON_LAZY_SYMBOL_POINTERS:
|
||||
|
@ -89,7 +87,7 @@ bool InputSection::isHashableForICF(bool isText) const {
|
|||
}
|
||||
}
|
||||
|
||||
void InputSection::hashForICF() {
|
||||
void ConcatInputSection::hashForICF() {
|
||||
assert(data.data()); // zeroFill section data has nullptr with non-zero size
|
||||
assert(icfEqClass[0] == 0); // don't overwrite a unique ID!
|
||||
// Turn-on the top bit to guarantee that valid hashes have no collisions
|
||||
|
|
|
@ -45,6 +45,7 @@ public:
|
|||
// Whether the data at \p off in this InputSection is live.
|
||||
virtual bool isLive(uint64_t off) const = 0;
|
||||
virtual void markLive(uint64_t off) = 0;
|
||||
virtual InputSection *canonical() { return this; }
|
||||
|
||||
InputFile *file = nullptr;
|
||||
StringRef name;
|
||||
|
@ -59,17 +60,6 @@ public:
|
|||
// is address assigned?
|
||||
bool isFinal = false;
|
||||
|
||||
bool isHashableForICF(bool isText) const;
|
||||
void hashForICF();
|
||||
InputSection *canonical() { return replacement ? replacement : this; }
|
||||
|
||||
// ICF can't fold functions with LSDA+personality
|
||||
bool hasPersonality = false;
|
||||
// Points to the surviving section after this one is folded by ICF
|
||||
InputSection *replacement = nullptr;
|
||||
// Equivalence-class ID for ICF
|
||||
uint64_t icfEqClass[2] = {0, 0};
|
||||
|
||||
ArrayRef<uint8_t> data;
|
||||
std::vector<Reloc> relocs;
|
||||
|
||||
|
@ -105,13 +95,25 @@ public:
|
|||
void markLive(uint64_t off) override { live = true; }
|
||||
bool isCoalescedWeak() const { return wasCoalesced && numRefs == 0; }
|
||||
bool shouldOmitFromOutput() const { return !live || isCoalescedWeak(); }
|
||||
bool isHashableForICF(bool isText) const;
|
||||
void hashForICF();
|
||||
void writeTo(uint8_t *buf);
|
||||
|
||||
void foldIdentical(ConcatInputSection *redundant);
|
||||
InputSection *canonical() override {
|
||||
return replacement ? replacement : this;
|
||||
}
|
||||
|
||||
static bool classof(const InputSection *isec) {
|
||||
return isec->kind() == ConcatKind;
|
||||
}
|
||||
|
||||
void foldIdentical(ConcatInputSection *redundant);
|
||||
// ICF can't fold functions with LSDA+personality
|
||||
bool hasPersonality = false;
|
||||
// Points to the surviving section after this one is folded by ICF
|
||||
InputSection *replacement = nullptr;
|
||||
// Equivalence-class ID for ICF
|
||||
uint64_t icfEqClass[2] = {0, 0};
|
||||
|
||||
// With subsections_via_symbols, most symbols have their own InputSection,
|
||||
// and for weak symbols (e.g. from inline functions), only the
|
||||
|
|
|
@ -153,7 +153,9 @@ void UnwindInfoSectionImpl<Ptr>::prepareRelocations(ConcatInputSection *isec) {
|
|||
Reloc &rFunc = isec->relocs[++i];
|
||||
assert(r.offset ==
|
||||
rFunc.offset + offsetof(CompactUnwindEntry<Ptr>, personality));
|
||||
rFunc.referent.get<InputSection *>()->hasPersonality = true;
|
||||
auto *referentIsec =
|
||||
cast<ConcatInputSection>(rFunc.referent.get<InputSection *>());
|
||||
referentIsec->hasPersonality = true;
|
||||
|
||||
if (auto *s = r.referent.dyn_cast<Symbol *>()) {
|
||||
if (auto *undefined = dyn_cast<Undefined>(s)) {
|
||||
|
|
|
@ -957,7 +957,7 @@ void Writer::foldIdenticalSections() {
|
|||
// relocs to find every referenced InputSection, but that precludes easy
|
||||
// parallelization. Therefore, we hash every InputSection here where we have
|
||||
// them all accessible as a simple vector.
|
||||
std::vector<InputSection *> hashable;
|
||||
std::vector<ConcatInputSection *> hashable;
|
||||
// If an InputSection is ineligible for ICF, we give it a unique ID to force
|
||||
// it into an unfoldable singleton equivalence class. Begin the unique-ID
|
||||
// space at inputSections.size(), so that it will never intersect with
|
||||
|
@ -967,12 +967,16 @@ void Writer::foldIdenticalSections() {
|
|||
// ICF::segregate()
|
||||
uint64_t icfUniqueID = inputSections.size();
|
||||
for (InputSection *isec : inputSections) {
|
||||
if (isec->isHashableForICF(isec->parent == textOutputSection))
|
||||
hashable.push_back(isec);
|
||||
else
|
||||
isec->icfEqClass[0] = ++icfUniqueID;
|
||||
if (auto *concatIsec = dyn_cast<ConcatInputSection>(isec)) {
|
||||
if (concatIsec->isHashableForICF(isec->parent == textOutputSection))
|
||||
hashable.push_back(concatIsec);
|
||||
else
|
||||
concatIsec->icfEqClass[0] = ++icfUniqueID;
|
||||
}
|
||||
// FIXME: hash literal sections here?
|
||||
}
|
||||
parallelForEach(hashable, [](InputSection *isec) { isec->hashForICF(); });
|
||||
parallelForEach(hashable,
|
||||
[](ConcatInputSection *isec) { isec->hashForICF(); });
|
||||
// Now that every input section is either hashed or marked as unique,
|
||||
// run the segregation algorithm to detect foldable subsections
|
||||
ICF(textOutputSection->inputs).run();
|
||||
|
|
Loading…
Reference in New Issue