[lld] r359923 - Shrink SectionChunk by combining Relocs and SectionName sizes

Reid Kleckner via llvm-commits llvm-commits at lists.llvm.org
Fri May 3 13:17:14 PDT 2019


Author: rnk
Date: Fri May  3 13:17:14 2019
New Revision: 359923

URL: http://llvm.org/viewvc/llvm-project?rev=359923&view=rev
Log:
Shrink SectionChunk by combining Relocs and SectionName sizes

SectionChunk is one of the most frequently allocated data structures in
LLD, since there are about four per function when optimizations and
debug info are enabled (.text, .pdata, .xdata, .debug$S).

A PE COFF file cannot be larger than 2GB, so there is an inherent limit
on the length of the section name and the number of relocations.
Decompose the ArrayRef and StringRef into pointer and size, and put them
back together in the accessors for section name and relocation list.

I plan to gather complete performance numbers later by padding
SectionChunk with dead data and measuring performance after all the size
optimizations are done.

Modified:
    lld/trunk/COFF/Chunks.cpp
    lld/trunk/COFF/Chunks.h
    lld/trunk/COFF/ICF.cpp
    lld/trunk/COFF/PDB.cpp
    lld/trunk/COFF/SymbolTable.cpp
    lld/trunk/COFF/Writer.cpp

Modified: lld/trunk/COFF/Chunks.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Chunks.cpp?rev=359923&r1=359922&r2=359923&view=diff
==============================================================================
--- lld/trunk/COFF/Chunks.cpp (original)
+++ lld/trunk/COFF/Chunks.cpp Fri May  3 13:17:14 2019
@@ -30,11 +30,16 @@ namespace lld {
 namespace coff {
 
 SectionChunk::SectionChunk(ObjFile *F, const coff_section *H)
-    : Chunk(SectionKind), File(F), Header(H),
-      Relocs(File->getCOFFObj()->getRelocations(Header)), Repl(this) {
+    : Chunk(SectionKind), File(F), Header(H), Repl(this) {
+  // Initialize Relocs.
+  setRelocs(File->getCOFFObj()->getRelocations(Header));
+
   // Initialize SectionName.
+  StringRef SectionName;
   if (Expected<StringRef> E = File->getCOFFObj()->getSectionName(Header))
     SectionName = *E;
+  SectionNameData = SectionName.data();
+  SectionNameSize = SectionName.size();
 
   Alignment = Header->getAlignment();
 
@@ -48,7 +53,7 @@ SectionChunk::SectionChunk(ObjFile *F, c
 // SectionChunk is one of the most frequently allocated classes, so it is
 // important to keep it as compact as possible. As of this writing, the number
 // below is the size of this class on x64 platforms.
-static_assert(sizeof(SectionChunk) <= 128, "SectionChunk grew unexpectedly");
+static_assert(sizeof(SectionChunk) <= 120, "SectionChunk grew unexpectedly");
 
 static void add16(uint8_t *P, int16_t V) { write16le(P, read16le(P) + V); }
 static void add32(uint8_t *P, int32_t V) { write32le(P, read32le(P) + V); }
@@ -343,8 +348,8 @@ void SectionChunk::writeTo(uint8_t *Buf)
 
   // Apply relocations.
   size_t InputSize = getSize();
-  for (size_t I = 0, E = Relocs.size(); I < E; I++) {
-    const coff_relocation &Rel = Relocs[I];
+  for (size_t I = 0, E = RelocsSize; I < E; I++) {
+    const coff_relocation &Rel = RelocsData[I];
 
     // Check for an invalid relocation offset. This check isn't perfect, because
     // we don't have the relocation size, which is only known after checking the
@@ -437,8 +442,8 @@ static uint8_t getBaserelType(const coff
 // fixed by the loader if load-time relocation is needed.
 // Only called when base relocation is enabled.
 void SectionChunk::getBaserels(std::vector<Baserel> *Res) {
-  for (size_t I = 0, E = Relocs.size(); I < E; I++) {
-    const coff_relocation &Rel = Relocs[I];
+  for (size_t I = 0, E = RelocsSize; I < E; I++) {
+    const coff_relocation &Rel = RelocsData[I];
     uint8_t Ty = getBaserelType(Rel);
     if (Ty == IMAGE_REL_BASED_ABSOLUTE)
       continue;
@@ -534,7 +539,7 @@ static int getRuntimePseudoRelocSize(uin
 // imported from another DLL).
 void SectionChunk::getRuntimePseudoRelocs(
     std::vector<RuntimePseudoReloc> &Res) {
-  for (const coff_relocation &Rel : Relocs) {
+  for (const coff_relocation &Rel : getRelocs()) {
     auto *Target =
         dyn_cast_or_null<Defined>(File->getSymbol(Rel.SymbolTableIndex));
     if (!Target || !Target->IsRuntimePseudoReloc)
@@ -587,7 +592,7 @@ ArrayRef<uint8_t> SectionChunk::getConte
 
 ArrayRef<uint8_t> SectionChunk::consumeDebugMagic() {
   assert(isCodeView());
-  return consumeDebugMagic(getContents(), SectionName);
+  return consumeDebugMagic(getContents(), getSectionName());
 }
 
 ArrayRef<uint8_t> SectionChunk::consumeDebugMagic(ArrayRef<uint8_t> Data,

Modified: lld/trunk/COFF/Chunks.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Chunks.h?rev=359923&r1=359922&r2=359923&view=diff
==============================================================================
--- lld/trunk/COFF/Chunks.h (original)
+++ lld/trunk/COFF/Chunks.h Fri May  3 13:17:14 2019
@@ -153,7 +153,9 @@ public:
   void writeTo(uint8_t *Buf) const override;
   bool hasData() const override;
   uint32_t getOutputCharacteristics() const override;
-  StringRef getSectionName() const override { return SectionName; }
+  StringRef getSectionName() const override {
+    return StringRef(SectionNameData, SectionNameSize);
+  }
   void getBaserels(std::vector<Baserel> *Res) override;
   bool isCOMDAT() const;
   void applyRelX64(uint8_t *Off, uint16_t Type, OutputSection *OS, uint64_t S,
@@ -180,18 +182,29 @@ public:
   // True if this is a codeview debug info chunk. These will not be laid out in
   // the image. Instead they will end up in the PDB, if one is requested.
   bool isCodeView() const {
-    return SectionName == ".debug" || SectionName.startswith(".debug$");
+    return getSectionName() == ".debug" || getSectionName().startswith(".debug$");
   }
 
   // True if this is a DWARF debug info or exception handling chunk.
   bool isDWARF() const {
-    return SectionName.startswith(".debug_") || SectionName == ".eh_frame";
+    return getSectionName().startswith(".debug_") || getSectionName() == ".eh_frame";
   }
 
   // Allow iteration over the bodies of this chunk's relocated symbols.
   llvm::iterator_range<symbol_iterator> symbols() const {
-    return llvm::make_range(symbol_iterator(File, Relocs.begin()),
-                            symbol_iterator(File, Relocs.end()));
+    return llvm::make_range(symbol_iterator(File, RelocsData),
+                            symbol_iterator(File, RelocsData + RelocsSize));
+  }
+
+  ArrayRef<coff_relocation> getRelocs() const {
+    return llvm::makeArrayRef(RelocsData, RelocsSize);
+  }
+
+  // Reloc setter used by ARM range extension thunk insertion.
+  void setRelocs(ArrayRef<coff_relocation> NewRelocs) {
+    RelocsData = NewRelocs.data();
+    RelocsSize = NewRelocs.size();
+    assert(RelocsSize == NewRelocs.size() && "reloc size truncation");
   }
 
   // Single linked list iterator for associated comdat children.
@@ -245,9 +258,6 @@ public:
   // The COMDAT leader symbol if this is a COMDAT chunk.
   DefinedRegular *Sym = nullptr;
 
-  // Relocations for this section.
-  ArrayRef<coff_relocation> Relocs;
-
   // The CRC of the contents as described in the COFF spec 4.5.5.
   // Auxiliary Format 5: Section Definitions. Used for ICF.
   uint32_t Checksum = 0;
@@ -265,12 +275,20 @@ public:
   SectionChunk *Repl;
 
 private:
-  StringRef SectionName;
   SectionChunk *AssocChildren = nullptr;
 
   // Used for ICF (Identical COMDAT Folding)
   void replace(SectionChunk *Other);
   uint32_t Class[2] = {0, 0};
+
+  // Relocations for this section. Size is stored below.
+  const coff_relocation *RelocsData;
+
+  // Section name string. Size is stored below.
+  const char *SectionNameData;
+
+  uint32_t RelocsSize = 0;
+  uint32_t SectionNameSize = 0;
 };
 
 // This class is used to implement an lld-specific feature (not implemented in

Modified: lld/trunk/COFF/ICF.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/ICF.cpp?rev=359923&r1=359922&r2=359923&view=diff
==============================================================================
--- lld/trunk/COFF/ICF.cpp (original)
+++ lld/trunk/COFF/ICF.cpp Fri May  3 13:17:14 2019
@@ -130,8 +130,8 @@ bool ICF::assocEquals(const SectionChunk
   auto ChildClasses = [&](const SectionChunk *SC) {
     std::vector<uint32_t> Classes;
     for (const SectionChunk &C : SC->children())
-      if (!C.SectionName.startswith(".debug") &&
-          C.SectionName != ".gfids$y" && C.SectionName != ".gljmp$y")
+      if (!C.getSectionName().startswith(".debug") &&
+          C.getSectionName() != ".gfids$y" && C.getSectionName() != ".gljmp$y")
         Classes.push_back(C.Class[Cnt % 2]);
     return Classes;
   };
@@ -141,7 +141,7 @@ bool ICF::assocEquals(const SectionChunk
 // Compare "non-moving" part of two sections, namely everything
 // except relocation targets.
 bool ICF::equalsConstant(const SectionChunk *A, const SectionChunk *B) {
-  if (A->Relocs.size() != B->Relocs.size())
+  if (A->RelocsSize != B->RelocsSize)
     return false;
 
   // Compare relocations.
@@ -160,12 +160,13 @@ bool ICF::equalsConstant(const SectionCh
                D1->getChunk()->Class[Cnt % 2] == D2->getChunk()->Class[Cnt % 2];
     return false;
   };
-  if (!std::equal(A->Relocs.begin(), A->Relocs.end(), B->Relocs.begin(), Eq))
+  if (!std::equal(A->getRelocs().begin(), A->getRelocs().end(),
+                  B->getRelocs().begin(), Eq))
     return false;
 
   // Compare section attributes and contents.
   return A->getOutputCharacteristics() == B->getOutputCharacteristics() &&
-         A->SectionName == B->SectionName &&
+         A->getSectionName() == B->getSectionName() &&
          A->Header->SizeOfRawData == B->Header->SizeOfRawData &&
          A->Checksum == B->Checksum && A->getContents() == B->getContents() &&
          assocEquals(A, B);
@@ -184,8 +185,8 @@ bool ICF::equalsVariable(const SectionCh
         return D1->getChunk()->Class[Cnt % 2] == D2->getChunk()->Class[Cnt % 2];
     return false;
   };
-  return std::equal(A->Relocs.begin(), A->Relocs.end(), B->Relocs.begin(),
-                    Eq) &&
+  return std::equal(A->getRelocs().begin(), A->getRelocs().end(),
+                    B->getRelocs().begin(), Eq) &&
          assocEquals(A, B);
 }
 

Modified: lld/trunk/COFF/PDB.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/PDB.cpp?rev=359923&r1=359922&r2=359923&view=diff
==============================================================================
--- lld/trunk/COFF/PDB.cpp (original)
+++ lld/trunk/COFF/PDB.cpp Fri May  3 13:17:14 2019
@@ -1744,7 +1744,7 @@ static bool findLineTable(const SectionC
 
     // Build a mapping of SECREL relocations in DbgC that refer to C.
     DenseMap<uint32_t, uint32_t> Secrels;
-    for (const coff_relocation &R : DbgC->Relocs) {
+    for (const coff_relocation &R : DbgC->getRelocs()) {
       if (R.Type != SecrelReloc)
         continue;
 

Modified: lld/trunk/COFF/SymbolTable.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/SymbolTable.cpp?rev=359923&r1=359922&r2=359923&view=diff
==============================================================================
--- lld/trunk/COFF/SymbolTable.cpp (original)
+++ lld/trunk/COFF/SymbolTable.cpp Fri May  3 13:17:14 2019
@@ -89,7 +89,7 @@ std::string getSymbolLocations(ObjFile *
     auto *SC = dyn_cast<SectionChunk>(C);
     if (!SC)
       continue;
-    for (const coff_relocation &R : SC->Relocs) {
+    for (const coff_relocation &R : SC->getRelocs()) {
       if (R.SymbolTableIndex != SymIndex)
         continue;
       std::pair<StringRef, uint32_t> FileLine =
@@ -183,7 +183,7 @@ bool SymbolTable::handleMinGWAutomaticIm
       dyn_cast_or_null<DefinedRegular>(find((".refptr." + Name).str()));
   if (Refptr && Refptr->getChunk()->getSize() == Config->Wordsize) {
     SectionChunk *SC = dyn_cast_or_null<SectionChunk>(Refptr->getChunk());
-    if (SC && SC->Relocs.size() == 1 && *SC->symbols().begin() == Sym) {
+    if (SC && SC->getRelocs().size() == 1 && *SC->symbols().begin() == Sym) {
       log("Replacing .refptr." + Name + " with " + Imp->getName());
       Refptr->getChunk()->Live = false;
       Refptr->replaceKeepingName(Imp, ImpSize);

Modified: lld/trunk/COFF/Writer.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Writer.cpp?rev=359923&r1=359922&r2=359923&view=diff
==============================================================================
--- lld/trunk/COFF/Writer.cpp (original)
+++ lld/trunk/COFF/Writer.cpp Fri May  3 13:17:14 2019
@@ -467,14 +467,15 @@ static bool createThunks(OutputSection *
     // modified. If the relocations point into the object file, allocate new
     // memory. Otherwise, this must be previously allocated memory that can be
     // modified in place.
+    ArrayRef<coff_relocation> CurRelocs = SC->getRelocs();
     MutableArrayRef<coff_relocation> NewRelocs;
-    if (OriginalRelocs.data() == SC->Relocs.data()) {
+    if (OriginalRelocs.data() == CurRelocs.data()) {
       NewRelocs = makeMutableArrayRef(
           BAlloc.Allocate<coff_relocation>(OriginalRelocs.size()),
           OriginalRelocs.size());
     } else {
       NewRelocs = makeMutableArrayRef(
-          const_cast<coff_relocation *>(SC->Relocs.data()), SC->Relocs.size());
+          const_cast<coff_relocation *>(CurRelocs.data()), CurRelocs.size());
     }
 
     // Copy each relocation, but replace the symbol table indices which need
@@ -489,7 +490,7 @@ static bool createThunks(OutputSection *
       }
     }
 
-    SC->Relocs = makeArrayRef(NewRelocs.data(), NewRelocs.size());
+    SC->setRelocs(NewRelocs);
   }
   return AddressesChanged;
 }
@@ -501,8 +502,9 @@ static bool verifyRanges(const std::vect
     if (!SC)
       continue;
 
-    for (size_t J = 0, E = SC->Relocs.size(); J < E; ++J) {
-      const coff_relocation &Rel = SC->Relocs[J];
+    ArrayRef<coff_relocation> Relocs = SC->getRelocs();
+    for (size_t J = 0, E = Relocs.size(); J < E; ++J) {
+      const coff_relocation &Rel = Relocs[J];
       Symbol *RelocTarget = SC->File->getSymbol(Rel.SymbolTableIndex);
 
       Defined *Sym = dyn_cast_or_null<Defined>(RelocTarget);
@@ -1476,7 +1478,7 @@ static void markSymbolsWithRelocations(O
     if (!SC || !SC->Live)
       continue;
 
-    for (const coff_relocation &Reloc : SC->Relocs) {
+    for (const coff_relocation &Reloc : SC->getRelocs()) {
       if (Config->Machine == I386 && Reloc.Type == COFF::IMAGE_REL_I386_REL32)
         // Ignore relative relocations on x86. On x86_64 they can't be ignored
         // since they're also used to compute absolute addresses.




More information about the llvm-commits mailing list