1 //===- CoverageMappingWriter.cpp - Code coverage mapping writer -----------===//
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
7 //===----------------------------------------------------------------------===//
9 // This file contains support for writing coverage mapping data for
10 // instrumentation based coverage.
12 //===----------------------------------------------------------------------===//
14 #include "llvm/ProfileData/Coverage/CoverageMappingWriter.h"
15 #include "llvm/ADT/ArrayRef.h"
16 #include "llvm/ADT/SmallVector.h"
17 #include "llvm/Support/LEB128.h"
18 #include "llvm/Support/raw_ostream.h"
25 using namespace coverage
;
27 void CoverageFilenamesSectionWriter::write(raw_ostream
&OS
) {
28 encodeULEB128(Filenames
.size(), OS
);
29 for (const auto &Filename
: Filenames
) {
30 encodeULEB128(Filename
.size(), OS
);
37 /// Gather only the expressions that are used by the mapping
38 /// regions in this function.
39 class CounterExpressionsMinimizer
{
40 ArrayRef
<CounterExpression
> Expressions
;
41 SmallVector
<CounterExpression
, 16> UsedExpressions
;
42 std::vector
<unsigned> AdjustedExpressionIDs
;
45 CounterExpressionsMinimizer(ArrayRef
<CounterExpression
> Expressions
,
46 ArrayRef
<CounterMappingRegion
> MappingRegions
)
47 : Expressions(Expressions
) {
48 AdjustedExpressionIDs
.resize(Expressions
.size(), 0);
49 for (const auto &I
: MappingRegions
)
51 for (const auto &I
: MappingRegions
)
55 void mark(Counter C
) {
56 if (!C
.isExpression())
58 unsigned ID
= C
.getExpressionID();
59 AdjustedExpressionIDs
[ID
] = 1;
60 mark(Expressions
[ID
].LHS
);
61 mark(Expressions
[ID
].RHS
);
64 void gatherUsed(Counter C
) {
65 if (!C
.isExpression() || !AdjustedExpressionIDs
[C
.getExpressionID()])
67 AdjustedExpressionIDs
[C
.getExpressionID()] = UsedExpressions
.size();
68 const auto &E
= Expressions
[C
.getExpressionID()];
69 UsedExpressions
.push_back(E
);
74 ArrayRef
<CounterExpression
> getExpressions() const { return UsedExpressions
; }
76 /// Adjust the given counter to correctly transition from the old
77 /// expression ids to the new expression ids.
78 Counter
adjust(Counter C
) const {
80 C
= Counter::getExpression(AdjustedExpressionIDs
[C
.getExpressionID()]);
85 } // end anonymous namespace
87 /// Encode the counter.
89 /// The encoding uses the following format:
91 /// Counter::Zero(0) - A Counter with kind Counter::Zero
92 /// Counter::CounterValueReference(1) - A counter with kind
93 /// Counter::CounterValueReference
94 /// Counter::Expression(2) + CounterExpression::Subtract(0) -
95 /// A counter with kind Counter::Expression and an expression
96 /// with kind CounterExpression::Subtract
97 /// Counter::Expression(2) + CounterExpression::Add(1) -
98 /// A counter with kind Counter::Expression and an expression
99 /// with kind CounterExpression::Add
100 /// Remaining bits - Counter/Expression ID.
101 static unsigned encodeCounter(ArrayRef
<CounterExpression
> Expressions
,
103 unsigned Tag
= unsigned(C
.getKind());
104 if (C
.isExpression())
105 Tag
+= Expressions
[C
.getExpressionID()].Kind
;
106 unsigned ID
= C
.getCounterID();
108 (std::numeric_limits
<unsigned>::max() >> Counter::EncodingTagBits
));
109 return Tag
| (ID
<< Counter::EncodingTagBits
);
112 static void writeCounter(ArrayRef
<CounterExpression
> Expressions
, Counter C
,
114 encodeULEB128(encodeCounter(Expressions
, C
), OS
);
117 void CoverageMappingWriter::write(raw_ostream
&OS
) {
118 // Check that we don't have any bogus regions.
119 assert(all_of(MappingRegions
,
120 [](const CounterMappingRegion
&CMR
) {
121 return CMR
.startLoc() <= CMR
.endLoc();
123 "Source region does not begin before it ends");
125 // Sort the regions in an ascending order by the file id and the starting
126 // location. Sort by region kinds to ensure stable order for tests.
127 llvm::stable_sort(MappingRegions
, [](const CounterMappingRegion
&LHS
,
128 const CounterMappingRegion
&RHS
) {
129 if (LHS
.FileID
!= RHS
.FileID
)
130 return LHS
.FileID
< RHS
.FileID
;
131 if (LHS
.startLoc() != RHS
.startLoc())
132 return LHS
.startLoc() < RHS
.startLoc();
133 return LHS
.Kind
< RHS
.Kind
;
136 // Write out the fileid -> filename mapping.
137 encodeULEB128(VirtualFileMapping
.size(), OS
);
138 for (const auto &FileID
: VirtualFileMapping
)
139 encodeULEB128(FileID
, OS
);
141 // Write out the expressions.
142 CounterExpressionsMinimizer
Minimizer(Expressions
, MappingRegions
);
143 auto MinExpressions
= Minimizer
.getExpressions();
144 encodeULEB128(MinExpressions
.size(), OS
);
145 for (const auto &E
: MinExpressions
) {
146 writeCounter(MinExpressions
, Minimizer
.adjust(E
.LHS
), OS
);
147 writeCounter(MinExpressions
, Minimizer
.adjust(E
.RHS
), OS
);
150 // Write out the mapping regions.
151 // Split the regions into subarrays where each region in a
152 // subarray has a fileID which is the index of that subarray.
153 unsigned PrevLineStart
= 0;
154 unsigned CurrentFileID
= ~0U;
155 for (auto I
= MappingRegions
.begin(), E
= MappingRegions
.end(); I
!= E
; ++I
) {
156 if (I
->FileID
!= CurrentFileID
) {
157 // Ensure that all file ids have at least one mapping region.
158 assert(I
->FileID
== (CurrentFileID
+ 1));
159 // Find the number of regions with this file id.
160 unsigned RegionCount
= 1;
161 for (auto J
= I
+ 1; J
!= E
&& I
->FileID
== J
->FileID
; ++J
)
163 // Start a new region sub-array.
164 encodeULEB128(RegionCount
, OS
);
166 CurrentFileID
= I
->FileID
;
169 Counter Count
= Minimizer
.adjust(I
->Count
);
171 case CounterMappingRegion::CodeRegion
:
172 case CounterMappingRegion::GapRegion
:
173 writeCounter(MinExpressions
, Count
, OS
);
175 case CounterMappingRegion::ExpansionRegion
: {
176 assert(Count
.isZero());
177 assert(I
->ExpandedFileID
<=
178 (std::numeric_limits
<unsigned>::max() >>
179 Counter::EncodingCounterTagAndExpansionRegionTagBits
));
180 // Mark an expansion region with a set bit that follows the counter tag,
181 // and pack the expanded file id into the remaining bits.
182 unsigned EncodedTagExpandedFileID
=
183 (1 << Counter::EncodingTagBits
) |
185 << Counter::EncodingCounterTagAndExpansionRegionTagBits
);
186 encodeULEB128(EncodedTagExpandedFileID
, OS
);
189 case CounterMappingRegion::SkippedRegion
:
190 assert(Count
.isZero());
191 encodeULEB128(unsigned(I
->Kind
)
192 << Counter::EncodingCounterTagAndExpansionRegionTagBits
,
196 assert(I
->LineStart
>= PrevLineStart
);
197 encodeULEB128(I
->LineStart
- PrevLineStart
, OS
);
198 encodeULEB128(I
->ColumnStart
, OS
);
199 assert(I
->LineEnd
>= I
->LineStart
);
200 encodeULEB128(I
->LineEnd
- I
->LineStart
, OS
);
201 encodeULEB128(I
->ColumnEnd
, OS
);
202 PrevLineStart
= I
->LineStart
;
204 // Ensure that all file ids have at least one mapping region.
205 assert(CurrentFileID
== (VirtualFileMapping
.size() - 1));