1 //===-- CFGMST.h - Minimum Spanning Tree for CFG ----------------*- C++ -*-===//
2 //
3 //                      The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file implements a Union-find algorithm to compute Minimum Spanning Tree
11 // for a given CFG.
12 //
13 //===----------------------------------------------------------------------===//
14 
15 #include "llvm/ADT/DenseMap.h"
16 #include "llvm/ADT/STLExtras.h"
17 #include "llvm/Analysis/BlockFrequencyInfo.h"
18 #include "llvm/Analysis/BranchProbabilityInfo.h"
19 #include "llvm/Analysis/CFG.h"
20 #include "llvm/Support/BranchProbability.h"
21 #include "llvm/Support/Debug.h"
22 #include "llvm/Support/raw_ostream.h"
23 #include "llvm/Transforms/Utils/BasicBlockUtils.h"
24 #include <string>
25 #include <utility>
26 #include <vector>
27 
28 namespace llvm {
29 
30 #define DEBUG_TYPE "cfgmst"
31 
32 /// \brief An union-find based Minimum Spanning Tree for CFG
33 ///
34 /// Implements a Union-find algorithm to compute Minimum Spanning Tree
35 /// for a given CFG.
36 template <class Edge, class BBInfo> class CFGMST {
37 public:
38   Function &F;
39 
40   // Store all the edges in CFG. It may contain some stale edges
41   // when Removed is set.
42   std::vector<std::unique_ptr<Edge>> AllEdges;
43 
44   // This map records the auxiliary information for each BB.
45   DenseMap<const BasicBlock *, std::unique_ptr<BBInfo>> BBInfos;
46 
47   // Find the root group of the G and compress the path from G to the root.
findAndCompressGroup(BBInfo * G)48   BBInfo *findAndCompressGroup(BBInfo *G) {
49     if (G->Group != G)
50       G->Group = findAndCompressGroup(static_cast<BBInfo *>(G->Group));
51     return static_cast<BBInfo *>(G->Group);
52   }
53 
54   // Union BB1 and BB2 into the same group and return true.
55   // Returns false if BB1 and BB2 are already in the same group.
unionGroups(const BasicBlock * BB1,const BasicBlock * BB2)56   bool unionGroups(const BasicBlock *BB1, const BasicBlock *BB2) {
57     BBInfo *BB1G = findAndCompressGroup(&getBBInfo(BB1));
58     BBInfo *BB2G = findAndCompressGroup(&getBBInfo(BB2));
59 
60     if (BB1G == BB2G)
61       return false;
62 
63     // Make the smaller rank tree a direct child or the root of high rank tree.
64     if (BB1G->Rank < BB2G->Rank)
65       BB1G->Group = BB2G;
66     else {
67       BB2G->Group = BB1G;
68       // If the ranks are the same, increment root of one tree by one.
69       if (BB1G->Rank == BB2G->Rank)
70         BB1G->Rank++;
71     }
72     return true;
73   }
74 
75   // Give BB, return the auxiliary information.
getBBInfo(const BasicBlock * BB)76   BBInfo &getBBInfo(const BasicBlock *BB) const {
77     auto It = BBInfos.find(BB);
78     assert(It->second.get() != nullptr);
79     return *It->second.get();
80   }
81 
82   // Traverse the CFG using a stack. Find all the edges and assign the weight.
83   // Edges with large weight will be put into MST first so they are less likely
84   // to be instrumented.
buildEdges()85   void buildEdges() {
86     DEBUG(dbgs() << "Build Edge on " << F.getName() << "\n");
87 
88     const BasicBlock *BB = &(F.getEntryBlock());
89     uint64_t EntryWeight = (BFI != nullptr ? BFI->getEntryFreq() : 2);
90     // Add a fake edge to the entry.
91     addEdge(nullptr, BB, EntryWeight);
92 
93     // Special handling for single BB functions.
94     if (succ_empty(BB)) {
95       addEdge(BB, nullptr, EntryWeight);
96       return;
97     }
98 
99     static const uint32_t CriticalEdgeMultiplier = 1000;
100 
101     for (Function::iterator BB = F.begin(), E = F.end(); BB != E; ++BB) {
102       TerminatorInst *TI = BB->getTerminator();
103       uint64_t BBWeight =
104           (BFI != nullptr ? BFI->getBlockFreq(&*BB).getFrequency() : 2);
105       uint64_t Weight = 2;
106       if (int successors = TI->getNumSuccessors()) {
107         for (int i = 0; i != successors; ++i) {
108           BasicBlock *TargetBB = TI->getSuccessor(i);
109           bool Critical = isCriticalEdge(TI, i);
110           uint64_t scaleFactor = BBWeight;
111           if (Critical) {
112             if (scaleFactor < UINT64_MAX / CriticalEdgeMultiplier)
113               scaleFactor *= CriticalEdgeMultiplier;
114             else
115               scaleFactor = UINT64_MAX;
116           }
117           if (BPI != nullptr)
118             Weight = BPI->getEdgeProbability(&*BB, TargetBB).scale(scaleFactor);
119           addEdge(&*BB, TargetBB, Weight).IsCritical = Critical;
120           DEBUG(dbgs() << "  Edge: from " << BB->getName() << " to "
121                        << TargetBB->getName() << "  w=" << Weight << "\n");
122         }
123       } else {
124         addEdge(&*BB, nullptr, BBWeight);
125         DEBUG(dbgs() << "  Edge: from " << BB->getName() << " to exit"
126                      << " w = " << BBWeight << "\n");
127       }
128     }
129   }
130 
131   // Sort CFG edges based on its weight.
sortEdgesByWeight()132   void sortEdgesByWeight() {
133     std::stable_sort(AllEdges.begin(), AllEdges.end(),
134                      [](const std::unique_ptr<Edge> &Edge1,
135                         const std::unique_ptr<Edge> &Edge2) {
136                        return Edge1->Weight > Edge2->Weight;
137                      });
138   }
139 
140   // Traverse all the edges and compute the Minimum Weight Spanning Tree
141   // using union-find algorithm.
computeMinimumSpanningTree()142   void computeMinimumSpanningTree() {
143     // First, put all the critical edge with landing-pad as the Dest to MST.
144     // This works around the insufficient support of critical edges split
145     // when destination BB is a landing pad.
146     for (auto &Ei : AllEdges) {
147       if (Ei->Removed)
148         continue;
149       if (Ei->IsCritical) {
150         if (Ei->DestBB && Ei->DestBB->isLandingPad()) {
151           if (unionGroups(Ei->SrcBB, Ei->DestBB))
152             Ei->InMST = true;
153         }
154       }
155     }
156 
157     for (auto &Ei : AllEdges) {
158       if (Ei->Removed)
159         continue;
160       if (unionGroups(Ei->SrcBB, Ei->DestBB))
161         Ei->InMST = true;
162     }
163   }
164 
165   // Dump the Debug information about the instrumentation.
dumpEdges(raw_ostream & OS,const Twine & Message)166   void dumpEdges(raw_ostream &OS, const Twine &Message) const {
167     if (!Message.str().empty())
168       OS << Message << "\n";
169     OS << "  Number of Basic Blocks: " << BBInfos.size() << "\n";
170     for (auto &BI : BBInfos) {
171       const BasicBlock *BB = BI.first;
172       OS << "  BB: " << (BB == nullptr ? "FakeNode" : BB->getName()) << "  "
173          << BI.second->infoString() << "\n";
174     }
175 
176     OS << "  Number of Edges: " << AllEdges.size()
177        << " (*: Instrument, C: CriticalEdge, -: Removed)\n";
178     uint32_t Count = 0;
179     for (auto &EI : AllEdges)
180       OS << "  Edge " << Count++ << ": " << getBBInfo(EI->SrcBB).Index << "-->"
181          << getBBInfo(EI->DestBB).Index << EI->infoString() << "\n";
182   }
183 
184   // Add an edge to AllEdges with weight W.
addEdge(const BasicBlock * Src,const BasicBlock * Dest,uint64_t W)185   Edge &addEdge(const BasicBlock *Src, const BasicBlock *Dest, uint64_t W) {
186     uint32_t Index = BBInfos.size();
187     auto Iter = BBInfos.end();
188     bool Inserted;
189     std::tie(Iter, Inserted) = BBInfos.insert(std::make_pair(Src, nullptr));
190     if (Inserted) {
191       // Newly inserted, update the real info.
192       Iter->second = std::move(llvm::make_unique<BBInfo>(Index));
193       Index++;
194     }
195     std::tie(Iter, Inserted) = BBInfos.insert(std::make_pair(Dest, nullptr));
196     if (Inserted)
197       // Newly inserted, update the real info.
198       Iter->second = std::move(llvm::make_unique<BBInfo>(Index));
199     AllEdges.emplace_back(new Edge(Src, Dest, W));
200     return *AllEdges.back();
201   }
202 
203   BranchProbabilityInfo *BPI;
204   BlockFrequencyInfo *BFI;
205 
206 public:
207   CFGMST(Function &Func, BranchProbabilityInfo *BPI_ = nullptr,
208          BlockFrequencyInfo *BFI_ = nullptr)
F(Func)209       : F(Func), BPI(BPI_), BFI(BFI_) {
210     buildEdges();
211     sortEdgesByWeight();
212     computeMinimumSpanningTree();
213   }
214 };
215 
216 #undef DEBUG_TYPE // "cfgmst"
217 } // end namespace llvm
218