File indexing completed on 2026-05-10 08:44:44
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015 #ifndef LLVM_TRANSFORMS_UTILS_SAMPLEPROFILELOADERBASEIMPL_H
0016 #define LLVM_TRANSFORMS_UTILS_SAMPLEPROFILELOADERBASEIMPL_H
0017
0018 #include "llvm/ADT/ArrayRef.h"
0019 #include "llvm/ADT/DenseMap.h"
0020 #include "llvm/ADT/DenseSet.h"
0021 #include "llvm/ADT/IntrusiveRefCntPtr.h"
0022 #include "llvm/ADT/SmallPtrSet.h"
0023 #include "llvm/ADT/SmallSet.h"
0024 #include "llvm/ADT/SmallVector.h"
0025 #include "llvm/Analysis/LazyCallGraph.h"
0026 #include "llvm/Analysis/LoopInfo.h"
0027 #include "llvm/Analysis/OptimizationRemarkEmitter.h"
0028 #include "llvm/Analysis/PostDominators.h"
0029 #include "llvm/IR/BasicBlock.h"
0030 #include "llvm/IR/CFG.h"
0031 #include "llvm/IR/DebugInfoMetadata.h"
0032 #include "llvm/IR/DebugLoc.h"
0033 #include "llvm/IR/Dominators.h"
0034 #include "llvm/IR/Function.h"
0035 #include "llvm/IR/Instruction.h"
0036 #include "llvm/IR/Instructions.h"
0037 #include "llvm/IR/Module.h"
0038 #include "llvm/IR/PseudoProbe.h"
0039 #include "llvm/ProfileData/SampleProf.h"
0040 #include "llvm/ProfileData/SampleProfReader.h"
0041 #include "llvm/Support/CommandLine.h"
0042 #include "llvm/Support/GenericDomTree.h"
0043 #include "llvm/Support/raw_ostream.h"
0044 #include "llvm/Transforms/Utils/SampleProfileInference.h"
0045 #include "llvm/Transforms/Utils/SampleProfileLoaderBaseUtil.h"
0046
0047 namespace llvm {
0048 using namespace sampleprof;
0049 using namespace sampleprofutil;
0050 using ProfileCount = Function::ProfileCount;
0051
0052 namespace vfs {
0053 class FileSystem;
0054 }
0055
0056 #define DEBUG_TYPE "sample-profile-impl"
0057
0058 namespace afdo_detail {
0059
0060 template <typename BlockT> struct IRTraits;
0061 template <> struct IRTraits<BasicBlock> {
0062 using InstructionT = Instruction;
0063 using BasicBlockT = BasicBlock;
0064 using FunctionT = Function;
0065 using BlockFrequencyInfoT = BlockFrequencyInfo;
0066 using LoopT = Loop;
0067 using LoopInfoPtrT = std::unique_ptr<LoopInfo>;
0068 using DominatorTreePtrT = std::unique_ptr<DominatorTree>;
0069 using PostDominatorTreeT = PostDominatorTree;
0070 using PostDominatorTreePtrT = std::unique_ptr<PostDominatorTree>;
0071 using OptRemarkEmitterT = OptimizationRemarkEmitter;
0072 using OptRemarkAnalysisT = OptimizationRemarkAnalysis;
0073 using PredRangeT = pred_range;
0074 using SuccRangeT = succ_range;
0075 static Function &getFunction(Function &F) { return F; }
0076 static const BasicBlock *getEntryBB(const Function *F) {
0077 return &F->getEntryBlock();
0078 }
0079 static pred_range getPredecessors(BasicBlock *BB) { return predecessors(BB); }
0080 static succ_range getSuccessors(BasicBlock *BB) { return successors(BB); }
0081 };
0082
0083 }
0084
0085
0086
0087
0088 class PseudoProbeManager {
0089 DenseMap<uint64_t, PseudoProbeDescriptor> GUIDToProbeDescMap;
0090
0091 public:
0092 PseudoProbeManager(const Module &M) {
0093 if (NamedMDNode *FuncInfo =
0094 M.getNamedMetadata(PseudoProbeDescMetadataName)) {
0095 for (const auto *Operand : FuncInfo->operands()) {
0096 const auto *MD = cast<MDNode>(Operand);
0097 auto GUID = mdconst::dyn_extract<ConstantInt>(MD->getOperand(0))
0098 ->getZExtValue();
0099 auto Hash = mdconst::dyn_extract<ConstantInt>(MD->getOperand(1))
0100 ->getZExtValue();
0101 GUIDToProbeDescMap.try_emplace(GUID, PseudoProbeDescriptor(GUID, Hash));
0102 }
0103 }
0104 }
0105
0106 const PseudoProbeDescriptor *getDesc(uint64_t GUID) const {
0107 auto I = GUIDToProbeDescMap.find(GUID);
0108 return I == GUIDToProbeDescMap.end() ? nullptr : &I->second;
0109 }
0110
0111 const PseudoProbeDescriptor *getDesc(StringRef FProfileName) const {
0112 return getDesc(Function::getGUID(FProfileName));
0113 }
0114
0115 const PseudoProbeDescriptor *getDesc(const Function &F) const {
0116 return getDesc(Function::getGUID(FunctionSamples::getCanonicalFnName(F)));
0117 }
0118
0119 bool profileIsHashMismatched(const PseudoProbeDescriptor &FuncDesc,
0120 const FunctionSamples &Samples) const {
0121 return FuncDesc.getFunctionHash() != Samples.getFunctionHash();
0122 }
0123
0124 bool moduleIsProbed(const Module &M) const {
0125 return M.getNamedMetadata(PseudoProbeDescMetadataName);
0126 }
0127
0128 bool profileIsValid(const Function &F, const FunctionSamples &Samples) const {
0129 const auto *Desc = getDesc(F);
0130 bool IsAvailableExternallyLinkage =
0131 GlobalValue::isAvailableExternallyLinkage(F.getLinkage());
0132
0133
0134
0135
0136
0137
0138
0139
0140
0141
0142
0143
0144 if (IsAvailableExternallyLinkage || !Desc)
0145 return !F.hasFnAttribute("profile-checksum-mismatch");
0146
0147 return Desc && !profileIsHashMismatched(*Desc, Samples);
0148 }
0149 };
0150
0151
0152
0153 extern cl::opt<bool> SampleProfileUseProfi;
0154
0155 static inline bool skipProfileForFunction(const Function &F) {
0156 return F.isDeclaration() || !F.hasFnAttribute("use-sample-profile");
0157 }
0158
0159 static inline void
0160 buildTopDownFuncOrder(LazyCallGraph &CG,
0161 std::vector<Function *> &FunctionOrderList) {
0162 CG.buildRefSCCs();
0163 for (LazyCallGraph::RefSCC &RC : CG.postorder_ref_sccs()) {
0164 for (LazyCallGraph::SCC &C : RC) {
0165 for (LazyCallGraph::Node &N : C) {
0166 Function &F = N.getFunction();
0167 if (!skipProfileForFunction(F))
0168 FunctionOrderList.push_back(&F);
0169 }
0170 }
0171 }
0172 std::reverse(FunctionOrderList.begin(), FunctionOrderList.end());
0173 }
0174
0175 template <typename FT> class SampleProfileLoaderBaseImpl {
0176 public:
0177 SampleProfileLoaderBaseImpl(std::string Name, std::string RemapName,
0178 IntrusiveRefCntPtr<vfs::FileSystem> FS)
0179 : Filename(Name), RemappingFilename(RemapName), FS(std::move(FS)) {}
0180 void dump() { Reader->dump(); }
0181
0182 using NodeRef = typename GraphTraits<FT *>::NodeRef;
0183 using BT = std::remove_pointer_t<NodeRef>;
0184 using InstructionT = typename afdo_detail::IRTraits<BT>::InstructionT;
0185 using BasicBlockT = typename afdo_detail::IRTraits<BT>::BasicBlockT;
0186 using BlockFrequencyInfoT =
0187 typename afdo_detail::IRTraits<BT>::BlockFrequencyInfoT;
0188 using FunctionT = typename afdo_detail::IRTraits<BT>::FunctionT;
0189 using LoopT = typename afdo_detail::IRTraits<BT>::LoopT;
0190 using LoopInfoPtrT = typename afdo_detail::IRTraits<BT>::LoopInfoPtrT;
0191 using DominatorTreePtrT =
0192 typename afdo_detail::IRTraits<BT>::DominatorTreePtrT;
0193 using PostDominatorTreePtrT =
0194 typename afdo_detail::IRTraits<BT>::PostDominatorTreePtrT;
0195 using PostDominatorTreeT =
0196 typename afdo_detail::IRTraits<BT>::PostDominatorTreeT;
0197 using OptRemarkEmitterT =
0198 typename afdo_detail::IRTraits<BT>::OptRemarkEmitterT;
0199 using OptRemarkAnalysisT =
0200 typename afdo_detail::IRTraits<BT>::OptRemarkAnalysisT;
0201 using PredRangeT = typename afdo_detail::IRTraits<BT>::PredRangeT;
0202 using SuccRangeT = typename afdo_detail::IRTraits<BT>::SuccRangeT;
0203
0204 using BlockWeightMap = DenseMap<const BasicBlockT *, uint64_t>;
0205 using EquivalenceClassMap =
0206 DenseMap<const BasicBlockT *, const BasicBlockT *>;
0207 using Edge = std::pair<const BasicBlockT *, const BasicBlockT *>;
0208 using EdgeWeightMap = DenseMap<Edge, uint64_t>;
0209 using BlockEdgeMap =
0210 DenseMap<const BasicBlockT *, SmallVector<const BasicBlockT *, 8>>;
0211
0212 protected:
0213 ~SampleProfileLoaderBaseImpl() = default;
0214 friend class SampleCoverageTracker;
0215
0216 Function &getFunction(FunctionT &F) {
0217 return afdo_detail::IRTraits<BT>::getFunction(F);
0218 }
0219 const BasicBlockT *getEntryBB(const FunctionT *F) {
0220 return afdo_detail::IRTraits<BT>::getEntryBB(F);
0221 }
0222 PredRangeT getPredecessors(BasicBlockT *BB) {
0223 return afdo_detail::IRTraits<BT>::getPredecessors(BB);
0224 }
0225 SuccRangeT getSuccessors(BasicBlockT *BB) {
0226 return afdo_detail::IRTraits<BT>::getSuccessors(BB);
0227 }
0228
0229 unsigned getFunctionLoc(FunctionT &Func);
0230 virtual ErrorOr<uint64_t> getInstWeight(const InstructionT &Inst);
0231 ErrorOr<uint64_t> getInstWeightImpl(const InstructionT &Inst);
0232 virtual ErrorOr<uint64_t> getProbeWeight(const InstructionT &Inst);
0233 ErrorOr<uint64_t> getBlockWeight(const BasicBlockT *BB);
0234 mutable DenseMap<const DILocation *, const FunctionSamples *>
0235 DILocation2SampleMap;
0236 virtual const FunctionSamples *
0237 findFunctionSamples(const InstructionT &I) const;
0238 void printEdgeWeight(raw_ostream &OS, Edge E);
0239 void printBlockWeight(raw_ostream &OS, const BasicBlockT *BB) const;
0240 void printBlockEquivalence(raw_ostream &OS, const BasicBlockT *BB);
0241 bool computeBlockWeights(FunctionT &F);
0242 void findEquivalenceClasses(FunctionT &F);
0243 void findEquivalencesFor(BasicBlockT *BB1,
0244 ArrayRef<BasicBlockT *> Descendants,
0245 PostDominatorTreeT *DomTree);
0246 void propagateWeights(FunctionT &F);
0247 void applyProfi(FunctionT &F, BlockEdgeMap &Successors,
0248 BlockWeightMap &SampleBlockWeights,
0249 BlockWeightMap &BlockWeights, EdgeWeightMap &EdgeWeights);
0250 uint64_t visitEdge(Edge E, unsigned *NumUnknownEdges, Edge *UnknownEdge);
0251 void buildEdges(FunctionT &F);
0252 bool propagateThroughEdges(FunctionT &F, bool UpdateBlockCount);
0253 void clearFunctionData(bool ResetDT = true);
0254 void computeDominanceAndLoopInfo(FunctionT &F);
0255 bool
0256 computeAndPropagateWeights(FunctionT &F,
0257 const DenseSet<GlobalValue::GUID> &InlinedGUIDs);
0258 void initWeightPropagation(FunctionT &F,
0259 const DenseSet<GlobalValue::GUID> &InlinedGUIDs);
0260 void
0261 finalizeWeightPropagation(FunctionT &F,
0262 const DenseSet<GlobalValue::GUID> &InlinedGUIDs);
0263 void emitCoverageRemarks(FunctionT &F);
0264
0265
0266
0267
0268
0269 BlockWeightMap BlockWeights;
0270
0271
0272
0273
0274
0275 EdgeWeightMap EdgeWeights;
0276
0277
0278 SmallPtrSet<const BasicBlockT *, 32> VisitedBlocks;
0279
0280
0281 SmallSet<Edge, 32> VisitedEdges;
0282
0283
0284
0285
0286
0287
0288
0289 EquivalenceClassMap EquivalenceClass;
0290
0291
0292 DominatorTreePtrT DT;
0293 PostDominatorTreePtrT PDT;
0294 LoopInfoPtrT LI;
0295
0296
0297 BlockEdgeMap Predecessors;
0298
0299
0300 BlockEdgeMap Successors;
0301
0302
0303 SampleCoverageTracker CoverageTracker;
0304
0305
0306 std::unique_ptr<SampleProfileReader> Reader;
0307
0308
0309
0310
0311 std::map<SampleContext, FunctionSamples> OutlineFunctionSamples;
0312
0313
0314 std::unique_ptr<PseudoProbeManager> ProbeManager;
0315
0316
0317 FunctionSamples *Samples = nullptr;
0318
0319
0320 std::string Filename;
0321
0322
0323 std::string RemappingFilename;
0324
0325
0326 IntrusiveRefCntPtr<vfs::FileSystem> FS;
0327
0328
0329 ProfileSummaryInfo *PSI = nullptr;
0330
0331
0332 OptRemarkEmitterT *ORE = nullptr;
0333 };
0334
0335
0336 template <typename BT>
0337 void SampleProfileLoaderBaseImpl<BT>::clearFunctionData(bool ResetDT) {
0338 BlockWeights.clear();
0339 EdgeWeights.clear();
0340 VisitedBlocks.clear();
0341 VisitedEdges.clear();
0342 EquivalenceClass.clear();
0343 if (ResetDT) {
0344 DT = nullptr;
0345 PDT = nullptr;
0346 LI = nullptr;
0347 }
0348 Predecessors.clear();
0349 Successors.clear();
0350 CoverageTracker.clear();
0351 }
0352
0353 #ifndef NDEBUG
0354
0355
0356
0357
0358 template <typename BT>
0359 void SampleProfileLoaderBaseImpl<BT>::printEdgeWeight(raw_ostream &OS, Edge E) {
0360 OS << "weight[" << E.first->getName() << "->" << E.second->getName()
0361 << "]: " << EdgeWeights[E] << "\n";
0362 }
0363
0364
0365
0366
0367
0368 template <typename BT>
0369 void SampleProfileLoaderBaseImpl<BT>::printBlockEquivalence(
0370 raw_ostream &OS, const BasicBlockT *BB) {
0371 const BasicBlockT *Equiv = EquivalenceClass[BB];
0372 OS << "equivalence[" << BB->getName()
0373 << "]: " << ((Equiv) ? EquivalenceClass[BB]->getName() : "NONE") << "\n";
0374 }
0375
0376
0377
0378
0379
0380 template <typename BT>
0381 void SampleProfileLoaderBaseImpl<BT>::printBlockWeight(
0382 raw_ostream &OS, const BasicBlockT *BB) const {
0383 const auto &I = BlockWeights.find(BB);
0384 uint64_t W = (I == BlockWeights.end() ? 0 : I->second);
0385 OS << "weight[" << BB->getName() << "]: " << W << "\n";
0386 }
0387 #endif
0388
0389
0390
0391
0392
0393
0394
0395
0396
0397
0398
0399
0400 template <typename BT>
0401 ErrorOr<uint64_t>
0402 SampleProfileLoaderBaseImpl<BT>::getInstWeight(const InstructionT &Inst) {
0403 if (FunctionSamples::ProfileIsProbeBased)
0404 return getProbeWeight(Inst);
0405 return getInstWeightImpl(Inst);
0406 }
0407
0408 template <typename BT>
0409 ErrorOr<uint64_t>
0410 SampleProfileLoaderBaseImpl<BT>::getInstWeightImpl(const InstructionT &Inst) {
0411 const FunctionSamples *FS = findFunctionSamples(Inst);
0412 if (!FS)
0413 return std::error_code();
0414
0415 const DebugLoc &DLoc = Inst.getDebugLoc();
0416 if (!DLoc)
0417 return std::error_code();
0418
0419 const DILocation *DIL = DLoc;
0420 uint32_t LineOffset = FunctionSamples::getOffset(DIL);
0421 uint32_t Discriminator;
0422 if (EnableFSDiscriminator)
0423 Discriminator = DIL->getDiscriminator();
0424 else
0425 Discriminator = DIL->getBaseDiscriminator();
0426
0427 ErrorOr<uint64_t> R = FS->findSamplesAt(LineOffset, Discriminator);
0428 if (R) {
0429 bool FirstMark =
0430 CoverageTracker.markSamplesUsed(FS, LineOffset, Discriminator, R.get());
0431 if (FirstMark) {
0432 ORE->emit([&]() {
0433 OptRemarkAnalysisT Remark(DEBUG_TYPE, "AppliedSamples", &Inst);
0434 Remark << "Applied " << ore::NV("NumSamples", *R);
0435 Remark << " samples from profile (offset: ";
0436 Remark << ore::NV("LineOffset", LineOffset);
0437 if (Discriminator) {
0438 Remark << ".";
0439 Remark << ore::NV("Discriminator", Discriminator);
0440 }
0441 Remark << ")";
0442 return Remark;
0443 });
0444 }
0445 LLVM_DEBUG(dbgs() << " " << DLoc.getLine() << "." << Discriminator << ":"
0446 << Inst << " (line offset: " << LineOffset << "."
0447 << Discriminator << " - weight: " << R.get() << ")\n");
0448 }
0449 return R;
0450 }
0451
0452 template <typename BT>
0453 ErrorOr<uint64_t>
0454 SampleProfileLoaderBaseImpl<BT>::getProbeWeight(const InstructionT &Inst) {
0455 assert(FunctionSamples::ProfileIsProbeBased &&
0456 "Profile is not pseudo probe based");
0457 std::optional<PseudoProbe> Probe = extractProbe(Inst);
0458
0459
0460 if (!Probe)
0461 return std::error_code();
0462
0463 const FunctionSamples *FS = findFunctionSamples(Inst);
0464 if (!FS) {
0465
0466
0467
0468
0469 return std::error_code();
0470 }
0471
0472 auto R = FS->findSamplesAt(Probe->Id, Probe->Discriminator);
0473 if (R) {
0474 uint64_t Samples = R.get() * Probe->Factor;
0475 bool FirstMark = CoverageTracker.markSamplesUsed(FS, Probe->Id, 0, Samples);
0476 if (FirstMark) {
0477 ORE->emit([&]() {
0478 OptRemarkAnalysisT Remark(DEBUG_TYPE, "AppliedSamples", &Inst);
0479 Remark << "Applied " << ore::NV("NumSamples", Samples);
0480 Remark << " samples from profile (ProbeId=";
0481 Remark << ore::NV("ProbeId", Probe->Id);
0482 if (Probe->Discriminator) {
0483 Remark << ".";
0484 Remark << ore::NV("Discriminator", Probe->Discriminator);
0485 }
0486 Remark << ", Factor=";
0487 Remark << ore::NV("Factor", Probe->Factor);
0488 Remark << ", OriginalSamples=";
0489 Remark << ore::NV("OriginalSamples", R.get());
0490 Remark << ")";
0491 return Remark;
0492 });
0493 }
0494 LLVM_DEBUG({dbgs() << " " << Probe->Id;
0495 if (Probe->Discriminator)
0496 dbgs() << "." << Probe->Discriminator;
0497 dbgs() << ":" << Inst << " - weight: " << R.get()
0498 << " - factor: " << format("%0.2f", Probe->Factor) << ")\n";});
0499 return Samples;
0500 }
0501 return R;
0502 }
0503
0504
0505
0506
0507
0508
0509
0510
0511
0512 template <typename BT>
0513 ErrorOr<uint64_t>
0514 SampleProfileLoaderBaseImpl<BT>::getBlockWeight(const BasicBlockT *BB) {
0515 uint64_t Max = 0;
0516 bool HasWeight = false;
0517 for (auto &I : *BB) {
0518 const ErrorOr<uint64_t> &R = getInstWeight(I);
0519 if (R) {
0520 Max = std::max(Max, R.get());
0521 HasWeight = true;
0522 }
0523 }
0524 return HasWeight ? ErrorOr<uint64_t>(Max) : std::error_code();
0525 }
0526
0527
0528
0529
0530
0531
0532
0533 template <typename BT>
0534 bool SampleProfileLoaderBaseImpl<BT>::computeBlockWeights(FunctionT &F) {
0535 bool Changed = false;
0536 LLVM_DEBUG(dbgs() << "Block weights\n");
0537 for (const auto &BB : F) {
0538 ErrorOr<uint64_t> Weight = getBlockWeight(&BB);
0539 if (Weight) {
0540 BlockWeights[&BB] = Weight.get();
0541 VisitedBlocks.insert(&BB);
0542 Changed = true;
0543 }
0544 LLVM_DEBUG(printBlockWeight(dbgs(), &BB));
0545 }
0546
0547 return Changed;
0548 }
0549
0550
0551
0552
0553
0554
0555
0556
0557
0558
0559 template <typename BT>
0560 const FunctionSamples *SampleProfileLoaderBaseImpl<BT>::findFunctionSamples(
0561 const InstructionT &Inst) const {
0562 const DILocation *DIL = Inst.getDebugLoc();
0563 if (!DIL)
0564 return Samples;
0565
0566 auto it = DILocation2SampleMap.try_emplace(DIL, nullptr);
0567 if (it.second) {
0568 it.first->second = Samples->findFunctionSamples(DIL, Reader->getRemapper());
0569 }
0570 return it.first->second;
0571 }
0572
0573
0574
0575
0576
0577
0578
0579
0580
0581
0582
0583
0584
0585
0586
0587
0588
0589
0590
0591
0592
0593
0594
0595
0596 template <typename BT>
0597 void SampleProfileLoaderBaseImpl<BT>::findEquivalencesFor(
0598 BasicBlockT *BB1, ArrayRef<BasicBlockT *> Descendants,
0599 PostDominatorTreeT *DomTree) {
0600 const BasicBlockT *EC = EquivalenceClass[BB1];
0601 uint64_t Weight = BlockWeights[EC];
0602 for (const auto *BB2 : Descendants) {
0603 bool IsDomParent = DomTree->dominates(BB2, BB1);
0604 bool IsInSameLoop = LI->getLoopFor(BB1) == LI->getLoopFor(BB2);
0605 if (BB1 != BB2 && IsDomParent && IsInSameLoop) {
0606 EquivalenceClass[BB2] = EC;
0607
0608 if (VisitedBlocks.count(BB2)) {
0609 VisitedBlocks.insert(EC);
0610 }
0611
0612
0613
0614
0615
0616
0617
0618
0619
0620 Weight = std::max(Weight, BlockWeights[BB2]);
0621 }
0622 }
0623 const BasicBlockT *EntryBB = getEntryBB(EC->getParent());
0624 if (EC == EntryBB) {
0625 BlockWeights[EC] = Samples->getHeadSamples() + 1;
0626 } else {
0627 BlockWeights[EC] = Weight;
0628 }
0629 }
0630
0631
0632
0633
0634
0635
0636
0637
0638
0639
0640 template <typename BT>
0641 void SampleProfileLoaderBaseImpl<BT>::findEquivalenceClasses(FunctionT &F) {
0642 SmallVector<BasicBlockT *, 8> DominatedBBs;
0643 LLVM_DEBUG(dbgs() << "\nBlock equivalence classes\n");
0644
0645 for (auto &BB : F) {
0646 BasicBlockT *BB1 = &BB;
0647
0648
0649 if (EquivalenceClass.count(BB1)) {
0650 LLVM_DEBUG(printBlockEquivalence(dbgs(), BB1));
0651 continue;
0652 }
0653
0654
0655 EquivalenceClass[BB1] = BB1;
0656
0657
0658
0659
0660
0661
0662
0663
0664
0665
0666
0667 DominatedBBs.clear();
0668 DT->getDescendants(BB1, DominatedBBs);
0669 findEquivalencesFor(BB1, DominatedBBs, &*PDT);
0670
0671 LLVM_DEBUG(printBlockEquivalence(dbgs(), BB1));
0672 }
0673
0674
0675
0676
0677
0678
0679
0680 LLVM_DEBUG(
0681 dbgs() << "\nAssign the same weight to all blocks in the same class\n");
0682 for (auto &BI : F) {
0683 const BasicBlockT *BB = &BI;
0684 const BasicBlockT *EquivBB = EquivalenceClass[BB];
0685 if (BB != EquivBB)
0686 BlockWeights[BB] = BlockWeights[EquivBB];
0687 LLVM_DEBUG(printBlockWeight(dbgs(), BB));
0688 }
0689 }
0690
0691
0692
0693
0694
0695
0696
0697
0698
0699
0700
0701 template <typename BT>
0702 uint64_t SampleProfileLoaderBaseImpl<BT>::visitEdge(Edge E,
0703 unsigned *NumUnknownEdges,
0704 Edge *UnknownEdge) {
0705 if (!VisitedEdges.count(E)) {
0706 (*NumUnknownEdges)++;
0707 *UnknownEdge = E;
0708 return 0;
0709 }
0710
0711 return EdgeWeights[E];
0712 }
0713
0714
0715
0716
0717
0718
0719
0720
0721
0722
0723
0724
0725
0726
0727 template <typename BT>
0728 bool SampleProfileLoaderBaseImpl<BT>::propagateThroughEdges(
0729 FunctionT &F, bool UpdateBlockCount) {
0730 bool Changed = false;
0731 LLVM_DEBUG(dbgs() << "\nPropagation through edges\n");
0732 for (const auto &BI : F) {
0733 const BasicBlockT *BB = &BI;
0734 const BasicBlockT *EC = EquivalenceClass[BB];
0735
0736
0737
0738
0739
0740
0741 for (unsigned i = 0; i < 2; i++) {
0742 uint64_t TotalWeight = 0;
0743 unsigned NumUnknownEdges = 0, NumTotalEdges = 0;
0744 Edge UnknownEdge, SelfReferentialEdge, SingleEdge;
0745
0746 if (i == 0) {
0747
0748 NumTotalEdges = Predecessors[BB].size();
0749 for (auto *Pred : Predecessors[BB]) {
0750 Edge E = std::make_pair(Pred, BB);
0751 TotalWeight += visitEdge(E, &NumUnknownEdges, &UnknownEdge);
0752 if (E.first == E.second)
0753 SelfReferentialEdge = E;
0754 }
0755 if (NumTotalEdges == 1) {
0756 SingleEdge = std::make_pair(Predecessors[BB][0], BB);
0757 }
0758 } else {
0759
0760 NumTotalEdges = Successors[BB].size();
0761 for (auto *Succ : Successors[BB]) {
0762 Edge E = std::make_pair(BB, Succ);
0763 TotalWeight += visitEdge(E, &NumUnknownEdges, &UnknownEdge);
0764 }
0765 if (NumTotalEdges == 1) {
0766 SingleEdge = std::make_pair(BB, Successors[BB][0]);
0767 }
0768 }
0769
0770
0771
0772
0773
0774
0775
0776
0777
0778
0779
0780
0781
0782
0783
0784
0785
0786
0787
0788
0789
0790
0791
0792
0793 if (NumUnknownEdges <= 1) {
0794 uint64_t &BBWeight = BlockWeights[EC];
0795 if (NumUnknownEdges == 0) {
0796 if (!VisitedBlocks.count(EC)) {
0797
0798
0799
0800 if (TotalWeight > BBWeight) {
0801 BBWeight = TotalWeight;
0802 Changed = true;
0803 LLVM_DEBUG(dbgs() << "All edge weights for " << BB->getName()
0804 << " known. Set weight for block: ";
0805 printBlockWeight(dbgs(), BB););
0806 }
0807 } else if (NumTotalEdges == 1 &&
0808 EdgeWeights[SingleEdge] < BlockWeights[EC]) {
0809
0810
0811 EdgeWeights[SingleEdge] = BlockWeights[EC];
0812 Changed = true;
0813 }
0814 } else if (NumUnknownEdges == 1 && VisitedBlocks.count(EC)) {
0815
0816
0817 if (BBWeight >= TotalWeight)
0818 EdgeWeights[UnknownEdge] = BBWeight - TotalWeight;
0819 else
0820 EdgeWeights[UnknownEdge] = 0;
0821 const BasicBlockT *OtherEC;
0822 if (i == 0)
0823 OtherEC = EquivalenceClass[UnknownEdge.first];
0824 else
0825 OtherEC = EquivalenceClass[UnknownEdge.second];
0826
0827 if (VisitedBlocks.count(OtherEC) &&
0828 EdgeWeights[UnknownEdge] > BlockWeights[OtherEC])
0829 EdgeWeights[UnknownEdge] = BlockWeights[OtherEC];
0830 VisitedEdges.insert(UnknownEdge);
0831 Changed = true;
0832 LLVM_DEBUG(dbgs() << "Set weight for edge: ";
0833 printEdgeWeight(dbgs(), UnknownEdge));
0834 }
0835 } else if (VisitedBlocks.count(EC) && BlockWeights[EC] == 0) {
0836
0837 if (i == 0) {
0838 for (auto *Pred : Predecessors[BB]) {
0839 Edge E = std::make_pair(Pred, BB);
0840 EdgeWeights[E] = 0;
0841 VisitedEdges.insert(E);
0842 }
0843 } else {
0844 for (auto *Succ : Successors[BB]) {
0845 Edge E = std::make_pair(BB, Succ);
0846 EdgeWeights[E] = 0;
0847 VisitedEdges.insert(E);
0848 }
0849 }
0850 } else if (SelfReferentialEdge.first && VisitedBlocks.count(EC)) {
0851 uint64_t &BBWeight = BlockWeights[BB];
0852
0853 if (BBWeight >= TotalWeight)
0854 EdgeWeights[SelfReferentialEdge] = BBWeight - TotalWeight;
0855 else
0856 EdgeWeights[SelfReferentialEdge] = 0;
0857 VisitedEdges.insert(SelfReferentialEdge);
0858 Changed = true;
0859 LLVM_DEBUG(dbgs() << "Set self-referential edge weight to: ";
0860 printEdgeWeight(dbgs(), SelfReferentialEdge));
0861 }
0862 if (UpdateBlockCount && TotalWeight > 0 &&
0863 VisitedBlocks.insert(EC).second) {
0864 BlockWeights[EC] = TotalWeight;
0865 Changed = true;
0866 }
0867 }
0868 }
0869
0870 return Changed;
0871 }
0872
0873
0874
0875
0876
0877 template <typename BT>
0878 void SampleProfileLoaderBaseImpl<BT>::buildEdges(FunctionT &F) {
0879 for (auto &BI : F) {
0880 BasicBlockT *B1 = &BI;
0881
0882
0883 SmallPtrSet<BasicBlockT *, 16> Visited;
0884 if (!Predecessors[B1].empty())
0885 llvm_unreachable("Found a stale predecessors list in a basic block.");
0886 for (auto *B2 : getPredecessors(B1))
0887 if (Visited.insert(B2).second)
0888 Predecessors[B1].push_back(B2);
0889
0890
0891 Visited.clear();
0892 if (!Successors[B1].empty())
0893 llvm_unreachable("Found a stale successors list in a basic block.");
0894 for (auto *B2 : getSuccessors(B1))
0895 if (Visited.insert(B2).second)
0896 Successors[B1].push_back(B2);
0897 }
0898 }
0899
0900
0901
0902
0903
0904
0905
0906
0907
0908
0909
0910
0911
0912
0913
0914
0915
0916
0917 template <typename BT>
0918 void SampleProfileLoaderBaseImpl<BT>::propagateWeights(FunctionT &F) {
0919
0920
0921 if (SampleProfileUseProfi) {
0922
0923 BlockWeightMap SampleBlockWeights;
0924 for (const auto &BI : F) {
0925 ErrorOr<uint64_t> Weight = getBlockWeight(&BI);
0926 if (Weight)
0927 SampleBlockWeights[&BI] = Weight.get();
0928 }
0929
0930 applyProfi(F, Successors, SampleBlockWeights, BlockWeights, EdgeWeights);
0931 } else {
0932 bool Changed = true;
0933 unsigned I = 0;
0934
0935
0936
0937 for (auto &BI : F) {
0938 BasicBlockT *BB = &BI;
0939 LoopT *L = LI->getLoopFor(BB);
0940 if (!L) {
0941 continue;
0942 }
0943 BasicBlockT *Header = L->getHeader();
0944 if (Header && BlockWeights[BB] > BlockWeights[Header]) {
0945 BlockWeights[Header] = BlockWeights[BB];
0946 }
0947 }
0948
0949
0950 while (Changed && I++ < SampleProfileMaxPropagateIterations) {
0951 Changed = propagateThroughEdges(F, false);
0952 }
0953
0954
0955
0956
0957 VisitedEdges.clear();
0958 Changed = true;
0959 while (Changed && I++ < SampleProfileMaxPropagateIterations) {
0960 Changed = propagateThroughEdges(F, false);
0961 }
0962
0963
0964
0965 Changed = true;
0966 while (Changed && I++ < SampleProfileMaxPropagateIterations) {
0967 Changed = propagateThroughEdges(F, true);
0968 }
0969 }
0970 }
0971
0972 template <typename FT>
0973 void SampleProfileLoaderBaseImpl<FT>::applyProfi(
0974 FunctionT &F, BlockEdgeMap &Successors, BlockWeightMap &SampleBlockWeights,
0975 BlockWeightMap &BlockWeights, EdgeWeightMap &EdgeWeights) {
0976 auto Infer = SampleProfileInference<FT>(F, Successors, SampleBlockWeights);
0977 Infer.apply(BlockWeights, EdgeWeights);
0978 }
0979
0980
0981
0982
0983
0984
0985
0986
0987
0988
0989
0990
0991
0992
0993
0994
0995
0996
0997
0998
0999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026 template <typename BT>
1027 bool SampleProfileLoaderBaseImpl<BT>::computeAndPropagateWeights(
1028 FunctionT &F, const DenseSet<GlobalValue::GUID> &InlinedGUIDs) {
1029 bool Changed = (InlinedGUIDs.size() != 0);
1030
1031
1032 Changed |= computeBlockWeights(F);
1033
1034 if (Changed) {
1035
1036 initWeightPropagation(F, InlinedGUIDs);
1037
1038
1039 propagateWeights(F);
1040
1041
1042 finalizeWeightPropagation(F, InlinedGUIDs);
1043 }
1044
1045 return Changed;
1046 }
1047
1048 template <typename BT>
1049 void SampleProfileLoaderBaseImpl<BT>::initWeightPropagation(
1050 FunctionT &F, const DenseSet<GlobalValue::GUID> &InlinedGUIDs) {
1051
1052
1053
1054
1055
1056 getFunction(F).setEntryCount(
1057 ProfileCount(Samples->getHeadSamples() + 1, Function::PCT_Real),
1058 &InlinedGUIDs);
1059
1060 if (!SampleProfileUseProfi) {
1061
1062 computeDominanceAndLoopInfo(F);
1063
1064
1065 findEquivalenceClasses(F);
1066 }
1067
1068
1069
1070
1071
1072
1073 buildEdges(F);
1074 }
1075
1076 template <typename BT>
1077 void SampleProfileLoaderBaseImpl<BT>::finalizeWeightPropagation(
1078 FunctionT &F, const DenseSet<GlobalValue::GUID> &InlinedGUIDs) {
1079
1080
1081
1082
1083
1084
1085 if (SampleProfileUseProfi) {
1086 const BasicBlockT *EntryBB = getEntryBB(&F);
1087 ErrorOr<uint64_t> EntryWeight = getBlockWeight(EntryBB);
1088 if (BlockWeights[EntryBB] > 0) {
1089 getFunction(F).setEntryCount(
1090 ProfileCount(BlockWeights[EntryBB], Function::PCT_Real),
1091 &InlinedGUIDs);
1092 }
1093 }
1094 }
1095
1096 template <typename BT>
1097 void SampleProfileLoaderBaseImpl<BT>::emitCoverageRemarks(FunctionT &F) {
1098
1099 const Function &Func = getFunction(F);
1100 if (SampleProfileRecordCoverage) {
1101 unsigned Used = CoverageTracker.countUsedRecords(Samples, PSI);
1102 unsigned Total = CoverageTracker.countBodyRecords(Samples, PSI);
1103 unsigned Coverage = CoverageTracker.computeCoverage(Used, Total);
1104 if (Coverage < SampleProfileRecordCoverage) {
1105 Func.getContext().diagnose(DiagnosticInfoSampleProfile(
1106 Func.getSubprogram()->getFilename(), getFunctionLoc(F),
1107 Twine(Used) + " of " + Twine(Total) + " available profile records (" +
1108 Twine(Coverage) + "%) were applied",
1109 DS_Warning));
1110 }
1111 }
1112
1113 if (SampleProfileSampleCoverage) {
1114 uint64_t Used = CoverageTracker.getTotalUsedSamples();
1115 uint64_t Total = CoverageTracker.countBodySamples(Samples, PSI);
1116 unsigned Coverage = CoverageTracker.computeCoverage(Used, Total);
1117 if (Coverage < SampleProfileSampleCoverage) {
1118 Func.getContext().diagnose(DiagnosticInfoSampleProfile(
1119 Func.getSubprogram()->getFilename(), getFunctionLoc(F),
1120 Twine(Used) + " of " + Twine(Total) + " available profile samples (" +
1121 Twine(Coverage) + "%) were applied",
1122 DS_Warning));
1123 }
1124 }
1125 }
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138 template <typename BT>
1139 unsigned SampleProfileLoaderBaseImpl<BT>::getFunctionLoc(FunctionT &F) {
1140 const Function &Func = getFunction(F);
1141 if (DISubprogram *S = Func.getSubprogram())
1142 return S->getLine();
1143
1144 if (NoWarnSampleUnused)
1145 return 0;
1146
1147
1148
1149 Func.getContext().diagnose(DiagnosticInfoSampleProfile(
1150 "No debug information found in function " + Func.getName() +
1151 ": Function profile not used",
1152 DS_Warning));
1153 return 0;
1154 }
1155
1156 #undef DEBUG_TYPE
1157
1158 }
1159 #endif