1*8477bc67SFabian Parzefall #include "bolt/Core/FunctionLayout.h"
2*8477bc67SFabian Parzefall #include "bolt/Core/BinaryFunction.h"
3*8477bc67SFabian Parzefall #include "llvm/ADT/STLExtras.h"
4*8477bc67SFabian Parzefall #include "llvm/ADT/edit_distance.h"
5*8477bc67SFabian Parzefall #include <algorithm>
6*8477bc67SFabian Parzefall #include <functional>
7*8477bc67SFabian Parzefall
8*8477bc67SFabian Parzefall using namespace llvm;
9*8477bc67SFabian Parzefall using namespace bolt;
10*8477bc67SFabian Parzefall
size() const11*8477bc67SFabian Parzefall unsigned FunctionFragment::size() const { return end() - begin(); }
empty() const12*8477bc67SFabian Parzefall bool FunctionFragment::empty() const { return end() == begin(); }
begin() const13*8477bc67SFabian Parzefall FunctionFragment::const_iterator FunctionFragment::begin() const {
14*8477bc67SFabian Parzefall return Layout.block_begin() + Layout.Fragments[Num.get()];
15*8477bc67SFabian Parzefall }
end() const16*8477bc67SFabian Parzefall FunctionFragment::const_iterator FunctionFragment::end() const {
17*8477bc67SFabian Parzefall return Layout.block_begin() + Layout.Fragments[Num.get() + 1];
18*8477bc67SFabian Parzefall }
front() const19*8477bc67SFabian Parzefall BinaryBasicBlock *FunctionFragment::front() const { return *begin(); }
20*8477bc67SFabian Parzefall
addFragment()21*8477bc67SFabian Parzefall FunctionFragment FunctionLayout::addFragment() {
22*8477bc67SFabian Parzefall Fragments.emplace_back(Blocks.size());
23*8477bc67SFabian Parzefall return back();
24*8477bc67SFabian Parzefall }
25*8477bc67SFabian Parzefall
getFragment(FragmentNum Num) const26*8477bc67SFabian Parzefall FunctionFragment FunctionLayout::getFragment(FragmentNum Num) const {
27*8477bc67SFabian Parzefall return FunctionFragment(Num, *this);
28*8477bc67SFabian Parzefall }
29*8477bc67SFabian Parzefall
30*8477bc67SFabian Parzefall FunctionFragment
findFragment(const BinaryBasicBlock * BB) const31*8477bc67SFabian Parzefall FunctionLayout::findFragment(const BinaryBasicBlock *BB) const {
32*8477bc67SFabian Parzefall return getFragment(BB->getFragmentNum());
33*8477bc67SFabian Parzefall }
34*8477bc67SFabian Parzefall
addBasicBlock(BinaryBasicBlock * BB)35*8477bc67SFabian Parzefall void FunctionLayout::addBasicBlock(BinaryBasicBlock *BB) {
36*8477bc67SFabian Parzefall if (empty())
37*8477bc67SFabian Parzefall addFragment();
38*8477bc67SFabian Parzefall
39*8477bc67SFabian Parzefall BB->setLayoutIndex(Blocks.size());
40*8477bc67SFabian Parzefall Blocks.emplace_back(BB);
41*8477bc67SFabian Parzefall ++Fragments.back();
42*8477bc67SFabian Parzefall
43*8477bc67SFabian Parzefall assert(Fragments.back() == Blocks.size());
44*8477bc67SFabian Parzefall }
45*8477bc67SFabian Parzefall
insertBasicBlocks(BinaryBasicBlock * InsertAfter,ArrayRef<BinaryBasicBlock * > NewBlocks)46*8477bc67SFabian Parzefall void FunctionLayout::insertBasicBlocks(BinaryBasicBlock *InsertAfter,
47*8477bc67SFabian Parzefall ArrayRef<BinaryBasicBlock *> NewBlocks) {
48*8477bc67SFabian Parzefall if (empty())
49*8477bc67SFabian Parzefall addFragment();
50*8477bc67SFabian Parzefall
51*8477bc67SFabian Parzefall const block_iterator InsertBeforePos =
52*8477bc67SFabian Parzefall InsertAfter ? std::next(findBasicBlockPos(InsertAfter)) : Blocks.begin();
53*8477bc67SFabian Parzefall Blocks.insert(InsertBeforePos, NewBlocks.begin(), NewBlocks.end());
54*8477bc67SFabian Parzefall
55*8477bc67SFabian Parzefall unsigned FragmentUpdateStart =
56*8477bc67SFabian Parzefall InsertAfter ? InsertAfter->getFragmentNum().get() + 1 : 1;
57*8477bc67SFabian Parzefall std::for_each(
58*8477bc67SFabian Parzefall Fragments.begin() + FragmentUpdateStart, Fragments.end(),
59*8477bc67SFabian Parzefall [&](unsigned &FragmentOffset) { FragmentOffset += NewBlocks.size(); });
60*8477bc67SFabian Parzefall }
61*8477bc67SFabian Parzefall
eraseBasicBlocks(const DenseSet<const BinaryBasicBlock * > ToErase)62*8477bc67SFabian Parzefall void FunctionLayout::eraseBasicBlocks(
63*8477bc67SFabian Parzefall const DenseSet<const BinaryBasicBlock *> ToErase) {
64*8477bc67SFabian Parzefall auto IsErased = [&](const BinaryBasicBlock *const BB) {
65*8477bc67SFabian Parzefall return ToErase.contains(BB);
66*8477bc67SFabian Parzefall };
67*8477bc67SFabian Parzefall FragmentListType NewFragments;
68*8477bc67SFabian Parzefall NewFragments.emplace_back(0);
69*8477bc67SFabian Parzefall for (const FunctionFragment F : *this) {
70*8477bc67SFabian Parzefall unsigned ErasedBlocks = count_if(F, IsErased);
71*8477bc67SFabian Parzefall unsigned NewFragment = NewFragments.back() + F.size() - ErasedBlocks;
72*8477bc67SFabian Parzefall NewFragments.emplace_back(NewFragment);
73*8477bc67SFabian Parzefall }
74*8477bc67SFabian Parzefall Blocks.erase(std::remove_if(Blocks.begin(), Blocks.end(), IsErased),
75*8477bc67SFabian Parzefall Blocks.end());
76*8477bc67SFabian Parzefall Fragments = std::move(NewFragments);
77*8477bc67SFabian Parzefall }
78*8477bc67SFabian Parzefall
updateLayoutIndices() const79*8477bc67SFabian Parzefall void FunctionLayout::updateLayoutIndices() const {
80*8477bc67SFabian Parzefall unsigned BlockIndex = 0;
81*8477bc67SFabian Parzefall for (const FunctionFragment F : *this) {
82*8477bc67SFabian Parzefall for (BinaryBasicBlock *const BB : F)
83*8477bc67SFabian Parzefall BB->setLayoutIndex(BlockIndex++);
84*8477bc67SFabian Parzefall }
85*8477bc67SFabian Parzefall }
86*8477bc67SFabian Parzefall
update(const ArrayRef<BinaryBasicBlock * > NewLayout)87*8477bc67SFabian Parzefall void FunctionLayout::update(const ArrayRef<BinaryBasicBlock *> NewLayout) {
88*8477bc67SFabian Parzefall PreviousBlocks = std::move(Blocks);
89*8477bc67SFabian Parzefall PreviousFragments = std::move(Fragments);
90*8477bc67SFabian Parzefall
91*8477bc67SFabian Parzefall Blocks.clear();
92*8477bc67SFabian Parzefall Fragments = {0};
93*8477bc67SFabian Parzefall
94*8477bc67SFabian Parzefall if (NewLayout.empty())
95*8477bc67SFabian Parzefall return;
96*8477bc67SFabian Parzefall
97*8477bc67SFabian Parzefall copy(NewLayout, std::back_inserter(Blocks));
98*8477bc67SFabian Parzefall
99*8477bc67SFabian Parzefall // Generate fragments
100*8477bc67SFabian Parzefall for (const auto &BB : enumerate(Blocks)) {
101*8477bc67SFabian Parzefall unsigned FragmentNum = BB.value()->getFragmentNum().get();
102*8477bc67SFabian Parzefall
103*8477bc67SFabian Parzefall assert(FragmentNum + 1 >= size() &&
104*8477bc67SFabian Parzefall "Blocks must be arranged such that fragments are monotonically "
105*8477bc67SFabian Parzefall "increasing.");
106*8477bc67SFabian Parzefall
107*8477bc67SFabian Parzefall // Add empty fragments if necessary
108*8477bc67SFabian Parzefall for (unsigned I = size(); I <= FragmentNum; ++I) {
109*8477bc67SFabian Parzefall addFragment();
110*8477bc67SFabian Parzefall Fragments[I] = BB.index();
111*8477bc67SFabian Parzefall }
112*8477bc67SFabian Parzefall
113*8477bc67SFabian Parzefall // Set the next fragment to point one past the current BB
114*8477bc67SFabian Parzefall Fragments[FragmentNum + 1] = BB.index() + 1;
115*8477bc67SFabian Parzefall }
116*8477bc67SFabian Parzefall
117*8477bc67SFabian Parzefall if (PreviousBlocks == Blocks && PreviousFragments == Fragments) {
118*8477bc67SFabian Parzefall // If new layout is the same as previous layout, clear previous layout so
119*8477bc67SFabian Parzefall // hasLayoutChanged() returns false.
120*8477bc67SFabian Parzefall PreviousBlocks = {};
121*8477bc67SFabian Parzefall PreviousFragments = {};
122*8477bc67SFabian Parzefall }
123*8477bc67SFabian Parzefall }
124*8477bc67SFabian Parzefall
clear()125*8477bc67SFabian Parzefall void FunctionLayout::clear() {
126*8477bc67SFabian Parzefall Blocks = {};
127*8477bc67SFabian Parzefall Fragments = {0};
128*8477bc67SFabian Parzefall PreviousBlocks = {};
129*8477bc67SFabian Parzefall PreviousFragments = {0};
130*8477bc67SFabian Parzefall }
131*8477bc67SFabian Parzefall
getBasicBlockAfter(const BinaryBasicBlock * BB,bool IgnoreSplits) const132*8477bc67SFabian Parzefall BinaryBasicBlock *FunctionLayout::getBasicBlockAfter(const BinaryBasicBlock *BB,
133*8477bc67SFabian Parzefall bool IgnoreSplits) const {
134*8477bc67SFabian Parzefall const block_const_iterator BBPos = find(Blocks, BB);
135*8477bc67SFabian Parzefall if (BBPos == Blocks.end())
136*8477bc67SFabian Parzefall return nullptr;
137*8477bc67SFabian Parzefall
138*8477bc67SFabian Parzefall const block_const_iterator BlockAfter = std::next(BBPos);
139*8477bc67SFabian Parzefall if (BlockAfter == Blocks.end())
140*8477bc67SFabian Parzefall return nullptr;
141*8477bc67SFabian Parzefall
142*8477bc67SFabian Parzefall if (!IgnoreSplits)
143*8477bc67SFabian Parzefall if (BlockAfter == getFragment(BB->getFragmentNum()).end())
144*8477bc67SFabian Parzefall return nullptr;
145*8477bc67SFabian Parzefall
146*8477bc67SFabian Parzefall return *BlockAfter;
147*8477bc67SFabian Parzefall }
148*8477bc67SFabian Parzefall
isSplit() const149*8477bc67SFabian Parzefall bool FunctionLayout::isSplit() const {
150*8477bc67SFabian Parzefall unsigned NonEmptyFragCount = llvm::count_if(
151*8477bc67SFabian Parzefall *this, [](const FunctionFragment &F) { return !F.empty(); });
152*8477bc67SFabian Parzefall return NonEmptyFragCount >= 2;
153*8477bc67SFabian Parzefall }
154*8477bc67SFabian Parzefall
getEditDistance() const155*8477bc67SFabian Parzefall uint64_t FunctionLayout::getEditDistance() const {
156*8477bc67SFabian Parzefall return ComputeEditDistance<BinaryBasicBlock *>(PreviousBlocks, Blocks);
157*8477bc67SFabian Parzefall }
158*8477bc67SFabian Parzefall
159*8477bc67SFabian Parzefall FunctionLayout::block_const_iterator
findBasicBlockPos(const BinaryBasicBlock * BB) const160*8477bc67SFabian Parzefall FunctionLayout::findBasicBlockPos(const BinaryBasicBlock *BB) const {
161*8477bc67SFabian Parzefall return find(Blocks, BB);
162*8477bc67SFabian Parzefall }
163*8477bc67SFabian Parzefall
164*8477bc67SFabian Parzefall FunctionLayout::block_iterator
findBasicBlockPos(const BinaryBasicBlock * BB)165*8477bc67SFabian Parzefall FunctionLayout::findBasicBlockPos(const BinaryBasicBlock *BB) {
166*8477bc67SFabian Parzefall return find(Blocks, BB);
167*8477bc67SFabian Parzefall }
168