[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