LLVM 18.0.0git
CoverageMapping.cpp
Go to the documentation of this file.
1//===- CoverageMapping.cpp - Code coverage mapping support ----------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file contains support for clang's and llvm's instrumentation based
10// code coverage.
11//
12//===----------------------------------------------------------------------===//
13
15#include "llvm/ADT/ArrayRef.h"
16#include "llvm/ADT/DenseMap.h"
21#include "llvm/ADT/StringRef.h"
22#include "llvm/Object/BuildID.h"
25#include "llvm/Support/Debug.h"
26#include "llvm/Support/Errc.h"
27#include "llvm/Support/Error.h"
32#include <algorithm>
33#include <cassert>
34#include <cmath>
35#include <cstdint>
36#include <iterator>
37#include <map>
38#include <memory>
39#include <optional>
40#include <string>
41#include <system_error>
42#include <utility>
43#include <vector>
44
45using namespace llvm;
46using namespace coverage;
47
48#define DEBUG_TYPE "coverage-mapping"
49
50Counter CounterExpressionBuilder::get(const CounterExpression &E) {
51 auto It = ExpressionIndices.find(E);
52 if (It != ExpressionIndices.end())
53 return Counter::getExpression(It->second);
54 unsigned I = Expressions.size();
55 Expressions.push_back(E);
56 ExpressionIndices[E] = I;
58}
59
60void CounterExpressionBuilder::extractTerms(Counter C, int Factor,
61 SmallVectorImpl<Term> &Terms) {
62 switch (C.getKind()) {
63 case Counter::Zero:
64 break;
66 Terms.emplace_back(C.getCounterID(), Factor);
67 break;
69 const auto &E = Expressions[C.getExpressionID()];
70 extractTerms(E.LHS, Factor, Terms);
71 extractTerms(
72 E.RHS, E.Kind == CounterExpression::Subtract ? -Factor : Factor, Terms);
73 break;
74 }
75}
76
77Counter CounterExpressionBuilder::simplify(Counter ExpressionTree) {
78 // Gather constant terms.
80 extractTerms(ExpressionTree, +1, Terms);
81
82 // If there are no terms, this is just a zero. The algorithm below assumes at
83 // least one term.
84 if (Terms.size() == 0)
85 return Counter::getZero();
86
87 // Group the terms by counter ID.
88 llvm::sort(Terms, [](const Term &LHS, const Term &RHS) {
89 return LHS.CounterID < RHS.CounterID;
90 });
91
92 // Combine terms by counter ID to eliminate counters that sum to zero.
93 auto Prev = Terms.begin();
94 for (auto I = Prev + 1, E = Terms.end(); I != E; ++I) {
95 if (I->CounterID == Prev->CounterID) {
96 Prev->Factor += I->Factor;
97 continue;
98 }
99 ++Prev;
100 *Prev = *I;
101 }
102 Terms.erase(++Prev, Terms.end());
103
104 Counter C;
105 // Create additions. We do this before subtractions to avoid constructs like
106 // ((0 - X) + Y), as opposed to (Y - X).
107 for (auto T : Terms) {
108 if (T.Factor <= 0)
109 continue;
110 for (int I = 0; I < T.Factor; ++I)
111 if (C.isZero())
112 C = Counter::getCounter(T.CounterID);
113 else
115 Counter::getCounter(T.CounterID)));
116 }
117
118 // Create subtractions.
119 for (auto T : Terms) {
120 if (T.Factor >= 0)
121 continue;
122 for (int I = 0; I < -T.Factor; ++I)
124 Counter::getCounter(T.CounterID)));
125 }
126 return C;
127}
128
131 return Simplify ? simplify(Cnt) : Cnt;
132}
133
135 bool Simplify) {
137 return Simplify ? simplify(Cnt) : Cnt;
138}
139
141 switch (C.getKind()) {
142 case Counter::Zero:
143 OS << '0';
144 return;
146 OS << '#' << C.getCounterID();
147 break;
148 case Counter::Expression: {
149 if (C.getExpressionID() >= Expressions.size())
150 return;
151 const auto &E = Expressions[C.getExpressionID()];
152 OS << '(';
153 dump(E.LHS, OS);
154 OS << (E.Kind == CounterExpression::Subtract ? " - " : " + ");
155 dump(E.RHS, OS);
156 OS << ')';
157 break;
158 }
159 }
160 if (CounterValues.empty())
161 return;
163 if (auto E = Value.takeError()) {
164 consumeError(std::move(E));
165 return;
166 }
167 OS << '[' << *Value << ']';
168}
169
171 switch (C.getKind()) {
172 case Counter::Zero:
173 return 0;
175 if (C.getCounterID() >= CounterValues.size())
177 return CounterValues[C.getCounterID()];
178 case Counter::Expression: {
179 if (C.getExpressionID() >= Expressions.size())
181 const auto &E = Expressions[C.getExpressionID()];
183 if (!LHS)
184 return LHS;
186 if (!RHS)
187 return RHS;
188 return E.Kind == CounterExpression::Subtract ? *LHS - *RHS : *LHS + *RHS;
189 }
190 }
191 llvm_unreachable("Unhandled CounterKind");
192}
193
195 const CounterMappingRegion *MCDCDecision) const {
196 unsigned ID = MCDCDecision->MCDCParams.BitmapIdx;
197 unsigned NC = MCDCDecision->MCDCParams.NumConditions;
198 unsigned SizeInBits = llvm::alignTo(1L << NC, CHAR_BIT);
199 unsigned SizeInBytes = SizeInBits / CHAR_BIT;
200
201 ArrayRef<uint8_t> Bytes(&BitmapBytes[ID], SizeInBytes);
202
203 // Mask each bitmap byte into the BitVector. Go in reverse so that the
204 // bitvector can just be shifted over by one byte on each iteration.
205 BitVector Result(SizeInBits, false);
206 for (auto Byte = std::rbegin(Bytes); Byte != std::rend(Bytes); ++Byte) {
207 uint32_t Data = *Byte;
208 Result <<= CHAR_BIT;
209 Result.setBitsInMask(&Data, 1);
210 }
211 return Result;
212}
213
215 /// A bitmap representing the executed test vectors for a boolean expression.
216 /// Each index of the bitmap corresponds to a possible test vector. An index
217 /// with a bit value of '1' indicates that the corresponding Test Vector
218 /// identified by that index was executed.
219 BitVector &ExecutedTestVectorBitmap;
220
221 /// Decision Region to which the ExecutedTestVectorBitmap applies.
223
224 /// Array of branch regions corresponding each conditions in the boolean
225 /// expression.
227
228 /// Total number of conditions in the boolean expression.
229 unsigned NumConditions;
230
231 /// Mapping of a condition ID to its corresponding branch region.
233
234 /// Vector used to track whether a condition is constant folded.
236
237 /// Mapping of calculated MC/DC Independence Pairs for each condition.
238 MCDCRecord::TVPairMap IndependencePairs;
239
240 /// Total number of possible Test Vectors for the boolean expression.
241 MCDCRecord::TestVectors TestVectors;
242
243 /// Actual executed Test Vectors for the boolean expression, based on
244 /// ExecutedTestVectorBitmap.
245 MCDCRecord::TestVectors ExecVectors;
246
247public:
250 : ExecutedTestVectorBitmap(Bitmap), Region(Region), Branches(Branches),
251 NumConditions(Region.MCDCParams.NumConditions),
252 Folded(NumConditions, false), IndependencePairs(NumConditions),
253 TestVectors(pow(2, NumConditions)) {}
254
255private:
256 void recordTestVector(MCDCRecord::TestVector &TV,
257 MCDCRecord::CondState Result) {
258 // Calculate an index that is used to identify the test vector in a vector
259 // of test vectors. This index also corresponds to the index values of an
260 // MCDC Region's bitmap (see findExecutedTestVectors()).
261 unsigned Index = 0;
262 for (auto Cond = std::rbegin(TV); Cond != std::rend(TV); ++Cond) {
263 Index <<= 1;
264 Index |= (*Cond == MCDCRecord::MCDC_True) ? 0x1 : 0x0;
265 }
266
267 // Copy the completed test vector to the vector of testvectors.
268 TestVectors[Index] = TV;
269
270 // The final value (T,F) is equal to the last non-dontcare state on the
271 // path (in a short-circuiting system).
272 TestVectors[Index].push_back(Result);
273 }
274
275 void shouldCopyOffTestVectorForTruePath(MCDCRecord::TestVector &TV,
276 unsigned ID) {
277 // Branch regions are hashed based on an ID.
279
280 TV[ID - 1] = MCDCRecord::MCDC_True;
281 if (Branch->MCDCParams.TrueID > 0)
282 buildTestVector(TV, Branch->MCDCParams.TrueID);
283 else
284 recordTestVector(TV, MCDCRecord::MCDC_True);
285 }
286
287 void shouldCopyOffTestVectorForFalsePath(MCDCRecord::TestVector &TV,
288 unsigned ID) {
289 // Branch regions are hashed based on an ID.
291
292 TV[ID - 1] = MCDCRecord::MCDC_False;
293 if (Branch->MCDCParams.FalseID > 0)
294 buildTestVector(TV, Branch->MCDCParams.FalseID);
295 else
296 recordTestVector(TV, MCDCRecord::MCDC_False);
297 }
298
299 void buildTestVector(MCDCRecord::TestVector &TV, unsigned ID = 1) {
300 shouldCopyOffTestVectorForTruePath(TV, ID);
301 shouldCopyOffTestVectorForFalsePath(TV, ID);
302
303 // Reset back to DontCare.
305 }
306
307 void findExecutedTestVectors(BitVector &ExecutedTestVectorBitmap) {
308 // Walk the bits in the bitmap. A bit set to '1' indicates that the test
309 // vector at the corresponding index was executed during a test run.
310 for (unsigned Idx = 0; Idx < ExecutedTestVectorBitmap.size(); Idx++) {
311 if (ExecutedTestVectorBitmap[Idx] == 0)
312 continue;
313 assert(!TestVectors[Idx].empty() && "Test Vector doesn't exist.");
314 ExecVectors.push_back(TestVectors[Idx]);
315 }
316 }
317
318 // For a given condition and two executed Test Vectors, A and B, see if the
319 // two test vectors match forming an Independence Pair for the condition.
320 // For two test vectors to match, the following must be satisfied:
321 // - The condition's value in each test vector must be opposite.
322 // - The result's value in each test vector must be opposite.
323 // - All other conditions' values must be equal or marked as "don't care".
324 bool matchTestVectors(unsigned Aidx, unsigned Bidx, unsigned ConditionIdx) {
325 const MCDCRecord::TestVector &A = ExecVectors[Aidx];
326 const MCDCRecord::TestVector &B = ExecVectors[Bidx];
327
328 // If condition values in both A and B aren't opposites, no match.
329 if (!((A[ConditionIdx] ^ B[ConditionIdx]) == 1))
330 return false;
331
332 // If the results of both A and B aren't opposites, no match.
333 if (!((A[NumConditions] ^ B[NumConditions]) == 1))
334 return false;
335
336 for (unsigned Idx = 0; Idx < NumConditions; Idx++) {
337 // Look for other conditions that don't match. Skip over the given
338 // Condition as well as any conditions marked as "don't care".
339 const auto ARecordTyForCond = A[Idx];
340 const auto BRecordTyForCond = B[Idx];
341 if (Idx == ConditionIdx ||
342 ARecordTyForCond == MCDCRecord::MCDC_DontCare ||
343 BRecordTyForCond == MCDCRecord::MCDC_DontCare)
344 continue;
345
346 // If there is a condition mismatch with any of the other conditions,
347 // there is no match for the test vectors.
348 if (ARecordTyForCond != BRecordTyForCond)
349 return false;
350 }
351
352 // Otherwise, match.
353 return true;
354 }
355
356 // Find all possible Independence Pairs for a boolean expression given its
357 // executed Test Vectors. This process involves looking at each condition
358 // and attempting to find two Test Vectors that "match", giving us a pair.
359 void findIndependencePairs() {
360 unsigned NumTVs = ExecVectors.size();
361
362 // For each condition.
363 for (unsigned C = 0; C < NumConditions; C++) {
364 bool PairFound = false;
365
366 // For each executed test vector.
367 for (unsigned I = 0; !PairFound && I < NumTVs; I++) {
368
369 // Compared to every other executed test vector.
370 for (unsigned J = 0; !PairFound && J < NumTVs; J++) {
371 if (I == J)
372 continue;
373
374 // If a matching pair of vectors is found, record them.
375 if ((PairFound = matchTestVectors(I, J, C)))
376 IndependencePairs[C] = std::make_pair(I + 1, J + 1);
377 }
378 }
379 }
380 }
381
382public:
383 /// Process the MC/DC Record in order to produce a result for a boolean
384 /// expression. This process includes tracking the conditions that comprise
385 /// the decision region, calculating the list of all possible test vectors,
386 /// marking the executed test vectors, and then finding an Independence Pair
387 /// out of the executed test vectors for each condition in the boolean
388 /// expression. A condition is tracked to ensure that its ID can be mapped to
389 /// its ordinal position in the boolean expression. The condition's source
390 /// location is also tracked, as well as whether it is constant folded (in
391 /// which case it is excuded from the metric).
393 unsigned I = 0;
394 MCDCRecord::CondIDMap PosToID;
396
397 // Walk the Record's BranchRegions (representing Conditions) in order to:
398 // - Hash the condition based on its corresponding ID. This will be used to
399 // calculate the test vectors.
400 // - Keep a map of the condition's ordinal position (1, 2, 3, 4) to its
401 // actual ID. This will be used to visualize the conditions in the
402 // correct order.
403 // - Keep track of the condition source location. This will be used to
404 // visualize where the condition is.
405 // - Record whether the condition is constant folded so that we exclude it
406 // from being measured.
407 for (const auto &B : Branches) {
408 Map[B.MCDCParams.ID] = &B;
409 PosToID[I] = B.MCDCParams.ID - 1;
410 CondLoc[I] = B.startLoc();
411 Folded[I++] = (B.Count.isZero() && B.FalseCount.isZero());
412 }
413
414 // Initialize a base test vector as 'DontCare'.
416
417 // Use the base test vector to build the list of all possible test vectors.
418 buildTestVector(TV);
419
420 // Using Profile Bitmap from runtime, mark the executed test vectors.
421 findExecutedTestVectors(ExecutedTestVectorBitmap);
422
423 // Compare executed test vectors against each other to find an independence
424 // pairs for each condition. This processing takes the most time.
425 findIndependencePairs();
426
427 // Record Test vectors, executed vectors, and independence pairs.
428 MCDCRecord Res(Region, ExecVectors, IndependencePairs, Folded, PosToID,
429 CondLoc);
430 return Res;
431 }
432};
433
435 CounterMappingRegion Region, BitVector ExecutedTestVectorBitmap,
437
438 MCDCRecordProcessor MCDCProcessor(ExecutedTestVectorBitmap, Region, Branches);
439 return MCDCProcessor.processMCDCRecord();
440}
441
443 switch (C.getKind()) {
444 case Counter::Zero:
445 return 0;
447 return C.getCounterID();
448 case Counter::Expression: {
449 if (C.getExpressionID() >= Expressions.size())
450 return 0;
451 const auto &E = Expressions[C.getExpressionID()];
452 return std::max(getMaxCounterID(E.LHS), getMaxCounterID(E.RHS));
453 }
454 }
455 llvm_unreachable("Unhandled CounterKind");
456}
457
458void FunctionRecordIterator::skipOtherFiles() {
459 while (Current != Records.end() && !Filename.empty() &&
460 Filename != Current->Filenames[0])
461 ++Current;
462 if (Current == Records.end())
463 *this = FunctionRecordIterator();
464}
465
466ArrayRef<unsigned> CoverageMapping::getImpreciseRecordIndicesForFilename(
467 StringRef Filename) const {
468 size_t FilenameHash = hash_value(Filename);
469 auto RecordIt = FilenameHash2RecordIndices.find(FilenameHash);
470 if (RecordIt == FilenameHash2RecordIndices.end())
471 return {};
472 return RecordIt->second;
473}
474
475static unsigned getMaxCounterID(const CounterMappingContext &Ctx,
477 unsigned MaxCounterID = 0;
478 for (const auto &Region : Record.MappingRegions) {
479 MaxCounterID = std::max(MaxCounterID, Ctx.getMaxCounterID(Region.Count));
480 }
481 return MaxCounterID;
482}
483
484static unsigned getMaxBitmapSize(const CounterMappingContext &Ctx,
486 unsigned MaxBitmapID = 0;
487 unsigned NumConditions = 0;
488 // The last DecisionRegion has the highest bitmap byte index used in the
489 // function, which when combined with its number of conditions, yields the
490 // full bitmap size.
491 for (const auto &Region : reverse(Record.MappingRegions)) {
493 MaxBitmapID = Region.MCDCParams.BitmapIdx;
494 NumConditions = Region.MCDCParams.NumConditions;
495 break;
496 }
497 }
498 unsigned SizeInBits = llvm::alignTo(1L << NumConditions, CHAR_BIT);
499 return MaxBitmapID + (SizeInBits / CHAR_BIT);
500}
501
502Error CoverageMapping::loadFunctionRecord(
504 IndexedInstrProfReader &ProfileReader) {
505 StringRef OrigFuncName = Record.FunctionName;
506 if (OrigFuncName.empty())
507 return make_error<CoverageMapError>(coveragemap_error::malformed,
508 "record function name is empty");
509
510 if (Record.Filenames.empty())
511 OrigFuncName = getFuncNameWithoutPrefix(OrigFuncName);
512 else
513 OrigFuncName = getFuncNameWithoutPrefix(OrigFuncName, Record.Filenames[0]);
514
515 CounterMappingContext Ctx(Record.Expressions);
516
517 std::vector<uint64_t> Counts;
518 if (Error E = ProfileReader.getFunctionCounts(Record.FunctionName,
519 Record.FunctionHash, Counts)) {
520 instrprof_error IPE = std::get<0>(InstrProfError::take(std::move(E)));
522 FuncHashMismatches.emplace_back(std::string(Record.FunctionName),
523 Record.FunctionHash);
524 return Error::success();
525 }
527 return make_error<InstrProfError>(IPE);
528 Counts.assign(getMaxCounterID(Ctx, Record) + 1, 0);
529 }
530 Ctx.setCounts(Counts);
531
532 std::vector<uint8_t> BitmapBytes;
533 if (Error E = ProfileReader.getFunctionBitmapBytes(
534 Record.FunctionName, Record.FunctionHash, BitmapBytes)) {
535 instrprof_error IPE = std::get<0>(InstrProfError::take(std::move(E)));
537 FuncHashMismatches.emplace_back(std::string(Record.FunctionName),
538 Record.FunctionHash);
539 return Error::success();
540 }
542 return make_error<InstrProfError>(IPE);
543 BitmapBytes.assign(getMaxBitmapSize(Ctx, Record) + 1, 0);
544 }
545 Ctx.setBitmapBytes(BitmapBytes);
546
547 assert(!Record.MappingRegions.empty() && "Function has no regions");
548
549 // This coverage record is a zero region for a function that's unused in
550 // some TU, but used in a different TU. Ignore it. The coverage maps from the
551 // the other TU will either be loaded (providing full region counts) or they
552 // won't (in which case we don't unintuitively report functions as uncovered
553 // when they have non-zero counts in the profile).
554 if (Record.MappingRegions.size() == 1 &&
555 Record.MappingRegions[0].Count.isZero() && Counts[0] > 0)
556 return Error::success();
557
558 unsigned NumConds = 0;
559 const CounterMappingRegion *MCDCDecision;
560 std::vector<CounterMappingRegion> MCDCBranches;
561
562 FunctionRecord Function(OrigFuncName, Record.Filenames);
563 for (const auto &Region : Record.MappingRegions) {
564 // If an MCDCDecisionRegion is seen, track the BranchRegions that follow
565 // it according to Region.NumConditions.
567 assert(NumConds == 0);
568 MCDCDecision = &Region;
569 NumConds = Region.MCDCParams.NumConditions;
570 continue;
571 }
572 Expected<int64_t> ExecutionCount = Ctx.evaluate(Region.Count);
573 if (auto E = ExecutionCount.takeError()) {
574 consumeError(std::move(E));
575 return Error::success();
576 }
577 Expected<int64_t> AltExecutionCount = Ctx.evaluate(Region.FalseCount);
578 if (auto E = AltExecutionCount.takeError()) {
579 consumeError(std::move(E));
580 return Error::success();
581 }
582 Function.pushRegion(Region, *ExecutionCount, *AltExecutionCount);
583
584 // If a MCDCDecisionRegion was seen, store the BranchRegions that
585 // correspond to it in a vector, according to the number of conditions
586 // recorded for the region (tracked by NumConds).
587 if (NumConds > 0 && Region.Kind == CounterMappingRegion::MCDCBranchRegion) {
588 MCDCBranches.push_back(Region);
589
590 // As we move through all of the MCDCBranchRegions that follow the
591 // MCDCDecisionRegion, decrement NumConds to make sure we account for
592 // them all before we calculate the bitmap of executed test vectors.
593 if (--NumConds == 0) {
594 // Evaluating the test vector bitmap for the decision region entails
595 // calculating precisely what bits are pertinent to this region alone.
596 // This is calculated based on the recorded offset into the global
597 // profile bitmap; the length is calculated based on the recorded
598 // number of conditions.
599 Expected<BitVector> ExecutedTestVectorBitmap =
600 Ctx.evaluateBitmap(MCDCDecision);
601 if (auto E = ExecutedTestVectorBitmap.takeError()) {
602 consumeError(std::move(E));
603 return Error::success();
604 }
605
606 // Since the bitmap identifies the executed test vectors for an MC/DC
607 // DecisionRegion, all of the information is now available to process.
608 // This is where the bulk of the MC/DC progressing takes place.
609 Expected<MCDCRecord> Record = Ctx.evaluateMCDCRegion(
610 *MCDCDecision, *ExecutedTestVectorBitmap, MCDCBranches);
611 if (auto E = Record.takeError()) {
612 consumeError(std::move(E));
613 return Error::success();
614 }
615
616 // Save the MC/DC Record so that it can be visualized later.
617 Function.pushMCDCRecord(*Record);
618 MCDCBranches.clear();
619 }
620 }
621 }
622
623 // Don't create records for (filenames, function) pairs we've already seen.
624 auto FilenamesHash = hash_combine_range(Record.Filenames.begin(),
625 Record.Filenames.end());
626 if (!RecordProvenance[FilenamesHash].insert(hash_value(OrigFuncName)).second)
627 return Error::success();
628
629 Functions.push_back(std::move(Function));
630
631 // Performance optimization: keep track of the indices of the function records
632 // which correspond to each filename. This can be used to substantially speed
633 // up queries for coverage info in a file.
634 unsigned RecordIndex = Functions.size() - 1;
635 for (StringRef Filename : Record.Filenames) {
636 auto &RecordIndices = FilenameHash2RecordIndices[hash_value(Filename)];
637 // Note that there may be duplicates in the filename set for a function
638 // record, because of e.g. macro expansions in the function in which both
639 // the macro and the function are defined in the same file.
640 if (RecordIndices.empty() || RecordIndices.back() != RecordIndex)
641 RecordIndices.push_back(RecordIndex);
642 }
643
644 return Error::success();
645}
646
647// This function is for memory optimization by shortening the lifetimes
648// of CoverageMappingReader instances.
649Error CoverageMapping::loadFromReaders(
650 ArrayRef<std::unique_ptr<CoverageMappingReader>> CoverageReaders,
651 IndexedInstrProfReader &ProfileReader, CoverageMapping &Coverage) {
652 for (const auto &CoverageReader : CoverageReaders) {
653 for (auto RecordOrErr : *CoverageReader) {
654 if (Error E = RecordOrErr.takeError())
655 return E;
656 const auto &Record = *RecordOrErr;
657 if (Error E = Coverage.loadFunctionRecord(Record, ProfileReader))
658 return E;
659 }
660 }
661 return Error::success();
662}
663
665 ArrayRef<std::unique_ptr<CoverageMappingReader>> CoverageReaders,
666 IndexedInstrProfReader &ProfileReader) {
667 auto Coverage = std::unique_ptr<CoverageMapping>(new CoverageMapping());
668 if (Error E = loadFromReaders(CoverageReaders, ProfileReader, *Coverage))
669 return std::move(E);
670 return std::move(Coverage);
671}
672
673// If E is a no_data_found error, returns success. Otherwise returns E.
675 return handleErrors(
676 std::move(E), [](const CoverageMapError &CME) {
678 return static_cast<Error>(Error::success());
679 return make_error<CoverageMapError>(CME.get(), CME.getMessage());
680 });
681}
682
683Error CoverageMapping::loadFromFile(
684 StringRef Filename, StringRef Arch, StringRef CompilationDir,
685 IndexedInstrProfReader &ProfileReader, CoverageMapping &Coverage,
686 bool &DataFound, SmallVectorImpl<object::BuildID> *FoundBinaryIDs) {
687 auto CovMappingBufOrErr = MemoryBuffer::getFileOrSTDIN(
688 Filename, /*IsText=*/false, /*RequiresNullTerminator=*/false);
689 if (std::error_code EC = CovMappingBufOrErr.getError())
690 return createFileError(Filename, errorCodeToError(EC));
691 MemoryBufferRef CovMappingBufRef =
692 CovMappingBufOrErr.get()->getMemBufferRef();
694 InstrProfSymtab &ProfSymTab = ProfileReader.getSymtab();
695
697 auto CoverageReadersOrErr = BinaryCoverageReader::create(
698 CovMappingBufRef, Arch, Buffers, ProfSymTab,
699 CompilationDir, FoundBinaryIDs ? &BinaryIDs : nullptr);
700 if (Error E = CoverageReadersOrErr.takeError()) {
701 E = handleMaybeNoDataFoundError(std::move(E));
702 if (E)
703 return createFileError(Filename, std::move(E));
704 return E;
705 }
706
708 for (auto &Reader : CoverageReadersOrErr.get())
709 Readers.push_back(std::move(Reader));
710 if (FoundBinaryIDs && !Readers.empty()) {
711 llvm::append_range(*FoundBinaryIDs,
712 llvm::map_range(BinaryIDs, [](object::BuildIDRef BID) {
713 return object::BuildID(BID);
714 }));
715 }
716 DataFound |= !Readers.empty();
717 if (Error E = loadFromReaders(Readers, ProfileReader, Coverage))
718 return createFileError(Filename, std::move(E));
719 return Error::success();
720}
721
723 ArrayRef<StringRef> ObjectFilenames, StringRef ProfileFilename,
724 vfs::FileSystem &FS, ArrayRef<StringRef> Arches, StringRef CompilationDir,
725 const object::BuildIDFetcher *BIDFetcher, bool CheckBinaryIDs) {
726 auto ProfileReaderOrErr = IndexedInstrProfReader::create(ProfileFilename, FS);
727 if (Error E = ProfileReaderOrErr.takeError())
728 return createFileError(ProfileFilename, std::move(E));
729 auto ProfileReader = std::move(ProfileReaderOrErr.get());
730 auto Coverage = std::unique_ptr<CoverageMapping>(new CoverageMapping());
731 bool DataFound = false;
732
733 auto GetArch = [&](size_t Idx) {
734 if (Arches.empty())
735 return StringRef();
736 if (Arches.size() == 1)
737 return Arches.front();
738 return Arches[Idx];
739 };
740
741 SmallVector<object::BuildID> FoundBinaryIDs;
742 for (const auto &File : llvm::enumerate(ObjectFilenames)) {
743 if (Error E =
744 loadFromFile(File.value(), GetArch(File.index()), CompilationDir,
745 *ProfileReader, *Coverage, DataFound, &FoundBinaryIDs))
746 return std::move(E);
747 }
748
749 if (BIDFetcher) {
750 std::vector<object::BuildID> ProfileBinaryIDs;
751 if (Error E = ProfileReader->readBinaryIds(ProfileBinaryIDs))
752 return createFileError(ProfileFilename, std::move(E));
753
754 SmallVector<object::BuildIDRef> BinaryIDsToFetch;
755 if (!ProfileBinaryIDs.empty()) {
756 const auto &Compare = [](object::BuildIDRef A, object::BuildIDRef B) {
757 return std::lexicographical_compare(A.begin(), A.end(), B.begin(),
758 B.end());
759 };
760 llvm::sort(FoundBinaryIDs, Compare);
761 std::set_difference(
762 ProfileBinaryIDs.begin(), ProfileBinaryIDs.end(),
763 FoundBinaryIDs.begin(), FoundBinaryIDs.end(),
764 std::inserter(BinaryIDsToFetch, BinaryIDsToFetch.end()), Compare);
765 }
766
767 for (object::BuildIDRef BinaryID : BinaryIDsToFetch) {
768 std::optional<std::string> PathOpt = BIDFetcher->fetch(BinaryID);
769 if (PathOpt) {
770 std::string Path = std::move(*PathOpt);
771 StringRef Arch = Arches.size() == 1 ? Arches.front() : StringRef();
772 if (Error E = loadFromFile(Path, Arch, CompilationDir, *ProfileReader,
773 *Coverage, DataFound))
774 return std::move(E);
775 } else if (CheckBinaryIDs) {
776 return createFileError(
777 ProfileFilename,
779 "Missing binary ID: " +
780 llvm::toHex(BinaryID, /*LowerCase=*/true)));
781 }
782 }
783 }
784
785 if (!DataFound)
786 return createFileError(
787 join(ObjectFilenames.begin(), ObjectFilenames.end(), ", "),
788 make_error<CoverageMapError>(coveragemap_error::no_data_found));
789 return std::move(Coverage);
790}
791
792namespace {
793
794/// Distributes functions into instantiation sets.
795///
796/// An instantiation set is a collection of functions that have the same source
797/// code, ie, template functions specializations.
798class FunctionInstantiationSetCollector {
799 using MapT = std::map<LineColPair, std::vector<const FunctionRecord *>>;
800 MapT InstantiatedFunctions;
801
802public:
803 void insert(const FunctionRecord &Function, unsigned FileID) {
804 auto I = Function.CountedRegions.begin(), E = Function.CountedRegions.end();
805 while (I != E && I->FileID != FileID)
806 ++I;
807 assert(I != E && "function does not cover the given file");
808 auto &Functions = InstantiatedFunctions[I->startLoc()];
809 Functions.push_back(&Function);
810 }
811
812 MapT::iterator begin() { return InstantiatedFunctions.begin(); }
813 MapT::iterator end() { return InstantiatedFunctions.end(); }
814};
815
816class SegmentBuilder {
817 std::vector<CoverageSegment> &Segments;
819
820 SegmentBuilder(std::vector<CoverageSegment> &Segments) : Segments(Segments) {}
821
822 /// Emit a segment with the count from \p Region starting at \p StartLoc.
823 //
824 /// \p IsRegionEntry: The segment is at the start of a new non-gap region.
825 /// \p EmitSkippedRegion: The segment must be emitted as a skipped region.
826 void startSegment(const CountedRegion &Region, LineColPair StartLoc,
827 bool IsRegionEntry, bool EmitSkippedRegion = false) {
828 bool HasCount = !EmitSkippedRegion &&
830
831 // If the new segment wouldn't affect coverage rendering, skip it.
832 if (!Segments.empty() && !IsRegionEntry && !EmitSkippedRegion) {
833 const auto &Last = Segments.back();
834 if (Last.HasCount == HasCount && Last.Count == Region.ExecutionCount &&
835 !Last.IsRegionEntry)
836 return;
837 }
838
839 if (HasCount)
840 Segments.emplace_back(StartLoc.first, StartLoc.second,
841 Region.ExecutionCount, IsRegionEntry,
843 else
844 Segments.emplace_back(StartLoc.first, StartLoc.second, IsRegionEntry);
845
846 LLVM_DEBUG({
847 const auto &Last = Segments.back();
848 dbgs() << "Segment at " << Last.Line << ":" << Last.Col
849 << " (count = " << Last.Count << ")"
850 << (Last.IsRegionEntry ? ", RegionEntry" : "")
851 << (!Last.HasCount ? ", Skipped" : "")
852 << (Last.IsGapRegion ? ", Gap" : "") << "\n";
853 });
854 }
855
856 /// Emit segments for active regions which end before \p Loc.
857 ///
858 /// \p Loc: The start location of the next region. If std::nullopt, all active
859 /// regions are completed.
860 /// \p FirstCompletedRegion: Index of the first completed region.
861 void completeRegionsUntil(std::optional<LineColPair> Loc,
862 unsigned FirstCompletedRegion) {
863 // Sort the completed regions by end location. This makes it simple to
864 // emit closing segments in sorted order.
865 auto CompletedRegionsIt = ActiveRegions.begin() + FirstCompletedRegion;
866 std::stable_sort(CompletedRegionsIt, ActiveRegions.end(),
867 [](const CountedRegion *L, const CountedRegion *R) {
868 return L->endLoc() < R->endLoc();
869 });
870
871 // Emit segments for all completed regions.
872 for (unsigned I = FirstCompletedRegion + 1, E = ActiveRegions.size(); I < E;
873 ++I) {
874 const auto *CompletedRegion = ActiveRegions[I];
875 assert((!Loc || CompletedRegion->endLoc() <= *Loc) &&
876 "Completed region ends after start of new region");
877
878 const auto *PrevCompletedRegion = ActiveRegions[I - 1];
879 auto CompletedSegmentLoc = PrevCompletedRegion->endLoc();
880
881 // Don't emit any more segments if they start where the new region begins.
882 if (Loc && CompletedSegmentLoc == *Loc)
883 break;
884
885 // Don't emit a segment if the next completed region ends at the same
886 // location as this one.
887 if (CompletedSegmentLoc == CompletedRegion->endLoc())
888 continue;
889
890 // Use the count from the last completed region which ends at this loc.
891 for (unsigned J = I + 1; J < E; ++J)
892 if (CompletedRegion->endLoc() == ActiveRegions[J]->endLoc())
893 CompletedRegion = ActiveRegions[J];
894
895 startSegment(*CompletedRegion, CompletedSegmentLoc, false);
896 }
897
898 auto Last = ActiveRegions.back();
899 if (FirstCompletedRegion && Last->endLoc() != *Loc) {
900 // If there's a gap after the end of the last completed region and the
901 // start of the new region, use the last active region to fill the gap.
902 startSegment(*ActiveRegions[FirstCompletedRegion - 1], Last->endLoc(),
903 false);
904 } else if (!FirstCompletedRegion && (!Loc || *Loc != Last->endLoc())) {
905 // Emit a skipped segment if there are no more active regions. This
906 // ensures that gaps between functions are marked correctly.
907 startSegment(*Last, Last->endLoc(), false, true);
908 }
909
910 // Pop the completed regions.
911 ActiveRegions.erase(CompletedRegionsIt, ActiveRegions.end());
912 }
913
914 void buildSegmentsImpl(ArrayRef<CountedRegion> Regions) {
915 for (const auto &CR : enumerate(Regions)) {
916 auto CurStartLoc = CR.value().startLoc();
917
918 // Active regions which end before the current region need to be popped.
919 auto CompletedRegions =
920 std::stable_partition(ActiveRegions.begin(), ActiveRegions.end(),
921 [&](const CountedRegion *Region) {
922 return !(Region->endLoc() <= CurStartLoc);
923 });
924 if (CompletedRegions != ActiveRegions.end()) {
925 unsigned FirstCompletedRegion =
926 std::distance(ActiveRegions.begin(), CompletedRegions);
927 completeRegionsUntil(CurStartLoc, FirstCompletedRegion);
928 }
929
930 bool GapRegion = CR.value().Kind == CounterMappingRegion::GapRegion;
931
932 // Try to emit a segment for the current region.
933 if (CurStartLoc == CR.value().endLoc()) {
934 // Avoid making zero-length regions active. If it's the last region,
935 // emit a skipped segment. Otherwise use its predecessor's count.
936 const bool Skipped =
937 (CR.index() + 1) == Regions.size() ||
938 CR.value().Kind == CounterMappingRegion::SkippedRegion;
939 startSegment(ActiveRegions.empty() ? CR.value() : *ActiveRegions.back(),
940 CurStartLoc, !GapRegion, Skipped);
941 // If it is skipped segment, create a segment with last pushed
942 // regions's count at CurStartLoc.
943 if (Skipped && !ActiveRegions.empty())
944 startSegment(*ActiveRegions.back(), CurStartLoc, false);
945 continue;
946 }
947 if (CR.index() + 1 == Regions.size() ||
948 CurStartLoc != Regions[CR.index() + 1].startLoc()) {
949 // Emit a segment if the next region doesn't start at the same location
950 // as this one.
951 startSegment(CR.value(), CurStartLoc, !GapRegion);
952 }
953
954 // This region is active (i.e not completed).
955 ActiveRegions.push_back(&CR.value());
956 }
957
958 // Complete any remaining active regions.
959 if (!ActiveRegions.empty())
960 completeRegionsUntil(std::nullopt, 0);
961 }
962
963 /// Sort a nested sequence of regions from a single file.
964 static void sortNestedRegions(MutableArrayRef<CountedRegion> Regions) {
965 llvm::sort(Regions, [](const CountedRegion &LHS, const CountedRegion &RHS) {
966 if (LHS.startLoc() != RHS.startLoc())
967 return LHS.startLoc() < RHS.startLoc();
968 if (LHS.endLoc() != RHS.endLoc())
969 // When LHS completely contains RHS, we sort LHS first.
970 return RHS.endLoc() < LHS.endLoc();
971 // If LHS and RHS cover the same area, we need to sort them according
972 // to their kinds so that the most suitable region will become "active"
973 // in combineRegions(). Because we accumulate counter values only from
974 // regions of the same kind as the first region of the area, prefer
975 // CodeRegion to ExpansionRegion and ExpansionRegion to SkippedRegion.
980 "Unexpected order of region kind values");
981 return LHS.Kind < RHS.Kind;
982 });
983 }
984
985 /// Combine counts of regions which cover the same area.
987 combineRegions(MutableArrayRef<CountedRegion> Regions) {
988 if (Regions.empty())
989 return Regions;
990 auto Active = Regions.begin();
991 auto End = Regions.end();
992 for (auto I = Regions.begin() + 1; I != End; ++I) {
993 if (Active->startLoc() != I->startLoc() ||
994 Active->endLoc() != I->endLoc()) {
995 // Shift to the next region.
996 ++Active;
997 if (Active != I)
998 *Active = *I;
999 continue;
1000 }
1001 // Merge duplicate region.
1002 // If CodeRegions and ExpansionRegions cover the same area, it's probably
1003 // a macro which is fully expanded to another macro. In that case, we need
1004 // to accumulate counts only from CodeRegions, or else the area will be
1005 // counted twice.
1006 // On the other hand, a macro may have a nested macro in its body. If the
1007 // outer macro is used several times, the ExpansionRegion for the nested
1008 // macro will also be added several times. These ExpansionRegions cover
1009 // the same source locations and have to be combined to reach the correct
1010 // value for that area.
1011 // We add counts of the regions of the same kind as the active region
1012 // to handle the both situations.
1013 if (I->Kind == Active->Kind)
1014 Active->ExecutionCount += I->ExecutionCount;
1015 }
1016 return Regions.drop_back(std::distance(++Active, End));
1017 }
1018
1019public:
1020 /// Build a sorted list of CoverageSegments from a list of Regions.
1021 static std::vector<CoverageSegment>
1022 buildSegments(MutableArrayRef<CountedRegion> Regions) {
1023 std::vector<CoverageSegment> Segments;
1024 SegmentBuilder Builder(Segments);
1025
1026 sortNestedRegions(Regions);
1027 ArrayRef<CountedRegion> CombinedRegions = combineRegions(Regions);
1028
1029 LLVM_DEBUG({
1030 dbgs() << "Combined regions:\n";
1031 for (const auto &CR : CombinedRegions)
1032 dbgs() << " " << CR.LineStart << ":" << CR.ColumnStart << " -> "
1033 << CR.LineEnd << ":" << CR.ColumnEnd
1034 << " (count=" << CR.ExecutionCount << ")\n";
1035 });
1036
1037 Builder.buildSegmentsImpl(CombinedRegions);
1038
1039#ifndef NDEBUG
1040 for (unsigned I = 1, E = Segments.size(); I < E; ++I) {
1041 const auto &L = Segments[I - 1];
1042 const auto &R = Segments[I];
1043 if (!(L.Line < R.Line) && !(L.Line == R.Line && L.Col < R.Col)) {
1044 if (L.Line == R.Line && L.Col == R.Col && !L.HasCount)
1045 continue;
1046 LLVM_DEBUG(dbgs() << " ! Segment " << L.Line << ":" << L.Col
1047 << " followed by " << R.Line << ":" << R.Col << "\n");
1048 assert(false && "Coverage segments not unique or sorted");
1049 }
1050 }
1051#endif
1052
1053 return Segments;
1054 }
1055};
1056
1057} // end anonymous namespace
1058
1059std::vector<StringRef> CoverageMapping::getUniqueSourceFiles() const {
1060 std::vector<StringRef> Filenames;
1061 for (const auto &Function : getCoveredFunctions())
1062 llvm::append_range(Filenames, Function.Filenames);
1063 llvm::sort(Filenames);
1064 auto Last = std::unique(Filenames.begin(), Filenames.end());
1065 Filenames.erase(Last, Filenames.end());
1066 return Filenames;
1067}
1068
1070 const FunctionRecord &Function) {
1071 SmallBitVector FilenameEquivalence(Function.Filenames.size(), false);
1072 for (unsigned I = 0, E = Function.Filenames.size(); I < E; ++I)
1073 if (SourceFile == Function.Filenames[I])
1074 FilenameEquivalence[I] = true;
1075 return FilenameEquivalence;
1076}
1077
1078/// Return the ID of the file where the definition of the function is located.
1079static std::optional<unsigned>
1081 SmallBitVector IsNotExpandedFile(Function.Filenames.size(), true);
1082 for (const auto &CR : Function.CountedRegions)
1084 IsNotExpandedFile[CR.ExpandedFileID] = false;
1085 int I = IsNotExpandedFile.find_first();
1086 if (I == -1)
1087 return std::nullopt;
1088 return I;
1089}
1090
1091/// Check if SourceFile is the file that contains the definition of
1092/// the Function. Return the ID of the file in that case or std::nullopt
1093/// otherwise.
1094static std::optional<unsigned>
1096 std::optional<unsigned> I = findMainViewFileID(Function);
1097 if (I && SourceFile == Function.Filenames[*I])
1098 return I;
1099 return std::nullopt;
1100}
1101
1102static bool isExpansion(const CountedRegion &R, unsigned FileID) {
1103 return R.Kind == CounterMappingRegion::ExpansionRegion && R.FileID == FileID;
1104}
1105
1107 CoverageData FileCoverage(Filename);
1108 std::vector<CountedRegion> Regions;
1109
1110 // Look up the function records in the given file. Due to hash collisions on
1111 // the filename, we may get back some records that are not in the file.
1112 ArrayRef<unsigned> RecordIndices =
1113 getImpreciseRecordIndicesForFilename(Filename);
1114 for (unsigned RecordIndex : RecordIndices) {
1115 const FunctionRecord &Function = Functions[RecordIndex];
1116 auto MainFileID = findMainViewFileID(Filename, Function);
1117 auto FileIDs = gatherFileIDs(Filename, Function);
1118 for (const auto &CR : Function.CountedRegions)
1119 if (FileIDs.test(CR.FileID)) {
1120 Regions.push_back(CR);
1121 if (MainFileID && isExpansion(CR, *MainFileID))
1122 FileCoverage.Expansions.emplace_back(CR, Function);
1123 }
1124 // Capture branch regions specific to the function (excluding expansions).
1125 for (const auto &CR : Function.CountedBranchRegions)
1126 if (FileIDs.test(CR.FileID) && (CR.FileID == CR.ExpandedFileID))
1127 FileCoverage.BranchRegions.push_back(CR);
1128 // Capture MCDC records specific to the function.
1129 for (const auto &MR : Function.MCDCRecords)
1130 if (FileIDs.test(MR.getDecisionRegion().FileID))
1131 FileCoverage.MCDCRecords.push_back(MR);
1132 }
1133
1134 LLVM_DEBUG(dbgs() << "Emitting segments for file: " << Filename << "\n");
1135 FileCoverage.Segments = SegmentBuilder::buildSegments(Regions);
1136
1137 return FileCoverage;
1138}
1139
1140std::vector<InstantiationGroup>
1142 FunctionInstantiationSetCollector InstantiationSetCollector;
1143 // Look up the function records in the given file. Due to hash collisions on
1144 // the filename, we may get back some records that are not in the file.
1145 ArrayRef<unsigned> RecordIndices =
1146 getImpreciseRecordIndicesForFilename(Filename);
1147 for (unsigned RecordIndex : RecordIndices) {
1148 const FunctionRecord &Function = Functions[RecordIndex];
1149 auto MainFileID = findMainViewFileID(Filename, Function);
1150 if (!MainFileID)
1151 continue;
1152 InstantiationSetCollector.insert(Function, *MainFileID);
1153 }
1154
1155 std::vector<InstantiationGroup> Result;
1156 for (auto &InstantiationSet : InstantiationSetCollector) {
1157 InstantiationGroup IG{InstantiationSet.first.first,
1158 InstantiationSet.first.second,
1159 std::move(InstantiationSet.second)};
1160 Result.emplace_back(std::move(IG));
1161 }
1162 return Result;
1163}
1164
1167 auto MainFileID = findMainViewFileID(Function);
1168 if (!MainFileID)
1169 return CoverageData();
1170
1171 CoverageData FunctionCoverage(Function.Filenames[*MainFileID]);
1172 std::vector<CountedRegion> Regions;
1173 for (const auto &CR : Function.CountedRegions)
1174 if (CR.FileID == *MainFileID) {
1175 Regions.push_back(CR);
1176 if (isExpansion(CR, *MainFileID))
1177 FunctionCoverage.Expansions.emplace_back(CR, Function);
1178 }
1179 // Capture branch regions specific to the function (excluding expansions).
1180 for (const auto &CR : Function.CountedBranchRegions)
1181 if (CR.FileID == *MainFileID)
1182 FunctionCoverage.BranchRegions.push_back(CR);
1183
1184 // Capture MCDC records specific to the function.
1185 for (const auto &MR : Function.MCDCRecords)
1186 if (MR.getDecisionRegion().FileID == *MainFileID)
1187 FunctionCoverage.MCDCRecords.push_back(MR);
1188
1189 LLVM_DEBUG(dbgs() << "Emitting segments for function: " << Function.Name
1190 << "\n");
1191 FunctionCoverage.Segments = SegmentBuilder::buildSegments(Regions);
1192
1193 return FunctionCoverage;
1194}
1195
1197 const ExpansionRecord &Expansion) const {
1198 CoverageData ExpansionCoverage(
1199 Expansion.Function.Filenames[Expansion.FileID]);
1200 std::vector<CountedRegion> Regions;
1201 for (const auto &CR : Expansion.Function.CountedRegions)
1202 if (CR.FileID == Expansion.FileID) {
1203 Regions.push_back(CR);
1204 if (isExpansion(CR, Expansion.FileID))
1205 ExpansionCoverage.Expansions.emplace_back(CR, Expansion.Function);
1206 }
1207 for (const auto &CR : Expansion.Function.CountedBranchRegions)
1208 // Capture branch regions that only pertain to the corresponding expansion.
1209 if (CR.FileID == Expansion.FileID)
1210 ExpansionCoverage.BranchRegions.push_back(CR);
1211
1212 LLVM_DEBUG(dbgs() << "Emitting segments for expansion of file "
1213 << Expansion.FileID << "\n");
1214 ExpansionCoverage.Segments = SegmentBuilder::buildSegments(Regions);
1215
1216 return ExpansionCoverage;
1217}
1218
1219LineCoverageStats::LineCoverageStats(
1221 const CoverageSegment *WrappedSegment, unsigned Line)
1222 : ExecutionCount(0), HasMultipleRegions(false), Mapped(false), Line(Line),
1223 LineSegments(LineSegments), WrappedSegment(WrappedSegment) {
1224 // Find the minimum number of regions which start in this line.
1225 unsigned MinRegionCount = 0;
1226 auto isStartOfRegion = [](const CoverageSegment *S) {
1227 return !S->IsGapRegion && S->HasCount && S->IsRegionEntry;
1228 };
1229 for (unsigned I = 0; I < LineSegments.size() && MinRegionCount < 2; ++I)
1230 if (isStartOfRegion(LineSegments[I]))
1231 ++MinRegionCount;
1232
1233 bool StartOfSkippedRegion = !LineSegments.empty() &&
1234 !LineSegments.front()->HasCount &&
1235 LineSegments.front()->IsRegionEntry;
1236
1237 HasMultipleRegions = MinRegionCount > 1;
1238 Mapped =
1239 !StartOfSkippedRegion &&
1240 ((WrappedSegment && WrappedSegment->HasCount) || (MinRegionCount > 0));
1241
1242 if (!Mapped)
1243 return;
1244
1245 // Pick the max count from the non-gap, region entry segments and the
1246 // wrapped count.
1247 if (WrappedSegment)
1248 ExecutionCount = WrappedSegment->Count;
1249 if (!MinRegionCount)
1250 return;
1251 for (const auto *LS : LineSegments)
1252 if (isStartOfRegion(LS))
1253 ExecutionCount = std::max(ExecutionCount, LS->Count);
1254}
1255
1257 if (Next == CD.end()) {
1258 Stats = LineCoverageStats();
1259 Ended = true;
1260 return *this;
1261 }
1262 if (Segments.size())
1263 WrappedSegment = Segments.back();
1264 Segments.clear();
1265 while (Next != CD.end() && Next->Line == Line)
1266 Segments.push_back(&*Next++);
1267 Stats = LineCoverageStats(Segments, WrappedSegment, Line);
1268 ++Line;
1269 return *this;
1270}
1271
1273 const std::string &ErrMsg = "") {
1274 std::string Msg;
1276
1277 switch ((uint32_t)Err) {
1279 OS << "success";
1280 break;
1282 OS << "end of File";
1283 break;
1285 OS << "no coverage data found";
1286 break;
1288 OS << "unsupported coverage format version";
1289 break;
1291 OS << "truncated coverage data";
1292 break;
1294 OS << "malformed coverage data";
1295 break;
1297 OS << "failed to decompress coverage data (zlib)";
1298 break;
1300 OS << "`-arch` specifier is invalid or missing for universal binary";
1301 break;
1302 default:
1303 llvm_unreachable("invalid coverage mapping error.");
1304 }
1305
1306 // If optional error message is not empty, append it to the message.
1307 if (!ErrMsg.empty())
1308 OS << ": " << ErrMsg;
1309
1310 return Msg;
1311}
1312
1313namespace {
1314
1315// FIXME: This class is only here to support the transition to llvm::Error. It
1316// will be removed once this transition is complete. Clients should prefer to
1317// deal with the Error value directly, rather than converting to error_code.
1318class CoverageMappingErrorCategoryType : public std::error_category {
1319 const char *name() const noexcept override { return "llvm.coveragemap"; }
1320 std::string message(int IE) const override {
1321 return getCoverageMapErrString(static_cast<coveragemap_error>(IE));
1322 }
1323};
1324
1325} // end anonymous namespace
1326
1327std::string CoverageMapError::message() const {
1328 return getCoverageMapErrString(Err, Msg);
1329}
1330
1331const std::error_category &llvm::coverage::coveragemap_category() {
1332 static CoverageMappingErrorCategoryType ErrorCategory;
1333 return ErrorCategory;
1334}
1335
1336char CoverageMapError::ID = 0;
aarch64 promote const
assume Assume Builder
This file declares a library for handling Build IDs and using them to find debug info.
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static SmallBitVector gatherFileIDs(StringRef SourceFile, const FunctionRecord &Function)
static std::optional< unsigned > findMainViewFileID(const FunctionRecord &Function)
Return the ID of the file where the definition of the function is located.
static bool isExpansion(const CountedRegion &R, unsigned FileID)
static Error handleMaybeNoDataFoundError(Error E)
static std::string getCoverageMapErrString(coveragemap_error Err, const std::string &ErrMsg="")
static unsigned getMaxBitmapSize(const CounterMappingContext &Ctx, const CoverageMappingRecord &Record)
static unsigned getMaxCounterID(const CounterMappingContext &Ctx, const CoverageMappingRecord &Record)
Returns the sub type a function will return at a given Idx Should correspond to the result type of an ExtractValue instruction executed with just that one unsigned Idx
#define LLVM_DEBUG(X)
Definition: Debug.h:101
This file defines the DenseMap class.
bool End
Definition: ELF_riscv.cpp:469
hexagon bit simplify
#define I(x, y, z)
Definition: MD5.cpp:58
if(VerifyEach)
const SmallVectorImpl< MachineOperand > & Cond
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
static const char * name
Definition: SMEABIPass.cpp:49
raw_pwrite_stream & OS
This file implements the SmallBitVector class.
This file defines the SmallString class.
This file defines the SmallVector class.
This file contains some functions that are useful when dealing with strings.
Defines the virtual file system interface vfs::FileSystem.
Value * RHS
Value * LHS
MCDCRecordProcessor(BitVector &Bitmap, CounterMappingRegion &Region, ArrayRef< CounterMappingRegion > Branches)
MCDCRecord processMCDCRecord()
Process the MC/DC Record in order to produce a result for a boolean expression.
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition: ArrayRef.h:41
const T & front() const
front - Get the first element.
Definition: ArrayRef.h:168
iterator end() const
Definition: ArrayRef.h:154
size_t size() const
size - Get the array size.
Definition: ArrayRef.h:165
iterator begin() const
Definition: ArrayRef.h:153
bool empty() const
empty - Check if the array is empty.
Definition: ArrayRef.h:160
size_type size() const
size - Returns the number of bits in this bitvector.
Definition: BitVector.h:159
Lightweight error class with error context and mandatory checking.
Definition: Error.h:154
static ErrorSuccess success()
Create a success value.
Definition: Error.h:328
Tagged union holding either a T or a Error.
Definition: Error.h:468
Error takeError()
Take ownership of the stored error.
Definition: Error.h:595
iterator begin()
Definition: Function.h:763
size_t size() const
Definition: Function.h:768
iterator end()
Definition: Function.h:765
Reader for the indexed binary instrprof format.
static Expected< std::unique_ptr< IndexedInstrProfReader > > create(const Twine &Path, vfs::FileSystem &FS, const Twine &RemappingPath="")
Factory method to create an indexed reader.
InstrProfSymtab & getSymtab() override
Return the PGO symtab.
Error getFunctionCounts(StringRef FuncName, uint64_t FuncHash, std::vector< uint64_t > &Counts)
Fill Counts with the profile data for the given function name.
Error getFunctionBitmapBytes(StringRef FuncName, uint64_t FuncHash, std::vector< uint8_t > &BitmapBytes)
Fill Bitmap Bytes with the profile data for the given function name.
Error readBinaryIds(std::vector< llvm::object::BuildID > &BinaryIds) override
Read a list of binary ids.
static std::pair< instrprof_error, std::string > take(Error E)
Consume an Error and return the raw enum value contained within it, and the optional error message.
Definition: InstrProf.h:392
A symbol table used for function PGO name look-up with keys (such as pointers, md5hash values) to the...
Definition: InstrProf.h:427
static ErrorOr< std::unique_ptr< MemoryBuffer > > getFileOrSTDIN(const Twine &Filename, bool IsText=false, bool RequiresNullTerminator=true, std::optional< Align > Alignment=std::nullopt)
Open the specified file as a MemoryBuffer, or open stdin if the Filename is "-".
MutableArrayRef - Represent a mutable reference to an array (0 or more elements consecutively in memo...
Definition: ArrayRef.h:307
iterator end() const
Definition: ArrayRef.h:357
iterator begin() const
Definition: ArrayRef.h:356
MutableArrayRef< T > drop_back(size_t N=1) const
Definition: ArrayRef.h:392
This is a 'bitvector' (really, a variable-sized bit array), optimized for the case when the array is ...
int find_first() const
Returns the index of the first set bit, -1 if none of the bits are set.
bool empty() const
Definition: SmallVector.h:94
size_t size() const
Definition: SmallVector.h:91
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
Definition: SmallVector.h:577
reference emplace_back(ArgTypes &&... Args)
Definition: SmallVector.h:941
iterator erase(const_iterator CI)
Definition: SmallVector.h:741
void push_back(const T &Elt)
Definition: SmallVector.h:416
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1200
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:50
constexpr bool empty() const
empty - Check if the string is empty.
Definition: StringRef.h:134
LLVM Value Representation.
Definition: Value.h:74
static Expected< std::vector< std::unique_ptr< BinaryCoverageReader > > > create(MemoryBufferRef ObjectBuffer, StringRef Arch, SmallVectorImpl< std::unique_ptr< MemoryBuffer > > &ObjectFileBuffers, InstrProfSymtab &IndexedProfSymTab, StringRef CompilationDir="", SmallVectorImpl< object::BuildIDRef > *BinaryIDs=nullptr)
Counter subtract(Counter LHS, Counter RHS, bool Simplify=true)
Return a counter that represents the expression that subtracts RHS from LHS.
Counter add(Counter LHS, Counter RHS, bool Simplify=true)
Return a counter that represents the expression that adds LHS and RHS.
A Counter mapping context is used to connect the counters, expressions and the obtained counter value...
Expected< BitVector > evaluateBitmap(const CounterMappingRegion *MCDCDecision) const
Return the number of times that a region of code associated with this counter was executed.
Expected< MCDCRecord > evaluateMCDCRegion(CounterMappingRegion Region, BitVector Bitmap, ArrayRef< CounterMappingRegion > Branches)
Return an MCDC record that indicates executed test vectors and condition pairs.
Expected< int64_t > evaluate(const Counter &C) const
Return the number of times that a region of code associated with this counter was executed.
unsigned getMaxCounterID(const Counter &C) const
void dump(const Counter &C, raw_ostream &OS) const
Coverage information to be processed or displayed.
std::vector< CoverageSegment >::const_iterator end() const
std::string message() const override
Return the error message as a string.
coveragemap_error get() const
const std::string & getMessage() const
The mapping of profile information to coverage data.
std::vector< StringRef > getUniqueSourceFiles() const
Returns a lexicographically sorted, unique list of files that are covered.
CoverageData getCoverageForExpansion(const ExpansionRecord &Expansion) const
Get the coverage for an expansion within a coverage set.
iterator_range< FunctionRecordIterator > getCoveredFunctions() const
Gets all of the functions covered by this profile.
CoverageData getCoverageForFunction(const FunctionRecord &Function) const
Get the coverage for a particular function.
std::vector< InstantiationGroup > getInstantiationGroups(StringRef Filename) const
Get the list of function instantiation groups in a particular file.
CoverageData getCoverageForFile(StringRef Filename) const
Get the coverage for a particular file.
static Expected< std::unique_ptr< CoverageMapping > > load(ArrayRef< std::unique_ptr< CoverageMappingReader > > CoverageReaders, IndexedInstrProfReader &ProfileReader)
Load the coverage mapping using the given readers.
An instantiation group contains a FunctionRecord list, such that each record corresponds to a distinc...
An iterator over the LineCoverageStats objects for lines described by a CoverageData instance.
Coverage statistics for a single line.
BuildIDFetcher searches local cache directories for debug info.
Definition: BuildID.h:39
virtual std::optional< std::string > fetch(BuildIDRef BuildID) const
Returns the path to the debug file with the given build ID.
Definition: BuildID.cpp:68
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition: raw_ostream.h:52
A raw_ostream that writes to an std::string.
Definition: raw_ostream.h:642
The virtual file system interface.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition: CallingConv.h:24
@ C
The default llvm calling convention, compatible with C.
Definition: CallingConv.h:34
const std::error_category & coveragemap_category()
std::pair< unsigned, unsigned > LineColPair
SmallVector< uint8_t, 10 > BuildID
A build ID in binary form.
Definition: BuildID.h:25
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
hash_code hash_value(const FixedPointSemantics &Val)
Definition: APFixedPoint.h:128
Error createFileError(const Twine &F, Error E)
Concatenate a source file path and/or name with an Error.
Definition: Error.h:1319
auto enumerate(FirstRange &&First, RestRanges &&...Rest)
Given two or more input ranges, returns a new range whose values are are tuples (A,...
Definition: STLExtras.h:2338
StringRef getFuncNameWithoutPrefix(StringRef PGOFuncName, StringRef FileName="<unknown>")
Given a PGO function name, remove the filename prefix and return the original (static) function name.
Definition: InstrProf.cpp:370
Error handleErrors(Error E, HandlerTs &&... Hs)
Pass the ErrorInfo(s) contained in E to their respective handlers.
Definition: Error.h:941
void append_range(Container &C, Range &&R)
Wrapper function to append a range to a container.
Definition: STLExtras.h:2037
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
Definition: Error.h:1238
auto map_range(ContainerTy &&C, FuncTy F)
Definition: STLExtras.h:378
@ no_such_file_or_directory
@ argument_out_of_domain
auto reverse(ContainerTy &&C)
Definition: STLExtras.h:429
void sort(IteratorTy Start, IteratorTy End)
Definition: STLExtras.h:1652
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:163
instrprof_error
Definition: InstrProf.h:323
uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
Definition: Alignment.h:155
Error errorCodeToError(std::error_code EC)
Helper for converting an std::error_code to a Error.
Definition: Error.cpp:103
void consumeError(Error Err)
Consume a Error without doing anything.
Definition: Error.h:1035
hash_code hash_combine_range(InputIteratorT first, InputIteratorT last)
Compute a hash_code for a sequence of values.
Definition: Hashing.h:491
#define NC
Definition: regutils.h:42
Associates a source range with an execution count.
A Counter expression is a value that represents an arithmetic operation with two counters.
unsigned NumConditions
Number of Conditions used for a Decision Region (MC/DC only).
unsigned BitmapIdx
Byte Index of Bitmap Coverage Object for a Decision Region (MC/DC only).
A Counter mapping region associates a source range with a specific counter.
MCDCParameters MCDCParams
Parameters used for Modified Condition/Decision Coverage.
@ ExpansionRegion
An ExpansionRegion represents a file expansion region that associates a source range with the expansi...
@ MCDCDecisionRegion
A DecisionRegion represents a top-level boolean expression and is associated with a variable length b...
@ MCDCBranchRegion
A Branch Region can be extended to include IDs to facilitate MC/DC.
@ SkippedRegion
A SkippedRegion represents a source range with code that was skipped by a preprocessor or similar mea...
@ GapRegion
A GapRegion is like a CodeRegion, but its count is only set as the line execution count when its the ...
@ CodeRegion
A CodeRegion associates some code with a counter.
A Counter is an abstract value that describes how to compute the execution count for a region of code...
static Counter getZero()
Return the counter that represents the number zero.
static Counter getCounter(unsigned CounterId)
Return the counter that corresponds to a specific profile counter.
static Counter getExpression(unsigned ExpressionId)
Return the counter that corresponds to a specific addition counter expression.
Coverage mapping information for a single function.
The execution count information starting at a point in a file.
bool HasCount
When false, the segment was uninstrumented or skipped.
uint64_t Count
The execution count, or zero if no count was recorded.
bool IsGapRegion
Whether this enters a gap region.
Coverage information for a macro expansion or #included file.
unsigned FileID
The abstract file this expansion covers.
const FunctionRecord & Function
Coverage for the expansion.
Code coverage information for a single function.
std::vector< CountedRegion > CountedBranchRegions
Branch Regions in the function along with their counts.
std::vector< CountedRegion > CountedRegions
Regions in the function along with their counts.
std::vector< std::string > Filenames
Mapping from FileID (i.e.
MCDC Record grouping all information together.