xref: /llvm-project/bolt/lib/Core/FunctionLayout.cpp (revision 49ee6069db372ce326bc36678e745459868c3771)
1fd38366eSAmir Ayupov //===- bolt/Core/FunctionLayout.cpp - Fragmented Function Layout -*- C++ -*-==//
2fd38366eSAmir Ayupov //
3fd38366eSAmir Ayupov // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4fd38366eSAmir Ayupov // See https://llvm.org/LICENSE.txt for license information.
5fd38366eSAmir Ayupov // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6fd38366eSAmir Ayupov //
7fd38366eSAmir Ayupov //===----------------------------------------------------------------------===//
8fd38366eSAmir Ayupov 
98477bc67SFabian Parzefall #include "bolt/Core/FunctionLayout.h"
10fd38366eSAmir Ayupov #include "bolt/Core/BinaryBasicBlock.h"
118477bc67SFabian Parzefall #include "llvm/ADT/STLExtras.h"
128477bc67SFabian Parzefall #include "llvm/ADT/edit_distance.h"
138477bc67SFabian Parzefall #include <algorithm>
1407f63b0aSFabian Parzefall #include <iterator>
158477bc67SFabian Parzefall 
168477bc67SFabian Parzefall using namespace llvm;
178477bc67SFabian Parzefall using namespace bolt;
188477bc67SFabian Parzefall 
1907f63b0aSFabian Parzefall FunctionFragment::FunctionFragment(FunctionLayout &Layout,
2007f63b0aSFabian Parzefall                                    const FragmentNum Num)
2107f63b0aSFabian Parzefall     : Layout(&Layout), Num(Num), StartIndex(Layout.block_size()) {}
2207f63b0aSFabian Parzefall 
2307f63b0aSFabian Parzefall FunctionFragment::iterator FunctionFragment::begin() {
2407f63b0aSFabian Parzefall   return iterator(Layout->block_begin() + StartIndex);
2507f63b0aSFabian Parzefall }
268477bc67SFabian Parzefall FunctionFragment::const_iterator FunctionFragment::begin() const {
2707f63b0aSFabian Parzefall   return const_iterator(Layout->block_begin() + StartIndex);
2807f63b0aSFabian Parzefall }
2907f63b0aSFabian Parzefall FunctionFragment::iterator FunctionFragment::end() {
3007f63b0aSFabian Parzefall   return iterator(Layout->block_begin() + StartIndex + Size);
318477bc67SFabian Parzefall }
328477bc67SFabian Parzefall FunctionFragment::const_iterator FunctionFragment::end() const {
3307f63b0aSFabian Parzefall   return const_iterator(Layout->block_begin() + StartIndex + Size);
348477bc67SFabian Parzefall }
358477bc67SFabian Parzefall 
36*49ee6069SMaksim Panchenko BinaryBasicBlock *FunctionFragment::front() const { return *begin(); }
37*49ee6069SMaksim Panchenko 
38*49ee6069SMaksim Panchenko BinaryBasicBlock *FunctionFragment::back() const { return *std::prev(end()); }
3907f63b0aSFabian Parzefall 
4007f63b0aSFabian Parzefall FunctionLayout::FunctionLayout() { addFragment(); }
4107f63b0aSFabian Parzefall 
4207f63b0aSFabian Parzefall FunctionLayout::FunctionLayout(const FunctionLayout &Other)
4307f63b0aSFabian Parzefall     : Blocks(Other.Blocks) {
4407f63b0aSFabian Parzefall   for (FunctionFragment *const FF : Other.Fragments) {
4507f63b0aSFabian Parzefall     auto *Copy = new FunctionFragment(*FF);
4607f63b0aSFabian Parzefall     Copy->Layout = this;
4707f63b0aSFabian Parzefall     Fragments.emplace_back(Copy);
4807f63b0aSFabian Parzefall   }
498477bc67SFabian Parzefall }
508477bc67SFabian Parzefall 
5107f63b0aSFabian Parzefall FunctionLayout::FunctionLayout(FunctionLayout &&Other)
5207f63b0aSFabian Parzefall     : Fragments(std::move(Other.Fragments)), Blocks(std::move(Other.Blocks)) {
5307f63b0aSFabian Parzefall   for (FunctionFragment *const F : Fragments)
5407f63b0aSFabian Parzefall     F->Layout = this;
5507f63b0aSFabian Parzefall }
5607f63b0aSFabian Parzefall 
5707f63b0aSFabian Parzefall FunctionLayout &FunctionLayout::operator=(const FunctionLayout &Other) {
5807f63b0aSFabian Parzefall   Blocks = Other.Blocks;
5907f63b0aSFabian Parzefall   for (FunctionFragment *const FF : Other.Fragments) {
6007f63b0aSFabian Parzefall     auto *const Copy = new FunctionFragment(*FF);
6107f63b0aSFabian Parzefall     Copy->Layout = this;
6207f63b0aSFabian Parzefall     Fragments.emplace_back(Copy);
6307f63b0aSFabian Parzefall   }
6407f63b0aSFabian Parzefall   return *this;
6507f63b0aSFabian Parzefall }
6607f63b0aSFabian Parzefall 
6707f63b0aSFabian Parzefall FunctionLayout &FunctionLayout::operator=(FunctionLayout &&Other) {
6807f63b0aSFabian Parzefall   Fragments = std::move(Other.Fragments);
6907f63b0aSFabian Parzefall   Blocks = std::move(Other.Blocks);
7007f63b0aSFabian Parzefall   for (FunctionFragment *const FF : Fragments)
7107f63b0aSFabian Parzefall     FF->Layout = this;
7207f63b0aSFabian Parzefall   return *this;
7307f63b0aSFabian Parzefall }
7407f63b0aSFabian Parzefall 
7507f63b0aSFabian Parzefall FunctionLayout::~FunctionLayout() {
7607f63b0aSFabian Parzefall   for (FunctionFragment *const F : Fragments) {
7707f63b0aSFabian Parzefall     delete F;
7807f63b0aSFabian Parzefall   }
7907f63b0aSFabian Parzefall }
8007f63b0aSFabian Parzefall 
8107f63b0aSFabian Parzefall FunctionFragment &FunctionLayout::addFragment() {
8207f63b0aSFabian Parzefall   FunctionFragment *const FF =
8307f63b0aSFabian Parzefall       new FunctionFragment(*this, FragmentNum(Fragments.size()));
8407f63b0aSFabian Parzefall   Fragments.emplace_back(FF);
8507f63b0aSFabian Parzefall   return *FF;
8607f63b0aSFabian Parzefall }
8707f63b0aSFabian Parzefall 
8807f63b0aSFabian Parzefall FunctionFragment &FunctionLayout::getFragment(FragmentNum Num) {
8907f63b0aSFabian Parzefall   return *Fragments[Num.get()];
9007f63b0aSFabian Parzefall }
9107f63b0aSFabian Parzefall 
9207f63b0aSFabian Parzefall const FunctionFragment &FunctionLayout::getFragment(FragmentNum Num) const {
9307f63b0aSFabian Parzefall   return *Fragments[Num.get()];
9407f63b0aSFabian Parzefall }
9507f63b0aSFabian Parzefall 
9607f63b0aSFabian Parzefall const FunctionFragment &
9707f63b0aSFabian Parzefall FunctionLayout::findFragment(const BinaryBasicBlock *const BB) const {
988477bc67SFabian Parzefall   return getFragment(BB->getFragmentNum());
998477bc67SFabian Parzefall }
1008477bc67SFabian Parzefall 
10107f63b0aSFabian Parzefall void FunctionLayout::addBasicBlock(BinaryBasicBlock *const BB) {
1028477bc67SFabian Parzefall   BB->setLayoutIndex(Blocks.size());
1038477bc67SFabian Parzefall   Blocks.emplace_back(BB);
10407f63b0aSFabian Parzefall   Fragments.back()->Size++;
1058477bc67SFabian Parzefall }
1068477bc67SFabian Parzefall 
10707f63b0aSFabian Parzefall void FunctionLayout::insertBasicBlocks(
10807f63b0aSFabian Parzefall     const BinaryBasicBlock *const InsertAfter,
10907f63b0aSFabian Parzefall     const ArrayRef<BinaryBasicBlock *> NewBlocks) {
11007f63b0aSFabian Parzefall   block_iterator InsertBeforePos = Blocks.begin();
11107f63b0aSFabian Parzefall   FragmentNum InsertFragmentNum = FragmentNum::main();
11207f63b0aSFabian Parzefall   unsigned LayoutIndex = 0;
1138477bc67SFabian Parzefall 
11407f63b0aSFabian Parzefall   if (InsertAfter) {
11507f63b0aSFabian Parzefall     InsertBeforePos = std::next(findBasicBlockPos(InsertAfter));
11607f63b0aSFabian Parzefall     InsertFragmentNum = InsertAfter->getFragmentNum();
11707f63b0aSFabian Parzefall     LayoutIndex = InsertAfter->getLayoutIndex();
11807f63b0aSFabian Parzefall   }
11907f63b0aSFabian Parzefall 
12007f63b0aSFabian Parzefall   llvm::copy(NewBlocks, std::inserter(Blocks, InsertBeforePos));
12107f63b0aSFabian Parzefall 
12207f63b0aSFabian Parzefall   for (BinaryBasicBlock *const BB : NewBlocks) {
12307f63b0aSFabian Parzefall     BB->setFragmentNum(InsertFragmentNum);
12407f63b0aSFabian Parzefall     BB->setLayoutIndex(LayoutIndex++);
12507f63b0aSFabian Parzefall   }
12607f63b0aSFabian Parzefall 
12707f63b0aSFabian Parzefall   const fragment_iterator InsertFragment =
12807f63b0aSFabian Parzefall       fragment_begin() + InsertFragmentNum.get();
12907f63b0aSFabian Parzefall   InsertFragment->Size += NewBlocks.size();
13007f63b0aSFabian Parzefall 
13107f63b0aSFabian Parzefall   const fragment_iterator TailBegin = std::next(InsertFragment);
13207f63b0aSFabian Parzefall   auto const UpdateFragment = [&](FunctionFragment &FF) {
13307f63b0aSFabian Parzefall     FF.StartIndex += NewBlocks.size();
13407f63b0aSFabian Parzefall     for (BinaryBasicBlock *const BB : FF)
13507f63b0aSFabian Parzefall       BB->setLayoutIndex(LayoutIndex++);
13607f63b0aSFabian Parzefall   };
13707f63b0aSFabian Parzefall   std::for_each(TailBegin, fragment_end(), UpdateFragment);
1388477bc67SFabian Parzefall }
1398477bc67SFabian Parzefall 
1408477bc67SFabian Parzefall void FunctionLayout::eraseBasicBlocks(
1418477bc67SFabian Parzefall     const DenseSet<const BinaryBasicBlock *> ToErase) {
14207f63b0aSFabian Parzefall   const auto IsErased = [&](const BinaryBasicBlock *const BB) {
1438477bc67SFabian Parzefall     return ToErase.contains(BB);
1448477bc67SFabian Parzefall   };
14507f63b0aSFabian Parzefall 
14607f63b0aSFabian Parzefall   unsigned TotalErased = 0;
14707f63b0aSFabian Parzefall   for (FunctionFragment &FF : fragments()) {
14807f63b0aSFabian Parzefall     unsigned Erased = count_if(FF, IsErased);
14907f63b0aSFabian Parzefall     FF.Size -= Erased;
15007f63b0aSFabian Parzefall     FF.StartIndex -= TotalErased;
15107f63b0aSFabian Parzefall     TotalErased += Erased;
1528477bc67SFabian Parzefall   }
1532febc32cSKazu Hirata   llvm::erase_if(Blocks, IsErased);
1540f74d191SFabian Parzefall 
1550f74d191SFabian Parzefall   // Remove empty fragments at the end
15607f63b0aSFabian Parzefall   const auto IsEmpty = [](const FunctionFragment *const FF) {
15707f63b0aSFabian Parzefall     return FF->empty();
15807f63b0aSFabian Parzefall   };
15907f63b0aSFabian Parzefall   const FragmentListType::iterator EmptyTailBegin =
16007f63b0aSFabian Parzefall       llvm::find_if_not(reverse(Fragments), IsEmpty).base();
161a0c7ca8aSKazu Hirata   for (FunctionFragment *const FF :
162a0c7ca8aSKazu Hirata        llvm::make_range(EmptyTailBegin, Fragments.end()))
163a0c7ca8aSKazu Hirata     delete FF;
16407f63b0aSFabian Parzefall   Fragments.erase(EmptyTailBegin, Fragments.end());
1650f74d191SFabian Parzefall 
1660f74d191SFabian Parzefall   updateLayoutIndices();
1678477bc67SFabian Parzefall }
1688477bc67SFabian Parzefall 
169629b6f4eSshaw young void FunctionLayout::updateLayoutIndices() const {
1708477bc67SFabian Parzefall   unsigned BlockIndex = 0;
171629b6f4eSshaw young   for (const FunctionFragment &FF : fragments()) {
1720f74d191SFabian Parzefall     for (BinaryBasicBlock *const BB : FF) {
1738477bc67SFabian Parzefall       BB->setLayoutIndex(BlockIndex++);
1740f74d191SFabian Parzefall       BB->setFragmentNum(FF.getFragmentNum());
1750f74d191SFabian Parzefall     }
1768477bc67SFabian Parzefall   }
1778477bc67SFabian Parzefall }
178629b6f4eSshaw young void FunctionLayout::updateLayoutIndices(
179629b6f4eSshaw young     ArrayRef<BinaryBasicBlock *> Order) const {
180629b6f4eSshaw young   for (auto [Index, BB] : llvm::enumerate(Order))
181629b6f4eSshaw young     BB->setLayoutIndex(Index);
182629b6f4eSshaw young }
1838477bc67SFabian Parzefall 
184aed75748SFabian Parzefall bool FunctionLayout::update(const ArrayRef<BinaryBasicBlock *> NewLayout) {
185aed75748SFabian Parzefall   const bool EqualBlockOrder = llvm::equal(Blocks, NewLayout);
186aed75748SFabian Parzefall   if (EqualBlockOrder) {
187aed75748SFabian Parzefall     const bool EqualPartitioning =
18807f63b0aSFabian Parzefall         llvm::all_of(fragments(), [](const FunctionFragment &FF) {
189aed75748SFabian Parzefall           return llvm::all_of(FF, [&](const BinaryBasicBlock *const BB) {
190aed75748SFabian Parzefall             return FF.Num == BB->getFragmentNum();
191aed75748SFabian Parzefall           });
192aed75748SFabian Parzefall         });
193aed75748SFabian Parzefall     if (EqualPartitioning)
194aed75748SFabian Parzefall       return false;
195aed75748SFabian Parzefall   }
1968477bc67SFabian Parzefall 
19707f63b0aSFabian Parzefall   clear();
1988477bc67SFabian Parzefall 
1998477bc67SFabian Parzefall   // Generate fragments
20007f63b0aSFabian Parzefall   for (BinaryBasicBlock *const BB : NewLayout) {
20107f63b0aSFabian Parzefall     FragmentNum Num = BB->getFragmentNum();
2028477bc67SFabian Parzefall 
2038477bc67SFabian Parzefall     // Add empty fragments if necessary
20407f63b0aSFabian Parzefall     while (Fragments.back()->getFragmentNum() < Num)
2058477bc67SFabian Parzefall       addFragment();
2068477bc67SFabian Parzefall 
2078477bc67SFabian Parzefall     // Set the next fragment to point one past the current BB
20807f63b0aSFabian Parzefall     addBasicBlock(BB);
2098477bc67SFabian Parzefall   }
2108477bc67SFabian Parzefall 
211aed75748SFabian Parzefall   return true;
2128477bc67SFabian Parzefall }
2138477bc67SFabian Parzefall 
2148477bc67SFabian Parzefall void FunctionLayout::clear() {
21507f63b0aSFabian Parzefall   Blocks = BasicBlockListType();
2169b6e7861SFabian Parzefall   // If the binary does not have relocations and is not split, the function will
2179b6e7861SFabian Parzefall   // be written to the output stream at its original file offset (see
2189b6e7861SFabian Parzefall   // `RewriteInstance::rewriteFile`). Hence, when the layout is cleared, retain
2199b6e7861SFabian Parzefall   // the main fragment, so that this information is not lost.
220a0c7ca8aSKazu Hirata   for (FunctionFragment *const FF : llvm::drop_begin(Fragments))
221a0c7ca8aSKazu Hirata     delete FF;
2229b6e7861SFabian Parzefall   Fragments = FragmentListType{Fragments.front()};
2239b6e7861SFabian Parzefall   getMainFragment().Size = 0;
2248477bc67SFabian Parzefall }
2258477bc67SFabian Parzefall 
22607f63b0aSFabian Parzefall const BinaryBasicBlock *
22707f63b0aSFabian Parzefall FunctionLayout::getBasicBlockAfter(const BinaryBasicBlock *BB,
2288477bc67SFabian Parzefall                                    bool IgnoreSplits) const {
22907f63b0aSFabian Parzefall   const block_const_iterator BBPos = find(blocks(), BB);
23007f63b0aSFabian Parzefall   if (BBPos == block_end())
2318477bc67SFabian Parzefall     return nullptr;
2328477bc67SFabian Parzefall 
2338477bc67SFabian Parzefall   const block_const_iterator BlockAfter = std::next(BBPos);
23407f63b0aSFabian Parzefall   if (BlockAfter == block_end())
2358477bc67SFabian Parzefall     return nullptr;
2368477bc67SFabian Parzefall 
2378477bc67SFabian Parzefall   if (!IgnoreSplits)
2388477bc67SFabian Parzefall     if (BlockAfter == getFragment(BB->getFragmentNum()).end())
2398477bc67SFabian Parzefall       return nullptr;
2408477bc67SFabian Parzefall 
2418477bc67SFabian Parzefall   return *BlockAfter;
2428477bc67SFabian Parzefall }
2438477bc67SFabian Parzefall 
2448477bc67SFabian Parzefall bool FunctionLayout::isSplit() const {
24507f63b0aSFabian Parzefall   const unsigned NonEmptyFragCount = llvm::count_if(
2460f8412c1SFabian Parzefall       fragments(), [](const FunctionFragment &FF) { return !FF.empty(); });
2478477bc67SFabian Parzefall   return NonEmptyFragCount >= 2;
2488477bc67SFabian Parzefall }
2498477bc67SFabian Parzefall 
250aed75748SFabian Parzefall uint64_t FunctionLayout::getEditDistance(
251aed75748SFabian Parzefall     const ArrayRef<const BinaryBasicBlock *> OldBlockOrder) const {
252aed75748SFabian Parzefall   return ComputeEditDistance<const BinaryBasicBlock *>(OldBlockOrder, Blocks);
2538477bc67SFabian Parzefall }
2548477bc67SFabian Parzefall 
2558477bc67SFabian Parzefall FunctionLayout::block_const_iterator
2568477bc67SFabian Parzefall FunctionLayout::findBasicBlockPos(const BinaryBasicBlock *BB) const {
25707f63b0aSFabian Parzefall   return block_const_iterator(find(Blocks, BB));
2588477bc67SFabian Parzefall }
2598477bc67SFabian Parzefall 
2608477bc67SFabian Parzefall FunctionLayout::block_iterator
2618477bc67SFabian Parzefall FunctionLayout::findBasicBlockPos(const BinaryBasicBlock *BB) {
2628477bc67SFabian Parzefall   return find(Blocks, BB);
2638477bc67SFabian Parzefall }
264