/src/llvm-project/llvm/lib/CodeGen/AsmPrinter/DebugLocEntry.h
Line | Count | Source (jump to first uncovered line) |
1 | | //===-- llvm/CodeGen/DebugLocEntry.h - Entry in debug_loc list -*- 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 | | #ifndef LLVM_LIB_CODEGEN_ASMPRINTER_DEBUGLOCENTRY_H |
10 | | #define LLVM_LIB_CODEGEN_ASMPRINTER_DEBUGLOCENTRY_H |
11 | | |
12 | | #include "DebugLocStream.h" |
13 | | #include "llvm/Config/llvm-config.h" |
14 | | #include "llvm/IR/Constants.h" |
15 | | #include "llvm/IR/DebugInfo.h" |
16 | | #include "llvm/MC/MCSymbol.h" |
17 | | #include "llvm/MC/MachineLocation.h" |
18 | | #include "llvm/Support/Debug.h" |
19 | | |
20 | | namespace llvm { |
21 | | class AsmPrinter; |
22 | | |
23 | | /// This struct describes target specific location. |
24 | | struct TargetIndexLocation { |
25 | | int Index; |
26 | | int Offset; |
27 | | |
28 | | TargetIndexLocation() = default; |
29 | | TargetIndexLocation(unsigned Idx, int64_t Offset) |
30 | 9 | : Index(Idx), Offset(Offset) {} |
31 | | |
32 | 3 | bool operator==(const TargetIndexLocation &Other) const { |
33 | 3 | return Index == Other.Index && Offset == Other.Offset; |
34 | 3 | } |
35 | | }; |
36 | | |
37 | | /// A single location or constant within a variable location description, with |
38 | | /// either a single entry (with an optional DIExpression) used for a DBG_VALUE, |
39 | | /// or a list of entries used for a DBG_VALUE_LIST. |
40 | | class DbgValueLocEntry { |
41 | | |
42 | | /// Type of entry that this represents. |
43 | | enum EntryType { |
44 | | E_Location, |
45 | | E_Integer, |
46 | | E_ConstantFP, |
47 | | E_ConstantInt, |
48 | | E_TargetIndexLocation |
49 | | }; |
50 | | enum EntryType EntryKind; |
51 | | |
52 | | /// Either a constant, |
53 | | union { |
54 | | int64_t Int; |
55 | | const ConstantFP *CFP; |
56 | | const ConstantInt *CIP; |
57 | | } Constant; |
58 | | |
59 | | union { |
60 | | /// Or a location in the machine frame. |
61 | | MachineLocation Loc; |
62 | | /// Or a location from target specific location. |
63 | | TargetIndexLocation TIL; |
64 | | }; |
65 | | |
66 | | public: |
67 | 799 | DbgValueLocEntry(int64_t i) : EntryKind(E_Integer) { Constant.Int = i; } |
68 | 0 | DbgValueLocEntry(const ConstantFP *CFP) : EntryKind(E_ConstantFP) { |
69 | 0 | Constant.CFP = CFP; |
70 | 0 | } |
71 | 0 | DbgValueLocEntry(const ConstantInt *CIP) : EntryKind(E_ConstantInt) { |
72 | 0 | Constant.CIP = CIP; |
73 | 0 | } |
74 | 2.44k | DbgValueLocEntry(MachineLocation Loc) : EntryKind(E_Location), Loc(Loc) {} |
75 | | DbgValueLocEntry(TargetIndexLocation Loc) |
76 | 9 | : EntryKind(E_TargetIndexLocation), TIL(Loc) {} |
77 | | |
78 | 1.39k | bool isLocation() const { return EntryKind == E_Location; } |
79 | 4.25k | bool isIndirectLocation() const { |
80 | 4.25k | return EntryKind == E_Location && Loc.isIndirect(); |
81 | 4.25k | } |
82 | 9 | bool isTargetIndexLocation() const { |
83 | 9 | return EntryKind == E_TargetIndexLocation; |
84 | 9 | } |
85 | 1.39k | bool isInt() const { return EntryKind == E_Integer; } |
86 | 0 | bool isConstantFP() const { return EntryKind == E_ConstantFP; } |
87 | 0 | bool isConstantInt() const { return EntryKind == E_ConstantInt; } |
88 | 376 | int64_t getInt() const { return Constant.Int; } |
89 | 0 | const ConstantFP *getConstantFP() const { return Constant.CFP; } |
90 | 0 | const ConstantInt *getConstantInt() const { return Constant.CIP; } |
91 | 1.29k | MachineLocation getLoc() const { return Loc; } |
92 | 9 | TargetIndexLocation getTargetIndexLocation() const { return TIL; } |
93 | | friend bool operator==(const DbgValueLocEntry &, const DbgValueLocEntry &); |
94 | | #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) |
95 | 0 | LLVM_DUMP_METHOD void dump() const { |
96 | 0 | if (isLocation()) { |
97 | 0 | llvm::dbgs() << "Loc = { reg=" << Loc.getReg() << " "; |
98 | 0 | if (Loc.isIndirect()) |
99 | 0 | llvm::dbgs() << "+0"; |
100 | 0 | llvm::dbgs() << "} "; |
101 | 0 | } else if (isConstantInt()) |
102 | 0 | Constant.CIP->dump(); |
103 | 0 | else if (isConstantFP()) |
104 | 0 | Constant.CFP->dump(); |
105 | 0 | } |
106 | | #endif |
107 | | }; |
108 | | |
109 | | /// The location of a single variable, composed of an expression and 0 or more |
110 | | /// DbgValueLocEntries. |
111 | | class DbgValueLoc { |
112 | | /// Any complex address location expression for this DbgValueLoc. |
113 | | const DIExpression *Expression; |
114 | | |
115 | | SmallVector<DbgValueLocEntry, 2> ValueLocEntries; |
116 | | |
117 | | bool IsVariadic; |
118 | | |
119 | | public: |
120 | | DbgValueLoc(const DIExpression *Expr, ArrayRef<DbgValueLocEntry> Locs) |
121 | | : Expression(Expr), ValueLocEntries(Locs.begin(), Locs.end()), |
122 | 0 | IsVariadic(true) {} |
123 | | |
124 | | DbgValueLoc(const DIExpression *Expr, ArrayRef<DbgValueLocEntry> Locs, |
125 | | bool IsVariadic) |
126 | | : Expression(Expr), ValueLocEntries(Locs.begin(), Locs.end()), |
127 | 3.25k | IsVariadic(IsVariadic) { |
128 | 3.25k | #ifndef NDEBUG |
129 | 3.25k | assert(Expr->isValid() || |
130 | 3.25k | !any_of(Locs, [](auto LE) { return LE.isLocation(); })); |
131 | 3.25k | if (!IsVariadic) { |
132 | 3.24k | assert(ValueLocEntries.size() == 1); |
133 | 3.24k | } |
134 | 3.25k | #endif |
135 | 3.25k | } |
136 | | |
137 | | DbgValueLoc(const DIExpression *Expr, DbgValueLocEntry Loc) |
138 | 0 | : Expression(Expr), ValueLocEntries(1, Loc), IsVariadic(false) { |
139 | 0 | assert(((Expr && Expr->isValid()) || !Loc.isLocation()) && |
140 | 0 | "DBG_VALUE with a machine location must have a valid expression."); |
141 | 0 | } |
142 | | |
143 | 1.43k | bool isFragment() const { return getExpression()->isFragment(); } |
144 | 0 | bool isEntryVal() const { return getExpression()->isEntryValue(); } |
145 | 1.44k | bool isVariadic() const { return IsVariadic; } |
146 | 2.12k | bool isEquivalent(const DbgValueLoc &Other) const { |
147 | | // Cannot be equivalent with different numbers of entries. |
148 | 2.12k | if (ValueLocEntries.size() != Other.ValueLocEntries.size()) |
149 | 0 | return false; |
150 | 2.12k | bool ThisIsIndirect = |
151 | 2.12k | !IsVariadic && ValueLocEntries[0].isIndirectLocation(); |
152 | 2.12k | bool OtherIsIndirect = |
153 | 2.12k | !Other.IsVariadic && Other.ValueLocEntries[0].isIndirectLocation(); |
154 | | // Check equivalence of DIExpressions + Directness together. |
155 | 2.12k | if (!DIExpression::isEqualExpression(Expression, ThisIsIndirect, |
156 | 2.12k | Other.Expression, OtherIsIndirect)) |
157 | 107 | return false; |
158 | | // Indirectness should have been accounted for in the above check, so just |
159 | | // compare register values directly here. |
160 | 2.02k | if (ThisIsIndirect || OtherIsIndirect) { |
161 | 48 | DbgValueLocEntry ThisOp = ValueLocEntries[0]; |
162 | 48 | DbgValueLocEntry OtherOp = Other.ValueLocEntries[0]; |
163 | 48 | return ThisOp.isLocation() && OtherOp.isLocation() && |
164 | 48 | ThisOp.getLoc().getReg() == OtherOp.getLoc().getReg(); |
165 | 48 | } |
166 | | // If neither are indirect, then just compare the loc entries directly. |
167 | 1.97k | return ValueLocEntries == Other.ValueLocEntries; |
168 | 2.02k | } |
169 | 2.99k | const DIExpression *getExpression() const { return Expression; } |
170 | 1.82k | ArrayRef<DbgValueLocEntry> getLocEntries() const { return ValueLocEntries; } |
171 | | friend bool operator==(const DbgValueLoc &, const DbgValueLoc &); |
172 | | friend bool operator<(const DbgValueLoc &, const DbgValueLoc &); |
173 | | #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) |
174 | 0 | LLVM_DUMP_METHOD void dump() const { |
175 | 0 | for (const DbgValueLocEntry &DV : ValueLocEntries) |
176 | 0 | DV.dump(); |
177 | 0 | if (Expression) |
178 | 0 | Expression->dump(); |
179 | 0 | } |
180 | | #endif |
181 | | }; |
182 | | |
183 | | /// This struct describes location entries emitted in the .debug_loc |
184 | | /// section. |
185 | | class DebugLocEntry { |
186 | | /// Begin and end symbols for the address range that this location is valid. |
187 | | const MCSymbol *Begin; |
188 | | const MCSymbol *End; |
189 | | |
190 | | /// A nonempty list of locations/constants belonging to this entry, |
191 | | /// sorted by offset. |
192 | | SmallVector<DbgValueLoc, 1> Values; |
193 | | |
194 | | public: |
195 | | /// Create a location list entry for the range [\p Begin, \p End). |
196 | | /// |
197 | | /// \param Vals One or more values describing (parts of) the variable. |
198 | | DebugLocEntry(const MCSymbol *Begin, const MCSymbol *End, |
199 | | ArrayRef<DbgValueLoc> Vals) |
200 | 3.18k | : Begin(Begin), End(End) { |
201 | 3.18k | addValues(Vals); |
202 | 3.18k | } |
203 | | |
204 | | /// Attempt to merge this DebugLocEntry with Next and return |
205 | | /// true if the merge was successful. Entries can be merged if they |
206 | | /// share the same Loc/Constant and if Next immediately follows this |
207 | | /// Entry. |
208 | 2.33k | bool MergeRanges(const DebugLocEntry &Next) { |
209 | | // If this and Next are describing the same variable, merge them. |
210 | 2.33k | if (End != Next.Begin) |
211 | 203 | return false; |
212 | 2.12k | if (Values.size() != Next.Values.size()) |
213 | 0 | return false; |
214 | 3.79k | for (unsigned EntryIdx = 0; EntryIdx < Values.size(); ++EntryIdx) |
215 | 2.12k | if (!Values[EntryIdx].isEquivalent(Next.Values[EntryIdx])) |
216 | 467 | return false; |
217 | 1.66k | End = Next.End; |
218 | 1.66k | return true; |
219 | 2.12k | } |
220 | | |
221 | 0 | const MCSymbol *getBeginSym() const { return Begin; } |
222 | 0 | const MCSymbol *getEndSym() const { return End; } |
223 | 89 | ArrayRef<DbgValueLoc> getValues() const { return Values; } |
224 | 3.18k | void addValues(ArrayRef<DbgValueLoc> Vals) { |
225 | 3.18k | Values.append(Vals.begin(), Vals.end()); |
226 | 3.18k | sortUniqueValues(); |
227 | 3.18k | assert((Values.size() == 1 || all_of(Values, [](DbgValueLoc V) { |
228 | 3.18k | return V.isFragment(); |
229 | 3.18k | })) && "must either have a single value or multiple pieces"); |
230 | 3.18k | } |
231 | | |
232 | | // Sort the pieces by offset. |
233 | | // Remove any duplicate entries by dropping all but the first. |
234 | 3.18k | void sortUniqueValues() { |
235 | | // Values is either 1 item that does not have a fragment, or many items |
236 | | // that all do. No need to sort if the former and also prevents operator< |
237 | | // being called on a non fragment item when _GLIBCXX_DEBUG is defined. |
238 | 3.18k | if (Values.size() == 1) |
239 | 3.18k | return; |
240 | 0 | llvm::sort(Values); |
241 | 0 | Values.erase(std::unique(Values.begin(), Values.end(), |
242 | 0 | [](const DbgValueLoc &A, const DbgValueLoc &B) { |
243 | 0 | return A.getExpression() == B.getExpression(); |
244 | 0 | }), |
245 | 0 | Values.end()); |
246 | 0 | } |
247 | | |
248 | | /// Lower this entry into a DWARF expression. |
249 | | void finalize(const AsmPrinter &AP, |
250 | | DebugLocStream::ListBuilder &List, |
251 | | const DIBasicType *BT, |
252 | | DwarfCompileUnit &TheCU); |
253 | | }; |
254 | | |
255 | | /// Compare two DbgValueLocEntries for equality. |
256 | 1.97k | inline bool operator==(const DbgValueLocEntry &A, const DbgValueLocEntry &B) { |
257 | 1.97k | if (A.EntryKind != B.EntryKind) |
258 | 233 | return false; |
259 | | |
260 | 1.74k | switch (A.EntryKind) { |
261 | 1.30k | case DbgValueLocEntry::E_Location: |
262 | 1.30k | return A.Loc == B.Loc; |
263 | 3 | case DbgValueLocEntry::E_TargetIndexLocation: |
264 | 3 | return A.TIL == B.TIL; |
265 | 431 | case DbgValueLocEntry::E_Integer: |
266 | 431 | return A.Constant.Int == B.Constant.Int; |
267 | 0 | case DbgValueLocEntry::E_ConstantFP: |
268 | 0 | return A.Constant.CFP == B.Constant.CFP; |
269 | 0 | case DbgValueLocEntry::E_ConstantInt: |
270 | 0 | return A.Constant.CIP == B.Constant.CIP; |
271 | 1.74k | } |
272 | 0 | llvm_unreachable("unhandled EntryKind"); |
273 | 0 | } |
274 | | |
275 | | /// Compare two DbgValueLocs for equality. |
276 | 0 | inline bool operator==(const DbgValueLoc &A, const DbgValueLoc &B) { |
277 | 0 | return A.ValueLocEntries == B.ValueLocEntries && |
278 | 0 | A.Expression == B.Expression && A.IsVariadic == B.IsVariadic; |
279 | 0 | } |
280 | | |
281 | | /// Compare two fragments based on their offset. |
282 | | inline bool operator<(const DbgValueLoc &A, |
283 | 0 | const DbgValueLoc &B) { |
284 | 0 | return A.getExpression()->getFragmentInfo()->OffsetInBits < |
285 | 0 | B.getExpression()->getFragmentInfo()->OffsetInBits; |
286 | 0 | } |
287 | | |
288 | | } |
289 | | |
290 | | #endif |