/Users/buildslave/jenkins/sharedspace/clang-stage2-coverage-R@2/llvm/tools/clang/lib/CodeGen/CoverageMappingGen.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===--- CoverageMappingGen.cpp - Coverage mapping generation ---*- C++ -*-===// |
2 | | // |
3 | | // The LLVM Compiler Infrastructure |
4 | | // |
5 | | // This file is distributed under the University of Illinois Open Source |
6 | | // License. See LICENSE.TXT for details. |
7 | | // |
8 | | //===----------------------------------------------------------------------===// |
9 | | // |
10 | | // Instrumentation-based code coverage mapping generator |
11 | | // |
12 | | //===----------------------------------------------------------------------===// |
13 | | |
14 | | #include "CoverageMappingGen.h" |
15 | | #include "CodeGenFunction.h" |
16 | | #include "clang/AST/StmtVisitor.h" |
17 | | #include "clang/Lex/Lexer.h" |
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" |
27 | | |
28 | | using namespace clang; |
29 | | using namespace CodeGen; |
30 | | using namespace llvm::coverage; |
31 | | |
32 | 13 | void CoverageSourceInfo::SourceRangeSkipped(SourceRange Range, SourceLocation) { |
33 | 13 | SkippedRanges.push_back(Range); |
34 | 13 | } |
35 | | |
36 | | namespace { |
37 | | |
38 | | /// \brief A region of source code that can be mapped to a counter. |
39 | | class SourceMappingRegion { |
40 | | Counter Count; |
41 | | |
42 | | /// \brief The region's starting location. |
43 | | Optional<SourceLocation> LocStart; |
44 | | |
45 | | /// \brief The region's ending location. |
46 | | Optional<SourceLocation> LocEnd; |
47 | | |
48 | | /// Whether this region should be emitted after its parent is emitted. |
49 | | bool DeferRegion; |
50 | | |
51 | | /// Whether this region is a gap region. The count from a gap region is set |
52 | | /// as the line execution count if there are no other regions on the line. |
53 | | bool GapRegion; |
54 | | |
55 | | public: |
56 | | SourceMappingRegion(Counter Count, Optional<SourceLocation> LocStart, |
57 | | Optional<SourceLocation> LocEnd, bool DeferRegion = false, |
58 | | bool GapRegion = false) |
59 | | : Count(Count), LocStart(LocStart), LocEnd(LocEnd), |
60 | 1.06k | DeferRegion(DeferRegion), GapRegion(GapRegion) {} |
61 | | |
62 | 4.75k | const Counter &getCounter() const { return Count; } |
63 | | |
64 | 73 | void setCounter(Counter C) { Count = C; } |
65 | | |
66 | 3.94k | bool hasStartLoc() const { return LocStart.hasValue(); } |
67 | | |
68 | 124 | void setStartLoc(SourceLocation Loc) { LocStart = Loc; } |
69 | | |
70 | 3.14k | SourceLocation getStartLoc() const { |
71 | 3.14k | assert(LocStart && "Region has no start location"); |
72 | 3.14k | return *LocStart; |
73 | 3.14k | } |
74 | | |
75 | 935 | bool hasEndLoc() const { return LocEnd.hasValue(); } |
76 | | |
77 | 814 | void setEndLoc(SourceLocation Loc) { LocEnd = Loc; } |
78 | | |
79 | 1.60k | SourceLocation getEndLoc() const { |
80 | 1.60k | assert(LocEnd && "Region has no end location"); |
81 | 1.60k | return *LocEnd; |
82 | 1.60k | } |
83 | | |
84 | 137 | bool isDeferred() const { return DeferRegion; } |
85 | | |
86 | 131 | void setDeferred(bool Deferred) { DeferRegion = Deferred; } |
87 | | |
88 | 866 | bool isGap() const { return GapRegion; } |
89 | | |
90 | 53 | void setGap(bool Gap) { GapRegion = Gap; } |
91 | | }; |
92 | | |
93 | | /// Spelling locations for the start and end of a source region. |
94 | | struct SpellingRegion { |
95 | | /// The line where the region starts. |
96 | | unsigned LineStart; |
97 | | |
98 | | /// The column where the region starts. |
99 | | unsigned ColumnStart; |
100 | | |
101 | | /// The line where the region ends. |
102 | | unsigned LineEnd; |
103 | | |
104 | | /// The column where the region ends. |
105 | | unsigned ColumnEnd; |
106 | | |
107 | | SpellingRegion(SourceManager &SM, SourceLocation LocStart, |
108 | 1.07k | SourceLocation LocEnd) { |
109 | 1.07k | LineStart = SM.getSpellingLineNumber(LocStart); |
110 | 1.07k | ColumnStart = SM.getSpellingColumnNumber(LocStart); |
111 | 1.07k | LineEnd = SM.getSpellingLineNumber(LocEnd); |
112 | 1.07k | ColumnEnd = SM.getSpellingColumnNumber(LocEnd); |
113 | 1.07k | } |
114 | | |
115 | | /// Check if the start and end locations appear in source order, i.e |
116 | | /// top->bottom, left->right. |
117 | 56 | bool isInSourceOrder() const { |
118 | 56 | return (LineStart < LineEnd) || |
119 | 3 | (LineStart == LineEnd && 3 ColumnStart <= ColumnEnd0 ); |
120 | 56 | } |
121 | | }; |
122 | | |
123 | | /// \brief Provides the common functionality for the different |
124 | | /// coverage mapping region builders. |
125 | | class CoverageMappingBuilder { |
126 | | public: |
127 | | CoverageMappingModuleGen &CVM; |
128 | | SourceManager &SM; |
129 | | const LangOptions &LangOpts; |
130 | | |
131 | | private: |
132 | | /// \brief Map of clang's FileIDs to IDs used for coverage mapping. |
133 | | llvm::SmallDenseMap<FileID, std::pair<unsigned, SourceLocation>, 8> |
134 | | FileIDMapping; |
135 | | |
136 | | public: |
137 | | /// \brief The coverage mapping regions for this function |
138 | | llvm::SmallVector<CounterMappingRegion, 32> MappingRegions; |
139 | | /// \brief The source mapping regions for this function. |
140 | | std::vector<SourceMappingRegion> SourceRegions; |
141 | | |
142 | | /// \brief A set of regions which can be used as a filter. |
143 | | /// |
144 | | /// It is produced by emitExpansionRegions() and is used in |
145 | | /// emitSourceRegions() to suppress producing code regions if |
146 | | /// the same area is covered by expansion regions. |
147 | | typedef llvm::SmallSet<std::pair<SourceLocation, SourceLocation>, 8> |
148 | | SourceRegionFilter; |
149 | | |
150 | | CoverageMappingBuilder(CoverageMappingModuleGen &CVM, SourceManager &SM, |
151 | | const LangOptions &LangOpts) |
152 | 154 | : CVM(CVM), SM(SM), LangOpts(LangOpts) {} |
153 | | |
154 | | /// \brief Return the precise end location for the given token. |
155 | 3.10k | SourceLocation getPreciseTokenLocEnd(SourceLocation Loc) { |
156 | 3.10k | // We avoid getLocForEndOfToken here, because it doesn't do what we want for |
157 | 3.10k | // macro locations, which we just treat as expanded files. |
158 | 3.10k | unsigned TokLen = |
159 | 3.10k | Lexer::MeasureTokenLength(SM.getSpellingLoc(Loc), SM, LangOpts); |
160 | 3.10k | return Loc.getLocWithOffset(TokLen); |
161 | 3.10k | } |
162 | | |
163 | | /// \brief Return the start location of an included file or expanded macro. |
164 | 858 | SourceLocation getStartOfFileOrMacro(SourceLocation Loc) { |
165 | 858 | if (Loc.isMacroID()) |
166 | 215 | return Loc.getLocWithOffset(-SM.getFileOffset(Loc)); |
167 | 643 | return SM.getLocForStartOfFile(SM.getFileID(Loc)); |
168 | 643 | } |
169 | | |
170 | | /// \brief Return the end location of an included file or expanded macro. |
171 | 203 | SourceLocation getEndOfFileOrMacro(SourceLocation Loc) { |
172 | 203 | if (Loc.isMacroID()) |
173 | 152 | return Loc.getLocWithOffset(SM.getFileIDSize(SM.getFileID(Loc)) - |
174 | 152 | SM.getFileOffset(Loc)); |
175 | 51 | return SM.getLocForEndOfFile(SM.getFileID(Loc)); |
176 | 51 | } |
177 | | |
178 | | /// \brief Find out where the current file is included or macro is expanded. |
179 | 1.81k | SourceLocation getIncludeOrExpansionLoc(SourceLocation Loc) { |
180 | 934 | return Loc.isMacroID() ? SM.getImmediateExpansionRange(Loc).first |
181 | 879 | : SM.getIncludeLoc(SM.getFileID(Loc)); |
182 | 1.81k | } |
183 | | |
184 | | /// \brief Return true if \c Loc is a location in a built-in macro. |
185 | 6.59k | bool isInBuiltin(SourceLocation Loc) { |
186 | 6.59k | return SM.getBufferName(SM.getSpellingLoc(Loc)) == "<built-in>"; |
187 | 6.59k | } |
188 | | |
189 | | /// \brief Check whether \c Loc is included or expanded from \c Parent. |
190 | 597 | bool isNestedIn(SourceLocation Loc, FileID Parent) { |
191 | 701 | do { |
192 | 701 | Loc = getIncludeOrExpansionLoc(Loc); |
193 | 701 | if (Loc.isInvalid()) |
194 | 332 | return false; |
195 | 369 | } while (!SM.isInFileID(Loc, Parent)); |
196 | 265 | return true; |
197 | 597 | } |
198 | | |
199 | | /// \brief Get the start of \c S ignoring macro arguments and builtin macros. |
200 | 3.69k | SourceLocation getStart(const Stmt *S) { |
201 | 3.69k | SourceLocation Loc = S->getLocStart(); |
202 | 3.90k | while (SM.isMacroArgExpansion(Loc) || 3.90k isInBuiltin(Loc)3.69k ) |
203 | 214 | Loc = SM.getImmediateExpansionRange(Loc).first; |
204 | 3.69k | return Loc; |
205 | 3.69k | } |
206 | | |
207 | | /// \brief Get the end of \c S ignoring macro arguments and builtin macros. |
208 | 2.89k | SourceLocation getEnd(const Stmt *S) { |
209 | 2.89k | SourceLocation Loc = S->getLocEnd(); |
210 | 3.04k | while (SM.isMacroArgExpansion(Loc) || 3.04k isInBuiltin(Loc)2.89k ) |
211 | 153 | Loc = SM.getImmediateExpansionRange(Loc).first; |
212 | 2.89k | return getPreciseTokenLocEnd(Loc); |
213 | 2.89k | } |
214 | | |
215 | | /// \brief Find the set of files we have regions for and assign IDs |
216 | | /// |
217 | | /// Fills \c Mapping with the virtual file mapping needed to write out |
218 | | /// coverage and collects the necessary file information to emit source and |
219 | | /// expansion regions. |
220 | 154 | void gatherFileIDs(SmallVectorImpl<unsigned> &Mapping) { |
221 | 154 | FileIDMapping.clear(); |
222 | 154 | |
223 | 154 | llvm::SmallSet<FileID, 8> Visited; |
224 | 154 | SmallVector<std::pair<SourceLocation, unsigned>, 8> FileLocs; |
225 | 885 | for (const auto &Region : SourceRegions) { |
226 | 885 | SourceLocation Loc = Region.getStartLoc(); |
227 | 885 | FileID File = SM.getFileID(Loc); |
228 | 885 | if (!Visited.insert(File).second) |
229 | 590 | continue; |
230 | 295 | |
231 | 295 | // Do not map FileID's associated with system headers. |
232 | 295 | if (295 SM.isInSystemHeader(SM.getSpellingLoc(Loc))295 ) |
233 | 3 | continue; |
234 | 292 | |
235 | 292 | unsigned Depth = 0; |
236 | 292 | for (SourceLocation Parent = getIncludeOrExpansionLoc(Loc); |
237 | 480 | Parent.isValid()480 ; Parent = getIncludeOrExpansionLoc(Parent)188 ) |
238 | 188 | ++Depth; |
239 | 885 | FileLocs.push_back(std::make_pair(Loc, Depth)); |
240 | 885 | } |
241 | 154 | std::stable_sort(FileLocs.begin(), FileLocs.end(), llvm::less_second()); |
242 | 154 | |
243 | 292 | for (const auto &FL : FileLocs) { |
244 | 292 | SourceLocation Loc = FL.first; |
245 | 292 | FileID SpellingFile = SM.getDecomposedSpellingLoc(Loc).first; |
246 | 292 | auto Entry = SM.getFileEntryForID(SpellingFile); |
247 | 292 | if (!Entry) |
248 | 4 | continue; |
249 | 288 | |
250 | 288 | FileIDMapping[SM.getFileID(Loc)] = std::make_pair(Mapping.size(), Loc); |
251 | 288 | Mapping.push_back(CVM.getFileID(Entry)); |
252 | 288 | } |
253 | 154 | } |
254 | | |
255 | | /// \brief Get the coverage mapping file ID for \c Loc. |
256 | | /// |
257 | | /// If such file id doesn't exist, return None. |
258 | 1.17k | Optional<unsigned> getCoverageFileID(SourceLocation Loc) { |
259 | 1.17k | auto Mapping = FileIDMapping.find(SM.getFileID(Loc)); |
260 | 1.17k | if (Mapping != FileIDMapping.end()) |
261 | 1.15k | return Mapping->second.first; |
262 | 13 | return None; |
263 | 13 | } |
264 | | |
265 | | /// \brief Gather all the regions that were skipped by the preprocessor |
266 | | /// using the constructs like #if. |
267 | 140 | void gatherSkippedRegions() { |
268 | 140 | /// An array of the minimum lineStarts and the maximum lineEnds |
269 | 140 | /// for mapping regions from the appropriate source files. |
270 | 140 | llvm::SmallVector<std::pair<unsigned, unsigned>, 8> FileLineRanges; |
271 | 140 | FileLineRanges.resize( |
272 | 140 | FileIDMapping.size(), |
273 | 140 | std::make_pair(std::numeric_limits<unsigned>::max(), 0)); |
274 | 987 | for (const auto &R : MappingRegions) { |
275 | 987 | FileLineRanges[R.FileID].first = |
276 | 987 | std::min(FileLineRanges[R.FileID].first, R.LineStart); |
277 | 987 | FileLineRanges[R.FileID].second = |
278 | 987 | std::max(FileLineRanges[R.FileID].second, R.LineEnd); |
279 | 987 | } |
280 | 140 | |
281 | 140 | auto SkippedRanges = CVM.getSourceInfo().getSkippedRanges(); |
282 | 18 | for (const auto &I : SkippedRanges) { |
283 | 18 | auto LocStart = I.getBegin(); |
284 | 18 | auto LocEnd = I.getEnd(); |
285 | 18 | assert(SM.isWrittenInSameFile(LocStart, LocEnd) && |
286 | 18 | "region spans multiple files"); |
287 | 18 | |
288 | 18 | auto CovFileID = getCoverageFileID(LocStart); |
289 | 18 | if (!CovFileID) |
290 | 5 | continue; |
291 | 13 | SpellingRegion SR{SM, LocStart, LocEnd}; |
292 | 13 | auto Region = CounterMappingRegion::makeSkipped( |
293 | 13 | *CovFileID, SR.LineStart, SR.ColumnStart, SR.LineEnd, SR.ColumnEnd); |
294 | 13 | // Make sure that we only collect the regions that are inside |
295 | 13 | // the souce code of this function. |
296 | 13 | if (Region.LineStart >= FileLineRanges[*CovFileID].first && |
297 | 9 | Region.LineEnd <= FileLineRanges[*CovFileID].second) |
298 | 9 | MappingRegions.push_back(Region); |
299 | 18 | } |
300 | 140 | } |
301 | | |
302 | | /// \brief Generate the coverage counter mapping regions from collected |
303 | | /// source regions. |
304 | 154 | void emitSourceRegions(const SourceRegionFilter &Filter) { |
305 | 885 | for (const auto &Region : SourceRegions) { |
306 | 885 | assert(Region.hasEndLoc() && "incomplete region"); |
307 | 885 | |
308 | 885 | SourceLocation LocStart = Region.getStartLoc(); |
309 | 885 | assert(SM.getFileID(LocStart).isValid() && "region in invalid file"); |
310 | 885 | |
311 | 885 | // Ignore regions from system headers. |
312 | 885 | if (SM.isInSystemHeader(SM.getSpellingLoc(LocStart))) |
313 | 7 | continue; |
314 | 878 | |
315 | 878 | auto CovFileID = getCoverageFileID(LocStart); |
316 | 878 | // Ignore regions that don't have a file, such as builtin macros. |
317 | 878 | if (!CovFileID) |
318 | 4 | continue; |
319 | 874 | |
320 | 874 | SourceLocation LocEnd = Region.getEndLoc(); |
321 | 874 | assert(SM.isWrittenInSameFile(LocStart, LocEnd) && |
322 | 874 | "region spans multiple files"); |
323 | 874 | |
324 | 874 | // Don't add code regions for the area covered by expansion regions. |
325 | 874 | // This not only suppresses redundant regions, but sometimes prevents |
326 | 874 | // creating regions with wrong counters if, for example, a statement's |
327 | 874 | // body ends at the end of a nested macro. |
328 | 874 | if (Filter.count(std::make_pair(LocStart, LocEnd))) |
329 | 8 | continue; |
330 | 866 | |
331 | 866 | // Find the spelling locations for the mapping region. |
332 | 866 | SpellingRegion SR{SM, LocStart, LocEnd}; |
333 | 866 | assert(SR.isInSourceOrder() && "region start and end out of order"); |
334 | 866 | |
335 | 866 | if (Region.isGap()866 ) { |
336 | 53 | MappingRegions.push_back(CounterMappingRegion::makeGapRegion( |
337 | 53 | Region.getCounter(), *CovFileID, SR.LineStart, SR.ColumnStart, |
338 | 53 | SR.LineEnd, SR.ColumnEnd)); |
339 | 866 | } else { |
340 | 813 | MappingRegions.push_back(CounterMappingRegion::makeRegion( |
341 | 813 | Region.getCounter(), *CovFileID, SR.LineStart, SR.ColumnStart, |
342 | 813 | SR.LineEnd, SR.ColumnEnd)); |
343 | 813 | } |
344 | 885 | } |
345 | 154 | } |
346 | | |
347 | | /// \brief Generate expansion regions for each virtual file we've seen. |
348 | 140 | SourceRegionFilter emitExpansionRegions() { |
349 | 140 | SourceRegionFilter Filter; |
350 | 274 | for (const auto &FM : FileIDMapping) { |
351 | 274 | SourceLocation ExpandedLoc = FM.second.second; |
352 | 274 | SourceLocation ParentLoc = getIncludeOrExpansionLoc(ExpandedLoc); |
353 | 274 | if (ParentLoc.isInvalid()) |
354 | 135 | continue; |
355 | 139 | |
356 | 139 | auto ParentFileID = getCoverageFileID(ParentLoc); |
357 | 139 | if (!ParentFileID) |
358 | 4 | continue; |
359 | 135 | auto ExpandedFileID = getCoverageFileID(ExpandedLoc); |
360 | 135 | assert(ExpandedFileID && "expansion in uncovered file"); |
361 | 135 | |
362 | 135 | SourceLocation LocEnd = getPreciseTokenLocEnd(ParentLoc); |
363 | 135 | assert(SM.isWrittenInSameFile(ParentLoc, LocEnd) && |
364 | 135 | "region spans multiple files"); |
365 | 135 | Filter.insert(std::make_pair(ParentLoc, LocEnd)); |
366 | 135 | |
367 | 135 | SpellingRegion SR{SM, ParentLoc, LocEnd}; |
368 | 135 | assert(SR.isInSourceOrder() && "region start and end out of order"); |
369 | 135 | MappingRegions.push_back(CounterMappingRegion::makeExpansion( |
370 | 135 | *ParentFileID, *ExpandedFileID, SR.LineStart, SR.ColumnStart, |
371 | 135 | SR.LineEnd, SR.ColumnEnd)); |
372 | 135 | } |
373 | 140 | return Filter; |
374 | 140 | } |
375 | | }; |
376 | | |
377 | | /// \brief Creates unreachable coverage regions for the functions that |
378 | | /// are not emitted. |
379 | | struct EmptyCoverageMappingBuilder : public CoverageMappingBuilder { |
380 | | EmptyCoverageMappingBuilder(CoverageMappingModuleGen &CVM, SourceManager &SM, |
381 | | const LangOptions &LangOpts) |
382 | 14 | : CoverageMappingBuilder(CVM, SM, LangOpts) {} |
383 | | |
384 | 14 | void VisitDecl(const Decl *D) { |
385 | 14 | if (!D->hasBody()) |
386 | 0 | return; |
387 | 14 | auto Body = D->getBody(); |
388 | 14 | SourceLocation Start = getStart(Body); |
389 | 14 | SourceLocation End = getEnd(Body); |
390 | 14 | if (!SM.isWrittenInSameFile(Start, End)14 ) { |
391 | 6 | // Walk up to find the common ancestor. |
392 | 6 | // Correct the locations accordingly. |
393 | 6 | FileID StartFileID = SM.getFileID(Start); |
394 | 6 | FileID EndFileID = SM.getFileID(End); |
395 | 10 | while (StartFileID != EndFileID && 10 !isNestedIn(End, StartFileID)8 ) { |
396 | 4 | Start = getIncludeOrExpansionLoc(Start); |
397 | 4 | assert(Start.isValid() && |
398 | 4 | "Declaration start location not nested within a known region"); |
399 | 4 | StartFileID = SM.getFileID(Start); |
400 | 4 | } |
401 | 10 | while (StartFileID != EndFileID10 ) { |
402 | 4 | End = getPreciseTokenLocEnd(getIncludeOrExpansionLoc(End)); |
403 | 4 | assert(End.isValid() && |
404 | 4 | "Declaration end location not nested within a known region"); |
405 | 4 | EndFileID = SM.getFileID(End); |
406 | 4 | } |
407 | 6 | } |
408 | 14 | SourceRegions.emplace_back(Counter(), Start, End); |
409 | 14 | } |
410 | | |
411 | | /// \brief Write the mapping data to the output stream |
412 | 14 | void write(llvm::raw_ostream &OS) { |
413 | 14 | SmallVector<unsigned, 16> FileIDMapping; |
414 | 14 | gatherFileIDs(FileIDMapping); |
415 | 14 | emitSourceRegions(SourceRegionFilter()); |
416 | 14 | |
417 | 14 | if (MappingRegions.empty()) |
418 | 0 | return; |
419 | 14 | |
420 | 14 | CoverageMappingWriter Writer(FileIDMapping, None, MappingRegions); |
421 | 14 | Writer.write(OS); |
422 | 14 | } |
423 | | }; |
424 | | |
425 | | /// \brief A StmtVisitor that creates coverage mapping regions which map |
426 | | /// from the source code locations to the PGO counters. |
427 | | struct CounterCoverageMappingBuilder |
428 | | : public CoverageMappingBuilder, |
429 | | public ConstStmtVisitor<CounterCoverageMappingBuilder> { |
430 | | /// \brief The map of statements to count values. |
431 | | llvm::DenseMap<const Stmt *, unsigned> &CounterMap; |
432 | | |
433 | | /// \brief A stack of currently live regions. |
434 | | std::vector<SourceMappingRegion> RegionStack; |
435 | | |
436 | | /// The currently deferred region: its end location and count can be set once |
437 | | /// its parent has been popped from the region stack. |
438 | | Optional<SourceMappingRegion> DeferredRegion; |
439 | | |
440 | | CounterExpressionBuilder Builder; |
441 | | |
442 | | /// \brief A location in the most recently visited file or macro. |
443 | | /// |
444 | | /// This is used to adjust the active source regions appropriately when |
445 | | /// expressions cross file or macro boundaries. |
446 | | SourceLocation MostRecentLocation; |
447 | | |
448 | | /// \brief Return a counter for the subtraction of \c RHS from \c LHS |
449 | 185 | Counter subtractCounters(Counter LHS, Counter RHS) { |
450 | 185 | return Builder.subtract(LHS, RHS); |
451 | 185 | } |
452 | | |
453 | | /// \brief Return a counter for the sum of \c LHS and \c RHS. |
454 | 381 | Counter addCounters(Counter LHS, Counter RHS) { |
455 | 381 | return Builder.add(LHS, RHS); |
456 | 381 | } |
457 | | |
458 | 59 | Counter addCounters(Counter C1, Counter C2, Counter C3) { |
459 | 59 | return addCounters(addCounters(C1, C2), C3); |
460 | 59 | } |
461 | | |
462 | | /// \brief Return the region counter for the given statement. |
463 | | /// |
464 | | /// This should only be called on statements that have a dedicated counter. |
465 | 404 | Counter getRegionCounter(const Stmt *S) { |
466 | 404 | return Counter::getCounter(CounterMap[S]); |
467 | 404 | } |
468 | | |
469 | | /// \brief Push a region onto the stack. |
470 | | /// |
471 | | /// Returns the index on the stack where the region was pushed. This can be |
472 | | /// used with popRegions to exit a "scope", ending the region that was pushed. |
473 | | size_t pushRegion(Counter Count, Optional<SourceLocation> StartLoc = None, |
474 | 806 | Optional<SourceLocation> EndLoc = None) { |
475 | 806 | if (StartLoc806 ) { |
476 | 593 | MostRecentLocation = *StartLoc; |
477 | 593 | completeDeferred(Count, MostRecentLocation); |
478 | 593 | } |
479 | 806 | RegionStack.emplace_back(Count, StartLoc, EndLoc); |
480 | 806 | |
481 | 806 | return RegionStack.size() - 1; |
482 | 806 | } |
483 | | |
484 | | /// Complete any pending deferred region by setting its end location and |
485 | | /// count, and then pushing it onto the region stack. |
486 | 3.63k | size_t completeDeferred(Counter Count, SourceLocation DeferredEndLoc) { |
487 | 3.63k | size_t Index = RegionStack.size(); |
488 | 3.63k | if (!DeferredRegion) |
489 | 3.58k | return Index; |
490 | 56 | |
491 | 56 | // Consume the pending region. |
492 | 56 | SourceMappingRegion DR = DeferredRegion.getValue(); |
493 | 56 | DeferredRegion = None; |
494 | 56 | |
495 | 56 | // If the region ends in an expansion, find the expansion site. |
496 | 56 | if (SM.getFileID(DeferredEndLoc) != SM.getMainFileID()56 ) { |
497 | 3 | FileID StartFile = SM.getFileID(DR.getStartLoc()); |
498 | 3 | if (isNestedIn(DeferredEndLoc, StartFile)3 ) { |
499 | 3 | do { |
500 | 3 | DeferredEndLoc = getIncludeOrExpansionLoc(DeferredEndLoc); |
501 | 3 | } while (StartFile != SM.getFileID(DeferredEndLoc)); |
502 | 3 | } |
503 | 3 | } |
504 | 56 | |
505 | 56 | // The parent of this deferred region ends where the containing decl ends, |
506 | 56 | // so the region isn't useful. |
507 | 56 | if (DR.getStartLoc() == DeferredEndLoc) |
508 | 0 | return Index; |
509 | 56 | |
510 | 56 | // If we're visiting statements in non-source order (e.g switch cases or |
511 | 56 | // a loop condition) we can't construct a sensible deferred region. |
512 | 56 | if (56 !SpellingRegion(SM, DR.getStartLoc(), DeferredEndLoc).isInSourceOrder()56 ) |
513 | 3 | return Index; |
514 | 53 | |
515 | 53 | DR.setGap(true); |
516 | 53 | DR.setCounter(Count); |
517 | 53 | DR.setEndLoc(DeferredEndLoc); |
518 | 53 | handleFileExit(DeferredEndLoc); |
519 | 53 | RegionStack.push_back(DR); |
520 | 53 | return Index; |
521 | 53 | } |
522 | | |
523 | | /// \brief Pop regions from the stack into the function's list of regions. |
524 | | /// |
525 | | /// Adds all regions from \c ParentIndex to the top of the stack to the |
526 | | /// function's \c SourceRegions. |
527 | 712 | void popRegions(size_t ParentIndex) { |
528 | 712 | assert(RegionStack.size() >= ParentIndex && "parent not in stack"); |
529 | 712 | bool ParentOfDeferredRegion = false; |
530 | 1.57k | while (RegionStack.size() > ParentIndex1.57k ) { |
531 | 859 | SourceMappingRegion &Region = RegionStack.back(); |
532 | 859 | if (Region.hasStartLoc()859 ) { |
533 | 722 | SourceLocation StartLoc = Region.getStartLoc(); |
534 | 722 | SourceLocation EndLoc = Region.hasEndLoc() |
535 | 649 | ? Region.getEndLoc() |
536 | 73 | : RegionStack[ParentIndex].getEndLoc(); |
537 | 745 | while (!SM.isWrittenInSameFile(StartLoc, EndLoc)745 ) { |
538 | 23 | // The region ends in a nested file or macro expansion. Create a |
539 | 23 | // separate region for each expansion. |
540 | 23 | SourceLocation NestedLoc = getStartOfFileOrMacro(EndLoc); |
541 | 23 | assert(SM.isWrittenInSameFile(NestedLoc, EndLoc)); |
542 | 23 | |
543 | 23 | if (!isRegionAlreadyAdded(NestedLoc, EndLoc)) |
544 | 22 | SourceRegions.emplace_back(Region.getCounter(), NestedLoc, EndLoc); |
545 | 23 | |
546 | 23 | EndLoc = getPreciseTokenLocEnd(getIncludeOrExpansionLoc(EndLoc)); |
547 | 23 | if (EndLoc.isInvalid()) |
548 | 0 | llvm::report_fatal_error("File exit not handled before popRegions"); |
549 | 23 | } |
550 | 722 | Region.setEndLoc(EndLoc); |
551 | 722 | |
552 | 722 | MostRecentLocation = EndLoc; |
553 | 722 | // If this region happens to span an entire expansion, we need to make |
554 | 722 | // sure we don't overlap the parent region with it. |
555 | 722 | if (StartLoc == getStartOfFileOrMacro(StartLoc) && |
556 | 32 | EndLoc == getEndOfFileOrMacro(EndLoc)) |
557 | 32 | MostRecentLocation = getIncludeOrExpansionLoc(EndLoc); |
558 | 722 | |
559 | 722 | assert(SM.isWrittenInSameFile(Region.getStartLoc(), EndLoc)); |
560 | 722 | SourceRegions.push_back(Region); |
561 | 722 | |
562 | 722 | if (ParentOfDeferredRegion722 ) { |
563 | 107 | ParentOfDeferredRegion = false; |
564 | 107 | |
565 | 107 | // If there's an existing deferred region, keep the old one, because |
566 | 107 | // it means there are two consecutive returns (or a similar pattern). |
567 | 107 | if (!DeferredRegion.hasValue() && |
568 | 107 | // File IDs aren't gathered within macro expansions, so it isn't |
569 | 107 | // useful to try and create a deferred region inside of one. |
570 | 106 | (SM.getFileID(EndLoc) == SM.getMainFileID())) |
571 | 99 | DeferredRegion = |
572 | 99 | SourceMappingRegion(Counter::getZero(), EndLoc, None); |
573 | 107 | } |
574 | 859 | } else if (137 Region.isDeferred()137 ) { |
575 | 107 | assert(!ParentOfDeferredRegion && "Consecutive deferred regions"); |
576 | 107 | ParentOfDeferredRegion = true; |
577 | 107 | } |
578 | 859 | RegionStack.pop_back(); |
579 | 859 | } |
580 | 712 | assert(!ParentOfDeferredRegion && "Deferred region with no parent"); |
581 | 712 | } |
582 | | |
583 | | /// \brief Return the currently active region. |
584 | 4.01k | SourceMappingRegion &getRegion() { |
585 | 4.01k | assert(!RegionStack.empty() && "statement has no region"); |
586 | 4.01k | return RegionStack.back(); |
587 | 4.01k | } |
588 | | |
589 | | /// \brief Propagate counts through the children of \c S. |
590 | 563 | Counter propagateCounts(Counter TopCount, const Stmt *S) { |
591 | 563 | SourceLocation StartLoc = getStart(S); |
592 | 563 | SourceLocation EndLoc = getEnd(S); |
593 | 563 | size_t Index = pushRegion(TopCount, StartLoc, EndLoc); |
594 | 563 | Visit(S); |
595 | 563 | Counter ExitCount = getRegion().getCounter(); |
596 | 563 | popRegions(Index); |
597 | 563 | |
598 | 563 | // The statement may be spanned by an expansion. Make sure we handle a file |
599 | 563 | // exit out of this expansion before moving to the next statement. |
600 | 563 | if (SM.isBeforeInTranslationUnit(StartLoc, S->getLocStart())) |
601 | 35 | MostRecentLocation = EndLoc; |
602 | 563 | |
603 | 563 | return ExitCount; |
604 | 563 | } |
605 | | |
606 | | /// \brief Check whether a region with bounds \c StartLoc and \c EndLoc |
607 | | /// is already added to \c SourceRegions. |
608 | 31 | bool isRegionAlreadyAdded(SourceLocation StartLoc, SourceLocation EndLoc) { |
609 | 31 | return SourceRegions.rend() != |
610 | 31 | std::find_if(SourceRegions.rbegin(), SourceRegions.rend(), |
611 | 365 | [&](const SourceMappingRegion &Region) { |
612 | 365 | return Region.getStartLoc() == StartLoc && |
613 | 12 | Region.getEndLoc() == EndLoc; |
614 | 365 | }); |
615 | 31 | } |
616 | | |
617 | | /// \brief Adjust the most recently visited location to \c EndLoc. |
618 | | /// |
619 | | /// This should be used after visiting any statements in non-source order. |
620 | 45 | void adjustForOutOfOrderTraversal(SourceLocation EndLoc) { |
621 | 45 | MostRecentLocation = EndLoc; |
622 | 45 | // The code region for a whole macro is created in handleFileExit() when |
623 | 45 | // it detects exiting of the virtual file of that macro. If we visited |
624 | 45 | // statements in non-source order, we might already have such a region |
625 | 45 | // added, for example, if a body of a loop is divided among multiple |
626 | 45 | // macros. Avoid adding duplicate regions in such case. |
627 | 45 | if (getRegion().hasEndLoc() && |
628 | 44 | MostRecentLocation == getEndOfFileOrMacro(MostRecentLocation) && |
629 | 8 | isRegionAlreadyAdded(getStartOfFileOrMacro(MostRecentLocation), |
630 | 8 | MostRecentLocation)) |
631 | 6 | MostRecentLocation = getIncludeOrExpansionLoc(MostRecentLocation); |
632 | 45 | } |
633 | | |
634 | | /// \brief Adjust regions and state when \c NewLoc exits a file. |
635 | | /// |
636 | | /// If moving from our most recently tracked location to \c NewLoc exits any |
637 | | /// files, this adjusts our current region stack and creates the file regions |
638 | | /// for the exited file. |
639 | 5.06k | void handleFileExit(SourceLocation NewLoc) { |
640 | 5.06k | if (NewLoc.isInvalid() || |
641 | 5.06k | SM.isWrittenInSameFile(MostRecentLocation, NewLoc)) |
642 | 4.86k | return; |
643 | 196 | |
644 | 196 | // If NewLoc is not in a file that contains MostRecentLocation, walk up to |
645 | 196 | // find the common ancestor. |
646 | 196 | SourceLocation LCA = NewLoc; |
647 | 196 | FileID ParentFile = SM.getFileID(LCA); |
648 | 233 | while (!isNestedIn(MostRecentLocation, ParentFile)233 ) { |
649 | 128 | LCA = getIncludeOrExpansionLoc(LCA); |
650 | 128 | if (LCA.isInvalid() || 128 SM.isWrittenInSameFile(LCA, MostRecentLocation)128 ) { |
651 | 91 | // Since there isn't a common ancestor, no file was exited. We just need |
652 | 91 | // to adjust our location to the new file. |
653 | 91 | MostRecentLocation = NewLoc; |
654 | 91 | return; |
655 | 91 | } |
656 | 37 | ParentFile = SM.getFileID(LCA); |
657 | 37 | } |
658 | 196 | |
659 | 105 | llvm::SmallSet<SourceLocation, 8> StartLocs; |
660 | 105 | Optional<Counter> ParentCounter; |
661 | 157 | for (SourceMappingRegion &I : llvm::reverse(RegionStack)) { |
662 | 157 | if (!I.hasStartLoc()) |
663 | 9 | continue; |
664 | 148 | SourceLocation Loc = I.getStartLoc(); |
665 | 148 | if (!isNestedIn(Loc, ParentFile)148 ) { |
666 | 100 | ParentCounter = I.getCounter(); |
667 | 100 | break; |
668 | 100 | } |
669 | 48 | |
670 | 101 | while (48 !SM.isInFileID(Loc, ParentFile)101 ) { |
671 | 53 | // The most nested region for each start location is the one with the |
672 | 53 | // correct count. We avoid creating redundant regions by stopping once |
673 | 53 | // we've seen this region. |
674 | 53 | if (StartLocs.insert(Loc).second) |
675 | 51 | SourceRegions.emplace_back(I.getCounter(), Loc, |
676 | 51 | getEndOfFileOrMacro(Loc)); |
677 | 53 | Loc = getIncludeOrExpansionLoc(Loc); |
678 | 53 | } |
679 | 157 | I.setStartLoc(getPreciseTokenLocEnd(Loc)); |
680 | 157 | } |
681 | 105 | |
682 | 105 | if (ParentCounter105 ) { |
683 | 100 | // If the file is contained completely by another region and doesn't |
684 | 100 | // immediately start its own region, the whole file gets a region |
685 | 100 | // corresponding to the parent. |
686 | 100 | SourceLocation Loc = MostRecentLocation; |
687 | 205 | while (isNestedIn(Loc, ParentFile)205 ) { |
688 | 105 | SourceLocation FileStart = getStartOfFileOrMacro(Loc); |
689 | 105 | if (StartLocs.insert(FileStart).second) |
690 | 76 | SourceRegions.emplace_back(*ParentCounter, FileStart, |
691 | 76 | getEndOfFileOrMacro(Loc)); |
692 | 105 | Loc = getIncludeOrExpansionLoc(Loc); |
693 | 105 | } |
694 | 100 | } |
695 | 5.06k | |
696 | 5.06k | MostRecentLocation = NewLoc; |
697 | 5.06k | } |
698 | | |
699 | | /// \brief Ensure that \c S is included in the current region. |
700 | 2.90k | void extendRegion(const Stmt *S) { |
701 | 2.90k | SourceMappingRegion &Region = getRegion(); |
702 | 2.90k | SourceLocation StartLoc = getStart(S); |
703 | 2.90k | |
704 | 2.90k | handleFileExit(StartLoc); |
705 | 2.90k | if (!Region.hasStartLoc()) |
706 | 76 | Region.setStartLoc(StartLoc); |
707 | 2.90k | |
708 | 2.90k | completeDeferred(Region.getCounter(), StartLoc); |
709 | 2.90k | } |
710 | | |
711 | | /// \brief Mark \c S as a terminator, starting a zero region. |
712 | 131 | void terminateRegion(const Stmt *S) { |
713 | 131 | extendRegion(S); |
714 | 131 | SourceMappingRegion &Region = getRegion(); |
715 | 131 | if (!Region.hasEndLoc()) |
716 | 19 | Region.setEndLoc(getEnd(S)); |
717 | 131 | pushRegion(Counter::getZero()); |
718 | 131 | getRegion().setDeferred(true); |
719 | 131 | } |
720 | | |
721 | | /// \brief Keep counts of breaks and continues inside loops. |
722 | | struct BreakContinue { |
723 | | Counter BreakCount; |
724 | | Counter ContinueCount; |
725 | | }; |
726 | | SmallVector<BreakContinue, 8> BreakContinueStack; |
727 | | |
728 | | CounterCoverageMappingBuilder( |
729 | | CoverageMappingModuleGen &CVM, |
730 | | llvm::DenseMap<const Stmt *, unsigned> &CounterMap, SourceManager &SM, |
731 | | const LangOptions &LangOpts) |
732 | | : CoverageMappingBuilder(CVM, SM, LangOpts), CounterMap(CounterMap), |
733 | 140 | DeferredRegion(None) {} |
734 | | |
735 | | /// \brief Write the mapping data to the output stream |
736 | 140 | void write(llvm::raw_ostream &OS) { |
737 | 140 | llvm::SmallVector<unsigned, 8> VirtualFileMapping; |
738 | 140 | gatherFileIDs(VirtualFileMapping); |
739 | 140 | SourceRegionFilter Filter = emitExpansionRegions(); |
740 | 140 | assert(!DeferredRegion && "Deferred region never completed"); |
741 | 140 | emitSourceRegions(Filter); |
742 | 140 | gatherSkippedRegions(); |
743 | 140 | |
744 | 140 | if (MappingRegions.empty()) |
745 | 1 | return; |
746 | 139 | |
747 | 139 | CoverageMappingWriter Writer(VirtualFileMapping, Builder.getExpressions(), |
748 | 139 | MappingRegions); |
749 | 139 | Writer.write(OS); |
750 | 139 | } |
751 | | |
752 | 2.07k | void VisitStmt(const Stmt *S) { |
753 | 2.07k | if (S->getLocStart().isValid()) |
754 | 2.07k | extendRegion(S); |
755 | 2.07k | for (const Stmt *Child : S->children()) |
756 | 1.69k | if (1.69k Child1.69k ) |
757 | 1.69k | this->Visit(Child); |
758 | 2.07k | handleFileExit(getEnd(S)); |
759 | 2.07k | } |
760 | | |
761 | 140 | void VisitDecl(const Decl *D) { |
762 | 140 | assert(!DeferredRegion && "Deferred region never completed"); |
763 | 140 | |
764 | 140 | Stmt *Body = D->getBody(); |
765 | 140 | |
766 | 140 | // Do not propagate region counts into system headers. |
767 | 140 | if (Body && 140 SM.isInSystemHeader(SM.getSpellingLoc(getStart(Body)))140 ) |
768 | 1 | return; |
769 | 139 | |
770 | 139 | Counter ExitCount = propagateCounts(getRegionCounter(Body), Body); |
771 | 139 | assert(RegionStack.empty() && "Regions entered but never exited"); |
772 | 139 | |
773 | 139 | // Special case: if the last statement is a return, throw away the |
774 | 139 | // deferred region. This allows the closing brace to have a count. |
775 | 139 | if (auto *CS = dyn_cast_or_null<CompoundStmt>(Body)) |
776 | 135 | if (135 dyn_cast_or_null<ReturnStmt>(CS->body_back())135 ) |
777 | 43 | DeferredRegion = None; |
778 | 140 | |
779 | 140 | // Complete any deferred regions introduced by the last statement. |
780 | 140 | popRegions(completeDeferred(ExitCount, getEnd(Body))); |
781 | 140 | } |
782 | | |
783 | 94 | void VisitReturnStmt(const ReturnStmt *S) { |
784 | 94 | extendRegion(S); |
785 | 94 | if (S->getRetValue()) |
786 | 56 | Visit(S->getRetValue()); |
787 | 94 | terminateRegion(S); |
788 | 94 | } |
789 | | |
790 | 3 | void VisitCXXThrowExpr(const CXXThrowExpr *E) { |
791 | 3 | extendRegion(E); |
792 | 3 | if (E->getSubExpr()) |
793 | 3 | Visit(E->getSubExpr()); |
794 | 3 | terminateRegion(E); |
795 | 3 | } |
796 | | |
797 | 9 | void VisitGotoStmt(const GotoStmt *S) { terminateRegion(S); } |
798 | | |
799 | 12 | void VisitLabelStmt(const LabelStmt *S) { |
800 | 12 | SourceLocation Start = getStart(S); |
801 | 12 | // We can't extendRegion here or we risk overlapping with our new region. |
802 | 12 | handleFileExit(Start); |
803 | 12 | pushRegion(getRegionCounter(S), Start); |
804 | 12 | Visit(S->getSubStmt()); |
805 | 12 | } |
806 | | |
807 | 19 | void VisitBreakStmt(const BreakStmt *S) { |
808 | 19 | assert(!BreakContinueStack.empty() && "break not in a loop or switch!"); |
809 | 19 | BreakContinueStack.back().BreakCount = addCounters( |
810 | 19 | BreakContinueStack.back().BreakCount, getRegion().getCounter()); |
811 | 19 | // FIXME: a break in a switch should terminate regions for all preceding |
812 | 19 | // case statements, not just the most recent one. |
813 | 19 | terminateRegion(S); |
814 | 19 | } |
815 | | |
816 | 5 | void VisitContinueStmt(const ContinueStmt *S) { |
817 | 5 | assert(!BreakContinueStack.empty() && "continue stmt not in a loop!"); |
818 | 5 | BreakContinueStack.back().ContinueCount = addCounters( |
819 | 5 | BreakContinueStack.back().ContinueCount, getRegion().getCounter()); |
820 | 5 | terminateRegion(S); |
821 | 5 | } |
822 | | |
823 | 88 | void VisitCallExpr(const CallExpr *E) { |
824 | 88 | VisitStmt(E); |
825 | 88 | |
826 | 88 | // Terminate the region when we hit a noreturn function. |
827 | 88 | // (This is helpful dealing with switch statements.) |
828 | 88 | QualType CalleeType = E->getCallee()->getType(); |
829 | 88 | if (getFunctionExtInfo(*CalleeType).getNoReturn()) |
830 | 1 | terminateRegion(E); |
831 | 88 | } |
832 | | |
833 | 28 | void VisitWhileStmt(const WhileStmt *S) { |
834 | 28 | extendRegion(S); |
835 | 28 | |
836 | 28 | Counter ParentCount = getRegion().getCounter(); |
837 | 28 | Counter BodyCount = getRegionCounter(S); |
838 | 28 | |
839 | 28 | // Handle the body first so that we can get the backedge count. |
840 | 28 | BreakContinueStack.push_back(BreakContinue()); |
841 | 28 | extendRegion(S->getBody()); |
842 | 28 | Counter BackedgeCount = propagateCounts(BodyCount, S->getBody()); |
843 | 28 | BreakContinue BC = BreakContinueStack.pop_back_val(); |
844 | 28 | |
845 | 28 | // Go back to handle the condition. |
846 | 28 | Counter CondCount = |
847 | 28 | addCounters(ParentCount, BackedgeCount, BC.ContinueCount); |
848 | 28 | propagateCounts(CondCount, S->getCond()); |
849 | 28 | adjustForOutOfOrderTraversal(getEnd(S)); |
850 | 28 | |
851 | 28 | Counter OutCount = |
852 | 28 | addCounters(BC.BreakCount, subtractCounters(CondCount, BodyCount)); |
853 | 28 | if (OutCount != ParentCount) |
854 | 3 | pushRegion(OutCount); |
855 | 28 | } |
856 | | |
857 | 9 | void VisitDoStmt(const DoStmt *S) { |
858 | 9 | extendRegion(S); |
859 | 9 | |
860 | 9 | Counter ParentCount = getRegion().getCounter(); |
861 | 9 | Counter BodyCount = getRegionCounter(S); |
862 | 9 | |
863 | 9 | BreakContinueStack.push_back(BreakContinue()); |
864 | 9 | extendRegion(S->getBody()); |
865 | 9 | Counter BackedgeCount = |
866 | 9 | propagateCounts(addCounters(ParentCount, BodyCount), S->getBody()); |
867 | 9 | BreakContinue BC = BreakContinueStack.pop_back_val(); |
868 | 9 | |
869 | 9 | Counter CondCount = addCounters(BackedgeCount, BC.ContinueCount); |
870 | 9 | propagateCounts(CondCount, S->getCond()); |
871 | 9 | |
872 | 9 | Counter OutCount = |
873 | 9 | addCounters(BC.BreakCount, subtractCounters(CondCount, BodyCount)); |
874 | 9 | if (OutCount != ParentCount) |
875 | 0 | pushRegion(OutCount); |
876 | 9 | } |
877 | | |
878 | 28 | void VisitForStmt(const ForStmt *S) { |
879 | 28 | extendRegion(S); |
880 | 28 | if (S->getInit()) |
881 | 16 | Visit(S->getInit()); |
882 | 28 | |
883 | 28 | Counter ParentCount = getRegion().getCounter(); |
884 | 28 | Counter BodyCount = getRegionCounter(S); |
885 | 28 | |
886 | 28 | // Handle the body first so that we can get the backedge count. |
887 | 28 | BreakContinueStack.push_back(BreakContinue()); |
888 | 28 | extendRegion(S->getBody()); |
889 | 28 | Counter BackedgeCount = propagateCounts(BodyCount, S->getBody()); |
890 | 28 | BreakContinue BC = BreakContinueStack.pop_back_val(); |
891 | 28 | |
892 | 28 | // The increment is essentially part of the body but it needs to include |
893 | 28 | // the count for all the continue statements. |
894 | 28 | if (const Stmt *Inc = S->getInc()) |
895 | 16 | propagateCounts(addCounters(BackedgeCount, BC.ContinueCount), Inc); |
896 | 28 | |
897 | 28 | // Go back to handle the condition. |
898 | 28 | Counter CondCount = |
899 | 28 | addCounters(ParentCount, BackedgeCount, BC.ContinueCount); |
900 | 28 | if (const Expr *Cond28 = S->getCond()) { |
901 | 17 | propagateCounts(CondCount, Cond); |
902 | 17 | adjustForOutOfOrderTraversal(getEnd(S)); |
903 | 17 | } |
904 | 28 | |
905 | 28 | Counter OutCount = |
906 | 28 | addCounters(BC.BreakCount, subtractCounters(CondCount, BodyCount)); |
907 | 28 | if (OutCount != ParentCount) |
908 | 7 | pushRegion(OutCount); |
909 | 28 | } |
910 | | |
911 | 2 | void VisitCXXForRangeStmt(const CXXForRangeStmt *S) { |
912 | 2 | extendRegion(S); |
913 | 2 | Visit(S->getLoopVarStmt()); |
914 | 2 | Visit(S->getRangeStmt()); |
915 | 2 | |
916 | 2 | Counter ParentCount = getRegion().getCounter(); |
917 | 2 | Counter BodyCount = getRegionCounter(S); |
918 | 2 | |
919 | 2 | BreakContinueStack.push_back(BreakContinue()); |
920 | 2 | extendRegion(S->getBody()); |
921 | 2 | Counter BackedgeCount = propagateCounts(BodyCount, S->getBody()); |
922 | 2 | BreakContinue BC = BreakContinueStack.pop_back_val(); |
923 | 2 | |
924 | 2 | Counter LoopCount = |
925 | 2 | addCounters(ParentCount, BackedgeCount, BC.ContinueCount); |
926 | 2 | Counter OutCount = |
927 | 2 | addCounters(BC.BreakCount, subtractCounters(LoopCount, BodyCount)); |
928 | 2 | if (OutCount != ParentCount) |
929 | 0 | pushRegion(OutCount); |
930 | 2 | } |
931 | | |
932 | 1 | void VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S) { |
933 | 1 | extendRegion(S); |
934 | 1 | Visit(S->getElement()); |
935 | 1 | |
936 | 1 | Counter ParentCount = getRegion().getCounter(); |
937 | 1 | Counter BodyCount = getRegionCounter(S); |
938 | 1 | |
939 | 1 | BreakContinueStack.push_back(BreakContinue()); |
940 | 1 | extendRegion(S->getBody()); |
941 | 1 | Counter BackedgeCount = propagateCounts(BodyCount, S->getBody()); |
942 | 1 | BreakContinue BC = BreakContinueStack.pop_back_val(); |
943 | 1 | |
944 | 1 | Counter LoopCount = |
945 | 1 | addCounters(ParentCount, BackedgeCount, BC.ContinueCount); |
946 | 1 | Counter OutCount = |
947 | 1 | addCounters(BC.BreakCount, subtractCounters(LoopCount, BodyCount)); |
948 | 1 | if (OutCount != ParentCount) |
949 | 0 | pushRegion(OutCount); |
950 | 1 | } |
951 | | |
952 | 16 | void VisitSwitchStmt(const SwitchStmt *S) { |
953 | 16 | extendRegion(S); |
954 | 16 | if (S->getInit()) |
955 | 1 | Visit(S->getInit()); |
956 | 16 | Visit(S->getCond()); |
957 | 16 | |
958 | 16 | BreakContinueStack.push_back(BreakContinue()); |
959 | 16 | |
960 | 16 | const Stmt *Body = S->getBody(); |
961 | 16 | extendRegion(Body); |
962 | 16 | if (const auto *CS16 = dyn_cast<CompoundStmt>(Body)) { |
963 | 12 | if (!CS->body_empty()12 ) { |
964 | 10 | // Make a region for the body of the switch. If the body starts with |
965 | 10 | // a case, that case will reuse this region; otherwise, this covers |
966 | 10 | // the unreachable code at the beginning of the switch body. |
967 | 10 | size_t Index = |
968 | 10 | pushRegion(Counter::getZero(), getStart(CS->body_front())); |
969 | 10 | for (const auto *Child : CS->children()) |
970 | 32 | Visit(Child); |
971 | 10 | |
972 | 10 | // Set the end for the body of the switch, if it isn't already set. |
973 | 47 | for (size_t i = RegionStack.size(); i != Index47 ; --i37 ) { |
974 | 37 | if (!RegionStack[i - 1].hasEndLoc()) |
975 | 20 | RegionStack[i - 1].setEndLoc(getEnd(CS->body_back())); |
976 | 37 | } |
977 | 10 | |
978 | 10 | popRegions(Index); |
979 | 10 | } |
980 | 12 | } else |
981 | 4 | propagateCounts(Counter::getZero(), Body); |
982 | 16 | BreakContinue BC = BreakContinueStack.pop_back_val(); |
983 | 16 | |
984 | 16 | if (!BreakContinueStack.empty()) |
985 | 2 | BreakContinueStack.back().ContinueCount = addCounters( |
986 | 2 | BreakContinueStack.back().ContinueCount, BC.ContinueCount); |
987 | 16 | |
988 | 16 | Counter ExitCount = getRegionCounter(S); |
989 | 16 | SourceLocation ExitLoc = getEnd(S); |
990 | 16 | pushRegion(ExitCount); |
991 | 16 | |
992 | 16 | // Ensure that handleFileExit recognizes when the end location is located |
993 | 16 | // in a different file. |
994 | 16 | MostRecentLocation = getStart(S); |
995 | 16 | handleFileExit(ExitLoc); |
996 | 16 | } |
997 | | |
998 | 28 | void VisitSwitchCase(const SwitchCase *S) { |
999 | 28 | extendRegion(S); |
1000 | 28 | |
1001 | 28 | SourceMappingRegion &Parent = getRegion(); |
1002 | 28 | |
1003 | 28 | Counter Count = addCounters(Parent.getCounter(), getRegionCounter(S)); |
1004 | 28 | // Reuse the existing region if it starts at our label. This is typical of |
1005 | 28 | // the first case in a switch. |
1006 | 28 | if (Parent.hasStartLoc() && 28 Parent.getStartLoc() == getStart(S)28 ) |
1007 | 20 | Parent.setCounter(Count); |
1008 | 28 | else |
1009 | 8 | pushRegion(Count, getStart(S)); |
1010 | 28 | |
1011 | 28 | if (const auto *CS28 = dyn_cast<CaseStmt>(S)) { |
1012 | 21 | Visit(CS->getLHS()); |
1013 | 21 | if (const Expr *RHS = CS->getRHS()) |
1014 | 0 | Visit(RHS); |
1015 | 21 | } |
1016 | 28 | Visit(S->getSubStmt()); |
1017 | 28 | } |
1018 | | |
1019 | 107 | void VisitIfStmt(const IfStmt *S) { |
1020 | 107 | extendRegion(S); |
1021 | 107 | if (S->getInit()) |
1022 | 1 | Visit(S->getInit()); |
1023 | 107 | |
1024 | 107 | // Extend into the condition before we propagate through it below - this is |
1025 | 107 | // needed to handle macros that generate the "if" but not the condition. |
1026 | 107 | extendRegion(S->getCond()); |
1027 | 107 | |
1028 | 107 | Counter ParentCount = getRegion().getCounter(); |
1029 | 107 | Counter ThenCount = getRegionCounter(S); |
1030 | 107 | |
1031 | 107 | // Emitting a counter for the condition makes it easier to interpret the |
1032 | 107 | // counter for the body when looking at the coverage. |
1033 | 107 | propagateCounts(ParentCount, S->getCond()); |
1034 | 107 | |
1035 | 107 | extendRegion(S->getThen()); |
1036 | 107 | Counter OutCount = propagateCounts(ThenCount, S->getThen()); |
1037 | 107 | |
1038 | 107 | Counter ElseCount = subtractCounters(ParentCount, ThenCount); |
1039 | 107 | if (const Stmt *Else107 = S->getElse()) { |
1040 | 26 | extendRegion(S->getElse()); |
1041 | 26 | OutCount = addCounters(OutCount, propagateCounts(ElseCount, Else)); |
1042 | 26 | } else |
1043 | 81 | OutCount = addCounters(OutCount, ElseCount); |
1044 | 107 | |
1045 | 107 | if (OutCount != ParentCount) |
1046 | 49 | pushRegion(OutCount); |
1047 | 107 | } |
1048 | | |
1049 | 7 | void VisitCXXTryStmt(const CXXTryStmt *S) { |
1050 | 7 | extendRegion(S); |
1051 | 7 | // Handle macros that generate the "try" but not the rest. |
1052 | 7 | extendRegion(S->getTryBlock()); |
1053 | 7 | |
1054 | 7 | Counter ParentCount = getRegion().getCounter(); |
1055 | 7 | propagateCounts(ParentCount, S->getTryBlock()); |
1056 | 7 | |
1057 | 16 | for (unsigned I = 0, E = S->getNumHandlers(); I < E16 ; ++I9 ) |
1058 | 9 | Visit(S->getHandler(I)); |
1059 | 7 | |
1060 | 7 | Counter ExitCount = getRegionCounter(S); |
1061 | 7 | pushRegion(ExitCount); |
1062 | 7 | } |
1063 | | |
1064 | 9 | void VisitCXXCatchStmt(const CXXCatchStmt *S) { |
1065 | 9 | propagateCounts(getRegionCounter(S), S->getHandlerBlock()); |
1066 | 9 | } |
1067 | | |
1068 | 10 | void VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) { |
1069 | 10 | extendRegion(E); |
1070 | 10 | |
1071 | 10 | Counter ParentCount = getRegion().getCounter(); |
1072 | 10 | Counter TrueCount = getRegionCounter(E); |
1073 | 10 | |
1074 | 10 | Visit(E->getCond()); |
1075 | 10 | |
1076 | 10 | if (!isa<BinaryConditionalOperator>(E)10 ) { |
1077 | 8 | extendRegion(E->getTrueExpr()); |
1078 | 8 | propagateCounts(TrueCount, E->getTrueExpr()); |
1079 | 8 | } |
1080 | 10 | extendRegion(E->getFalseExpr()); |
1081 | 10 | propagateCounts(subtractCounters(ParentCount, TrueCount), |
1082 | 10 | E->getFalseExpr()); |
1083 | 10 | } |
1084 | | |
1085 | 3 | void VisitBinLAnd(const BinaryOperator *E) { |
1086 | 3 | extendRegion(E); |
1087 | 3 | Visit(E->getLHS()); |
1088 | 3 | |
1089 | 3 | extendRegion(E->getRHS()); |
1090 | 3 | propagateCounts(getRegionCounter(E), E->getRHS()); |
1091 | 3 | } |
1092 | | |
1093 | 5 | void VisitBinLOr(const BinaryOperator *E) { |
1094 | 5 | extendRegion(E); |
1095 | 5 | Visit(E->getLHS()); |
1096 | 5 | |
1097 | 5 | extendRegion(E->getRHS()); |
1098 | 5 | propagateCounts(getRegionCounter(E), E->getRHS()); |
1099 | 5 | } |
1100 | | |
1101 | 2 | void VisitLambdaExpr(const LambdaExpr *LE) { |
1102 | 2 | // Lambdas are treated as their own functions for now, so we shouldn't |
1103 | 2 | // propagate counts into them. |
1104 | 2 | } |
1105 | | }; |
1106 | | |
1107 | 54 | std::string getCoverageSection(const CodeGenModule &CGM) { |
1108 | 54 | return llvm::getInstrProfSectionName( |
1109 | 54 | llvm::IPSK_covmap, |
1110 | 54 | CGM.getContext().getTargetInfo().getTriple().getObjectFormat()); |
1111 | 54 | } |
1112 | | |
1113 | 206 | std::string normalizeFilename(StringRef Filename) { |
1114 | 206 | llvm::SmallString<256> Path(Filename); |
1115 | 206 | llvm::sys::fs::make_absolute(Path); |
1116 | 206 | llvm::sys::path::remove_dots(Path, /*remove_dot_dots=*/true); |
1117 | 206 | return Path.str().str(); |
1118 | 206 | } |
1119 | | |
1120 | | } // end anonymous namespace |
1121 | | |
1122 | | static void dump(llvm::raw_ostream &OS, StringRef FunctionName, |
1123 | | ArrayRef<CounterExpression> Expressions, |
1124 | 133 | ArrayRef<CounterMappingRegion> Regions) { |
1125 | 133 | OS << FunctionName << ":\n"; |
1126 | 133 | CounterMappingContext Ctx(Expressions); |
1127 | 986 | for (const auto &R : Regions) { |
1128 | 986 | OS.indent(2); |
1129 | 986 | switch (R.Kind) { |
1130 | 790 | case CounterMappingRegion::CodeRegion: |
1131 | 790 | break; |
1132 | 135 | case CounterMappingRegion::ExpansionRegion: |
1133 | 135 | OS << "Expansion,"; |
1134 | 135 | break; |
1135 | 9 | case CounterMappingRegion::SkippedRegion: |
1136 | 9 | OS << "Skipped,"; |
1137 | 9 | break; |
1138 | 52 | case CounterMappingRegion::GapRegion: |
1139 | 52 | OS << "Gap,"; |
1140 | 52 | break; |
1141 | 986 | } |
1142 | 986 | |
1143 | 986 | OS << "File " << R.FileID << ", " << R.LineStart << ":" << R.ColumnStart |
1144 | 986 | << " -> " << R.LineEnd << ":" << R.ColumnEnd << " = "; |
1145 | 986 | Ctx.dump(R.Count, OS); |
1146 | 986 | if (R.Kind == CounterMappingRegion::ExpansionRegion) |
1147 | 135 | OS << " (Expanded file = " << R.ExpandedFileID << ")"; |
1148 | 986 | OS << "\n"; |
1149 | 986 | } |
1150 | 133 | } |
1151 | | |
1152 | | void CoverageMappingModuleGen::addFunctionMappingRecord( |
1153 | | llvm::GlobalVariable *NamePtr, StringRef NameValue, uint64_t FuncHash, |
1154 | 153 | const std::string &CoverageMapping, bool IsUsed) { |
1155 | 153 | llvm::LLVMContext &Ctx = CGM.getLLVMContext(); |
1156 | 153 | if (!FunctionRecordTy153 ) { |
1157 | 162 | #define COVMAP_FUNC_RECORD(Type, LLVMType, Name, Init) LLVMType, |
1158 | 54 | llvm::Type *FunctionRecordTypes[] = { |
1159 | 54 | #include "llvm/ProfileData/InstrProfData.inc" |
1160 | 54 | }; |
1161 | 54 | FunctionRecordTy = |
1162 | 54 | llvm::StructType::get(Ctx, makeArrayRef(FunctionRecordTypes), |
1163 | 54 | /*isPacked=*/true); |
1164 | 54 | } |
1165 | 153 | |
1166 | 459 | #define COVMAP_FUNC_RECORD(Type, LLVMType, Name, Init) Init, |
1167 | 153 | llvm::Constant *FunctionRecordVals[] = { |
1168 | 153 | #include "llvm/ProfileData/InstrProfData.inc" |
1169 | 153 | }; |
1170 | 153 | FunctionRecords.push_back(llvm::ConstantStruct::get( |
1171 | 153 | FunctionRecordTy, makeArrayRef(FunctionRecordVals))); |
1172 | 153 | if (!IsUsed) |
1173 | 14 | FunctionNames.push_back( |
1174 | 14 | llvm::ConstantExpr::getBitCast(NamePtr, llvm::Type::getInt8PtrTy(Ctx))); |
1175 | 153 | CoverageMappings.push_back(CoverageMapping); |
1176 | 153 | |
1177 | 153 | if (CGM.getCodeGenOpts().DumpCoverageMapping153 ) { |
1178 | 133 | // Dump the coverage mapping data for this function by decoding the |
1179 | 133 | // encoded data. This allows us to dump the mapping regions which were |
1180 | 133 | // also processed by the CoverageMappingWriter which performs |
1181 | 133 | // additional minimization operations such as reducing the number of |
1182 | 133 | // expressions. |
1183 | 133 | std::vector<StringRef> Filenames; |
1184 | 133 | std::vector<CounterExpression> Expressions; |
1185 | 133 | std::vector<CounterMappingRegion> Regions; |
1186 | 133 | llvm::SmallVector<std::string, 16> FilenameStrs; |
1187 | 133 | llvm::SmallVector<StringRef, 16> FilenameRefs; |
1188 | 133 | FilenameStrs.resize(FileEntries.size()); |
1189 | 133 | FilenameRefs.resize(FileEntries.size()); |
1190 | 145 | for (const auto &Entry : FileEntries) { |
1191 | 145 | auto I = Entry.second; |
1192 | 145 | FilenameStrs[I] = normalizeFilename(Entry.first->getName()); |
1193 | 145 | FilenameRefs[I] = FilenameStrs[I]; |
1194 | 145 | } |
1195 | 133 | RawCoverageMappingReader Reader(CoverageMapping, FilenameRefs, Filenames, |
1196 | 133 | Expressions, Regions); |
1197 | 133 | if (Reader.read()) |
1198 | 0 | return; |
1199 | 133 | dump(llvm::outs(), NameValue, Expressions, Regions); |
1200 | 133 | } |
1201 | 153 | } |
1202 | | |
1203 | 54 | void CoverageMappingModuleGen::emit() { |
1204 | 54 | if (FunctionRecords.empty()) |
1205 | 0 | return; |
1206 | 54 | llvm::LLVMContext &Ctx = CGM.getLLVMContext(); |
1207 | 54 | auto *Int32Ty = llvm::Type::getInt32Ty(Ctx); |
1208 | 54 | |
1209 | 54 | // Create the filenames and merge them with coverage mappings |
1210 | 54 | llvm::SmallVector<std::string, 16> FilenameStrs; |
1211 | 54 | llvm::SmallVector<StringRef, 16> FilenameRefs; |
1212 | 54 | FilenameStrs.resize(FileEntries.size()); |
1213 | 54 | FilenameRefs.resize(FileEntries.size()); |
1214 | 61 | for (const auto &Entry : FileEntries) { |
1215 | 61 | auto I = Entry.second; |
1216 | 61 | FilenameStrs[I] = normalizeFilename(Entry.first->getName()); |
1217 | 61 | FilenameRefs[I] = FilenameStrs[I]; |
1218 | 61 | } |
1219 | 54 | |
1220 | 54 | std::string FilenamesAndCoverageMappings; |
1221 | 54 | llvm::raw_string_ostream OS(FilenamesAndCoverageMappings); |
1222 | 54 | CoverageFilenamesSectionWriter(FilenameRefs).write(OS); |
1223 | 54 | std::string RawCoverageMappings = |
1224 | 54 | llvm::join(CoverageMappings.begin(), CoverageMappings.end(), ""); |
1225 | 54 | OS << RawCoverageMappings; |
1226 | 54 | size_t CoverageMappingSize = RawCoverageMappings.size(); |
1227 | 54 | size_t FilenamesSize = OS.str().size() - CoverageMappingSize; |
1228 | 54 | // Append extra zeroes if necessary to ensure that the size of the filenames |
1229 | 54 | // and coverage mappings is a multiple of 8. |
1230 | 54 | if (size_t Rem54 = OS.str().size() % 8) { |
1231 | 45 | CoverageMappingSize += 8 - Rem; |
1232 | 201 | for (size_t I = 0, S = 8 - Rem; I < S201 ; ++I156 ) |
1233 | 156 | OS << '\0'; |
1234 | 45 | } |
1235 | 54 | auto *FilenamesAndMappingsVal = |
1236 | 54 | llvm::ConstantDataArray::getString(Ctx, OS.str(), false); |
1237 | 54 | |
1238 | 54 | // Create the deferred function records array |
1239 | 54 | auto RecordsTy = |
1240 | 54 | llvm::ArrayType::get(FunctionRecordTy, FunctionRecords.size()); |
1241 | 54 | auto RecordsVal = llvm::ConstantArray::get(RecordsTy, FunctionRecords); |
1242 | 54 | |
1243 | 54 | llvm::Type *CovDataHeaderTypes[] = { |
1244 | 216 | #define COVMAP_HEADER(Type, LLVMType, Name, Init) LLVMType, |
1245 | 54 | #include "llvm/ProfileData/InstrProfData.inc" |
1246 | 54 | }; |
1247 | 54 | auto CovDataHeaderTy = |
1248 | 54 | llvm::StructType::get(Ctx, makeArrayRef(CovDataHeaderTypes)); |
1249 | 54 | llvm::Constant *CovDataHeaderVals[] = { |
1250 | 216 | #define COVMAP_HEADER(Type, LLVMType, Name, Init) Init, |
1251 | 54 | #include "llvm/ProfileData/InstrProfData.inc" |
1252 | 54 | }; |
1253 | 54 | auto CovDataHeaderVal = llvm::ConstantStruct::get( |
1254 | 54 | CovDataHeaderTy, makeArrayRef(CovDataHeaderVals)); |
1255 | 54 | |
1256 | 54 | // Create the coverage data record |
1257 | 54 | llvm::Type *CovDataTypes[] = {CovDataHeaderTy, RecordsTy, |
1258 | 54 | FilenamesAndMappingsVal->getType()}; |
1259 | 54 | auto CovDataTy = llvm::StructType::get(Ctx, makeArrayRef(CovDataTypes)); |
1260 | 54 | llvm::Constant *TUDataVals[] = {CovDataHeaderVal, RecordsVal, |
1261 | 54 | FilenamesAndMappingsVal}; |
1262 | 54 | auto CovDataVal = |
1263 | 54 | llvm::ConstantStruct::get(CovDataTy, makeArrayRef(TUDataVals)); |
1264 | 54 | auto CovData = new llvm::GlobalVariable( |
1265 | 54 | CGM.getModule(), CovDataTy, true, llvm::GlobalValue::InternalLinkage, |
1266 | 54 | CovDataVal, llvm::getCoverageMappingVarName()); |
1267 | 54 | |
1268 | 54 | CovData->setSection(getCoverageSection(CGM)); |
1269 | 54 | CovData->setAlignment(8); |
1270 | 54 | |
1271 | 54 | // Make sure the data doesn't get deleted. |
1272 | 54 | CGM.addUsedGlobal(CovData); |
1273 | 54 | // Create the deferred function records array |
1274 | 54 | if (!FunctionNames.empty()54 ) { |
1275 | 6 | auto NamesArrTy = llvm::ArrayType::get(llvm::Type::getInt8PtrTy(Ctx), |
1276 | 6 | FunctionNames.size()); |
1277 | 6 | auto NamesArrVal = llvm::ConstantArray::get(NamesArrTy, FunctionNames); |
1278 | 6 | // This variable will *NOT* be emitted to the object file. It is used |
1279 | 6 | // to pass the list of names referenced to codegen. |
1280 | 6 | new llvm::GlobalVariable(CGM.getModule(), NamesArrTy, true, |
1281 | 6 | llvm::GlobalValue::InternalLinkage, NamesArrVal, |
1282 | 6 | llvm::getCoverageUnusedNamesVarName()); |
1283 | 6 | } |
1284 | 54 | } |
1285 | | |
1286 | 288 | unsigned CoverageMappingModuleGen::getFileID(const FileEntry *File) { |
1287 | 288 | auto It = FileEntries.find(File); |
1288 | 288 | if (It != FileEntries.end()) |
1289 | 227 | return It->second; |
1290 | 61 | unsigned FileID = FileEntries.size(); |
1291 | 61 | FileEntries.insert(std::make_pair(File, FileID)); |
1292 | 61 | return FileID; |
1293 | 61 | } |
1294 | | |
1295 | | void CoverageMappingGen::emitCounterMapping(const Decl *D, |
1296 | 140 | llvm::raw_ostream &OS) { |
1297 | 140 | assert(CounterMap); |
1298 | 140 | CounterCoverageMappingBuilder Walker(CVM, *CounterMap, SM, LangOpts); |
1299 | 140 | Walker.VisitDecl(D); |
1300 | 140 | Walker.write(OS); |
1301 | 140 | } |
1302 | | |
1303 | | void CoverageMappingGen::emitEmptyMapping(const Decl *D, |
1304 | 14 | llvm::raw_ostream &OS) { |
1305 | 14 | EmptyCoverageMappingBuilder Walker(CVM, SM, LangOpts); |
1306 | 14 | Walker.VisitDecl(D); |
1307 | 14 | Walker.write(OS); |
1308 | 14 | } |