[lld] r305582 - [COFF] Drop unused comdat sections when GC is turned off

Reid Kleckner via llvm-commits llvm-commits at lists.llvm.org
Fri Jun 16 13:47:20 PDT 2017


Author: rnk
Date: Fri Jun 16 15:47:19 2017
New Revision: 305582

URL: http://llvm.org/viewvc/llvm-project?rev=305582&view=rev
Log:
[COFF] Drop unused comdat sections when GC is turned off

Summary:
Adds a "Discarded" bool to SectionChunk to indicate if the section was
discarded by COMDAT deduplication. The Writer still just checks
`isLive()`.

Fixes PR33446

Reviewers: ruiu

Subscribers: llvm-commits

Differential Revision: https://reviews.llvm.org/D34288

Added:
    lld/trunk/test/COFF/Inputs/associative-comdat-2.s
    lld/trunk/test/COFF/associative-comdat.s
Modified:
    lld/trunk/COFF/Chunks.cpp
    lld/trunk/COFF/Chunks.h
    lld/trunk/COFF/InputFiles.cpp
    lld/trunk/COFF/SymbolTable.cpp

Modified: lld/trunk/COFF/Chunks.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Chunks.cpp?rev=305582&r1=305581&r2=305582&view=diff
==============================================================================
--- lld/trunk/COFF/Chunks.cpp (original)
+++ lld/trunk/COFF/Chunks.cpp Fri Jun 16 15:47:19 2017
@@ -37,8 +37,14 @@ SectionChunk::SectionChunk(ObjectFile *F
 
   Align = Header->getAlignment();
 
-  // Only COMDAT sections are subject of dead-stripping.
-  Live = !isCOMDAT();
+  // Chunks may be discarded during comdat merging.
+  Discarded = false;
+
+  // If linker GC is disabled, every chunk starts out alive.  If linker GC is
+  // enabled, treat non-comdat sections as roots. Generally optimized object
+  // files will be built with -ffunction-sections or /Gy, so most things worth
+  // stripping will be in a comdat.
+  Live = !Config->DoGC || !isCOMDAT();
 }
 
 static void add16(uint8_t *P, int16_t V) { write16le(P, read16le(P) + V); }
@@ -226,8 +232,12 @@ bool SectionChunk::isCOMDAT() const {
 void SectionChunk::printDiscardedMessage() const {
   // Removed by dead-stripping. If it's removed by ICF, ICF already
   // printed out the name, so don't repeat that here.
-  if (Sym && this == Repl)
-    message("Discarded " + Sym->getName());
+  if (Sym && this == Repl) {
+    if (Discarded)
+      message("Discarded comdat symbol " + Sym->getName());
+    else if (!Live)
+      message("Discarded " + Sym->getName());
+  }
 }
 
 StringRef SectionChunk::getDebugName() {

Modified: lld/trunk/COFF/Chunks.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Chunks.h?rev=305582&r1=305581&r2=305582&view=diff
==============================================================================
--- lld/trunk/COFF/Chunks.h (original)
+++ lld/trunk/COFF/Chunks.h Fri Jun 16 15:47:19 2017
@@ -159,13 +159,23 @@ public:
   StringRef getDebugName() override;
   void setSymbol(DefinedRegular *S) { if (!Sym) Sym = S; }
 
+  // Returns true if the chunk was not dropped by GC or COMDAT deduplication.
+  bool isLive() { return Live && !Discarded; }
+
   // Used by the garbage collector.
-  bool isLive() { return !Config->DoGC || Live; }
   void markLive() {
+    assert(Config->DoGC && "should only mark things live from GC");
     assert(!isLive() && "Cannot mark an already live section!");
     Live = true;
   }
 
+  // Returns true if this chunk was dropped by COMDAT deduplication.
+  bool isDiscarded() const { return Discarded; }
+
+  // Used by the SymbolTable when discarding unused comdat sections. This is
+  // redundant when GC is enabled, as all comdat sections will start out dead.
+  void markDiscarded() { Discarded = true; }
+
   // 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()),
@@ -196,6 +206,9 @@ private:
   llvm::iterator_range<const coff_relocation *> Relocs;
   size_t NumRelocs;
 
+  // True if this chunk was discarded because it was a duplicate comdat section.
+  bool Discarded;
+
   // Used by the garbage collector.
   bool Live;
 

Modified: lld/trunk/COFF/InputFiles.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/InputFiles.cpp?rev=305582&r1=305581&r2=305582&view=diff
==============================================================================
--- lld/trunk/COFF/InputFiles.cpp (original)
+++ lld/trunk/COFF/InputFiles.cpp Fri Jun 16 15:47:19 2017
@@ -249,8 +249,12 @@ SymbolBody *ObjectFile::createDefined(CO
     auto *Aux = reinterpret_cast<const coff_aux_section_definition *>(AuxP);
     if (Aux->Selection == IMAGE_COMDAT_SELECT_ASSOCIATIVE)
       if (auto *ParentSC = cast_or_null<SectionChunk>(
-              SparseChunks[Aux->getNumber(Sym.isBigObj())]))
+              SparseChunks[Aux->getNumber(Sym.isBigObj())])) {
         ParentSC->addAssociative(SC);
+        // If we already discarded the parent, discard the child.
+        if (ParentSC->isDiscarded())
+          SC->markDiscarded();
+      }
     SC->Checksum = Aux->CheckSum;
   }
 

Modified: lld/trunk/COFF/SymbolTable.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/SymbolTable.cpp?rev=305582&r1=305581&r2=305582&view=diff
==============================================================================
--- lld/trunk/COFF/SymbolTable.cpp (original)
+++ lld/trunk/COFF/SymbolTable.cpp Fri Jun 16 15:47:19 2017
@@ -244,6 +244,12 @@ Symbol *SymbolTable::addRegular(InputFil
     reportDuplicate(S, F);
   } else if (SP == SP_NEW) {
     replaceBody<DefinedRegular>(S, F, N, IsCOMDAT, /*IsExternal*/ true, Sym, C);
+  } else if (SP == SP_EXISTING && IsCOMDAT && C) {
+    C->markDiscarded();
+    // Discard associative chunks that we've parsed so far. No need to recurse
+    // because an associative section cannot have children.
+    for (SectionChunk *Child : C->children())
+      Child->markDiscarded();
   }
   return S;
 }

Added: lld/trunk/test/COFF/Inputs/associative-comdat-2.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/COFF/Inputs/associative-comdat-2.s?rev=305582&view=auto
==============================================================================
--- lld/trunk/test/COFF/Inputs/associative-comdat-2.s (added)
+++ lld/trunk/test/COFF/Inputs/associative-comdat-2.s Fri Jun 16 15:47:19 2017
@@ -0,0 +1,13 @@
+# Defines foo and foo_assoc globals. foo is comdat, and foo_assoc is comdat
+# associative with it. foo_assoc should be discarded iff foo is discarded,
+# either by linker GC or normal comdat merging.
+
+        .section        .rdata,"dr",associative,foo
+        .p2align        3
+        .quad   foo
+
+        .section        .data,"dw",discard,foo
+        .globl  foo                     # @foo
+        .p2align        2
+foo:
+        .long   42

Added: lld/trunk/test/COFF/associative-comdat.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/COFF/associative-comdat.s?rev=305582&view=auto
==============================================================================
--- lld/trunk/test/COFF/associative-comdat.s (added)
+++ lld/trunk/test/COFF/associative-comdat.s Fri Jun 16 15:47:19 2017
@@ -0,0 +1,46 @@
+# RUN: llvm-mc %s -filetype=obj -o %t1.obj
+# RUN: llvm-mc %S/Inputs/associative-comdat-2.s -filetype=obj -o %t2.obj
+
+# RUN: lld-link -entry:main %t1.obj %t2.obj -out:%t.gc.exe
+# RUN: llvm-readobj -sections %t.gc.exe | FileCheck %s
+
+# RUN: lld-link -entry:main %t1.obj %t2.obj -opt:noref -out:%t.nogc.exe
+# RUN: llvm-readobj -sections %t.nogc.exe | FileCheck %s
+
+# CHECK: Sections [
+# CHECK:   Section {
+# CHECK:     Number: 1
+# CHECK-LABEL:     Name: .data (2E 64 61 74 61 00 00 00)
+# CHECK-NEXT:     VirtualSize: 0x4
+# CHECK:   Section {
+# CHECK-LABEL:     Name: .rdata (2E 72 64 61 74 61 00 00)
+#             This is the critical check to show that only *one* definition of
+#             foo_assoc was retained. This *must* be 8, not 16.
+# CHECK-NEXT:     VirtualSize: 0x8
+
+        .text
+        .def     main;
+        .scl    2;
+        .type   32;
+        .endef
+        .globl  main                    # -- Begin function main
+        .p2align        4, 0x90
+main:                                   # @main
+# BB#0:
+        movl    foo(%rip), %eax
+        retq
+                                        # -- End function
+
+# Defines foo and foo_assoc globals. foo is comdat, and foo_assoc is comdat
+# associative with it. foo_assoc should be discarded iff foo is discarded,
+# either by linker GC or normal comdat merging.
+
+        .section        .rdata,"dr",associative,foo
+        .p2align        3
+        .quad   foo
+
+        .section        .data,"dw",discard,foo
+        .globl  foo                     # @foo
+        .p2align        2
+foo:
+        .long   42




More information about the llvm-commits mailing list