File indexing completed on 2026-05-10 08:44:43
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
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
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
0036 bool isEntry() const { return PredJumps.empty(); }
0037
0038
0039 bool isExit() const { return SuccJumps.empty(); }
0040 };
0041
0042
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
0053 struct FlowFunction {
0054
0055 std::vector<FlowBlock> Blocks;
0056
0057 std::vector<FlowJump> Jumps;
0058
0059 uint64_t Entry{0};
0060 };
0061
0062
0063
0064
0065 struct ProfiParams {
0066
0067 bool EvenFlowDistribution{false};
0068
0069
0070 bool RebalanceUnknown{false};
0071
0072
0073 bool JoinIslands{false};
0074
0075
0076 unsigned CostBlockInc{0};
0077
0078
0079 unsigned CostBlockDec{0};
0080
0081
0082 unsigned CostBlockZeroInc{0};
0083
0084
0085 unsigned CostBlockEntryInc{0};
0086
0087
0088 unsigned CostBlockEntryDec{0};
0089
0090
0091 unsigned CostBlockUnknownInc{0};
0092
0093
0094 unsigned CostJumpInc{0};
0095
0096
0097 unsigned CostJumpFTInc{0};
0098
0099
0100 unsigned CostJumpDec{0};
0101
0102
0103 unsigned CostJumpFTDec{0};
0104
0105
0106 unsigned CostJumpUnknownInc{0};
0107
0108
0109 unsigned CostJumpUnknownFTInc{0};
0110
0111
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
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
0135 void apply(BlockWeightMap &BlockWeights, EdgeWeightMap &EdgeWeights);
0136
0137 private:
0138
0139 FlowFunction
0140 createFlowFunction(const std::vector<const BasicBlockT *> &BasicBlocks,
0141 DenseMap<const BasicBlockT *, uint64_t> &BlockIndex);
0142
0143
0144
0145
0146 void findUnlikelyJumps(const std::vector<const BasicBlockT *> &BasicBlocks,
0147 BlockEdgeMap &Successors, FlowFunction &Func);
0148
0149
0150 bool isExit(const BasicBlockT *BB);
0151
0152
0153 const FunctionT &F;
0154
0155
0156 BlockEdgeMap &Successors;
0157
0158
0159 BlockWeightMap &SampleBlockWeights;
0160 };
0161
0162 template <typename BT>
0163 void SampleProfileInference<BT>::apply(BlockWeightMap &BlockWeights,
0164 EdgeWeightMap &EdgeWeights) {
0165
0166
0167 df_iterator_default_set<const BasicBlockT *> Reachable;
0168 for (auto *BB : depth_first_ext(&F, Reachable))
0169 (void)BB ;
0170
0171
0172
0173 df_iterator_default_set<const BasicBlockT *> InverseReachable;
0174 for (const auto &BB : F) {
0175
0176 if (isExit(&BB)) {
0177 for (auto *RBB : inverse_depth_first_ext(&BB, InverseReachable))
0178 (void)RBB;
0179 }
0180 }
0181
0182
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
0205 if (BasicBlocks.size() <= 1 || !HasSamples) {
0206 return;
0207 }
0208
0209
0210 FlowFunction Func = createFlowFunction(BasicBlocks, BlockIndex);
0211
0212
0213 applyFlowInference(Func);
0214
0215
0216
0217
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
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
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
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
0280 findUnlikelyJumps(BasicBlocks, Successors, Func);
0281
0282
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
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 }
0312 #endif