mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-26 14:36:08 +00:00

Make FunctionLayout::updateLayoutIndices const and add an overloaded function that updates LayoutIndices given an Order parameter.
262 lines
8.0 KiB
C++
262 lines
8.0 KiB
C++
//===- bolt/Core/FunctionLayout.cpp - Fragmented Function Layout -*- C++ -*-==//
|
|
//
|
|
// 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 "bolt/Core/FunctionLayout.h"
|
|
#include "bolt/Core/BinaryBasicBlock.h"
|
|
#include "llvm/ADT/STLExtras.h"
|
|
#include "llvm/ADT/edit_distance.h"
|
|
#include <algorithm>
|
|
#include <iterator>
|
|
|
|
using namespace llvm;
|
|
using namespace bolt;
|
|
|
|
FunctionFragment::FunctionFragment(FunctionLayout &Layout,
|
|
const FragmentNum Num)
|
|
: Layout(&Layout), Num(Num), StartIndex(Layout.block_size()) {}
|
|
|
|
FunctionFragment::iterator FunctionFragment::begin() {
|
|
return iterator(Layout->block_begin() + StartIndex);
|
|
}
|
|
FunctionFragment::const_iterator FunctionFragment::begin() const {
|
|
return const_iterator(Layout->block_begin() + StartIndex);
|
|
}
|
|
FunctionFragment::iterator FunctionFragment::end() {
|
|
return iterator(Layout->block_begin() + StartIndex + Size);
|
|
}
|
|
FunctionFragment::const_iterator FunctionFragment::end() const {
|
|
return const_iterator(Layout->block_begin() + StartIndex + Size);
|
|
}
|
|
|
|
const BinaryBasicBlock *FunctionFragment::front() const { return *begin(); }
|
|
|
|
FunctionLayout::FunctionLayout() { addFragment(); }
|
|
|
|
FunctionLayout::FunctionLayout(const FunctionLayout &Other)
|
|
: Blocks(Other.Blocks) {
|
|
for (FunctionFragment *const FF : Other.Fragments) {
|
|
auto *Copy = new FunctionFragment(*FF);
|
|
Copy->Layout = this;
|
|
Fragments.emplace_back(Copy);
|
|
}
|
|
}
|
|
|
|
FunctionLayout::FunctionLayout(FunctionLayout &&Other)
|
|
: Fragments(std::move(Other.Fragments)), Blocks(std::move(Other.Blocks)) {
|
|
for (FunctionFragment *const F : Fragments)
|
|
F->Layout = this;
|
|
}
|
|
|
|
FunctionLayout &FunctionLayout::operator=(const FunctionLayout &Other) {
|
|
Blocks = Other.Blocks;
|
|
for (FunctionFragment *const FF : Other.Fragments) {
|
|
auto *const Copy = new FunctionFragment(*FF);
|
|
Copy->Layout = this;
|
|
Fragments.emplace_back(Copy);
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
FunctionLayout &FunctionLayout::operator=(FunctionLayout &&Other) {
|
|
Fragments = std::move(Other.Fragments);
|
|
Blocks = std::move(Other.Blocks);
|
|
for (FunctionFragment *const FF : Fragments)
|
|
FF->Layout = this;
|
|
return *this;
|
|
}
|
|
|
|
FunctionLayout::~FunctionLayout() {
|
|
for (FunctionFragment *const F : Fragments) {
|
|
delete F;
|
|
}
|
|
}
|
|
|
|
FunctionFragment &FunctionLayout::addFragment() {
|
|
FunctionFragment *const FF =
|
|
new FunctionFragment(*this, FragmentNum(Fragments.size()));
|
|
Fragments.emplace_back(FF);
|
|
return *FF;
|
|
}
|
|
|
|
FunctionFragment &FunctionLayout::getFragment(FragmentNum Num) {
|
|
return *Fragments[Num.get()];
|
|
}
|
|
|
|
const FunctionFragment &FunctionLayout::getFragment(FragmentNum Num) const {
|
|
return *Fragments[Num.get()];
|
|
}
|
|
|
|
const FunctionFragment &
|
|
FunctionLayout::findFragment(const BinaryBasicBlock *const BB) const {
|
|
return getFragment(BB->getFragmentNum());
|
|
}
|
|
|
|
void FunctionLayout::addBasicBlock(BinaryBasicBlock *const BB) {
|
|
BB->setLayoutIndex(Blocks.size());
|
|
Blocks.emplace_back(BB);
|
|
Fragments.back()->Size++;
|
|
}
|
|
|
|
void FunctionLayout::insertBasicBlocks(
|
|
const BinaryBasicBlock *const InsertAfter,
|
|
const ArrayRef<BinaryBasicBlock *> NewBlocks) {
|
|
block_iterator InsertBeforePos = Blocks.begin();
|
|
FragmentNum InsertFragmentNum = FragmentNum::main();
|
|
unsigned LayoutIndex = 0;
|
|
|
|
if (InsertAfter) {
|
|
InsertBeforePos = std::next(findBasicBlockPos(InsertAfter));
|
|
InsertFragmentNum = InsertAfter->getFragmentNum();
|
|
LayoutIndex = InsertAfter->getLayoutIndex();
|
|
}
|
|
|
|
llvm::copy(NewBlocks, std::inserter(Blocks, InsertBeforePos));
|
|
|
|
for (BinaryBasicBlock *const BB : NewBlocks) {
|
|
BB->setFragmentNum(InsertFragmentNum);
|
|
BB->setLayoutIndex(LayoutIndex++);
|
|
}
|
|
|
|
const fragment_iterator InsertFragment =
|
|
fragment_begin() + InsertFragmentNum.get();
|
|
InsertFragment->Size += NewBlocks.size();
|
|
|
|
const fragment_iterator TailBegin = std::next(InsertFragment);
|
|
auto const UpdateFragment = [&](FunctionFragment &FF) {
|
|
FF.StartIndex += NewBlocks.size();
|
|
for (BinaryBasicBlock *const BB : FF)
|
|
BB->setLayoutIndex(LayoutIndex++);
|
|
};
|
|
std::for_each(TailBegin, fragment_end(), UpdateFragment);
|
|
}
|
|
|
|
void FunctionLayout::eraseBasicBlocks(
|
|
const DenseSet<const BinaryBasicBlock *> ToErase) {
|
|
const auto IsErased = [&](const BinaryBasicBlock *const BB) {
|
|
return ToErase.contains(BB);
|
|
};
|
|
|
|
unsigned TotalErased = 0;
|
|
for (FunctionFragment &FF : fragments()) {
|
|
unsigned Erased = count_if(FF, IsErased);
|
|
FF.Size -= Erased;
|
|
FF.StartIndex -= TotalErased;
|
|
TotalErased += Erased;
|
|
}
|
|
llvm::erase_if(Blocks, IsErased);
|
|
|
|
// Remove empty fragments at the end
|
|
const auto IsEmpty = [](const FunctionFragment *const FF) {
|
|
return FF->empty();
|
|
};
|
|
const FragmentListType::iterator EmptyTailBegin =
|
|
llvm::find_if_not(reverse(Fragments), IsEmpty).base();
|
|
for (FunctionFragment *const FF :
|
|
llvm::make_range(EmptyTailBegin, Fragments.end()))
|
|
delete FF;
|
|
Fragments.erase(EmptyTailBegin, Fragments.end());
|
|
|
|
updateLayoutIndices();
|
|
}
|
|
|
|
void FunctionLayout::updateLayoutIndices() const {
|
|
unsigned BlockIndex = 0;
|
|
for (const FunctionFragment &FF : fragments()) {
|
|
for (BinaryBasicBlock *const BB : FF) {
|
|
BB->setLayoutIndex(BlockIndex++);
|
|
BB->setFragmentNum(FF.getFragmentNum());
|
|
}
|
|
}
|
|
}
|
|
void FunctionLayout::updateLayoutIndices(
|
|
ArrayRef<BinaryBasicBlock *> Order) const {
|
|
for (auto [Index, BB] : llvm::enumerate(Order))
|
|
BB->setLayoutIndex(Index);
|
|
}
|
|
|
|
bool FunctionLayout::update(const ArrayRef<BinaryBasicBlock *> NewLayout) {
|
|
const bool EqualBlockOrder = llvm::equal(Blocks, NewLayout);
|
|
if (EqualBlockOrder) {
|
|
const bool EqualPartitioning =
|
|
llvm::all_of(fragments(), [](const FunctionFragment &FF) {
|
|
return llvm::all_of(FF, [&](const BinaryBasicBlock *const BB) {
|
|
return FF.Num == BB->getFragmentNum();
|
|
});
|
|
});
|
|
if (EqualPartitioning)
|
|
return false;
|
|
}
|
|
|
|
clear();
|
|
|
|
// Generate fragments
|
|
for (BinaryBasicBlock *const BB : NewLayout) {
|
|
FragmentNum Num = BB->getFragmentNum();
|
|
|
|
// Add empty fragments if necessary
|
|
while (Fragments.back()->getFragmentNum() < Num)
|
|
addFragment();
|
|
|
|
// Set the next fragment to point one past the current BB
|
|
addBasicBlock(BB);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void FunctionLayout::clear() {
|
|
Blocks = BasicBlockListType();
|
|
// If the binary does not have relocations and is not split, the function will
|
|
// be written to the output stream at its original file offset (see
|
|
// `RewriteInstance::rewriteFile`). Hence, when the layout is cleared, retain
|
|
// the main fragment, so that this information is not lost.
|
|
for (FunctionFragment *const FF : llvm::drop_begin(Fragments))
|
|
delete FF;
|
|
Fragments = FragmentListType{Fragments.front()};
|
|
getMainFragment().Size = 0;
|
|
}
|
|
|
|
const BinaryBasicBlock *
|
|
FunctionLayout::getBasicBlockAfter(const BinaryBasicBlock *BB,
|
|
bool IgnoreSplits) const {
|
|
const block_const_iterator BBPos = find(blocks(), BB);
|
|
if (BBPos == block_end())
|
|
return nullptr;
|
|
|
|
const block_const_iterator BlockAfter = std::next(BBPos);
|
|
if (BlockAfter == block_end())
|
|
return nullptr;
|
|
|
|
if (!IgnoreSplits)
|
|
if (BlockAfter == getFragment(BB->getFragmentNum()).end())
|
|
return nullptr;
|
|
|
|
return *BlockAfter;
|
|
}
|
|
|
|
bool FunctionLayout::isSplit() const {
|
|
const unsigned NonEmptyFragCount = llvm::count_if(
|
|
fragments(), [](const FunctionFragment &FF) { return !FF.empty(); });
|
|
return NonEmptyFragCount >= 2;
|
|
}
|
|
|
|
uint64_t FunctionLayout::getEditDistance(
|
|
const ArrayRef<const BinaryBasicBlock *> OldBlockOrder) const {
|
|
return ComputeEditDistance<const BinaryBasicBlock *>(OldBlockOrder, Blocks);
|
|
}
|
|
|
|
FunctionLayout::block_const_iterator
|
|
FunctionLayout::findBasicBlockPos(const BinaryBasicBlock *BB) const {
|
|
return block_const_iterator(find(Blocks, BB));
|
|
}
|
|
|
|
FunctionLayout::block_iterator
|
|
FunctionLayout::findBasicBlockPos(const BinaryBasicBlock *BB) {
|
|
return find(Blocks, BB);
|
|
}
|