xref: /freebsd/contrib/llvm-project/lld/ELF/BPSectionOrderer.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
1*700637cbSDimitry Andric //===- BPSectionOrderer.cpp -----------------------------------------------===//
2*700637cbSDimitry Andric //
3*700637cbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*700637cbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*700637cbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*700637cbSDimitry Andric //
7*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
8*700637cbSDimitry Andric 
9*700637cbSDimitry Andric #include "BPSectionOrderer.h"
10*700637cbSDimitry Andric #include "InputFiles.h"
11*700637cbSDimitry Andric #include "InputSection.h"
12*700637cbSDimitry Andric #include "SymbolTable.h"
13*700637cbSDimitry Andric #include "Symbols.h"
14*700637cbSDimitry Andric #include "lld/Common/BPSectionOrdererBase.inc"
15*700637cbSDimitry Andric #include "llvm/Support/Endian.h"
16*700637cbSDimitry Andric 
17*700637cbSDimitry Andric using namespace llvm;
18*700637cbSDimitry Andric using namespace lld::elf;
19*700637cbSDimitry Andric 
20*700637cbSDimitry Andric namespace {
21*700637cbSDimitry Andric struct BPOrdererELF;
22*700637cbSDimitry Andric }
23*700637cbSDimitry Andric template <> struct lld::BPOrdererTraits<struct BPOrdererELF> {
24*700637cbSDimitry Andric   using Section = elf::InputSectionBase;
25*700637cbSDimitry Andric   using Defined = elf::Defined;
26*700637cbSDimitry Andric };
27*700637cbSDimitry Andric namespace {
28*700637cbSDimitry Andric struct BPOrdererELF : lld::BPOrderer<BPOrdererELF> {
29*700637cbSDimitry Andric   DenseMap<const InputSectionBase *, Defined *> secToSym;
30*700637cbSDimitry Andric 
getSize__anon82a32a8b0211::BPOrdererELF31*700637cbSDimitry Andric   static uint64_t getSize(const Section &sec) { return sec.getSize(); }
isCodeSection__anon82a32a8b0211::BPOrdererELF32*700637cbSDimitry Andric   static bool isCodeSection(const Section &sec) {
33*700637cbSDimitry Andric     return sec.flags & ELF::SHF_EXECINSTR;
34*700637cbSDimitry Andric   }
getSymbols__anon82a32a8b0211::BPOrdererELF35*700637cbSDimitry Andric   ArrayRef<Defined *> getSymbols(const Section &sec) {
36*700637cbSDimitry Andric     auto it = secToSym.find(&sec);
37*700637cbSDimitry Andric     if (it == secToSym.end())
38*700637cbSDimitry Andric       return {};
39*700637cbSDimitry Andric     return ArrayRef(it->second);
40*700637cbSDimitry Andric   }
41*700637cbSDimitry Andric 
42*700637cbSDimitry Andric   static void
getSectionHashes__anon82a32a8b0211::BPOrdererELF43*700637cbSDimitry Andric   getSectionHashes(const Section &sec, SmallVectorImpl<uint64_t> &hashes,
44*700637cbSDimitry Andric                    const DenseMap<const void *, uint64_t> &sectionToIdx) {
45*700637cbSDimitry Andric     constexpr unsigned windowSize = 4;
46*700637cbSDimitry Andric 
47*700637cbSDimitry Andric     // Calculate content hashes: k-mers and the last k-1 bytes.
48*700637cbSDimitry Andric     ArrayRef<uint8_t> data = sec.content();
49*700637cbSDimitry Andric     if (data.size() >= windowSize)
50*700637cbSDimitry Andric       for (size_t i = 0; i <= data.size() - windowSize; ++i)
51*700637cbSDimitry Andric         hashes.push_back(support::endian::read32le(data.data() + i));
52*700637cbSDimitry Andric     for (uint8_t byte : data.take_back(windowSize - 1))
53*700637cbSDimitry Andric       hashes.push_back(byte);
54*700637cbSDimitry Andric 
55*700637cbSDimitry Andric     llvm::sort(hashes);
56*700637cbSDimitry Andric     hashes.erase(llvm::unique(hashes), hashes.end());
57*700637cbSDimitry Andric   }
58*700637cbSDimitry Andric 
getSymName__anon82a32a8b0211::BPOrdererELF59*700637cbSDimitry Andric   static StringRef getSymName(const Defined &sym) { return sym.getName(); }
getSymValue__anon82a32a8b0211::BPOrdererELF60*700637cbSDimitry Andric   static uint64_t getSymValue(const Defined &sym) { return sym.value; }
getSymSize__anon82a32a8b0211::BPOrdererELF61*700637cbSDimitry Andric   static uint64_t getSymSize(const Defined &sym) { return sym.size; }
62*700637cbSDimitry Andric };
63*700637cbSDimitry Andric } // namespace
64*700637cbSDimitry Andric 
runBalancedPartitioning(Ctx & ctx,StringRef profilePath,bool forFunctionCompression,bool forDataCompression,bool compressionSortStartupFunctions,bool verbose)65*700637cbSDimitry Andric DenseMap<const InputSectionBase *, int> elf::runBalancedPartitioning(
66*700637cbSDimitry Andric     Ctx &ctx, StringRef profilePath, bool forFunctionCompression,
67*700637cbSDimitry Andric     bool forDataCompression, bool compressionSortStartupFunctions,
68*700637cbSDimitry Andric     bool verbose) {
69*700637cbSDimitry Andric   // Collect candidate sections and associated symbols.
70*700637cbSDimitry Andric   SmallVector<InputSectionBase *> sections;
71*700637cbSDimitry Andric   DenseMap<CachedHashStringRef, std::set<unsigned>> rootSymbolToSectionIdxs;
72*700637cbSDimitry Andric   BPOrdererELF orderer;
73*700637cbSDimitry Andric 
74*700637cbSDimitry Andric   auto addSection = [&](Symbol &sym) {
75*700637cbSDimitry Andric     auto *d = dyn_cast<Defined>(&sym);
76*700637cbSDimitry Andric     if (!d)
77*700637cbSDimitry Andric       return;
78*700637cbSDimitry Andric     auto *sec = dyn_cast_or_null<InputSection>(d->section);
79*700637cbSDimitry Andric     // Skip empty, discarded, ICF folded sections. Skipping ICF folded sections
80*700637cbSDimitry Andric     // reduces duplicate detection work in BPSectionOrderer.
81*700637cbSDimitry Andric     if (!sec || sec->size == 0 || !sec->isLive() || sec->repl != sec ||
82*700637cbSDimitry Andric         !orderer.secToSym.try_emplace(sec, d).second)
83*700637cbSDimitry Andric       return;
84*700637cbSDimitry Andric     rootSymbolToSectionIdxs[CachedHashStringRef(
85*700637cbSDimitry Andric                                 lld::utils::getRootSymbol(sym.getName()))]
86*700637cbSDimitry Andric         .insert(sections.size());
87*700637cbSDimitry Andric     sections.emplace_back(sec);
88*700637cbSDimitry Andric   };
89*700637cbSDimitry Andric 
90*700637cbSDimitry Andric   for (Symbol *sym : ctx.symtab->getSymbols())
91*700637cbSDimitry Andric     addSection(*sym);
92*700637cbSDimitry Andric   for (ELFFileBase *file : ctx.objectFiles)
93*700637cbSDimitry Andric     for (Symbol *sym : file->getLocalSymbols())
94*700637cbSDimitry Andric       addSection(*sym);
95*700637cbSDimitry Andric   return orderer.computeOrder(profilePath, forFunctionCompression,
96*700637cbSDimitry Andric                               forDataCompression,
97*700637cbSDimitry Andric                               compressionSortStartupFunctions, verbose,
98*700637cbSDimitry Andric                               sections, rootSymbolToSectionIdxs);
99*700637cbSDimitry Andric }
100