[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