/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
Line | Count | Source (jump to first uncovered line) |
1 | | //===- CoverageMapping.h - Code coverage mapping support --------*- C++ -*-===// |
2 | | // |
3 | | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | | // See https://llvm.org/LICENSE.txt for license information. |
5 | | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | | // |
7 | | //===----------------------------------------------------------------------===// |
8 | | // |
9 | | // Code coverage mapping data is generated by clang and read by |
10 | | // llvm-cov to show code coverage statistics for a file. |
11 | | // |
12 | | //===----------------------------------------------------------------------===// |
13 | | |
14 | | #ifndef LLVM_PROFILEDATA_COVERAGE_COVERAGEMAPPING_H |
15 | | #define LLVM_PROFILEDATA_COVERAGE_COVERAGEMAPPING_H |
16 | | |
17 | | #include "llvm/ADT/ArrayRef.h" |
18 | | #include "llvm/ADT/DenseMap.h" |
19 | | #include "llvm/ADT/DenseSet.h" |
20 | | #include "llvm/ADT/Hashing.h" |
21 | | #include "llvm/ADT/None.h" |
22 | | #include "llvm/ADT/StringRef.h" |
23 | | #include "llvm/ADT/StringSet.h" |
24 | | #include "llvm/ADT/iterator.h" |
25 | | #include "llvm/ADT/iterator_range.h" |
26 | | #include "llvm/ProfileData/InstrProf.h" |
27 | | #include "llvm/Support/Compiler.h" |
28 | | #include "llvm/Support/Debug.h" |
29 | | #include "llvm/Support/Endian.h" |
30 | | #include "llvm/Support/Error.h" |
31 | | #include "llvm/Support/raw_ostream.h" |
32 | | #include <cassert> |
33 | | #include <cstdint> |
34 | | #include <iterator> |
35 | | #include <memory> |
36 | | #include <string> |
37 | | #include <system_error> |
38 | | #include <tuple> |
39 | | #include <utility> |
40 | | #include <vector> |
41 | | |
42 | | namespace llvm { |
43 | | |
44 | | class IndexedInstrProfReader; |
45 | | |
46 | | namespace coverage { |
47 | | |
48 | | class CoverageMappingReader; |
49 | | struct CoverageMappingRecord; |
50 | | |
51 | | enum class coveragemap_error { |
52 | | success = 0, |
53 | | eof, |
54 | | no_data_found, |
55 | | unsupported_version, |
56 | | truncated, |
57 | | malformed |
58 | | }; |
59 | | |
60 | | const std::error_category &coveragemap_category(); |
61 | | |
62 | 0 | inline std::error_code make_error_code(coveragemap_error E) { |
63 | 0 | return std::error_code(static_cast<int>(E), coveragemap_category()); |
64 | 0 | } |
65 | | |
66 | | class CoverageMapError : public ErrorInfo<CoverageMapError> { |
67 | | public: |
68 | 236 | CoverageMapError(coveragemap_error Err) : Err(Err) { |
69 | 236 | assert(Err != coveragemap_error::success && "Not an error"); |
70 | 236 | } |
71 | | |
72 | | std::string message() const override; |
73 | | |
74 | 0 | void log(raw_ostream &OS) const override { OS << message(); } |
75 | | |
76 | 0 | std::error_code convertToErrorCode() const override { |
77 | 0 | return make_error_code(Err); |
78 | 0 | } |
79 | | |
80 | 236 | coveragemap_error get() const { return Err; } |
81 | | |
82 | | static char ID; |
83 | | |
84 | | private: |
85 | | coveragemap_error Err; |
86 | | }; |
87 | | |
88 | | /// A Counter is an abstract value that describes how to compute the |
89 | | /// execution count for a region of code using the collected profile count data. |
90 | | struct Counter { |
91 | | enum CounterKind { Zero, CounterValueReference, Expression }; |
92 | | static const unsigned EncodingTagBits = 2; |
93 | | static const unsigned EncodingTagMask = 0x3; |
94 | | static const unsigned EncodingCounterTagAndExpansionRegionTagBits = |
95 | | EncodingTagBits + 1; |
96 | | |
97 | | private: |
98 | | CounterKind Kind = Zero; |
99 | | unsigned ID = 0; |
100 | | |
101 | 16.3k | Counter(CounterKind Kind, unsigned ID) : Kind(Kind), ID(ID) {} |
102 | | |
103 | | public: |
104 | 6.17k | Counter() = default; |
105 | | |
106 | 13.2k | CounterKind getKind() const { return Kind; } |
107 | | |
108 | 1.05k | bool isZero() const { return Kind == Zero; } |
109 | | |
110 | 8.12k | bool isExpression() const { return Kind == Expression; } |
111 | | |
112 | 13.4k | unsigned getCounterID() const { return ID; } |
113 | | |
114 | 4.39k | unsigned getExpressionID() const { return ID; } |
115 | | |
116 | 14.8k | friend bool operator==(const Counter &LHS, const Counter &RHS) { |
117 | 14.8k | return LHS.Kind == RHS.Kind && LHS.ID == RHS.ID13.7k ; |
118 | 14.8k | } |
119 | | |
120 | 183 | friend bool operator!=(const Counter &LHS, const Counter &RHS) { |
121 | 183 | return !(LHS == RHS); |
122 | 183 | } |
123 | | |
124 | 0 | friend bool operator<(const Counter &LHS, const Counter &RHS) { |
125 | 0 | return std::tie(LHS.Kind, LHS.ID) < std::tie(RHS.Kind, RHS.ID); |
126 | 0 | } |
127 | | |
128 | | /// Return the counter that represents the number zero. |
129 | 321 | static Counter getZero() { return Counter(); } |
130 | | |
131 | | /// Return the counter that corresponds to a specific profile counter. |
132 | 14.0k | static Counter getCounter(unsigned CounterId) { |
133 | 14.0k | return Counter(CounterValueReference, CounterId); |
134 | 14.0k | } |
135 | | |
136 | | /// Return the counter that corresponds to a specific addition counter |
137 | | /// expression. |
138 | 2.28k | static Counter getExpression(unsigned ExpressionId) { |
139 | 2.28k | return Counter(Expression, ExpressionId); |
140 | 2.28k | } |
141 | | }; |
142 | | |
143 | | /// A Counter expression is a value that represents an arithmetic operation |
144 | | /// with two counters. |
145 | | struct CounterExpression { |
146 | | enum ExprKind { Subtract, Add }; |
147 | | ExprKind Kind; |
148 | | Counter LHS, RHS; |
149 | | |
150 | | CounterExpression(ExprKind Kind, Counter LHS, Counter RHS) |
151 | 6.21k | : Kind(Kind), LHS(LHS), RHS(RHS) {} |
152 | | }; |
153 | | |
154 | | /// A Counter expression builder is used to construct the counter expressions. |
155 | | /// It avoids unnecessary duplication and simplifies algebraic expressions. |
156 | | class CounterExpressionBuilder { |
157 | | /// A list of all the counter expressions |
158 | | std::vector<CounterExpression> Expressions; |
159 | | |
160 | | /// A lookup table for the index of a given expression. |
161 | | DenseMap<CounterExpression, unsigned> ExpressionIndices; |
162 | | |
163 | | /// Return the counter which corresponds to the given expression. |
164 | | /// |
165 | | /// If the given expression is already stored in the builder, a counter |
166 | | /// that references that expression is returned. Otherwise, the given |
167 | | /// expression is added to the builder's collection of expressions. |
168 | | Counter get(const CounterExpression &E); |
169 | | |
170 | | /// Represents a term in a counter expression tree. |
171 | | struct Term { |
172 | | unsigned CounterID; |
173 | | int Factor; |
174 | | |
175 | | Term(unsigned CounterID, int Factor) |
176 | 1.40k | : CounterID(CounterID), Factor(Factor) {} |
177 | | }; |
178 | | |
179 | | /// Gather the terms of the expression tree for processing. |
180 | | /// |
181 | | /// This collects each addition and subtraction referenced by the counter into |
182 | | /// a sequence that can be sorted and combined to build a simplified counter |
183 | | /// expression. |
184 | | void extractTerms(Counter C, int Sign, SmallVectorImpl<Term> &Terms); |
185 | | |
186 | | /// Simplifies the given expression tree |
187 | | /// by getting rid of algebraically redundant operations. |
188 | | Counter simplify(Counter ExpressionTree); |
189 | | |
190 | | public: |
191 | 161 | ArrayRef<CounterExpression> getExpressions() const { return Expressions; } |
192 | | |
193 | | /// Return a counter that represents the expression that adds LHS and RHS. |
194 | | Counter add(Counter LHS, Counter RHS); |
195 | | |
196 | | /// Return a counter that represents the expression that subtracts RHS from |
197 | | /// LHS. |
198 | | Counter subtract(Counter LHS, Counter RHS); |
199 | | }; |
200 | | |
201 | | using LineColPair = std::pair<unsigned, unsigned>; |
202 | | |
203 | | /// A Counter mapping region associates a source range with a specific counter. |
204 | | struct CounterMappingRegion { |
205 | | enum RegionKind { |
206 | | /// A CodeRegion associates some code with a counter |
207 | | CodeRegion, |
208 | | |
209 | | /// An ExpansionRegion represents a file expansion region that associates |
210 | | /// a source range with the expansion of a virtual source file, such as |
211 | | /// for a macro instantiation or #include file. |
212 | | ExpansionRegion, |
213 | | |
214 | | /// A SkippedRegion represents a source range with code that was skipped |
215 | | /// by a preprocessor or similar means. |
216 | | SkippedRegion, |
217 | | |
218 | | /// A GapRegion is like a CodeRegion, but its count is only set as the |
219 | | /// line execution count when its the only region in the line. |
220 | | GapRegion |
221 | | }; |
222 | | |
223 | | Counter Count; |
224 | | unsigned FileID, ExpandedFileID; |
225 | | unsigned LineStart, ColumnStart, LineEnd, ColumnEnd; |
226 | | RegionKind Kind; |
227 | | |
228 | | CounterMappingRegion(Counter Count, unsigned FileID, unsigned ExpandedFileID, |
229 | | unsigned LineStart, unsigned ColumnStart, |
230 | | unsigned LineEnd, unsigned ColumnEnd, RegionKind Kind) |
231 | | : Count(Count), FileID(FileID), ExpandedFileID(ExpandedFileID), |
232 | | LineStart(LineStart), ColumnStart(ColumnStart), LineEnd(LineEnd), |
233 | 5.00k | ColumnEnd(ColumnEnd), Kind(Kind) {} |
234 | | |
235 | | static CounterMappingRegion |
236 | | makeRegion(Counter Count, unsigned FileID, unsigned LineStart, |
237 | 1.24k | unsigned ColumnStart, unsigned LineEnd, unsigned ColumnEnd) { |
238 | 1.24k | return CounterMappingRegion(Count, FileID, 0, LineStart, ColumnStart, |
239 | 1.24k | LineEnd, ColumnEnd, CodeRegion); |
240 | 1.24k | } |
241 | | |
242 | | static CounterMappingRegion |
243 | | makeExpansion(unsigned FileID, unsigned ExpandedFileID, unsigned LineStart, |
244 | 167 | unsigned ColumnStart, unsigned LineEnd, unsigned ColumnEnd) { |
245 | 167 | return CounterMappingRegion(Counter(), FileID, ExpandedFileID, LineStart, |
246 | 167 | ColumnStart, LineEnd, ColumnEnd, |
247 | 167 | ExpansionRegion); |
248 | 167 | } |
249 | | |
250 | | static CounterMappingRegion |
251 | | makeSkipped(unsigned FileID, unsigned LineStart, unsigned ColumnStart, |
252 | 17 | unsigned LineEnd, unsigned ColumnEnd) { |
253 | 17 | return CounterMappingRegion(Counter(), FileID, 0, LineStart, ColumnStart, |
254 | 17 | LineEnd, ColumnEnd, SkippedRegion); |
255 | 17 | } |
256 | | |
257 | | static CounterMappingRegion |
258 | | makeGapRegion(Counter Count, unsigned FileID, unsigned LineStart, |
259 | 186 | unsigned ColumnStart, unsigned LineEnd, unsigned ColumnEnd) { |
260 | 186 | return CounterMappingRegion(Count, FileID, 0, LineStart, ColumnStart, |
261 | 186 | LineEnd, (1U << 31) | ColumnEnd, GapRegion); |
262 | 186 | } |
263 | | |
264 | 42.3k | inline LineColPair startLoc() const { |
265 | 42.3k | return LineColPair(LineStart, ColumnStart); |
266 | 42.3k | } |
267 | | |
268 | 16.6k | inline LineColPair endLoc() const { return LineColPair(LineEnd, ColumnEnd); } |
269 | | }; |
270 | | |
271 | | /// Associates a source range with an execution count. |
272 | | struct CountedRegion : public CounterMappingRegion { |
273 | | uint64_t ExecutionCount; |
274 | | |
275 | | CountedRegion(const CounterMappingRegion &R, uint64_t ExecutionCount) |
276 | 2.15k | : CounterMappingRegion(R), ExecutionCount(ExecutionCount) {} |
277 | | }; |
278 | | |
279 | | /// A Counter mapping context is used to connect the counters, expressions |
280 | | /// and the obtained counter values. |
281 | | class CounterMappingContext { |
282 | | ArrayRef<CounterExpression> Expressions; |
283 | | ArrayRef<uint64_t> CounterValues; |
284 | | |
285 | | public: |
286 | | CounterMappingContext(ArrayRef<CounterExpression> Expressions, |
287 | | ArrayRef<uint64_t> CounterValues = None) |
288 | 671 | : Expressions(Expressions), CounterValues(CounterValues) {} |
289 | | |
290 | 520 | void setCounts(ArrayRef<uint64_t> Counts) { CounterValues = Counts; } |
291 | | |
292 | | void dump(const Counter &C, raw_ostream &OS) const; |
293 | 0 | void dump(const Counter &C) const { dump(C, dbgs()); } |
294 | | |
295 | | /// Return the number of times that a region of code associated with this |
296 | | /// counter was executed. |
297 | | Expected<int64_t> evaluate(const Counter &C) const; |
298 | | }; |
299 | | |
300 | | /// Code coverage information for a single function. |
301 | | struct FunctionRecord { |
302 | | /// Raw function name. |
303 | | std::string Name; |
304 | | /// Associated files. |
305 | | std::vector<std::string> Filenames; |
306 | | /// Regions in the function along with their counts. |
307 | | std::vector<CountedRegion> CountedRegions; |
308 | | /// The number of times this function was executed. |
309 | | uint64_t ExecutionCount; |
310 | | |
311 | | FunctionRecord(StringRef Name, ArrayRef<StringRef> Filenames) |
312 | 520 | : Name(Name), Filenames(Filenames.begin(), Filenames.end()) {} |
313 | | |
314 | 940 | FunctionRecord(FunctionRecord &&FR) = default; |
315 | | FunctionRecord &operator=(FunctionRecord &&) = default; |
316 | | |
317 | 2.15k | void pushRegion(CounterMappingRegion Region, uint64_t Count) { |
318 | 2.15k | if (CountedRegions.empty()) |
319 | 520 | ExecutionCount = Count; |
320 | 2.15k | CountedRegions.emplace_back(Region, Count); |
321 | 2.15k | } |
322 | | }; |
323 | | |
324 | | /// Iterator over Functions, optionally filtered to a single file. |
325 | | class FunctionRecordIterator |
326 | | : public iterator_facade_base<FunctionRecordIterator, |
327 | | std::forward_iterator_tag, FunctionRecord> { |
328 | | ArrayRef<FunctionRecord> Records; |
329 | | ArrayRef<FunctionRecord>::iterator Current; |
330 | | StringRef Filename; |
331 | | |
332 | | /// Skip records whose primary file is not \c Filename. |
333 | | void skipOtherFiles(); |
334 | | |
335 | | public: |
336 | | FunctionRecordIterator(ArrayRef<FunctionRecord> Records_, |
337 | | StringRef Filename = "") |
338 | 316 | : Records(Records_), Current(Records.begin()), Filename(Filename) { |
339 | 316 | skipOtherFiles(); |
340 | 316 | } |
341 | | |
342 | 609 | FunctionRecordIterator() : Current(Records.begin()) {} |
343 | | |
344 | 1.22k | bool operator==(const FunctionRecordIterator &RHS) const { |
345 | 1.22k | return Current == RHS.Current && Filename == RHS.Filename293 ; |
346 | 1.22k | } |
347 | | |
348 | 947 | const FunctionRecord &operator*() const { return *Current; } |
349 | | |
350 | 931 | FunctionRecordIterator &operator++() { |
351 | 931 | assert(Current != Records.end() && "incremented past end"); |
352 | 931 | ++Current; |
353 | 931 | skipOtherFiles(); |
354 | 931 | return *this; |
355 | 931 | } |
356 | | }; |
357 | | |
358 | | /// Coverage information for a macro expansion or #included file. |
359 | | /// |
360 | | /// When covered code has pieces that can be expanded for more detail, such as a |
361 | | /// preprocessor macro use and its definition, these are represented as |
362 | | /// expansions whose coverage can be looked up independently. |
363 | | struct ExpansionRecord { |
364 | | /// The abstract file this expansion covers. |
365 | | unsigned FileID; |
366 | | /// The region that expands to this record. |
367 | | const CountedRegion &Region; |
368 | | /// Coverage for the expansion. |
369 | | const FunctionRecord &Function; |
370 | | |
371 | | ExpansionRecord(const CountedRegion &Region, |
372 | | const FunctionRecord &Function) |
373 | 27 | : FileID(Region.ExpandedFileID), Region(Region), Function(Function) {} |
374 | | }; |
375 | | |
376 | | /// The execution count information starting at a point in a file. |
377 | | /// |
378 | | /// A sequence of CoverageSegments gives execution counts for a file in format |
379 | | /// that's simple to iterate through for processing. |
380 | | struct CoverageSegment { |
381 | | /// The line where this segment begins. |
382 | | unsigned Line; |
383 | | /// The column where this segment begins. |
384 | | unsigned Col; |
385 | | /// The execution count, or zero if no count was recorded. |
386 | | uint64_t Count; |
387 | | /// When false, the segment was uninstrumented or skipped. |
388 | | bool HasCount; |
389 | | /// Whether this enters a new region or returns to a previous count. |
390 | | bool IsRegionEntry; |
391 | | /// Whether this enters a gap region. |
392 | | bool IsGapRegion; |
393 | | |
394 | | CoverageSegment(unsigned Line, unsigned Col, bool IsRegionEntry) |
395 | | : Line(Line), Col(Col), Count(0), HasCount(false), |
396 | 675 | IsRegionEntry(IsRegionEntry), IsGapRegion(false) {} |
397 | | |
398 | | CoverageSegment(unsigned Line, unsigned Col, uint64_t Count, |
399 | | bool IsRegionEntry, bool IsGapRegion = false) |
400 | | : Line(Line), Col(Col), Count(Count), HasCount(true), |
401 | 3.69k | IsRegionEntry(IsRegionEntry), IsGapRegion(IsGapRegion) {} |
402 | | |
403 | | friend bool operator==(const CoverageSegment &L, const CoverageSegment &R) { |
404 | | return std::tie(L.Line, L.Col, L.Count, L.HasCount, L.IsRegionEntry, |
405 | | L.IsGapRegion) == std::tie(R.Line, R.Col, R.Count, |
406 | | R.HasCount, R.IsRegionEntry, |
407 | | R.IsGapRegion); |
408 | | } |
409 | | }; |
410 | | |
411 | | /// An instantiation group contains a \c FunctionRecord list, such that each |
412 | | /// record corresponds to a distinct instantiation of the same function. |
413 | | /// |
414 | | /// Note that it's possible for a function to have more than one instantiation |
415 | | /// (consider C++ template specializations or static inline functions). |
416 | | class InstantiationGroup { |
417 | | friend class CoverageMapping; |
418 | | |
419 | | unsigned Line; |
420 | | unsigned Col; |
421 | | std::vector<const FunctionRecord *> Instantiations; |
422 | | |
423 | | InstantiationGroup(unsigned Line, unsigned Col, |
424 | | std::vector<const FunctionRecord *> Instantiations) |
425 | 309 | : Line(Line), Col(Col), Instantiations(std::move(Instantiations)) {} |
426 | | |
427 | | public: |
428 | | InstantiationGroup(const InstantiationGroup &) = delete; |
429 | 376 | InstantiationGroup(InstantiationGroup &&) = default; |
430 | | |
431 | | /// Get the number of instantiations in this group. |
432 | | size_t size() const { return Instantiations.size(); } |
433 | | |
434 | | /// Get the line where the common function was defined. |
435 | | unsigned getLine() const { return Line; } |
436 | | |
437 | | /// Get the column where the common function was defined. |
438 | | unsigned getColumn() const { return Col; } |
439 | | |
440 | | /// Check if the instantiations in this group have a common mangled name. |
441 | | bool hasName() const { |
442 | | for (unsigned I = 1, E = Instantiations.size(); I < E; ++I) |
443 | | if (Instantiations[I]->Name != Instantiations[0]->Name) |
444 | | return false; |
445 | | return true; |
446 | | } |
447 | | |
448 | | /// Get the common mangled name for instantiations in this group. |
449 | | StringRef getName() const { |
450 | | assert(hasName() && "Instantiations don't have a shared name"); |
451 | | return Instantiations[0]->Name; |
452 | | } |
453 | | |
454 | | /// Get the total execution count of all instantiations in this group. |
455 | | uint64_t getTotalExecutionCount() const { |
456 | | uint64_t Count = 0; |
457 | | for (const FunctionRecord *F : Instantiations) |
458 | | Count += F->ExecutionCount; |
459 | | return Count; |
460 | | } |
461 | | |
462 | | /// Get the instantiations in this group. |
463 | | ArrayRef<const FunctionRecord *> getInstantiations() const { |
464 | | return Instantiations; |
465 | | } |
466 | | }; |
467 | | |
468 | | /// Coverage information to be processed or displayed. |
469 | | /// |
470 | | /// This represents the coverage of an entire file, expansion, or function. It |
471 | | /// provides a sequence of CoverageSegments to iterate through, as well as the |
472 | | /// list of expansions that can be further processed. |
473 | | class CoverageData { |
474 | | friend class CoverageMapping; |
475 | | |
476 | | std::string Filename; |
477 | | std::vector<CoverageSegment> Segments; |
478 | | std::vector<ExpansionRecord> Expansions; |
479 | | |
480 | | public: |
481 | 0 | CoverageData() = default; |
482 | | |
483 | 525 | CoverageData(StringRef Filename) : Filename(Filename) {} |
484 | | |
485 | | /// Get the name of the file this data covers. |
486 | | StringRef getFilename() const { return Filename; } |
487 | | |
488 | | /// Get an iterator over the coverage segments for this object. The segments |
489 | | /// are guaranteed to be uniqued and sorted by location. |
490 | | std::vector<CoverageSegment>::const_iterator begin() const { |
491 | | return Segments.begin(); |
492 | | } |
493 | | |
494 | 13.4k | std::vector<CoverageSegment>::const_iterator end() const { |
495 | 13.4k | return Segments.end(); |
496 | 13.4k | } |
497 | | |
498 | | bool empty() const { return Segments.empty(); } |
499 | | |
500 | | /// Expansions that can be further processed. |
501 | | ArrayRef<ExpansionRecord> getExpansions() const { return Expansions; } |
502 | | }; |
503 | | |
504 | | /// The mapping of profile information to coverage data. |
505 | | /// |
506 | | /// This is the main interface to get coverage information, using a profile to |
507 | | /// fill out execution counts. |
508 | | class CoverageMapping { |
509 | | DenseMap<size_t, DenseSet<size_t>> RecordProvenance; |
510 | | std::vector<FunctionRecord> Functions; |
511 | | std::vector<std::pair<std::string, uint64_t>> FuncHashMismatches; |
512 | | |
513 | 215 | CoverageMapping() = default; |
514 | | |
515 | | /// Add a function record corresponding to \p Record. |
516 | | Error loadFunctionRecord(const CoverageMappingRecord &Record, |
517 | | IndexedInstrProfReader &ProfileReader); |
518 | | |
519 | | public: |
520 | | CoverageMapping(const CoverageMapping &) = delete; |
521 | | CoverageMapping &operator=(const CoverageMapping &) = delete; |
522 | | |
523 | | /// Load the coverage mapping using the given readers. |
524 | | static Expected<std::unique_ptr<CoverageMapping>> |
525 | | load(ArrayRef<std::unique_ptr<CoverageMappingReader>> CoverageReaders, |
526 | | IndexedInstrProfReader &ProfileReader); |
527 | | |
528 | | /// Load the coverage mapping from the given object files and profile. If |
529 | | /// \p Arches is non-empty, it must specify an architecture for each object. |
530 | | static Expected<std::unique_ptr<CoverageMapping>> |
531 | | load(ArrayRef<StringRef> ObjectFilenames, StringRef ProfileFilename, |
532 | | ArrayRef<StringRef> Arches = None); |
533 | | |
534 | | /// The number of functions that couldn't have their profiles mapped. |
535 | | /// |
536 | | /// This is a count of functions whose profile is out of date or otherwise |
537 | | /// can't be associated with any coverage information. |
538 | | unsigned getMismatchedCount() const { return FuncHashMismatches.size(); } |
539 | | |
540 | | /// A hash mismatch occurs when a profile record for a symbol does not have |
541 | | /// the same hash as a coverage mapping record for the same symbol. This |
542 | | /// returns a list of hash mismatches, where each mismatch is a pair of the |
543 | | /// symbol name and its coverage mapping hash. |
544 | | ArrayRef<std::pair<std::string, uint64_t>> getHashMismatches() const { |
545 | | return FuncHashMismatches; |
546 | | } |
547 | | |
548 | | /// Returns a lexicographically sorted, unique list of files that are |
549 | | /// covered. |
550 | | std::vector<StringRef> getUniqueSourceFiles() const; |
551 | | |
552 | | /// Get the coverage for a particular file. |
553 | | /// |
554 | | /// The given filename must be the name as recorded in the coverage |
555 | | /// information. That is, only names returned from getUniqueSourceFiles will |
556 | | /// yield a result. |
557 | | CoverageData getCoverageForFile(StringRef Filename) const; |
558 | | |
559 | | /// Get the coverage for a particular function. |
560 | | CoverageData getCoverageForFunction(const FunctionRecord &Function) const; |
561 | | |
562 | | /// Get the coverage for an expansion within a coverage set. |
563 | | CoverageData getCoverageForExpansion(const ExpansionRecord &Expansion) const; |
564 | | |
565 | | /// Gets all of the functions covered by this profile. |
566 | 281 | iterator_range<FunctionRecordIterator> getCoveredFunctions() const { |
567 | 281 | return make_range(FunctionRecordIterator(Functions), |
568 | 281 | FunctionRecordIterator()); |
569 | 281 | } |
570 | | |
571 | | /// Gets all of the functions in a particular file. |
572 | | iterator_range<FunctionRecordIterator> |
573 | | getCoveredFunctions(StringRef Filename) const { |
574 | | return make_range(FunctionRecordIterator(Functions, Filename), |
575 | | FunctionRecordIterator()); |
576 | | } |
577 | | |
578 | | /// Get the list of function instantiation groups in a particular file. |
579 | | /// |
580 | | /// Every instantiation group in a program is attributed to exactly one file: |
581 | | /// the file in which the definition for the common function begins. |
582 | | std::vector<InstantiationGroup> |
583 | | getInstantiationGroups(StringRef Filename) const; |
584 | | }; |
585 | | |
586 | | /// Coverage statistics for a single line. |
587 | | class LineCoverageStats { |
588 | | uint64_t ExecutionCount; |
589 | | bool HasMultipleRegions; |
590 | | bool Mapped; |
591 | | unsigned Line; |
592 | | ArrayRef<const CoverageSegment *> LineSegments; |
593 | | const CoverageSegment *WrappedSegment; |
594 | | |
595 | | friend class LineCoverageIterator; |
596 | 1.60k | LineCoverageStats() = default; |
597 | | |
598 | | public: |
599 | | LineCoverageStats(ArrayRef<const CoverageSegment *> LineSegments, |
600 | | const CoverageSegment *WrappedSegment, unsigned Line); |
601 | | |
602 | | uint64_t getExecutionCount() const { return ExecutionCount; } |
603 | | |
604 | | bool hasMultipleRegions() const { return HasMultipleRegions; } |
605 | | |
606 | | bool isMapped() const { return Mapped; } |
607 | | |
608 | | unsigned getLine() const { return Line; } |
609 | | |
610 | | ArrayRef<const CoverageSegment *> getLineSegments() const { |
611 | | return LineSegments; |
612 | | } |
613 | | |
614 | | const CoverageSegment *getWrappedSegment() const { return WrappedSegment; } |
615 | | }; |
616 | | |
617 | | /// An iterator over the \c LineCoverageStats objects for lines described by |
618 | | /// a \c CoverageData instance. |
619 | | class LineCoverageIterator |
620 | | : public iterator_facade_base< |
621 | | LineCoverageIterator, std::forward_iterator_tag, LineCoverageStats> { |
622 | | public: |
623 | | LineCoverageIterator(const CoverageData &CD) |
624 | 0 | : LineCoverageIterator(CD, CD.begin()->Line) {} |
625 | | |
626 | | LineCoverageIterator(const CoverageData &CD, unsigned Line) |
627 | | : CD(CD), WrappedSegment(nullptr), Next(CD.begin()), Ended(false), |
628 | | Line(Line), Segments(), Stats() { |
629 | | this->operator++(); |
630 | | } |
631 | | |
632 | | bool operator==(const LineCoverageIterator &R) const { |
633 | | return &CD == &R.CD && Next == R.Next && Ended == R.Ended; |
634 | | } |
635 | | |
636 | 0 | const LineCoverageStats &operator*() const { return Stats; } |
637 | | |
638 | | LineCoverageStats &operator*() { return Stats; } |
639 | | |
640 | | LineCoverageIterator &operator++(); |
641 | | |
642 | | LineCoverageIterator getEnd() const { |
643 | | auto EndIt = *this; |
644 | | EndIt.Next = CD.end(); |
645 | | EndIt.Ended = true; |
646 | | return EndIt; |
647 | | } |
648 | | |
649 | | private: |
650 | | const CoverageData &CD; |
651 | | const CoverageSegment *WrappedSegment; |
652 | | std::vector<CoverageSegment>::const_iterator Next; |
653 | | bool Ended; |
654 | | unsigned Line; |
655 | | SmallVector<const CoverageSegment *, 4> Segments; |
656 | | LineCoverageStats Stats; |
657 | | }; |
658 | | |
659 | | /// Get a \c LineCoverageIterator range for the lines described by \p CD. |
660 | | static inline iterator_range<LineCoverageIterator> |
661 | 0 | getLineCoverageStats(const coverage::CoverageData &CD) { |
662 | 0 | auto Begin = LineCoverageIterator(CD); |
663 | 0 | auto End = Begin.getEnd(); |
664 | 0 | return make_range(Begin, End); |
665 | 0 | } Unexecuted instantiation: CoverageMappingGen.cpp:llvm::coverage::getLineCoverageStats(llvm::coverage::CoverageData const&) Unexecuted instantiation: CoverageMapping.cpp:llvm::coverage::getLineCoverageStats(llvm::coverage::CoverageData const&) Unexecuted instantiation: CoverageMappingWriter.cpp:llvm::coverage::getLineCoverageStats(llvm::coverage::CoverageData const&) Unexecuted instantiation: CoverageMappingReader.cpp:llvm::coverage::getLineCoverageStats(llvm::coverage::CoverageData const&) |
666 | | |
667 | | // Profile coverage map has the following layout: |
668 | | // [CoverageMapFileHeader] |
669 | | // [ArrayStart] |
670 | | // [CovMapFunctionRecord] |
671 | | // [CovMapFunctionRecord] |
672 | | // ... |
673 | | // [ArrayEnd] |
674 | | // [Encoded Region Mapping Data] |
675 | | LLVM_PACKED_START |
676 | | template <class IntPtrT> struct CovMapFunctionRecordV1 { |
677 | | #define COVMAP_V1 |
678 | | #define COVMAP_FUNC_RECORD(Type, LLVMType, Name, Init) Type Name; |
679 | | #include "llvm/ProfileData/InstrProfData.inc" |
680 | | #undef COVMAP_V1 |
681 | | |
682 | | // Return the structural hash associated with the function. |
683 | 47 | template <support::endianness Endian> uint64_t getFuncHash() const { |
684 | 47 | return support::endian::byte_swap<uint64_t, Endian>(FuncHash); |
685 | 47 | } unsigned long long llvm::coverage::CovMapFunctionRecordV1<unsigned int>::getFuncHash<(llvm::support::endianness)1>() const Line | Count | Source | 683 | 1 | template <support::endianness Endian> uint64_t getFuncHash() const { | 684 | 1 | return support::endian::byte_swap<uint64_t, Endian>(FuncHash); | 685 | 1 | } |
unsigned long long llvm::coverage::CovMapFunctionRecordV1<unsigned int>::getFuncHash<(llvm::support::endianness)0>() const Line | Count | Source | 683 | 1 | template <support::endianness Endian> uint64_t getFuncHash() const { | 684 | 1 | return support::endian::byte_swap<uint64_t, Endian>(FuncHash); | 685 | 1 | } |
unsigned long long llvm::coverage::CovMapFunctionRecordV1<unsigned long long>::getFuncHash<(llvm::support::endianness)1>() const Line | Count | Source | 683 | 45 | template <support::endianness Endian> uint64_t getFuncHash() const { | 684 | 45 | return support::endian::byte_swap<uint64_t, Endian>(FuncHash); | 685 | 45 | } |
Unexecuted instantiation: unsigned long long llvm::coverage::CovMapFunctionRecordV1<unsigned long long>::getFuncHash<(llvm::support::endianness)0>() const |
686 | | |
687 | | // Return the coverage map data size for the funciton. |
688 | 47 | template <support::endianness Endian> uint32_t getDataSize() const { |
689 | 47 | return support::endian::byte_swap<uint32_t, Endian>(DataSize); |
690 | 47 | } unsigned int llvm::coverage::CovMapFunctionRecordV1<unsigned int>::getDataSize<(llvm::support::endianness)1>() const Line | Count | Source | 688 | 1 | template <support::endianness Endian> uint32_t getDataSize() const { | 689 | 1 | return support::endian::byte_swap<uint32_t, Endian>(DataSize); | 690 | 1 | } |
unsigned int llvm::coverage::CovMapFunctionRecordV1<unsigned int>::getDataSize<(llvm::support::endianness)0>() const Line | Count | Source | 688 | 1 | template <support::endianness Endian> uint32_t getDataSize() const { | 689 | 1 | return support::endian::byte_swap<uint32_t, Endian>(DataSize); | 690 | 1 | } |
unsigned int llvm::coverage::CovMapFunctionRecordV1<unsigned long long>::getDataSize<(llvm::support::endianness)1>() const Line | Count | Source | 688 | 45 | template <support::endianness Endian> uint32_t getDataSize() const { | 689 | 45 | return support::endian::byte_swap<uint32_t, Endian>(DataSize); | 690 | 45 | } |
Unexecuted instantiation: unsigned int llvm::coverage::CovMapFunctionRecordV1<unsigned long long>::getDataSize<(llvm::support::endianness)0>() const |
691 | | |
692 | | // Return function lookup key. The value is consider opaque. |
693 | 92 | template <support::endianness Endian> IntPtrT getFuncNameRef() const { |
694 | 92 | return support::endian::byte_swap<IntPtrT, Endian>(NamePtr); |
695 | 92 | } unsigned int llvm::coverage::CovMapFunctionRecordV1<unsigned int>::getFuncNameRef<(llvm::support::endianness)1>() const Line | Count | Source | 693 | 2 | template <support::endianness Endian> IntPtrT getFuncNameRef() const { | 694 | 2 | return support::endian::byte_swap<IntPtrT, Endian>(NamePtr); | 695 | 2 | } |
unsigned int llvm::coverage::CovMapFunctionRecordV1<unsigned int>::getFuncNameRef<(llvm::support::endianness)0>() const Line | Count | Source | 693 | 2 | template <support::endianness Endian> IntPtrT getFuncNameRef() const { | 694 | 2 | return support::endian::byte_swap<IntPtrT, Endian>(NamePtr); | 695 | 2 | } |
unsigned long long llvm::coverage::CovMapFunctionRecordV1<unsigned long long>::getFuncNameRef<(llvm::support::endianness)1>() const Line | Count | Source | 693 | 88 | template <support::endianness Endian> IntPtrT getFuncNameRef() const { | 694 | 88 | return support::endian::byte_swap<IntPtrT, Endian>(NamePtr); | 695 | 88 | } |
Unexecuted instantiation: unsigned long long llvm::coverage::CovMapFunctionRecordV1<unsigned long long>::getFuncNameRef<(llvm::support::endianness)0>() const |
696 | | |
697 | | // Return the PGO name of the function */ |
698 | | template <support::endianness Endian> |
699 | 45 | Error getFuncName(InstrProfSymtab &ProfileNames, StringRef &FuncName) const { |
700 | 45 | IntPtrT NameRef = getFuncNameRef<Endian>(); |
701 | 45 | uint32_t NameS = support::endian::byte_swap<uint32_t, Endian>(NameSize); |
702 | 45 | FuncName = ProfileNames.getFuncName(NameRef, NameS); |
703 | 45 | if (NameS && FuncName.empty()) |
704 | 0 | return make_error<CoverageMapError>(coveragemap_error::malformed); |
705 | 45 | return Error::success(); |
706 | 45 | } llvm::Error llvm::coverage::CovMapFunctionRecordV1<unsigned int>::getFuncName<(llvm::support::endianness)1>(llvm::InstrProfSymtab&, llvm::StringRef&) const Line | Count | Source | 699 | 1 | Error getFuncName(InstrProfSymtab &ProfileNames, StringRef &FuncName) const { | 700 | 1 | IntPtrT NameRef = getFuncNameRef<Endian>(); | 701 | 1 | uint32_t NameS = support::endian::byte_swap<uint32_t, Endian>(NameSize); | 702 | 1 | FuncName = ProfileNames.getFuncName(NameRef, NameS); | 703 | 1 | if (NameS && FuncName.empty()) | 704 | 0 | return make_error<CoverageMapError>(coveragemap_error::malformed); | 705 | 1 | return Error::success(); | 706 | 1 | } |
llvm::Error llvm::coverage::CovMapFunctionRecordV1<unsigned int>::getFuncName<(llvm::support::endianness)0>(llvm::InstrProfSymtab&, llvm::StringRef&) const Line | Count | Source | 699 | 1 | Error getFuncName(InstrProfSymtab &ProfileNames, StringRef &FuncName) const { | 700 | 1 | IntPtrT NameRef = getFuncNameRef<Endian>(); | 701 | 1 | uint32_t NameS = support::endian::byte_swap<uint32_t, Endian>(NameSize); | 702 | 1 | FuncName = ProfileNames.getFuncName(NameRef, NameS); | 703 | 1 | if (NameS && FuncName.empty()) | 704 | 0 | return make_error<CoverageMapError>(coveragemap_error::malformed); | 705 | 1 | return Error::success(); | 706 | 1 | } |
llvm::Error llvm::coverage::CovMapFunctionRecordV1<unsigned long long>::getFuncName<(llvm::support::endianness)1>(llvm::InstrProfSymtab&, llvm::StringRef&) const Line | Count | Source | 699 | 43 | Error getFuncName(InstrProfSymtab &ProfileNames, StringRef &FuncName) const { | 700 | 43 | IntPtrT NameRef = getFuncNameRef<Endian>(); | 701 | 43 | uint32_t NameS = support::endian::byte_swap<uint32_t, Endian>(NameSize); | 702 | 43 | FuncName = ProfileNames.getFuncName(NameRef, NameS); | 703 | 43 | if (NameS && FuncName.empty()) | 704 | 0 | return make_error<CoverageMapError>(coveragemap_error::malformed); | 705 | 43 | return Error::success(); | 706 | 43 | } |
Unexecuted instantiation: llvm::Error llvm::coverage::CovMapFunctionRecordV1<unsigned long long>::getFuncName<(llvm::support::endianness)0>(llvm::InstrProfSymtab&, llvm::StringRef&) const |
707 | | }; |
708 | | |
709 | | struct CovMapFunctionRecord { |
710 | | #define COVMAP_FUNC_RECORD(Type, LLVMType, Name, Init) Type Name; |
711 | | #include "llvm/ProfileData/InstrProfData.inc" |
712 | | |
713 | | // Return the structural hash associated with the function. |
714 | 393 | template <support::endianness Endian> uint64_t getFuncHash() const { |
715 | 393 | return support::endian::byte_swap<uint64_t, Endian>(FuncHash); |
716 | 393 | } unsigned long long llvm::coverage::CovMapFunctionRecord::getFuncHash<(llvm::support::endianness)1>() const Line | Count | Source | 714 | 393 | template <support::endianness Endian> uint64_t getFuncHash() const { | 715 | 393 | return support::endian::byte_swap<uint64_t, Endian>(FuncHash); | 716 | 393 | } |
Unexecuted instantiation: unsigned long long llvm::coverage::CovMapFunctionRecord::getFuncHash<(llvm::support::endianness)0>() const |
717 | | |
718 | | // Return the coverage map data size for the funciton. |
719 | 393 | template <support::endianness Endian> uint32_t getDataSize() const { |
720 | 393 | return support::endian::byte_swap<uint32_t, Endian>(DataSize); |
721 | 393 | } unsigned int llvm::coverage::CovMapFunctionRecord::getDataSize<(llvm::support::endianness)1>() const Line | Count | Source | 719 | 393 | template <support::endianness Endian> uint32_t getDataSize() const { | 720 | 393 | return support::endian::byte_swap<uint32_t, Endian>(DataSize); | 721 | 393 | } |
Unexecuted instantiation: unsigned int llvm::coverage::CovMapFunctionRecord::getDataSize<(llvm::support::endianness)0>() const |
722 | | |
723 | | // Return function lookup key. The value is consider opaque. |
724 | 750 | template <support::endianness Endian> uint64_t getFuncNameRef() const { |
725 | 750 | return support::endian::byte_swap<uint64_t, Endian>(NameRef); |
726 | 750 | } unsigned long long llvm::coverage::CovMapFunctionRecord::getFuncNameRef<(llvm::support::endianness)1>() const Line | Count | Source | 724 | 750 | template <support::endianness Endian> uint64_t getFuncNameRef() const { | 725 | 750 | return support::endian::byte_swap<uint64_t, Endian>(NameRef); | 726 | 750 | } |
Unexecuted instantiation: unsigned long long llvm::coverage::CovMapFunctionRecord::getFuncNameRef<(llvm::support::endianness)0>() const |
727 | | |
728 | | // Return the PGO name of the function */ |
729 | | template <support::endianness Endian> |
730 | 357 | Error getFuncName(InstrProfSymtab &ProfileNames, StringRef &FuncName) const { |
731 | 357 | uint64_t NameRef = getFuncNameRef<Endian>(); |
732 | 357 | FuncName = ProfileNames.getFuncName(NameRef); |
733 | 357 | return Error::success(); |
734 | 357 | } llvm::Error llvm::coverage::CovMapFunctionRecord::getFuncName<(llvm::support::endianness)1>(llvm::InstrProfSymtab&, llvm::StringRef&) const Line | Count | Source | 730 | 357 | Error getFuncName(InstrProfSymtab &ProfileNames, StringRef &FuncName) const { | 731 | 357 | uint64_t NameRef = getFuncNameRef<Endian>(); | 732 | 357 | FuncName = ProfileNames.getFuncName(NameRef); | 733 | 357 | return Error::success(); | 734 | 357 | } |
Unexecuted instantiation: llvm::Error llvm::coverage::CovMapFunctionRecord::getFuncName<(llvm::support::endianness)0>(llvm::InstrProfSymtab&, llvm::StringRef&) const |
735 | | }; |
736 | | |
737 | | // Per module coverage mapping data header, i.e. CoverageMapFileHeader |
738 | | // documented above. |
739 | | struct CovMapHeader { |
740 | | #define COVMAP_HEADER(Type, LLVMType, Name, Init) Type Name; |
741 | | #include "llvm/ProfileData/InstrProfData.inc" |
742 | 172 | template <support::endianness Endian> uint32_t getNRecords() const { |
743 | 172 | return support::endian::byte_swap<uint32_t, Endian>(NRecords); |
744 | 172 | } unsigned int llvm::coverage::CovMapHeader::getNRecords<(llvm::support::endianness)1>() const Line | Count | Source | 742 | 171 | template <support::endianness Endian> uint32_t getNRecords() const { | 743 | 171 | return support::endian::byte_swap<uint32_t, Endian>(NRecords); | 744 | 171 | } |
unsigned int llvm::coverage::CovMapHeader::getNRecords<(llvm::support::endianness)0>() const Line | Count | Source | 742 | 1 | template <support::endianness Endian> uint32_t getNRecords() const { | 743 | 1 | return support::endian::byte_swap<uint32_t, Endian>(NRecords); | 744 | 1 | } |
|
745 | | |
746 | 172 | template <support::endianness Endian> uint32_t getFilenamesSize() const { |
747 | 172 | return support::endian::byte_swap<uint32_t, Endian>(FilenamesSize); |
748 | 172 | } unsigned int llvm::coverage::CovMapHeader::getFilenamesSize<(llvm::support::endianness)1>() const Line | Count | Source | 746 | 171 | template <support::endianness Endian> uint32_t getFilenamesSize() const { | 747 | 171 | return support::endian::byte_swap<uint32_t, Endian>(FilenamesSize); | 748 | 171 | } |
unsigned int llvm::coverage::CovMapHeader::getFilenamesSize<(llvm::support::endianness)0>() const Line | Count | Source | 746 | 1 | template <support::endianness Endian> uint32_t getFilenamesSize() const { | 747 | 1 | return support::endian::byte_swap<uint32_t, Endian>(FilenamesSize); | 748 | 1 | } |
|
749 | | |
750 | 172 | template <support::endianness Endian> uint32_t getCoverageSize() const { |
751 | 172 | return support::endian::byte_swap<uint32_t, Endian>(CoverageSize); |
752 | 172 | } unsigned int llvm::coverage::CovMapHeader::getCoverageSize<(llvm::support::endianness)1>() const Line | Count | Source | 750 | 171 | template <support::endianness Endian> uint32_t getCoverageSize() const { | 751 | 171 | return support::endian::byte_swap<uint32_t, Endian>(CoverageSize); | 752 | 171 | } |
unsigned int llvm::coverage::CovMapHeader::getCoverageSize<(llvm::support::endianness)0>() const Line | Count | Source | 750 | 1 | template <support::endianness Endian> uint32_t getCoverageSize() const { | 751 | 1 | return support::endian::byte_swap<uint32_t, Endian>(CoverageSize); | 752 | 1 | } |
|
753 | | |
754 | 123 | template <support::endianness Endian> uint32_t getVersion() const { |
755 | 123 | return support::endian::byte_swap<uint32_t, Endian>(Version); |
756 | 123 | } unsigned int llvm::coverage::CovMapHeader::getVersion<(llvm::support::endianness)1>() const Line | Count | Source | 754 | 122 | template <support::endianness Endian> uint32_t getVersion() const { | 755 | 122 | return support::endian::byte_swap<uint32_t, Endian>(Version); | 756 | 122 | } |
unsigned int llvm::coverage::CovMapHeader::getVersion<(llvm::support::endianness)0>() const Line | Count | Source | 754 | 1 | template <support::endianness Endian> uint32_t getVersion() const { | 755 | 1 | return support::endian::byte_swap<uint32_t, Endian>(Version); | 756 | 1 | } |
|
757 | | }; |
758 | | |
759 | | LLVM_PACKED_END |
760 | | |
761 | | enum CovMapVersion { |
762 | | Version1 = 0, |
763 | | // Function's name reference from CovMapFuncRecord is changed from raw |
764 | | // name string pointer to MD5 to support name section compression. Name |
765 | | // section is also compressed. |
766 | | Version2 = 1, |
767 | | // A new interpretation of the columnEnd field is added in order to mark |
768 | | // regions as gap areas. |
769 | | Version3 = 2, |
770 | | // The current version is Version3 |
771 | | CurrentVersion = INSTR_PROF_COVMAP_VERSION |
772 | | }; |
773 | | |
774 | | template <int CovMapVersion, class IntPtrT> struct CovMapTraits { |
775 | | using CovMapFuncRecordType = CovMapFunctionRecord; |
776 | | using NameRefType = uint64_t; |
777 | | }; |
778 | | |
779 | | template <class IntPtrT> struct CovMapTraits<CovMapVersion::Version1, IntPtrT> { |
780 | | using CovMapFuncRecordType = CovMapFunctionRecordV1<IntPtrT>; |
781 | | using NameRefType = IntPtrT; |
782 | | }; |
783 | | |
784 | | } // end namespace coverage |
785 | | |
786 | | /// Provide DenseMapInfo for CounterExpression |
787 | | template<> struct DenseMapInfo<coverage::CounterExpression> { |
788 | 2.52k | static inline coverage::CounterExpression getEmptyKey() { |
789 | 2.52k | using namespace coverage; |
790 | 2.52k | |
791 | 2.52k | return CounterExpression(CounterExpression::ExprKind::Subtract, |
792 | 2.52k | Counter::getCounter(~0U), |
793 | 2.52k | Counter::getCounter(~0U)); |
794 | 2.52k | } |
795 | | |
796 | 1.83k | static inline coverage::CounterExpression getTombstoneKey() { |
797 | 1.83k | using namespace coverage; |
798 | 1.83k | |
799 | 1.83k | return CounterExpression(CounterExpression::ExprKind::Add, |
800 | 1.83k | Counter::getCounter(~0U), |
801 | 1.83k | Counter::getCounter(~0U)); |
802 | 1.83k | } |
803 | | |
804 | 1.76k | static unsigned getHashValue(const coverage::CounterExpression &V) { |
805 | 1.76k | return static_cast<unsigned>( |
806 | 1.76k | hash_combine(V.Kind, V.LHS.getKind(), V.LHS.getCounterID(), |
807 | 1.76k | V.RHS.getKind(), V.RHS.getCounterID())); |
808 | 1.76k | } |
809 | | |
810 | | static bool isEqual(const coverage::CounterExpression &LHS, |
811 | 10.4k | const coverage::CounterExpression &RHS) { |
812 | 10.4k | return LHS.Kind == RHS.Kind && LHS.LHS == RHS.LHS8.25k && LHS.RHS == RHS.RHS6.40k ; |
813 | 10.4k | } |
814 | | }; |
815 | | |
816 | | } // end namespace llvm |
817 | | |
818 | | #endif // LLVM_PROFILEDATA_COVERAGE_COVERAGEMAPPING_H |