1 //===- bolt/Core/FunctionLayout.cpp - Fragmented Function Layout -*- C++ -*-==//
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
7 //===----------------------------------------------------------------------===//
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"
19 FunctionFragment::FunctionFragment(FunctionLayout
&Layout
,
20 const FragmentNum Num
)
21 : Layout(&Layout
), Num(Num
), StartIndex(Layout
.block_size()) {}
23 FunctionFragment::iterator
FunctionFragment::begin() {
24 return iterator(Layout
->block_begin() + StartIndex
);
26 FunctionFragment::const_iterator
FunctionFragment::begin() const {
27 return const_iterator(Layout
->block_begin() + StartIndex
);
29 FunctionFragment::iterator
FunctionFragment::end() {
30 return iterator(Layout
->block_begin() + StartIndex
+ Size
);
32 FunctionFragment::const_iterator
FunctionFragment::end() const {
33 return const_iterator(Layout
->block_begin() + StartIndex
+ Size
);
36 BinaryBasicBlock
*FunctionFragment::front() const { return *begin(); }
38 BinaryBasicBlock
*FunctionFragment::back() const { return *std::prev(end()); }
40 FunctionLayout::FunctionLayout() { addFragment(); }
42 FunctionLayout::FunctionLayout(const FunctionLayout
&Other
)
43 : Blocks(Other
.Blocks
) {
44 for (FunctionFragment
*const FF
: Other
.Fragments
) {
45 auto *Copy
= new FunctionFragment(*FF
);
47 Fragments
.emplace_back(Copy
);
51 FunctionLayout::FunctionLayout(FunctionLayout
&&Other
)
52 : Fragments(std::move(Other
.Fragments
)), Blocks(std::move(Other
.Blocks
)) {
53 for (FunctionFragment
*const F
: Fragments
)
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
);
62 Fragments
.emplace_back(Copy
);
67 FunctionLayout
&FunctionLayout::operator=(FunctionLayout
&&Other
) {
68 Fragments
= std::move(Other
.Fragments
);
69 Blocks
= std::move(Other
.Blocks
);
70 for (FunctionFragment
*const FF
: Fragments
)
75 FunctionLayout::~FunctionLayout() {
76 for (FunctionFragment
*const F
: Fragments
) {
81 FunctionFragment
&FunctionLayout::addFragment() {
82 FunctionFragment
*const FF
=
83 new FunctionFragment(*this, FragmentNum(Fragments
.size()));
84 Fragments
.emplace_back(FF
);
88 FunctionFragment
&FunctionLayout::getFragment(FragmentNum Num
) {
89 return *Fragments
[Num
.get()];
92 const FunctionFragment
&FunctionLayout::getFragment(FragmentNum Num
) const {
93 return *Fragments
[Num
.get()];
96 const FunctionFragment
&
97 FunctionLayout::findFragment(const BinaryBasicBlock
*const BB
) const {
98 return getFragment(BB
->getFragmentNum());
101 void FunctionLayout::addBasicBlock(BinaryBasicBlock
*const BB
) {
102 BB
->setLayoutIndex(Blocks
.size());
103 Blocks
.emplace_back(BB
);
104 Fragments
.back()->Size
++;
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;
115 InsertBeforePos
= std::next(findBasicBlockPos(InsertAfter
));
116 InsertFragmentNum
= InsertAfter
->getFragmentNum();
117 LayoutIndex
= InsertAfter
->getLayoutIndex();
120 llvm::copy(NewBlocks
, std::inserter(Blocks
, InsertBeforePos
));
122 for (BinaryBasicBlock
*const BB
: NewBlocks
) {
123 BB
->setFragmentNum(InsertFragmentNum
);
124 BB
->setLayoutIndex(LayoutIndex
++);
127 const fragment_iterator InsertFragment
=
128 fragment_begin() + InsertFragmentNum
.get();
129 InsertFragment
->Size
+= NewBlocks
.size();
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
++);
137 std::for_each(TailBegin
, fragment_end(), UpdateFragment
);
140 void FunctionLayout::eraseBasicBlocks(
141 const DenseSet
<const BinaryBasicBlock
*> ToErase
) {
142 const auto IsErased
= [&](const BinaryBasicBlock
*const BB
) {
143 return ToErase
.contains(BB
);
146 unsigned TotalErased
= 0;
147 for (FunctionFragment
&FF
: fragments()) {
148 unsigned Erased
= count_if(FF
, IsErased
);
150 FF
.StartIndex
-= TotalErased
;
151 TotalErased
+= Erased
;
153 llvm::erase_if(Blocks
, IsErased
);
155 // Remove empty fragments at the end
156 const auto IsEmpty
= [](const FunctionFragment
*const FF
) {
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()))
164 Fragments
.erase(EmptyTailBegin
, Fragments
.end());
166 updateLayoutIndices();
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());
178 void FunctionLayout::updateLayoutIndices(
179 ArrayRef
<BinaryBasicBlock
*> Order
) const {
180 for (auto [Index
, BB
] : llvm::enumerate(Order
))
181 BB
->setLayoutIndex(Index
);
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();
193 if (EqualPartitioning
)
199 // Generate fragments
200 for (BinaryBasicBlock
*const BB
: NewLayout
) {
201 FragmentNum Num
= BB
->getFragmentNum();
203 // Add empty fragments if necessary
204 while (Fragments
.back()->getFragmentNum() < Num
)
207 // Set the next fragment to point one past the current BB
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
))
222 Fragments
= FragmentListType
{Fragments
.front()};
223 getMainFragment().Size
= 0;
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())
233 const block_const_iterator BlockAfter
= std::next(BBPos
);
234 if (BlockAfter
== block_end())
238 if (BlockAfter
== getFragment(BB
->getFragmentNum()).end())
244 bool FunctionLayout::isSplit() const {
245 const unsigned NonEmptyFragCount
= llvm::count_if(
246 fragments(), [](const FunctionFragment
&FF
) { return !FF
.empty(); });
247 return NonEmptyFragCount
>= 2;
250 uint64_t FunctionLayout::getEditDistance(
251 const ArrayRef
<const BinaryBasicBlock
*> OldBlockOrder
) const {
252 return ComputeEditDistance
<const BinaryBasicBlock
*>(OldBlockOrder
, Blocks
);
255 FunctionLayout::block_const_iterator
256 FunctionLayout::findBasicBlockPos(const BinaryBasicBlock
*BB
) const {
257 return block_const_iterator(find(Blocks
, BB
));
260 FunctionLayout::block_iterator
261 FunctionLayout::findBasicBlockPos(const BinaryBasicBlock
*BB
) {
262 return find(Blocks
, BB
);