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