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