
When using Temporal Profiling with the BP algorithm, we encounter an issue with the internal function reorder. In cases where the symbol table contains entries like: ``` Symbol table '.symtab' contains 45 entries: Num: Value Size Type Bind Vis Ndx Name 10: 0000000000000000 0 SECTION LOCAL DEFAULT 18 .text.L1 11: 0000000000000000 24 FUNC LOCAL DEFAULT 18 L1 ```` The zero-sized section symbol .text.L1 gets stored in the secToSym map first. However, when the function lookup searches for L1 (as seen in [BPSectionOrdererBase.inc:191](https://github.com/llvm/llvm-project/blob/main/lld/include/lld/Common/BPSectionOrdererBase.inc#L191)), it fails to find the correct entry in rootSymbolToSectionIdxs because the section symbol has already claimed that slot. This patch fixes the issue by skipping zero-sized symbols during the addSections process, ensuring that function symbols are properly registered for lookup.
102 lines
3.7 KiB
C++
102 lines
3.7 KiB
C++
//===- 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 section symbols. Skip empty, discarded, ICF folded sections, .bss.
|
|
// Skipping ICF folded sections reduces duplicate detection work in
|
|
// BPSectionOrderer.
|
|
if (sym.isSection() || !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);
|
|
}
|