clang: lib/CodeGen/CoverageMappingGen.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
18#include "llvm/ADT/DenseSet.h"
19#include "llvm/ADT/SmallSet.h"
20#include "llvm/ADT/StringExtras.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/Support/FileSystem.h"
25#include "llvm/Support/Path.h"
26#include
27
28
29
30#define COVMAP_V3
31
32namespace llvm {
33cl::opt
35 llvm:🆑:ZeroOrMore,
36 llvm:🆑:desc("Enable single byte coverage"),
37 llvm:🆑:Hidden, llvm:🆑:init(false));
38}
39
41 "emptyline-comment-coverage",
42 llvm:🆑:desc("Emit emptylines and comment lines as skipped regions (only "
43 "disable it on test)"),
44 llvm:🆑:init(true), llvm:🆑:Hidden);
45
48 "system-headers-coverage",
49 cl::desc("Enable collecting coverage from system headers"), cl::init(false),
50 cl::Hidden);
51}
52
53using namespace clang;
54using namespace CodeGen;
56
61 PP.addPPCallbacks(std::unique_ptr(CoverageInfo));
67
69 if (Tok.getKind() != clang::tok::eod)
71 });
72 }
73 return CoverageInfo;
74}
75
79 PrevTokLoc == SkippedRanges.back().PrevTokLoc &&
80 SourceMgr.isWrittenInSameFile(SkippedRanges.back().Range.getEnd(),
82 SkippedRanges.back().Range.setEnd(Range.getEnd());
83 else
84 SkippedRanges.push_back({Range, RangeKind, PrevTokLoc});
85}
86
89}
90
93}
94
97 return false;
98}
99
101 if (!SkippedRanges.empty() && SkippedRanges.back().NextTokLoc.isInvalid())
102 SkippedRanges.back().NextTokLoc = Loc;
103}
104
105namespace {
106
107class SourceMappingRegion {
108
109 Counter Count;
110
111
112 std::optional FalseCount;
113
114
115 mcdc::Parameters MCDCParams;
116
117
118 std::optional LocStart;
119
120
121 std::optional LocEnd;
122
123
124
125 bool GapRegion;
126
127
128
129 bool SkippedRegion;
130
131public:
132 SourceMappingRegion(Counter Count, std::optional LocStart,
133 std::optional LocEnd,
134 bool GapRegion = false)
135 : Count(Count), LocStart(LocStart), LocEnd(LocEnd), GapRegion(GapRegion),
136 SkippedRegion(false) {}
137
138 SourceMappingRegion(Counter Count, std::optional FalseCount,
139 mcdc::Parameters MCDCParams,
140 std::optional LocStart,
141 std::optional LocEnd,
142 bool GapRegion = false)
143 : Count(Count), FalseCount(FalseCount), MCDCParams(MCDCParams),
144 LocStart(LocStart), LocEnd(LocEnd), GapRegion(GapRegion),
145 SkippedRegion(false) {}
146
147 SourceMappingRegion(mcdc::Parameters MCDCParams,
148 std::optional LocStart,
149 std::optional LocEnd)
150 : MCDCParams(MCDCParams), LocStart(LocStart), LocEnd(LocEnd),
151 GapRegion(false), SkippedRegion(false) {}
152
153 const Counter &getCounter() const { return Count; }
154
155 const Counter &getFalseCounter() const {
156 assert(FalseCount && "Region has no alternate counter");
157 return *FalseCount;
158 }
159
160 void setCounter(Counter C) { Count = C; }
161
162 bool hasStartLoc() const { return LocStart.has_value(); }
163
165
167 assert(LocStart && "Region has no start location");
168 return *LocStart;
169 }
170
171 bool hasEndLoc() const { return LocEnd.has_value(); }
172
174 assert(Loc.isValid() && "Setting an invalid end location");
175 LocEnd = Loc;
176 }
177
179 assert(LocEnd && "Region has no end location");
180 return *LocEnd;
181 }
182
183 bool isGap() const { return GapRegion; }
184
185 void setGap(bool Gap) { GapRegion = Gap; }
186
187 bool isSkipped() const { return SkippedRegion; }
188
189 void setSkipped(bool Skipped) { SkippedRegion = Skipped; }
190
191 bool isBranch() const { return FalseCount.has_value(); }
192
193 bool isMCDCBranch() const {
194 return std::holds_alternativemcdc::BranchParameters(MCDCParams);
195 }
196
197 const auto &getMCDCBranchParams() const {
198 return mcdc::getParams(MCDCParams);
199 }
200
201 bool isMCDCDecision() const {
202 return std::holds_alternativemcdc::DecisionParameters(MCDCParams);
203 }
204
205 const auto &getMCDCDecisionParams() const {
206 return mcdc::getParams(MCDCParams);
207 }
208
209 const mcdc::Parameters &getMCDCParams() const { return MCDCParams; }
210
211 void resetMCDCParams() { MCDCParams = mcdc::Parameters(); }
212};
213
214
215struct SpellingRegion {
216
217 unsigned LineStart;
218
219
220 unsigned ColumnStart;
221
222
223 unsigned LineEnd;
224
225
226 unsigned ColumnEnd;
227
230 LineStart = SM.getSpellingLineNumber(LocStart);
231 ColumnStart = SM.getSpellingColumnNumber(LocStart);
232 LineEnd = SM.getSpellingLineNumber(LocEnd);
233 ColumnEnd = SM.getSpellingColumnNumber(LocEnd);
234 }
235
236 SpellingRegion(SourceManager &SM, SourceMappingRegion &R)
237 : SpellingRegion(SM, R.getBeginLoc(), R.getEndLoc()) {}
238
239
240
241 bool isInSourceOrder() const {
242 return (LineStart < LineEnd) ||
243 (LineStart == LineEnd && ColumnStart <= ColumnEnd);
244 }
245};
246
247
248
249class CoverageMappingBuilder {
250public:
254
255private:
256
257 llvm::SmallDenseMap<FileID, std::pair<unsigned, SourceLocation>, 8>
258 FileIDMapping;
259
260public:
261
263
264 std::vector SourceRegions;
265
266
267
268
269
270
271 typedef llvm::SmallSet<std::pair<SourceLocation, SourceLocation>, 8>
272 SourceRegionFilter;
273
276 : CVM(CVM), SM(SM), LangOpts(LangOpts) {}
277
278
280
281
282 unsigned TokLen =
285 }
286
287
291 return SM.getLocForStartOfFile(SM.getFileID(Loc));
292 }
293
294
299 return SM.getLocForEndOfFile(SM.getFileID(Loc));
300 }
301
302
303
304
305
306
307
308
309 std::pair<SourceLocation, std::optional>
311 std::optional EndLoc = std::nullopt;
313 SM.isWrittenInScratchSpace(SM.getSpellingLoc(Loc))) {
314 auto ExpansionRange = SM.getImmediateExpansionRange(Loc);
315 Loc = ExpansionRange.getBegin();
316 EndLoc = ExpansionRange.getEnd();
317 }
318 return std::make_pair(Loc, EndLoc);
319 }
320
321
322
323
325 bool AcceptScratch = true) {
327 return SM.getIncludeLoc(SM.getFileID(Loc));
328 Loc = SM.getImmediateExpansionRange(Loc).getBegin();
329 if (AcceptScratch)
330 return Loc;
331 return getNonScratchExpansionLoc(Loc).first;
332 }
333
334
336 return SM.getBufferName(SM.getSpellingLoc(Loc)) == "";
337 }
338
339
341 do {
342 Loc = getIncludeOrExpansionLoc(Loc);
344 return false;
346 return true;
347 }
348
349
352 while (SM.isMacroArgExpansion(Loc) || isInBuiltin(Loc))
353 Loc = SM.getImmediateExpansionRange(Loc).getBegin();
354 return Loc;
355 }
356
357
360 while (SM.isMacroArgExpansion(Loc) || isInBuiltin(Loc))
361 Loc = SM.getImmediateExpansionRange(Loc).getBegin();
362 return getPreciseTokenLocEnd(Loc);
363 }
364
365
366
367
368
369
371 FileIDMapping.clear();
372
373 llvm::SmallSet<FileID, 8> Visited;
375 for (auto &Region : SourceRegions) {
377
378
379 auto NonScratchExpansionLoc = getNonScratchExpansionLoc(Loc);
380 auto EndLoc = NonScratchExpansionLoc.second;
381 if (EndLoc.has_value()) {
382 Loc = NonScratchExpansionLoc.first;
383 Region.setStartLoc(Loc);
384 Region.setEndLoc(EndLoc.value());
385 }
386
387
389 auto BeginLoc = SM.getSpellingLoc(Loc);
390 auto EndLoc = SM.getSpellingLoc(Region.getEndLoc());
391 if (SM.isWrittenInSameFile(BeginLoc, EndLoc)) {
393 Region.setStartLoc(Loc);
394 Region.setEndLoc(SM.getFileLoc(Region.getEndLoc()));
395 }
396 }
397
400 continue;
401
403 .isInSystemHeader(SM.getSpellingLoc(Loc)));
404
405 unsigned Depth = 0;
408 ++Depth;
409 FileLocs.push_back(std::make_pair(Loc, Depth));
410 }
411 llvm::stable_sort(FileLocs, llvm::less_second());
412
413 for (const auto &FL : FileLocs) {
415 FileID SpellingFile = SM.getDecomposedSpellingLoc(Loc).first;
416 auto Entry = SM.getFileEntryRefForID(SpellingFile);
417 if (!Entry)
418 continue;
419
420 FileIDMapping[SM.getFileID(Loc)] = std::make_pair(Mapping.size(), Loc);
421 Mapping.push_back(CVM.getFileID(*Entry));
422 }
423 }
424
425
426
427
429 auto Mapping = FileIDMapping.find(SM.getFileID(Loc));
430 if (Mapping != FileIDMapping.end())
431 return Mapping->second.first;
432 return std::nullopt;
433 }
434
435
436
437
438
439
440 std::optional adjustSkippedRange(SourceManager &SM,
445 SpellingRegion SR{SM, LocStart, LocEnd};
446 SR.ColumnStart = 1;
447 if (PrevTokLoc.isValid() && SM.isWrittenInSameFile(LocStart, PrevTokLoc) &&
448 SR.LineStart == SM.getSpellingLineNumber(PrevTokLoc))
449 SR.LineStart++;
450 if (NextTokLoc.isValid() && SM.isWrittenInSameFile(LocEnd, NextTokLoc) &&
451 SR.LineEnd == SM.getSpellingLineNumber(NextTokLoc)) {
452 SR.LineEnd--;
453 SR.ColumnEnd++;
454 }
455 if (SR.isInSourceOrder())
456 return SR;
457 return std::nullopt;
458 }
459
460
461
462 void gatherSkippedRegions() {
463
464
466 FileLineRanges.resize(
467 FileIDMapping.size(),
468 std::make_pair(std::numeric_limits::max(), 0));
469 for (const auto &R : MappingRegions) {
470 FileLineRanges[R.FileID].first =
471 std::min(FileLineRanges[R.FileID].first, R.LineStart);
472 FileLineRanges[R.FileID].second =
473 std::max(FileLineRanges[R.FileID].second, R.LineEnd);
474 }
475
477 for (auto &I : SkippedRanges) {
481 assert(SM.isWrittenInSameFile(LocStart, LocEnd) &&
482 "region spans multiple files");
483
484 auto CovFileID = getCoverageFileID(LocStart);
485 if (!CovFileID)
486 continue;
487 std::optional SR;
488 if (I.isComment())
489 SR = adjustSkippedRange(SM, LocStart, LocEnd, I.PrevTokLoc,
490 I.NextTokLoc);
491 else if (I.isPPIfElse() || I.isEmptyLine())
492 SR = {SM, LocStart, LocEnd};
493
494 if (!SR)
495 continue;
496 auto Region = CounterMappingRegion::makeSkipped(
497 *CovFileID, SR->LineStart, SR->ColumnStart, SR->LineEnd,
498 SR->ColumnEnd);
499
500
501 if (Region.LineStart >= FileLineRanges[*CovFileID].first &&
502 Region.LineEnd <= FileLineRanges[*CovFileID].second)
503 MappingRegions.push_back(Region);
504 }
505 }
506
507
508
509 void emitSourceRegions(const SourceRegionFilter &Filter) {
510 for (const auto &Region : SourceRegions) {
511 assert(Region.hasEndLoc() && "incomplete region");
512
514 assert(SM.getFileID(LocStart).isValid() && "region in invalid file");
515
516
517
519 SM.isInSystemHeader(SM.getSpellingLoc(LocStart))) {
520 assert(!Region.isMCDCBranch() && !Region.isMCDCDecision() &&
521 "Don't suppress the condition in system headers");
522 continue;
523 }
524
525 auto CovFileID = getCoverageFileID(LocStart);
526
527 if (!CovFileID) {
528 assert(!Region.isMCDCBranch() && !Region.isMCDCDecision() &&
529 "Don't suppress the condition in non-file regions");
530 continue;
531 }
532
534 assert(SM.isWrittenInSameFile(LocStart, LocEnd) &&
535 "region spans multiple files");
536
537
538
539
540
541 if (Filter.count(std::make_pair(LocStart, LocEnd))) {
542 assert(!Region.isMCDCBranch() && !Region.isMCDCDecision() &&
543 "Don't suppress the condition");
544 continue;
545 }
546
547
548 SpellingRegion SR{SM, LocStart, LocEnd};
549 assert(SR.isInSourceOrder() && "region start and end out of order");
550
551 if (Region.isGap()) {
552 MappingRegions.push_back(CounterMappingRegion::makeGapRegion(
553 Region.getCounter(), *CovFileID, SR.LineStart, SR.ColumnStart,
554 SR.LineEnd, SR.ColumnEnd));
555 } else if (Region.isSkipped()) {
556 MappingRegions.push_back(CounterMappingRegion::makeSkipped(
557 *CovFileID, SR.LineStart, SR.ColumnStart, SR.LineEnd,
558 SR.ColumnEnd));
559 } else if (Region.isBranch()) {
560 MappingRegions.push_back(CounterMappingRegion::makeBranchRegion(
561 Region.getCounter(), Region.getFalseCounter(), *CovFileID,
562 SR.LineStart, SR.ColumnStart, SR.LineEnd, SR.ColumnEnd,
563 Region.getMCDCParams()));
564 } else if (Region.isMCDCDecision()) {
565 MappingRegions.push_back(CounterMappingRegion::makeDecisionRegion(
566 Region.getMCDCDecisionParams(), *CovFileID, SR.LineStart,
567 SR.ColumnStart, SR.LineEnd, SR.ColumnEnd));
568 } else {
569 MappingRegions.push_back(CounterMappingRegion::makeRegion(
570 Region.getCounter(), *CovFileID, SR.LineStart, SR.ColumnStart,
571 SR.LineEnd, SR.ColumnEnd));
572 }
573 }
574 }
575
576
577 SourceRegionFilter emitExpansionRegions() {
578 SourceRegionFilter Filter;
579 for (const auto &FM : FileIDMapping) {
581 SourceLocation ParentLoc = getIncludeOrExpansionLoc(ExpandedLoc, false);
583 continue;
584
585 auto ParentFileID = getCoverageFileID(ParentLoc);
586 if (!ParentFileID)
587 continue;
588 auto ExpandedFileID = getCoverageFileID(ExpandedLoc);
589 assert(ExpandedFileID && "expansion in uncovered file");
590
591 SourceLocation LocEnd = getPreciseTokenLocEnd(ParentLoc);
592 assert(SM.isWrittenInSameFile(ParentLoc, LocEnd) &&
593 "region spans multiple files");
594 Filter.insert(std::make_pair(ParentLoc, LocEnd));
595
596 SpellingRegion SR{SM, ParentLoc, LocEnd};
597 assert(SR.isInSourceOrder() && "region start and end out of order");
598 MappingRegions.push_back(CounterMappingRegion::makeExpansion(
599 *ParentFileID, *ExpandedFileID, SR.LineStart, SR.ColumnStart,
600 SR.LineEnd, SR.ColumnEnd));
601 }
603 }
604};
605
606
607
608struct EmptyCoverageMappingBuilder : public CoverageMappingBuilder {
611 : CoverageMappingBuilder(CVM, SM, LangOpts) {}
612
613 void VisitDecl(const Decl *D) {
615 return;
619 if (.isWrittenInSameFile(Start, End)) {
620
621
622 FileID StartFileID = SM.getFileID(Start);
623 FileID EndFileID = SM.getFileID(End);
624 while (StartFileID != EndFileID && !isNestedIn(End, StartFileID)) {
625 Start = getIncludeOrExpansionLoc(Start);
626 assert(Start.isValid() &&
627 "Declaration start location not nested within a known region");
628 StartFileID = SM.getFileID(Start);
629 }
630 while (StartFileID != EndFileID) {
631 End = getPreciseTokenLocEnd(getIncludeOrExpansionLoc(End));
632 assert(End.isValid() &&
633 "Declaration end location not nested within a known region");
634 EndFileID = SM.getFileID(End);
635 }
636 }
637 SourceRegions.emplace_back(Counter(), Start, End);
638 }
639
640
641 void write(llvm::raw_ostream &OS) {
643 gatherFileIDs(FileIDMapping);
644 emitSourceRegions(SourceRegionFilter());
645
646 if (MappingRegions.empty())
647 return;
648
649 CoverageMappingWriter Writer(FileIDMapping, {}, MappingRegions);
650 Writer.write(OS);
651 }
652};
653
654
655
656
657
658
659
660
661
662struct MCDCCoverageBuilder {
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751private:
753
756 const Stmt *DecisionStmt = nullptr;
757 mcdc::ConditionID NextID = 0;
758 bool NotMapped = false;
759
760
761
762 static constexpr mcdc::ConditionIDs DecisionStackSentinel{-1, -1};
763
764
766 return E->getOpcode() == BO_LAnd;
767 }
768
769public:
771 : CGM(CGM), DecisionStack(1, DecisionStackSentinel),
772 MCDCState(MCDCState) {}
773
774
775
776
777 bool isIdle() const { return (NextID == 0 && !NotMapped); }
778
779
780
781
782 bool isBuilding() const { return (NextID > 0); }
783
784
785 void setCondID(const Expr *Cond, mcdc::ConditionID ID) {
786 MCDCState.BranchByStmt[CodeGenFunction::stripCond(Cond)] = {ID,
787 DecisionStmt};
788 }
789
790
791 mcdc::ConditionID getCondID(const Expr *Cond) const {
792 auto I = MCDCState.BranchByStmt.find(CodeGenFunction::stripCond(Cond));
794 return -1;
795 else
796 return I->second.ID;
797 }
798
799
800 const mcdc::ConditionIDs &back() const { return DecisionStack.back(); }
801
802
803
804
807 return;
808
809
810 if (!isBuilding() &&
811 !MCDCState.DecisionByStmt.contains(CodeGenFunction::stripCond(E)))
812 NotMapped = true;
813
814
815 if (NotMapped)
816 return;
817
818 if (NextID == 0) {
819 DecisionStmt = E;
821 }
822
823 const mcdc::ConditionIDs &ParentDecision = DecisionStack.back();
824
825
826
827
828 if (MCDCState.BranchByStmt.contains(CodeGenFunction::stripCond(E)))
829 setCondID(E->getLHS(), getCondID(E));
830 else
831 setCondID(E->getLHS(), NextID++);
832
833
834 mcdc::ConditionID RHSid = NextID++;
835 setCondID(E->getRHS(), RHSid);
836
837
838 if (isLAnd(E))
839 DecisionStack.push_back({ParentDecision[false], RHSid});
840 else
841 DecisionStack.push_back({RHSid, ParentDecision[true]});
842 }
843
844
845 mcdc::ConditionIDs pop() {
847 return DecisionStackSentinel;
848
849 assert(DecisionStack.size() > 1);
850 return DecisionStack.pop_back_val();
851 }
852
853
854
855 unsigned getTotalConditionsAndReset(const BinaryOperator *E) {
857 return 0;
858
859 assert(!isIdle());
860 assert(DecisionStack.size() == 1);
861
862
863 if (NotMapped) {
864 NotMapped = false;
865 assert(NextID == 0);
866 return 0;
867 }
868
869
870 unsigned TotalConds = NextID;
871
872
873 NextID = 0;
874
875 return TotalConds;
876 }
877};
878
879
880
881struct CounterCoverageMappingBuilder
882 : public CoverageMappingBuilder,
884
885 llvm::DenseMap<const Stmt *, CounterPair> &CounterMap;
886
888
889
891
892
893
894 llvm::DenseSet<const Stmt *> LeafExprSet;
895
896
897 MCDCCoverageBuilder MCDCBuilder;
898
899 CounterExpressionBuilder Builder;
900
901
902
903
904
906
907
908 bool HasTerminateStmt = false;
909
910
911 Counter GapRegionCounter;
912
913
914 Counter subtractCounters(Counter LHS, Counter RHS, bool Simplify = true) {
916 "cannot add counters when single byte coverage mode is enabled");
917 return Builder.subtract(LHS, RHS, Simplify);
918 }
919
920
921 Counter addCounters(Counter LHS, Counter RHS, bool Simplify = true) {
922 return Builder.add(LHS, RHS, Simplify);
923 }
924
925 Counter addCounters(Counter C1, Counter C2, Counter C3,
926 bool Simplify = true) {
927 return addCounters(addCounters(C1, C2, Simplify), C3, Simplify);
928 }
929
930
931
932
933 Counter getRegionCounter(const Stmt *S) {
934 return Counter::getCounter(CounterMap[S].Executed);
935 }
936
937 struct BranchCounterPair {
938 Counter Executed;
939 Counter Skipped;
940 };
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958 BranchCounterPair
959 getBranchCounterPair(const Stmt *S, Counter ParentCnt,
960 std::optional SkipCntForOld = std::nullopt) {
961 Counter ExecCnt = getRegionCounter(S);
962
963
964
966 assert(SkipCntForOld &&
967 "SingleByte must provide SkipCntForOld as a fake Skipped count.");
968 return {ExecCnt, *SkipCntForOld};
969 }
970
971 return {ExecCnt, Builder.subtract(ParentCnt, ExecCnt)};
972 }
973
974 bool IsCounterEqual(Counter OutCount, Counter ParentCount) {
975 if (OutCount == ParentCount)
976 return true;
977
978 return false;
979 }
980
981
982
983
984
985 size_t pushRegion(Counter Count,
986 std::optional StartLoc = std::nullopt,
987 std::optional EndLoc = std::nullopt,
988 std::optional FalseCount = std::nullopt,
989 const mcdc::Parameters &BranchParams = std::monostate()) {
990
991 if (StartLoc && !FalseCount) {
992 MostRecentLocation = *StartLoc;
993 }
994
995
996
997 assert((!StartLoc || StartLoc->isValid()) && "Start location is not valid");
998 assert((!EndLoc || EndLoc->isValid()) && "End location is not valid");
999
1000
1001
1002
1003
1004 if (StartLoc && StartLoc->isInvalid())
1005 StartLoc = std::nullopt;
1006 if (EndLoc && EndLoc->isInvalid())
1007 EndLoc = std::nullopt;
1008 RegionStack.emplace_back(Count, FalseCount, BranchParams, StartLoc, EndLoc);
1009
1010 return RegionStack.size() - 1;
1011 }
1012
1013 size_t pushRegion(const mcdc::DecisionParameters &DecisionParams,
1014 std::optional StartLoc = std::nullopt,
1015 std::optional EndLoc = std::nullopt) {
1016
1017 RegionStack.emplace_back(DecisionParams, StartLoc, EndLoc);
1018
1019 return RegionStack.size() - 1;
1020 }
1021
1023 size_t Depth = 0;
1025 Loc = getIncludeOrExpansionLoc(Loc);
1026 Depth++;
1027 }
1028 return Depth;
1029 }
1030
1031
1032
1033
1034
1035 void popRegions(size_t ParentIndex) {
1036 assert(RegionStack.size() >= ParentIndex && "parent not in stack");
1037 while (RegionStack.size() > ParentIndex) {
1038 SourceMappingRegion &Region = RegionStack.back();
1039 if (Region.hasStartLoc() &&
1040 (Region.hasEndLoc() || RegionStack[ParentIndex].hasEndLoc())) {
1043 ? Region.getEndLoc()
1044 : RegionStack[ParentIndex].getEndLoc();
1045 bool isBranch = Region.isBranch();
1046 size_t StartDepth = locationDepth(StartLoc);
1047 size_t EndDepth = locationDepth(EndLoc);
1048 while (.isWrittenInSameFile(StartLoc, EndLoc)) {
1049 bool UnnestStart = StartDepth >= EndDepth;
1050 bool UnnestEnd = EndDepth >= StartDepth;
1051 if (UnnestEnd) {
1052
1053
1054
1055
1056
1057
1058 SourceLocation NestedLoc = getStartOfFileOrMacro(EndLoc);
1059 assert(SM.isWrittenInSameFile(NestedLoc, EndLoc));
1060
1061 if (!isBranch && !isRegionAlreadyAdded(NestedLoc, EndLoc))
1062 SourceRegions.emplace_back(Region.getCounter(), NestedLoc,
1063 EndLoc);
1064
1065 EndLoc = getPreciseTokenLocEnd(getIncludeOrExpansionLoc(EndLoc));
1067 llvm::report_fatal_error(
1068 "File exit not handled before popRegions");
1069 EndDepth--;
1070 }
1071 if (UnnestStart) {
1072
1073
1074
1075
1076
1077
1078 SourceLocation NestedLoc = getEndOfFileOrMacro(StartLoc);
1079 assert(SM.isWrittenInSameFile(StartLoc, NestedLoc));
1080
1081 if (!isBranch && !isRegionAlreadyAdded(StartLoc, NestedLoc))
1082 SourceRegions.emplace_back(Region.getCounter(), StartLoc,
1083 NestedLoc);
1084
1085 StartLoc = getIncludeOrExpansionLoc(StartLoc);
1087 llvm::report_fatal_error(
1088 "File exit not handled before popRegions");
1089 StartDepth--;
1090 }
1091 }
1092 Region.setStartLoc(StartLoc);
1093 Region.setEndLoc(EndLoc);
1094
1095 if (!isBranch) {
1096 MostRecentLocation = EndLoc;
1097
1098
1099 if (StartLoc == getStartOfFileOrMacro(StartLoc) &&
1100 EndLoc == getEndOfFileOrMacro(EndLoc))
1101 MostRecentLocation = getIncludeOrExpansionLoc(EndLoc);
1102 }
1103
1104 assert(SM.isWrittenInSameFile(Region.getBeginLoc(), EndLoc));
1105 assert(SpellingRegion(SM, Region).isInSourceOrder());
1106 SourceRegions.push_back(Region);
1107 }
1108 RegionStack.pop_back();
1109 }
1110 }
1111
1112
1113 SourceMappingRegion &getRegion() {
1114 assert(!RegionStack.empty() && "statement has no region");
1115 return RegionStack.back();
1116 }
1117
1118
1119
1120 Counter propagateCounts(Counter TopCount, const Stmt *S,
1121 bool VisitChildren = true) {
1124 size_t Index = pushRegion(TopCount, StartLoc, EndLoc);
1125 if (VisitChildren)
1126 Visit(S);
1127 Counter ExitCount = getRegion().getCounter();
1128 popRegions(Index);
1129
1130
1131
1132 if (SM.isBeforeInTranslationUnit(StartLoc, S->getBeginLoc()))
1133 MostRecentLocation = EndLoc;
1134
1135 return ExitCount;
1136 }
1137
1138
1139
1140
1141
1142 void createBranchRegion(const Expr *C, Counter TrueCnt, Counter FalseCnt,
1143 const mcdc::ConditionIDs &Conds = {}) {
1144
1145 if ()
1146 return;
1147
1148
1149
1150
1151
1152
1153
1154 if (CodeGenFunction::isInstrumentedCondition(C) ||
1155 LeafExprSet.count(CodeGenFunction::stripCond(C))) {
1156 mcdc::Parameters BranchParams;
1157 mcdc::ConditionID ID = MCDCBuilder.getCondID(C);
1158 if (ID >= 0)
1159 BranchParams = mcdc::BranchParameters{ID, Conds};
1160
1161
1162
1163
1164
1165
1166
1169 if (Result.Val.getInt().getBoolValue())
1170 FalseCnt = Counter::getZero();
1171 else
1172 TrueCnt = Counter::getZero();
1173 }
1174 popRegions(
1175 pushRegion(TrueCnt, getStart(C), getEnd(C), FalseCnt, BranchParams));
1176 }
1177 }
1178
1179
1180
1181
1182 void createDecisionRegion(const Expr *C,
1183 const mcdc::DecisionParameters &DecisionParams) {
1184 popRegions(pushRegion(DecisionParams, getStart(C), getEnd(C)));
1185 }
1186
1187
1188
1189
1190 Counter createSwitchCaseRegion(const SwitchCase *SC, Counter ParentCount) {
1191
1192
1193
1194 Counter TrueCnt = getRegionCounter(SC);
1195 popRegions(pushRegion(TrueCnt, getStart(SC), SC->getColonLoc(),
1196 subtractCounters(ParentCount, TrueCnt)));
1197 return TrueCnt;
1198 }
1199
1200
1201
1203 bool isBranch = false) {
1204 return llvm::any_of(
1205 llvm::reverse(SourceRegions), [&](const SourceMappingRegion &Region) {
1206 return Region.getBeginLoc() == StartLoc &&
1207 Region.getEndLoc() == EndLoc && Region.isBranch() == isBranch;
1208 });
1209 }
1210
1211
1212
1213
1214 void adjustForOutOfOrderTraversal(SourceLocation EndLoc) {
1215 MostRecentLocation = EndLoc;
1216
1217
1218
1219
1220
1222 MostRecentLocation == getEndOfFileOrMacro(MostRecentLocation) &&
1223 isRegionAlreadyAdded(getStartOfFileOrMacro(MostRecentLocation),
1224 MostRecentLocation, getRegion().isBranch()))
1225 MostRecentLocation = getIncludeOrExpansionLoc(MostRecentLocation);
1226 }
1227
1228
1229
1230
1231
1232
1235 SM.isWrittenInSameFile(MostRecentLocation, NewLoc))
1236 return;
1237
1238
1239
1241 FileID ParentFile = SM.getFileID(LCA);
1242 while (!isNestedIn(MostRecentLocation, ParentFile)) {
1243 LCA = getIncludeOrExpansionLoc(LCA);
1244 if (LCA.isInvalid() || SM.isWrittenInSameFile(LCA, MostRecentLocation)) {
1245
1246
1247 MostRecentLocation = NewLoc;
1248 return;
1249 }
1250 ParentFile = SM.getFileID(LCA);
1251 }
1252
1253 llvm::SmallSet<SourceLocation, 8> StartLocs;
1254 std::optional ParentCounter;
1255 for (SourceMappingRegion &I : llvm::reverse(RegionStack)) {
1256 if (!I.hasStartLoc())
1257 continue;
1259 if (!isNestedIn(Loc, ParentFile)) {
1260 ParentCounter = I.getCounter();
1261 break;
1262 }
1263
1264 while (.isInFileID(Loc, ParentFile)) {
1265
1266
1267
1268 if (StartLocs.insert(Loc).second) {
1269 if (I.isBranch())
1270 SourceRegions.emplace_back(I.getCounter(), I.getFalseCounter(),
1271 I.getMCDCParams(), Loc,
1272 getEndOfFileOrMacro(Loc), I.isBranch());
1273 else
1274 SourceRegions.emplace_back(I.getCounter(), Loc,
1275 getEndOfFileOrMacro(Loc));
1276 }
1277 Loc = getIncludeOrExpansionLoc(Loc);
1278 }
1279 I.setStartLoc(getPreciseTokenLocEnd(Loc));
1280 }
1281
1282 if (ParentCounter) {
1283
1284
1285
1287 while (isNestedIn(Loc, ParentFile)) {
1289 if (StartLocs.insert(FileStart).second) {
1290 SourceRegions.emplace_back(*ParentCounter, FileStart,
1291 getEndOfFileOrMacro(Loc));
1292 assert(SpellingRegion(SM, SourceRegions.back()).isInSourceOrder());
1293 }
1294 Loc = getIncludeOrExpansionLoc(Loc);
1295 }
1296 }
1297
1298 MostRecentLocation = NewLoc;
1299 }
1300
1301
1302 void extendRegion(const Stmt *S) {
1303 SourceMappingRegion &Region = getRegion();
1305
1306 handleFileExit(StartLoc);
1307 if (!Region.hasStartLoc())
1308 Region.setStartLoc(StartLoc);
1309 }
1310
1311
1312 void terminateRegion(const Stmt *S) {
1313 extendRegion(S);
1314 SourceMappingRegion &Region = getRegion();
1316 if (!Region.hasEndLoc())
1317 Region.setEndLoc(EndLoc);
1318 pushRegion(Counter::getZero());
1319 HasTerminateStmt = true;
1320 }
1321
1322
1323 std::optional findGapAreaBetween(SourceLocation AfterLoc,
1325
1326
1327
1329 return std::nullopt;
1330
1331
1332
1334 FileID FID = SM.getFileID(AfterLoc);
1338 }
1339
1340 size_t StartDepth = locationDepth(AfterLoc);
1341 size_t EndDepth = locationDepth(BeforeLoc);
1342 while (.isWrittenInSameFile(AfterLoc, BeforeLoc)) {
1343 bool UnnestStart = StartDepth >= EndDepth;
1344 bool UnnestEnd = EndDepth >= StartDepth;
1345 if (UnnestEnd) {
1346 assert(SM.isWrittenInSameFile(getStartOfFileOrMacro(BeforeLoc),
1347 BeforeLoc));
1348
1349 BeforeLoc = getIncludeOrExpansionLoc(BeforeLoc);
1350 assert(BeforeLoc.isValid());
1351 EndDepth--;
1352 }
1353 if (UnnestStart) {
1354 assert(SM.isWrittenInSameFile(AfterLoc,
1355 getEndOfFileOrMacro(AfterLoc)));
1356
1357 AfterLoc = getIncludeOrExpansionLoc(AfterLoc);
1358 assert(AfterLoc.isValid());
1359 AfterLoc = getPreciseTokenLocEnd(AfterLoc);
1360 assert(AfterLoc.isValid());
1361 StartDepth--;
1362 }
1363 }
1364 AfterLoc = getPreciseTokenLocEnd(AfterLoc);
1365
1366
1368 return std::nullopt;
1369 if (.isWrittenInSameFile(AfterLoc, BeforeLoc) ||
1370 !SpellingRegion(SM, AfterLoc, BeforeLoc).isInSourceOrder())
1371 return std::nullopt;
1372 return {{AfterLoc, BeforeLoc}};
1373 }
1374
1375
1377 Counter Count) {
1378 if (StartLoc == EndLoc)
1379 return;
1380 assert(SpellingRegion(SM, StartLoc, EndLoc).isInSourceOrder());
1381 handleFileExit(StartLoc);
1382 size_t Index = pushRegion(Count, StartLoc, EndLoc);
1384 handleFileExit(EndLoc);
1385 popRegions(Index);
1386 }
1387
1388
1389
1390 std::optional findAreaStartingFromTo(SourceLocation StartingLoc,
1392
1394 FileID FID = SM.getFileID(StartingLoc);
1398 }
1399
1400 size_t StartDepth = locationDepth(StartingLoc);
1401 size_t EndDepth = locationDepth(BeforeLoc);
1402 while (.isWrittenInSameFile(StartingLoc, BeforeLoc)) {
1403 bool UnnestStart = StartDepth >= EndDepth;
1404 bool UnnestEnd = EndDepth >= StartDepth;
1405 if (UnnestEnd) {
1406 assert(SM.isWrittenInSameFile(getStartOfFileOrMacro(BeforeLoc),
1407 BeforeLoc));
1408
1409 BeforeLoc = getIncludeOrExpansionLoc(BeforeLoc);
1410 assert(BeforeLoc.isValid());
1411 EndDepth--;
1412 }
1413 if (UnnestStart) {
1414 assert(SM.isWrittenInSameFile(StartingLoc,
1415 getStartOfFileOrMacro(StartingLoc)));
1416
1417 StartingLoc = getIncludeOrExpansionLoc(StartingLoc);
1418 assert(StartingLoc.isValid());
1419 StartDepth--;
1420 }
1421 }
1422
1423
1425 return std::nullopt;
1426 if (.isWrittenInSameFile(StartingLoc, BeforeLoc) ||
1427 !SpellingRegion(SM, StartingLoc, BeforeLoc).isInSourceOrder())
1428 return std::nullopt;
1429 return {{StartingLoc, BeforeLoc}};
1430 }
1431
1433 const auto Skipped = findAreaStartingFromTo(StartLoc, BeforeLoc);
1434
1435 if (!Skipped)
1436 return;
1437
1438 const auto NewStartLoc = Skipped->getBegin();
1439 const auto EndLoc = Skipped->getEnd();
1440
1441 if (NewStartLoc == EndLoc)
1442 return;
1443 assert(SpellingRegion(SM, NewStartLoc, EndLoc).isInSourceOrder());
1444 handleFileExit(NewStartLoc);
1445 size_t Index = pushRegion(Counter{}, NewStartLoc, EndLoc);
1447 handleFileExit(EndLoc);
1448 popRegions(Index);
1449 }
1450
1451
1452 struct BreakContinue {
1453 Counter BreakCount;
1454 Counter ContinueCount;
1455 };
1457
1458 CounterCoverageMappingBuilder(
1460 llvm::DenseMap<const Stmt *, CounterPair> &CounterMap,
1462 : CoverageMappingBuilder(CVM, SM, LangOpts), CounterMap(CounterMap),
1463 MCDCState(MCDCState), MCDCBuilder(CVM.getCodeGenModule(), MCDCState) {}
1464
1465
1466 void write(llvm::raw_ostream &OS) {
1468 gatherFileIDs(VirtualFileMapping);
1469 SourceRegionFilter Filter = emitExpansionRegions();
1470 emitSourceRegions(Filter);
1471 gatherSkippedRegions();
1472
1473 if (MappingRegions.empty())
1474 return;
1475
1476 CoverageMappingWriter Writer(VirtualFileMapping, Builder.getExpressions(),
1477 MappingRegions);
1478 Writer.write(OS);
1479 }
1480
1481 void VisitStmt(const Stmt *S) {
1482 if (S->getBeginLoc().isValid())
1483 extendRegion(S);
1484 const Stmt *LastStmt = nullptr;
1485 bool SaveTerminateStmt = HasTerminateStmt;
1486 HasTerminateStmt = false;
1487 GapRegionCounter = Counter::getZero();
1488 for (const Stmt *Child : S->children())
1489 if (Child) {
1490
1491
1492 if (LastStmt && HasTerminateStmt) {
1493 auto Gap = findGapAreaBetween(getEnd(LastStmt), getStart(Child));
1494 if (Gap)
1495 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(),
1496 GapRegionCounter);
1497 SaveTerminateStmt = true;
1498 HasTerminateStmt = false;
1499 }
1500 this->Visit(Child);
1501 LastStmt = Child;
1502 }
1503 if (SaveTerminateStmt)
1504 HasTerminateStmt = true;
1505 handleFileExit(getEnd(S));
1506 }
1507
1508 void VisitDecl(const Decl *D) {
1510
1511
1512
1514 SM.isInSystemHeader(SM.getSpellingLoc(getStart(Body))))
1515 return;
1516
1517
1518
1519
1520
1521 Counter BodyCounter = getRegionCounter(Body);
1523 if (auto *Method = dyn_cast(D))
1524 Defaulted = Method->isDefaulted();
1525 if (auto *Ctor = dyn_cast(D)) {
1526 for (auto *Initializer : Ctor->inits()) {
1529 if (getStart(Init).isValid() && getEnd(Init).isValid())
1530 propagateCounts(BodyCounter, Init);
1531 }
1532 }
1533 }
1534
1535 propagateCounts(BodyCounter, Body,
1537 assert(RegionStack.empty() && "Regions entered but never exited");
1538 }
1539
1540 void VisitReturnStmt(const ReturnStmt *S) {
1541 extendRegion(S);
1542 if (S->getRetValue())
1543 Visit(S->getRetValue());
1544 terminateRegion(S);
1545 }
1546
1548 extendRegion(S);
1549 Visit(S->getBody());
1550 }
1551
1552 void VisitCoreturnStmt(const CoreturnStmt *S) {
1553 extendRegion(S);
1554 if (S->getOperand())
1555 Visit(S->getOperand());
1556 terminateRegion(S);
1557 }
1558
1560 Visit(E->getOperand());
1561 }
1562
1564 extendRegion(E);
1565 if (E->getSubExpr())
1566 Visit(E->getSubExpr());
1567 terminateRegion(E);
1568 }
1569
1570 void VisitGotoStmt(const GotoStmt *S) { terminateRegion(S); }
1571
1572 void VisitLabelStmt(const LabelStmt *S) {
1573 Counter LabelCount = getRegionCounter(S);
1575
1576 handleFileExit(Start);
1577 pushRegion(LabelCount, Start);
1578 Visit(S->getSubStmt());
1579 }
1580
1581 void VisitBreakStmt(const BreakStmt *S) {
1582 assert(!BreakContinueStack.empty() && "break not in a loop or switch!");
1584 BreakContinueStack.back().BreakCount = addCounters(
1585 BreakContinueStack.back().BreakCount, getRegion().getCounter());
1586
1587
1588 terminateRegion(S);
1589 }
1590
1591 void VisitContinueStmt(const ContinueStmt *S) {
1592 assert(!BreakContinueStack.empty() && "continue stmt not in a loop!");
1594 BreakContinueStack.back().ContinueCount = addCounters(
1595 BreakContinueStack.back().ContinueCount, getRegion().getCounter());
1596 terminateRegion(S);
1597 }
1598
1599 void VisitCallExpr(const CallExpr *E) {
1600 VisitStmt(E);
1601
1602
1603
1606 terminateRegion(E);
1607 }
1608
1609 void VisitWhileStmt(const WhileStmt *S) {
1610 extendRegion(S);
1611
1612 Counter ParentCount = getRegion().getCounter();
1614 ? getRegionCounter(S->getBody())
1615 : getRegionCounter(S);
1616
1617
1618 BreakContinueStack.push_back(BreakContinue());
1619 extendRegion(S->getBody());
1620 Counter BackedgeCount = propagateCounts(BodyCount, S->getBody());
1621 BreakContinue BC = BreakContinueStack.pop_back_val();
1622
1623 bool BodyHasTerminateStmt = HasTerminateStmt;
1624 HasTerminateStmt = false;
1625
1626
1627 Counter CondCount =
1629 ? getRegionCounter(S->getCond())
1630 : addCounters(ParentCount, BackedgeCount, BC.ContinueCount);
1631 auto BranchCount = getBranchCounterPair(S, CondCount, getRegionCounter(S));
1632 assert(BranchCount.Executed.isZero() || BranchCount.Executed == BodyCount ||
1634
1635 propagateCounts(CondCount, S->getCond());
1636 adjustForOutOfOrderTraversal(getEnd(S));
1637
1638
1639 auto Gap = findGapAreaBetween(S->getRParenLoc(), getStart(S->getBody()));
1640 if (Gap)
1641 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount);
1642
1643 assert(
1645 (BC.BreakCount.isZero() && BranchCount.Skipped == getRegionCounter(S)));
1646 Counter OutCount = addCounters(BC.BreakCount, BranchCount.Skipped);
1647 if (!IsCounterEqual(OutCount, ParentCount)) {
1648 pushRegion(OutCount);
1649 GapRegionCounter = OutCount;
1650 if (BodyHasTerminateStmt)
1651 HasTerminateStmt = true;
1652 }
1653
1654
1656 createBranchRegion(S->getCond(), BodyCount, BranchCount.Skipped);
1657 }
1658
1659 void VisitDoStmt(const DoStmt *S) {
1660 extendRegion(S);
1661
1662 Counter ParentCount = getRegion().getCounter();
1664 ? getRegionCounter(S->getBody())
1665 : getRegionCounter(S);
1666
1667 BreakContinueStack.push_back(BreakContinue());
1668 extendRegion(S->getBody());
1669
1670 Counter BackedgeCount;
1672 propagateCounts(BodyCount, S->getBody());
1673 else
1674 BackedgeCount =
1675 propagateCounts(addCounters(ParentCount, BodyCount), S->getBody());
1676
1677 BreakContinue BC = BreakContinueStack.pop_back_val();
1678
1679 bool BodyHasTerminateStmt = HasTerminateStmt;
1680 HasTerminateStmt = false;
1681
1683 ? getRegionCounter(S->getCond())
1684 : addCounters(BackedgeCount, BC.ContinueCount);
1685 auto BranchCount = getBranchCounterPair(S, CondCount, getRegionCounter(S));
1686 assert(BranchCount.Executed.isZero() || BranchCount.Executed == BodyCount ||
1688
1689 propagateCounts(CondCount, S->getCond());
1690
1691 assert(
1693 (BC.BreakCount.isZero() && BranchCount.Skipped == getRegionCounter(S)));
1694 Counter OutCount = addCounters(BC.BreakCount, BranchCount.Skipped);
1695 if (!IsCounterEqual(OutCount, ParentCount)) {
1696 pushRegion(OutCount);
1697 GapRegionCounter = OutCount;
1698 }
1699
1700
1702 createBranchRegion(S->getCond(), BodyCount, BranchCount.Skipped);
1703
1704 if (BodyHasTerminateStmt)
1705 HasTerminateStmt = true;
1706 }
1707
1708 void VisitForStmt(const ForStmt *S) {
1709 extendRegion(S);
1710 if (S->getInit())
1711 Visit(S->getInit());
1712
1713 Counter ParentCount = getRegion().getCounter();
1715 ? getRegionCounter(S->getBody())
1716 : getRegionCounter(S);
1717
1718
1719 if (S->getInc())
1720 BreakContinueStack.emplace_back();
1721
1722
1723 BreakContinueStack.emplace_back();
1724 extendRegion(S->getBody());
1725 Counter BackedgeCount = propagateCounts(BodyCount, S->getBody());
1726 BreakContinue BodyBC = BreakContinueStack.pop_back_val();
1727
1728 bool BodyHasTerminateStmt = HasTerminateStmt;
1729 HasTerminateStmt = false;
1730
1731
1732
1733 BreakContinue IncrementBC;
1734 if (const Stmt *Inc = S->getInc()) {
1735 Counter IncCount;
1737 IncCount = getRegionCounter(S->getInc());
1738 else
1739 IncCount = addCounters(BackedgeCount, BodyBC.ContinueCount);
1740 propagateCounts(IncCount, Inc);
1741 IncrementBC = BreakContinueStack.pop_back_val();
1742 }
1743
1744
1745 Counter CondCount =
1747 ? getRegionCounter(S->getCond())
1748 : addCounters(
1749 addCounters(ParentCount, BackedgeCount, BodyBC.ContinueCount),
1750 IncrementBC.ContinueCount);
1751 auto BranchCount = getBranchCounterPair(S, CondCount, getRegionCounter(S));
1752 assert(BranchCount.Executed.isZero() || BranchCount.Executed == BodyCount ||
1754
1755 if (const Expr *Cond = S->getCond()) {
1756 propagateCounts(CondCount, Cond);
1757 adjustForOutOfOrderTraversal(getEnd(S));
1758 }
1759
1760
1761 auto Gap = findGapAreaBetween(S->getRParenLoc(), getStart(S->getBody()));
1762 if (Gap)
1763 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount);
1764
1766 (BodyBC.BreakCount.isZero() && IncrementBC.BreakCount.isZero()));
1767 Counter OutCount = addCounters(BodyBC.BreakCount, IncrementBC.BreakCount,
1768 BranchCount.Skipped);
1769 if (!IsCounterEqual(OutCount, ParentCount)) {
1770 pushRegion(OutCount);
1771 GapRegionCounter = OutCount;
1772 if (BodyHasTerminateStmt)
1773 HasTerminateStmt = true;
1774 }
1775
1776
1778 createBranchRegion(S->getCond(), BodyCount, BranchCount.Skipped);
1779 }
1780
1782 extendRegion(S);
1783 if (S->getInit())
1784 Visit(S->getInit());
1785 Visit(S->getLoopVarStmt());
1786 Visit(S->getRangeStmt());
1787
1788 Counter ParentCount = getRegion().getCounter();
1790 ? getRegionCounter(S->getBody())
1791 : getRegionCounter(S);
1792
1793 BreakContinueStack.push_back(BreakContinue());
1794 extendRegion(S->getBody());
1795 Counter BackedgeCount = propagateCounts(BodyCount, S->getBody());
1796 BreakContinue BC = BreakContinueStack.pop_back_val();
1797
1798 bool BodyHasTerminateStmt = HasTerminateStmt;
1799 HasTerminateStmt = false;
1800
1801
1802 auto Gap = findGapAreaBetween(S->getRParenLoc(), getStart(S->getBody()));
1803 if (Gap)
1804 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount);
1805
1806 Counter LoopCount =
1807 addCounters(ParentCount, BackedgeCount, BC.ContinueCount);
1808 auto BranchCount = getBranchCounterPair(S, LoopCount, getRegionCounter(S));
1809 assert(BranchCount.Executed.isZero() || BranchCount.Executed == BodyCount ||
1811 assert(
1813 (BC.BreakCount.isZero() && BranchCount.Skipped == getRegionCounter(S)));
1814
1815 Counter OutCount = addCounters(BC.BreakCount, BranchCount.Skipped);
1816 if (!IsCounterEqual(OutCount, ParentCount)) {
1817 pushRegion(OutCount);
1818 GapRegionCounter = OutCount;
1819 if (BodyHasTerminateStmt)
1820 HasTerminateStmt = true;
1821 }
1822
1823
1825 createBranchRegion(S->getCond(), BodyCount, BranchCount.Skipped);
1826 }
1827
1829 extendRegion(S);
1830 Visit(S->getElement());
1831
1832 Counter ParentCount = getRegion().getCounter();
1833 Counter BodyCount = getRegionCounter(S);
1834
1835 BreakContinueStack.push_back(BreakContinue());
1836 extendRegion(S->getBody());
1837 Counter BackedgeCount = propagateCounts(BodyCount, S->getBody());
1838 BreakContinue BC = BreakContinueStack.pop_back_val();
1839
1840
1841 auto Gap = findGapAreaBetween(S->getRParenLoc(), getStart(S->getBody()));
1842 if (Gap)
1843 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount);
1844
1845 Counter LoopCount =
1846 addCounters(ParentCount, BackedgeCount, BC.ContinueCount);
1847 auto BranchCount = getBranchCounterPair(S, LoopCount);
1848 assert(BranchCount.Executed.isZero() || BranchCount.Executed == BodyCount);
1849 Counter OutCount = addCounters(BC.BreakCount, BranchCount.Skipped);
1850 if (!IsCounterEqual(OutCount, ParentCount)) {
1851 pushRegion(OutCount);
1852 GapRegionCounter = OutCount;
1853 }
1854 }
1855
1856 void VisitSwitchStmt(const SwitchStmt *S) {
1857 extendRegion(S);
1858 if (S->getInit())
1859 Visit(S->getInit());
1860 Visit(S->getCond());
1861
1862 BreakContinueStack.push_back(BreakContinue());
1863
1864 const Stmt *Body = S->getBody();
1865 extendRegion(Body);
1866 if (const auto *CS = dyn_cast(Body)) {
1867 if (!CS->body_empty()) {
1868
1869
1870
1871 size_t Index = pushRegion(Counter::getZero(), getStart(CS));
1873 Visit(Body);
1874
1875
1876 for (size_t i = RegionStack.size(); i != Index; --i) {
1877 if (!RegionStack[i - 1].hasEndLoc())
1878 RegionStack[i - 1].setEndLoc(getEnd(CS->body_back()));
1879 }
1880
1881 popRegions(Index);
1882 }
1883 } else
1884 propagateCounts(Counter::getZero(), Body);
1885 BreakContinue BC = BreakContinueStack.pop_back_val();
1886
1888 BreakContinueStack.back().ContinueCount = addCounters(
1889 BreakContinueStack.back().ContinueCount, BC.ContinueCount);
1890
1891 Counter ParentCount = getRegion().getCounter();
1892 Counter ExitCount = getRegionCounter(S);
1894 pushRegion(ExitCount);
1895 GapRegionCounter = ExitCount;
1896
1897
1898
1899 MostRecentLocation = getStart(S);
1900 handleFileExit(ExitLoc);
1901
1902
1903
1905 return;
1906
1907
1908
1909 Counter CaseCountSum;
1910 bool HasDefaultCase = false;
1911 const SwitchCase *Case = S->getSwitchCaseList();
1913 HasDefaultCase = HasDefaultCase || isa(Case);
1914 auto CaseCount = createSwitchCaseRegion(Case, ParentCount);
1915 CaseCountSum = addCounters(CaseCountSum, CaseCount, false);
1916 }
1917
1918
1919
1920 if (!HasDefaultCase) {
1921
1922
1923
1924 CaseCountSum =
1925 addCounters(CaseCountSum, Counter::getZero(), true);
1926
1927
1928 Counter SwitchFalse = subtractCounters(ParentCount, CaseCountSum);
1929 createBranchRegion(S->getCond(), CaseCountSum, SwitchFalse);
1930 }
1931 }
1932
1933 void VisitSwitchCase(const SwitchCase *S) {
1934 extendRegion(S);
1935
1938 ? getRegionCounter(S)
1939 : addCounters(Parent.getCounter(), getRegionCounter(S));
1940
1941
1942
1943 if (Parent.hasStartLoc() && Parent.getBeginLoc() == getStart(S))
1944 Parent.setCounter(Count);
1945 else
1946 pushRegion(Count, getStart(S));
1947
1948 GapRegionCounter = Count;
1949
1950 if (const auto *CS = dyn_cast(S)) {
1951 Visit(CS->getLHS());
1952 if (const Expr *RHS = CS->getRHS())
1953 Visit(RHS);
1954 }
1955 Visit(S->getSubStmt());
1956 }
1957
1958 void coverIfConsteval(const IfStmt *S) {
1959 assert(S->isConsteval());
1960
1961 const auto *Then = S->getThen();
1962 const auto *Else = S->getElse();
1963
1964
1965
1966
1967 const Counter ParentCount = getRegion().getCounter();
1968
1969 extendRegion(S);
1970
1971 if (S->isNegatedConsteval()) {
1972
1973 markSkipped(S->getIfLoc(), getStart(Then));
1974 propagateCounts(ParentCount, Then);
1975
1976 if (Else) {
1977
1978 markSkipped(getEnd(Then), getEnd(Else));
1979 }
1980 } else {
1981 assert(S->isNonNegatedConsteval());
1982
1983 markSkipped(S->getIfLoc(), Else ? getStart(Else) : getEnd(Then));
1984
1985 if (Else)
1986 propagateCounts(ParentCount, Else);
1987 }
1988 }
1989
1990 void coverIfConstexpr(const IfStmt *S) {
1991 assert(S->isConstexpr());
1992
1993
1994 const bool isTrue =
1995 S->getCond()
1997 .getBoolValue();
1998
1999 extendRegion(S);
2000
2001
2002
2003 const Counter ParentCount = getRegion().getCounter();
2004
2005
2007
2008 if (const auto *Init = S->getInit()) {
2009 const auto start = getStart(Init);
2010 const auto end = getEnd(Init);
2011
2012
2013
2014 if (start.isValid() && end.isValid()) {
2015 markSkipped(startOfSkipped, start);
2016 propagateCounts(ParentCount, Init);
2017 startOfSkipped = getEnd(Init);
2018 }
2019 }
2020
2021 const auto *Then = S->getThen();
2022 const auto *Else = S->getElse();
2023
2024 if (isTrue) {
2025
2026 markSkipped(startOfSkipped, getStart(Then));
2027 propagateCounts(ParentCount, Then);
2028
2029 if (Else)
2030
2031 markSkipped(getEnd(Then), getEnd(Else));
2032 } else {
2033
2034 markSkipped(startOfSkipped, Else ? getStart(Else) : getEnd(Then));
2035
2036 if (Else)
2037 propagateCounts(ParentCount, Else);
2038 }
2039 }
2040
2041 void VisitIfStmt(const IfStmt *S) {
2042
2043
2044 if (S->isConsteval())
2045 return coverIfConsteval(S);
2046 else if (S->isConstexpr())
2047 return coverIfConstexpr(S);
2048
2049 extendRegion(S);
2050 if (S->getInit())
2051 Visit(S->getInit());
2052
2053
2054
2055 extendRegion(S->getCond());
2056
2057 Counter ParentCount = getRegion().getCounter();
2058 auto [ThenCount, ElseCount] =
2060 ? BranchCounterPair{getRegionCounter(S->getThen()),
2061 (S->getElse() ? getRegionCounter(S->getElse())
2062 : Counter::getZero())}
2063 : getBranchCounterPair(S, ParentCount));
2064
2065
2066
2067 propagateCounts(ParentCount, S->getCond());
2068
2069
2070 std::optional Gap =
2071 findGapAreaBetween(S->getRParenLoc(), getStart(S->getThen()));
2072 if (Gap)
2073 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), ThenCount);
2074
2075 extendRegion(S->getThen());
2076 Counter OutCount = propagateCounts(ThenCount, S->getThen());
2077
2078 if (const Stmt *Else = S->getElse()) {
2079 bool ThenHasTerminateStmt = HasTerminateStmt;
2080 HasTerminateStmt = false;
2081
2082 std::optional Gap =
2083 findGapAreaBetween(getEnd(S->getThen()), getStart(Else));
2084 if (Gap)
2085 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), ElseCount);
2086 extendRegion(Else);
2087
2088 Counter ElseOutCount = propagateCounts(ElseCount, Else);
2090 OutCount = addCounters(OutCount, ElseOutCount);
2091
2092 if (ThenHasTerminateStmt)
2093 HasTerminateStmt = true;
2095 OutCount = addCounters(OutCount, ElseCount);
2096
2098 OutCount = getRegionCounter(S);
2099
2100 if (!IsCounterEqual(OutCount, ParentCount)) {
2101 pushRegion(OutCount);
2102 GapRegionCounter = OutCount;
2103 }
2104
2106
2107 createBranchRegion(S->getCond(), ThenCount, ElseCount);
2108 }
2109
2110 void VisitCXXTryStmt(const CXXTryStmt *S) {
2111 extendRegion(S);
2112
2113 extendRegion(S->getTryBlock());
2114
2115 Counter ParentCount = getRegion().getCounter();
2116 propagateCounts(ParentCount, S->getTryBlock());
2117
2118 for (unsigned I = 0, E = S->getNumHandlers(); I < E; ++I)
2119 Visit(S->getHandler(I));
2120
2121 Counter ExitCount = getRegionCounter(S);
2122 pushRegion(ExitCount);
2123 }
2124
2125 void VisitCXXCatchStmt(const CXXCatchStmt *S) {
2126 propagateCounts(getRegionCounter(S), S->getHandlerBlock());
2127 }
2128
2130 extendRegion(E);
2131
2132 Counter ParentCount = getRegion().getCounter();
2133 auto [TrueCount, FalseCount] =
2135 ? BranchCounterPair{getRegionCounter(E->getTrueExpr()),
2136 getRegionCounter(E->getFalseExpr())}
2137 : getBranchCounterPair(E, ParentCount));
2138 Counter OutCount;
2139
2140 if (const auto *BCO = dyn_cast(E)) {
2141 propagateCounts(ParentCount, BCO->getCommon());
2142 OutCount = TrueCount;
2143 } else {
2144 propagateCounts(ParentCount, E->getCond());
2145
2146 auto Gap =
2147 findGapAreaBetween(E->getQuestionLoc(), getStart(E->getTrueExpr()));
2148 if (Gap)
2149 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), TrueCount);
2150
2151 extendRegion(E->getTrueExpr());
2152 OutCount = propagateCounts(TrueCount, E->getTrueExpr());
2153 }
2154
2155 extendRegion(E->getFalseExpr());
2156 Counter FalseOutCount = propagateCounts(FalseCount, E->getFalseExpr());
2158 OutCount = getRegionCounter(E);
2159 else
2160 OutCount = addCounters(OutCount, FalseOutCount);
2161
2162 if (!IsCounterEqual(OutCount, ParentCount)) {
2163 pushRegion(OutCount);
2164 GapRegionCounter = OutCount;
2165 }
2166
2167
2169 createBranchRegion(E->getCond(), TrueCount, FalseCount);
2170 }
2171
2172 void createOrCancelDecision(const BinaryOperator *E, unsigned Since) {
2173 unsigned NumConds = MCDCBuilder.getTotalConditionsAndReset(E);
2174 if (NumConds == 0)
2175 return;
2176
2177
2179 for (const auto &SR : ArrayRef(SourceRegions).slice(Since)) {
2180 if (SR.isMCDCBranch()) {
2181 auto [ID, Conds] = SR.getMCDCBranchParams();
2182 CondIDs[ID] = Conds;
2183 }
2184 }
2185
2186
2187 mcdc::TVIdxBuilder Builder(CondIDs);
2188 unsigned NumTVs = Builder.NumTestVectors;
2190 assert(MaxTVs < mcdc::TVIdxBuilder::HardMaxTVs);
2191
2192 if (NumTVs > MaxTVs) {
2193
2194 cancelDecision(E, Since, NumTVs, MaxTVs);
2195 return;
2196 }
2197
2198
2202 std::move(Builder.Indices),
2203 };
2204
2205 auto DecisionParams = mcdc::DecisionParameters{
2206 MCDCState.BitmapBits += NumTVs,
2207 NumConds,
2208 };
2209
2210
2211 createDecisionRegion(E, DecisionParams);
2212 }
2213
2214
2215 void cancelDecision(const BinaryOperator *E, unsigned Since, int NumTVs,
2216 int MaxTVs) {
2218 unsigned DiagID =
2220 "unsupported MC/DC boolean expression; "
2221 "number of test vectors (%0) exceeds max (%1). "
2222 "Expression will not be covered");
2224
2225
2226 for (auto &SR : MutableArrayRef(SourceRegions).slice(Since)) {
2227 assert(!SR.isMCDCDecision() && "Decision shouldn't be seen here");
2228 if (SR.isMCDCBranch())
2229 SR.resetMCDCParams();
2230 }
2231
2232
2234 }
2235
2236
2237 bool isExprInSystemHeader(const BinaryOperator *E) const {
2239 SM.isInSystemHeader(SM.getSpellingLoc(E->getOperatorLoc())) &&
2241 SM.isInSystemHeader(SM.getSpellingLoc(E->getEndLoc())));
2242 }
2243
2245 if (isExprInSystemHeader(E)) {
2246 LeafExprSet.insert(E);
2247 return;
2248 }
2249
2250 bool IsRootNode = MCDCBuilder.isIdle();
2251
2252 unsigned SourceRegionsSince = SourceRegions.size();
2253
2254
2255 MCDCBuilder.pushAndAssignIDs(E);
2256
2257 extendRegion(E->getLHS());
2258 propagateCounts(getRegion().getCounter(), E->getLHS());
2259 handleFileExit(getEnd(E->getLHS()));
2260
2261
2262 const auto DecisionLHS = MCDCBuilder.pop();
2263
2264
2265 extendRegion(E->getRHS());
2266 propagateCounts(getRegionCounter(E), E->getRHS());
2267
2269 return;
2270
2271
2272 const auto DecisionRHS = MCDCBuilder.back();
2273
2274
2275 Counter ParentCnt = getRegion().getCounter();
2276
2277
2278 auto [RHSExecCnt, LHSExitCnt] = getBranchCounterPair(E, ParentCnt);
2279
2280
2281 auto [RHSTrueCnt, RHSExitCnt] =
2282 getBranchCounterPair(E->getRHS(), RHSExecCnt);
2283
2284
2285 createBranchRegion(E->getLHS(), RHSExecCnt, LHSExitCnt, DecisionLHS);
2286
2287
2288 createBranchRegion(E->getRHS(), RHSTrueCnt, RHSExitCnt, DecisionRHS);
2289
2290
2291 if (IsRootNode)
2292 createOrCancelDecision(E, SourceRegionsSince);
2293 }
2294
2295
2296 bool shouldVisitRHS(const Expr *LHS) {
2297 bool LHSIsTrue = false;
2298 bool LHSIsConst = false;
2302 return !LHSIsConst || (LHSIsConst && !LHSIsTrue);
2303 }
2304
2306 if (isExprInSystemHeader(E)) {
2307 LeafExprSet.insert(E);
2308 return;
2309 }
2310
2311 bool IsRootNode = MCDCBuilder.isIdle();
2312
2313 unsigned SourceRegionsSince = SourceRegions.size();
2314
2315
2316 MCDCBuilder.pushAndAssignIDs(E);
2317
2318 extendRegion(E->getLHS());
2319 Counter OutCount = propagateCounts(getRegion().getCounter(), E->getLHS());
2320 handleFileExit(getEnd(E->getLHS()));
2321
2322
2323 const auto DecisionLHS = MCDCBuilder.pop();
2324
2325
2326 extendRegion(E->getRHS());
2327 propagateCounts(getRegionCounter(E), E->getRHS());
2328
2330 return;
2331
2332
2333 const auto DecisionRHS = MCDCBuilder.back();
2334
2335
2336 Counter ParentCnt = getRegion().getCounter();
2337
2338
2339 auto [RHSExecCnt, LHSExitCnt] = getBranchCounterPair(E, ParentCnt);
2340
2341
2342 auto [RHSFalseCnt, RHSExitCnt] =
2343 getBranchCounterPair(E->getRHS(), RHSExecCnt);
2344
2345 if (!shouldVisitRHS(E->getLHS())) {
2346 GapRegionCounter = OutCount;
2347 }
2348
2349
2350 createBranchRegion(E->getLHS(), LHSExitCnt, RHSExecCnt, DecisionLHS);
2351
2352
2353 createBranchRegion(E->getRHS(), RHSExitCnt, RHSFalseCnt, DecisionRHS);
2354
2355
2356 if (IsRootNode)
2357 createOrCancelDecision(E, SourceRegionsSince);
2358 }
2359
2360 void VisitLambdaExpr(const LambdaExpr *LE) {
2361
2362
2363 }
2364
2367 }
2368
2370
2372 }
2373
2377 }
2378};
2379
2380}
2381
2382static void dump(llvm::raw_ostream &OS, StringRef FunctionName,
2385 OS << FunctionName << ":\n";
2386 CounterMappingContext Ctx(Expressions);
2387 for (const auto &R : Regions) {
2388 OS.indent(2);
2389 switch (R.Kind) {
2390 case CounterMappingRegion::CodeRegion:
2391 break;
2392 case CounterMappingRegion::ExpansionRegion:
2393 OS << "Expansion,";
2394 break;
2395 case CounterMappingRegion::SkippedRegion:
2396 OS << "Skipped,";
2397 break;
2398 case CounterMappingRegion::GapRegion:
2399 OS << "Gap,";
2400 break;
2401 case CounterMappingRegion::BranchRegion:
2402 case CounterMappingRegion::MCDCBranchRegion:
2403 OS << "Branch,";
2404 break;
2405 case CounterMappingRegion::MCDCDecisionRegion:
2406 OS << "Decision,";
2407 break;
2408 }
2409
2410 OS << "File " << R.FileID << ", " << R.LineStart << ":" << R.ColumnStart
2411 << " -> " << R.LineEnd << ":" << R.ColumnEnd << " = ";
2412
2413 if (const auto *DecisionParams =
2414 std::get_ifmcdc::DecisionParameters(&R.MCDCParams)) {
2415 OS << "M:" << DecisionParams->BitmapIdx;
2416 OS << ", C:" << DecisionParams->NumConditions;
2417 } else {
2418 Ctx.dump(R.Count, OS);
2419
2420 if (R.isBranch()) {
2421 OS << ", ";
2422 Ctx.dump(R.FalseCount, OS);
2423 }
2424 }
2425
2426 if (const auto *BranchParams =
2427 std::get_ifmcdc::BranchParameters(&R.MCDCParams)) {
2428 OS << " [" << BranchParams->ID + 1 << ","
2429 << BranchParams->Conds[true] + 1;
2430 OS << "," << BranchParams->Conds[false] + 1 << "] ";
2431 }
2432
2433 if (R.Kind == CounterMappingRegion::ExpansionRegion)
2434 OS << " (Expanded file = " << R.ExpandedFileID << ")";
2435 OS << "\n";
2436 }
2437}
2438
2441 : CGM(CGM), SourceInfo(SourceInfo) {}
2442
2443std::string CoverageMappingModuleGen::getCurrentDirname() {
2446
2448 llvm::sys::fs::current_path(CWD);
2449 return CWD.str().str();
2450}
2451
2452std::string CoverageMappingModuleGen::normalizeFilename(StringRef Filename) {
2454 llvm::sys::path::remove_dots(Path, true);
2455
2456
2457
2458
2459 for (const auto &[From, To] :
2461 if (llvm::sys::path::replace_path_prefix(Path, From, To))
2462 break;
2463 }
2464 return Path.str().str();
2465}
2466
2468 llvm::InstrProfSectKind SK) {
2469 return llvm::getInstrProfSectionName(
2471}
2472
2473void CoverageMappingModuleGen::emitFunctionMappingRecord(
2474 const FunctionInfo &Info, uint64_t FilenamesRef) {
2476
2477
2478 std::string FuncRecordName = "__covrec_" + llvm::utohexstr(Info.NameHash);
2479
2480
2481
2482
2483
2484 if (Info.IsUsed)
2485 FuncRecordName += "u";
2486
2487
2488 const uint64_t NameHash = Info.NameHash;
2489 const uint64_t FuncHash = Info.FuncHash;
2490 const std::string &CoverageMapping = Info.CoverageMapping;
2491#define COVMAP_FUNC_RECORD(Type, LLVMType, Name, Init) LLVMType,
2492 llvm::Type *FunctionRecordTypes[] = {
2493#include "llvm/ProfileData/InstrProfData.inc"
2494 };
2495 auto *FunctionRecordTy =
2496 llvm::StructType::get(Ctx, ArrayRef(FunctionRecordTypes),
2497 true);
2498
2499
2500#define COVMAP_FUNC_RECORD(Type, LLVMType, Name, Init) Init,
2501 llvm::Constant *FunctionRecordVals[] = {
2502 #include "llvm/ProfileData/InstrProfData.inc"
2503 };
2504 auto *FuncRecordConstant =
2505 llvm::ConstantStruct::get(FunctionRecordTy, ArrayRef(FunctionRecordVals));
2506
2507
2508 auto *FuncRecord = new llvm::GlobalVariable(
2509 CGM.getModule(), FunctionRecordTy, true,
2510 llvm::GlobalValue::LinkOnceODRLinkage, FuncRecordConstant,
2511 FuncRecordName);
2512 FuncRecord->setVisibility(llvm::GlobalValue::HiddenVisibility);
2514 FuncRecord->setAlignment(llvm::Align(8));
2516 FuncRecord->setComdat(CGM.getModule().getOrInsertComdat(FuncRecordName));
2517
2518
2520}
2521
2523 llvm::GlobalVariable *NamePtr, StringRef NameValue, uint64_t FuncHash,
2524 const std::string &CoverageMapping, bool IsUsed) {
2525 const uint64_t NameHash = llvm::IndexedInstrProf::ComputeHash(NameValue);
2526 FunctionRecords.push_back({NameHash, FuncHash, CoverageMapping, IsUsed});
2527
2528 if (!IsUsed)
2529 FunctionNames.push_back(NamePtr);
2530
2532
2533
2534
2535
2536
2538 std::vector Filenames;
2539 std::vector Expressions;
2540 std::vector Regions;
2541 FilenameStrs.resize(FileEntries.size() + 1);
2542 FilenameStrs[0] = normalizeFilename(getCurrentDirname());
2543 for (const auto &Entry : FileEntries) {
2544 auto I = Entry.second;
2545 FilenameStrs[I] = normalizeFilename(Entry.first.getName());
2546 }
2548 RawCoverageMappingReader Reader(CoverageMapping, FilenameRefs, Filenames,
2549 Expressions, Regions);
2550 if (Reader.read())
2551 return;
2552 dump(llvm::outs(), NameValue, Expressions, Regions);
2553 }
2554}
2555
2557 if (FunctionRecords.empty())
2558 return;
2560 auto *Int32Ty = llvm::Type::getInt32Ty(Ctx);
2561
2562
2564 FilenameStrs.resize(FileEntries.size() + 1);
2565
2566 FilenameStrs[0] = normalizeFilename(getCurrentDirname());
2567 for (const auto &Entry : FileEntries) {
2568 auto I = Entry.second;
2569 FilenameStrs[I] = normalizeFilename(Entry.first.getName());
2570 }
2571
2572 std::string Filenames;
2573 {
2574 llvm::raw_string_ostream OS(Filenames);
2575 CoverageFilenamesSectionWriter(FilenameStrs).write(OS);
2576 }
2577 auto *FilenamesVal =
2578 llvm::ConstantDataArray::getString(Ctx, Filenames, false);
2579 const int64_t FilenamesRef = llvm::IndexedInstrProf::ComputeHash(Filenames);
2580
2581
2582 for (const FunctionInfo &Info : FunctionRecords)
2583 emitFunctionMappingRecord(Info, FilenamesRef);
2584
2585 const unsigned NRecords = 0;
2586 const size_t FilenamesSize = Filenames.size();
2587 const unsigned CoverageMappingSize = 0;
2588 llvm::Type *CovDataHeaderTypes[] = {
2589#define COVMAP_HEADER(Type, LLVMType, Name, Init) LLVMType,
2590#include "llvm/ProfileData/InstrProfData.inc"
2591 };
2592 auto CovDataHeaderTy =
2593 llvm::StructType::get(Ctx, ArrayRef(CovDataHeaderTypes));
2594 llvm::Constant *CovDataHeaderVals[] = {
2595#define COVMAP_HEADER(Type, LLVMType, Name, Init) Init,
2596#include "llvm/ProfileData/InstrProfData.inc"
2597 };
2598 auto CovDataHeaderVal =
2599 llvm::ConstantStruct::get(CovDataHeaderTy, ArrayRef(CovDataHeaderVals));
2600
2601
2602 llvm::Type *CovDataTypes[] = {CovDataHeaderTy, FilenamesVal->getType()};
2603 auto CovDataTy = llvm::StructType::get(Ctx, ArrayRef(CovDataTypes));
2604 llvm::Constant *TUDataVals[] = {CovDataHeaderVal, FilenamesVal};
2605 auto CovDataVal = llvm::ConstantStruct::get(CovDataTy, ArrayRef(TUDataVals));
2606 auto CovData = new llvm::GlobalVariable(
2607 CGM.getModule(), CovDataTy, true, llvm::GlobalValue::PrivateLinkage,
2608 CovDataVal, llvm::getCoverageMappingVarName());
2609
2611 CovData->setAlignment(llvm::Align(8));
2612
2613
2615
2616 if (!FunctionNames.empty()) {
2617 auto NamesArrTy = llvm::ArrayType::get(llvm::PointerType::getUnqual(Ctx),
2618 FunctionNames.size());
2619 auto NamesArrVal = llvm::ConstantArray::get(NamesArrTy, FunctionNames);
2620
2621
2622 new llvm::GlobalVariable(CGM.getModule(), NamesArrTy, true,
2623 llvm::GlobalValue::InternalLinkage, NamesArrVal,
2624 llvm::getCoverageUnusedNamesVarName());
2625 }
2626}
2627
2629 return FileEntries.try_emplace(File, FileEntries.size() + 1).first->second;
2630}
2631
2633 llvm::raw_ostream &OS) {
2634 assert(CounterMap && MCDCState);
2635 CounterCoverageMappingBuilder Walker(CVM, *CounterMap, *MCDCState, SM,
2636 LangOpts);
2637 Walker.VisitDecl(D);
2638 Walker.write(OS);
2639}
2640
2642 llvm::raw_ostream &OS) {
2643 EmptyCoverageMappingBuilder Walker(CVM, SM, LangOpts);
2644 Walker.VisitDecl(D);
2645 Walker.write(OS);
2646}
Defines the Diagnostic-related interfaces.
static const MemRegion * getRegion(const CallEvent &Call, const MutexDescriptor &Descriptor, bool IsLock)
static std::string getInstrProfSection(const CodeGenModule &CGM, llvm::InstrProfSectKind SK)
static void dump(llvm::raw_ostream &OS, StringRef FunctionName, ArrayRef< CounterExpression > Expressions, ArrayRef< CounterMappingRegion > Regions)
static llvm:🆑:opt< bool > EmptyLineCommentCoverage("emptyline-comment-coverage", llvm:🆑:desc("Emit emptylines and comment lines as skipped regions (only " "disable it on test)"), llvm:🆑:init(true), llvm:🆑:Hidden)
llvm::DenseSet< const void * > Visited
static DiagnosticBuilder Diag(DiagnosticsEngine *Diags, const LangOptions &Features, FullSourceLoc TokLoc, const char *TokBegin, const char *TokRangeBegin, const char *TokRangeEnd, unsigned DiagID)
Produce a diagnostic highlighting some portion of a literal.
const TargetInfo & getTargetInfo() const
AbstractConditionalOperator - An abstract base class for ConditionalOperator and BinaryConditionalOpe...
Represents a loop initializing the elements of an array.
OpaqueValueExpr * getCommonExpr() const
Get the common subexpression shared by all initializations (the source array).
A builtin binary operation expression such as "x + y" or "x <= y".
BreakStmt - This represents a break.
CXXCatchStmt - This represents a C++ catch block.
CXXForRangeStmt - This represents C++0x [stmt.ranged]'s ranged for statement, represented as 'for (ra...
A C++ throw-expression (C++ [except.throw]).
CXXTryStmt - A C++ try block, including all handlers.
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
llvm::SmallVector< std::pair< std::string, std::string >, 0 > CoveragePrefixMap
Prefix replacement map for source-based code coverage to remap source file paths in coverage mapping.
std::string CoverageCompilationDir
The string to embed in coverage mapping as the current working directory.
This class organizes the cross-function state that is used while generating LLVM code.
llvm::Module & getModule() const
DiagnosticsEngine & getDiags() const
void addUsedGlobal(llvm::GlobalValue *GV)
Add a global to a list to be added to the llvm.used metadata.
ASTContext & getContext() const
bool supportsCOMDAT() const
const CodeGenOptions & getCodeGenOpts() const
llvm::LLVMContext & getLLVMContext()
void emitEmptyMapping(const Decl *D, llvm::raw_ostream &OS)
Emit the coverage mapping data for an unused function.
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...
Organizes the cross-function state that is used while generating code coverage mapping data.
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.
CoverageSourceInfo & getSourceInfo() const
static CoverageSourceInfo * setUpCoverageCallbacks(Preprocessor &PP)
CoverageMappingModuleGen(CodeGenModule &CGM, CoverageSourceInfo &SourceInfo)
void emit()
Emit the coverage mapping data for a translation unit.
CodeGenModule & getCodeGenModule()
Return an interface into CodeGenModule.
unsigned getFileID(FileEntryRef File)
Return the coverage mapping translation unit file id for the given file.
ConstStmtVisitor - This class implements a simple visitor for Stmt subclasses.
ContinueStmt - This represents a continue.
Represents a 'co_return' statement in the C++ Coroutines TS.
Represents the body of a coroutine.
Represents an expression that might suspend coroutine execution; either a co_await or co_yield expres...
Stores additional source code information like skipped ranges which is required by the coverage mappi...
void SourceRangeSkipped(SourceRange Range, SourceLocation EndifLoc) override
Hook called when a source range is skipped.
void updateNextTokLoc(SourceLocation Loc)
void AddSkippedRange(SourceRange Range, SkippedRange::Kind RangeKind)
std::vector< SkippedRange > & getSkippedRanges()
bool HandleComment(Preprocessor &PP, SourceRange Range) override
SourceLocation PrevTokLoc
void HandleEmptyline(SourceRange Range) override
Decl - This represents one declaration (or definition), e.g.
virtual Stmt * getBody() const
getBody - If this Decl represents a declaration for a body of code, such as a function or method defi...
virtual bool hasBody() const
Returns true if this Decl represents a declaration for a body of code, such as a function or method d...
DoStmt - This represents a 'do/while' stmt.
This represents one expression.
bool isValueDependent() const
Determines whether the value of this expression depends on.
bool EvaluateAsBooleanCondition(bool &Result, const ASTContext &Ctx, bool InConstantContext=false) const
EvaluateAsBooleanCondition - Return true if this is a constant which we can fold and convert to a boo...
A reference to a FileEntry that includes the name of the file as it was accessed by the FileManager's...
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
ForStmt - This represents a 'for (init;cond;inc)' stmt.
GotoStmt - This represents a direct goto.
IfStmt - This represents an if/then/else.
LabelStmt - Represents a label, which has a substatement.
A C++ lambda expression, which produces a function object (of unspecified type) that can be invoked l...
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
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 ...
Represents Objective-C's collection statement.
OpaqueValueExpr - An expression referring to an opaque object of a fixed type and value class.
Expr * getSourceExpr() const
The source expression of an opaque value expression is the expression which originally generated the ...
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
void addCommentHandler(CommentHandler *Handler)
Add the specified comment handler to the preprocessor.
void addPPCallbacks(std::unique_ptr< PPCallbacks > C)
SourceManager & getSourceManager() const
void setPreprocessToken(bool Preprocess)
void setTokenWatcher(llvm::unique_function< void(const clang::Token &)> F)
Register a function that would be called on each token in the final expanded token stream.
void setEmptylineHandler(EmptylineHandler *Handler)
Set empty line handler.
PseudoObjectExpr - An expression which accesses a pseudo-object l-value.
Expr * getSyntacticForm()
Return the syntactic form of this expression, i.e.
A (possibly-)qualified type.
ReturnStmt - This represents a return, optionally of an expression: return; return 4;.
Encodes a location in the source.
bool isValid() const
Return true if this is a valid SourceLocation object.
SourceLocation getLocWithOffset(IntTy Offset) const
Return a source location with the specified offset from this SourceLocation.
This class handles loading and caching of source files into memory.
A trivial tuple used to represent a source range.
SourceLocation getEnd() const
SourceLocation getBegin() const
Each ExpansionInfo encodes the expansion location - where the token was ultimately expanded,...
SourceLocation getExpansionLocStart() const
bool isFunctionMacroExpansion() const
SourceLocation getExpansionLocEnd() const
Stmt - This represents one statement.
SourceLocation getEndLoc() const LLVM_READONLY
SourceLocation getBeginLoc() const LLVM_READONLY
SourceLocation getColonLoc() const
const SwitchCase * getNextSwitchCase() const
SwitchStmt - This represents a 'switch' stmt.
const llvm::Triple & getTriple() const
Returns the target triple of the primary target.
Token - This structure provides full information about a lexed token.
SourceLocation getLocation() const
Return a source location identifier for the specified offset in the current file.
tok::TokenKind getKind() const
WhileStmt - This represents a 'while' stmt.
The JSON file list parser is used to communicate input to InstallAPI.
FunctionType::ExtInfo getFunctionExtInfo(const Type &t)
cl::opt< bool > SystemHeadersCoverage
Diagnostic wrappers for TextAPI types for error reporting.
cl::opt< bool > EnableSingleByteCoverage
Per-Function MC/DC state.
llvm::DenseMap< const Stmt *, Branch > BranchByStmt
llvm::DenseMap< const Stmt *, Decision > DecisionByStmt
EvalResult is a struct with detailed info about an evaluated expression.