1 //===- bolt/Passes/SplitFunctions.h - Split function code -------*- 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 #ifndef BOLT_PASSES_SPLIT_FUNCTIONS_H 10 #define BOLT_PASSES_SPLIT_FUNCTIONS_H 11 12 #include "bolt/Core/FunctionLayout.h" 13 #include "bolt/Passes/BinaryPasses.h" 14 #include "llvm/ADT/Hashing.h" 15 #include "llvm/Support/CommandLine.h" 16 #include <atomic> 17 18 namespace llvm { 19 namespace bolt { 20 21 /// Strategy used to partition blocks into fragments. 22 enum SplitFunctionsStrategy : char { 23 /// Split each function into a hot and cold fragment using profiling 24 /// information. 25 Profile2 = 0, 26 /// Split each function into a hot, warm, and cold fragment using 27 /// profiling information. 28 CDSplit, 29 /// Split each function into a hot and cold fragment at a randomly chosen 30 /// split point (ignoring any available profiling information). 31 Random2, 32 /// Split each function into N fragments at a randomly chosen split points 33 /// (ignoring any available profiling information). 34 RandomN, 35 /// Split all basic blocks of each function into fragments such that each 36 /// fragment contains exactly a single basic block. 37 All 38 }; 39 40 class SplitStrategy { 41 public: 42 using BlockIt = BinaryFunction::BasicBlockOrderType::iterator; 43 44 virtual ~SplitStrategy() = default; 45 virtual bool canSplit(const BinaryFunction &BF) = 0; 46 virtual bool compactFragments() = 0; 47 virtual void fragment(const BlockIt Start, const BlockIt End) = 0; 48 }; 49 50 /// Split function code in multiple parts. 51 class SplitFunctions : public BinaryFunctionPass { 52 private: 53 /// Split function body into fragments. 54 void splitFunction(BinaryFunction &Function, SplitStrategy &Strategy); 55 56 struct TrampolineKey { 57 FragmentNum SourceFN = FragmentNum::main(); 58 const MCSymbol *Target = nullptr; 59 60 TrampolineKey() = default; TrampolineKeyTrampolineKey61 TrampolineKey(const FragmentNum SourceFN, const MCSymbol *const Target) 62 : SourceFN(SourceFN), Target(Target) {} 63 getEmptyKeyTrampolineKey64 static inline TrampolineKey getEmptyKey() { return TrampolineKey(); }; getTombstoneKeyTrampolineKey65 static inline TrampolineKey getTombstoneKey() { 66 return TrampolineKey(FragmentNum(UINT_MAX), nullptr); 67 }; getHashValueTrampolineKey68 static unsigned getHashValue(const TrampolineKey &Val) { 69 return llvm::hash_combine(Val.SourceFN.get(), Val.Target); 70 } isEqualTrampolineKey71 static bool isEqual(const TrampolineKey &LHS, const TrampolineKey &RHS) { 72 return LHS.SourceFN == RHS.SourceFN && LHS.Target == RHS.Target; 73 } 74 }; 75 76 /// Map basic block labels to their trampoline block labels. 77 using TrampolineSetType = 78 DenseMap<TrampolineKey, const MCSymbol *, TrampolineKey>; 79 80 using BasicBlockOrderType = BinaryFunction::BasicBlockOrderType; 81 82 /// Create trampoline landing pads for exception handling code to guarantee 83 /// that every landing pad is placed in the same function fragment as the 84 /// corresponding thrower block. The trampoline landing pad, when created, 85 /// will redirect the execution to the real landing pad in a different 86 /// fragment. 87 TrampolineSetType createEHTrampolines(BinaryFunction &Function) const; 88 89 /// Merge trampolines into \p Layout without trampolines. The merge will place 90 /// a trampoline immediately before its destination. Used to revert the effect 91 /// of trampolines after createEHTrampolines(). 92 BasicBlockOrderType 93 mergeEHTrampolines(BinaryFunction &BF, BasicBlockOrderType &Layout, 94 const TrampolineSetType &Trampolines) const; 95 96 std::atomic<uint64_t> SplitBytesHot{0ull}; 97 std::atomic<uint64_t> SplitBytesCold{0ull}; 98 99 public: SplitFunctions(const cl::opt<bool> & PrintPass)100 explicit SplitFunctions(const cl::opt<bool> &PrintPass) 101 : BinaryFunctionPass(PrintPass) {} 102 103 bool shouldOptimize(const BinaryFunction &BF) const override; 104 getName()105 const char *getName() const override { return "split-functions"; } 106 107 Error runOnFunctions(BinaryContext &BC) override; 108 }; 109 110 } // namespace bolt 111 } // namespace llvm 112 113 #endif 114