File indexing completed on 2026-05-10 08:44:38
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #ifndef LLVM_TRANSFORMS_INSTRUMENTATION_CFGMST_H
0015 #define LLVM_TRANSFORMS_INSTRUMENTATION_CFGMST_H
0016
0017 #include "llvm/ADT/DenseMap.h"
0018 #include "llvm/ADT/STLExtras.h"
0019 #include "llvm/Analysis/BlockFrequencyInfo.h"
0020 #include "llvm/Analysis/BranchProbabilityInfo.h"
0021 #include "llvm/Analysis/CFG.h"
0022 #include "llvm/Analysis/LoopInfo.h"
0023 #include "llvm/IR/Instructions.h"
0024 #include "llvm/IR/IntrinsicInst.h"
0025 #include "llvm/Support/BranchProbability.h"
0026 #include "llvm/Support/Debug.h"
0027 #include "llvm/Support/raw_ostream.h"
0028 #include "llvm/Transforms/Utils/BasicBlockUtils.h"
0029 #include <utility>
0030 #include <vector>
0031
0032 #define DEBUG_TYPE "cfgmst"
0033
0034 namespace llvm {
0035
0036
0037
0038
0039
0040 template <class Edge, class BBInfo> class CFGMST {
0041 Function &F;
0042
0043
0044
0045 std::vector<std::unique_ptr<Edge>> AllEdges;
0046
0047
0048 DenseMap<const BasicBlock *, std::unique_ptr<BBInfo>> BBInfos;
0049
0050
0051
0052 bool ExitBlockFound = false;
0053
0054 BranchProbabilityInfo *const BPI;
0055 BlockFrequencyInfo *const BFI;
0056 LoopInfo *const LI;
0057
0058
0059 const bool InstrumentFuncEntry;
0060
0061
0062 const bool InstrumentLoopEntries;
0063
0064
0065 BBInfo *findAndCompressGroup(BBInfo *G) {
0066 if (G->Group != G)
0067 G->Group = findAndCompressGroup(static_cast<BBInfo *>(G->Group));
0068 return static_cast<BBInfo *>(G->Group);
0069 }
0070
0071
0072
0073 bool unionGroups(const BasicBlock *BB1, const BasicBlock *BB2) {
0074 BBInfo *BB1G = findAndCompressGroup(&getBBInfo(BB1));
0075 BBInfo *BB2G = findAndCompressGroup(&getBBInfo(BB2));
0076
0077 if (BB1G == BB2G)
0078 return false;
0079
0080
0081 if (BB1G->Rank < BB2G->Rank)
0082 BB1G->Group = BB2G;
0083 else {
0084 BB2G->Group = BB1G;
0085
0086 if (BB1G->Rank == BB2G->Rank)
0087 BB1G->Rank++;
0088 }
0089 return true;
0090 }
0091
0092 void handleCoroSuspendEdge(Edge *E) {
0093
0094
0095
0096
0097
0098
0099
0100
0101
0102
0103
0104
0105
0106
0107
0108 if (!E->DestBB)
0109 return;
0110 assert(E->SrcBB);
0111 if (llvm::isPresplitCoroSuspendExitEdge(*E->SrcBB, *E->DestBB))
0112 E->Removed = true;
0113 }
0114
0115
0116
0117
0118 void buildEdges() {
0119 LLVM_DEBUG(dbgs() << "Build Edge on " << F.getName() << "\n");
0120
0121 BasicBlock *Entry = &(F.getEntryBlock());
0122 uint64_t EntryWeight =
0123 (BFI != nullptr ? BFI->getEntryFreq().getFrequency() : 2);
0124
0125 if (InstrumentFuncEntry)
0126 EntryWeight = 0;
0127 Edge *EntryIncoming = nullptr, *EntryOutgoing = nullptr,
0128 *ExitOutgoing = nullptr, *ExitIncoming = nullptr;
0129 uint64_t MaxEntryOutWeight = 0, MaxExitOutWeight = 0, MaxExitInWeight = 0;
0130
0131
0132 EntryIncoming = &addEdge(nullptr, Entry, EntryWeight);
0133 LLVM_DEBUG(dbgs() << " Edge: from fake node to " << Entry->getName()
0134 << " w = " << EntryWeight << "\n");
0135
0136
0137 if (succ_empty(Entry)) {
0138 addEdge(Entry, nullptr, EntryWeight);
0139 return;
0140 }
0141
0142 static const uint32_t CriticalEdgeMultiplier = 1000;
0143
0144 for (BasicBlock &BB : F) {
0145 Instruction *TI = BB.getTerminator();
0146 uint64_t BBWeight =
0147 (BFI != nullptr ? BFI->getBlockFreq(&BB).getFrequency() : 2);
0148 uint64_t Weight = 2;
0149 if (int successors = TI->getNumSuccessors()) {
0150 for (int i = 0; i != successors; ++i) {
0151 BasicBlock *TargetBB = TI->getSuccessor(i);
0152 bool Critical = isCriticalEdge(TI, i);
0153 uint64_t scaleFactor = BBWeight;
0154 if (Critical) {
0155 if (scaleFactor < UINT64_MAX / CriticalEdgeMultiplier)
0156 scaleFactor *= CriticalEdgeMultiplier;
0157 else
0158 scaleFactor = UINT64_MAX;
0159 }
0160 if (BPI != nullptr)
0161 Weight = BPI->getEdgeProbability(&BB, TargetBB).scale(scaleFactor);
0162
0163
0164
0165
0166 if (InstrumentLoopEntries && LI->isLoopHeader(TargetBB)) {
0167 Loop *TargetLoop = LI->getLoopFor(TargetBB);
0168 assert(TargetLoop);
0169 if (!TargetLoop->contains(&BB))
0170 Weight = 0;
0171 }
0172 if (Weight == 0)
0173 Weight++;
0174 auto *E = &addEdge(&BB, TargetBB, Weight);
0175 E->IsCritical = Critical;
0176 handleCoroSuspendEdge(E);
0177 LLVM_DEBUG(dbgs() << " Edge: from " << BB.getName() << " to "
0178 << TargetBB->getName() << " w=" << Weight << "\n");
0179
0180
0181 if (&BB == Entry) {
0182 if (Weight > MaxEntryOutWeight) {
0183 MaxEntryOutWeight = Weight;
0184 EntryOutgoing = E;
0185 }
0186 }
0187
0188 auto *TargetTI = TargetBB->getTerminator();
0189 if (TargetTI && !TargetTI->getNumSuccessors()) {
0190 if (Weight > MaxExitInWeight) {
0191 MaxExitInWeight = Weight;
0192 ExitIncoming = E;
0193 }
0194 }
0195 }
0196 } else {
0197 ExitBlockFound = true;
0198 Edge *ExitO = &addEdge(&BB, nullptr, BBWeight);
0199 if (BBWeight > MaxExitOutWeight) {
0200 MaxExitOutWeight = BBWeight;
0201 ExitOutgoing = ExitO;
0202 }
0203 LLVM_DEBUG(dbgs() << " Edge: from " << BB.getName() << " to fake exit"
0204 << " w = " << BBWeight << "\n");
0205 }
0206 }
0207
0208
0209
0210
0211
0212
0213
0214
0215
0216
0217
0218 uint64_t EntryInWeight = EntryWeight;
0219
0220 if (EntryInWeight >= MaxExitOutWeight &&
0221 EntryInWeight * 2 < MaxExitOutWeight * 3) {
0222 EntryIncoming->Weight = MaxExitOutWeight;
0223 ExitOutgoing->Weight = EntryInWeight + 1;
0224 }
0225
0226 if (MaxEntryOutWeight >= MaxExitInWeight &&
0227 MaxEntryOutWeight * 2 < MaxExitInWeight * 3) {
0228 EntryOutgoing->Weight = MaxExitInWeight;
0229 ExitIncoming->Weight = MaxEntryOutWeight + 1;
0230 }
0231 }
0232
0233
0234 void sortEdgesByWeight() {
0235 llvm::stable_sort(AllEdges, [](const std::unique_ptr<Edge> &Edge1,
0236 const std::unique_ptr<Edge> &Edge2) {
0237 return Edge1->Weight > Edge2->Weight;
0238 });
0239 }
0240
0241
0242
0243 void computeMinimumSpanningTree() {
0244
0245
0246
0247 for (auto &Ei : AllEdges) {
0248 if (Ei->Removed)
0249 continue;
0250 if (Ei->IsCritical) {
0251 if (Ei->DestBB && Ei->DestBB->isLandingPad()) {
0252 if (unionGroups(Ei->SrcBB, Ei->DestBB))
0253 Ei->InMST = true;
0254 }
0255 }
0256 }
0257
0258 for (auto &Ei : AllEdges) {
0259 if (Ei->Removed)
0260 continue;
0261
0262
0263 if (!ExitBlockFound && Ei->SrcBB == nullptr)
0264 continue;
0265 if (unionGroups(Ei->SrcBB, Ei->DestBB))
0266 Ei->InMST = true;
0267 }
0268 }
0269
0270 [[maybe_unused]] bool validateLoopEntryInstrumentation() {
0271 if (!InstrumentLoopEntries)
0272 return true;
0273 for (auto &Ei : AllEdges) {
0274 if (Ei->Removed)
0275 continue;
0276 if (Ei->DestBB && LI->isLoopHeader(Ei->DestBB) &&
0277 !LI->getLoopFor(Ei->DestBB)->contains(Ei->SrcBB) && Ei->InMST)
0278 return false;
0279 }
0280 return true;
0281 }
0282
0283 public:
0284
0285 void dumpEdges(raw_ostream &OS, const Twine &Message) const {
0286 if (!Message.str().empty())
0287 OS << Message << "\n";
0288 OS << " Number of Basic Blocks: " << BBInfos.size() << "\n";
0289 for (auto &BI : BBInfos) {
0290 const BasicBlock *BB = BI.first;
0291 OS << " BB: " << (BB == nullptr ? "FakeNode" : BB->getName()) << " "
0292 << BI.second->infoString() << "\n";
0293 }
0294
0295 OS << " Number of Edges: " << AllEdges.size()
0296 << " (*: Instrument, C: CriticalEdge, -: Removed)\n";
0297 uint32_t Count = 0;
0298 for (auto &EI : AllEdges)
0299 OS << " Edge " << Count++ << ": " << getBBInfo(EI->SrcBB).Index << "-->"
0300 << getBBInfo(EI->DestBB).Index << EI->infoString() << "\n";
0301 }
0302
0303
0304 Edge &addEdge(BasicBlock *Src, BasicBlock *Dest, uint64_t W) {
0305 uint32_t Index = BBInfos.size();
0306 auto Iter = BBInfos.end();
0307 bool Inserted;
0308 std::tie(Iter, Inserted) = BBInfos.insert(std::make_pair(Src, nullptr));
0309 if (Inserted) {
0310
0311 Iter->second = std::make_unique<BBInfo>(Index);
0312 Index++;
0313 }
0314 std::tie(Iter, Inserted) = BBInfos.insert(std::make_pair(Dest, nullptr));
0315 if (Inserted)
0316
0317 Iter->second = std::make_unique<BBInfo>(Index);
0318 AllEdges.emplace_back(new Edge(Src, Dest, W));
0319 return *AllEdges.back();
0320 }
0321
0322 CFGMST(Function &Func, bool InstrumentFuncEntry, bool InstrumentLoopEntries,
0323 BranchProbabilityInfo *BPI = nullptr,
0324 BlockFrequencyInfo *BFI = nullptr, LoopInfo *LI = nullptr)
0325 : F(Func), BPI(BPI), BFI(BFI), LI(LI),
0326 InstrumentFuncEntry(InstrumentFuncEntry),
0327 InstrumentLoopEntries(InstrumentLoopEntries) {
0328 assert(!(InstrumentLoopEntries && !LI) &&
0329 "expected a LoopInfo to instrumenting loop entries");
0330 buildEdges();
0331 sortEdgesByWeight();
0332 computeMinimumSpanningTree();
0333 assert(validateLoopEntryInstrumentation() &&
0334 "Loop entries should not be in MST when "
0335 "InstrumentLoopEntries is on");
0336 if (AllEdges.size() > 1 && InstrumentFuncEntry)
0337 std::iter_swap(std::move(AllEdges.begin()),
0338 std::move(AllEdges.begin() + AllEdges.size() - 1));
0339 }
0340
0341 const std::vector<std::unique_ptr<Edge>> &allEdges() const {
0342 return AllEdges;
0343 }
0344
0345 std::vector<std::unique_ptr<Edge>> &allEdges() { return AllEdges; }
0346
0347 size_t numEdges() const { return AllEdges.size(); }
0348
0349 size_t bbInfoSize() const { return BBInfos.size(); }
0350
0351
0352 BBInfo &getBBInfo(const BasicBlock *BB) const {
0353 auto It = BBInfos.find(BB);
0354 assert(It->second.get() != nullptr);
0355 return *It->second.get();
0356 }
0357
0358
0359 BBInfo *findBBInfo(const BasicBlock *BB) const {
0360 auto It = BBInfos.find(BB);
0361 if (It == BBInfos.end())
0362 return nullptr;
0363 return It->second.get();
0364 }
0365 };
0366
0367 }
0368
0369 #undef DEBUG_TYPE
0370
0371 #endif