xref: /llvm-project/llvm/lib/Transforms/Instrumentation/BlockCoverageInference.cpp (revision 167e8f8b6b11db304b485b40403034497df69036)
1*167e8f8bSEllis Hoag //===-- BlockCoverageInference.cpp - Minimal Execution Coverage -*- C++ -*-===//
2*167e8f8bSEllis Hoag //
3*167e8f8bSEllis Hoag // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*167e8f8bSEllis Hoag // See https://llvm.org/LICENSE.txt for license information.
5*167e8f8bSEllis Hoag // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*167e8f8bSEllis Hoag //
7*167e8f8bSEllis Hoag //===----------------------------------------------------------------------===//
8*167e8f8bSEllis Hoag //
9*167e8f8bSEllis Hoag // Our algorithm works by first identifying a subset of nodes that must always
10*167e8f8bSEllis Hoag // be instrumented. We call these nodes ambiguous because knowing the coverage
11*167e8f8bSEllis Hoag // of all remaining nodes is not enough to infer their coverage status.
12*167e8f8bSEllis Hoag //
13*167e8f8bSEllis Hoag // In general a node v is ambiguous if there exists two entry-to-terminal paths
14*167e8f8bSEllis Hoag // P_1 and P_2 such that:
15*167e8f8bSEllis Hoag //   1. v not in P_1 but P_1 visits a predecessor of v, and
16*167e8f8bSEllis Hoag //   2. v not in P_2 but P_2 visits a successor of v.
17*167e8f8bSEllis Hoag //
18*167e8f8bSEllis Hoag // If a node v is not ambiguous, then if condition 1 fails, we can infer v’s
19*167e8f8bSEllis Hoag // coverage from the coverage of its predecessors, or if condition 2 fails, we
20*167e8f8bSEllis Hoag // can infer v’s coverage from the coverage of its successors.
21*167e8f8bSEllis Hoag //
22*167e8f8bSEllis Hoag // Sadly, there are example CFGs where it is not possible to infer all nodes
23*167e8f8bSEllis Hoag // from the ambiguous nodes alone. Our algorithm selects a minimum number of
24*167e8f8bSEllis Hoag // extra nodes to add to the ambiguous nodes to form a valid instrumentation S.
25*167e8f8bSEllis Hoag //
26*167e8f8bSEllis Hoag // Details on this algorithm can be found in https://arxiv.org/abs/2208.13907
27*167e8f8bSEllis Hoag //
28*167e8f8bSEllis Hoag //===----------------------------------------------------------------------===//
29*167e8f8bSEllis Hoag 
30*167e8f8bSEllis Hoag #include "llvm/Transforms/Instrumentation/BlockCoverageInference.h"
31*167e8f8bSEllis Hoag #include "llvm/ADT/DepthFirstIterator.h"
32*167e8f8bSEllis Hoag #include "llvm/ADT/Statistic.h"
33*167e8f8bSEllis Hoag #include "llvm/Support/CRC.h"
34*167e8f8bSEllis Hoag #include "llvm/Support/Debug.h"
35*167e8f8bSEllis Hoag #include "llvm/Support/GraphWriter.h"
36*167e8f8bSEllis Hoag #include "llvm/Support/raw_ostream.h"
37*167e8f8bSEllis Hoag #include "llvm/Transforms/Utils/BasicBlockUtils.h"
38*167e8f8bSEllis Hoag 
39*167e8f8bSEllis Hoag using namespace llvm;
40*167e8f8bSEllis Hoag 
41*167e8f8bSEllis Hoag #define DEBUG_TYPE "pgo-block-coverage"
42*167e8f8bSEllis Hoag 
43*167e8f8bSEllis Hoag STATISTIC(NumFunctions, "Number of total functions that BCI has processed");
44*167e8f8bSEllis Hoag STATISTIC(NumIneligibleFunctions,
45*167e8f8bSEllis Hoag           "Number of functions for which BCI cannot run on");
46*167e8f8bSEllis Hoag STATISTIC(NumBlocks, "Number of total basic blocks that BCI has processed");
47*167e8f8bSEllis Hoag STATISTIC(NumInstrumentedBlocks,
48*167e8f8bSEllis Hoag           "Number of basic blocks instrumented for coverage");
49*167e8f8bSEllis Hoag 
BlockCoverageInference(const Function & F,bool ForceInstrumentEntry)50*167e8f8bSEllis Hoag BlockCoverageInference::BlockCoverageInference(const Function &F,
51*167e8f8bSEllis Hoag                                                bool ForceInstrumentEntry)
52*167e8f8bSEllis Hoag     : F(F), ForceInstrumentEntry(ForceInstrumentEntry) {
53*167e8f8bSEllis Hoag   findDependencies();
54*167e8f8bSEllis Hoag   assert(!ForceInstrumentEntry || shouldInstrumentBlock(F.getEntryBlock()));
55*167e8f8bSEllis Hoag 
56*167e8f8bSEllis Hoag   ++NumFunctions;
57*167e8f8bSEllis Hoag   for (auto &BB : F) {
58*167e8f8bSEllis Hoag     ++NumBlocks;
59*167e8f8bSEllis Hoag     if (shouldInstrumentBlock(BB))
60*167e8f8bSEllis Hoag       ++NumInstrumentedBlocks;
61*167e8f8bSEllis Hoag   }
62*167e8f8bSEllis Hoag }
63*167e8f8bSEllis Hoag 
64*167e8f8bSEllis Hoag BlockCoverageInference::BlockSet
getDependencies(const BasicBlock & BB) const65*167e8f8bSEllis Hoag BlockCoverageInference::getDependencies(const BasicBlock &BB) const {
66*167e8f8bSEllis Hoag   assert(BB.getParent() == &F);
67*167e8f8bSEllis Hoag   BlockSet Dependencies;
68*167e8f8bSEllis Hoag   auto It = PredecessorDependencies.find(&BB);
69*167e8f8bSEllis Hoag   if (It != PredecessorDependencies.end())
70*167e8f8bSEllis Hoag     Dependencies.set_union(It->second);
71*167e8f8bSEllis Hoag   It = SuccessorDependencies.find(&BB);
72*167e8f8bSEllis Hoag   if (It != SuccessorDependencies.end())
73*167e8f8bSEllis Hoag     Dependencies.set_union(It->second);
74*167e8f8bSEllis Hoag   return Dependencies;
75*167e8f8bSEllis Hoag }
76*167e8f8bSEllis Hoag 
getInstrumentedBlocksHash() const77*167e8f8bSEllis Hoag uint64_t BlockCoverageInference::getInstrumentedBlocksHash() const {
78*167e8f8bSEllis Hoag   JamCRC JC;
79*167e8f8bSEllis Hoag   uint64_t Index = 0;
80*167e8f8bSEllis Hoag   for (auto &BB : F) {
81*167e8f8bSEllis Hoag     if (shouldInstrumentBlock(BB)) {
82*167e8f8bSEllis Hoag       uint8_t Data[8];
83*167e8f8bSEllis Hoag       support::endian::write64le(Data, Index);
84*167e8f8bSEllis Hoag       JC.update(Data);
85*167e8f8bSEllis Hoag     }
86*167e8f8bSEllis Hoag     Index++;
87*167e8f8bSEllis Hoag   }
88*167e8f8bSEllis Hoag   return JC.getCRC();
89*167e8f8bSEllis Hoag }
90*167e8f8bSEllis Hoag 
shouldInstrumentBlock(const BasicBlock & BB) const91*167e8f8bSEllis Hoag bool BlockCoverageInference::shouldInstrumentBlock(const BasicBlock &BB) const {
92*167e8f8bSEllis Hoag   assert(BB.getParent() == &F);
93*167e8f8bSEllis Hoag   auto It = PredecessorDependencies.find(&BB);
94*167e8f8bSEllis Hoag   if (It != PredecessorDependencies.end() && It->second.size())
95*167e8f8bSEllis Hoag     return false;
96*167e8f8bSEllis Hoag   It = SuccessorDependencies.find(&BB);
97*167e8f8bSEllis Hoag   if (It != SuccessorDependencies.end() && It->second.size())
98*167e8f8bSEllis Hoag     return false;
99*167e8f8bSEllis Hoag   return true;
100*167e8f8bSEllis Hoag }
101*167e8f8bSEllis Hoag 
findDependencies()102*167e8f8bSEllis Hoag void BlockCoverageInference::findDependencies() {
103*167e8f8bSEllis Hoag   assert(PredecessorDependencies.empty() && SuccessorDependencies.empty());
104*167e8f8bSEllis Hoag   // Empirical analysis shows that this algorithm finishes within 5 seconds for
105*167e8f8bSEllis Hoag   // functions with fewer than 1.5K blocks.
106*167e8f8bSEllis Hoag   if (F.hasFnAttribute(Attribute::NoReturn) || F.size() > 1500) {
107*167e8f8bSEllis Hoag     ++NumIneligibleFunctions;
108*167e8f8bSEllis Hoag     return;
109*167e8f8bSEllis Hoag   }
110*167e8f8bSEllis Hoag 
111*167e8f8bSEllis Hoag   SmallVector<const BasicBlock *, 4> TerminalBlocks;
112*167e8f8bSEllis Hoag   for (auto &BB : F)
113*167e8f8bSEllis Hoag     if (succ_empty(&BB))
114*167e8f8bSEllis Hoag       TerminalBlocks.push_back(&BB);
115*167e8f8bSEllis Hoag 
116*167e8f8bSEllis Hoag   // Traverse the CFG backwards from the terminal blocks to make sure every
117*167e8f8bSEllis Hoag   // block can reach some terminal block. Otherwise this algorithm will not work
118*167e8f8bSEllis Hoag   // and we must fall back to instrumenting every block.
119*167e8f8bSEllis Hoag   df_iterator_default_set<const BasicBlock *> Visited;
120*167e8f8bSEllis Hoag   for (auto *BB : TerminalBlocks)
121*167e8f8bSEllis Hoag     for (auto *N : inverse_depth_first_ext(BB, Visited))
122*167e8f8bSEllis Hoag       (void)N;
123*167e8f8bSEllis Hoag   if (F.size() != Visited.size()) {
124*167e8f8bSEllis Hoag     ++NumIneligibleFunctions;
125*167e8f8bSEllis Hoag     return;
126*167e8f8bSEllis Hoag   }
127*167e8f8bSEllis Hoag 
128*167e8f8bSEllis Hoag   // The current implementation for computing `PredecessorDependencies` and
129*167e8f8bSEllis Hoag   // `SuccessorDependencies` runs in quadratic time with respect to the number
130*167e8f8bSEllis Hoag   // of basic blocks. While we do have a more complicated linear time algorithm
131*167e8f8bSEllis Hoag   // in https://arxiv.org/abs/2208.13907 we do not know if it will give a
132*167e8f8bSEllis Hoag   // significant speedup in practice given that most functions tend to be
133*167e8f8bSEllis Hoag   // relatively small in size for intended use cases.
134*167e8f8bSEllis Hoag   auto &EntryBlock = F.getEntryBlock();
135*167e8f8bSEllis Hoag   for (auto &BB : F) {
136*167e8f8bSEllis Hoag     // The set of blocks that are reachable while avoiding BB.
137*167e8f8bSEllis Hoag     BlockSet ReachableFromEntry, ReachableFromTerminal;
138*167e8f8bSEllis Hoag     getReachableAvoiding(EntryBlock, BB, /*IsForward=*/true,
139*167e8f8bSEllis Hoag                          ReachableFromEntry);
140*167e8f8bSEllis Hoag     for (auto *TerminalBlock : TerminalBlocks)
141*167e8f8bSEllis Hoag       getReachableAvoiding(*TerminalBlock, BB, /*IsForward=*/false,
142*167e8f8bSEllis Hoag                            ReachableFromTerminal);
143*167e8f8bSEllis Hoag 
144*167e8f8bSEllis Hoag     auto Preds = predecessors(&BB);
145*167e8f8bSEllis Hoag     bool HasSuperReachablePred = llvm::any_of(Preds, [&](auto *Pred) {
146*167e8f8bSEllis Hoag       return ReachableFromEntry.count(Pred) &&
147*167e8f8bSEllis Hoag              ReachableFromTerminal.count(Pred);
148*167e8f8bSEllis Hoag     });
149*167e8f8bSEllis Hoag     if (!HasSuperReachablePred)
150*167e8f8bSEllis Hoag       for (auto *Pred : Preds)
151*167e8f8bSEllis Hoag         if (ReachableFromEntry.count(Pred))
152*167e8f8bSEllis Hoag           PredecessorDependencies[&BB].insert(Pred);
153*167e8f8bSEllis Hoag 
154*167e8f8bSEllis Hoag     auto Succs = successors(&BB);
155*167e8f8bSEllis Hoag     bool HasSuperReachableSucc = llvm::any_of(Succs, [&](auto *Succ) {
156*167e8f8bSEllis Hoag       return ReachableFromEntry.count(Succ) &&
157*167e8f8bSEllis Hoag              ReachableFromTerminal.count(Succ);
158*167e8f8bSEllis Hoag     });
159*167e8f8bSEllis Hoag     if (!HasSuperReachableSucc)
160*167e8f8bSEllis Hoag       for (auto *Succ : Succs)
161*167e8f8bSEllis Hoag         if (ReachableFromTerminal.count(Succ))
162*167e8f8bSEllis Hoag           SuccessorDependencies[&BB].insert(Succ);
163*167e8f8bSEllis Hoag   }
164*167e8f8bSEllis Hoag 
165*167e8f8bSEllis Hoag   if (ForceInstrumentEntry) {
166*167e8f8bSEllis Hoag     // Force the entry block to be instrumented by clearing the blocks it can
167*167e8f8bSEllis Hoag     // infer coverage from.
168*167e8f8bSEllis Hoag     PredecessorDependencies[&EntryBlock].clear();
169*167e8f8bSEllis Hoag     SuccessorDependencies[&EntryBlock].clear();
170*167e8f8bSEllis Hoag   }
171*167e8f8bSEllis Hoag 
172*167e8f8bSEllis Hoag   // Construct a graph where blocks are connected if there is a mutual
173*167e8f8bSEllis Hoag   // dependency between them. This graph has a special property that it contains
174*167e8f8bSEllis Hoag   // only paths.
175*167e8f8bSEllis Hoag   DenseMap<const BasicBlock *, BlockSet> AdjacencyList;
176*167e8f8bSEllis Hoag   for (auto &BB : F) {
177*167e8f8bSEllis Hoag     for (auto *Succ : successors(&BB)) {
178*167e8f8bSEllis Hoag       if (SuccessorDependencies[&BB].count(Succ) &&
179*167e8f8bSEllis Hoag           PredecessorDependencies[Succ].count(&BB)) {
180*167e8f8bSEllis Hoag         AdjacencyList[&BB].insert(Succ);
181*167e8f8bSEllis Hoag         AdjacencyList[Succ].insert(&BB);
182*167e8f8bSEllis Hoag       }
183*167e8f8bSEllis Hoag     }
184*167e8f8bSEllis Hoag   }
185*167e8f8bSEllis Hoag 
186*167e8f8bSEllis Hoag   // Given a path with at least one node, return the next node on the path.
187*167e8f8bSEllis Hoag   auto getNextOnPath = [&](BlockSet &Path) -> const BasicBlock * {
188*167e8f8bSEllis Hoag     assert(Path.size());
189*167e8f8bSEllis Hoag     auto &Neighbors = AdjacencyList[Path.back()];
190*167e8f8bSEllis Hoag     if (Path.size() == 1) {
191*167e8f8bSEllis Hoag       // This is the first node on the path, return its neighbor.
192*167e8f8bSEllis Hoag       assert(Neighbors.size() == 1);
193*167e8f8bSEllis Hoag       return Neighbors.front();
194*167e8f8bSEllis Hoag     } else if (Neighbors.size() == 2) {
195*167e8f8bSEllis Hoag       // This is the middle of the path, find the neighbor that is not on the
196*167e8f8bSEllis Hoag       // path already.
197*167e8f8bSEllis Hoag       assert(Path.size() >= 2);
198*167e8f8bSEllis Hoag       return Path.count(Neighbors[0]) ? Neighbors[1] : Neighbors[0];
199*167e8f8bSEllis Hoag     }
200*167e8f8bSEllis Hoag     // This is the end of the path.
201*167e8f8bSEllis Hoag     assert(Neighbors.size() == 1);
202*167e8f8bSEllis Hoag     return nullptr;
203*167e8f8bSEllis Hoag   };
204*167e8f8bSEllis Hoag 
205*167e8f8bSEllis Hoag   // Remove all cycles in the inferencing graph.
206*167e8f8bSEllis Hoag   for (auto &BB : F) {
207*167e8f8bSEllis Hoag     if (AdjacencyList[&BB].size() == 1) {
208*167e8f8bSEllis Hoag       // We found the head of some path.
209*167e8f8bSEllis Hoag       BlockSet Path;
210*167e8f8bSEllis Hoag       Path.insert(&BB);
211*167e8f8bSEllis Hoag       while (const BasicBlock *Next = getNextOnPath(Path))
212*167e8f8bSEllis Hoag         Path.insert(Next);
213*167e8f8bSEllis Hoag       LLVM_DEBUG(dbgs() << "Found path: " << getBlockNames(Path) << "\n");
214*167e8f8bSEllis Hoag 
215*167e8f8bSEllis Hoag       // Remove these nodes from the graph so we don't discover this path again.
216*167e8f8bSEllis Hoag       for (auto *BB : Path)
217*167e8f8bSEllis Hoag         AdjacencyList[BB].clear();
218*167e8f8bSEllis Hoag 
219*167e8f8bSEllis Hoag       // Finally, remove the cycles.
220*167e8f8bSEllis Hoag       if (PredecessorDependencies[Path.front()].size()) {
221*167e8f8bSEllis Hoag         for (auto *BB : Path)
222*167e8f8bSEllis Hoag           if (BB != Path.back())
223*167e8f8bSEllis Hoag             SuccessorDependencies[BB].clear();
224*167e8f8bSEllis Hoag       } else {
225*167e8f8bSEllis Hoag         for (auto *BB : Path)
226*167e8f8bSEllis Hoag           if (BB != Path.front())
227*167e8f8bSEllis Hoag             PredecessorDependencies[BB].clear();
228*167e8f8bSEllis Hoag       }
229*167e8f8bSEllis Hoag     }
230*167e8f8bSEllis Hoag   }
231*167e8f8bSEllis Hoag   LLVM_DEBUG(dump(dbgs()));
232*167e8f8bSEllis Hoag }
233*167e8f8bSEllis Hoag 
getReachableAvoiding(const BasicBlock & Start,const BasicBlock & Avoid,bool IsForward,BlockSet & Reachable) const234*167e8f8bSEllis Hoag void BlockCoverageInference::getReachableAvoiding(const BasicBlock &Start,
235*167e8f8bSEllis Hoag                                                   const BasicBlock &Avoid,
236*167e8f8bSEllis Hoag                                                   bool IsForward,
237*167e8f8bSEllis Hoag                                                   BlockSet &Reachable) const {
238*167e8f8bSEllis Hoag   df_iterator_default_set<const BasicBlock *> Visited;
239*167e8f8bSEllis Hoag   Visited.insert(&Avoid);
240*167e8f8bSEllis Hoag   if (IsForward) {
241*167e8f8bSEllis Hoag     auto Range = depth_first_ext(&Start, Visited);
242*167e8f8bSEllis Hoag     Reachable.insert(Range.begin(), Range.end());
243*167e8f8bSEllis Hoag   } else {
244*167e8f8bSEllis Hoag     auto Range = inverse_depth_first_ext(&Start, Visited);
245*167e8f8bSEllis Hoag     Reachable.insert(Range.begin(), Range.end());
246*167e8f8bSEllis Hoag   }
247*167e8f8bSEllis Hoag }
248*167e8f8bSEllis Hoag 
249*167e8f8bSEllis Hoag namespace llvm {
250*167e8f8bSEllis Hoag class DotFuncBCIInfo {
251*167e8f8bSEllis Hoag private:
252*167e8f8bSEllis Hoag   const BlockCoverageInference *BCI;
253*167e8f8bSEllis Hoag   const DenseMap<const BasicBlock *, bool> *Coverage;
254*167e8f8bSEllis Hoag 
255*167e8f8bSEllis Hoag public:
DotFuncBCIInfo(const BlockCoverageInference * BCI,const DenseMap<const BasicBlock *,bool> * Coverage)256*167e8f8bSEllis Hoag   DotFuncBCIInfo(const BlockCoverageInference *BCI,
257*167e8f8bSEllis Hoag                  const DenseMap<const BasicBlock *, bool> *Coverage)
258*167e8f8bSEllis Hoag       : BCI(BCI), Coverage(Coverage) {}
259*167e8f8bSEllis Hoag 
getFunction()260*167e8f8bSEllis Hoag   const Function &getFunction() { return BCI->F; }
261*167e8f8bSEllis Hoag 
isInstrumented(const BasicBlock * BB) const262*167e8f8bSEllis Hoag   bool isInstrumented(const BasicBlock *BB) const {
263*167e8f8bSEllis Hoag     return BCI->shouldInstrumentBlock(*BB);
264*167e8f8bSEllis Hoag   }
265*167e8f8bSEllis Hoag 
isCovered(const BasicBlock * BB) const266*167e8f8bSEllis Hoag   bool isCovered(const BasicBlock *BB) const {
267*167e8f8bSEllis Hoag     return Coverage && Coverage->lookup(BB);
268*167e8f8bSEllis Hoag   }
269*167e8f8bSEllis Hoag 
isDependent(const BasicBlock * Src,const BasicBlock * Dest) const270*167e8f8bSEllis Hoag   bool isDependent(const BasicBlock *Src, const BasicBlock *Dest) const {
271*167e8f8bSEllis Hoag     return BCI->getDependencies(*Src).count(Dest);
272*167e8f8bSEllis Hoag   }
273*167e8f8bSEllis Hoag };
274*167e8f8bSEllis Hoag 
275*167e8f8bSEllis Hoag template <>
276*167e8f8bSEllis Hoag struct GraphTraits<DotFuncBCIInfo *> : public GraphTraits<const BasicBlock *> {
getEntryNodellvm::GraphTraits277*167e8f8bSEllis Hoag   static NodeRef getEntryNode(DotFuncBCIInfo *Info) {
278*167e8f8bSEllis Hoag     return &(Info->getFunction().getEntryBlock());
279*167e8f8bSEllis Hoag   }
280*167e8f8bSEllis Hoag 
281*167e8f8bSEllis Hoag   // nodes_iterator/begin/end - Allow iteration over all nodes in the graph
282*167e8f8bSEllis Hoag   using nodes_iterator = pointer_iterator<Function::const_iterator>;
283*167e8f8bSEllis Hoag 
nodes_beginllvm::GraphTraits284*167e8f8bSEllis Hoag   static nodes_iterator nodes_begin(DotFuncBCIInfo *Info) {
285*167e8f8bSEllis Hoag     return nodes_iterator(Info->getFunction().begin());
286*167e8f8bSEllis Hoag   }
287*167e8f8bSEllis Hoag 
nodes_endllvm::GraphTraits288*167e8f8bSEllis Hoag   static nodes_iterator nodes_end(DotFuncBCIInfo *Info) {
289*167e8f8bSEllis Hoag     return nodes_iterator(Info->getFunction().end());
290*167e8f8bSEllis Hoag   }
291*167e8f8bSEllis Hoag 
sizellvm::GraphTraits292*167e8f8bSEllis Hoag   static size_t size(DotFuncBCIInfo *Info) {
293*167e8f8bSEllis Hoag     return Info->getFunction().size();
294*167e8f8bSEllis Hoag   }
295*167e8f8bSEllis Hoag };
296*167e8f8bSEllis Hoag 
297*167e8f8bSEllis Hoag template <>
298*167e8f8bSEllis Hoag struct DOTGraphTraits<DotFuncBCIInfo *> : public DefaultDOTGraphTraits {
299*167e8f8bSEllis Hoag 
DOTGraphTraitsllvm::DOTGraphTraits300*167e8f8bSEllis Hoag   DOTGraphTraits(bool IsSimple = false) : DefaultDOTGraphTraits(IsSimple) {}
301*167e8f8bSEllis Hoag 
getGraphNamellvm::DOTGraphTraits302*167e8f8bSEllis Hoag   static std::string getGraphName(DotFuncBCIInfo *Info) {
303*167e8f8bSEllis Hoag     return "BCI CFG for " + Info->getFunction().getName().str();
304*167e8f8bSEllis Hoag   }
305*167e8f8bSEllis Hoag 
getNodeLabelllvm::DOTGraphTraits306*167e8f8bSEllis Hoag   std::string getNodeLabel(const BasicBlock *Node, DotFuncBCIInfo *Info) {
307*167e8f8bSEllis Hoag     return Node->getName().str();
308*167e8f8bSEllis Hoag   }
309*167e8f8bSEllis Hoag 
getEdgeAttributesllvm::DOTGraphTraits310*167e8f8bSEllis Hoag   std::string getEdgeAttributes(const BasicBlock *Src, const_succ_iterator I,
311*167e8f8bSEllis Hoag                                 DotFuncBCIInfo *Info) {
312*167e8f8bSEllis Hoag     const BasicBlock *Dest = *I;
313*167e8f8bSEllis Hoag     if (Info->isDependent(Src, Dest))
314*167e8f8bSEllis Hoag       return "color=red";
315*167e8f8bSEllis Hoag     if (Info->isDependent(Dest, Src))
316*167e8f8bSEllis Hoag       return "color=blue";
317*167e8f8bSEllis Hoag     return "";
318*167e8f8bSEllis Hoag   }
319*167e8f8bSEllis Hoag 
getNodeAttributesllvm::DOTGraphTraits320*167e8f8bSEllis Hoag   std::string getNodeAttributes(const BasicBlock *Node, DotFuncBCIInfo *Info) {
321*167e8f8bSEllis Hoag     std::string Result;
322*167e8f8bSEllis Hoag     if (Info->isInstrumented(Node))
323*167e8f8bSEllis Hoag       Result += "style=filled,fillcolor=gray";
324*167e8f8bSEllis Hoag     if (Info->isCovered(Node))
325*167e8f8bSEllis Hoag       Result += std::string(Result.empty() ? "" : ",") + "color=red";
326*167e8f8bSEllis Hoag     return Result;
327*167e8f8bSEllis Hoag   }
328*167e8f8bSEllis Hoag };
329*167e8f8bSEllis Hoag 
330*167e8f8bSEllis Hoag } // namespace llvm
331*167e8f8bSEllis Hoag 
viewBlockCoverageGraph(const DenseMap<const BasicBlock *,bool> * Coverage) const332*167e8f8bSEllis Hoag void BlockCoverageInference::viewBlockCoverageGraph(
333*167e8f8bSEllis Hoag     const DenseMap<const BasicBlock *, bool> *Coverage) const {
334*167e8f8bSEllis Hoag   DotFuncBCIInfo Info(this, Coverage);
335*167e8f8bSEllis Hoag   WriteGraph(&Info, "BCI", false,
336*167e8f8bSEllis Hoag              "Block Coverage Inference for " + F.getName());
337*167e8f8bSEllis Hoag }
338*167e8f8bSEllis Hoag 
dump(raw_ostream & OS) const339*167e8f8bSEllis Hoag void BlockCoverageInference::dump(raw_ostream &OS) const {
340*167e8f8bSEllis Hoag   OS << "Minimal block coverage for function \'" << F.getName()
341*167e8f8bSEllis Hoag      << "\' (Instrumented=*)\n";
342*167e8f8bSEllis Hoag   for (auto &BB : F) {
343*167e8f8bSEllis Hoag     OS << (shouldInstrumentBlock(BB) ? "* " : "  ") << BB.getName() << "\n";
344*167e8f8bSEllis Hoag     auto It = PredecessorDependencies.find(&BB);
345*167e8f8bSEllis Hoag     if (It != PredecessorDependencies.end() && It->second.size())
346*167e8f8bSEllis Hoag       OS << "    PredDeps = " << getBlockNames(It->second) << "\n";
347*167e8f8bSEllis Hoag     It = SuccessorDependencies.find(&BB);
348*167e8f8bSEllis Hoag     if (It != SuccessorDependencies.end() && It->second.size())
349*167e8f8bSEllis Hoag       OS << "    SuccDeps = " << getBlockNames(It->second) << "\n";
350*167e8f8bSEllis Hoag   }
351*167e8f8bSEllis Hoag   OS << "  Instrumented Blocks Hash = 0x"
352*167e8f8bSEllis Hoag      << Twine::utohexstr(getInstrumentedBlocksHash()) << "\n";
353*167e8f8bSEllis Hoag }
354*167e8f8bSEllis Hoag 
355*167e8f8bSEllis Hoag std::string
getBlockNames(ArrayRef<const BasicBlock * > BBs)356*167e8f8bSEllis Hoag BlockCoverageInference::getBlockNames(ArrayRef<const BasicBlock *> BBs) {
357*167e8f8bSEllis Hoag   std::string Result;
358*167e8f8bSEllis Hoag   raw_string_ostream OS(Result);
359*167e8f8bSEllis Hoag   OS << "[";
360*167e8f8bSEllis Hoag   if (!BBs.empty()) {
361*167e8f8bSEllis Hoag     OS << BBs.front()->getName();
362*167e8f8bSEllis Hoag     BBs = BBs.drop_front();
363*167e8f8bSEllis Hoag   }
364*167e8f8bSEllis Hoag   for (auto *BB : BBs)
365*167e8f8bSEllis Hoag     OS << ", " << BB->getName();
366*167e8f8bSEllis Hoag   OS << "]";
367*167e8f8bSEllis Hoag   return OS.str();
368*167e8f8bSEllis Hoag }
369