Skip to content

Commit 101344a

Browse files
author
Fabian Parzefall
committed
[BOLT] Allocate FunctionFragment on heap
This changes `FunctionFragment` from being used as a temporary proxy object to access basic block ranges to a heap-allocated object that can store fragment-specific information. Reviewed By: rafauler Differential Revision: https://reviews.llvm.org/D132050
1 parent 587d265 commit 101344a

File tree

9 files changed

+271
-166
lines changed

9 files changed

+271
-166
lines changed

bolt/include/bolt/Core/BinaryEmitter.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ void emitBinaryContext(MCStreamer &Streamer, BinaryContext &BC,
3535
/// Emit \p BF function code. The caller is responsible for emitting function
3636
/// symbol(s) and setting the section to emit the code to.
3737
void emitFunctionBody(MCStreamer &Streamer, BinaryFunction &BF,
38-
const FunctionFragment &FF, bool EmitCodeOnly);
38+
FunctionFragment &FF, bool EmitCodeOnly);
3939

4040
} // namespace bolt
4141
} // namespace llvm

bolt/include/bolt/Core/FunctionLayout.h

Lines changed: 111 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
#include "llvm/ADT/SmallVector.h"
2525
#include "llvm/ADT/iterator.h"
2626
#include "llvm/ADT/iterator_range.h"
27+
#include <iterator>
28+
#include <utility>
2729

2830
namespace llvm {
2931
namespace bolt {
@@ -69,28 +71,41 @@ class FunctionFragment {
6971
using FragmentListType = SmallVector<unsigned, 0>;
7072

7173
public:
72-
using const_iterator = BasicBlockListType::const_iterator;
74+
using iterator = raw_pointer_iterator<BasicBlockListType::const_iterator,
75+
BinaryBasicBlock>;
76+
using const_iterator =
77+
raw_pointer_iterator<BasicBlockListType::const_iterator,
78+
const BinaryBasicBlock>;
7379

7480
private:
81+
FunctionLayout *Layout;
7582
FragmentNum Num;
76-
const FunctionLayout &Layout;
83+
unsigned StartIndex;
84+
unsigned Size = 0;
7785

78-
FunctionFragment(FragmentNum Num, const FunctionLayout &Layout)
79-
: Num(Num), Layout(Layout) {}
86+
FunctionFragment(FunctionLayout &Layout, FragmentNum Num);
87+
FunctionFragment(const FunctionFragment &) = default;
88+
FunctionFragment(FunctionFragment &&) = default;
89+
FunctionFragment &operator=(const FunctionFragment &) = default;
90+
FunctionFragment &operator=(FunctionFragment &&) = default;
91+
~FunctionFragment() = default;
8092

8193
public:
8294
FragmentNum getFragmentNum() const { return Num; }
83-
bool isMainFragment() const { return Num.get() == 0; }
84-
bool isSplitFragment() const { return Num.get() > 0; }
95+
bool isMainFragment() const {
96+
return getFragmentNum() == FragmentNum::main();
97+
}
98+
bool isSplitFragment() const { return !isMainFragment(); }
8599

86-
unsigned size() const;
87-
bool empty() const;
100+
unsigned size() const { return Size; };
101+
bool empty() const { return size() == 0; };
102+
iterator begin();
88103
const_iterator begin() const;
104+
iterator end();
89105
const_iterator end() const;
90-
BinaryBasicBlock *front() const;
106+
const BinaryBasicBlock *front() const;
91107

92108
friend class FunctionLayout;
93-
friend class FragmentIterator;
94109
};
95110

96111
/// The function layout represents the fragments we split a function into and
@@ -103,102 +118,84 @@ class FunctionFragment {
103118
/// iterating either over fragments or over BinaryFunction::begin()..end().
104119
class FunctionLayout {
105120
private:
121+
using FragmentListType = SmallVector<FunctionFragment *, 0>;
106122
using BasicBlockListType = SmallVector<BinaryBasicBlock *, 0>;
107123
using block_iterator = BasicBlockListType::iterator;
108-
using FragmentListType = SmallVector<unsigned, 0>;
109124

110125
public:
111-
class FragmentIterator;
112-
113-
class FragmentIterator
114-
: public iterator_facade_base<
115-
FragmentIterator, std::bidirectional_iterator_tag, FunctionFragment,
116-
std::ptrdiff_t, FunctionFragment *, FunctionFragment> {
117-
FragmentNum Num;
118-
const FunctionLayout *Layout;
119-
120-
FragmentIterator(FragmentNum Num, const FunctionLayout *Layout)
121-
: Num(Num), Layout(Layout) {
122-
assert(Num.get() <= Layout->fragment_size() &&
123-
"Initializing iterator out of bounds");
124-
}
125-
126-
public:
127-
bool operator==(const FragmentIterator &Other) const {
128-
return Num == Other.Num;
129-
}
130-
131-
FunctionFragment operator*() const {
132-
assert(Num.get() < Layout->fragment_size() &&
133-
"Dereferencing end() iterator (or past it)");
134-
return FunctionFragment(Num, *Layout);
135-
}
136-
137-
FragmentIterator &operator++() {
138-
assert(Num.get() < Layout->fragment_size() &&
139-
"Incrementing iterator past end()");
140-
Num = FragmentNum(Num.get() + 1);
141-
return *this;
142-
}
143-
144-
FragmentIterator &operator--() {
145-
assert(Num.get() > 0 && "Decrementing iterator past begin()");
146-
Num = FragmentNum(Num.get() - 1);
147-
return *this;
148-
}
149-
150-
friend class FunctionLayout;
151-
};
152-
153-
using const_iterator = FragmentIterator;
154-
using block_const_iterator = BasicBlockListType::const_iterator;
126+
using fragment_iterator = pointee_iterator<FragmentListType::const_iterator>;
127+
using fragment_const_iterator =
128+
pointee_iterator<FragmentListType::const_iterator,
129+
const FunctionFragment>;
130+
using block_const_iterator =
131+
raw_pointer_iterator<BasicBlockListType::const_iterator,
132+
const BinaryBasicBlock>;
133+
using block_reverse_iterator = std::reverse_iterator<block_iterator>;
155134
using block_const_reverse_iterator =
156-
BasicBlockListType::const_reverse_iterator;
135+
std::reverse_iterator<block_const_iterator>;
157136

158137
private:
138+
FragmentListType Fragments;
159139
BasicBlockListType Blocks;
160-
/// List of indices dividing block list into fragments. To simplify iteration,
161-
/// we have `Fragments.back()` equals `Blocks.size()`. Hence,
162-
/// `Fragments.size()` equals `this->size() + 1`. Always contains at least one
163-
/// fragment.
164-
FragmentListType Fragments = {0, 0};
165140

166141
public:
142+
FunctionLayout();
143+
FunctionLayout(const FunctionLayout &Other);
144+
FunctionLayout(FunctionLayout &&Other);
145+
FunctionLayout &operator=(const FunctionLayout &Other);
146+
FunctionLayout &operator=(FunctionLayout &&Other);
147+
~FunctionLayout();
148+
167149
/// Add an empty fragment.
168-
FunctionFragment addFragment();
150+
FunctionFragment &addFragment();
151+
152+
/// Return the fragment identified by Num.
153+
FunctionFragment &getFragment(FragmentNum Num);
169154

170155
/// Return the fragment identified by Num.
171-
FunctionFragment getFragment(FragmentNum Num) const;
156+
const FunctionFragment &getFragment(FragmentNum Num) const;
172157

173158
/// Get the fragment that contains all entry blocks and other blocks that
174159
/// cannot be split.
175-
FunctionFragment getMainFragment() const {
160+
FunctionFragment &getMainFragment() {
176161
return getFragment(FragmentNum::main());
177162
}
178163

179164
/// Get the fragment that contains all entry blocks and other blocks that
180165
/// cannot be split.
181-
iterator_range<const_iterator> getSplitFragments() const {
166+
const FunctionFragment &getMainFragment() const {
167+
return getFragment(FragmentNum::main());
168+
}
169+
170+
/// Get the fragment that contains all entry blocks and other blocks that
171+
/// cannot be split.
172+
iterator_range<fragment_iterator> getSplitFragments() {
173+
return {++fragment_begin(), fragment_end()};
174+
}
175+
176+
/// Get the fragment that contains all entry blocks and other blocks that
177+
/// cannot be split.
178+
iterator_range<fragment_const_iterator> getSplitFragments() const {
182179
return {++fragment_begin(), fragment_end()};
183180
}
184181

185182
/// Find the fragment that contains BB.
186-
FunctionFragment findFragment(const BinaryBasicBlock *BB) const;
183+
const FunctionFragment &findFragment(const BinaryBasicBlock *BB) const;
187184

188185
/// Add BB to the end of the last fragment.
189186
void addBasicBlock(BinaryBasicBlock *BB);
190187

191188
/// Insert range of basic blocks after InsertAfter. If InsertAfter is nullptr,
192189
/// the blocks will be inserted at the start of the function.
193-
void insertBasicBlocks(BinaryBasicBlock *InsertAfter,
190+
void insertBasicBlocks(const BinaryBasicBlock *InsertAfter,
194191
ArrayRef<BinaryBasicBlock *> NewBlocks);
195192

196193
/// Erase all blocks from the layout that are in ToErase. If this method
197194
/// erases all blocks of a fragment, it will be removed as well.
198195
void eraseBasicBlocks(const DenseSet<const BinaryBasicBlock *> ToErase);
199196

200197
/// Make sure fragments' and basic blocks' indices match the current layout.
201-
void updateLayoutIndices() const;
198+
void updateLayoutIndices();
202199

203200
/// Replace the current layout with NewLayout. Uses the block's
204201
/// self-identifying fragment number to assign blocks to infer function
@@ -209,12 +206,25 @@ class FunctionLayout {
209206
/// Clear layout releasing memory.
210207
void clear();
211208

212-
BinaryBasicBlock *getBlock(unsigned Index) const { return Blocks[Index]; }
209+
BinaryBasicBlock *getBlock(unsigned Index) { return Blocks[Index]; }
210+
211+
const BinaryBasicBlock *getBlock(unsigned Index) const {
212+
return Blocks[Index];
213+
}
214+
215+
/// Returns the basic block after the given basic block in the layout or
216+
/// nullptr if the last basic block is given.
217+
BinaryBasicBlock *getBasicBlockAfter(const BinaryBasicBlock *const BB,
218+
const bool IgnoreSplits = true) {
219+
return const_cast<BinaryBasicBlock *>(
220+
static_cast<const FunctionLayout &>(*this).getBasicBlockAfter(
221+
BB, IgnoreSplits));
222+
}
213223

214224
/// Returns the basic block after the given basic block in the layout or
215225
/// nullptr if the last basic block is given.
216-
BinaryBasicBlock *getBasicBlockAfter(const BinaryBasicBlock *BB,
217-
bool IgnoreSplits = true) const;
226+
const BinaryBasicBlock *getBasicBlockAfter(const BinaryBasicBlock *BB,
227+
bool IgnoreSplits = true) const;
218228

219229
/// True if the layout contains at least two non-empty fragments.
220230
bool isSplit() const;
@@ -230,29 +240,49 @@ class FunctionLayout {
230240
bool isHotColdSplit() const { return fragment_size() <= 2; }
231241

232242
size_t fragment_size() const {
233-
assert(Fragments.size() >= 2 &&
243+
assert(Fragments.size() >= 1 &&
234244
"Layout should have at least one fragment.");
235-
return Fragments.size() - 1;
245+
return Fragments.size();
236246
}
237-
bool fragment_empty() const { return Fragments.size() == 1; }
238-
const_iterator fragment_begin() const { return {FragmentNum(0), this}; }
239-
const_iterator fragment_end() const {
240-
return {FragmentNum(fragment_size()), this};
247+
bool fragment_empty() const { return fragment_size() == 0; }
248+
249+
fragment_iterator fragment_begin() { return Fragments.begin(); }
250+
fragment_const_iterator fragment_begin() const { return Fragments.begin(); }
251+
fragment_iterator fragment_end() { return Fragments.end(); }
252+
fragment_const_iterator fragment_end() const { return Fragments.end(); }
253+
iterator_range<fragment_iterator> fragments() {
254+
return {fragment_begin(), fragment_end()};
241255
}
242-
iterator_range<const_iterator> fragments() const {
256+
iterator_range<fragment_const_iterator> fragments() const {
243257
return {fragment_begin(), fragment_end()};
244258
}
245259

246260
size_t block_size() const { return Blocks.size(); }
247261
bool block_empty() const { return Blocks.empty(); }
262+
263+
/// Required to return non-const qualified `BinaryBasicBlock *` for graph
264+
/// traits.
248265
BinaryBasicBlock *block_front() const { return Blocks.front(); }
249-
BinaryBasicBlock *block_back() const { return Blocks.back(); }
250-
block_const_iterator block_begin() const { return Blocks.begin(); }
251-
block_const_iterator block_end() const { return Blocks.end(); }
266+
const BinaryBasicBlock *block_back() const { return Blocks.back(); }
267+
268+
block_iterator block_begin() { return Blocks.begin(); }
269+
block_const_iterator block_begin() const {
270+
return block_const_iterator(Blocks.begin());
271+
}
272+
block_iterator block_end() { return Blocks.end(); }
273+
block_const_iterator block_end() const {
274+
return block_const_iterator(Blocks.end());
275+
}
276+
iterator_range<block_iterator> blocks() {
277+
return {block_begin(), block_end()};
278+
}
252279
iterator_range<block_const_iterator> blocks() const {
253280
return {block_begin(), block_end()};
254281
}
282+
283+
block_reverse_iterator block_rbegin() { return Blocks.rbegin(); }
255284
block_const_reverse_iterator block_rbegin() const { return Blocks.rbegin(); }
285+
block_reverse_iterator block_rend() { return Blocks.rend(); }
256286
block_const_reverse_iterator block_rend() const { return Blocks.rend(); }
257287
iterator_range<block_const_reverse_iterator> rblocks() const {
258288
return {block_rbegin(), block_rend()};

bolt/lib/Core/BinaryContext.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2199,7 +2199,7 @@ BinaryContext::calculateEmittedSize(BinaryFunction &BF, bool FixBranches) {
21992199

22002200
using LabelRange = std::pair<const MCSymbol *, const MCSymbol *>;
22012201
SmallVector<LabelRange> SplitLabels;
2202-
for (const FunctionFragment FF : BF.getLayout().getSplitFragments()) {
2202+
for (FunctionFragment &FF : BF.getLayout().getSplitFragments()) {
22032203
MCSymbol *const SplitStartLabel = LocalCtx->createTempSymbol();
22042204
MCSymbol *const SplitEndLabel = LocalCtx->createTempSymbol();
22052205
SplitLabels.emplace_back(SplitStartLabel, SplitEndLabel);

bolt/lib/Core/BinaryEmitter.cpp

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -129,15 +129,15 @@ class BinaryEmitter {
129129

130130
/// Emit function code. The caller is responsible for emitting function
131131
/// symbol(s) and setting the section to emit the code to.
132-
void emitFunctionBody(BinaryFunction &BF, const FunctionFragment &FF,
132+
void emitFunctionBody(BinaryFunction &BF, FunctionFragment &FF,
133133
bool EmitCodeOnly = false);
134134

135135
private:
136136
/// Emit function code.
137137
void emitFunctions();
138138

139139
/// Emit a single function.
140-
bool emitFunction(BinaryFunction &BF, const FunctionFragment &FF);
140+
bool emitFunction(BinaryFunction &BF, FunctionFragment &FF);
141141

142142
/// Helper for emitFunctionBody to write data inside a function
143143
/// (used for AArch64)
@@ -234,7 +234,7 @@ void BinaryEmitter::emitFunctions() {
234234
!Function->hasValidProfile())
235235
Streamer.setAllowAutoPadding(false);
236236

237-
const FunctionLayout &Layout = Function->getLayout();
237+
FunctionLayout &Layout = Function->getLayout();
238238
Emitted |= emitFunction(*Function, Layout.getMainFragment());
239239

240240
if (Function->isSplit()) {
@@ -243,7 +243,7 @@ void BinaryEmitter::emitFunctions() {
243243

244244
assert((Layout.fragment_size() == 1 || Function->isSimple()) &&
245245
"Only simple functions can have fragments");
246-
for (const FunctionFragment FF : Layout.getSplitFragments()) {
246+
for (FunctionFragment &FF : Layout.getSplitFragments()) {
247247
// Skip empty fragments so no symbols and sections for empty fragments
248248
// are generated
249249
if (FF.empty() && !Function->hasConstantIsland())
@@ -280,7 +280,7 @@ void BinaryEmitter::emitFunctions() {
280280
}
281281

282282
bool BinaryEmitter::emitFunction(BinaryFunction &Function,
283-
const FunctionFragment &FF) {
283+
FunctionFragment &FF) {
284284
if (Function.size() == 0 && !Function.hasIslandsInfo())
285285
return false;
286286

@@ -402,8 +402,7 @@ bool BinaryEmitter::emitFunction(BinaryFunction &Function,
402402
return true;
403403
}
404404

405-
void BinaryEmitter::emitFunctionBody(BinaryFunction &BF,
406-
const FunctionFragment &FF,
405+
void BinaryEmitter::emitFunctionBody(BinaryFunction &BF, FunctionFragment &FF,
407406
bool EmitCodeOnly) {
408407
if (!EmitCodeOnly && FF.isSplitFragment() && BF.hasConstantIsland()) {
409408
assert(BF.getLayout().isHotColdSplit() &&
@@ -1160,7 +1159,7 @@ void emitBinaryContext(MCStreamer &Streamer, BinaryContext &BC,
11601159
}
11611160

11621161
void emitFunctionBody(MCStreamer &Streamer, BinaryFunction &BF,
1163-
const FunctionFragment &FF, bool EmitCodeOnly) {
1162+
FunctionFragment &FF, bool EmitCodeOnly) {
11641163
BinaryEmitter(Streamer, BF.getBinaryContext())
11651164
.emitFunctionBody(BF, FF, EmitCodeOnly);
11661165
}

0 commit comments

Comments
 (0)