[TargetVersion] Only enable on RISC-V and AArch64 (#115991)
[llvm-project.git] / bolt / lib / Core / FunctionLayout.cpp
blob4498fc44da954805d7db8a07599094c5ea9f0c20
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 //===----------------------------------------------------------------------===//
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>
16 using namespace llvm;
17 using namespace bolt;
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);
46 Copy->Layout = this;
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)
54 F->Layout = this;
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);
64 return *this;
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;
75 FunctionLayout::~FunctionLayout() {
76 for (FunctionFragment *const F : Fragments) {
77 delete F;
81 FunctionFragment &FunctionLayout::addFragment() {
82 FunctionFragment *const FF =
83 new FunctionFragment(*this, FragmentNum(Fragments.size()));
84 Fragments.emplace_back(FF);
85 return *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;
114 if (InsertAfter) {
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);
149 FF.Size -= Erased;
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) {
157 return FF->empty();
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());
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)
194 return false;
197 clear();
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)
205 addFragment();
207 // Set the next fragment to point one past the current BB
208 addBasicBlock(BB);
211 return true;
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;
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;
233 const block_const_iterator BlockAfter = std::next(BBPos);
234 if (BlockAfter == block_end())
235 return nullptr;
237 if (!IgnoreSplits)
238 if (BlockAfter == getFragment(BB->getFragmentNum()).end())
239 return nullptr;
241 return *BlockAfter;
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);