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