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