20 #include "llvm/ADT/Optional.h"
21 #include "llvm/ADT/SmallSet.h"
22 #include "llvm/ADT/StringExtras.h"
23 #include "llvm/ProfileData/Coverage/CoverageMapping.h"
24 #include "llvm/ProfileData/Coverage/CoverageMappingReader.h"
25 #include "llvm/ProfileData/Coverage/CoverageMappingWriter.h"
26 #include "llvm/ProfileData/InstrProfReader.h"
27 #include "llvm/Support/FileSystem.h"
28 #include "llvm/Support/Path.h"
35 "emptyline-comment-coverage",
36 llvm::cl::desc(
"Emit emptylines and comment lines as skipped regions (only "
37 "disable it on test)"),
38 llvm::cl::init(
true), llvm::cl::Hidden);
40 using namespace clang;
41 using namespace CodeGen;
42 using namespace llvm::coverage;
56 if (Tok.
getKind() != clang::tok::eod)
65 PrevTokLoc == SkippedRanges.back().PrevTokLoc &&
66 SourceMgr.isWrittenInSameFile(SkippedRanges.back().Range.getEnd(),
68 SkippedRanges.back().Range.setEnd(Range.getEnd());
70 SkippedRanges.push_back({Range, PrevTokLoc});
74 AddSkippedRange(Range);
78 AddSkippedRange(Range);
82 AddSkippedRange(Range);
87 if (!SkippedRanges.empty() && SkippedRanges.back().NextTokLoc.isInvalid())
88 SkippedRanges.back().NextTokLoc = Loc;
94 class SourceMappingRegion {
114 : Count(Count), LocStart(LocStart), LocEnd(LocEnd), GapRegion(GapRegion) {
120 : Count(Count), FalseCount(FalseCount), LocStart(LocStart),
121 LocEnd(LocEnd), GapRegion(GapRegion) {}
123 const Counter &getCounter()
const {
return Count; }
125 const Counter &getFalseCounter()
const {
126 assert(FalseCount &&
"Region has no alternate counter");
130 void setCounter(Counter C) { Count =
C; }
132 bool hasStartLoc()
const {
return LocStart.hasValue(); }
137 assert(LocStart &&
"Region has no start location");
141 bool hasEndLoc()
const {
return LocEnd.hasValue(); }
144 assert(Loc.
isValid() &&
"Setting an invalid end location");
149 assert(LocEnd &&
"Region has no end location");
153 bool isGap()
const {
return GapRegion; }
155 void setGap(
bool Gap) { GapRegion = Gap; }
157 bool isBranch()
const {
return FalseCount.hasValue(); }
161 struct SpellingRegion {
166 unsigned ColumnStart;
176 LineStart =
SM.getSpellingLineNumber(LocStart);
177 ColumnStart =
SM.getSpellingColumnNumber(LocStart);
178 LineEnd =
SM.getSpellingLineNumber(LocEnd);
179 ColumnEnd =
SM.getSpellingColumnNumber(LocEnd);
183 : SpellingRegion(
SM, R.getBeginLoc(), R.getEndLoc()) {}
187 bool isInSourceOrder()
const {
188 return (LineStart < LineEnd) ||
189 (LineStart == LineEnd && ColumnStart <= ColumnEnd);
195 class CoverageMappingBuilder {
203 llvm::SmallDenseMap<FileID, std::pair<unsigned, SourceLocation>, 8>
210 std::vector<SourceMappingRegion> SourceRegions;
217 typedef llvm::SmallSet<std::pair<SourceLocation, SourceLocation>, 8>
222 : CVM(CVM),
SM(
SM), LangOpts(LangOpts) {}
237 return SM.getLocForStartOfFile(
SM.getFileID(Loc));
244 SM.getFileOffset(Loc));
245 return SM.getLocForEndOfFile(
SM.getFileID(Loc));
250 return Loc.
isMacroID() ?
SM.getImmediateExpansionRange(Loc).getBegin()
251 :
SM.getIncludeLoc(
SM.getFileID(Loc));
256 return SM.getBufferName(
SM.getSpellingLoc(Loc)) ==
"<built-in>";
262 Loc = getIncludeOrExpansionLoc(Loc);
265 }
while (!
SM.isInFileID(Loc,
Parent));
272 while (
SM.isMacroArgExpansion(Loc) || isInBuiltin(Loc))
273 Loc =
SM.getImmediateExpansionRange(Loc).getBegin();
280 while (
SM.isMacroArgExpansion(Loc) || isInBuiltin(Loc))
281 Loc =
SM.getImmediateExpansionRange(Loc).getBegin();
282 return getPreciseTokenLocEnd(Loc);
291 FileIDMapping.clear();
293 llvm::SmallSet<FileID, 8> Visited;
295 for (
const auto &Region : SourceRegions) {
298 if (!Visited.insert(File).second)
302 if (
SM.isInSystemHeader(
SM.getSpellingLoc(Loc)))
309 FileLocs.push_back(std::make_pair(Loc,
Depth));
311 llvm::stable_sort(FileLocs, llvm::less_second());
313 for (
const auto &FL : FileLocs) {
315 FileID SpellingFile =
SM.getDecomposedSpellingLoc(Loc).first;
316 auto Entry =
SM.getFileEntryForID(SpellingFile);
320 FileIDMapping[
SM.getFileID(Loc)] = std::make_pair(Mapping.size(), Loc);
329 auto Mapping = FileIDMapping.find(
SM.getFileID(Loc));
330 if (Mapping != FileIDMapping.end())
331 return Mapping->second.first;
343 SpellingRegion SR{
SM, LocStart, LocEnd};
345 if (PrevTokLoc.
isValid() &&
SM.isWrittenInSameFile(LocStart, PrevTokLoc) &&
346 SR.LineStart ==
SM.getSpellingLineNumber(PrevTokLoc))
348 if (NextTokLoc.
isValid() &&
SM.isWrittenInSameFile(LocEnd, NextTokLoc) &&
349 SR.LineEnd ==
SM.getSpellingLineNumber(NextTokLoc)) {
353 if (SR.isInSourceOrder())
360 void gatherSkippedRegions() {
364 FileLineRanges.resize(
365 FileIDMapping.size(),
367 for (
const auto &R : MappingRegions) {
368 FileLineRanges[R.FileID].first =
369 std::min(FileLineRanges[R.FileID].first, R.LineStart);
370 FileLineRanges[R.FileID].second =
371 std::max(FileLineRanges[R.FileID].second, R.LineEnd);
375 for (
auto &I : SkippedRanges) {
377 auto LocStart =
Range.getBegin();
378 auto LocEnd =
Range.getEnd();
379 assert(
SM.isWrittenInSameFile(LocStart, LocEnd) &&
380 "region spans multiple files");
382 auto CovFileID = getCoverageFileID(LocStart);
386 adjustSkippedRange(
SM, LocStart, LocEnd, I.PrevTokLoc, I.NextTokLoc);
389 auto Region = CounterMappingRegion::makeSkipped(
390 *CovFileID, SR->LineStart, SR->ColumnStart, SR->LineEnd,
394 if (Region.LineStart >= FileLineRanges[*CovFileID].first &&
395 Region.LineEnd <= FileLineRanges[*CovFileID].second)
396 MappingRegions.push_back(Region);
402 void emitSourceRegions(
const SourceRegionFilter &
Filter) {
403 for (
const auto &Region : SourceRegions) {
404 assert(Region.hasEndLoc() &&
"incomplete region");
407 assert(
SM.getFileID(LocStart).isValid() &&
"region in invalid file");
410 if (
SM.isInSystemHeader(
SM.getSpellingLoc(LocStart)))
413 auto CovFileID = getCoverageFileID(LocStart);
419 assert(
SM.isWrittenInSameFile(LocStart, LocEnd) &&
420 "region spans multiple files");
426 if (
Filter.count(std::make_pair(LocStart, LocEnd)))
430 SpellingRegion SR{
SM, LocStart, LocEnd};
431 assert(SR.isInSourceOrder() &&
"region start and end out of order");
433 if (Region.isGap()) {
434 MappingRegions.push_back(CounterMappingRegion::makeGapRegion(
435 Region.getCounter(), *CovFileID, SR.LineStart, SR.ColumnStart,
436 SR.LineEnd, SR.ColumnEnd));
437 }
else if (Region.isBranch()) {
438 MappingRegions.push_back(CounterMappingRegion::makeBranchRegion(
439 Region.getCounter(), Region.getFalseCounter(), *CovFileID,
440 SR.LineStart, SR.ColumnStart, SR.LineEnd, SR.ColumnEnd));
442 MappingRegions.push_back(CounterMappingRegion::makeRegion(
443 Region.getCounter(), *CovFileID, SR.LineStart, SR.ColumnStart,
444 SR.LineEnd, SR.ColumnEnd));
450 SourceRegionFilter emitExpansionRegions() {
451 SourceRegionFilter
Filter;
452 for (
const auto &FM : FileIDMapping) {
458 auto ParentFileID = getCoverageFileID(ParentLoc);
461 auto ExpandedFileID = getCoverageFileID(ExpandedLoc);
462 assert(ExpandedFileID &&
"expansion in uncovered file");
465 assert(
SM.isWrittenInSameFile(ParentLoc, LocEnd) &&
466 "region spans multiple files");
467 Filter.insert(std::make_pair(ParentLoc, LocEnd));
469 SpellingRegion SR{
SM, ParentLoc, LocEnd};
470 assert(SR.isInSourceOrder() &&
"region start and end out of order");
471 MappingRegions.push_back(CounterMappingRegion::makeExpansion(
472 *ParentFileID, *ExpandedFileID, SR.LineStart, SR.ColumnStart,
473 SR.LineEnd, SR.ColumnEnd));
481 struct EmptyCoverageMappingBuilder :
public CoverageMappingBuilder {
484 : CoverageMappingBuilder(CVM,
SM, LangOpts) {}
486 void VisitDecl(
const Decl *D) {
492 if (!
SM.isWrittenInSameFile(Start,
End)) {
495 FileID StartFileID =
SM.getFileID(Start);
497 while (StartFileID != EndFileID && !isNestedIn(
End, StartFileID)) {
498 Start = getIncludeOrExpansionLoc(Start);
500 "Declaration start location not nested within a known region");
501 StartFileID =
SM.getFileID(Start);
503 while (StartFileID != EndFileID) {
504 End = getPreciseTokenLocEnd(getIncludeOrExpansionLoc(
End));
506 "Declaration end location not nested within a known region");
507 EndFileID =
SM.getFileID(
End);
510 SourceRegions.emplace_back(Counter(), Start,
End);
514 void write(llvm::raw_ostream &OS) {
516 gatherFileIDs(FileIDMapping);
517 emitSourceRegions(SourceRegionFilter());
519 if (MappingRegions.empty())
522 CoverageMappingWriter Writer(FileIDMapping, None, MappingRegions);
529 struct CounterCoverageMappingBuilder
530 :
public CoverageMappingBuilder,
533 llvm::DenseMap<const Stmt *, unsigned> &CounterMap;
536 std::vector<SourceMappingRegion> RegionStack;
538 CounterExpressionBuilder Builder;
547 bool HasTerminateStmt =
false;
550 Counter GapRegionCounter;
553 Counter subtractCounters(Counter LHS, Counter RHS) {
554 return Builder.subtract(LHS, RHS);
558 Counter addCounters(Counter LHS, Counter RHS) {
559 return Builder.add(LHS, RHS);
562 Counter addCounters(Counter C1, Counter C2, Counter C3) {
563 return addCounters(addCounters(C1, C2), C3);
569 Counter getRegionCounter(
const Stmt *S) {
570 return Counter::getCounter(CounterMap[S]);
581 if (StartLoc && !FalseCount.hasValue()) {
582 MostRecentLocation = *StartLoc;
585 RegionStack.emplace_back(Count, FalseCount, StartLoc, EndLoc);
587 return RegionStack.size() - 1;
593 Loc = getIncludeOrExpansionLoc(Loc);
603 void popRegions(
size_t ParentIndex) {
604 assert(RegionStack.size() >= ParentIndex &&
"parent not in stack");
605 while (RegionStack.size() > ParentIndex) {
606 SourceMappingRegion &Region = RegionStack.back();
607 if (Region.hasStartLoc()) {
611 : RegionStack[ParentIndex].getEndLoc();
612 bool isBranch = Region.isBranch();
613 size_t StartDepth = locationDepth(StartLoc);
614 size_t EndDepth = locationDepth(EndLoc);
615 while (!
SM.isWrittenInSameFile(StartLoc, EndLoc)) {
616 bool UnnestStart = StartDepth >= EndDepth;
617 bool UnnestEnd = EndDepth >= StartDepth;
626 assert(
SM.isWrittenInSameFile(NestedLoc, EndLoc));
628 if (!isBranch && !isRegionAlreadyAdded(NestedLoc, EndLoc))
629 SourceRegions.emplace_back(Region.getCounter(), NestedLoc,
632 EndLoc = getPreciseTokenLocEnd(getIncludeOrExpansionLoc(EndLoc));
634 llvm::report_fatal_error(
635 "File exit not handled before popRegions");
646 assert(
SM.isWrittenInSameFile(StartLoc, NestedLoc));
648 if (!isBranch && !isRegionAlreadyAdded(StartLoc, NestedLoc))
649 SourceRegions.emplace_back(Region.getCounter(), StartLoc,
652 StartLoc = getIncludeOrExpansionLoc(StartLoc);
654 llvm::report_fatal_error(
655 "File exit not handled before popRegions");
659 Region.setStartLoc(StartLoc);
660 Region.setEndLoc(EndLoc);
663 MostRecentLocation = EndLoc;
666 if (StartLoc == getStartOfFileOrMacro(StartLoc) &&
667 EndLoc == getEndOfFileOrMacro(EndLoc))
668 MostRecentLocation = getIncludeOrExpansionLoc(EndLoc);
671 assert(
SM.isWrittenInSameFile(Region.getBeginLoc(), EndLoc));
672 assert(SpellingRegion(
SM, Region).isInSourceOrder());
673 SourceRegions.push_back(Region);
675 RegionStack.pop_back();
680 SourceMappingRegion &getRegion() {
681 assert(!RegionStack.empty() &&
"statement has no region");
682 return RegionStack.back();
687 Counter propagateCounts(Counter TopCount,
const Stmt *S,
688 bool VisitChildren =
true) {
691 size_t Index = pushRegion(TopCount, StartLoc, EndLoc);
694 Counter ExitCount = getRegion().getCounter();
699 if (
SM.isBeforeInTranslationUnit(StartLoc, S->getBeginLoc()))
700 MostRecentLocation = EndLoc;
706 bool ConditionFoldsToBool(
const Expr *Cond) {
715 void createBranchRegion(
const Expr *C, Counter TrueCnt, Counter FalseCnt) {
731 if (ConditionFoldsToBool(C))
732 popRegions(pushRegion(Counter::getZero(), getStart(C), getEnd(C),
733 Counter::getZero()));
736 popRegions(pushRegion(TrueCnt, getStart(C), getEnd(C), FalseCnt));
742 void createSwitchCaseRegion(
const SwitchCase *SC, Counter TrueCnt,
747 popRegions(pushRegion(TrueCnt, getStart(SC), SC->
getColonLoc(), FalseCnt));
753 bool isBranch =
false) {
755 llvm::reverse(SourceRegions), [&](
const SourceMappingRegion &Region) {
756 return Region.getBeginLoc() == StartLoc &&
757 Region.getEndLoc() == EndLoc && Region.isBranch() == isBranch;
765 MostRecentLocation = EndLoc;
771 if (getRegion().hasEndLoc() &&
772 MostRecentLocation == getEndOfFileOrMacro(MostRecentLocation) &&
773 isRegionAlreadyAdded(getStartOfFileOrMacro(MostRecentLocation),
774 MostRecentLocation, getRegion().isBranch()))
775 MostRecentLocation = getIncludeOrExpansionLoc(MostRecentLocation);
785 SM.isWrittenInSameFile(MostRecentLocation, NewLoc))
791 FileID ParentFile =
SM.getFileID(LCA);
792 while (!isNestedIn(MostRecentLocation, ParentFile)) {
793 LCA = getIncludeOrExpansionLoc(LCA);
794 if (LCA.
isInvalid() ||
SM.isWrittenInSameFile(LCA, MostRecentLocation)) {
797 MostRecentLocation = NewLoc;
800 ParentFile =
SM.getFileID(LCA);
803 llvm::SmallSet<SourceLocation, 8> StartLocs;
805 for (SourceMappingRegion &I : llvm::reverse(RegionStack)) {
806 if (!I.hasStartLoc())
809 if (!isNestedIn(Loc, ParentFile)) {
810 ParentCounter = I.getCounter();
814 while (!
SM.isInFileID(Loc, ParentFile)) {
818 if (StartLocs.insert(Loc).second) {
820 SourceRegions.emplace_back(I.getCounter(), I.getFalseCounter(), Loc,
821 getEndOfFileOrMacro(Loc), I.isBranch());
823 SourceRegions.emplace_back(I.getCounter(), Loc,
824 getEndOfFileOrMacro(Loc));
826 Loc = getIncludeOrExpansionLoc(Loc);
828 I.setStartLoc(getPreciseTokenLocEnd(Loc));
836 while (isNestedIn(Loc, ParentFile)) {
838 if (StartLocs.insert(FileStart).second) {
839 SourceRegions.emplace_back(*ParentCounter, FileStart,
840 getEndOfFileOrMacro(Loc));
841 assert(SpellingRegion(
SM, SourceRegions.back()).isInSourceOrder());
843 Loc = getIncludeOrExpansionLoc(Loc);
847 MostRecentLocation = NewLoc;
851 void extendRegion(
const Stmt *S) {
852 SourceMappingRegion &Region = getRegion();
855 handleFileExit(StartLoc);
856 if (!Region.hasStartLoc())
857 Region.setStartLoc(StartLoc);
861 void terminateRegion(
const Stmt *S) {
863 SourceMappingRegion &Region = getRegion();
865 if (!Region.hasEndLoc())
866 Region.setEndLoc(EndLoc);
867 pushRegion(Counter::getZero());
868 HasTerminateStmt =
true;
877 FileID FID =
SM.getFileID(AfterLoc);
883 size_t StartDepth = locationDepth(AfterLoc);
884 size_t EndDepth = locationDepth(BeforeLoc);
885 while (!
SM.isWrittenInSameFile(AfterLoc, BeforeLoc)) {
886 bool UnnestStart = StartDepth >= EndDepth;
887 bool UnnestEnd = EndDepth >= StartDepth;
889 assert(
SM.isWrittenInSameFile(getStartOfFileOrMacro(BeforeLoc),
892 BeforeLoc = getIncludeOrExpansionLoc(BeforeLoc);
897 assert(
SM.isWrittenInSameFile(AfterLoc,
898 getEndOfFileOrMacro(AfterLoc)));
900 AfterLoc = getIncludeOrExpansionLoc(AfterLoc);
902 AfterLoc = getPreciseTokenLocEnd(AfterLoc);
907 AfterLoc = getPreciseTokenLocEnd(AfterLoc);
912 if (!
SM.isWrittenInSameFile(AfterLoc, BeforeLoc) ||
913 !SpellingRegion(
SM, AfterLoc, BeforeLoc).isInSourceOrder())
915 return {{AfterLoc, BeforeLoc}};
921 if (StartLoc == EndLoc)
923 assert(SpellingRegion(
SM, StartLoc, EndLoc).isInSourceOrder());
924 handleFileExit(StartLoc);
925 size_t Index = pushRegion(Count, StartLoc, EndLoc);
926 getRegion().setGap(
true);
927 handleFileExit(EndLoc);
932 struct BreakContinue {
934 Counter ContinueCount;
938 CounterCoverageMappingBuilder(
942 : CoverageMappingBuilder(CVM,
SM, LangOpts), CounterMap(CounterMap) {}
945 void write(llvm::raw_ostream &OS) {
947 gatherFileIDs(VirtualFileMapping);
948 SourceRegionFilter
Filter = emitExpansionRegions();
949 emitSourceRegions(
Filter);
950 gatherSkippedRegions();
952 if (MappingRegions.empty())
955 CoverageMappingWriter Writer(VirtualFileMapping, Builder.getExpressions(),
960 void VisitStmt(
const Stmt *S) {
961 if (S->getBeginLoc().isValid())
963 const Stmt *LastStmt =
nullptr;
964 bool SaveTerminateStmt = HasTerminateStmt;
965 HasTerminateStmt =
false;
966 GapRegionCounter = Counter::getZero();
967 for (
const Stmt *Child : S->children())
972 if (LastStmt && HasTerminateStmt && !isa<AttributedStmt>(Child)) {
973 auto Gap = findGapAreaBetween(getEnd(LastStmt), getStart(Child));
975 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(),
977 SaveTerminateStmt =
true;
978 HasTerminateStmt =
false;
983 if (SaveTerminateStmt)
984 HasTerminateStmt =
true;
985 handleFileExit(getEnd(S));
988 void VisitDecl(
const Decl *D) {
992 if (Body &&
SM.isInSystemHeader(
SM.getSpellingLoc(getStart(Body))))
1000 if (
auto *Method = dyn_cast<CXXMethodDecl>(D))
1003 propagateCounts(getRegionCounter(Body), Body,
1005 assert(RegionStack.empty() &&
"Regions entered but never exited");
1010 if (S->getRetValue())
1011 Visit(S->getRetValue());
1017 Visit(S->getBody());
1022 if (S->getOperand())
1023 Visit(S->getOperand());
1034 void VisitGotoStmt(
const GotoStmt *S) { terminateRegion(S); }
1036 void VisitLabelStmt(
const LabelStmt *S) {
1037 Counter LabelCount = getRegionCounter(S);
1040 handleFileExit(Start);
1041 pushRegion(LabelCount, Start);
1042 Visit(S->getSubStmt());
1045 void VisitBreakStmt(
const BreakStmt *S) {
1046 assert(!BreakContinueStack.empty() &&
"break not in a loop or switch!");
1047 BreakContinueStack.back().BreakCount = addCounters(
1048 BreakContinueStack.back().BreakCount, getRegion().getCounter());
1055 assert(!BreakContinueStack.empty() &&
"continue stmt not in a loop!");
1056 BreakContinueStack.back().ContinueCount = addCounters(
1057 BreakContinueStack.back().ContinueCount, getRegion().getCounter());
1061 void VisitCallExpr(
const CallExpr *E) {
1071 void VisitWhileStmt(
const WhileStmt *S) {
1074 Counter ParentCount = getRegion().getCounter();
1075 Counter BodyCount = getRegionCounter(S);
1078 BreakContinueStack.push_back(BreakContinue());
1079 extendRegion(S->getBody());
1080 Counter BackedgeCount = propagateCounts(BodyCount, S->getBody());
1081 BreakContinue BC = BreakContinueStack.pop_back_val();
1083 bool BodyHasTerminateStmt = HasTerminateStmt;
1084 HasTerminateStmt =
false;
1088 addCounters(ParentCount, BackedgeCount, BC.ContinueCount);
1089 propagateCounts(CondCount, S->getCond());
1090 adjustForOutOfOrderTraversal(getEnd(S));
1093 auto Gap = findGapAreaBetween(S->getRParenLoc(), getStart(S->getBody()));
1095 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount);
1098 addCounters(BC.BreakCount, subtractCounters(CondCount, BodyCount));
1099 if (OutCount != ParentCount) {
1100 pushRegion(OutCount);
1101 GapRegionCounter = OutCount;
1102 if (BodyHasTerminateStmt)
1103 HasTerminateStmt =
true;
1107 createBranchRegion(S->getCond(), BodyCount,
1108 subtractCounters(CondCount, BodyCount));
1111 void VisitDoStmt(
const DoStmt *S) {
1114 Counter ParentCount = getRegion().getCounter();
1115 Counter BodyCount = getRegionCounter(S);
1117 BreakContinueStack.push_back(BreakContinue());
1118 extendRegion(S->getBody());
1119 Counter BackedgeCount =
1120 propagateCounts(addCounters(ParentCount, BodyCount), S->getBody());
1121 BreakContinue BC = BreakContinueStack.pop_back_val();
1123 bool BodyHasTerminateStmt = HasTerminateStmt;
1124 HasTerminateStmt =
false;
1126 Counter CondCount = addCounters(BackedgeCount, BC.ContinueCount);
1127 propagateCounts(CondCount, S->getCond());
1130 addCounters(BC.BreakCount, subtractCounters(CondCount, BodyCount));
1131 if (OutCount != ParentCount) {
1132 pushRegion(OutCount);
1133 GapRegionCounter = OutCount;
1137 createBranchRegion(S->getCond(), BodyCount,
1138 subtractCounters(CondCount, BodyCount));
1140 if (BodyHasTerminateStmt)
1141 HasTerminateStmt =
true;
1144 void VisitForStmt(
const ForStmt *S) {
1147 Visit(S->getInit());
1149 Counter ParentCount = getRegion().getCounter();
1150 Counter BodyCount = getRegionCounter(S);
1154 BreakContinueStack.emplace_back();
1157 BreakContinueStack.emplace_back();
1158 extendRegion(S->getBody());
1159 Counter BackedgeCount = propagateCounts(BodyCount, S->getBody());
1160 BreakContinue BodyBC = BreakContinueStack.pop_back_val();
1162 bool BodyHasTerminateStmt = HasTerminateStmt;
1163 HasTerminateStmt =
false;
1167 BreakContinue IncrementBC;
1168 if (
const Stmt *Inc = S->getInc()) {
1169 propagateCounts(addCounters(BackedgeCount, BodyBC.ContinueCount), Inc);
1170 IncrementBC = BreakContinueStack.pop_back_val();
1174 Counter CondCount = addCounters(
1175 addCounters(ParentCount, BackedgeCount, BodyBC.ContinueCount),
1176 IncrementBC.ContinueCount);
1177 if (
const Expr *Cond = S->getCond()) {
1178 propagateCounts(CondCount, Cond);
1179 adjustForOutOfOrderTraversal(getEnd(S));
1183 auto Gap = findGapAreaBetween(S->getRParenLoc(), getStart(S->getBody()));
1185 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount);
1187 Counter OutCount = addCounters(BodyBC.BreakCount, IncrementBC.BreakCount,
1188 subtractCounters(CondCount, BodyCount));
1189 if (OutCount != ParentCount) {
1190 pushRegion(OutCount);
1191 GapRegionCounter = OutCount;
1192 if (BodyHasTerminateStmt)
1193 HasTerminateStmt =
true;
1197 createBranchRegion(S->getCond(), BodyCount,
1198 subtractCounters(CondCount, BodyCount));
1204 Visit(S->getInit());
1205 Visit(S->getLoopVarStmt());
1206 Visit(S->getRangeStmt());
1208 Counter ParentCount = getRegion().getCounter();
1209 Counter BodyCount = getRegionCounter(S);
1211 BreakContinueStack.push_back(BreakContinue());
1212 extendRegion(S->getBody());
1213 Counter BackedgeCount = propagateCounts(BodyCount, S->getBody());
1214 BreakContinue BC = BreakContinueStack.pop_back_val();
1216 bool BodyHasTerminateStmt = HasTerminateStmt;
1217 HasTerminateStmt =
false;
1220 auto Gap = findGapAreaBetween(S->getRParenLoc(), getStart(S->getBody()));
1222 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount);
1225 addCounters(ParentCount, BackedgeCount, BC.ContinueCount);
1227 addCounters(BC.BreakCount, subtractCounters(LoopCount, BodyCount));
1228 if (OutCount != ParentCount) {
1229 pushRegion(OutCount);
1230 GapRegionCounter = OutCount;
1231 if (BodyHasTerminateStmt)
1232 HasTerminateStmt =
true;
1236 createBranchRegion(S->getCond(), BodyCount,
1237 subtractCounters(LoopCount, BodyCount));
1242 Visit(S->getElement());
1244 Counter ParentCount = getRegion().getCounter();
1245 Counter BodyCount = getRegionCounter(S);
1247 BreakContinueStack.push_back(BreakContinue());
1248 extendRegion(S->getBody());
1249 Counter BackedgeCount = propagateCounts(BodyCount, S->getBody());
1250 BreakContinue BC = BreakContinueStack.pop_back_val();
1253 auto Gap = findGapAreaBetween(S->getRParenLoc(), getStart(S->getBody()));
1255 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount);
1258 addCounters(ParentCount, BackedgeCount, BC.ContinueCount);
1260 addCounters(BC.BreakCount, subtractCounters(LoopCount, BodyCount));
1261 if (OutCount != ParentCount) {
1262 pushRegion(OutCount);
1263 GapRegionCounter = OutCount;
1270 Visit(S->getInit());
1271 Visit(S->getCond());
1273 BreakContinueStack.push_back(BreakContinue());
1275 const Stmt *Body = S->getBody();
1277 if (
const auto *CS = dyn_cast<CompoundStmt>(Body)) {
1278 if (!CS->body_empty()) {
1282 size_t Index = pushRegion(Counter::getZero(), getStart(CS));
1283 getRegion().setGap(
true);
1287 for (
size_t i = RegionStack.size(); i != Index; --i) {
1288 if (!RegionStack[i - 1].hasEndLoc())
1289 RegionStack[i - 1].setEndLoc(getEnd(CS->body_back()));
1295 propagateCounts(Counter::getZero(), Body);
1296 BreakContinue BC = BreakContinueStack.pop_back_val();
1298 if (!BreakContinueStack.empty())
1299 BreakContinueStack.back().ContinueCount = addCounters(
1300 BreakContinueStack.back().ContinueCount, BC.ContinueCount);
1302 Counter ParentCount = getRegion().getCounter();
1303 Counter ExitCount = getRegionCounter(S);
1305 pushRegion(ExitCount);
1306 GapRegionCounter = ExitCount;
1310 MostRecentLocation = getStart(S);
1311 handleFileExit(ExitLoc);
1315 Counter CaseCountSum;
1316 bool HasDefaultCase =
false;
1317 const SwitchCase *Case = S->getSwitchCaseList();
1319 HasDefaultCase = HasDefaultCase || isa<DefaultStmt>(Case);
1320 CaseCountSum = addCounters(CaseCountSum, getRegionCounter(Case));
1321 createSwitchCaseRegion(
1322 Case, getRegionCounter(Case),
1323 subtractCounters(ParentCount, getRegionCounter(Case)));
1329 if (!HasDefaultCase) {
1330 Counter DefaultTrue = subtractCounters(ParentCount, CaseCountSum);
1331 Counter DefaultFalse = subtractCounters(ParentCount, DefaultTrue);
1332 createBranchRegion(S->getCond(), DefaultTrue, DefaultFalse);
1339 SourceMappingRegion &
Parent = getRegion();
1341 Counter Count = addCounters(
Parent.getCounter(), getRegionCounter(S));
1344 if (
Parent.hasStartLoc() &&
Parent.getBeginLoc() == getStart(S))
1345 Parent.setCounter(Count);
1347 pushRegion(Count, getStart(S));
1349 GapRegionCounter = Count;
1351 if (
const auto *CS = dyn_cast<CaseStmt>(S)) {
1352 Visit(CS->getLHS());
1353 if (
const Expr *RHS = CS->getRHS())
1356 Visit(S->getSubStmt());
1359 void VisitIfStmt(
const IfStmt *S) {
1362 Visit(S->getInit());
1366 extendRegion(S->getCond());
1368 Counter ParentCount = getRegion().getCounter();
1369 Counter ThenCount = getRegionCounter(S);
1373 propagateCounts(ParentCount, S->getCond());
1376 auto Gap = findGapAreaBetween(S->getRParenLoc(), getStart(S->getThen()));
1378 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), ThenCount);
1380 extendRegion(S->getThen());
1381 Counter OutCount = propagateCounts(ThenCount, S->getThen());
1383 Counter ElseCount = subtractCounters(ParentCount, ThenCount);
1384 if (
const Stmt *Else = S->getElse()) {
1385 bool ThenHasTerminateStmt = HasTerminateStmt;
1386 HasTerminateStmt =
false;
1389 Gap = findGapAreaBetween(getEnd(S->getThen()), getStart(Else));
1391 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), ElseCount);
1393 OutCount = addCounters(OutCount, propagateCounts(ElseCount, Else));
1395 if (ThenHasTerminateStmt)
1396 HasTerminateStmt =
true;
1398 OutCount = addCounters(OutCount, ElseCount);
1400 if (OutCount != ParentCount) {
1401 pushRegion(OutCount);
1402 GapRegionCounter = OutCount;
1406 createBranchRegion(S->getCond(), ThenCount,
1407 subtractCounters(ParentCount, ThenCount));
1413 extendRegion(S->getTryBlock());
1415 Counter ParentCount = getRegion().getCounter();
1416 propagateCounts(ParentCount, S->getTryBlock());
1418 for (
unsigned I = 0, E = S->getNumHandlers(); I < E; ++I)
1419 Visit(S->getHandler(I));
1421 Counter ExitCount = getRegionCounter(S);
1422 pushRegion(ExitCount);
1426 propagateCounts(getRegionCounter(S), S->getHandlerBlock());
1432 Counter ParentCount = getRegion().getCounter();
1433 Counter TrueCount = getRegionCounter(E);
1435 propagateCounts(ParentCount, E->
getCond());
1437 if (!isa<BinaryConditionalOperator>(E)) {
1442 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), TrueCount);
1449 propagateCounts(subtractCounters(ParentCount, TrueCount),
1453 createBranchRegion(E->
getCond(), TrueCount,
1454 subtractCounters(ParentCount, TrueCount));
1458 extendRegion(E->
getLHS());
1459 propagateCounts(getRegion().getCounter(), E->
getLHS());
1460 handleFileExit(getEnd(E->
getLHS()));
1463 extendRegion(E->
getRHS());
1464 propagateCounts(getRegionCounter(E), E->
getRHS());
1467 Counter RHSExecCnt = getRegionCounter(E);
1470 Counter RHSTrueCnt = getRegionCounter(E->
getRHS());
1473 Counter ParentCnt = getRegion().getCounter();
1476 createBranchRegion(E->
getLHS(), RHSExecCnt,
1477 subtractCounters(ParentCnt, RHSExecCnt));
1480 createBranchRegion(E->
getRHS(), RHSTrueCnt,
1481 subtractCounters(RHSExecCnt, RHSTrueCnt));
1485 extendRegion(E->
getLHS());
1486 propagateCounts(getRegion().getCounter(), E->
getLHS());
1487 handleFileExit(getEnd(E->
getLHS()));
1490 extendRegion(E->
getRHS());
1491 propagateCounts(getRegionCounter(E), E->
getRHS());
1494 Counter RHSExecCnt = getRegionCounter(E);
1497 Counter RHSFalseCnt = getRegionCounter(E->
getRHS());
1500 Counter ParentCnt = getRegion().getCounter();
1503 createBranchRegion(E->
getLHS(), subtractCounters(ParentCnt, RHSExecCnt),
1507 createBranchRegion(E->
getRHS(), subtractCounters(RHSExecCnt, RHSFalseCnt),
1519 static void dump(llvm::raw_ostream &OS, StringRef FunctionName,
1522 OS << FunctionName <<
":\n";
1523 CounterMappingContext Ctx(Expressions);
1524 for (
const auto &R : Regions) {
1527 case CounterMappingRegion::CodeRegion:
1529 case CounterMappingRegion::ExpansionRegion:
1532 case CounterMappingRegion::SkippedRegion:
1535 case CounterMappingRegion::GapRegion:
1538 case CounterMappingRegion::BranchRegion:
1543 OS <<
"File " << R.FileID <<
", " << R.LineStart <<
":" << R.ColumnStart
1544 <<
" -> " << R.LineEnd <<
":" << R.ColumnEnd <<
" = ";
1545 Ctx.dump(R.Count, OS);
1547 if (R.Kind == CounterMappingRegion::BranchRegion) {
1549 Ctx.dump(R.FalseCount, OS);
1552 if (R.Kind == CounterMappingRegion::ExpansionRegion)
1553 OS <<
" (Expanded file = " << R.ExpandedFileID <<
")";
1560 : CGM(CGM), SourceInfo(SourceInfo) {
1564 std::string CoverageMappingModuleGen::getCurrentDirname() {
1569 llvm::sys::fs::current_path(CWD);
1570 return CWD.str().str();
1575 llvm::sys::path::remove_dots(Path,
true);
1576 for (
const auto &Entry : CoveragePrefixMap) {
1577 if (llvm::sys::path::replace_path_prefix(Path, Entry.first, Entry.second))
1580 return Path.str().str();
1584 llvm::InstrProfSectKind SK) {
1585 return llvm::getInstrProfSectionName(
1589 void CoverageMappingModuleGen::emitFunctionMappingRecord(
1590 const FunctionInfo &Info, uint64_t FilenamesRef) {
1594 std::string FuncRecordName =
"__covrec_" + llvm::utohexstr(Info.NameHash);
1601 FuncRecordName +=
"u";
1604 const uint64_t NameHash = Info.NameHash;
1605 const uint64_t FuncHash = Info.FuncHash;
1606 const std::string &CoverageMapping = Info.CoverageMapping;
1607 #define COVMAP_FUNC_RECORD(Type, LLVMType, Name, Init) LLVMType,
1608 llvm::Type *FunctionRecordTypes[] = {
1609 #include "llvm/ProfileData/InstrProfData.inc"
1611 auto *FunctionRecordTy =
1612 llvm::StructType::get(Ctx, makeArrayRef(FunctionRecordTypes),
1616 #define COVMAP_FUNC_RECORD(Type, LLVMType, Name, Init) Init,
1617 llvm::Constant *FunctionRecordVals[] = {
1618 #include "llvm/ProfileData/InstrProfData.inc"
1620 auto *FuncRecordConstant = llvm::ConstantStruct::get(
1621 FunctionRecordTy, makeArrayRef(FunctionRecordVals));
1624 auto *FuncRecord =
new llvm::GlobalVariable(
1625 CGM.
getModule(), FunctionRecordTy,
true,
1626 llvm::GlobalValue::LinkOnceODRLinkage, FuncRecordConstant,
1630 FuncRecord->setAlignment(llvm::Align(8));
1632 FuncRecord->setComdat(CGM.
getModule().getOrInsertComdat(FuncRecordName));
1639 llvm::GlobalVariable *NamePtr, StringRef NameValue, uint64_t FuncHash,
1640 const std::string &CoverageMapping,
bool IsUsed) {
1643 FunctionRecords.push_back({NameHash, FuncHash, CoverageMapping, IsUsed});
1646 FunctionNames.push_back(
1647 llvm::ConstantExpr::getBitCast(NamePtr, llvm::Type::getInt8PtrTy(Ctx)));
1656 std::vector<StringRef> Filenames;
1657 std::vector<CounterExpression> Expressions;
1658 std::vector<CounterMappingRegion> Regions;
1659 FilenameStrs.resize(FileEntries.size() + 1);
1660 FilenameStrs[0] = normalizeFilename(getCurrentDirname());
1661 for (
const auto &Entry : FileEntries) {
1662 auto I = Entry.second;
1663 FilenameStrs[I] = normalizeFilename(Entry.first->getName());
1666 RawCoverageMappingReader Reader(CoverageMapping, FilenameRefs, Filenames,
1667 Expressions, Regions);
1670 dump(llvm::outs(), NameValue, Expressions, Regions);
1675 if (FunctionRecords.empty())
1678 auto *Int32Ty = llvm::Type::getInt32Ty(Ctx);
1682 FilenameStrs.resize(FileEntries.size() + 1);
1684 FilenameStrs[0] = normalizeFilename(getCurrentDirname());
1685 for (
const auto &Entry : FileEntries) {
1686 auto I = Entry.second;
1687 FilenameStrs[I] = normalizeFilename(Entry.first->getName());
1692 llvm::raw_string_ostream OS(Filenames);
1693 CoverageFilenamesSectionWriter(FilenameStrs).write(OS);
1695 auto *FilenamesVal =
1696 llvm::ConstantDataArray::getString(Ctx, Filenames,
false);
1700 for (
const FunctionInfo &Info : FunctionRecords)
1701 emitFunctionMappingRecord(Info, FilenamesRef);
1703 const unsigned NRecords = 0;
1704 const size_t FilenamesSize = Filenames.size();
1705 const unsigned CoverageMappingSize = 0;
1706 llvm::Type *CovDataHeaderTypes[] = {
1707 #define COVMAP_HEADER(Type, LLVMType, Name, Init) LLVMType,
1708 #include "llvm/ProfileData/InstrProfData.inc"
1710 auto CovDataHeaderTy =
1711 llvm::StructType::get(Ctx, makeArrayRef(CovDataHeaderTypes));
1712 llvm::Constant *CovDataHeaderVals[] = {
1713 #define COVMAP_HEADER(Type, LLVMType, Name, Init) Init,
1714 #include "llvm/ProfileData/InstrProfData.inc"
1716 auto CovDataHeaderVal = llvm::ConstantStruct::get(
1717 CovDataHeaderTy, makeArrayRef(CovDataHeaderVals));
1720 llvm::Type *CovDataTypes[] = {CovDataHeaderTy, FilenamesVal->getType()};
1721 auto CovDataTy = llvm::StructType::get(Ctx, makeArrayRef(CovDataTypes));
1722 llvm::Constant *TUDataVals[] = {CovDataHeaderVal, FilenamesVal};
1724 llvm::ConstantStruct::get(CovDataTy, makeArrayRef(TUDataVals));
1725 auto CovData =
new llvm::GlobalVariable(
1726 CGM.
getModule(), CovDataTy,
true, llvm::GlobalValue::PrivateLinkage,
1727 CovDataVal, llvm::getCoverageMappingVarName());
1730 CovData->setAlignment(llvm::Align(8));
1735 if (!FunctionNames.empty()) {
1736 auto NamesArrTy = llvm::ArrayType::get(llvm::Type::getInt8PtrTy(Ctx),
1737 FunctionNames.size());
1738 auto NamesArrVal = llvm::ConstantArray::get(NamesArrTy, FunctionNames);
1741 new llvm::GlobalVariable(CGM.
getModule(), NamesArrTy,
true,
1743 llvm::getCoverageUnusedNamesVarName());
1748 auto It = FileEntries.find(
File);
1749 if (It != FileEntries.end())
1751 unsigned FileID = FileEntries.size() + 1;
1752 FileEntries.insert(std::make_pair(
File,
FileID));
1757 llvm::raw_ostream &OS) {
1759 CounterCoverageMappingBuilder Walker(CVM, *CounterMap,
SM, LangOpts);
1760 Walker.VisitDecl(D);
1765 llvm::raw_ostream &OS) {
1766 EmptyCoverageMappingBuilder Walker(CVM,
SM, LangOpts);
1767 Walker.VisitDecl(D);