Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:44:43

0001 //===- Transforms/Utils/SampleProfileInference.h ----------*- C++ -*-===//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 //
0009 /// \file
0010 /// This file provides the interface for the profile inference algorithm, profi.
0011 //
0012 //===----------------------------------------------------------------------===//
0013 
0014 #ifndef LLVM_TRANSFORMS_UTILS_SAMPLEPROFILEINFERENCE_H
0015 #define LLVM_TRANSFORMS_UTILS_SAMPLEPROFILEINFERENCE_H
0016 
0017 #include "llvm/ADT/DenseMap.h"
0018 #include "llvm/ADT/DepthFirstIterator.h"
0019 #include "llvm/ADT/SmallVector.h"
0020 
0021 namespace llvm {
0022 
0023 struct FlowJump;
0024 
0025 /// A wrapper of a binary basic block.
0026 struct FlowBlock {
0027   uint64_t Index;
0028   uint64_t Weight{0};
0029   bool HasUnknownWeight{true};
0030   bool IsUnlikely{false};
0031   uint64_t Flow{0};
0032   std::vector<FlowJump *> SuccJumps;
0033   std::vector<FlowJump *> PredJumps;
0034 
0035   /// Check if it is the entry block in the function.
0036   bool isEntry() const { return PredJumps.empty(); }
0037 
0038   /// Check if it is an exit block in the function.
0039   bool isExit() const { return SuccJumps.empty(); }
0040 };
0041 
0042 /// A wrapper of a jump between two basic blocks.
0043 struct FlowJump {
0044   uint64_t Source;
0045   uint64_t Target;
0046   uint64_t Weight{0};
0047   bool HasUnknownWeight{true};
0048   bool IsUnlikely{false};
0049   uint64_t Flow{0};
0050 };
0051 
0052 /// A wrapper of binary function with basic blocks and jumps.
0053 struct FlowFunction {
0054   /// Basic blocks in the function.
0055   std::vector<FlowBlock> Blocks;
0056   /// Jumps between the basic blocks.
0057   std::vector<FlowJump> Jumps;
0058   /// The index of the entry block.
0059   uint64_t Entry{0};
0060 };
0061 
0062 /// Various thresholds and options controlling the behavior of the profile
0063 /// inference algorithm. Default values are tuned for several large-scale
0064 /// applications, and can be modified via corresponding command-line flags.
0065 struct ProfiParams {
0066   /// Evenly distribute flow when there are multiple equally likely options.
0067   bool EvenFlowDistribution{false};
0068 
0069   /// Evenly re-distribute flow among unknown subgraphs.
0070   bool RebalanceUnknown{false};
0071 
0072   /// Join isolated components having positive flow.
0073   bool JoinIslands{false};
0074 
0075   /// The cost of increasing a block's count by one.
0076   unsigned CostBlockInc{0};
0077 
0078   /// The cost of decreasing a block's count by one.
0079   unsigned CostBlockDec{0};
0080 
0081   /// The cost of increasing a count of zero-weight block by one.
0082   unsigned CostBlockZeroInc{0};
0083 
0084   /// The cost of increasing the entry block's count by one.
0085   unsigned CostBlockEntryInc{0};
0086 
0087   /// The cost of decreasing the entry block's count by one.
0088   unsigned CostBlockEntryDec{0};
0089 
0090   /// The cost of increasing an unknown block's count by one.
0091   unsigned CostBlockUnknownInc{0};
0092 
0093   /// The cost of increasing a jump's count by one.
0094   unsigned CostJumpInc{0};
0095 
0096   /// The cost of increasing a fall-through jump's count by one.
0097   unsigned CostJumpFTInc{0};
0098 
0099   /// The cost of decreasing a jump's count by one.
0100   unsigned CostJumpDec{0};
0101 
0102   /// The cost of decreasing a fall-through jump's count by one.
0103   unsigned CostJumpFTDec{0};
0104 
0105   /// The cost of increasing an unknown jump's count by one.
0106   unsigned CostJumpUnknownInc{0};
0107 
0108   /// The cost of increasing an unknown fall-through jump's count by one.
0109   unsigned CostJumpUnknownFTInc{0};
0110 
0111   /// The cost of taking an unlikely block/jump.
0112   const int64_t CostUnlikely = ((int64_t)1) << 30;
0113 };
0114 
0115 void applyFlowInference(const ProfiParams &Params, FlowFunction &Func);
0116 void applyFlowInference(FlowFunction &Func);
0117 
0118 /// Sample profile inference pass.
0119 template <typename FT> class SampleProfileInference {
0120 public:
0121   using NodeRef = typename GraphTraits<FT *>::NodeRef;
0122   using BasicBlockT = std::remove_pointer_t<NodeRef>;
0123   using FunctionT = FT;
0124   using Edge = std::pair<const BasicBlockT *, const BasicBlockT *>;
0125   using BlockWeightMap = DenseMap<const BasicBlockT *, uint64_t>;
0126   using EdgeWeightMap = DenseMap<Edge, uint64_t>;
0127   using BlockEdgeMap =
0128       DenseMap<const BasicBlockT *, SmallVector<const BasicBlockT *, 8>>;
0129 
0130   SampleProfileInference(FunctionT &F, BlockEdgeMap &Successors,
0131                          BlockWeightMap &SampleBlockWeights)
0132       : F(F), Successors(Successors), SampleBlockWeights(SampleBlockWeights) {}
0133 
0134   /// Apply the profile inference algorithm for a given function
0135   void apply(BlockWeightMap &BlockWeights, EdgeWeightMap &EdgeWeights);
0136 
0137 private:
0138   /// Initialize flow function blocks, jumps and misc metadata.
0139   FlowFunction
0140   createFlowFunction(const std::vector<const BasicBlockT *> &BasicBlocks,
0141                      DenseMap<const BasicBlockT *, uint64_t> &BlockIndex);
0142 
0143   /// Try to infer branch probabilities mimicking implementation of
0144   /// BranchProbabilityInfo. Unlikely taken branches are marked so that the
0145   /// inference algorithm can avoid sending flow along corresponding edges.
0146   void findUnlikelyJumps(const std::vector<const BasicBlockT *> &BasicBlocks,
0147                          BlockEdgeMap &Successors, FlowFunction &Func);
0148 
0149   /// Determine whether the block is an exit in the CFG.
0150   bool isExit(const BasicBlockT *BB);
0151 
0152   /// Function.
0153   const FunctionT &F;
0154 
0155   /// Successors for each basic block in the CFG.
0156   BlockEdgeMap &Successors;
0157 
0158   /// Map basic blocks to their sampled weights.
0159   BlockWeightMap &SampleBlockWeights;
0160 };
0161 
0162 template <typename BT>
0163 void SampleProfileInference<BT>::apply(BlockWeightMap &BlockWeights,
0164                                        EdgeWeightMap &EdgeWeights) {
0165   // Find all forwards reachable blocks which the inference algorithm will be
0166   // applied on.
0167   df_iterator_default_set<const BasicBlockT *> Reachable;
0168   for (auto *BB : depth_first_ext(&F, Reachable))
0169     (void)BB /* Mark all reachable blocks */;
0170 
0171   // Find all backwards reachable blocks which the inference algorithm will be
0172   // applied on.
0173   df_iterator_default_set<const BasicBlockT *> InverseReachable;
0174   for (const auto &BB : F) {
0175     // An exit block is a block without any successors.
0176     if (isExit(&BB)) {
0177       for (auto *RBB : inverse_depth_first_ext(&BB, InverseReachable))
0178         (void)RBB;
0179     }
0180   }
0181 
0182   // Keep a stable order for reachable blocks
0183   DenseMap<const BasicBlockT *, uint64_t> BlockIndex;
0184   std::vector<const BasicBlockT *> BasicBlocks;
0185   BlockIndex.reserve(Reachable.size());
0186   BasicBlocks.reserve(Reachable.size());
0187   for (const auto &BB : F) {
0188     if (Reachable.count(&BB) && InverseReachable.count(&BB)) {
0189       BlockIndex[&BB] = BasicBlocks.size();
0190       BasicBlocks.push_back(&BB);
0191     }
0192   }
0193 
0194   BlockWeights.clear();
0195   EdgeWeights.clear();
0196   bool HasSamples = false;
0197   for (const auto *BB : BasicBlocks) {
0198     auto It = SampleBlockWeights.find(BB);
0199     if (It != SampleBlockWeights.end() && It->second > 0) {
0200       HasSamples = true;
0201       BlockWeights[BB] = It->second;
0202     }
0203   }
0204   // Quit early for functions with a single block or ones w/o samples
0205   if (BasicBlocks.size() <= 1 || !HasSamples) {
0206     return;
0207   }
0208 
0209   // Create necessary objects
0210   FlowFunction Func = createFlowFunction(BasicBlocks, BlockIndex);
0211 
0212   // Create and apply the inference network model.
0213   applyFlowInference(Func);
0214 
0215   // Extract the resulting weights from the control flow
0216   // All weights are increased by one to avoid propagation errors introduced by
0217   // zero weights.
0218   for (const auto *BB : BasicBlocks) {
0219     BlockWeights[BB] = Func.Blocks[BlockIndex[BB]].Flow;
0220   }
0221   for (auto &Jump : Func.Jumps) {
0222     Edge E = std::make_pair(BasicBlocks[Jump.Source], BasicBlocks[Jump.Target]);
0223     EdgeWeights[E] = Jump.Flow;
0224   }
0225 
0226 #ifndef NDEBUG
0227   // Unreachable blocks and edges should not have a weight.
0228   for (auto &I : BlockWeights) {
0229     assert(Reachable.contains(I.first));
0230     assert(InverseReachable.contains(I.first));
0231   }
0232   for (auto &I : EdgeWeights) {
0233     assert(Reachable.contains(I.first.first) &&
0234            Reachable.contains(I.first.second));
0235     assert(InverseReachable.contains(I.first.first) &&
0236            InverseReachable.contains(I.first.second));
0237   }
0238 #endif
0239 }
0240 
0241 template <typename BT>
0242 FlowFunction SampleProfileInference<BT>::createFlowFunction(
0243     const std::vector<const BasicBlockT *> &BasicBlocks,
0244     DenseMap<const BasicBlockT *, uint64_t> &BlockIndex) {
0245   FlowFunction Func;
0246   Func.Blocks.reserve(BasicBlocks.size());
0247   // Create FlowBlocks
0248   for (const auto *BB : BasicBlocks) {
0249     FlowBlock Block;
0250     auto It = SampleBlockWeights.find(BB);
0251     if (It != SampleBlockWeights.end()) {
0252       Block.HasUnknownWeight = false;
0253       Block.Weight = It->second;
0254     } else {
0255       Block.HasUnknownWeight = true;
0256       Block.Weight = 0;
0257     }
0258     Block.Index = Func.Blocks.size();
0259     Func.Blocks.push_back(Block);
0260   }
0261   // Create FlowEdges
0262   for (const auto *BB : BasicBlocks) {
0263     for (auto *Succ : Successors[BB]) {
0264       if (!BlockIndex.count(Succ))
0265         continue;
0266       FlowJump Jump;
0267       Jump.Source = BlockIndex[BB];
0268       Jump.Target = BlockIndex[Succ];
0269       Func.Jumps.push_back(Jump);
0270     }
0271   }
0272   for (auto &Jump : Func.Jumps) {
0273     uint64_t Src = Jump.Source;
0274     uint64_t Dst = Jump.Target;
0275     Func.Blocks[Src].SuccJumps.push_back(&Jump);
0276     Func.Blocks[Dst].PredJumps.push_back(&Jump);
0277   }
0278 
0279   // Try to infer probabilities of jumps based on the content of basic block
0280   findUnlikelyJumps(BasicBlocks, Successors, Func);
0281 
0282   // Find the entry block
0283   for (size_t I = 0; I < Func.Blocks.size(); I++) {
0284     if (Func.Blocks[I].isEntry()) {
0285       Func.Entry = I;
0286       break;
0287     }
0288   }
0289   assert(Func.Entry == 0 && "incorrect index of the entry block");
0290 
0291   // Pre-process data: make sure the entry weight is at least 1
0292   auto &EntryBlock = Func.Blocks[Func.Entry];
0293   if (EntryBlock.Weight == 0 && !EntryBlock.HasUnknownWeight) {
0294     EntryBlock.Weight = 1;
0295     EntryBlock.HasUnknownWeight = false;
0296   }
0297 
0298   return Func;
0299 }
0300 
0301 template <typename BT>
0302 inline void SampleProfileInference<BT>::findUnlikelyJumps(
0303     const std::vector<const BasicBlockT *> &BasicBlocks,
0304     BlockEdgeMap &Successors, FlowFunction &Func) {}
0305 
0306 template <typename BT>
0307 inline bool SampleProfileInference<BT>::isExit(const BasicBlockT *BB) {
0308   return BB->succ_empty();
0309 }
0310 
0311 } // end namespace llvm
0312 #endif // LLVM_TRANSFORMS_UTILS_SAMPLEPROFILEINFERENCE_H