1 //===- bolt/Core/FunctionLayout.h - 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 //===----------------------------------------------------------------------===// 8 // 9 // This file contains the declaration of the FunctionLayout class. The layout of 10 // a function is the order of basic blocks, in which we will arrange them in the 11 // new binary. Normally, when not optimizing for code layout, the blocks of a 12 // function are contiguous. However, we can split the layout into multiple 13 // fragments. The blocks within a fragment are contiguous, but the fragments 14 // itself are disjoint. Fragments could be used to enhance code layout, e.g. to 15 // separate the blocks into hot and cold sections. 16 // 17 //===----------------------------------------------------------------------===// 18 19 #ifndef BOLT_CORE_FUNCTION_LAYOUT_H 20 #define BOLT_CORE_FUNCTION_LAYOUT_H 21 22 #include "llvm/ADT/ArrayRef.h" 23 #include "llvm/ADT/DenseSet.h" 24 #include "llvm/ADT/SmallVector.h" 25 #include "llvm/ADT/iterator.h" 26 27 namespace llvm { 28 namespace bolt { 29 30 class BinaryFunction; 31 class BinaryBasicBlock; 32 class FunctionLayout; 33 34 class FragmentNum { 35 unsigned Value{0}; 36 37 public: 38 constexpr FragmentNum() = default; FragmentNum(unsigned Value)39 constexpr explicit FragmentNum(unsigned Value) : Value(Value) {} get()40 constexpr unsigned get() const { return Value; } 41 constexpr bool operator==(const FragmentNum Other) const { 42 return Value == Other.Value; 43 } 44 constexpr bool operator!=(const FragmentNum Other) const { 45 return !(*this == Other); 46 } 47 hot()48 static constexpr FragmentNum hot() { return FragmentNum(0); } cold()49 static constexpr FragmentNum cold() { return FragmentNum(1); } 50 }; 51 52 /// A freestanding subset of contiguous blocks of a function. 53 class FunctionFragment { 54 using BasicBlockListType = SmallVector<BinaryBasicBlock *, 0>; 55 using FragmentListType = SmallVector<unsigned, 0>; 56 57 public: 58 using const_iterator = BasicBlockListType::const_iterator; 59 60 private: 61 FragmentNum Num; 62 const FunctionLayout &Layout; 63 FunctionFragment(FragmentNum Num,const FunctionLayout & Layout)64 FunctionFragment(FragmentNum Num, const FunctionLayout &Layout) 65 : Num(Num), Layout(Layout) {} 66 67 public: 68 unsigned size() const; 69 bool empty() const; 70 const_iterator begin() const; 71 const_iterator end() const; 72 BinaryBasicBlock *front() const; 73 74 friend class FunctionLayout; 75 friend class FragmentIterator; 76 }; 77 78 /// The function layout represents the fragments we split a function into and 79 /// the order of basic blocks within each fragment. 80 /// 81 /// Internally, the function layout stores blocks across fragments contiguously. 82 /// This is necessary to retain compatibility with existing code and tests that 83 /// iterate over all blocks of the layout and depend on that order. When 84 /// writing new code, avoid iterating using FunctionLayout::blocks() by 85 /// iterating either over fragments or over BinaryFunction::begin()..end(). 86 class FunctionLayout { 87 private: 88 using BasicBlockListType = SmallVector<BinaryBasicBlock *, 0>; 89 using block_iterator = BasicBlockListType::iterator; 90 using FragmentListType = SmallVector<unsigned, 0>; 91 92 public: 93 class FragmentIterator; 94 95 class FragmentIterator 96 : public iterator_facade_base< 97 FragmentIterator, std::bidirectional_iterator_tag, FunctionFragment, 98 std::ptrdiff_t, FunctionFragment *, FunctionFragment> { 99 FragmentNum Num; 100 const FunctionLayout *Layout; 101 FragmentIterator(FragmentNum Num,const FunctionLayout * Layout)102 FragmentIterator(FragmentNum Num, const FunctionLayout *Layout) 103 : Num(Num), Layout(Layout) {} 104 105 public: 106 bool operator==(const FragmentIterator &Other) const { 107 return Num == Other.Num; 108 } 109 110 FunctionFragment operator*() const { 111 return FunctionFragment(Num, *Layout); 112 } 113 114 FragmentIterator &operator++() { 115 Num = FragmentNum(Num.get() + 1); 116 return *this; 117 } 118 119 FragmentIterator &operator--() { 120 Num = FragmentNum(Num.get() - 1); 121 return *this; 122 } 123 124 friend class FunctionLayout; 125 }; 126 127 using const_iterator = FragmentIterator; 128 using block_const_iterator = BasicBlockListType::const_iterator; 129 using block_const_reverse_iterator = 130 BasicBlockListType::const_reverse_iterator; 131 132 private: 133 BasicBlockListType Blocks; 134 /// List of indices dividing block list into fragments. To simplify iteration, 135 /// we have `Fragments.back()` equals `Blocks.size()`. Hence, 136 /// `Fragments.size()` equals `this->size() + 1`. 137 FragmentListType Fragments = {0}; 138 BasicBlockListType PreviousBlocks; 139 FragmentListType PreviousFragments; 140 141 public: 142 /// Add an empty fragment. 143 FunctionFragment addFragment(); 144 145 /// Return the fragment identified by Num. 146 FunctionFragment getFragment(FragmentNum Num) const; 147 148 /// Find the fragment that contains BB. 149 FunctionFragment findFragment(const BinaryBasicBlock *BB) const; 150 151 /// Add BB to the end of the last fragment. 152 void addBasicBlock(BinaryBasicBlock *BB); 153 154 /// Insert range of basic blocks after InsertAfter. If InsertAfter is nullptr, 155 /// the blocks will be inserted at the start of the function. 156 void insertBasicBlocks(BinaryBasicBlock *InsertAfter, 157 ArrayRef<BinaryBasicBlock *> NewBlocks); 158 159 /// Erase all blocks from the layout that are in ToErase. 160 void eraseBasicBlocks(const DenseSet<const BinaryBasicBlock *> ToErase); 161 162 /// Make sure fragments' and basic blocks' indices match the current layout. 163 void updateLayoutIndices() const; 164 165 /// Replace the current layout with NewLayout. Uses the block's 166 /// self-identifying fragment number to assign blocks to infer function 167 /// fragments. 168 void update(const ArrayRef<BinaryBasicBlock *> NewLayout); 169 170 /// Return true if the layout has been changed by basic block reordering, 171 /// false otherwise. hasLayoutChanged()172 bool hasLayoutChanged() const { return !PreviousBlocks.empty(); } 173 174 /// Clear layout releasing memory. 175 void clear(); 176 getBlock(unsigned Index)177 BinaryBasicBlock *getBlock(unsigned Index) const { return Blocks[Index]; } 178 179 /// Returns the basic block after the given basic block in the layout or 180 /// nullptr if the last basic block is given. 181 BinaryBasicBlock *getBasicBlockAfter(const BinaryBasicBlock *BB, 182 bool IgnoreSplits = true) const; 183 184 /// True if the layout contains at least two non-empty fragments. 185 bool isSplit() const; 186 187 /// Get the edit distance of the new layout with respect to the previous 188 /// layout after basic block reordering. 189 uint64_t getEditDistance() const; 190 size()191 size_t size() const { return Fragments.size() - 1; } empty()192 bool empty() const { return Fragments.size() == 1; } begin()193 const_iterator begin() const { return {FragmentNum(0), this}; } end()194 const_iterator end() const { return {FragmentNum(size()), this}; } front()195 FunctionFragment front() const { return *begin(); } back()196 FunctionFragment back() const { return *std::prev(end()); } 197 FunctionFragment operator[](const FragmentNum Num) const { 198 return getFragment(Num); 199 } 200 block_size()201 size_t block_size() const { return Blocks.size(); } block_empty()202 bool block_empty() const { return Blocks.empty(); } block_front()203 BinaryBasicBlock *block_front() const { return Blocks.front(); } block_back()204 BinaryBasicBlock *block_back() const { return Blocks.back(); } block_begin()205 block_const_iterator block_begin() const { return Blocks.begin(); } block_end()206 block_const_iterator block_end() const { return Blocks.end(); } blocks()207 iterator_range<block_const_iterator> blocks() const { 208 return {block_begin(), block_end()}; 209 } block_rbegin()210 block_const_reverse_iterator block_rbegin() const { return Blocks.rbegin(); } block_rend()211 block_const_reverse_iterator block_rend() const { return Blocks.rend(); } rblocks()212 iterator_range<block_const_reverse_iterator> rblocks() const { 213 return {block_rbegin(), block_rend()}; 214 } 215 216 private: 217 block_const_iterator findBasicBlockPos(const BinaryBasicBlock *BB) const; 218 block_iterator findBasicBlockPos(const BinaryBasicBlock *BB); 219 220 friend class FunctionFragment; 221 }; 222 223 } // namespace bolt 224 } // namespace llvm 225 226 #endif 227