[ELF] Read the call graph profile from object files.
This uses the call graph profile embedded in the object files to construct the call graph.
This is read from a SHT_LLVM_CALL_GRAPH_PROFILE (0x6fff4c02) section as (uint32_t, uint32_t, uint64_t) tuples as (from symbol index, to symbol index, weight).
Differential Revision: https://reviews.llvm.org/D45850
git-svn-id: https://llvm.org/svn/llvm-project/lld/trunk@343552 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/ELF/Driver.cpp b/ELF/Driver.cpp
index 98ec393..34bfba8 100644
--- a/ELF/Driver.cpp
+++ b/ELF/Driver.cpp
@@ -679,6 +679,27 @@
}
}
+template <class ELFT> static void readCallGraphsFromObjectFiles() {
+ auto FindSection = [&](const Symbol *Sym) -> const InputSectionBase * {
+ warnUnorderableSymbol(Sym);
+ if (const auto *SymD = dyn_cast<Defined>(Sym))
+ return dyn_cast_or_null<InputSectionBase>(SymD->Section);
+ return nullptr;
+ };
+
+ for (auto File : ObjectFiles) {
+ auto *Obj = cast<ObjFile<ELFT>>(File);
+ for (const Elf_CGProfile_Impl<ELFT> &CGPE : Obj->CGProfile) {
+ const InputSectionBase *FromSB =
+ FindSection(&Obj->getSymbol(CGPE.cgp_from));
+ const InputSectionBase *ToSB = FindSection(&Obj->getSymbol(CGPE.cgp_to));
+ if (!FromSB || !ToSB)
+ continue;
+ Config->CallGraphProfile[{FromSB, ToSB}] += CGPE.cgp_weight;
+ }
+ }
+}
+
static bool getCompressDebugSections(opt::InputArgList &Args) {
StringRef S = Args.getLastArgValue(OPT_compress_debug_sections, "none");
if (S == "none")
@@ -1598,6 +1619,7 @@
if (auto *Arg = Args.getLastArg(OPT_call_graph_ordering_file))
if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue()))
readCallGraph(*Buffer);
+ readCallGraphsFromObjectFiles<ELFT>();
// Write the result to the file.
writeResult<ELFT>();
diff --git a/ELF/InputFiles.cpp b/ELF/InputFiles.cpp
index 36d559f..c535a27 100644
--- a/ELF/InputFiles.cpp
+++ b/ELF/InputFiles.cpp
@@ -412,6 +412,11 @@
continue;
const Elf_Shdr &Sec = ObjSections[I];
+ if (Sec.sh_type == ELF::SHT_LLVM_CALL_GRAPH_PROFILE)
+ CGProfile = check(
+ this->getObj().template getSectionContentsAsArray<Elf_CGProfile>(
+ &Sec));
+
// SHF_EXCLUDE'ed sections are discarded by the linker. However,
// if -r is given, we'll let the final link discard such sections.
// This is compatible with GNU.
diff --git a/ELF/InputFiles.h b/ELF/InputFiles.h
index 50583de..3481a0a 100644
--- a/ELF/InputFiles.h
+++ b/ELF/InputFiles.h
@@ -171,6 +171,7 @@
typedef typename ELFT::Sym Elf_Sym;
typedef typename ELFT::Shdr Elf_Shdr;
typedef typename ELFT::Word Elf_Word;
+ typedef typename ELFT::CGProfile Elf_CGProfile;
StringRef getShtGroupSignature(ArrayRef<Elf_Shdr> Sections,
const Elf_Shdr &Sec);
@@ -220,6 +221,9 @@
// Pointer to this input file's .llvm_addrsig section, if it has one.
const Elf_Shdr *AddrsigSec = nullptr;
+ // SHT_LLVM_CALL_GRAPH_PROFILE table
+ ArrayRef<Elf_CGProfile> CGProfile;
+
private:
void
initializeSections(llvm::DenseSet<llvm::CachedHashStringRef> &ComdatGroups);
diff --git a/test/ELF/cgprofile-obj-warn.s b/test/ELF/cgprofile-obj-warn.s
new file mode 100644
index 0000000..1882160
--- /dev/null
+++ b/test/ELF/cgprofile-obj-warn.s
@@ -0,0 +1,37 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+# RUN: ld.lld -e A %t -o /dev/null \
+# RUN: -noinhibit-exec -icf=all 2>&1 | FileCheck %s
+
+ .section .text.C,"ax",@progbits
+ .globl C
+C:
+ mov poppy, %rax
+ retq
+
+B = 0x1234
+
+ .section .text.A,"ax",@progbits
+ .globl A
+A:
+ mov poppy, %rax
+ retq
+
+ .cg_profile A, B, 100
+ .cg_profile A, C, 40
+ .cg_profile B, C, 30
+ .cg_profile adena1, A, 30
+ .cg_profile A, adena2, 30
+ .cg_profile poppy, A, 30
+
+# CHECK: unable to order absolute symbol: B
+# CHECK: unable to order undefined symbol: adena1
+# CHECK: unable to order undefined symbol: adena2
+# CHECK: unable to order undefined symbol: poppy
+
+# RUN: ld.lld %t -o /dev/null \
+# RUN: -noinhibit-exec -icf=all --no-warn-symbol-ordering 2>&1 \
+# RUN: | FileCheck %s --check-prefix=NOWARN
+# NOWARN-NOT: unable to order
diff --git a/test/ELF/cgprofile-obj.s b/test/ELF/cgprofile-obj.s
new file mode 100644
index 0000000..90cd0f4
--- /dev/null
+++ b/test/ELF/cgprofile-obj.s
@@ -0,0 +1,41 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: ld.lld -e A %t -o %t2
+# RUN: llvm-readobj -symbols %t2 | FileCheck %s
+
+ .section .text.D,"ax",@progbits
+D:
+ retq
+
+ .section .text.C,"ax",@progbits
+ .globl C
+C:
+ retq
+
+ .section .text.B,"ax",@progbits
+ .globl B
+B:
+ retq
+
+ .section .text.A,"ax",@progbits
+ .globl A
+A:
+Aa:
+ retq
+
+ .cg_profile A, B, 10
+ .cg_profile A, B, 10
+ .cg_profile Aa, B, 80
+ .cg_profile A, C, 40
+ .cg_profile B, C, 30
+ .cg_profile C, D, 90
+
+# CHECK: Name: D
+# CHECK-NEXT: Value: 0x201003
+# CHECK: Name: A
+# CHECK-NEXT: Value: 0x201000
+# CHECK: Name: B
+# CHECK-NEXT: Value: 0x201001
+# CHECK: Name: C
+# CHECK-NEXT: Value: 0x201002