[lld] [lld][ELF] Fold LSDA-bearing sections with equivalent LSDA and CIE (PR #224929)
Kazu Hirata via llvm-commits
llvm-commits at lists.llvm.org
Sun Sep 20 08:29:59 PDT 2026
================
@@ -463,17 +616,77 @@ static void combineRelocHashes(unsigned cnt, InputSection *isec,
// The main function of ICF.
template <class ELFT> void ICF<ELFT>::run() {
// Two text sections may have identical content and relocations but different
- // LSDA, e.g. the two functions may have catch blocks of different types. If a
- // text section is referenced by a .eh_frame FDE with LSDA, it is not
- // eligible. This is implemented by iterating over CIE/FDE and setting
- // eqClass[0] to the referenced text section from a live FDE.
- //
- // If two .gcc_except_table have identical semantics (usually identical
- // content with PC-relative encoding), we will lose folding opportunity.
+ // LSDA, e.g. the two functions may have catch blocks of different types.
+ // A section whose FDE has an LSDA is foldable only when the associated LSDA
+ // section is known and is equal for both sections (see lsdaMap). Sections
+ // with an LSDA that cannot be analyzed (e.g. a shared .gcc_except_table
+ // section referenced at a nonzero offset) are not eligible, as before.
uint32_t uniqueId = 0;
- ctx.in.ehFrame->iterateFDEWithLSDA<ELFT>(
- [&](InputSection &s) { s.eqClass[0] = s.eqClass[1] = ++uniqueId; });
-
+ DenseMap<InputSection *, LsdaInfo> lsdaSecs;
+ DenseSet<InputSection *> lsdaConflict;
+ SmallVector<InputSection *, 0> lsdaUncomparable;
+ ctx.in.ehFrame->iterateFDEWithLSDATarget<ELFT>(
+ [&](InputSection &text, const CieInfo &cie, const Symbol &sym,
+ int64_t addend) {
+ auto *d = dyn_cast<Defined>(&sym);
+ InputSection *lsda =
+ d ? dyn_cast_or_null<InputSection>(d->section) : nullptr;
+ if (!lsda || d->value + addend != 0) {
+ lsdaUncomparable.push_back(&text);
+ return;
+ }
+ // Resolve the personality function. A compiler usually materializes
+ // the CIE personality pointer indirectly through a per-object pointer
+ // ("DW.ref.<personality>"); follow that indirection so that the same
+ // personality in different objects compares equal even though the
+ // local thunk symbols differ.
+ const Symbol *personality = nullptr;
+ int64_t personalityAddend = 0;
+ bool personalityKnown = true;
+ ArrayRef<Relocation> otherCieRels = cie.rels;
+ if (cie.personalityEncoding) {
+ if (cie.rels.empty()) {
+ personalityKnown = false;
+ } else {
+ const Relocation &r = cie.rels.front();
+ otherCieRels = cie.rels.drop_front();
+ if (*cie.personalityEncoding & llvm::dwarf::DW_EH_PE_indirect) {
+ auto *pd = dyn_cast<Defined>(r.sym);
+ auto *thunk =
+ pd ? dyn_cast_or_null<InputSection>(pd->section) : nullptr;
+ personality =
+ thunk ? relocTargetAt<ELFT>(thunk, pd->value + r.addend,
+ personalityAddend)
+ : nullptr;
+ if (!personality)
+ personalityKnown = false;
+ } else {
+ personality = r.sym;
+ personalityAddend = r.addend;
+ }
+ }
+ }
+ LsdaInfo info{lsda, cie.piece->data(), personalityKnown,
+ personality, personalityAddend, otherCieRels};
+ auto it = lsdaSecs.try_emplace(&text, info);
+ if (!it.second) {
+ const LsdaInfo &prev = it.first->second;
+ if (prev.lsda != lsda || prev.cieData != cie.piece->data() ||
+ prev.personalityKnown != personalityKnown ||
+ prev.personality != personality ||
+ prev.personalityAddend != personalityAddend ||
+ !cieRelsEqual(prev.otherCieRels, otherCieRels))
+ lsdaConflict.insert(&text);
+ }
+ });
+ for (InputSection *s : lsdaUncomparable)
+ s->eqClass[0] = s->eqClass[1] = ++uniqueId;
+ for (auto &kv : lsdaSecs) {
+ if (lsdaConflict.contains(kv.first))
+ kv.first->eqClass[0] = kv.first->eqClass[1] = ++uniqueId;
+ else
+ lsdaMap.try_emplace(kv.first, kv.second);
----------------
kazutakahirata wrote:
May I suggest structured bindings here?
```suggestion
for (auto &[sec, info] : lsdaSecs) {
if (lsdaConflict.contains(sec))
sec->eqClass[0] = sec->eqClass[1] = ++uniqueId;
else
lsdaMap.try_emplace(sec, info);
```
https://github.com/llvm/llvm-project/pull/224929
More information about the llvm-commits
mailing list