xref: /freebsd-src/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/DebugLocEntry.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
10b57cec5SDimitry Andric //===-- llvm/CodeGen/DebugLocEntry.h - Entry in debug_loc list -*- C++ -*--===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #ifndef LLVM_LIB_CODEGEN_ASMPRINTER_DEBUGLOCENTRY_H
100b57cec5SDimitry Andric #define LLVM_LIB_CODEGEN_ASMPRINTER_DEBUGLOCENTRY_H
110b57cec5SDimitry Andric 
120b57cec5SDimitry Andric #include "DebugLocStream.h"
130b57cec5SDimitry Andric #include "llvm/Config/llvm-config.h"
140b57cec5SDimitry Andric #include "llvm/IR/Constants.h"
150b57cec5SDimitry Andric #include "llvm/IR/DebugInfo.h"
160b57cec5SDimitry Andric #include "llvm/MC/MCSymbol.h"
170b57cec5SDimitry Andric #include "llvm/MC/MachineLocation.h"
180b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
190b57cec5SDimitry Andric 
200b57cec5SDimitry Andric namespace llvm {
210b57cec5SDimitry Andric class AsmPrinter;
220b57cec5SDimitry Andric 
23480093f4SDimitry Andric /// This struct describes target specific location.
24480093f4SDimitry Andric struct TargetIndexLocation {
25480093f4SDimitry Andric   int Index;
26480093f4SDimitry Andric   int Offset;
27480093f4SDimitry Andric 
28480093f4SDimitry Andric   TargetIndexLocation() = default;
29480093f4SDimitry Andric   TargetIndexLocation(unsigned Idx, int64_t Offset)
30480093f4SDimitry Andric       : Index(Idx), Offset(Offset) {}
31480093f4SDimitry Andric 
32480093f4SDimitry Andric   bool operator==(const TargetIndexLocation &Other) const {
33480093f4SDimitry Andric     return Index == Other.Index && Offset == Other.Offset;
34480093f4SDimitry Andric   }
35480093f4SDimitry Andric };
36480093f4SDimitry Andric 
37fe6060f1SDimitry Andric /// A single location or constant within a variable location description, with
38fe6060f1SDimitry Andric /// either a single entry (with an optional DIExpression) used for a DBG_VALUE,
39fe6060f1SDimitry Andric /// or a list of entries used for a DBG_VALUE_LIST.
40fe6060f1SDimitry Andric class DbgValueLocEntry {
410b57cec5SDimitry Andric 
420b57cec5SDimitry Andric   /// Type of entry that this represents.
43480093f4SDimitry Andric   enum EntryType {
44480093f4SDimitry Andric     E_Location,
45480093f4SDimitry Andric     E_Integer,
46480093f4SDimitry Andric     E_ConstantFP,
47480093f4SDimitry Andric     E_ConstantInt,
48480093f4SDimitry Andric     E_TargetIndexLocation
49480093f4SDimitry Andric   };
500b57cec5SDimitry Andric   enum EntryType EntryKind;
510b57cec5SDimitry Andric 
520b57cec5SDimitry Andric   /// Either a constant,
530b57cec5SDimitry Andric   union {
540b57cec5SDimitry Andric     int64_t Int;
550b57cec5SDimitry Andric     const ConstantFP *CFP;
560b57cec5SDimitry Andric     const ConstantInt *CIP;
570b57cec5SDimitry Andric   } Constant;
580b57cec5SDimitry Andric 
59480093f4SDimitry Andric   union {
600b57cec5SDimitry Andric     /// Or a location in the machine frame.
610b57cec5SDimitry Andric     MachineLocation Loc;
62480093f4SDimitry Andric     /// Or a location from target specific location.
63480093f4SDimitry Andric     TargetIndexLocation TIL;
64480093f4SDimitry Andric   };
650b57cec5SDimitry Andric 
660b57cec5SDimitry Andric public:
67fe6060f1SDimitry Andric   DbgValueLocEntry(int64_t i) : EntryKind(E_Integer) { Constant.Int = i; }
68fe6060f1SDimitry Andric   DbgValueLocEntry(const ConstantFP *CFP) : EntryKind(E_ConstantFP) {
690b57cec5SDimitry Andric     Constant.CFP = CFP;
700b57cec5SDimitry Andric   }
71fe6060f1SDimitry Andric   DbgValueLocEntry(const ConstantInt *CIP) : EntryKind(E_ConstantInt) {
720b57cec5SDimitry Andric     Constant.CIP = CIP;
730b57cec5SDimitry Andric   }
74fe6060f1SDimitry Andric   DbgValueLocEntry(MachineLocation Loc) : EntryKind(E_Location), Loc(Loc) {}
75fe6060f1SDimitry Andric   DbgValueLocEntry(TargetIndexLocation Loc)
76fe6060f1SDimitry Andric       : EntryKind(E_TargetIndexLocation), TIL(Loc) {}
770b57cec5SDimitry Andric 
780b57cec5SDimitry Andric   bool isLocation() const { return EntryKind == E_Location; }
79bdd1243dSDimitry Andric   bool isIndirectLocation() const {
80bdd1243dSDimitry Andric     return EntryKind == E_Location && Loc.isIndirect();
81bdd1243dSDimitry Andric   }
82480093f4SDimitry Andric   bool isTargetIndexLocation() const {
83480093f4SDimitry Andric     return EntryKind == E_TargetIndexLocation;
84480093f4SDimitry Andric   }
850b57cec5SDimitry Andric   bool isInt() const { return EntryKind == E_Integer; }
860b57cec5SDimitry Andric   bool isConstantFP() const { return EntryKind == E_ConstantFP; }
870b57cec5SDimitry Andric   bool isConstantInt() const { return EntryKind == E_ConstantInt; }
880b57cec5SDimitry Andric   int64_t getInt() const { return Constant.Int; }
890b57cec5SDimitry Andric   const ConstantFP *getConstantFP() const { return Constant.CFP; }
900b57cec5SDimitry Andric   const ConstantInt *getConstantInt() const { return Constant.CIP; }
910b57cec5SDimitry Andric   MachineLocation getLoc() const { return Loc; }
92480093f4SDimitry Andric   TargetIndexLocation getTargetIndexLocation() const { return TIL; }
93fe6060f1SDimitry Andric   friend bool operator==(const DbgValueLocEntry &, const DbgValueLocEntry &);
940b57cec5SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
950b57cec5SDimitry Andric   LLVM_DUMP_METHOD void dump() const {
960b57cec5SDimitry Andric     if (isLocation()) {
970b57cec5SDimitry Andric       llvm::dbgs() << "Loc = { reg=" << Loc.getReg() << " ";
980b57cec5SDimitry Andric       if (Loc.isIndirect())
990b57cec5SDimitry Andric         llvm::dbgs() << "+0";
1000b57cec5SDimitry Andric       llvm::dbgs() << "} ";
1010b57cec5SDimitry Andric     } else if (isConstantInt())
1020b57cec5SDimitry Andric       Constant.CIP->dump();
1030b57cec5SDimitry Andric     else if (isConstantFP())
1040b57cec5SDimitry Andric       Constant.CFP->dump();
105fe6060f1SDimitry Andric   }
106fe6060f1SDimitry Andric #endif
107fe6060f1SDimitry Andric };
108fe6060f1SDimitry Andric 
109fe6060f1SDimitry Andric /// The location of a single variable, composed of an expression and 0 or more
110fe6060f1SDimitry Andric /// DbgValueLocEntries.
111fe6060f1SDimitry Andric class DbgValueLoc {
112fe6060f1SDimitry Andric   /// Any complex address location expression for this DbgValueLoc.
113fe6060f1SDimitry Andric   const DIExpression *Expression;
114fe6060f1SDimitry Andric 
115fe6060f1SDimitry Andric   SmallVector<DbgValueLocEntry, 2> ValueLocEntries;
116fe6060f1SDimitry Andric 
117fe6060f1SDimitry Andric   bool IsVariadic;
118fe6060f1SDimitry Andric 
119fe6060f1SDimitry Andric public:
120fe6060f1SDimitry Andric   DbgValueLoc(const DIExpression *Expr, ArrayRef<DbgValueLocEntry> Locs)
121fe6060f1SDimitry Andric       : Expression(Expr), ValueLocEntries(Locs.begin(), Locs.end()),
122bdd1243dSDimitry Andric         IsVariadic(true) {}
123fe6060f1SDimitry Andric 
124fe6060f1SDimitry Andric   DbgValueLoc(const DIExpression *Expr, ArrayRef<DbgValueLocEntry> Locs,
125fe6060f1SDimitry Andric               bool IsVariadic)
126fe6060f1SDimitry Andric       : Expression(Expr), ValueLocEntries(Locs.begin(), Locs.end()),
127fe6060f1SDimitry Andric         IsVariadic(IsVariadic) {
128fe6060f1SDimitry Andric #ifndef NDEBUG
12906c3fb27SDimitry Andric     assert(Expr->isValid() ||
130fe6060f1SDimitry Andric            !any_of(Locs, [](auto LE) { return LE.isLocation(); }));
131fe6060f1SDimitry Andric     if (!IsVariadic) {
132fe6060f1SDimitry Andric       assert(ValueLocEntries.size() == 1);
133fe6060f1SDimitry Andric     }
134fe6060f1SDimitry Andric #endif
135fe6060f1SDimitry Andric   }
136fe6060f1SDimitry Andric 
137fe6060f1SDimitry Andric   DbgValueLoc(const DIExpression *Expr, DbgValueLocEntry Loc)
138fe6060f1SDimitry Andric       : Expression(Expr), ValueLocEntries(1, Loc), IsVariadic(false) {
139fe6060f1SDimitry Andric     assert(((Expr && Expr->isValid()) || !Loc.isLocation()) &&
140fe6060f1SDimitry Andric            "DBG_VALUE with a machine location must have a valid expression.");
141fe6060f1SDimitry Andric   }
142fe6060f1SDimitry Andric 
143fe6060f1SDimitry Andric   bool isFragment() const { return getExpression()->isFragment(); }
144fe6060f1SDimitry Andric   bool isEntryVal() const { return getExpression()->isEntryValue(); }
145fe6060f1SDimitry Andric   bool isVariadic() const { return IsVariadic; }
146bdd1243dSDimitry Andric   bool isEquivalent(const DbgValueLoc &Other) const {
147bdd1243dSDimitry Andric     // Cannot be equivalent with different numbers of entries.
148bdd1243dSDimitry Andric     if (ValueLocEntries.size() != Other.ValueLocEntries.size())
149bdd1243dSDimitry Andric       return false;
150bdd1243dSDimitry Andric     bool ThisIsIndirect =
151bdd1243dSDimitry Andric         !IsVariadic && ValueLocEntries[0].isIndirectLocation();
152bdd1243dSDimitry Andric     bool OtherIsIndirect =
153bdd1243dSDimitry Andric         !Other.IsVariadic && Other.ValueLocEntries[0].isIndirectLocation();
154bdd1243dSDimitry Andric     // Check equivalence of DIExpressions + Directness together.
155bdd1243dSDimitry Andric     if (!DIExpression::isEqualExpression(Expression, ThisIsIndirect,
156bdd1243dSDimitry Andric                                          Other.Expression, OtherIsIndirect))
157bdd1243dSDimitry Andric       return false;
158bdd1243dSDimitry Andric     // Indirectness should have been accounted for in the above check, so just
159bdd1243dSDimitry Andric     // compare register values directly here.
160bdd1243dSDimitry Andric     if (ThisIsIndirect || OtherIsIndirect) {
161bdd1243dSDimitry Andric       DbgValueLocEntry ThisOp = ValueLocEntries[0];
162bdd1243dSDimitry Andric       DbgValueLocEntry OtherOp = Other.ValueLocEntries[0];
163bdd1243dSDimitry Andric       return ThisOp.isLocation() && OtherOp.isLocation() &&
164bdd1243dSDimitry Andric              ThisOp.getLoc().getReg() == OtherOp.getLoc().getReg();
165fe6060f1SDimitry Andric     }
166bdd1243dSDimitry Andric     // If neither are indirect, then just compare the loc entries directly.
167bdd1243dSDimitry Andric     return ValueLocEntries == Other.ValueLocEntries;
168bdd1243dSDimitry Andric   }
169bdd1243dSDimitry Andric   const DIExpression *getExpression() const { return Expression; }
170bdd1243dSDimitry Andric   ArrayRef<DbgValueLocEntry> getLocEntries() const { return ValueLocEntries; }
171fe6060f1SDimitry Andric   friend bool operator==(const DbgValueLoc &, const DbgValueLoc &);
172fe6060f1SDimitry Andric   friend bool operator<(const DbgValueLoc &, const DbgValueLoc &);
173fe6060f1SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
174fe6060f1SDimitry Andric   LLVM_DUMP_METHOD void dump() const {
175349cc55cSDimitry Andric     for (const DbgValueLocEntry &DV : ValueLocEntries)
176fe6060f1SDimitry Andric       DV.dump();
1770b57cec5SDimitry Andric     if (Expression)
1780b57cec5SDimitry Andric       Expression->dump();
1790b57cec5SDimitry Andric   }
1800b57cec5SDimitry Andric #endif
1810b57cec5SDimitry Andric };
1820b57cec5SDimitry Andric 
1830b57cec5SDimitry Andric /// This struct describes location entries emitted in the .debug_loc
1840b57cec5SDimitry Andric /// section.
1850b57cec5SDimitry Andric class DebugLocEntry {
1860b57cec5SDimitry Andric   /// Begin and end symbols for the address range that this location is valid.
1870b57cec5SDimitry Andric   const MCSymbol *Begin;
1880b57cec5SDimitry Andric   const MCSymbol *End;
1890b57cec5SDimitry Andric 
1900b57cec5SDimitry Andric   /// A nonempty list of locations/constants belonging to this entry,
1910b57cec5SDimitry Andric   /// sorted by offset.
1920b57cec5SDimitry Andric   SmallVector<DbgValueLoc, 1> Values;
1930b57cec5SDimitry Andric 
1940b57cec5SDimitry Andric public:
1950b57cec5SDimitry Andric   /// Create a location list entry for the range [\p Begin, \p End).
1960b57cec5SDimitry Andric   ///
1970b57cec5SDimitry Andric   /// \param Vals One or more values describing (parts of) the variable.
1980b57cec5SDimitry Andric   DebugLocEntry(const MCSymbol *Begin, const MCSymbol *End,
1990b57cec5SDimitry Andric                 ArrayRef<DbgValueLoc> Vals)
2000b57cec5SDimitry Andric       : Begin(Begin), End(End) {
2010b57cec5SDimitry Andric     addValues(Vals);
2020b57cec5SDimitry Andric   }
2030b57cec5SDimitry Andric 
2040b57cec5SDimitry Andric   /// Attempt to merge this DebugLocEntry with Next and return
2050b57cec5SDimitry Andric   /// true if the merge was successful. Entries can be merged if they
2060b57cec5SDimitry Andric   /// share the same Loc/Constant and if Next immediately follows this
2070b57cec5SDimitry Andric   /// Entry.
2080b57cec5SDimitry Andric   bool MergeRanges(const DebugLocEntry &Next) {
2090b57cec5SDimitry Andric     // If this and Next are describing the same variable, merge them.
210bdd1243dSDimitry Andric     if (End != Next.Begin)
211bdd1243dSDimitry Andric       return false;
212bdd1243dSDimitry Andric     if (Values.size() != Next.Values.size())
213bdd1243dSDimitry Andric       return false;
214bdd1243dSDimitry Andric     for (unsigned EntryIdx = 0; EntryIdx < Values.size(); ++EntryIdx)
215bdd1243dSDimitry Andric       if (!Values[EntryIdx].isEquivalent(Next.Values[EntryIdx]))
216bdd1243dSDimitry Andric         return false;
2170b57cec5SDimitry Andric     End = Next.End;
2180b57cec5SDimitry Andric     return true;
2190b57cec5SDimitry Andric   }
2200b57cec5SDimitry Andric 
2210b57cec5SDimitry Andric   const MCSymbol *getBeginSym() const { return Begin; }
2220b57cec5SDimitry Andric   const MCSymbol *getEndSym() const { return End; }
2230b57cec5SDimitry Andric   ArrayRef<DbgValueLoc> getValues() const { return Values; }
2240b57cec5SDimitry Andric   void addValues(ArrayRef<DbgValueLoc> Vals) {
2250b57cec5SDimitry Andric     Values.append(Vals.begin(), Vals.end());
2260b57cec5SDimitry Andric     sortUniqueValues();
2270b57cec5SDimitry Andric     assert((Values.size() == 1 || all_of(Values, [](DbgValueLoc V) {
2280b57cec5SDimitry Andric               return V.isFragment();
2290b57cec5SDimitry Andric             })) && "must either have a single value or multiple pieces");
2300b57cec5SDimitry Andric   }
2310b57cec5SDimitry Andric 
2320b57cec5SDimitry Andric   // Sort the pieces by offset.
2330b57cec5SDimitry Andric   // Remove any duplicate entries by dropping all but the first.
2340b57cec5SDimitry Andric   void sortUniqueValues() {
235bdd1243dSDimitry Andric     // Values is either 1 item that does not have a fragment, or many items
236bdd1243dSDimitry Andric     // that all do. No need to sort if the former and also prevents operator<
237bdd1243dSDimitry Andric     // being called on a non fragment item when _GLIBCXX_DEBUG is defined.
238bdd1243dSDimitry Andric     if (Values.size() == 1)
239bdd1243dSDimitry Andric       return;
2400b57cec5SDimitry Andric     llvm::sort(Values);
241*0fca6ea1SDimitry Andric     Values.erase(llvm::unique(Values,
2420b57cec5SDimitry Andric                               [](const DbgValueLoc &A, const DbgValueLoc &B) {
2430b57cec5SDimitry Andric                                 return A.getExpression() == B.getExpression();
2440b57cec5SDimitry Andric                               }),
2450b57cec5SDimitry Andric                  Values.end());
2460b57cec5SDimitry Andric   }
2470b57cec5SDimitry Andric 
2480b57cec5SDimitry Andric   /// Lower this entry into a DWARF expression.
2490b57cec5SDimitry Andric   void finalize(const AsmPrinter &AP,
2500b57cec5SDimitry Andric                 DebugLocStream::ListBuilder &List,
2510b57cec5SDimitry Andric                 const DIBasicType *BT,
2520b57cec5SDimitry Andric                 DwarfCompileUnit &TheCU);
2530b57cec5SDimitry Andric };
2540b57cec5SDimitry Andric 
255fe6060f1SDimitry Andric /// Compare two DbgValueLocEntries for equality.
256fe6060f1SDimitry Andric inline bool operator==(const DbgValueLocEntry &A, const DbgValueLocEntry &B) {
2570b57cec5SDimitry Andric   if (A.EntryKind != B.EntryKind)
2580b57cec5SDimitry Andric     return false;
2590b57cec5SDimitry Andric 
2600b57cec5SDimitry Andric   switch (A.EntryKind) {
261fe6060f1SDimitry Andric   case DbgValueLocEntry::E_Location:
2620b57cec5SDimitry Andric     return A.Loc == B.Loc;
263fe6060f1SDimitry Andric   case DbgValueLocEntry::E_TargetIndexLocation:
264480093f4SDimitry Andric     return A.TIL == B.TIL;
265fe6060f1SDimitry Andric   case DbgValueLocEntry::E_Integer:
2660b57cec5SDimitry Andric     return A.Constant.Int == B.Constant.Int;
267fe6060f1SDimitry Andric   case DbgValueLocEntry::E_ConstantFP:
2680b57cec5SDimitry Andric     return A.Constant.CFP == B.Constant.CFP;
269fe6060f1SDimitry Andric   case DbgValueLocEntry::E_ConstantInt:
2700b57cec5SDimitry Andric     return A.Constant.CIP == B.Constant.CIP;
2710b57cec5SDimitry Andric   }
2720b57cec5SDimitry Andric   llvm_unreachable("unhandled EntryKind");
2730b57cec5SDimitry Andric }
2740b57cec5SDimitry Andric 
275fe6060f1SDimitry Andric /// Compare two DbgValueLocs for equality.
276fe6060f1SDimitry Andric inline bool operator==(const DbgValueLoc &A, const DbgValueLoc &B) {
277fe6060f1SDimitry Andric   return A.ValueLocEntries == B.ValueLocEntries &&
278fe6060f1SDimitry Andric          A.Expression == B.Expression && A.IsVariadic == B.IsVariadic;
279fe6060f1SDimitry Andric }
280fe6060f1SDimitry Andric 
2810b57cec5SDimitry Andric /// Compare two fragments based on their offset.
2820b57cec5SDimitry Andric inline bool operator<(const DbgValueLoc &A,
2830b57cec5SDimitry Andric                       const DbgValueLoc &B) {
2840b57cec5SDimitry Andric   return A.getExpression()->getFragmentInfo()->OffsetInBits <
2850b57cec5SDimitry Andric          B.getExpression()->getFragmentInfo()->OffsetInBits;
2860b57cec5SDimitry Andric }
2870b57cec5SDimitry Andric 
2880b57cec5SDimitry Andric }
2890b57cec5SDimitry Andric 
2900b57cec5SDimitry Andric #endif
291