SampleProfileInference.h 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. #pragma once
  2. #ifdef __GNUC__
  3. #pragma GCC diagnostic push
  4. #pragma GCC diagnostic ignored "-Wunused-parameter"
  5. #endif
  6. //===- Transforms/Utils/SampleProfileInference.h ----------*- C++ -*-===//
  7. //
  8. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  9. // See https://llvm.org/LICENSE.txt for license information.
  10. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  11. //
  12. //===----------------------------------------------------------------------===//
  13. //
  14. /// \file
  15. /// This file provides the interface for the profile inference algorithm, profi.
  16. //
  17. //===----------------------------------------------------------------------===//
  18. #ifndef LLVM_TRANSFORMS_UTILS_SAMPLEPROFILEINFERENCE_H
  19. #define LLVM_TRANSFORMS_UTILS_SAMPLEPROFILEINFERENCE_H
  20. #include "llvm/ADT/DenseMap.h"
  21. #include "llvm/ADT/DepthFirstIterator.h"
  22. #include "llvm/ADT/SmallVector.h"
  23. #include "llvm/IR/BasicBlock.h"
  24. #include "llvm/IR/Instruction.h"
  25. #include "llvm/IR/Instructions.h"
  26. namespace llvm {
  27. class BasicBlock;
  28. class Function;
  29. class MachineBasicBlock;
  30. class MachineFunction;
  31. namespace afdo_detail {
  32. template <class BlockT> struct TypeMap {};
  33. template <> struct TypeMap<BasicBlock> {
  34. using BasicBlockT = BasicBlock;
  35. using FunctionT = Function;
  36. };
  37. template <> struct TypeMap<MachineBasicBlock> {
  38. using BasicBlockT = MachineBasicBlock;
  39. using FunctionT = MachineFunction;
  40. };
  41. } // end namespace afdo_detail
  42. struct FlowJump;
  43. /// A wrapper of a binary basic block.
  44. struct FlowBlock {
  45. uint64_t Index;
  46. uint64_t Weight{0};
  47. bool UnknownWeight{false};
  48. uint64_t Flow{0};
  49. bool HasSelfEdge{false};
  50. std::vector<FlowJump *> SuccJumps;
  51. std::vector<FlowJump *> PredJumps;
  52. /// Check if it is the entry block in the function.
  53. bool isEntry() const { return PredJumps.empty(); }
  54. /// Check if it is an exit block in the function.
  55. bool isExit() const { return SuccJumps.empty(); }
  56. };
  57. /// A wrapper of a jump between two basic blocks.
  58. struct FlowJump {
  59. uint64_t Source;
  60. uint64_t Target;
  61. uint64_t Flow{0};
  62. bool IsUnlikely{false};
  63. };
  64. /// A wrapper of binary function with basic blocks and jumps.
  65. struct FlowFunction {
  66. std::vector<FlowBlock> Blocks;
  67. std::vector<FlowJump> Jumps;
  68. /// The index of the entry block.
  69. uint64_t Entry;
  70. };
  71. void applyFlowInference(FlowFunction &Func);
  72. /// Sample profile inference pass.
  73. template <typename BT> class SampleProfileInference {
  74. public:
  75. using BasicBlockT = typename afdo_detail::TypeMap<BT>::BasicBlockT;
  76. using FunctionT = typename afdo_detail::TypeMap<BT>::FunctionT;
  77. using Edge = std::pair<const BasicBlockT *, const BasicBlockT *>;
  78. using BlockWeightMap = DenseMap<const BasicBlockT *, uint64_t>;
  79. using EdgeWeightMap = DenseMap<Edge, uint64_t>;
  80. using BlockEdgeMap =
  81. DenseMap<const BasicBlockT *, SmallVector<const BasicBlockT *, 8>>;
  82. SampleProfileInference(FunctionT &F, BlockEdgeMap &Successors,
  83. BlockWeightMap &SampleBlockWeights)
  84. : F(F), Successors(Successors), SampleBlockWeights(SampleBlockWeights) {}
  85. /// Apply the profile inference algorithm for a given function
  86. void apply(BlockWeightMap &BlockWeights, EdgeWeightMap &EdgeWeights);
  87. private:
  88. /// Try to infer branch probabilities mimicking implementation of
  89. /// BranchProbabilityInfo. Unlikely taken branches are marked so that the
  90. /// inference algorithm can avoid sending flow along corresponding edges.
  91. void findUnlikelyJumps(const std::vector<const BasicBlockT *> &BasicBlocks,
  92. BlockEdgeMap &Successors, FlowFunction &Func);
  93. /// Determine whether the block is an exit in the CFG.
  94. bool isExit(const BasicBlockT *BB);
  95. /// Function.
  96. const FunctionT &F;
  97. /// Successors for each basic block in the CFG.
  98. BlockEdgeMap &Successors;
  99. /// Map basic blocks to their sampled weights.
  100. BlockWeightMap &SampleBlockWeights;
  101. };
  102. template <typename BT>
  103. void SampleProfileInference<BT>::apply(BlockWeightMap &BlockWeights,
  104. EdgeWeightMap &EdgeWeights) {
  105. // Find all forwards reachable blocks which the inference algorithm will be
  106. // applied on.
  107. df_iterator_default_set<const BasicBlockT *> Reachable;
  108. for (auto *BB : depth_first_ext(&F, Reachable))
  109. (void)BB /* Mark all reachable blocks */;
  110. // Find all backwards reachable blocks which the inference algorithm will be
  111. // applied on.
  112. df_iterator_default_set<const BasicBlockT *> InverseReachable;
  113. for (const auto &BB : F) {
  114. // An exit block is a block without any successors.
  115. if (isExit(&BB)) {
  116. for (auto *RBB : inverse_depth_first_ext(&BB, InverseReachable))
  117. (void)RBB;
  118. }
  119. }
  120. // Keep a stable order for reachable blocks
  121. DenseMap<const BasicBlockT *, uint64_t> BlockIndex;
  122. std::vector<const BasicBlockT *> BasicBlocks;
  123. BlockIndex.reserve(Reachable.size());
  124. BasicBlocks.reserve(Reachable.size());
  125. for (const auto &BB : F) {
  126. if (Reachable.count(&BB) && InverseReachable.count(&BB)) {
  127. BlockIndex[&BB] = BasicBlocks.size();
  128. BasicBlocks.push_back(&BB);
  129. }
  130. }
  131. BlockWeights.clear();
  132. EdgeWeights.clear();
  133. bool HasSamples = false;
  134. for (const auto *BB : BasicBlocks) {
  135. auto It = SampleBlockWeights.find(BB);
  136. if (It != SampleBlockWeights.end() && It->second > 0) {
  137. HasSamples = true;
  138. BlockWeights[BB] = It->second;
  139. }
  140. }
  141. // Quit early for functions with a single block or ones w/o samples
  142. if (BasicBlocks.size() <= 1 || !HasSamples) {
  143. return;
  144. }
  145. // Create necessary objects
  146. FlowFunction Func;
  147. Func.Blocks.reserve(BasicBlocks.size());
  148. // Create FlowBlocks
  149. for (const auto *BB : BasicBlocks) {
  150. FlowBlock Block;
  151. if (SampleBlockWeights.find(BB) != SampleBlockWeights.end()) {
  152. Block.UnknownWeight = false;
  153. Block.Weight = SampleBlockWeights[BB];
  154. } else {
  155. Block.UnknownWeight = true;
  156. Block.Weight = 0;
  157. }
  158. Block.Index = Func.Blocks.size();
  159. Func.Blocks.push_back(Block);
  160. }
  161. // Create FlowEdges
  162. for (const auto *BB : BasicBlocks) {
  163. for (auto *Succ : Successors[BB]) {
  164. if (!BlockIndex.count(Succ))
  165. continue;
  166. FlowJump Jump;
  167. Jump.Source = BlockIndex[BB];
  168. Jump.Target = BlockIndex[Succ];
  169. Func.Jumps.push_back(Jump);
  170. if (BB == Succ) {
  171. Func.Blocks[BlockIndex[BB]].HasSelfEdge = true;
  172. }
  173. }
  174. }
  175. for (auto &Jump : Func.Jumps) {
  176. Func.Blocks[Jump.Source].SuccJumps.push_back(&Jump);
  177. Func.Blocks[Jump.Target].PredJumps.push_back(&Jump);
  178. }
  179. // Try to infer probabilities of jumps based on the content of basic block
  180. findUnlikelyJumps(BasicBlocks, Successors, Func);
  181. // Find the entry block
  182. for (size_t I = 0; I < Func.Blocks.size(); I++) {
  183. if (Func.Blocks[I].isEntry()) {
  184. Func.Entry = I;
  185. break;
  186. }
  187. }
  188. // Create and apply the inference network model.
  189. applyFlowInference(Func);
  190. // Extract the resulting weights from the control flow
  191. // All weights are increased by one to avoid propagation errors introduced by
  192. // zero weights.
  193. for (const auto *BB : BasicBlocks) {
  194. BlockWeights[BB] = Func.Blocks[BlockIndex[BB]].Flow;
  195. }
  196. for (auto &Jump : Func.Jumps) {
  197. Edge E = std::make_pair(BasicBlocks[Jump.Source], BasicBlocks[Jump.Target]);
  198. EdgeWeights[E] = Jump.Flow;
  199. }
  200. #ifndef NDEBUG
  201. // Unreachable blocks and edges should not have a weight.
  202. for (auto &I : BlockWeights) {
  203. assert(Reachable.contains(I.first));
  204. assert(InverseReachable.contains(I.first));
  205. }
  206. for (auto &I : EdgeWeights) {
  207. assert(Reachable.contains(I.first.first) &&
  208. Reachable.contains(I.first.second));
  209. assert(InverseReachable.contains(I.first.first) &&
  210. InverseReachable.contains(I.first.second));
  211. }
  212. #endif
  213. }
  214. template <typename BT>
  215. inline void SampleProfileInference<BT>::findUnlikelyJumps(
  216. const std::vector<const BasicBlockT *> &BasicBlocks,
  217. BlockEdgeMap &Successors, FlowFunction &Func) {}
  218. template <>
  219. inline void SampleProfileInference<BasicBlock>::findUnlikelyJumps(
  220. const std::vector<const BasicBlockT *> &BasicBlocks,
  221. BlockEdgeMap &Successors, FlowFunction &Func) {
  222. for (auto &Jump : Func.Jumps) {
  223. const auto *BB = BasicBlocks[Jump.Source];
  224. const auto *Succ = BasicBlocks[Jump.Target];
  225. const Instruction *TI = BB->getTerminator();
  226. // Check if a block ends with InvokeInst and mark non-taken branch unlikely.
  227. // In that case block Succ should be a landing pad
  228. if (Successors[BB].size() == 2 && Successors[BB].back() == Succ) {
  229. if (isa<InvokeInst>(TI)) {
  230. Jump.IsUnlikely = true;
  231. }
  232. }
  233. const Instruction *SuccTI = Succ->getTerminator();
  234. // Check if the target block contains UnreachableInst and mark it unlikely
  235. if (SuccTI->getNumSuccessors() == 0) {
  236. if (isa<UnreachableInst>(SuccTI)) {
  237. Jump.IsUnlikely = true;
  238. }
  239. }
  240. }
  241. }
  242. template <typename BT>
  243. inline bool SampleProfileInference<BT>::isExit(const BasicBlockT *BB) {
  244. return BB->succ_empty();
  245. }
  246. template <>
  247. inline bool SampleProfileInference<BasicBlock>::isExit(const BasicBlock *BB) {
  248. return succ_empty(BB);
  249. }
  250. } // end namespace llvm
  251. #endif // LLVM_TRANSFORMS_UTILS_SAMPLEPROFILEINFERENCE_H
  252. #ifdef __GNUC__
  253. #pragma GCC diagnostic pop
  254. #endif