[llvm-shlib] Fix the version naming style of libLLVM for Windows (#85710)
[llvm-project.git] / bolt / lib / Core / FunctionLayout.cpp
blob27e40de94be660f0ffbe9b5f6ddacb5b0393b0ac
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>
11 using namespace llvm;
12 using namespace bolt;
14 FunctionFragment::FunctionFragment(FunctionLayout &Layout,
15 const FragmentNum Num)
16 : Layout(&Layout), Num(Num), StartIndex(Layout.block_size()) {}
18 FunctionFragment::iterator FunctionFragment::begin() {
19 return iterator(Layout->block_begin() + StartIndex);
21 FunctionFragment::const_iterator FunctionFragment::begin() const {
22 return const_iterator(Layout->block_begin() + StartIndex);
24 FunctionFragment::iterator FunctionFragment::end() {
25 return iterator(Layout->block_begin() + StartIndex + Size);
27 FunctionFragment::const_iterator FunctionFragment::end() const {
28 return const_iterator(Layout->block_begin() + StartIndex + Size);
31 const BinaryBasicBlock *FunctionFragment::front() const { return *begin(); }
33 FunctionLayout::FunctionLayout() { addFragment(); }
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);
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;
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);
57 return *this;
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;
68 FunctionLayout::~FunctionLayout() {
69 for (FunctionFragment *const F : Fragments) {
70 delete F;
74 FunctionFragment &FunctionLayout::addFragment() {
75 FunctionFragment *const FF =
76 new FunctionFragment(*this, FragmentNum(Fragments.size()));
77 Fragments.emplace_back(FF);
78 return *FF;
81 FunctionFragment &FunctionLayout::getFragment(FragmentNum Num) {
82 return *Fragments[Num.get()];
85 const FunctionFragment &FunctionLayout::getFragment(FragmentNum Num) const {
86 return *Fragments[Num.get()];
89 const FunctionFragment &
90 FunctionLayout::findFragment(const BinaryBasicBlock *const BB) const {
91 return getFragment(BB->getFragmentNum());
94 void FunctionLayout::addBasicBlock(BinaryBasicBlock *const BB) {
95 BB->setLayoutIndex(Blocks.size());
96 Blocks.emplace_back(BB);
97 Fragments.back()->Size++;
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;
107 if (InsertAfter) {
108 InsertBeforePos = std::next(findBasicBlockPos(InsertAfter));
109 InsertFragmentNum = InsertAfter->getFragmentNum();
110 LayoutIndex = InsertAfter->getLayoutIndex();
113 llvm::copy(NewBlocks, std::inserter(Blocks, InsertBeforePos));
115 for (BinaryBasicBlock *const BB : NewBlocks) {
116 BB->setFragmentNum(InsertFragmentNum);
117 BB->setLayoutIndex(LayoutIndex++);
120 const fragment_iterator InsertFragment =
121 fragment_begin() + InsertFragmentNum.get();
122 InsertFragment->Size += NewBlocks.size();
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++);
130 std::for_each(TailBegin, fragment_end(), UpdateFragment);
133 void FunctionLayout::eraseBasicBlocks(
134 const DenseSet<const BinaryBasicBlock *> ToErase) {
135 const auto IsErased = [&](const BinaryBasicBlock *const BB) {
136 return ToErase.contains(BB);
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;
146 llvm::erase_if(Blocks, IsErased);
148 // Remove empty fragments at the end
149 const auto IsEmpty = [](const FunctionFragment *const FF) {
150 return FF->empty();
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());
159 updateLayoutIndices();
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());
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();
181 if (EqualPartitioning)
182 return false;
185 clear();
187 // Generate fragments
188 for (BinaryBasicBlock *const BB : NewLayout) {
189 FragmentNum Num = BB->getFragmentNum();
191 // Add empty fragments if necessary
192 while (Fragments.back()->getFragmentNum() < Num)
193 addFragment();
195 // Set the next fragment to point one past the current BB
196 addBasicBlock(BB);
199 return true;
202 void FunctionLayout::clear() {
203 Blocks = BasicBlockListType();
204 // If the binary does not have relocations and is not split, the function will
205 // be written to the output stream at its original file offset (see
206 // `RewriteInstance::rewriteFile`). Hence, when the layout is cleared, retain
207 // the main fragment, so that this information is not lost.
208 for (FunctionFragment *const FF : llvm::drop_begin(Fragments))
209 delete FF;
210 Fragments = FragmentListType{Fragments.front()};
211 getMainFragment().Size = 0;
214 const BinaryBasicBlock *
215 FunctionLayout::getBasicBlockAfter(const BinaryBasicBlock *BB,
216 bool IgnoreSplits) const {
217 const block_const_iterator BBPos = find(blocks(), BB);
218 if (BBPos == block_end())
219 return nullptr;
221 const block_const_iterator BlockAfter = std::next(BBPos);
222 if (BlockAfter == block_end())
223 return nullptr;
225 if (!IgnoreSplits)
226 if (BlockAfter == getFragment(BB->getFragmentNum()).end())
227 return nullptr;
229 return *BlockAfter;
232 bool FunctionLayout::isSplit() const {
233 const unsigned NonEmptyFragCount = llvm::count_if(
234 fragments(), [](const FunctionFragment &FF) { return !FF.empty(); });
235 return NonEmptyFragCount >= 2;
238 uint64_t FunctionLayout::getEditDistance(
239 const ArrayRef<const BinaryBasicBlock *> OldBlockOrder) const {
240 return ComputeEditDistance<const BinaryBasicBlock *>(OldBlockOrder, Blocks);
243 FunctionLayout::block_const_iterator
244 FunctionLayout::findBasicBlockPos(const BinaryBasicBlock *BB) const {
245 return block_const_iterator(find(Blocks, BB));
248 FunctionLayout::block_iterator
249 FunctionLayout::findBasicBlockPos(const BinaryBasicBlock *BB) {
250 return find(Blocks, BB);