InstrProf: Strip filename prefixes from the names we display for coverage
[oota-llvm.git] / lib / ProfileData / CoverageMapping.cpp
1 //=-- CoverageMapping.cpp - Code coverage mapping support ---------*- 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 contains support for clang's and llvm's instrumentation based
11 // code coverage.
12 //
13 //===----------------------------------------------------------------------===//
14
15 #include "llvm/ProfileData/CoverageMapping.h"
16 #include "llvm/ADT/DenseMap.h"
17 #include "llvm/ADT/Optional.h"
18 #include "llvm/ADT/SmallBitVector.h"
19 #include "llvm/ProfileData/CoverageMappingReader.h"
20 #include "llvm/ProfileData/InstrProfReader.h"
21 #include "llvm/Support/Debug.h"
22 #include "llvm/Support/ErrorHandling.h"
23 #include "llvm/Support/Path.h"
24 #include "llvm/Support/raw_ostream.h"
25
26 using namespace llvm;
27 using namespace coverage;
28
29 #define DEBUG_TYPE "coverage-mapping"
30
31 Counter CounterExpressionBuilder::get(const CounterExpression &E) {
32   auto It = ExpressionIndices.find(E);
33   if (It != ExpressionIndices.end())
34     return Counter::getExpression(It->second);
35   unsigned I = Expressions.size();
36   Expressions.push_back(E);
37   ExpressionIndices[E] = I;
38   return Counter::getExpression(I);
39 }
40
41 void CounterExpressionBuilder::extractTerms(
42     Counter C, int Sign, SmallVectorImpl<std::pair<unsigned, int>> &Terms) {
43   switch (C.getKind()) {
44   case Counter::Zero:
45     break;
46   case Counter::CounterValueReference:
47     Terms.push_back(std::make_pair(C.getCounterID(), Sign));
48     break;
49   case Counter::Expression:
50     const auto &E = Expressions[C.getExpressionID()];
51     extractTerms(E.LHS, Sign, Terms);
52     extractTerms(E.RHS, E.Kind == CounterExpression::Subtract ? -Sign : Sign,
53                  Terms);
54     break;
55   }
56 }
57
58 Counter CounterExpressionBuilder::simplify(Counter ExpressionTree) {
59   // Gather constant terms.
60   llvm::SmallVector<std::pair<unsigned, int>, 32> Terms;
61   extractTerms(ExpressionTree, +1, Terms);
62
63   // If there are no terms, this is just a zero. The algorithm below assumes at
64   // least one term.
65   if (Terms.size() == 0)
66     return Counter::getZero();
67
68   // Group the terms by counter ID.
69   std::sort(Terms.begin(), Terms.end(),
70             [](const std::pair<unsigned, int> &LHS,
71                const std::pair<unsigned, int> &RHS) {
72     return LHS.first < RHS.first;
73   });
74
75   // Combine terms by counter ID to eliminate counters that sum to zero.
76   auto Prev = Terms.begin();
77   for (auto I = Prev + 1, E = Terms.end(); I != E; ++I) {
78     if (I->first == Prev->first) {
79       Prev->second += I->second;
80       continue;
81     }
82     ++Prev;
83     *Prev = *I;
84   }
85   Terms.erase(++Prev, Terms.end());
86
87   Counter C;
88   // Create additions. We do this before subtractions to avoid constructs like
89   // ((0 - X) + Y), as opposed to (Y - X).
90   for (auto Term : Terms) {
91     if (Term.second <= 0)
92       continue;
93     for (int I = 0; I < Term.second; ++I)
94       if (C.isZero())
95         C = Counter::getCounter(Term.first);
96       else
97         C = get(CounterExpression(CounterExpression::Add, C,
98                                   Counter::getCounter(Term.first)));
99   }
100
101   // Create subtractions.
102   for (auto Term : Terms) {
103     if (Term.second >= 0)
104       continue;
105     for (int I = 0; I < -Term.second; ++I)
106       C = get(CounterExpression(CounterExpression::Subtract, C,
107                                 Counter::getCounter(Term.first)));
108   }
109   return C;
110 }
111
112 Counter CounterExpressionBuilder::add(Counter LHS, Counter RHS) {
113   return simplify(get(CounterExpression(CounterExpression::Add, LHS, RHS)));
114 }
115
116 Counter CounterExpressionBuilder::subtract(Counter LHS, Counter RHS) {
117   return simplify(
118       get(CounterExpression(CounterExpression::Subtract, LHS, RHS)));
119 }
120
121 void CounterMappingContext::dump(const Counter &C,
122                                  llvm::raw_ostream &OS) const {
123   switch (C.getKind()) {
124   case Counter::Zero:
125     OS << '0';
126     return;
127   case Counter::CounterValueReference:
128     OS << '#' << C.getCounterID();
129     break;
130   case Counter::Expression: {
131     if (C.getExpressionID() >= Expressions.size())
132       return;
133     const auto &E = Expressions[C.getExpressionID()];
134     OS << '(';
135     dump(E.LHS, OS);
136     OS << (E.Kind == CounterExpression::Subtract ? " - " : " + ");
137     dump(E.RHS, OS);
138     OS << ')';
139     break;
140   }
141   }
142   if (CounterValues.empty())
143     return;
144   ErrorOr<int64_t> Value = evaluate(C);
145   if (!Value)
146     return;
147   OS << '[' << *Value << ']';
148 }
149
150 ErrorOr<int64_t> CounterMappingContext::evaluate(const Counter &C) const {
151   switch (C.getKind()) {
152   case Counter::Zero:
153     return 0;
154   case Counter::CounterValueReference:
155     if (C.getCounterID() >= CounterValues.size())
156       return std::make_error_code(std::errc::argument_out_of_domain);
157     return CounterValues[C.getCounterID()];
158   case Counter::Expression: {
159     if (C.getExpressionID() >= Expressions.size())
160       return std::make_error_code(std::errc::argument_out_of_domain);
161     const auto &E = Expressions[C.getExpressionID()];
162     ErrorOr<int64_t> LHS = evaluate(E.LHS);
163     if (!LHS)
164       return LHS;
165     ErrorOr<int64_t> RHS = evaluate(E.RHS);
166     if (!RHS)
167       return RHS;
168     return E.Kind == CounterExpression::Subtract ? *LHS - *RHS : *LHS + *RHS;
169   }
170   }
171   llvm_unreachable("Unhandled CounterKind");
172 }
173
174 void FunctionRecordIterator::skipOtherFiles() {
175   while (Current != Records.end() && !Filename.empty() &&
176          Filename != Current->Filenames[0])
177     ++Current;
178   if (Current == Records.end())
179     *this = FunctionRecordIterator();
180 }
181
182 /// Get the function name from the record, removing the filename prefix if
183 /// necessary.
184 static StringRef getFuncNameWithoutPrefix(const CoverageMappingRecord &Record) {
185   StringRef FunctionName = Record.FunctionName;
186   if (Record.Filenames.empty())
187     return FunctionName;
188   StringRef Filename = sys::path::filename(Record.Filenames[0]);
189   if (FunctionName.startswith(Filename))
190     FunctionName = FunctionName.drop_front(Filename.size() + 1);
191   return FunctionName;
192 }
193
194 ErrorOr<std::unique_ptr<CoverageMapping>>
195 CoverageMapping::load(CoverageMappingReader &CoverageReader,
196                       IndexedInstrProfReader &ProfileReader) {
197   auto Coverage = std::unique_ptr<CoverageMapping>(new CoverageMapping());
198
199   std::vector<uint64_t> Counts;
200   for (const auto &Record : CoverageReader) {
201     CounterMappingContext Ctx(Record.Expressions);
202
203     Counts.clear();
204     if (std::error_code EC = ProfileReader.getFunctionCounts(
205             Record.FunctionName, Record.FunctionHash, Counts)) {
206       if (EC == instrprof_error::hash_mismatch) {
207         Coverage->MismatchedFunctionCount++;
208         continue;
209       } else if (EC != instrprof_error::unknown_function)
210         return EC;
211     } else
212       Ctx.setCounts(Counts);
213
214     assert(!Record.MappingRegions.empty() && "Function has no regions");
215
216     FunctionRecord Function(getFuncNameWithoutPrefix(Record), Record.Filenames);
217     for (const auto &Region : Record.MappingRegions) {
218       ErrorOr<int64_t> ExecutionCount = Ctx.evaluate(Region.Count);
219       if (!ExecutionCount)
220         break;
221       Function.pushRegion(Region, *ExecutionCount);
222     }
223     if (Function.CountedRegions.size() != Record.MappingRegions.size()) {
224       Coverage->MismatchedFunctionCount++;
225       continue;
226     }
227
228     Coverage->Functions.push_back(std::move(Function));
229   }
230
231   return std::move(Coverage);
232 }
233
234 ErrorOr<std::unique_ptr<CoverageMapping>>
235 CoverageMapping::load(StringRef ObjectFilename, StringRef ProfileFilename,
236                       Triple::ArchType Arch) {
237   auto CounterMappingBuff = MemoryBuffer::getFileOrSTDIN(ObjectFilename);
238   if (std::error_code EC = CounterMappingBuff.getError())
239     return EC;
240   auto CoverageReaderOrErr =
241       BinaryCoverageReader::create(CounterMappingBuff.get(), Arch);
242   if (std::error_code EC = CoverageReaderOrErr.getError())
243     return EC;
244   auto CoverageReader = std::move(CoverageReaderOrErr.get());
245   auto ProfileReaderOrErr = IndexedInstrProfReader::create(ProfileFilename);
246   if (auto EC = ProfileReaderOrErr.getError())
247     return EC;
248   auto ProfileReader = std::move(ProfileReaderOrErr.get());
249   return load(*CoverageReader, *ProfileReader);
250 }
251
252 namespace {
253 /// \brief Distributes functions into instantiation sets.
254 ///
255 /// An instantiation set is a collection of functions that have the same source
256 /// code, ie, template functions specializations.
257 class FunctionInstantiationSetCollector {
258   typedef DenseMap<std::pair<unsigned, unsigned>,
259                    std::vector<const FunctionRecord *>> MapT;
260   MapT InstantiatedFunctions;
261
262 public:
263   void insert(const FunctionRecord &Function, unsigned FileID) {
264     auto I = Function.CountedRegions.begin(), E = Function.CountedRegions.end();
265     while (I != E && I->FileID != FileID)
266       ++I;
267     assert(I != E && "function does not cover the given file");
268     auto &Functions = InstantiatedFunctions[I->startLoc()];
269     Functions.push_back(&Function);
270   }
271
272   MapT::iterator begin() { return InstantiatedFunctions.begin(); }
273
274   MapT::iterator end() { return InstantiatedFunctions.end(); }
275 };
276
277 class SegmentBuilder {
278   std::vector<CoverageSegment> Segments;
279   SmallVector<const CountedRegion *, 8> ActiveRegions;
280
281   /// Start a segment with no count specified.
282   void startSegment(unsigned Line, unsigned Col) {
283     DEBUG(dbgs() << "Top level segment at " << Line << ":" << Col << "\n");
284     Segments.emplace_back(Line, Col, /*IsRegionEntry=*/false);
285   }
286
287   /// Start a segment with the given Region's count.
288   void startSegment(unsigned Line, unsigned Col, bool IsRegionEntry,
289                     const CountedRegion &Region) {
290     if (Segments.empty())
291       Segments.emplace_back(Line, Col, IsRegionEntry);
292     CoverageSegment S = Segments.back();
293     // Avoid creating empty regions.
294     if (S.Line != Line || S.Col != Col) {
295       Segments.emplace_back(Line, Col, IsRegionEntry);
296       S = Segments.back();
297     }
298     DEBUG(dbgs() << "Segment at " << Line << ":" << Col);
299     // Set this region's count.
300     if (Region.Kind != coverage::CounterMappingRegion::SkippedRegion) {
301       DEBUG(dbgs() << " with count " << Region.ExecutionCount);
302       Segments.back().setCount(Region.ExecutionCount);
303     }
304     DEBUG(dbgs() << "\n");
305   }
306
307   /// Start a segment for the given region.
308   void startSegment(const CountedRegion &Region) {
309     startSegment(Region.LineStart, Region.ColumnStart, true, Region);
310   }
311
312   /// Pop the top region off of the active stack, starting a new segment with
313   /// the containing Region's count.
314   void popRegion() {
315     const CountedRegion *Active = ActiveRegions.back();
316     unsigned Line = Active->LineEnd, Col = Active->ColumnEnd;
317     ActiveRegions.pop_back();
318     if (ActiveRegions.empty())
319       startSegment(Line, Col);
320     else
321       startSegment(Line, Col, false, *ActiveRegions.back());
322   }
323
324 public:
325   /// Build a list of CoverageSegments from a sorted list of Regions.
326   std::vector<CoverageSegment> buildSegments(ArrayRef<CountedRegion> Regions) {
327     const CountedRegion *PrevRegion = nullptr;
328     for (const auto &Region : Regions) {
329       // Pop any regions that end before this one starts.
330       while (!ActiveRegions.empty() &&
331              ActiveRegions.back()->endLoc() <= Region.startLoc())
332         popRegion();
333       if (PrevRegion && PrevRegion->startLoc() == Region.startLoc() &&
334           PrevRegion->endLoc() == Region.endLoc()) {
335         if (Region.Kind == coverage::CounterMappingRegion::CodeRegion)
336           Segments.back().addCount(Region.ExecutionCount);
337       } else {
338         // Add this region to the stack.
339         ActiveRegions.push_back(&Region);
340         startSegment(Region);
341       }
342       PrevRegion = &Region;
343     }
344     // Pop any regions that are left in the stack.
345     while (!ActiveRegions.empty())
346       popRegion();
347     return Segments;
348   }
349 };
350 }
351
352 std::vector<StringRef> CoverageMapping::getUniqueSourceFiles() const {
353   std::vector<StringRef> Filenames;
354   for (const auto &Function : getCoveredFunctions())
355     Filenames.insert(Filenames.end(), Function.Filenames.begin(),
356                      Function.Filenames.end());
357   std::sort(Filenames.begin(), Filenames.end());
358   auto Last = std::unique(Filenames.begin(), Filenames.end());
359   Filenames.erase(Last, Filenames.end());
360   return Filenames;
361 }
362
363 static SmallBitVector gatherFileIDs(StringRef SourceFile,
364                                     const FunctionRecord &Function) {
365   SmallBitVector FilenameEquivalence(Function.Filenames.size(), false);
366   for (unsigned I = 0, E = Function.Filenames.size(); I < E; ++I)
367     if (SourceFile == Function.Filenames[I])
368       FilenameEquivalence[I] = true;
369   return FilenameEquivalence;
370 }
371
372 static Optional<unsigned> findMainViewFileID(StringRef SourceFile,
373                                              const FunctionRecord &Function) {
374   SmallBitVector IsNotExpandedFile(Function.Filenames.size(), true);
375   SmallBitVector FilenameEquivalence = gatherFileIDs(SourceFile, Function);
376   for (const auto &CR : Function.CountedRegions)
377     if (CR.Kind == CounterMappingRegion::ExpansionRegion &&
378         FilenameEquivalence[CR.FileID])
379       IsNotExpandedFile[CR.ExpandedFileID] = false;
380   IsNotExpandedFile &= FilenameEquivalence;
381   int I = IsNotExpandedFile.find_first();
382   if (I == -1)
383     return None;
384   return I;
385 }
386
387 static Optional<unsigned> findMainViewFileID(const FunctionRecord &Function) {
388   SmallBitVector IsNotExpandedFile(Function.Filenames.size(), true);
389   for (const auto &CR : Function.CountedRegions)
390     if (CR.Kind == CounterMappingRegion::ExpansionRegion)
391       IsNotExpandedFile[CR.ExpandedFileID] = false;
392   int I = IsNotExpandedFile.find_first();
393   if (I == -1)
394     return None;
395   return I;
396 }
397
398 /// Sort a nested sequence of regions from a single file.
399 template <class It> static void sortNestedRegions(It First, It Last) {
400   std::sort(First, Last,
401             [](const CountedRegion &LHS, const CountedRegion &RHS) {
402     if (LHS.startLoc() == RHS.startLoc())
403       // When LHS completely contains RHS, we sort LHS first.
404       return RHS.endLoc() < LHS.endLoc();
405     return LHS.startLoc() < RHS.startLoc();
406   });
407 }
408
409 static bool isExpansion(const CountedRegion &R, unsigned FileID) {
410   return R.Kind == CounterMappingRegion::ExpansionRegion && R.FileID == FileID;
411 }
412
413 CoverageData CoverageMapping::getCoverageForFile(StringRef Filename) {
414   CoverageData FileCoverage(Filename);
415   std::vector<coverage::CountedRegion> Regions;
416
417   for (const auto &Function : Functions) {
418     auto MainFileID = findMainViewFileID(Filename, Function);
419     if (!MainFileID)
420       continue;
421     auto FileIDs = gatherFileIDs(Filename, Function);
422     for (const auto &CR : Function.CountedRegions)
423       if (FileIDs.test(CR.FileID)) {
424         Regions.push_back(CR);
425         if (isExpansion(CR, *MainFileID))
426           FileCoverage.Expansions.emplace_back(CR, Function);
427       }
428   }
429
430   sortNestedRegions(Regions.begin(), Regions.end());
431   DEBUG(dbgs() << "Emitting segments for file: " << Filename << "\n");
432   FileCoverage.Segments = SegmentBuilder().buildSegments(Regions);
433
434   return FileCoverage;
435 }
436
437 std::vector<const FunctionRecord *>
438 CoverageMapping::getInstantiations(StringRef Filename) {
439   FunctionInstantiationSetCollector InstantiationSetCollector;
440   for (const auto &Function : Functions) {
441     auto MainFileID = findMainViewFileID(Filename, Function);
442     if (!MainFileID)
443       continue;
444     InstantiationSetCollector.insert(Function, *MainFileID);
445   }
446
447   std::vector<const FunctionRecord *> Result;
448   for (const auto &InstantiationSet : InstantiationSetCollector) {
449     if (InstantiationSet.second.size() < 2)
450       continue;
451     Result.insert(Result.end(), InstantiationSet.second.begin(),
452                   InstantiationSet.second.end());
453   }
454   return Result;
455 }
456
457 CoverageData
458 CoverageMapping::getCoverageForFunction(const FunctionRecord &Function) {
459   auto MainFileID = findMainViewFileID(Function);
460   if (!MainFileID)
461     return CoverageData();
462
463   CoverageData FunctionCoverage(Function.Filenames[*MainFileID]);
464   std::vector<coverage::CountedRegion> Regions;
465   for (const auto &CR : Function.CountedRegions)
466     if (CR.FileID == *MainFileID) {
467       Regions.push_back(CR);
468       if (isExpansion(CR, *MainFileID))
469         FunctionCoverage.Expansions.emplace_back(CR, Function);
470     }
471
472   sortNestedRegions(Regions.begin(), Regions.end());
473   DEBUG(dbgs() << "Emitting segments for function: " << Function.Name << "\n");
474   FunctionCoverage.Segments = SegmentBuilder().buildSegments(Regions);
475
476   return FunctionCoverage;
477 }
478
479 CoverageData
480 CoverageMapping::getCoverageForExpansion(const ExpansionRecord &Expansion) {
481   CoverageData ExpansionCoverage(
482       Expansion.Function.Filenames[Expansion.FileID]);
483   std::vector<coverage::CountedRegion> Regions;
484   for (const auto &CR : Expansion.Function.CountedRegions)
485     if (CR.FileID == Expansion.FileID) {
486       Regions.push_back(CR);
487       if (isExpansion(CR, Expansion.FileID))
488         ExpansionCoverage.Expansions.emplace_back(CR, Expansion.Function);
489     }
490
491   sortNestedRegions(Regions.begin(), Regions.end());
492   DEBUG(dbgs() << "Emitting segments for expansion of file " << Expansion.FileID
493                << "\n");
494   ExpansionCoverage.Segments = SegmentBuilder().buildSegments(Regions);
495
496   return ExpansionCoverage;
497 }