diff --git a/lld/COFF/Chunks.cpp b/lld/COFF/Chunks.cpp index cb5cba5c414a1..548d87bdaefe5 100644 --- a/lld/COFF/Chunks.cpp +++ b/lld/COFF/Chunks.cpp @@ -777,7 +777,7 @@ uint32_t SectionChunk::getSectionNumber() const { return s.getIndex() + 1; } -CommonChunk::CommonChunk(const COFFSymbolRef s) : sym(s) { +CommonChunk::CommonChunk(const COFFSymbolRef s) : live(false), sym(s) { // The value of a common symbol is its size. Align all common symbols smaller // than 32 bytes naturally, i.e. round the size up to the next power of two. // This is what MSVC link.exe does. diff --git a/lld/COFF/Chunks.h b/lld/COFF/Chunks.h index 6d88f5ec73776..cf8857dc57305 100644 --- a/lld/COFF/Chunks.h +++ b/lld/COFF/Chunks.h @@ -522,6 +522,8 @@ class CommonChunk : public NonSectionChunk { uint32_t getOutputCharacteristics() const override; StringRef getSectionName() const override { return ".bss"; } + bool live; + private: const COFFSymbolRef sym; }; diff --git a/lld/COFF/Symbols.h b/lld/COFF/Symbols.h index c86ded860876b..9f077ddb2bb72 100644 --- a/lld/COFF/Symbols.h +++ b/lld/COFF/Symbols.h @@ -236,6 +236,8 @@ class DefinedCommon : public DefinedCOFF { CommonChunk *c = nullptr) : DefinedCOFF(DefinedCommonKind, f, n, s), data(c), size(size) { this->isExternal = true; + if (c) + c->live = true; } static bool classof(const Symbol *s) { diff --git a/lld/COFF/Writer.cpp b/lld/COFF/Writer.cpp index 258a82e371f3a..3ac26681541ba 100644 --- a/lld/COFF/Writer.cpp +++ b/lld/COFF/Writer.cpp @@ -1114,6 +1114,10 @@ void Writer::createSections() { sc->printDiscardedMessage(); continue; } + if (auto *cc = dyn_cast(c)) { + if (!cc->live) + continue; + } StringRef name = c->getSectionName(); if (shouldStripSectionSuffix(sc, name, ctx.config.mingw)) name = name.split('$').first; diff --git a/lld/test/COFF/common-dedup.ll b/lld/test/COFF/common-dedup.ll new file mode 100644 index 0000000000000..9a4071ab08ff8 --- /dev/null +++ b/lld/test/COFF/common-dedup.ll @@ -0,0 +1,38 @@ +; REQUIRES: x86 +; RUN: split-file %s %t.dir +; RUN: llc %t.dir/t1.ll -o %t.t1.obj --filetype=obj +; RUN: llc %t.dir/t2.ll -o %t.t2.obj --filetype=obj +; RUN: lld-link %t.t1.obj %t.t2.obj -entry:main -out:%t.exe +; RUN: llvm-readobj --section-headers %t.exe | FileCheck %s + +; Make sure that the data section contains just one copy of @a, not two. +; CHECK: Name: .data +; CHECK-NEXT: VirtualSize: 0x1000 + +;--- t1.ll +target triple = "x86_64-pc-windows-msvc" +@a = common global [4096 x i8] zeroinitializer + +define i32 @usea() { + %ref_common = load i32, ptr @a + ret i32 %ref_common +} + +;--- t2.ll +target triple = "x86_64-pc-windows-msvc" +@a = common global [4096 x i8] zeroinitializer + +define i32 @useb() { + %ref_common = load i32, ptr @a + ret i32 %ref_common +} + +declare i32 @usea() + +define dso_local i32 @main() local_unnamed_addr { +entry: + %a = tail call i32 @usea() + %b = tail call i32 @useb() + %add = add nsw i32 %a, %b + ret i32 %add +}