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 | : Index(Idx), Offset(Offset) {} |
31 | |
32 | bool operator==(const TargetIndexLocation &Other) const { |
33 | return Index == Other.Index && Offset == Other.Offset; |
34 | } |
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 | DbgValueLocEntry(int64_t i) : EntryKind(E_Integer) { Constant.Int = i; } |
68 | DbgValueLocEntry(const ConstantFP *CFP) : EntryKind(E_ConstantFP) { |
69 | Constant.CFP = CFP; |
70 | } |
71 | DbgValueLocEntry(const ConstantInt *CIP) : EntryKind(E_ConstantInt) { |
72 | Constant.CIP = CIP; |
73 | } |
74 | DbgValueLocEntry(MachineLocation Loc) : EntryKind(E_Location), Loc(Loc) {} |
75 | DbgValueLocEntry(TargetIndexLocation Loc) |
76 | : EntryKind(E_TargetIndexLocation), TIL(Loc) {} |
77 | |
78 | bool isLocation() const { return EntryKind == E_Location; } |
79 | bool isIndirectLocation() const { |
80 | return EntryKind == E_Location && Loc.isIndirect(); |
81 | } |
82 | bool isTargetIndexLocation() const { |
83 | return EntryKind == E_TargetIndexLocation; |
84 | } |
85 | bool isInt() const { return EntryKind == E_Integer; } |
86 | bool isConstantFP() const { return EntryKind == E_ConstantFP; } |
87 | bool isConstantInt() const { return EntryKind == E_ConstantInt; } |
88 | int64_t getInt() const { return Constant.Int; } |
89 | const ConstantFP *getConstantFP() const { return Constant.CFP; } |
90 | const ConstantInt *getConstantInt() const { return Constant.CIP; } |
91 | MachineLocation getLoc() const { return Loc; } |
92 | TargetIndexLocation getTargetIndexLocation() const { return TIL; } |
93 | friend bool operator==(const DbgValueLocEntry &, const DbgValueLocEntry &); |
94 | #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) |
95 | LLVM_DUMP_METHOD void dump() const { |
96 | if (isLocation()) { |
97 | llvm::dbgs() << "Loc = { reg=" << Loc.getReg() << " " ; |
98 | if (Loc.isIndirect()) |
99 | llvm::dbgs() << "+0" ; |
100 | llvm::dbgs() << "} " ; |
101 | } else if (isConstantInt()) |
102 | Constant.CIP->dump(); |
103 | else if (isConstantFP()) |
104 | Constant.CFP->dump(); |
105 | } |
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 | IsVariadic(true) {} |
123 | |
124 | DbgValueLoc(const DIExpression *Expr, ArrayRef<DbgValueLocEntry> Locs, |
125 | bool IsVariadic) |
126 | : Expression(Expr), ValueLocEntries(Locs.begin(), Locs.end()), |
127 | IsVariadic(IsVariadic) { |
128 | #ifndef NDEBUG |
129 | assert(Expr->isValid() || |
130 | !any_of(Locs, [](auto LE) { return LE.isLocation(); })); |
131 | if (!IsVariadic) { |
132 | assert(ValueLocEntries.size() == 1); |
133 | } |
134 | #endif |
135 | } |
136 | |
137 | DbgValueLoc(const DIExpression *Expr, DbgValueLocEntry Loc) |
138 | : Expression(Expr), ValueLocEntries(1, Loc), IsVariadic(false) { |
139 | assert(((Expr && Expr->isValid()) || !Loc.isLocation()) && |
140 | "DBG_VALUE with a machine location must have a valid expression." ); |
141 | } |
142 | |
143 | bool isFragment() const { return getExpression()->isFragment(); } |
144 | bool isEntryVal() const { return getExpression()->isEntryValue(); } |
145 | bool isVariadic() const { return IsVariadic; } |
146 | bool isEquivalent(const DbgValueLoc &Other) const { |
147 | // Cannot be equivalent with different numbers of entries. |
148 | if (ValueLocEntries.size() != Other.ValueLocEntries.size()) |
149 | return false; |
150 | bool ThisIsIndirect = |
151 | !IsVariadic && ValueLocEntries[0].isIndirectLocation(); |
152 | bool OtherIsIndirect = |
153 | !Other.IsVariadic && Other.ValueLocEntries[0].isIndirectLocation(); |
154 | // Check equivalence of DIExpressions + Directness together. |
155 | if (!DIExpression::isEqualExpression(FirstExpr: Expression, FirstIndirect: ThisIsIndirect, |
156 | SecondExpr: Other.Expression, SecondIndirect: OtherIsIndirect)) |
157 | return false; |
158 | // Indirectness should have been accounted for in the above check, so just |
159 | // compare register values directly here. |
160 | if (ThisIsIndirect || OtherIsIndirect) { |
161 | DbgValueLocEntry ThisOp = ValueLocEntries[0]; |
162 | DbgValueLocEntry OtherOp = Other.ValueLocEntries[0]; |
163 | return ThisOp.isLocation() && OtherOp.isLocation() && |
164 | ThisOp.getLoc().getReg() == OtherOp.getLoc().getReg(); |
165 | } |
166 | // If neither are indirect, then just compare the loc entries directly. |
167 | return ValueLocEntries == Other.ValueLocEntries; |
168 | } |
169 | const DIExpression *getExpression() const { return Expression; } |
170 | 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 | LLVM_DUMP_METHOD void dump() const { |
175 | for (const DbgValueLocEntry &DV : ValueLocEntries) |
176 | DV.dump(); |
177 | if (Expression) |
178 | Expression->dump(); |
179 | } |
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 | : Begin(Begin), End(End) { |
201 | addValues(Vals); |
202 | } |
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 | bool MergeRanges(const DebugLocEntry &Next) { |
209 | // If this and Next are describing the same variable, merge them. |
210 | if (End != Next.Begin) |
211 | return false; |
212 | if (Values.size() != Next.Values.size()) |
213 | return false; |
214 | for (unsigned EntryIdx = 0; EntryIdx < Values.size(); ++EntryIdx) |
215 | if (!Values[EntryIdx].isEquivalent(Other: Next.Values[EntryIdx])) |
216 | return false; |
217 | End = Next.End; |
218 | return true; |
219 | } |
220 | |
221 | const MCSymbol *getBeginSym() const { return Begin; } |
222 | const MCSymbol *getEndSym() const { return End; } |
223 | ArrayRef<DbgValueLoc> getValues() const { return Values; } |
224 | void addValues(ArrayRef<DbgValueLoc> Vals) { |
225 | Values.append(in_start: Vals.begin(), in_end: Vals.end()); |
226 | sortUniqueValues(); |
227 | assert((Values.size() == 1 || all_of(Values, [](DbgValueLoc V) { |
228 | return V.isFragment(); |
229 | })) && "must either have a single value or multiple pieces" ); |
230 | } |
231 | |
232 | // Sort the pieces by offset. |
233 | // Remove any duplicate entries by dropping all but the first. |
234 | 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 | if (Values.size() == 1) |
239 | return; |
240 | llvm::sort(C&: Values); |
241 | Values.erase(CS: llvm::unique(R&: Values, |
242 | P: [](const DbgValueLoc &A, const DbgValueLoc &B) { |
243 | return A.getExpression() == B.getExpression(); |
244 | }), |
245 | CE: Values.end()); |
246 | } |
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 | inline bool operator==(const DbgValueLocEntry &A, const DbgValueLocEntry &B) { |
257 | if (A.EntryKind != B.EntryKind) |
258 | return false; |
259 | |
260 | switch (A.EntryKind) { |
261 | case DbgValueLocEntry::E_Location: |
262 | return A.Loc == B.Loc; |
263 | case DbgValueLocEntry::E_TargetIndexLocation: |
264 | return A.TIL == B.TIL; |
265 | case DbgValueLocEntry::E_Integer: |
266 | return A.Constant.Int == B.Constant.Int; |
267 | case DbgValueLocEntry::E_ConstantFP: |
268 | return A.Constant.CFP == B.Constant.CFP; |
269 | case DbgValueLocEntry::E_ConstantInt: |
270 | return A.Constant.CIP == B.Constant.CIP; |
271 | } |
272 | llvm_unreachable("unhandled EntryKind" ); |
273 | } |
274 | |
275 | /// Compare two DbgValueLocs for equality. |
276 | inline bool operator==(const DbgValueLoc &A, const DbgValueLoc &B) { |
277 | return A.ValueLocEntries == B.ValueLocEntries && |
278 | A.Expression == B.Expression && A.IsVariadic == B.IsVariadic; |
279 | } |
280 | |
281 | /// Compare two fragments based on their offset. |
282 | inline bool operator<(const DbgValueLoc &A, |
283 | const DbgValueLoc &B) { |
284 | return A.getExpression()->getFragmentInfo()->OffsetInBits < |
285 | B.getExpression()->getFragmentInfo()->OffsetInBits; |
286 | } |
287 | |
288 | } |
289 | |
290 | #endif |
291 | |