xref: /llvm-project/bolt/lib/Core/FunctionLayout.cpp (revision a0c7ca8ad41eeac0ae7c2334d77777e602965414)
1 #include "bolt/Core/FunctionLayout.h"
2 #include "bolt/Core/BinaryFunction.h"
3 #include "llvm/ADT/STLExtras.h"
4 #include "llvm/ADT/edit_distance.h"
5 #include <algorithm>
6 #include <cstddef>
7 #include <functional>
8 #include <iterator>
9 #include <memory>
10 
11 using namespace llvm;
12 using namespace bolt;
13 
14 FunctionFragment::FunctionFragment(FunctionLayout &Layout,
15                                    const FragmentNum Num)
16     : Layout(&Layout), Num(Num), StartIndex(Layout.block_size()) {}
17 
18 FunctionFragment::iterator FunctionFragment::begin() {
19   return iterator(Layout->block_begin() + StartIndex);
20 }
21 FunctionFragment::const_iterator FunctionFragment::begin() const {
22   return const_iterator(Layout->block_begin() + StartIndex);
23 }
24 FunctionFragment::iterator FunctionFragment::end() {
25   return iterator(Layout->block_begin() + StartIndex + Size);
26 }
27 FunctionFragment::const_iterator FunctionFragment::end() const {
28   return const_iterator(Layout->block_begin() + StartIndex + Size);
29 }
30 
31 const BinaryBasicBlock *FunctionFragment::front() const { return *begin(); }
32 
33 FunctionLayout::FunctionLayout() { addFragment(); }
34 
35 FunctionLayout::FunctionLayout(const FunctionLayout &Other)
36     : Blocks(Other.Blocks) {
37   for (FunctionFragment *const FF : Other.Fragments) {
38     auto *Copy = new FunctionFragment(*FF);
39     Copy->Layout = this;
40     Fragments.emplace_back(Copy);
41   }
42 }
43 
44 FunctionLayout::FunctionLayout(FunctionLayout &&Other)
45     : Fragments(std::move(Other.Fragments)), Blocks(std::move(Other.Blocks)) {
46   for (FunctionFragment *const F : Fragments)
47     F->Layout = this;
48 }
49 
50 FunctionLayout &FunctionLayout::operator=(const FunctionLayout &Other) {
51   Blocks = Other.Blocks;
52   for (FunctionFragment *const FF : Other.Fragments) {
53     auto *const Copy = new FunctionFragment(*FF);
54     Copy->Layout = this;
55     Fragments.emplace_back(Copy);
56   }
57   return *this;
58 }
59 
60 FunctionLayout &FunctionLayout::operator=(FunctionLayout &&Other) {
61   Fragments = std::move(Other.Fragments);
62   Blocks = std::move(Other.Blocks);
63   for (FunctionFragment *const FF : Fragments)
64     FF->Layout = this;
65   return *this;
66 }
67 
68 FunctionLayout::~FunctionLayout() {
69   for (FunctionFragment *const F : Fragments) {
70     delete F;
71   }
72 }
73 
74 FunctionFragment &FunctionLayout::addFragment() {
75   FunctionFragment *const FF =
76       new FunctionFragment(*this, FragmentNum(Fragments.size()));
77   Fragments.emplace_back(FF);
78   return *FF;
79 }
80 
81 FunctionFragment &FunctionLayout::getFragment(FragmentNum Num) {
82   return *Fragments[Num.get()];
83 }
84 
85 const FunctionFragment &FunctionLayout::getFragment(FragmentNum Num) const {
86   return *Fragments[Num.get()];
87 }
88 
89 const FunctionFragment &
90 FunctionLayout::findFragment(const BinaryBasicBlock *const BB) const {
91   return getFragment(BB->getFragmentNum());
92 }
93 
94 void FunctionLayout::addBasicBlock(BinaryBasicBlock *const BB) {
95   BB->setLayoutIndex(Blocks.size());
96   Blocks.emplace_back(BB);
97   Fragments.back()->Size++;
98 }
99 
100 void FunctionLayout::insertBasicBlocks(
101     const BinaryBasicBlock *const InsertAfter,
102     const ArrayRef<BinaryBasicBlock *> NewBlocks) {
103   block_iterator InsertBeforePos = Blocks.begin();
104   FragmentNum InsertFragmentNum = FragmentNum::main();
105   unsigned LayoutIndex = 0;
106 
107   if (InsertAfter) {
108     InsertBeforePos = std::next(findBasicBlockPos(InsertAfter));
109     InsertFragmentNum = InsertAfter->getFragmentNum();
110     LayoutIndex = InsertAfter->getLayoutIndex();
111   }
112 
113   llvm::copy(NewBlocks, std::inserter(Blocks, InsertBeforePos));
114 
115   for (BinaryBasicBlock *const BB : NewBlocks) {
116     BB->setFragmentNum(InsertFragmentNum);
117     BB->setLayoutIndex(LayoutIndex++);
118   }
119 
120   const fragment_iterator InsertFragment =
121       fragment_begin() + InsertFragmentNum.get();
122   InsertFragment->Size += NewBlocks.size();
123 
124   const fragment_iterator TailBegin = std::next(InsertFragment);
125   auto const UpdateFragment = [&](FunctionFragment &FF) {
126     FF.StartIndex += NewBlocks.size();
127     for (BinaryBasicBlock *const BB : FF)
128       BB->setLayoutIndex(LayoutIndex++);
129   };
130   std::for_each(TailBegin, fragment_end(), UpdateFragment);
131 }
132 
133 void FunctionLayout::eraseBasicBlocks(
134     const DenseSet<const BinaryBasicBlock *> ToErase) {
135   const auto IsErased = [&](const BinaryBasicBlock *const BB) {
136     return ToErase.contains(BB);
137   };
138 
139   unsigned TotalErased = 0;
140   for (FunctionFragment &FF : fragments()) {
141     unsigned Erased = count_if(FF, IsErased);
142     FF.Size -= Erased;
143     FF.StartIndex -= TotalErased;
144     TotalErased += Erased;
145   }
146   llvm::erase_if(Blocks, IsErased);
147 
148   // Remove empty fragments at the end
149   const auto IsEmpty = [](const FunctionFragment *const FF) {
150     return FF->empty();
151   };
152   const FragmentListType::iterator EmptyTailBegin =
153       llvm::find_if_not(reverse(Fragments), IsEmpty).base();
154   for (FunctionFragment *const FF :
155        llvm::make_range(EmptyTailBegin, Fragments.end()))
156     delete FF;
157   Fragments.erase(EmptyTailBegin, Fragments.end());
158 
159   updateLayoutIndices();
160 }
161 
162 void FunctionLayout::updateLayoutIndices() {
163   unsigned BlockIndex = 0;
164   for (FunctionFragment &FF : fragments()) {
165     for (BinaryBasicBlock *const BB : FF) {
166       BB->setLayoutIndex(BlockIndex++);
167       BB->setFragmentNum(FF.getFragmentNum());
168     }
169   }
170 }
171 
172 bool FunctionLayout::update(const ArrayRef<BinaryBasicBlock *> NewLayout) {
173   const bool EqualBlockOrder = llvm::equal(Blocks, NewLayout);
174   if (EqualBlockOrder) {
175     const bool EqualPartitioning =
176         llvm::all_of(fragments(), [](const FunctionFragment &FF) {
177           return llvm::all_of(FF, [&](const BinaryBasicBlock *const BB) {
178             return FF.Num == BB->getFragmentNum();
179           });
180         });
181     if (EqualPartitioning)
182       return false;
183   }
184 
185   clear();
186 
187   // Generate fragments
188   for (BinaryBasicBlock *const BB : NewLayout) {
189     FragmentNum Num = BB->getFragmentNum();
190 
191     assert(Num >= Fragments.back()->getFragmentNum() &&
192            "Blocks must be arranged such that fragments are monotonically "
193            "increasing.");
194 
195     // Add empty fragments if necessary
196     while (Fragments.back()->getFragmentNum() < Num)
197       addFragment();
198 
199     // Set the next fragment to point one past the current BB
200     addBasicBlock(BB);
201   }
202 
203   return true;
204 }
205 
206 void FunctionLayout::clear() {
207   Blocks = BasicBlockListType();
208   // If the binary does not have relocations and is not split, the function will
209   // be written to the output stream at its original file offset (see
210   // `RewriteInstance::rewriteFile`). Hence, when the layout is cleared, retain
211   // the main fragment, so that this information is not lost.
212   for (FunctionFragment *const FF : llvm::drop_begin(Fragments))
213     delete FF;
214   Fragments = FragmentListType{Fragments.front()};
215   getMainFragment().Size = 0;
216 }
217 
218 const BinaryBasicBlock *
219 FunctionLayout::getBasicBlockAfter(const BinaryBasicBlock *BB,
220                                    bool IgnoreSplits) const {
221   const block_const_iterator BBPos = find(blocks(), BB);
222   if (BBPos == block_end())
223     return nullptr;
224 
225   const block_const_iterator BlockAfter = std::next(BBPos);
226   if (BlockAfter == block_end())
227     return nullptr;
228 
229   if (!IgnoreSplits)
230     if (BlockAfter == getFragment(BB->getFragmentNum()).end())
231       return nullptr;
232 
233   return *BlockAfter;
234 }
235 
236 bool FunctionLayout::isSplit() const {
237   const unsigned NonEmptyFragCount = llvm::count_if(
238       fragments(), [](const FunctionFragment &FF) { return !FF.empty(); });
239   return NonEmptyFragCount >= 2;
240 }
241 
242 uint64_t FunctionLayout::getEditDistance(
243     const ArrayRef<const BinaryBasicBlock *> OldBlockOrder) const {
244   return ComputeEditDistance<const BinaryBasicBlock *>(OldBlockOrder, Blocks);
245 }
246 
247 FunctionLayout::block_const_iterator
248 FunctionLayout::findBasicBlockPos(const BinaryBasicBlock *BB) const {
249   return block_const_iterator(find(Blocks, BB));
250 }
251 
252 FunctionLayout::block_iterator
253 FunctionLayout::findBasicBlockPos(const BinaryBasicBlock *BB) {
254   return find(Blocks, BB);
255 }
256