aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFangrui Song <i@maskray.me>2021-07-20 13:22:00 -0700
committerFangrui Song <i@maskray.me>2021-07-20 13:22:00 -0700
commitdb5e0786900e53843f87c4169c404f8c7831eb8c (patch)
tree35da5fa3a9c42965f2504fdae276b09481ead698
parentce8024e8ff76e7be8b9ffa1a39d1dc9310bf74c7 (diff)
downloadllvm-db5e0786900e53843f87c4169c404f8c7831eb8c.zip
llvm-db5e0786900e53843f87c4169c404f8c7831eb8c.tar.gz
llvm-db5e0786900e53843f87c4169c404f8c7831eb8c.tar.bz2
[LTO] Add SelectionKind to IRSymtab and use it in ld.lld/LLVMgold
In PGO, a C++ external linkage function `foo` has a private counter `__profc_foo` and a private `__profd_foo` in a `comdat nodeduplicate`. A `__attribute__((weak))` function `foo` has a weak hidden counter `__profc_foo` and a private `__profd_foo` in a `comdat nodeduplicate`. In `ld.lld a.o b.o`, say a.o defines an external linkage `foo` and b.o defines a weak `foo`. Currently we treat `comdat nodeduplicate` as `comdat any`, ld.lld will incorrectly consider `b.o:__profc_foo` non-prevailing. In the worst case when `b.o:__profd_foo` is retained and `b.o:__profc_foo` isn't, there will be dangling reference causing an `undefined hidden symbol` error. Add SelectionKind to `Comdat` in IRSymtab and let linkers ignore nodeduplicate comdat. Differential Revision: https://reviews.llvm.org/D106228
-rw-r--r--lld/COFF/InputFiles.cpp8
-rw-r--r--lld/ELF/InputFiles.cpp7
-rw-r--r--lld/test/ELF/lto/comdat-nodeduplicate.ll127
-rw-r--r--lld/wasm/InputFiles.cpp5
-rw-r--r--llvm/include/llvm/LTO/LTO.h6
-rw-r--r--llvm/include/llvm/Object/IRSymtab.h14
-rw-r--r--llvm/lib/Object/IRSymtab.cpp1
-rw-r--r--llvm/test/LTO/Resolution/X86/symtab.ll11
-rw-r--r--llvm/test/Object/X86/irsymtab.ll4
-rw-r--r--llvm/test/tools/gold/X86/comdat-nodeduplicate.ll100
-rw-r--r--llvm/tools/gold/gold-plugin.cpp6
-rw-r--r--llvm/tools/llvm-lto2/llvm-lto2.cpp26
12 files changed, 291 insertions, 24 deletions
diff --git a/lld/COFF/InputFiles.cpp b/lld/COFF/InputFiles.cpp
index ef37e20..f32353c 100644
--- a/lld/COFF/InputFiles.cpp
+++ b/lld/COFF/InputFiles.cpp
@@ -1067,9 +1067,9 @@ FakeSectionChunk ltoDataSectionChunk(&ltoDataSection.section);
void BitcodeFile::parse() {
std::vector<std::pair<Symbol *, bool>> comdat(obj->getComdatTable().size());
for (size_t i = 0; i != obj->getComdatTable().size(); ++i)
- // FIXME: lto::InputFile doesn't keep enough data to do correct comdat
- // selection handling.
- comdat[i] = symtab->addComdat(this, saver.save(obj->getComdatTable()[i]));
+ // FIXME: Check nodeduplicate
+ comdat[i] =
+ symtab->addComdat(this, saver.save(obj->getComdatTable()[i].first));
for (const lto::InputFile::Symbol &objSym : obj->symbols()) {
StringRef symName = saver.save(objSym.getName());
int comdatIndex = objSym.getComdatIndex();
@@ -1090,7 +1090,7 @@ void BitcodeFile::parse() {
Symbol *alias = symtab->addUndefined(saver.save(fallback));
checkAndSetWeakAlias(symtab, this, sym, alias);
} else if (comdatIndex != -1) {
- if (symName == obj->getComdatTable()[comdatIndex]) {
+ if (symName == obj->getComdatTable()[comdatIndex].first) {
sym = comdat[comdatIndex].first;
if (cast<DefinedRegular>(sym)->data == nullptr)
cast<DefinedRegular>(sym)->data = &fakeSC->repl;
diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp
index 271926a..d5b9efb 100644
--- a/lld/ELF/InputFiles.cpp
+++ b/lld/ELF/InputFiles.cpp
@@ -1744,9 +1744,12 @@ static Symbol *createBitcodeSymbol(const std::vector<bool> &keptComdats,
template <class ELFT> void BitcodeFile::parse() {
std::vector<bool> keptComdats;
- for (StringRef s : obj->getComdatTable())
+ for (std::pair<StringRef, Comdat::SelectionKind> s : obj->getComdatTable()) {
keptComdats.push_back(
- symtab->comdatGroups.try_emplace(CachedHashStringRef(s), this).second);
+ s.second == Comdat::NoDeduplicate ||
+ symtab->comdatGroups.try_emplace(CachedHashStringRef(s.first), this)
+ .second);
+ }
for (const lto::InputFile::Symbol &objSym : obj->symbols())
symbols.push_back(createBitcodeSymbol<ELFT>(keptComdats, objSym, *this));
diff --git a/lld/test/ELF/lto/comdat-nodeduplicate.ll b/lld/test/ELF/lto/comdat-nodeduplicate.ll
new file mode 100644
index 0000000..9535c99
--- /dev/null
+++ b/lld/test/ELF/lto/comdat-nodeduplicate.ll
@@ -0,0 +1,127 @@
+; REQUIRES: x86, shell
+
+;; Keep __profd_foo in a nodeduplicate comdat, despite a comdat of the same name
+;; in a previous object file.
+
+;; Regular LTO
+
+; RUN: rm -rf %t && split-file %s %t
+; RUN: llvm-as %t/a.ll -o %t/a.bc
+; RUN: llvm-as %t/b.ll -o %t/b.bc
+; RUN: llvm-as %t/c.ll -o %t/c.bc
+
+; RUN: ld.lld --save-temps -u foo %t/a.bc --start-lib %t/b.bc --end-lib -o %t/ab
+; RUN: FileCheck %s --check-prefix=RESOL_AB < %t/ab.resolution.txt
+; RUN: llvm-readelf -x .data %t/ab | FileCheck %s --check-prefix=DATA
+
+; RESOL_AB: -r={{.*}}b.bc,__profc_foo,pl{{$}}
+
+;; .data contains a.bc:data. b.bc:data and c.bc:data are discarded.
+; DATA: 0x[[#%x,]] 01000000 00000000 ........
+
+;; __profc_foo from c.bc is non-prevailing and thus discarded.
+; RUN: ld.lld --save-temps -u foo -u c %t/a.bc --start-lib %t/b.bc %t/c.bc --end-lib -o %t/abc
+; RUN: FileCheck %s --check-prefix=RESOL_ABC < %t/abc.resolution.txt
+; RUN: llvm-readelf -x .data %t/abc | FileCheck %s --check-prefix=DATA
+
+; RESOL_ABC: -r={{.*}}b.bc,__profc_foo,pl{{$}}
+; RESOL_ABC: -r={{.*}}c.bc,__profc_foo,{{$}}
+
+;; ThinLTO
+
+; RUN: rm -rf %t && split-file %s %t
+; RUN: opt --module-summary %t/a.ll -o %t/a.bc
+; RUN: opt --module-summary %t/b.ll -o %t/b.bc
+; RUN: opt --module-summary %t/c.ll -o %t/c.bc
+
+; RUN: ld.lld --thinlto-index-only --save-temps -u foo %t/a.bc %t/b.bc -o %t/ab
+; RUN: FileCheck %s --check-prefix=RESOL_AB < %t/ab.resolution.txt
+; RUN: (llvm-dis < %t/b.bc && llvm-dis < %t/b.bc.thinlto.bc) | FileCheck %s --check-prefix=IR_AB
+; RUN: ld.lld -u foo %t/a.bc %t/b.bc -o %t/ab
+; RUN: llvm-readelf -x .data %t/ab | FileCheck %s --check-prefix=DATA
+
+; RUN: ld.lld --thinlto-index-only --save-temps -u foo %t/a.bc --start-lib %t/b.bc --end-lib -o %t/ab
+; RUN: FileCheck %s --check-prefix=RESOL_AB < %t/ab.resolution.txt
+; RUN: (llvm-dis < %t/b.bc && llvm-dis < %t/b.bc.thinlto.bc) | FileCheck %s --check-prefix=IR_AB
+; RUN: ld.lld -u foo %t/a.bc --start-lib %t/b.bc --end-lib -o %t/ab
+; RUN: llvm-readelf -x .data %t/ab | FileCheck %s --check-prefix=DATA
+
+; RUN: ld.lld --thinlto-index-only --save-temps -u foo -u c %t/a.bc --start-lib %t/b.bc %t/c.bc --end-lib -o %t/abc
+; RUN: FileCheck %s --check-prefix=RESOL_ABC < %t/abc.resolution.txt
+; RUN: (llvm-dis < %t/b.bc && llvm-dis < %t/b.bc.thinlto.bc) | FileCheck %s --check-prefix=IR_ABC
+; RUN: ld.lld -u foo %t/a.bc --start-lib %t/b.bc %t/c.bc --end-lib -o %t/abc
+; RUN: llvm-readelf -x .data %t/abc | FileCheck %s --check-prefix=DATA
+
+; IR_AB: gv: (name: "__profd_foo", {{.*}} guid = [[PROFD:[0-9]+]]
+; IR_AB: gv: (name: "__profc_foo", {{.*}} guid = [[PROFC:[0-9]+]]
+
+;; Check extra attributes. b.bc:__profc_foo is prevailing, so it can be internalized.
+; IR_AB: gv: (guid: [[PROFD]], summaries: (variable: (module: ^0, flags: (linkage: private, visibility: default, notEligibleToImport: 0, live: 0, dsoLocal: 1, canAutoHide: 0), varFlags: (readonly: 0, writeonly: 0, constant: 0),
+; IR_AB: gv: (guid: [[PROFC]], summaries: (variable: (module: ^0, flags: (linkage: internal, visibility: hidden, notEligibleToImport: 0, live: 1, dsoLocal: 1, canAutoHide: 0), varFlags: (readonly: 0, writeonly: 0, constant: 0))))
+
+; IR_ABC: gv: (name: "__profd_foo", {{.*}} guid = [[PROFD:[0-9]+]]
+; IR_ABC: gv: (name: "__profc_foo", {{.*}} guid = [[PROFC:[0-9]+]]
+
+;; b.bc:__profc_foo prevails c.bc:__profc_foo, so it is exported and therefore not internalized.
+; IR_ABC: gv: (guid: [[PROFD]], summaries: (variable: (module: ^0, flags: (linkage: private, visibility: default, notEligibleToImport: 0, live: 0, dsoLocal: 1, canAutoHide: 0), varFlags: (readonly: 0, writeonly: 0, constant: 0),
+; IR_ABC: gv: (guid: [[PROFC]], summaries: (variable: (module: ^0, flags: (linkage: weak, visibility: hidden, notEligibleToImport: 0, live: 1, dsoLocal: 1, canAutoHide: 0), varFlags: (readonly: 0, writeonly: 0, constant: 0))))
+
+;--- a.ll
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+$__profc_foo = comdat nodeduplicate
+@__profc_foo = private global i64 1, comdat, align 8
+@__profd_foo = private global i64* @__profc_foo, comdat($__profc_foo), align 8
+
+declare void @b()
+
+define i64 @foo() {
+ %v = load i64, i64* @__profc_foo
+ %inc = add i64 1, %v
+ store i64 %inc, i64* @__profc_foo
+ ret i64 %inc
+}
+
+define void @_start() {
+ call void @b()
+ ret void
+}
+
+;--- b.ll
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+$__profc_foo = comdat nodeduplicate
+@__profc_foo = weak hidden global i64 2, comdat, align 8
+@__profd_foo = private global i64* @__profc_foo, comdat($__profc_foo)
+
+define weak i64 @foo() {
+ %v = load i64, i64* @__profc_foo
+ %inc = add i64 1, %v
+ store i64 %inc, i64* @__profc_foo
+ ret i64 %inc
+}
+
+define void @b() {
+ ret void
+}
+
+;--- c.ll
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+$__profc_foo = comdat nodeduplicate
+@__profc_foo = weak hidden global i64 3, comdat, align 8
+@__profd_foo = private global i64* @__profc_foo, comdat($__profc_foo)
+
+define weak i64 @foo() {
+ %v = load i64, i64* @__profc_foo
+ %inc = add i64 1, %v
+ store i64 %inc, i64* @__profc_foo
+ ret i64 %inc
+}
+
+define void @c() {
+ ret void
+}
diff --git a/lld/wasm/InputFiles.cpp b/lld/wasm/InputFiles.cpp
index 1ee5a8e..35d8dd1 100644
--- a/lld/wasm/InputFiles.cpp
+++ b/lld/wasm/InputFiles.cpp
@@ -758,8 +758,9 @@ void BitcodeFile::parse() {
}
checkArch(t.getArch());
std::vector<bool> keptComdats;
- for (StringRef s : obj->getComdatTable())
- keptComdats.push_back(symtab->addComdat(s));
+ // TODO Support nodeduplicate https://bugs.llvm.org/show_bug.cgi?id=50531
+ for (std::pair<StringRef, Comdat::SelectionKind> s : obj->getComdatTable())
+ keptComdats.push_back(symtab->addComdat(s.first));
for (const lto::InputFile::Symbol &objSym : obj->symbols())
symbols.push_back(createBitcodeSymbol(keptComdats, objSym, *this));
diff --git a/llvm/include/llvm/LTO/LTO.h b/llvm/include/llvm/LTO/LTO.h
index 0cdef3f..ea1dea2 100644
--- a/llvm/include/llvm/LTO/LTO.h
+++ b/llvm/include/llvm/LTO/LTO.h
@@ -119,7 +119,7 @@ private:
StringRef TargetTriple, SourceFileName, COFFLinkerOpts;
std::vector<StringRef> DependentLibraries;
- std::vector<StringRef> ComdatTable;
+ std::vector<std::pair<StringRef, Comdat::SelectionKind>> ComdatTable;
public:
~InputFile();
@@ -172,7 +172,9 @@ public:
StringRef getSourceFileName() const { return SourceFileName; }
// Returns a table with all the comdats used by this file.
- ArrayRef<StringRef> getComdatTable() const { return ComdatTable; }
+ ArrayRef<std::pair<StringRef, Comdat::SelectionKind>> getComdatTable() const {
+ return ComdatTable;
+ }
// Returns the only BitcodeModule from InputFile.
BitcodeModule &getSingleBitcodeModule();
diff --git a/llvm/include/llvm/Object/IRSymtab.h b/llvm/include/llvm/Object/IRSymtab.h
index 4ee32fc..72a51ff 100644
--- a/llvm/include/llvm/Object/IRSymtab.h
+++ b/llvm/include/llvm/Object/IRSymtab.h
@@ -26,6 +26,7 @@
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/iterator_range.h"
+#include "llvm/IR/Comdat.h"
#include "llvm/IR/GlobalValue.h"
#include "llvm/Object/SymbolicFile.h"
#include "llvm/Support/Allocator.h"
@@ -80,6 +81,9 @@ struct Module {
/// This is equivalent to an IR comdat.
struct Comdat {
Str Name;
+
+ // llvm::Comdat::SelectionKind
+ Word SelectionKind;
};
/// Contains the information needed by linkers for symbol resolution, as well as
@@ -132,7 +136,7 @@ struct Header {
/// when the format changes, but it does not need to be incremented if a
/// change to LLVM would cause it to create a different symbol table.
Word Version;
- enum { kCurrentVersion = 2 };
+ enum { kCurrentVersion = 3 };
/// The producer's version string (LLVM_VERSION_STRING " " LLVM_REVISION).
/// Consumers should rebuild the symbol table from IR if the producer's
@@ -280,11 +284,13 @@ public:
StringRef getSourceFileName() const { return str(header().SourceFileName); }
/// Returns a table with all the comdats used by this file.
- std::vector<StringRef> getComdatTable() const {
- std::vector<StringRef> ComdatTable;
+ std::vector<std::pair<StringRef, llvm::Comdat::SelectionKind>>
+ getComdatTable() const {
+ std::vector<std::pair<StringRef, llvm::Comdat::SelectionKind>> ComdatTable;
ComdatTable.reserve(Comdats.size());
for (auto C : Comdats)
- ComdatTable.push_back(str(C.Name));
+ ComdatTable.push_back({str(C.Name), llvm::Comdat::SelectionKind(
+ uint32_t(C.SelectionKind))});
return ComdatTable;
}
diff --git a/llvm/lib/Object/IRSymtab.cpp b/llvm/lib/Object/IRSymtab.cpp
index bcada85..746b008 100644
--- a/llvm/lib/Object/IRSymtab.cpp
+++ b/llvm/lib/Object/IRSymtab.cpp
@@ -199,6 +199,7 @@ Expected<int> Builder::getComdatIndex(const Comdat *C, const Module *M) {
storage::Comdat Comdat;
setStr(Comdat.Name, Saver.save(Name));
+ Comdat.SelectionKind = C->getSelectionKind();
Comdats.push_back(Comdat);
}
diff --git a/llvm/test/LTO/Resolution/X86/symtab.ll b/llvm/test/LTO/Resolution/X86/symtab.ll
index c43494a..88d71ca 100644
--- a/llvm/test/LTO/Resolution/X86/symtab.ll
+++ b/llvm/test/LTO/Resolution/X86/symtab.ll
@@ -18,7 +18,7 @@ define i32 @fun() {
}
; CHECK: D------X @fun2@8
-; CHECK-NEXT: comdat @fun2@8
+; CHECK-NEXT: comdat any @fun2@8
$fun2 = comdat any
define x86_fastcallcc i32 @fun2(i32 inreg %a, i32 inreg %b) comdat {
entry:
@@ -52,7 +52,7 @@ entry:
@g8 = common global i32 0, align 8
; CHECK: D------- _g9
-; CHECK-NEXT: comdat _g9
+; CHECK-NEXT: comdat any _g9
$g9 = comdat any
@g9 = global i32 0, comdat
@@ -64,7 +64,12 @@ $g10 = comdat any
; CHECK-NOT: comdat
@g11 = global i32 0, comdat($g10)
+; CHECK: D------- _g12
+; CHECK-NEXT: comdat nodeduplicate _g12
+$g12 = comdat nodeduplicate
+@g12 = global i32 0, comdat
+
; CHECK: D--WI--- _a1
-; CHECK-NEXT: comdat _g9
+; CHECK-NEXT: comdat any _g9
; CHECK-NEXT: fallback _g9
@a1 = weak alias i32, i32* @g9
diff --git a/llvm/test/Object/X86/irsymtab.ll b/llvm/test/Object/X86/irsymtab.ll
index 2e7b189..8fd7d19 100644
--- a/llvm/test/Object/X86/irsymtab.ll
+++ b/llvm/test/Object/X86/irsymtab.ll
@@ -9,13 +9,13 @@
; BCA: <SYMTAB_BLOCK
; Version stored at offset 0.
-; BCA-NEXT: <BLOB abbrevid=4/> blob data = '\x02\x00\x00\x00\x06\x00\x00\x00\x08\x00\x00\x00L\x00\x00\x00\x01\x00\x00\x00X\x00\x00\x00\x00\x00\x00\x00X\x00\x00\x00\x02\x00\x00\x00\x88\x00\x00\x00\x00\x00\x00\x00\x0E\x00\x00\x00\x18\x00\x00\x00&\x00\x00\x00\x0B\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x88\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\xFF\xFF\xFF\xFF\x00$\x00\x00\x03\x00\x00\x00\x03\x00\x00\x00\x03\x00\x00\x00\x03\x00\x00\x00\xFF\xFF\xFF\xFF\x08$\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x03\x00\x00\x00\x03\x00\x00\x00'
+; BCA-NEXT: <BLOB abbrevid=4/> blob data = '\x03\x00\x00\x00\x06\x00\x00\x00\x08\x00\x00\x00L\x00\x00\x00\x01\x00\x00\x00X\x00\x00\x00\x00\x00\x00\x00X\x00\x00\x00\x02\x00\x00\x00\x88\x00\x00\x00\x00\x00\x00\x00\x0E\x00\x00\x00\x18\x00\x00\x00&\x00\x00\x00\x0B\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x88\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\xFF\xFF\xFF\xFF\x00$\x00\x00\x03\x00\x00\x00\x03\x00\x00\x00\x03\x00\x00\x00\x03\x00\x00\x00\xFF\xFF\xFF\xFF\x08$\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x03\x00\x00\x00\x03\x00\x00\x00'
; BCA-NEXT: </SYMTAB_BLOCK>
; BCA-NEXT: <STRTAB_BLOCK
; BCA-NEXT: <BLOB abbrevid=4/> blob data = 'foobarproducerx86_64-unknown-linux-gnuirsymtab.ll'
; BCA-NEXT: </STRTAB_BLOCK>
-; SYMTAB: version: 2
+; SYMTAB: version: 3
; SYMTAB-NEXT: producer: producer
; SYMTAB-NEXT: target triple: x86_64-unknown-linux-gnu
; SYMTAB-NEXT: source filename: irsymtab.ll
diff --git a/llvm/test/tools/gold/X86/comdat-nodeduplicate.ll b/llvm/test/tools/gold/X86/comdat-nodeduplicate.ll
new file mode 100644
index 0000000..11d04d2
--- /dev/null
+++ b/llvm/test/tools/gold/X86/comdat-nodeduplicate.ll
@@ -0,0 +1,100 @@
+;; Keep __profd_foo in a nodeduplicate comdat, despite a comdat of the same name
+;; in a previous object file.
+
+;; Regular LTO
+
+; RUN: rm -rf %t && split-file %s %t
+; RUN: llvm-as %t/a.ll -o %t/a.bc
+; RUN: llvm-as %t/b.ll -o %t/b.bc
+; RUN: llvm-as %t/c.ll -o %t/c.bc
+
+; RUN: %gold -plugin %llvmshlibdir/LLVMgold%shlibext --plugin-opt=save-temps \
+; RUN: -u foo %t/a.bc --start-lib %t/b.bc --end-lib -o %t/ab
+
+; RUN: FileCheck %s --check-prefix=RESOL_AB < %t/ab.resolution.txt
+; RUN: llvm-readelf -x .data %t/ab | FileCheck %s --check-prefix=DATA
+
+; RESOL_AB: -r={{.*}}b.bc,__profc_foo,pl{{$}}
+
+;; .data contains a.bc:data. b.bc:data and c.bc:data are discarded.
+; DATA: 0x[[#%x,]] 01000000 00000000 ........
+
+;; __profc_foo from c.bc is non-prevailing and thus discarded.
+; RUN: %gold -plugin %llvmshlibdir/LLVMgold%shlibext --plugin-opt=save-temps \
+; RUN: -u foo -u c %t/a.bc --start-lib %t/b.bc %t/c.bc --end-lib -o %t/abc
+; RUN: FileCheck %s --check-prefix=RESOL_ABC < %t/abc.resolution.txt
+; RUN: llvm-readelf -x .data %t/abc | FileCheck %s --check-prefix=DATA
+
+; RESOL_ABC: -r={{.*}}b.bc,__profc_foo,pl{{$}}
+; RESOL_ABC: -r={{.*}}c.bc,__profc_foo,l{{$}}
+
+;; ThinLTO
+
+; RUN: rm -rf %t && split-file %s %t
+; RUN: opt --module-summary %t/a.ll -o %t/a.bc
+; RUN: opt --module-summary %t/b.ll -o %t/b.bc
+; RUN: opt --module-summary %t/c.ll -o %t/c.bc
+
+; RUN: %gold -plugin %llvmshlibdir/LLVMgold%shlibext \
+; RUN: -u foo %t/a.bc --start-lib %t/b.bc %t/c.bc --end-lib -o %t/abc
+; RUN: llvm-readelf -x .data %t/abc | FileCheck %s --check-prefix=DATA
+
+;--- a.ll
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+$__profc_foo = comdat nodeduplicate
+@__profc_foo = private global i64 1, comdat, align 8
+@__profd_foo = private global i64* @__profc_foo, comdat($__profc_foo), align 8
+
+declare void @b()
+
+define i64 @foo() {
+ %v = load i64, i64* @__profc_foo
+ %inc = add i64 1, %v
+ store i64 %inc, i64* @__profc_foo
+ ret i64 %inc
+}
+
+define void @_start() {
+ call void @b()
+ ret void
+}
+
+;--- b.ll
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+$__profc_foo = comdat nodeduplicate
+@__profc_foo = weak hidden global i64 2, comdat, align 8
+@__profd_foo = private global i64* @__profc_foo, comdat($__profc_foo)
+
+define weak i64 @foo() {
+ %v = load i64, i64* @__profc_foo
+ %inc = add i64 1, %v
+ store i64 %inc, i64* @__profc_foo
+ ret i64 %inc
+}
+
+define void @b() {
+ ret void
+}
+
+;--- c.ll
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+$__profc_foo = comdat nodeduplicate
+@__profc_foo = weak hidden global i64 3, comdat, align 8
+@__profd_foo = private global i64* @__profc_foo, comdat($__profc_foo)
+
+define weak i64 @foo() {
+ %v = load i64, i64* @__profc_foo
+ %inc = add i64 1, %v
+ store i64 %inc, i64* @__profc_foo
+ ret i64 %inc
+}
+
+define void @c() {
+ ret void
+}
diff --git a/llvm/tools/gold/gold-plugin.cpp b/llvm/tools/gold/gold-plugin.cpp
index 9870f3a..6bcb1e4 100644
--- a/llvm/tools/gold/gold-plugin.cpp
+++ b/llvm/tools/gold/gold-plugin.cpp
@@ -623,8 +623,10 @@ static ld_plugin_status claim_file_hook(const ld_plugin_input_file *file,
sym.comdat_key = nullptr;
int CI = Sym.getComdatIndex();
if (CI != -1) {
- StringRef C = Obj->getComdatTable()[CI];
- sym.comdat_key = strdup(C.str().c_str());
+ // Not setting comdat_key for nodeduplicate ensuress we don't deduplicate.
+ std::pair<StringRef, Comdat::SelectionKind> C = Obj->getComdatTable()[CI];
+ if (C.second != Comdat::NoDeduplicate)
+ sym.comdat_key = strdup(C.first.str().c_str());
}
sym.resolution = LDPR_UNKNOWN;
diff --git a/llvm/tools/llvm-lto2/llvm-lto2.cpp b/llvm/tools/llvm-lto2/llvm-lto2.cpp
index cedfd6f..c0bff1e 100644
--- a/llvm/tools/llvm-lto2/llvm-lto2.cpp
+++ b/llvm/tools/llvm-lto2/llvm-lto2.cpp
@@ -418,7 +418,8 @@ static int dumpSymtab(int argc, char **argv) {
outs() << '\n';
}
- std::vector<StringRef> ComdatTable = Input->getComdatTable();
+ ArrayRef<std::pair<StringRef, Comdat::SelectionKind>> ComdatTable =
+ Input->getComdatTable();
for (const InputFile::Symbol &Sym : Input->symbols()) {
switch (Sym.getVisibility()) {
case GlobalValue::HiddenVisibility:
@@ -447,8 +448,27 @@ static int dumpSymtab(int argc, char **argv) {
<< Sym.getCommonAlignment() << '\n';
int Comdat = Sym.getComdatIndex();
- if (Comdat != -1)
- outs() << " comdat " << ComdatTable[Comdat] << '\n';
+ if (Comdat != -1) {
+ outs() << " comdat ";
+ switch (ComdatTable[Comdat].second) {
+ case Comdat::Any:
+ outs() << "any";
+ break;
+ case Comdat::ExactMatch:
+ outs() << "exactmatch";
+ break;
+ case Comdat::Largest:
+ outs() << "largest";
+ break;
+ case Comdat::NoDeduplicate:
+ outs() << "nodeduplicate";
+ break;
+ case Comdat::SameSize:
+ outs() << "samesize";
+ break;
+ }
+ outs() << ' ' << ComdatTable[Comdat].first << '\n';
+ }
if (TT.isOSBinFormatCOFF() && Sym.isWeak() && Sym.isIndirect())
outs() << " fallback " << Sym.getCOFFWeakExternalFallback() << '\n';