forked from OSchip/llvm-project
[BOLT] Add main fragment to function layout
Functions that do not contain any code still have to be emitted. This occurs on AArch64 where functions can consist only of a constant island. To support fragment semantics in code emission, this commits adds a guaranteed main fragment to function layout. This fragment might be empty, but allows us omit checks whether the function is empty in most places. Reviewed By: rafauler Differential Revision: https://reviews.llvm.org/D130051
This commit is contained in:
parent
7ed3d81333
commit
0f8412c19c
|
@ -23,6 +23,7 @@
|
|||
#include "llvm/ADT/DenseSet.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/iterator.h"
|
||||
#include "llvm/ADT/iterator_range.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace bolt {
|
||||
|
@ -100,7 +101,10 @@ public:
|
|||
const FunctionLayout *Layout;
|
||||
|
||||
FragmentIterator(FragmentNum Num, const FunctionLayout *Layout)
|
||||
: Num(Num), Layout(Layout) {}
|
||||
: Num(Num), Layout(Layout) {
|
||||
assert(Num.get() <= Layout->fragment_size() &&
|
||||
"Initializing iterator out of bounds");
|
||||
}
|
||||
|
||||
public:
|
||||
bool operator==(const FragmentIterator &Other) const {
|
||||
|
@ -108,15 +112,20 @@ public:
|
|||
}
|
||||
|
||||
FunctionFragment operator*() const {
|
||||
assert(Num.get() < Layout->fragment_size() &&
|
||||
"Dereferencing end() iterator (or past it)");
|
||||
return FunctionFragment(Num, *Layout);
|
||||
}
|
||||
|
||||
FragmentIterator &operator++() {
|
||||
assert(Num.get() < Layout->fragment_size() &&
|
||||
"Incrementing iterator past end()");
|
||||
Num = FragmentNum(Num.get() + 1);
|
||||
return *this;
|
||||
}
|
||||
|
||||
FragmentIterator &operator--() {
|
||||
assert(Num.get() > 0 && "Decrementing iterator past begin()");
|
||||
Num = FragmentNum(Num.get() - 1);
|
||||
return *this;
|
||||
}
|
||||
|
@ -133,8 +142,9 @@ private:
|
|||
BasicBlockListType Blocks;
|
||||
/// List of indices dividing block list into fragments. To simplify iteration,
|
||||
/// we have `Fragments.back()` equals `Blocks.size()`. Hence,
|
||||
/// `Fragments.size()` equals `this->size() + 1`.
|
||||
FragmentListType Fragments = {0};
|
||||
/// `Fragments.size()` equals `this->size() + 1`. Always contains at least one
|
||||
/// fragment.
|
||||
FragmentListType Fragments = {0, 0};
|
||||
BasicBlockListType PreviousBlocks;
|
||||
FragmentListType PreviousFragments;
|
||||
|
||||
|
@ -188,14 +198,23 @@ public:
|
|||
/// layout after basic block reordering.
|
||||
uint64_t getEditDistance() const;
|
||||
|
||||
size_t size() const { return Fragments.size() - 1; }
|
||||
bool empty() const { return Fragments.size() == 1; }
|
||||
const_iterator begin() const { return {FragmentNum(0), this}; }
|
||||
const_iterator end() const { return {FragmentNum(size()), this}; }
|
||||
FunctionFragment front() const { return *begin(); }
|
||||
FunctionFragment back() const { return *std::prev(end()); }
|
||||
FunctionFragment operator[](const FragmentNum Num) const {
|
||||
return getFragment(Num);
|
||||
/// True if the function is split into at most 2 fragments. Mostly used for
|
||||
/// checking whether a function can be processed in places that do not support
|
||||
/// multiple fragments yet.
|
||||
bool isHotColdSplit() const { return fragment_size() <= 2; }
|
||||
|
||||
size_t fragment_size() const {
|
||||
assert(Fragments.size() >= 2 &&
|
||||
"Layout should have at least one fragment.");
|
||||
return Fragments.size() - 1;
|
||||
}
|
||||
bool fragment_empty() const { return Fragments.size() == 1; }
|
||||
const_iterator fragment_begin() const { return {FragmentNum(0), this}; }
|
||||
const_iterator fragment_end() const {
|
||||
return {FragmentNum(fragment_size()), this};
|
||||
}
|
||||
iterator_range<const_iterator> fragments() const {
|
||||
return {fragment_begin(), fragment_end()};
|
||||
}
|
||||
|
||||
size_t block_size() const { return Blocks.size(); }
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "bolt/Core/BinaryContext.h"
|
||||
#include "bolt/Core/BinaryFunction.h"
|
||||
#include "bolt/Core/DebugData.h"
|
||||
#include "bolt/Core/FunctionLayout.h"
|
||||
#include "bolt/Utils/CommandLineOpts.h"
|
||||
#include "bolt/Utils/Utils.h"
|
||||
#include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h"
|
||||
|
@ -396,12 +397,12 @@ void BinaryEmitter::emitFunctionBody(BinaryFunction &BF, bool EmitColdPart,
|
|||
if (!EmitCodeOnly && EmitColdPart && BF.hasConstantIsland())
|
||||
BF.duplicateConstantIslands();
|
||||
|
||||
const FunctionFragment FF = BF.getLayout().getFragment(
|
||||
EmitColdPart ? FragmentNum::cold() : FragmentNum::hot());
|
||||
|
||||
// Track the first emitted instruction with debug info.
|
||||
bool FirstInstr = true;
|
||||
for (BinaryBasicBlock *BB : BF.getLayout().blocks()) {
|
||||
if (EmitColdPart != BB->isCold())
|
||||
continue;
|
||||
|
||||
for (BinaryBasicBlock *const BB : FF) {
|
||||
if ((opts::AlignBlocks || opts::PreserveBlocksAlignment) &&
|
||||
BB->getAlignment() > 1)
|
||||
Streamer.emitCodeAlignment(BB->getAlignment(), &*BC.STI,
|
||||
|
|
|
@ -503,10 +503,10 @@ void BinaryFunction::print(raw_ostream &OS, std::string Annotation,
|
|||
}
|
||||
|
||||
StringRef SplitPointMsg = "";
|
||||
for (const FunctionFragment F : Layout) {
|
||||
for (const FunctionFragment FF : Layout.fragments()) {
|
||||
OS << SplitPointMsg;
|
||||
SplitPointMsg = "------- HOT-COLD SPLIT POINT -------\n\n";
|
||||
for (const BinaryBasicBlock *BB : F) {
|
||||
for (const BinaryBasicBlock *BB : FF) {
|
||||
OS << BB->getName() << " (" << BB->size()
|
||||
<< " instructions, align : " << BB->getAlignment() << ")\n";
|
||||
|
||||
|
@ -2782,12 +2782,12 @@ bool BinaryFunction::finalizeCFIState() {
|
|||
|
||||
const char *Sep = "";
|
||||
(void)Sep;
|
||||
for (const FunctionFragment F : Layout) {
|
||||
for (const FunctionFragment FF : Layout.fragments()) {
|
||||
// Hot-cold border: at start of each region (with a different FDE) we need
|
||||
// to reset the CFI state.
|
||||
int32_t State = 0;
|
||||
|
||||
for (BinaryBasicBlock *BB : F) {
|
||||
for (BinaryBasicBlock *BB : FF) {
|
||||
const int32_t CFIStateAtExit = BB->getCFIStateAtExit();
|
||||
|
||||
// We need to recover the correct state if it doesn't match expected
|
||||
|
|
|
@ -20,7 +20,7 @@ BinaryBasicBlock *FunctionFragment::front() const { return *begin(); }
|
|||
|
||||
FunctionFragment FunctionLayout::addFragment() {
|
||||
Fragments.emplace_back(Blocks.size());
|
||||
return back();
|
||||
return getFragment(FragmentNum(Blocks.size() - 1));
|
||||
}
|
||||
|
||||
FunctionFragment FunctionLayout::getFragment(FragmentNum Num) const {
|
||||
|
@ -33,21 +33,14 @@ FunctionLayout::findFragment(const BinaryBasicBlock *BB) const {
|
|||
}
|
||||
|
||||
void FunctionLayout::addBasicBlock(BinaryBasicBlock *BB) {
|
||||
if (empty())
|
||||
addFragment();
|
||||
|
||||
BB->setLayoutIndex(Blocks.size());
|
||||
Blocks.emplace_back(BB);
|
||||
++Fragments.back();
|
||||
|
||||
assert(Fragments.back() == Blocks.size());
|
||||
}
|
||||
|
||||
void FunctionLayout::insertBasicBlocks(BinaryBasicBlock *InsertAfter,
|
||||
ArrayRef<BinaryBasicBlock *> NewBlocks) {
|
||||
if (empty())
|
||||
addFragment();
|
||||
|
||||
const block_iterator InsertBeforePos =
|
||||
InsertAfter ? std::next(findBasicBlockPos(InsertAfter)) : Blocks.begin();
|
||||
Blocks.insert(InsertBeforePos, NewBlocks.begin(), NewBlocks.end());
|
||||
|
@ -66,9 +59,9 @@ void FunctionLayout::eraseBasicBlocks(
|
|||
};
|
||||
FragmentListType NewFragments;
|
||||
NewFragments.emplace_back(0);
|
||||
for (const FunctionFragment F : *this) {
|
||||
unsigned ErasedBlocks = count_if(F, IsErased);
|
||||
unsigned NewFragment = NewFragments.back() + F.size() - ErasedBlocks;
|
||||
for (const FunctionFragment FF : fragments()) {
|
||||
unsigned ErasedBlocks = count_if(FF, IsErased);
|
||||
unsigned NewFragment = NewFragments.back() + FF.size() - ErasedBlocks;
|
||||
NewFragments.emplace_back(NewFragment);
|
||||
}
|
||||
llvm::erase_if(Blocks, IsErased);
|
||||
|
@ -77,8 +70,8 @@ void FunctionLayout::eraseBasicBlocks(
|
|||
|
||||
void FunctionLayout::updateLayoutIndices() const {
|
||||
unsigned BlockIndex = 0;
|
||||
for (const FunctionFragment F : *this) {
|
||||
for (BinaryBasicBlock *const BB : F)
|
||||
for (const FunctionFragment FF : fragments()) {
|
||||
for (BinaryBasicBlock *const BB : FF)
|
||||
BB->setLayoutIndex(BlockIndex++);
|
||||
}
|
||||
}
|
||||
|
@ -88,7 +81,7 @@ void FunctionLayout::update(const ArrayRef<BinaryBasicBlock *> NewLayout) {
|
|||
PreviousFragments = std::move(Fragments);
|
||||
|
||||
Blocks.clear();
|
||||
Fragments = {0};
|
||||
Fragments = {0, 0};
|
||||
|
||||
if (NewLayout.empty())
|
||||
return;
|
||||
|
@ -99,12 +92,12 @@ void FunctionLayout::update(const ArrayRef<BinaryBasicBlock *> NewLayout) {
|
|||
for (const auto &BB : enumerate(Blocks)) {
|
||||
unsigned FragmentNum = BB.value()->getFragmentNum().get();
|
||||
|
||||
assert(FragmentNum + 1 >= size() &&
|
||||
assert(FragmentNum >= fragment_size() - 1 &&
|
||||
"Blocks must be arranged such that fragments are monotonically "
|
||||
"increasing.");
|
||||
|
||||
// Add empty fragments if necessary
|
||||
for (unsigned I = size(); I <= FragmentNum; ++I) {
|
||||
for (unsigned I = fragment_size(); I <= FragmentNum; ++I) {
|
||||
addFragment();
|
||||
Fragments[I] = BB.index();
|
||||
}
|
||||
|
@ -123,9 +116,9 @@ void FunctionLayout::update(const ArrayRef<BinaryBasicBlock *> NewLayout) {
|
|||
|
||||
void FunctionLayout::clear() {
|
||||
Blocks = {};
|
||||
Fragments = {0};
|
||||
Fragments = {0, 0};
|
||||
PreviousBlocks = {};
|
||||
PreviousFragments = {0};
|
||||
PreviousFragments = {0, 0};
|
||||
}
|
||||
|
||||
BinaryBasicBlock *FunctionLayout::getBasicBlockAfter(const BinaryBasicBlock *BB,
|
||||
|
@ -147,7 +140,7 @@ BinaryBasicBlock *FunctionLayout::getBasicBlockAfter(const BinaryBasicBlock *BB,
|
|||
|
||||
bool FunctionLayout::isSplit() const {
|
||||
unsigned NonEmptyFragCount = llvm::count_if(
|
||||
*this, [](const FunctionFragment &F) { return !F.empty(); });
|
||||
fragments(), [](const FunctionFragment &FF) { return !FF.empty(); });
|
||||
return NonEmptyFragCount >= 2;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue