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 #include "llvm/ADT/iterator_range.h" 27 #include <iterator> 28 29 namespace llvm { 30 namespace bolt { 31 32 class BinaryFunction; 33 class BinaryBasicBlock; 34 class FunctionLayout; 35 36 class FragmentNum { 37 unsigned Value{0}; 38 39 public: 40 constexpr FragmentNum() = default; 41 constexpr explicit FragmentNum(unsigned Value) : Value(Value) {} 42 constexpr unsigned get() const { return Value; } 43 44 constexpr bool operator==(const FragmentNum Other) const { 45 return Value == Other.Value; 46 } 47 constexpr bool operator!=(const FragmentNum Other) const { 48 return Value != Other.Value; 49 } 50 constexpr bool operator<(const FragmentNum Other) const { 51 return Value < Other.Value; 52 } 53 constexpr bool operator<=(const FragmentNum Other) const { 54 return Value <= Other.Value; 55 } 56 constexpr bool operator>=(const FragmentNum Other) const { 57 return Value >= Other.Value; 58 } 59 constexpr bool operator>(const FragmentNum Other) const { 60 return Value > Other.Value; 61 } 62 63 static constexpr FragmentNum main() { return FragmentNum(0); } 64 static constexpr FragmentNum cold() { return FragmentNum(1); } 65 static constexpr FragmentNum warm() { return FragmentNum(2); } 66 }; 67 68 /// A freestanding subset of contiguous blocks of a function. 69 class FunctionFragment { 70 using BasicBlockListType = SmallVector<BinaryBasicBlock *, 0>; 71 using FragmentListType = SmallVector<unsigned, 0>; 72 73 public: 74 using iterator = BasicBlockListType::iterator; 75 using const_iterator = BasicBlockListType::const_iterator; 76 77 private: 78 FunctionLayout *Layout; 79 FragmentNum Num; 80 unsigned StartIndex; 81 unsigned Size = 0; 82 83 /// Output address for the fragment. 84 uint64_t Address = 0; 85 86 /// The address for the code for this fragment in codegen memory. Used for 87 /// functions that are emitted in a dedicated section with a fixed address, 88 /// e.g. for functions that are overwritten in-place. 89 uint64_t ImageAddress = 0; 90 91 /// The size of the code in memory. 92 uint64_t ImageSize = 0; 93 94 /// Offset in the file. 95 uint64_t FileOffset = 0; 96 97 FunctionFragment(FunctionLayout &Layout, FragmentNum Num); 98 FunctionFragment(const FunctionFragment &) = default; 99 FunctionFragment(FunctionFragment &&) = default; 100 FunctionFragment &operator=(const FunctionFragment &) = default; 101 FunctionFragment &operator=(FunctionFragment &&) = default; 102 ~FunctionFragment() = default; 103 104 public: 105 FragmentNum getFragmentNum() const { return Num; } 106 bool isMainFragment() const { 107 return getFragmentNum() == FragmentNum::main(); 108 } 109 bool isSplitFragment() const { return !isMainFragment(); } 110 111 uint64_t getAddress() const { return Address; } 112 void setAddress(uint64_t Value) { Address = Value; } 113 uint64_t getImageAddress() const { return ImageAddress; } 114 void setImageAddress(uint64_t Address) { ImageAddress = Address; } 115 uint64_t getImageSize() const { return ImageSize; } 116 void setImageSize(uint64_t Size) { ImageSize = Size; } 117 uint64_t getFileOffset() const { return FileOffset; } 118 void setFileOffset(uint64_t Offset) { FileOffset = Offset; } 119 120 unsigned size() const { return Size; }; 121 bool empty() const { return size() == 0; }; 122 iterator begin(); 123 const_iterator begin() const; 124 iterator end(); 125 const_iterator end() const; 126 BinaryBasicBlock *front() const; 127 BinaryBasicBlock *back() const; 128 129 friend class FunctionLayout; 130 }; 131 132 /// The function layout represents the fragments we split a function into and 133 /// the order of basic blocks within each fragment. 134 /// 135 /// Internally, the function layout stores blocks across fragments contiguously. 136 /// This is necessary to retain compatibility with existing code and tests that 137 /// iterate over all blocks of the layout and depend on that order. When 138 /// writing new code, avoid iterating using FunctionLayout::blocks() by 139 /// iterating either over fragments or over BinaryFunction::begin()..end(). 140 class FunctionLayout { 141 private: 142 using FragmentListType = SmallVector<FunctionFragment *, 0>; 143 using BasicBlockListType = SmallVector<BinaryBasicBlock *, 0>; 144 145 public: 146 using fragment_iterator = pointee_iterator<FragmentListType::const_iterator>; 147 using fragment_const_iterator = 148 pointee_iterator<FragmentListType::const_iterator, 149 const FunctionFragment>; 150 using block_iterator = BasicBlockListType::iterator; 151 using block_const_iterator = BasicBlockListType::const_iterator; 152 using block_reverse_iterator = std::reverse_iterator<block_iterator>; 153 using block_const_reverse_iterator = 154 std::reverse_iterator<block_const_iterator>; 155 156 private: 157 FragmentListType Fragments; 158 BasicBlockListType Blocks; 159 160 public: 161 FunctionLayout(); 162 FunctionLayout(const FunctionLayout &Other); 163 FunctionLayout(FunctionLayout &&Other); 164 FunctionLayout &operator=(const FunctionLayout &Other); 165 FunctionLayout &operator=(FunctionLayout &&Other); 166 ~FunctionLayout(); 167 168 /// Add an empty fragment. 169 FunctionFragment &addFragment(); 170 171 /// Return the fragment identified by Num. 172 FunctionFragment &getFragment(FragmentNum Num); 173 174 /// Return the fragment identified by Num. 175 const FunctionFragment &getFragment(FragmentNum Num) const; 176 177 /// Get the fragment that contains all entry blocks and other blocks that 178 /// cannot be split. 179 FunctionFragment &getMainFragment() { 180 return getFragment(FragmentNum::main()); 181 } 182 183 /// Get the fragment that contains all entry blocks and other blocks that 184 /// cannot be split. 185 const FunctionFragment &getMainFragment() const { 186 return getFragment(FragmentNum::main()); 187 } 188 189 /// Get the fragment that contains all entry blocks and other blocks that 190 /// cannot be split. 191 iterator_range<fragment_iterator> getSplitFragments() { 192 return {++fragment_begin(), fragment_end()}; 193 } 194 195 /// Get the fragment that contains all entry blocks and other blocks that 196 /// cannot be split. 197 iterator_range<fragment_const_iterator> getSplitFragments() const { 198 return {++fragment_begin(), fragment_end()}; 199 } 200 201 /// Find the fragment that contains BB. 202 const FunctionFragment &findFragment(const BinaryBasicBlock *BB) const; 203 204 /// Add BB to the end of the last fragment. 205 void addBasicBlock(BinaryBasicBlock *BB); 206 207 /// Insert range of basic blocks after InsertAfter. If InsertAfter is nullptr, 208 /// the blocks will be inserted at the start of the function. 209 void insertBasicBlocks(const BinaryBasicBlock *InsertAfter, 210 ArrayRef<BinaryBasicBlock *> NewBlocks); 211 212 /// Erase all blocks from the layout that are in ToErase. If this method 213 /// erases all blocks of a fragment, it will be removed as well. 214 void eraseBasicBlocks(const DenseSet<const BinaryBasicBlock *> ToErase); 215 216 /// Make sure fragments' and basic blocks' indices match the current layout. 217 void updateLayoutIndices() const; 218 void updateLayoutIndices(ArrayRef<BinaryBasicBlock *> Order) const; 219 220 /// Replace the current layout with NewLayout. Uses the block's 221 /// self-identifying fragment number to assign blocks to infer function 222 /// fragments. Returns `true` if the new layout is different from the current 223 /// layout. 224 bool update(ArrayRef<BinaryBasicBlock *> NewLayout); 225 226 /// Clear layout releasing memory. 227 void clear(); 228 229 BinaryBasicBlock *getBlock(unsigned Index) { return Blocks[Index]; } 230 231 const BinaryBasicBlock *getBlock(unsigned Index) const { 232 return Blocks[Index]; 233 } 234 235 /// Returns the basic block after the given basic block in the layout or 236 /// nullptr if the last basic block is given. 237 BinaryBasicBlock *getBasicBlockAfter(const BinaryBasicBlock *const BB, 238 const bool IgnoreSplits = true) { 239 return const_cast<BinaryBasicBlock *>( 240 static_cast<const FunctionLayout &>(*this).getBasicBlockAfter( 241 BB, IgnoreSplits)); 242 } 243 244 /// Returns the basic block after the given basic block in the layout or 245 /// nullptr if the last basic block is given. 246 const BinaryBasicBlock *getBasicBlockAfter(const BinaryBasicBlock *BB, 247 bool IgnoreSplits = true) const; 248 249 /// True if the layout contains at least two non-empty fragments. 250 bool isSplit() const; 251 252 /// Get the edit distance of the new layout with respect to the previous 253 /// layout after basic block reordering. 254 uint64_t 255 getEditDistance(ArrayRef<const BinaryBasicBlock *> OldBlockOrder) const; 256 257 /// True if the function is split into at most 2 fragments. Mostly used for 258 /// checking whether a function can be processed in places that do not support 259 /// multiple fragments yet. 260 bool isHotColdSplit() const { return fragment_size() <= 2; } 261 262 size_t fragment_size() const { 263 assert(Fragments.size() >= 1 && 264 "Layout should have at least one fragment."); 265 return Fragments.size(); 266 } 267 bool fragment_empty() const { return fragment_size() == 0; } 268 269 fragment_iterator fragment_begin() { return Fragments.begin(); } 270 fragment_const_iterator fragment_begin() const { return Fragments.begin(); } 271 fragment_iterator fragment_end() { return Fragments.end(); } 272 fragment_const_iterator fragment_end() const { return Fragments.end(); } 273 iterator_range<fragment_iterator> fragments() { 274 return {fragment_begin(), fragment_end()}; 275 } 276 iterator_range<fragment_const_iterator> fragments() const { 277 return {fragment_begin(), fragment_end()}; 278 } 279 280 size_t block_size() const { return Blocks.size(); } 281 bool block_empty() const { return Blocks.empty(); } 282 283 /// Required to return non-const qualified `BinaryBasicBlock *` for graph 284 /// traits. 285 BinaryBasicBlock *block_front() const { return Blocks.front(); } 286 const BinaryBasicBlock *block_back() const { return Blocks.back(); } 287 288 block_iterator block_begin() { return Blocks.begin(); } 289 block_const_iterator block_begin() const { 290 return block_const_iterator(Blocks.begin()); 291 } 292 block_iterator block_end() { return Blocks.end(); } 293 block_const_iterator block_end() const { 294 return block_const_iterator(Blocks.end()); 295 } 296 iterator_range<block_iterator> blocks() { 297 return {block_begin(), block_end()}; 298 } 299 iterator_range<block_const_iterator> blocks() const { 300 return {block_begin(), block_end()}; 301 } 302 block_reverse_iterator block_rbegin() { 303 return block_reverse_iterator(Blocks.rbegin()); 304 } 305 block_const_reverse_iterator block_rbegin() const { 306 return block_const_reverse_iterator( 307 std::make_reverse_iterator(block_end())); 308 } 309 block_reverse_iterator block_rend() { 310 return block_reverse_iterator(Blocks.rend()); 311 } 312 block_const_reverse_iterator block_rend() const { 313 return block_const_reverse_iterator( 314 std::make_reverse_iterator(block_begin())); 315 } 316 iterator_range<block_const_reverse_iterator> rblocks() const { 317 return {block_rbegin(), block_rend()}; 318 } 319 320 private: 321 block_const_iterator findBasicBlockPos(const BinaryBasicBlock *BB) const; 322 block_iterator findBasicBlockPos(const BinaryBasicBlock *BB); 323 324 friend class FunctionFragment; 325 }; 326 327 } // namespace bolt 328 } // namespace llvm 329 330 #endif 331