18 #include "llvm/ADT/SmallSet.h" 19 #include "llvm/ADT/StringExtras.h" 20 #include "llvm/ADT/Optional.h" 21 #include "llvm/ProfileData/Coverage/CoverageMapping.h" 22 #include "llvm/ProfileData/Coverage/CoverageMappingReader.h" 23 #include "llvm/ProfileData/Coverage/CoverageMappingWriter.h" 24 #include "llvm/ProfileData/InstrProfReader.h" 25 #include "llvm/Support/FileSystem.h" 26 #include "llvm/Support/Path.h" 28 using namespace clang;
29 using namespace CodeGen;
33 SkippedRanges.push_back(Range);
39 class SourceMappingRegion {
58 bool GapRegion =
false)
59 : Count(Count), LocStart(LocStart), LocEnd(LocEnd),
60 DeferRegion(DeferRegion), GapRegion(GapRegion) {}
62 const Counter &getCounter()
const {
return Count; }
64 void setCounter(Counter C) { Count = C; }
66 bool hasStartLoc()
const {
return LocStart.hasValue(); }
71 assert(LocStart &&
"Region has no start location");
75 bool hasEndLoc()
const {
return LocEnd.hasValue(); }
78 assert(Loc.
isValid() &&
"Setting an invalid end location");
83 assert(LocEnd &&
"Region has no end location");
87 bool isDeferred()
const {
return DeferRegion; }
89 void setDeferred(
bool Deferred) { DeferRegion = Deferred; }
91 bool isGap()
const {
return GapRegion; }
93 void setGap(
bool Gap) { GapRegion = Gap; }
97 struct SpellingRegion {
102 unsigned ColumnStart;
119 : SpellingRegion(SM, R.getBeginLoc(), R.getEndLoc()) {}
123 bool isInSourceOrder()
const {
124 return (LineStart < LineEnd) ||
125 (LineStart == LineEnd && ColumnStart <= ColumnEnd);
131 class CoverageMappingBuilder {
139 llvm::SmallDenseMap<FileID, std::pair<unsigned, SourceLocation>, 8>
146 std::vector<SourceMappingRegion> SourceRegions;
153 typedef llvm::SmallSet<std::pair<SourceLocation, SourceLocation>, 8>
158 : CVM(CVM),
SM(SM), LangOpts(LangOpts) {}
198 Loc = getIncludeOrExpansionLoc(Loc);
218 return getPreciseTokenLocEnd(Loc);
227 FileIDMapping.clear();
229 llvm::SmallSet<FileID, 8> Visited;
231 for (
const auto &Region : SourceRegions) {
234 if (!Visited.insert(File).second)
243 Parent.
isValid(); Parent = getIncludeOrExpansionLoc(Parent))
245 FileLocs.push_back(std::make_pair(Loc, Depth));
247 std::stable_sort(FileLocs.begin(), FileLocs.end(), llvm::less_second());
249 for (
const auto &FL : FileLocs) {
256 FileIDMapping[SM.
getFileID(Loc)] = std::make_pair(Mapping.size(), Loc);
265 auto Mapping = FileIDMapping.find(SM.
getFileID(Loc));
266 if (Mapping != FileIDMapping.end())
267 return Mapping->second.first;
273 void gatherSkippedRegions() {
277 FileLineRanges.resize(
278 FileIDMapping.size(),
280 for (
const auto &R : MappingRegions) {
281 FileLineRanges[R.FileID].first =
282 std::min(FileLineRanges[R.FileID].first, R.LineStart);
283 FileLineRanges[R.FileID].second =
284 std::max(FileLineRanges[R.FileID].second, R.LineEnd);
288 for (
const auto &I : SkippedRanges) {
289 auto LocStart = I.getBegin();
290 auto LocEnd = I.getEnd();
292 "region spans multiple files");
294 auto CovFileID = getCoverageFileID(LocStart);
297 SpellingRegion SR{
SM, LocStart, LocEnd};
298 auto Region = CounterMappingRegion::makeSkipped(
299 *CovFileID, SR.LineStart, SR.ColumnStart, SR.LineEnd, SR.ColumnEnd);
302 if (Region.LineStart >= FileLineRanges[*CovFileID].first &&
303 Region.LineEnd <= FileLineRanges[*CovFileID].second)
304 MappingRegions.push_back(Region);
310 void emitSourceRegions(
const SourceRegionFilter &
Filter) {
311 for (
const auto &Region : SourceRegions) {
312 assert(Region.hasEndLoc() &&
"incomplete region");
321 auto CovFileID = getCoverageFileID(LocStart);
328 "region spans multiple files");
334 if (Filter.count(std::make_pair(LocStart, LocEnd)))
338 SpellingRegion SR{
SM, LocStart, LocEnd};
339 assert(SR.isInSourceOrder() &&
"region start and end out of order");
341 if (Region.isGap()) {
342 MappingRegions.push_back(CounterMappingRegion::makeGapRegion(
343 Region.getCounter(), *CovFileID, SR.LineStart, SR.ColumnStart,
344 SR.LineEnd, SR.ColumnEnd));
346 MappingRegions.push_back(CounterMappingRegion::makeRegion(
347 Region.getCounter(), *CovFileID, SR.LineStart, SR.ColumnStart,
348 SR.LineEnd, SR.ColumnEnd));
354 SourceRegionFilter emitExpansionRegions() {
355 SourceRegionFilter
Filter;
356 for (
const auto &FM : FileIDMapping) {
362 auto ParentFileID = getCoverageFileID(ParentLoc);
365 auto ExpandedFileID = getCoverageFileID(ExpandedLoc);
366 assert(ExpandedFileID &&
"expansion in uncovered file");
370 "region spans multiple files");
371 Filter.insert(std::make_pair(ParentLoc, LocEnd));
373 SpellingRegion SR{
SM, ParentLoc, LocEnd};
374 assert(SR.isInSourceOrder() &&
"region start and end out of order");
375 MappingRegions.push_back(CounterMappingRegion::makeExpansion(
376 *ParentFileID, *ExpandedFileID, SR.LineStart, SR.ColumnStart,
377 SR.LineEnd, SR.ColumnEnd));
385 struct EmptyCoverageMappingBuilder :
public CoverageMappingBuilder {
388 : CoverageMappingBuilder(CVM, SM, LangOpts) {}
390 void VisitDecl(
const Decl *D) {
401 while (StartFileID != EndFileID && !isNestedIn(End, StartFileID)) {
402 Start = getIncludeOrExpansionLoc(Start);
404 "Declaration start location not nested within a known region");
407 while (StartFileID != EndFileID) {
408 End = getPreciseTokenLocEnd(getIncludeOrExpansionLoc(End));
410 "Declaration end location not nested within a known region");
414 SourceRegions.emplace_back(Counter(), Start, End);
418 void write(llvm::raw_ostream &OS) {
420 gatherFileIDs(FileIDMapping);
421 emitSourceRegions(SourceRegionFilter());
423 if (MappingRegions.empty())
426 CoverageMappingWriter Writer(FileIDMapping, None, MappingRegions);
433 struct CounterCoverageMappingBuilder
434 :
public CoverageMappingBuilder,
437 llvm::DenseMap<const Stmt *, unsigned> &CounterMap;
440 std::vector<SourceMappingRegion> RegionStack;
446 CounterExpressionBuilder Builder;
458 Counter subtractCounters(Counter LHS, Counter RHS) {
459 return Builder.subtract(LHS, RHS);
463 Counter addCounters(Counter LHS, Counter RHS) {
464 return Builder.add(LHS, RHS);
467 Counter addCounters(Counter C1, Counter C2, Counter C3) {
468 return addCounters(addCounters(C1, C2), C3);
474 Counter getRegionCounter(
const Stmt *S) {
475 return Counter::getCounter(CounterMap[S]);
485 MostRecentLocation = *StartLoc;
486 completeDeferred(Count, MostRecentLocation);
488 RegionStack.emplace_back(Count, StartLoc, EndLoc);
490 return RegionStack.size() - 1;
495 size_t completeDeferred(Counter Count,
SourceLocation DeferredEndLoc) {
496 size_t Index = RegionStack.size();
501 SourceMappingRegion DR = DeferredRegion.getValue();
502 DeferredRegion = None;
507 if (isNestedIn(DeferredEndLoc, StartFile)) {
509 DeferredEndLoc = getIncludeOrExpansionLoc(DeferredEndLoc);
510 }
while (StartFile !=
SM.
getFileID(DeferredEndLoc));
518 if (DR.getBeginLoc() == DeferredEndLoc)
523 if (!SpellingRegion(
SM, DR.getBeginLoc(), DeferredEndLoc).isInSourceOrder())
527 DR.setCounter(Count);
528 DR.setEndLoc(DeferredEndLoc);
529 handleFileExit(DeferredEndLoc);
530 RegionStack.push_back(DR);
536 void completeTopLevelDeferredRegion(Counter Count,
538 if (DeferredRegion || !LastTerminatedRegion)
541 if (LastTerminatedRegion->second != RegionStack.size())
548 SourceMappingRegion DR = RegionStack.back();
549 DR.setStartLoc(Start);
550 DR.setDeferred(
false);
552 completeDeferred(Count, DeferredEndLoc);
558 Loc = getIncludeOrExpansionLoc(Loc);
568 void popRegions(
size_t ParentIndex) {
569 assert(RegionStack.size() >= ParentIndex &&
"parent not in stack");
570 bool ParentOfDeferredRegion =
false;
571 while (RegionStack.size() > ParentIndex) {
572 SourceMappingRegion &Region = RegionStack.back();
573 if (Region.hasStartLoc()) {
577 : RegionStack[ParentIndex].getEndLoc();
578 size_t StartDepth = locationDepth(StartLoc);
579 size_t EndDepth = locationDepth(EndLoc);
581 bool UnnestStart = StartDepth >= EndDepth;
582 bool UnnestEnd = EndDepth >= StartDepth;
589 if (!isRegionAlreadyAdded(NestedLoc, EndLoc))
590 SourceRegions.emplace_back(Region.getCounter(), NestedLoc, EndLoc);
592 EndLoc = getPreciseTokenLocEnd(getIncludeOrExpansionLoc(EndLoc));
594 llvm::report_fatal_error(
"File exit not handled before popRegions");
603 if (!isRegionAlreadyAdded(StartLoc, NestedLoc))
604 SourceRegions.emplace_back(Region.getCounter(), StartLoc, NestedLoc);
606 StartLoc = getIncludeOrExpansionLoc(StartLoc);
608 llvm::report_fatal_error(
"File exit not handled before popRegions");
612 Region.setStartLoc(StartLoc);
613 Region.setEndLoc(EndLoc);
615 MostRecentLocation = EndLoc;
618 if (StartLoc == getStartOfFileOrMacro(StartLoc) &&
619 EndLoc == getEndOfFileOrMacro(EndLoc))
620 MostRecentLocation = getIncludeOrExpansionLoc(EndLoc);
623 assert(SpellingRegion(
SM, Region).isInSourceOrder());
624 SourceRegions.push_back(Region);
626 if (ParentOfDeferredRegion) {
627 ParentOfDeferredRegion =
false;
631 if (!DeferredRegion.hasValue() &&
636 SourceMappingRegion(Counter::getZero(), EndLoc, None);
638 }
else if (Region.isDeferred()) {
639 assert(!ParentOfDeferredRegion &&
"Consecutive deferred regions");
640 ParentOfDeferredRegion =
true;
642 RegionStack.pop_back();
646 if (LastTerminatedRegion &&
647 RegionStack.size() < LastTerminatedRegion->second)
648 LastTerminatedRegion = None;
650 assert(!ParentOfDeferredRegion &&
"Deferred region with no parent");
654 SourceMappingRegion &getRegion() {
655 assert(!RegionStack.empty() &&
"statement has no region");
656 return RegionStack.back();
661 Counter propagateCounts(Counter TopCount,
const Stmt *S,
662 bool VisitChildren =
true) {
665 size_t Index = pushRegion(TopCount, StartLoc, EndLoc);
668 Counter ExitCount = getRegion().getCounter();
674 MostRecentLocation = EndLoc;
682 return SourceRegions.rend() !=
683 std::find_if(SourceRegions.rbegin(), SourceRegions.rend(),
684 [&](
const SourceMappingRegion &Region) {
685 return Region.getBeginLoc() == StartLoc &&
686 Region.getEndLoc() == EndLoc;
694 MostRecentLocation = EndLoc;
700 if (getRegion().hasEndLoc() &&
701 MostRecentLocation == getEndOfFileOrMacro(MostRecentLocation) &&
702 isRegionAlreadyAdded(getStartOfFileOrMacro(MostRecentLocation),
704 MostRecentLocation = getIncludeOrExpansionLoc(MostRecentLocation);
721 while (!isNestedIn(MostRecentLocation, ParentFile)) {
722 LCA = getIncludeOrExpansionLoc(LCA);
726 MostRecentLocation = NewLoc;
732 llvm::SmallSet<SourceLocation, 8> StartLocs;
734 for (SourceMappingRegion &I : llvm::reverse(RegionStack)) {
735 if (!I.hasStartLoc())
738 if (!isNestedIn(Loc, ParentFile)) {
739 ParentCounter = I.getCounter();
747 if (StartLocs.insert(Loc).second)
748 SourceRegions.emplace_back(I.getCounter(), Loc,
749 getEndOfFileOrMacro(Loc));
750 Loc = getIncludeOrExpansionLoc(Loc);
752 I.setStartLoc(getPreciseTokenLocEnd(Loc));
760 while (isNestedIn(Loc, ParentFile)) {
762 if (StartLocs.insert(FileStart).second) {
763 SourceRegions.emplace_back(*ParentCounter, FileStart,
764 getEndOfFileOrMacro(Loc));
765 assert(SpellingRegion(
SM, SourceRegions.back()).isInSourceOrder());
767 Loc = getIncludeOrExpansionLoc(Loc);
771 MostRecentLocation = NewLoc;
775 void extendRegion(
const Stmt *S) {
776 SourceMappingRegion &Region = getRegion();
779 handleFileExit(StartLoc);
780 if (!Region.hasStartLoc())
781 Region.setStartLoc(StartLoc);
783 completeDeferred(Region.getCounter(), StartLoc);
787 void terminateRegion(
const Stmt *S) {
789 SourceMappingRegion &Region = getRegion();
791 if (!Region.hasEndLoc())
792 Region.setEndLoc(EndLoc);
793 pushRegion(Counter::getZero());
794 auto &ZeroRegion = getRegion();
795 ZeroRegion.setDeferred(
true);
796 LastTerminatedRegion = {EndLoc, RegionStack.size()};
808 return {{AfterLoc, BeforeLoc}};
813 const Stmt *BeforeStmt) {
814 return findGapAreaBetween(getPreciseTokenLocEnd(getEnd(AfterStmt)),
815 getStart(BeforeStmt));
821 if (StartLoc == EndLoc)
823 assert(SpellingRegion(
SM, StartLoc, EndLoc).isInSourceOrder());
824 handleFileExit(StartLoc);
825 size_t Index = pushRegion(Count, StartLoc, EndLoc);
826 getRegion().setGap(
true);
827 handleFileExit(EndLoc);
832 struct BreakContinue {
834 Counter ContinueCount;
838 CounterCoverageMappingBuilder(
842 : CoverageMappingBuilder(CVM, SM, LangOpts), CounterMap(CounterMap),
843 DeferredRegion(None) {}
846 void write(llvm::raw_ostream &OS) {
848 gatherFileIDs(VirtualFileMapping);
849 SourceRegionFilter
Filter = emitExpansionRegions();
850 assert(!DeferredRegion &&
"Deferred region never completed");
851 emitSourceRegions(Filter);
852 gatherSkippedRegions();
854 if (MappingRegions.empty())
857 CoverageMappingWriter Writer(VirtualFileMapping, Builder.getExpressions(),
862 void VisitStmt(
const Stmt *S) {
868 handleFileExit(getEnd(S));
871 void VisitDecl(
const Decl *D) {
872 assert(!DeferredRegion &&
"Deferred region never completed");
884 bool Defaulted =
false;
885 if (
auto *Method = dyn_cast<CXXMethodDecl>(D))
886 Defaulted = Method->isDefaulted();
888 propagateCounts(getRegionCounter(Body), Body,
890 assert(RegionStack.empty() &&
"Regions entered but never exited");
895 DeferredRegion = None;
912 void VisitGotoStmt(
const GotoStmt *S) { terminateRegion(S); }
914 void VisitLabelStmt(
const LabelStmt *S) {
915 Counter LabelCount = getRegionCounter(S);
917 completeTopLevelDeferredRegion(LabelCount, Start);
918 completeDeferred(LabelCount, Start);
920 handleFileExit(Start);
921 pushRegion(LabelCount, Start);
925 void VisitBreakStmt(
const BreakStmt *S) {
926 assert(!BreakContinueStack.empty() &&
"break not in a loop or switch!");
927 BreakContinueStack.back().BreakCount = addCounters(
928 BreakContinueStack.back().BreakCount, getRegion().getCounter());
935 assert(!BreakContinueStack.empty() &&
"continue stmt not in a loop!");
936 BreakContinueStack.back().ContinueCount = addCounters(
937 BreakContinueStack.back().ContinueCount, getRegion().getCounter());
941 void VisitCallExpr(
const CallExpr *E) {
951 void VisitWhileStmt(
const WhileStmt *S) {
954 Counter ParentCount = getRegion().getCounter();
955 Counter BodyCount = getRegionCounter(S);
958 BreakContinueStack.push_back(BreakContinue());
960 Counter BackedgeCount = propagateCounts(BodyCount, S->
getBody());
961 BreakContinue BC = BreakContinueStack.pop_back_val();
965 addCounters(ParentCount, BackedgeCount, BC.ContinueCount);
966 propagateCounts(CondCount, S->
getCond());
967 adjustForOutOfOrderTraversal(getEnd(S));
972 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount);
975 addCounters(BC.BreakCount, subtractCounters(CondCount, BodyCount));
976 if (OutCount != ParentCount)
977 pushRegion(OutCount);
980 void VisitDoStmt(
const DoStmt *S) {
983 Counter ParentCount = getRegion().getCounter();
984 Counter BodyCount = getRegionCounter(S);
986 BreakContinueStack.push_back(BreakContinue());
988 Counter BackedgeCount =
989 propagateCounts(addCounters(ParentCount, BodyCount), S->
getBody());
990 BreakContinue BC = BreakContinueStack.pop_back_val();
992 Counter CondCount = addCounters(BackedgeCount, BC.ContinueCount);
993 propagateCounts(CondCount, S->
getCond());
996 addCounters(BC.BreakCount, subtractCounters(CondCount, BodyCount));
997 if (OutCount != ParentCount)
998 pushRegion(OutCount);
1001 void VisitForStmt(
const ForStmt *S) {
1006 Counter ParentCount = getRegion().getCounter();
1007 Counter BodyCount = getRegionCounter(S);
1011 BreakContinueStack.emplace_back();
1014 BreakContinueStack.emplace_back();
1016 Counter BackedgeCount = propagateCounts(BodyCount, S->
getBody());
1017 BreakContinue BodyBC = BreakContinueStack.pop_back_val();
1021 BreakContinue IncrementBC;
1023 propagateCounts(addCounters(BackedgeCount, BodyBC.ContinueCount), Inc);
1024 IncrementBC = BreakContinueStack.pop_back_val();
1028 Counter CondCount = addCounters(
1029 addCounters(ParentCount, BackedgeCount, BodyBC.ContinueCount),
1030 IncrementBC.ContinueCount);
1032 propagateCounts(CondCount, Cond);
1033 adjustForOutOfOrderTraversal(getEnd(S));
1037 auto Gap = findGapAreaBetween(getPreciseTokenLocEnd(S->
getRParenLoc()),
1040 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount);
1042 Counter OutCount = addCounters(BodyBC.BreakCount, IncrementBC.BreakCount,
1043 subtractCounters(CondCount, BodyCount));
1044 if (OutCount != ParentCount)
1045 pushRegion(OutCount);
1055 Counter ParentCount = getRegion().getCounter();
1056 Counter BodyCount = getRegionCounter(S);
1058 BreakContinueStack.push_back(BreakContinue());
1060 Counter BackedgeCount = propagateCounts(BodyCount, S->
getBody());
1061 BreakContinue BC = BreakContinueStack.pop_back_val();
1064 auto Gap = findGapAreaBetween(getPreciseTokenLocEnd(S->
getRParenLoc()),
1067 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount);
1070 addCounters(ParentCount, BackedgeCount, BC.ContinueCount);
1072 addCounters(BC.BreakCount, subtractCounters(LoopCount, BodyCount));
1073 if (OutCount != ParentCount)
1074 pushRegion(OutCount);
1081 Counter ParentCount = getRegion().getCounter();
1082 Counter BodyCount = getRegionCounter(S);
1084 BreakContinueStack.push_back(BreakContinue());
1086 Counter BackedgeCount = propagateCounts(BodyCount, S->
getBody());
1087 BreakContinue BC = BreakContinueStack.pop_back_val();
1090 auto Gap = findGapAreaBetween(getPreciseTokenLocEnd(S->
getRParenLoc()),
1093 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount);
1096 addCounters(ParentCount, BackedgeCount, BC.ContinueCount);
1098 addCounters(BC.BreakCount, subtractCounters(LoopCount, BodyCount));
1099 if (OutCount != ParentCount)
1100 pushRegion(OutCount);
1109 BreakContinueStack.push_back(BreakContinue());
1113 if (
const auto *CS = dyn_cast<CompoundStmt>(Body)) {
1114 if (!CS->body_empty()) {
1119 pushRegion(Counter::getZero(), getStart(CS->body_front()));
1120 for (
const auto *Child : CS->children())
1124 for (
size_t i = RegionStack.size(); i != Index; --i) {
1125 if (!RegionStack[i - 1].hasEndLoc())
1126 RegionStack[i - 1].setEndLoc(getEnd(CS->body_back()));
1132 propagateCounts(Counter::getZero(), Body);
1133 BreakContinue BC = BreakContinueStack.pop_back_val();
1135 if (!BreakContinueStack.empty())
1136 BreakContinueStack.back().ContinueCount = addCounters(
1137 BreakContinueStack.back().ContinueCount, BC.ContinueCount);
1139 Counter ExitCount = getRegionCounter(S);
1141 pushRegion(ExitCount);
1145 MostRecentLocation = getStart(S);
1146 handleFileExit(ExitLoc);
1152 SourceMappingRegion &
Parent = getRegion();
1154 Counter Count = addCounters(Parent.getCounter(), getRegionCounter(S));
1157 if (Parent.hasStartLoc() && Parent.getBeginLoc() == getStart(S))
1158 Parent.setCounter(Count);
1160 pushRegion(Count, getStart(S));
1162 if (
const auto *CS = dyn_cast<CaseStmt>(S)) {
1163 Visit(CS->getLHS());
1164 if (
const Expr *RHS = CS->getRHS())
1170 void VisitIfStmt(
const IfStmt *S) {
1179 Counter ParentCount = getRegion().getCounter();
1180 Counter ThenCount = getRegionCounter(S);
1184 propagateCounts(ParentCount, S->
getCond());
1189 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), ThenCount);
1192 Counter OutCount = propagateCounts(ThenCount, S->
getThen());
1194 Counter ElseCount = subtractCounters(ParentCount, ThenCount);
1197 Gap = findGapAreaBetween(S->
getThen(), Else);
1199 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), ElseCount);
1201 OutCount = addCounters(OutCount, propagateCounts(ElseCount, Else));
1203 OutCount = addCounters(OutCount, ElseCount);
1205 if (OutCount != ParentCount)
1206 pushRegion(OutCount);
1214 Counter ParentCount = getRegion().getCounter();
1220 Counter ExitCount = getRegionCounter(S);
1221 pushRegion(ExitCount);
1231 Counter ParentCount = getRegion().getCounter();
1232 Counter TrueCount = getRegionCounter(E);
1236 if (!isa<BinaryConditionalOperator>(E)) {
1241 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), TrueCount);
1248 propagateCounts(subtractCounters(ParentCount, TrueCount),
1253 extendRegion(E->
getLHS());
1254 propagateCounts(getRegion().getCounter(), E->
getLHS());
1255 handleFileExit(getEnd(E->
getLHS()));
1257 extendRegion(E->
getRHS());
1258 propagateCounts(getRegionCounter(E), E->
getRHS());
1262 extendRegion(E->
getLHS());
1263 propagateCounts(getRegion().getCounter(), E->
getLHS());
1264 handleFileExit(getEnd(E->
getLHS()));
1266 extendRegion(E->
getRHS());
1267 propagateCounts(getRegionCounter(E), E->
getRHS());
1277 return llvm::getInstrProfSectionName(
1282 std::string normalizeFilename(StringRef
Filename) {
1284 llvm::sys::fs::make_absolute(Path);
1285 llvm::sys::path::remove_dots(Path,
true);
1286 return Path.str().str();
1291 static void dump(llvm::raw_ostream &OS, StringRef FunctionName,
1294 OS << FunctionName <<
":\n";
1295 CounterMappingContext Ctx(Expressions);
1296 for (
const auto &R : Regions) {
1299 case CounterMappingRegion::CodeRegion:
1301 case CounterMappingRegion::ExpansionRegion:
1304 case CounterMappingRegion::SkippedRegion:
1307 case CounterMappingRegion::GapRegion:
1312 OS <<
"File " << R.FileID <<
", " << R.LineStart <<
":" << R.ColumnStart
1313 <<
" -> " << R.LineEnd <<
":" << R.ColumnEnd <<
" = ";
1314 Ctx.dump(R.Count, OS);
1315 if (R.Kind == CounterMappingRegion::ExpansionRegion)
1316 OS <<
" (Expanded file = " << R.ExpandedFileID <<
")";
1322 llvm::GlobalVariable *NamePtr, StringRef NameValue, uint64_t FuncHash,
1323 const std::string &CoverageMapping,
bool IsUsed) {
1324 llvm::LLVMContext &Ctx = CGM.getLLVMContext();
1325 if (!FunctionRecordTy) {
1326 #define COVMAP_FUNC_RECORD(Type, LLVMType, Name, Init) LLVMType, 1328 #include "llvm/ProfileData/InstrProfData.inc" 1331 llvm::StructType::get(Ctx, makeArrayRef(FunctionRecordTypes),
1335 #define COVMAP_FUNC_RECORD(Type, LLVMType, Name, Init) Init, 1336 llvm::Constant *FunctionRecordVals[] = {
1337 #include "llvm/ProfileData/InstrProfData.inc" 1339 FunctionRecords.push_back(llvm::ConstantStruct::get(
1340 FunctionRecordTy, makeArrayRef(FunctionRecordVals)));
1342 FunctionNames.push_back(
1343 llvm::ConstantExpr::getBitCast(NamePtr, llvm::Type::getInt8PtrTy(Ctx)));
1344 CoverageMappings.push_back(CoverageMapping);
1346 if (CGM.getCodeGenOpts().DumpCoverageMapping) {
1352 std::vector<StringRef> Filenames;
1353 std::vector<CounterExpression> Expressions;
1354 std::vector<CounterMappingRegion> Regions;
1357 FilenameStrs.resize(FileEntries.size());
1358 FilenameRefs.resize(FileEntries.size());
1359 for (
const auto &Entry : FileEntries) {
1360 auto I = Entry.second;
1361 FilenameStrs[I] = normalizeFilename(Entry.first->getName());
1362 FilenameRefs[I] = FilenameStrs[I];
1364 RawCoverageMappingReader Reader(CoverageMapping, FilenameRefs, Filenames,
1365 Expressions, Regions);
1368 dump(llvm::outs(), NameValue, Expressions, Regions);
1373 if (FunctionRecords.empty())
1375 llvm::LLVMContext &Ctx = CGM.getLLVMContext();
1376 auto *Int32Ty = llvm::Type::getInt32Ty(Ctx);
1381 FilenameStrs.resize(FileEntries.size());
1382 FilenameRefs.resize(FileEntries.size());
1383 for (
const auto &Entry : FileEntries) {
1384 auto I = Entry.second;
1385 FilenameStrs[I] = normalizeFilename(Entry.first->getName());
1386 FilenameRefs[I] = FilenameStrs[I];
1389 std::string FilenamesAndCoverageMappings;
1390 llvm::raw_string_ostream OS(FilenamesAndCoverageMappings);
1391 CoverageFilenamesSectionWriter(FilenameRefs).write(OS);
1392 std::string RawCoverageMappings =
1393 llvm::join(CoverageMappings.begin(), CoverageMappings.end(),
"");
1394 OS << RawCoverageMappings;
1395 size_t CoverageMappingSize = RawCoverageMappings.size();
1396 size_t FilenamesSize = OS.str().size() - CoverageMappingSize;
1399 if (
size_t Rem = OS.str().size() % 8) {
1400 CoverageMappingSize += 8 - Rem;
1401 OS.write_zeros(8 - Rem);
1403 auto *FilenamesAndMappingsVal =
1404 llvm::ConstantDataArray::getString(Ctx, OS.str(),
false);
1408 llvm::ArrayType::get(FunctionRecordTy, FunctionRecords.size());
1409 auto RecordsVal = llvm::ConstantArray::get(RecordsTy, FunctionRecords);
1412 #define COVMAP_HEADER(Type, LLVMType, Name, Init) LLVMType, 1413 #include "llvm/ProfileData/InstrProfData.inc" 1415 auto CovDataHeaderTy =
1416 llvm::StructType::get(Ctx, makeArrayRef(CovDataHeaderTypes));
1417 llvm::Constant *CovDataHeaderVals[] = {
1418 #define COVMAP_HEADER(Type, LLVMType, Name, Init) Init, 1419 #include "llvm/ProfileData/InstrProfData.inc" 1421 auto CovDataHeaderVal = llvm::ConstantStruct::get(
1422 CovDataHeaderTy, makeArrayRef(CovDataHeaderVals));
1425 llvm::Type *CovDataTypes[] = {CovDataHeaderTy, RecordsTy,
1426 FilenamesAndMappingsVal->getType()};
1427 auto CovDataTy = llvm::StructType::get(Ctx, makeArrayRef(CovDataTypes));
1428 llvm::Constant *TUDataVals[] = {CovDataHeaderVal, RecordsVal,
1429 FilenamesAndMappingsVal};
1431 llvm::ConstantStruct::get(CovDataTy, makeArrayRef(TUDataVals));
1432 auto CovData =
new llvm::GlobalVariable(
1434 CovDataVal, llvm::getCoverageMappingVarName());
1436 CovData->setSection(getCoverageSection(CGM));
1437 CovData->setAlignment(8);
1440 CGM.addUsedGlobal(CovData);
1442 if (!FunctionNames.empty()) {
1443 auto NamesArrTy = llvm::ArrayType::get(llvm::Type::getInt8PtrTy(Ctx),
1444 FunctionNames.size());
1445 auto NamesArrVal = llvm::ConstantArray::get(NamesArrTy, FunctionNames);
1448 new llvm::GlobalVariable(CGM.getModule(), NamesArrTy,
true,
1450 llvm::getCoverageUnusedNamesVarName());
1455 auto It = FileEntries.find(File);
1456 if (It != FileEntries.end())
1458 unsigned FileID = FileEntries.size();
1459 FileEntries.insert(std::make_pair(File,
FileID));
1464 llvm::raw_ostream &OS) {
1466 CounterCoverageMappingBuilder Walker(CVM, *CounterMap,
SM, LangOpts);
1467 Walker.VisitDecl(D);
1472 llvm::raw_ostream &OS) {
1473 EmptyCoverageMappingBuilder Walker(CVM,
SM, LangOpts);
1474 Walker.VisitDecl(D);
SourceLocation getLocForStartOfFile(FileID FID) const
Return the source location corresponding to the first byte of the specified file. ...
bool isWrittenInSameFile(SourceLocation Loc1, SourceLocation Loc2) const
Returns true if the spelling locations for both SourceLocations are part of the same file buffer...
SourceLocation getLocWithOffset(int Offset) const
Return a source location with the specified offset from this SourceLocation.
A (possibly-)qualified type.
const Expr * getSubExpr() const
SourceLocation getLocForEndOfFile(FileID FID) const
Return the source location corresponding to the last byte of the specified file.
ConstStmtVisitor - This class implements a simple visitor for Stmt subclasses.
virtual Stmt * getBody() const
getBody - If this Decl represents a declaration for a body of code, such as a function or method defi...
Stmt - This represents one statement.
CXXCatchStmt * getHandler(unsigned i)
IfStmt - This represents an if/then/else.
const llvm::Triple & getTriple() const
Returns the target triple of the primary target.
StringRef getBufferName(SourceLocation Loc, bool *Invalid=nullptr) const
Return the filename or buffer identifier of the buffer the location is in.
Decl - This represents one declaration (or definition), e.g.
Stmt * getHandlerBlock() const
bool isBeforeInTranslationUnit(SourceLocation LHS, SourceLocation RHS) const
Determines the order of 2 source locations in the translation unit.
Expr * getFalseExpr() const
const TargetInfo & getTargetInfo() const
A C++ throw-expression (C++ [except.throw]).
void emit()
Emit the coverage mapping data for a translation unit.
LabelStmt - Represents a label, which has a substatement.
SourceLocation getBegin() const
SourceLocation getBeginLoc() const LLVM_READONLY
void addFunctionMappingRecord(llvm::GlobalVariable *FunctionName, StringRef FunctionNameValue, uint64_t FunctionHash, const std::string &CoverageMapping, bool IsUsed=true)
Add a function's coverage mapping record to the collection of the function mapping records...
SourceLocation getQuestionLoc() const
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
ForStmt - This represents a 'for (init;cond;inc)' stmt.
static void dump(llvm::raw_ostream &OS, StringRef FunctionName, ArrayRef< CounterExpression > Expressions, ArrayRef< CounterMappingRegion > Regions)
SourceLocation getRParenLoc() const
A builtin binary operation expression such as "x + y" or "x <= y".
CXXForRangeStmt - This represents C++0x [stmt.ranged]'s ranged for statement, represented as 'for (ra...
unsigned getSpellingLineNumber(SourceLocation Loc, bool *Invalid=nullptr) const
SourceLocation getSpellingLoc(SourceLocation Loc) const
Given a SourceLocation object, return the spelling location referenced by the ID. ...
A C++ lambda expression, which produces a function object (of unspecified type) that can be invoked l...
unsigned getFileIDSize(FileID FID) const
The size of the SLocEntry that FID represents.
bool isInFileID(SourceLocation Loc, FileID FID, unsigned *RelativeOffset=nullptr) const
Given a specific FileID, returns true if Loc is inside that FileID chunk and sets relative offset (of...
This represents one expression.
bool isInSystemHeader(SourceLocation Loc) const
Returns if a SourceLocation is in a system header.
static unsigned MeasureTokenLength(SourceLocation Loc, const SourceManager &SM, const LangOptions &LangOpts)
MeasureTokenLength - Relex the token at the specified location and return its length in bytes in the ...
const FileEntry * getFileEntryForID(FileID FID) const
Returns the FileEntry record for the provided FileID.
Organizes the cross-function state that is used while generating code coverage mapping data...
CXXTryStmt - A C++ try block, including all handlers.
void SourceRangeSkipped(SourceRange Range, SourceLocation EndifLoc) override
Hook called when a source range is skipped.
CharSourceRange getImmediateExpansionRange(SourceLocation Loc) const
Return the start/end of the expansion information for an expansion location.
ReturnStmt - This represents a return, optionally of an expression: return; return 4;...
Expr * getTrueExpr() const
ASTContext & getContext() const
SourceLocation getEndLoc() const LLVM_READONLY
unsigned getFileID(const FileEntry *File)
Return the coverage mapping translation unit file id for the given file.
DoStmt - This represents a 'do/while' stmt.
virtual bool hasBody() const
Returns true if this Decl represents a declaration for a body of code, such as a function or method d...
The l-value was considered opaque, so the alignment was determined from a type.
unsigned getFileOffset(SourceLocation SpellingLoc) const
Returns the offset from the start of the file that the specified SourceLocation represents.
std::pair< FileID, unsigned > getDecomposedSpellingLoc(SourceLocation Loc) const
Decompose the specified location into a raw FileID + Offset pair.
Encodes a location in the source.
unsigned getNumHandlers() const
ArrayRef< SourceRange > getSkippedRanges() const
Cached information about one file (either on disk or in the virtual file system). ...
CoverageSourceInfo & getSourceInfo() const
unsigned getSpellingColumnNumber(SourceLocation Loc, bool *Invalid=nullptr) const
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
This class organizes the cross-function state that is used while generating LLVM code.
Dataflow Directional Tag Classes.
bool isValid() const
Return true if this is a valid SourceLocation object.
SourceLocation getIncludeLoc(FileID FID) const
Returns the include location if FID is a #include'd file otherwise it returns an invalid location...
FileID getMainFileID() const
Returns the FileID of the main source file.
FunctionType::ExtInfo getFunctionExtInfo(const Type &t)
SwitchStmt - This represents a 'switch' stmt.
FileID getFileID(SourceLocation SpellingLoc) const
Return the FileID for a SourceLocation.
SourceLocation getRParenLoc() const
bool isMacroArgExpansion(SourceLocation Loc, SourceLocation *StartLoc=nullptr) const
Tests whether the given source location represents a macro argument's expansion into the function-lik...
Represents Objective-C's collection statement.
AbstractConditionalOperator - An abstract base class for ConditionalOperator and BinaryConditionalOpe...
Internal linkage, which indicates that the entity can be referred to from within the translation unit...
SourceLocation getRParenLoc() const
DeclStmt * getRangeStmt()
GotoStmt - This represents a direct goto.
void emitCounterMapping(const Decl *D, llvm::raw_ostream &OS)
Emit the coverage mapping data which maps the regions of code to counters that will be used to find t...
ContinueStmt - This represents a continue.
CXXCatchStmt - This represents a C++ catch block.
WhileStmt - This represents a 'while' stmt.
CompoundStmt * getTryBlock()
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
__DEVICE__ int max(int __a, int __b)
BreakStmt - This represents a break.
__DEVICE__ int min(int __a, int __b)
DeclStmt * getLoopVarStmt()
A trivial tuple used to represent a source range.
void emitEmptyMapping(const Decl *D, llvm::raw_ostream &OS)
Emit the coverage mapping data for an unused function.
This class handles loading and caching of source files into memory.