diff options
author | Michael J. Spencer <bigcheesegs@gmail.com> | 2018-10-02 00:17:15 +0000 |
---|---|---|
committer | Michael J. Spencer <bigcheesegs@gmail.com> | 2018-10-02 00:17:15 +0000 |
commit | 999b654f1de51a41270ef40635e634112503301b (patch) | |
tree | 192a993544cfc7ef73fbe946de59be9a8a64dac6 | |
parent | 22336491c25ccc2e17db4ee02a660bce35f8d01b (diff) |
[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
-rw-r--r-- | lld/ELF/Driver.cpp | 22 | ||||
-rw-r--r-- | lld/ELF/InputFiles.cpp | 5 | ||||
-rw-r--r-- | lld/ELF/InputFiles.h | 4 | ||||
-rw-r--r-- | lld/test/ELF/cgprofile-obj-warn.s | 37 | ||||
-rw-r--r-- | lld/test/ELF/cgprofile-obj.s | 41 |
5 files changed, 109 insertions, 0 deletions
diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp index 98ec3938635..34bfba8c941 100644 --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -679,6 +679,27 @@ static void readCallGraph(MemoryBufferRef MB) { } } +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 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) { 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/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp index 36d559f3e65..c535a27b889 100644 --- a/lld/ELF/InputFiles.cpp +++ b/lld/ELF/InputFiles.cpp @@ -412,6 +412,11 @@ void ObjFile<ELFT>::initializeSections( 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/lld/ELF/InputFiles.h b/lld/ELF/InputFiles.h index 50583de16cd..3481a0a54d5 100644 --- a/lld/ELF/InputFiles.h +++ b/lld/ELF/InputFiles.h @@ -171,6 +171,7 @@ template <class ELFT> class ObjFile : public ELFFileBase<ELFT> { 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 @@ public: // 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/lld/test/ELF/cgprofile-obj-warn.s b/lld/test/ELF/cgprofile-obj-warn.s new file mode 100644 index 00000000000..188216091a6 --- /dev/null +++ b/lld/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/lld/test/ELF/cgprofile-obj.s b/lld/test/ELF/cgprofile-obj.s new file mode 100644 index 00000000000..90cd0f46133 --- /dev/null +++ b/lld/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 |