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> §ionToIdx) {
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