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