xref: /freebsd/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/DebugLocEntry.h (revision 349cc55c9796c4596a5b9904cd3281af295f878f)
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; }
79480093f4SDimitry Andric   bool isTargetIndexLocation() const {
80480093f4SDimitry Andric     return EntryKind == E_TargetIndexLocation;
81480093f4SDimitry Andric   }
820b57cec5SDimitry Andric   bool isInt() const { return EntryKind == E_Integer; }
830b57cec5SDimitry Andric   bool isConstantFP() const { return EntryKind == E_ConstantFP; }
840b57cec5SDimitry Andric   bool isConstantInt() const { return EntryKind == E_ConstantInt; }
850b57cec5SDimitry Andric   int64_t getInt() const { return Constant.Int; }
860b57cec5SDimitry Andric   const ConstantFP *getConstantFP() const { return Constant.CFP; }
870b57cec5SDimitry Andric   const ConstantInt *getConstantInt() const { return Constant.CIP; }
880b57cec5SDimitry Andric   MachineLocation getLoc() const { return Loc; }
89480093f4SDimitry Andric   TargetIndexLocation getTargetIndexLocation() const { return TIL; }
90fe6060f1SDimitry Andric   friend bool operator==(const DbgValueLocEntry &, const DbgValueLocEntry &);
910b57cec5SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
920b57cec5SDimitry Andric   LLVM_DUMP_METHOD void dump() const {
930b57cec5SDimitry Andric     if (isLocation()) {
940b57cec5SDimitry Andric       llvm::dbgs() << "Loc = { reg=" << Loc.getReg() << " ";
950b57cec5SDimitry Andric       if (Loc.isIndirect())
960b57cec5SDimitry Andric         llvm::dbgs() << "+0";
970b57cec5SDimitry Andric       llvm::dbgs() << "} ";
980b57cec5SDimitry Andric     } else if (isConstantInt())
990b57cec5SDimitry Andric       Constant.CIP->dump();
1000b57cec5SDimitry Andric     else if (isConstantFP())
1010b57cec5SDimitry Andric       Constant.CFP->dump();
102fe6060f1SDimitry Andric   }
103fe6060f1SDimitry Andric #endif
104fe6060f1SDimitry Andric };
105fe6060f1SDimitry Andric 
106fe6060f1SDimitry Andric /// The location of a single variable, composed of an expression and 0 or more
107fe6060f1SDimitry Andric /// DbgValueLocEntries.
108fe6060f1SDimitry Andric class DbgValueLoc {
109fe6060f1SDimitry Andric   /// Any complex address location expression for this DbgValueLoc.
110fe6060f1SDimitry Andric   const DIExpression *Expression;
111fe6060f1SDimitry Andric 
112fe6060f1SDimitry Andric   SmallVector<DbgValueLocEntry, 2> ValueLocEntries;
113fe6060f1SDimitry Andric 
114fe6060f1SDimitry Andric   bool IsVariadic;
115fe6060f1SDimitry Andric 
116fe6060f1SDimitry Andric public:
117fe6060f1SDimitry Andric   DbgValueLoc(const DIExpression *Expr, ArrayRef<DbgValueLocEntry> Locs)
118fe6060f1SDimitry Andric       : Expression(Expr), ValueLocEntries(Locs.begin(), Locs.end()),
119fe6060f1SDimitry Andric         IsVariadic(true) {
120fe6060f1SDimitry Andric #ifndef NDEBUG
121fe6060f1SDimitry Andric     // Currently, DBG_VALUE_VAR expressions must use stack_value.
122fe6060f1SDimitry Andric     assert(Expr && Expr->isValid() &&
123fe6060f1SDimitry Andric            is_contained(Locs, dwarf::DW_OP_stack_value));
124fe6060f1SDimitry Andric #endif
125fe6060f1SDimitry Andric   }
126fe6060f1SDimitry Andric 
127fe6060f1SDimitry Andric   DbgValueLoc(const DIExpression *Expr, ArrayRef<DbgValueLocEntry> Locs,
128fe6060f1SDimitry Andric               bool IsVariadic)
129fe6060f1SDimitry Andric       : Expression(Expr), ValueLocEntries(Locs.begin(), Locs.end()),
130fe6060f1SDimitry Andric         IsVariadic(IsVariadic) {
131fe6060f1SDimitry Andric #ifndef NDEBUG
132fe6060f1SDimitry Andric     assert(cast<DIExpression>(Expr)->isValid() ||
133fe6060f1SDimitry Andric            !any_of(Locs, [](auto LE) { return LE.isLocation(); }));
134fe6060f1SDimitry Andric     if (!IsVariadic) {
135fe6060f1SDimitry Andric       assert(ValueLocEntries.size() == 1);
136fe6060f1SDimitry Andric     } else {
137fe6060f1SDimitry Andric       // Currently, DBG_VALUE_VAR expressions must use stack_value.
138fe6060f1SDimitry Andric       assert(Expr && Expr->isValid() &&
139fe6060f1SDimitry Andric              is_contained(Expr->getElements(), dwarf::DW_OP_stack_value));
140fe6060f1SDimitry Andric     }
141fe6060f1SDimitry Andric #endif
142fe6060f1SDimitry Andric   }
143fe6060f1SDimitry Andric 
144fe6060f1SDimitry Andric   DbgValueLoc(const DIExpression *Expr, DbgValueLocEntry Loc)
145fe6060f1SDimitry Andric       : Expression(Expr), ValueLocEntries(1, Loc), IsVariadic(false) {
146fe6060f1SDimitry Andric     assert(((Expr && Expr->isValid()) || !Loc.isLocation()) &&
147fe6060f1SDimitry Andric            "DBG_VALUE with a machine location must have a valid expression.");
148fe6060f1SDimitry Andric   }
149fe6060f1SDimitry Andric 
150fe6060f1SDimitry Andric   bool isFragment() const { return getExpression()->isFragment(); }
151fe6060f1SDimitry Andric   bool isEntryVal() const { return getExpression()->isEntryValue(); }
152fe6060f1SDimitry Andric   bool isVariadic() const { return IsVariadic; }
153fe6060f1SDimitry Andric   const DIExpression *getExpression() const { return Expression; }
154fe6060f1SDimitry Andric   const ArrayRef<DbgValueLocEntry> getLocEntries() const {
155fe6060f1SDimitry Andric     return ValueLocEntries;
156fe6060f1SDimitry Andric   }
157fe6060f1SDimitry Andric   friend bool operator==(const DbgValueLoc &, const DbgValueLoc &);
158fe6060f1SDimitry Andric   friend bool operator<(const DbgValueLoc &, const DbgValueLoc &);
159fe6060f1SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
160fe6060f1SDimitry Andric   LLVM_DUMP_METHOD void dump() const {
161*349cc55cSDimitry Andric     for (const DbgValueLocEntry &DV : ValueLocEntries)
162fe6060f1SDimitry Andric       DV.dump();
1630b57cec5SDimitry Andric     if (Expression)
1640b57cec5SDimitry Andric       Expression->dump();
1650b57cec5SDimitry Andric   }
1660b57cec5SDimitry Andric #endif
1670b57cec5SDimitry Andric };
1680b57cec5SDimitry Andric 
1690b57cec5SDimitry Andric /// This struct describes location entries emitted in the .debug_loc
1700b57cec5SDimitry Andric /// section.
1710b57cec5SDimitry Andric class DebugLocEntry {
1720b57cec5SDimitry Andric   /// Begin and end symbols for the address range that this location is valid.
1730b57cec5SDimitry Andric   const MCSymbol *Begin;
1740b57cec5SDimitry Andric   const MCSymbol *End;
1750b57cec5SDimitry Andric 
1760b57cec5SDimitry Andric   /// A nonempty list of locations/constants belonging to this entry,
1770b57cec5SDimitry Andric   /// sorted by offset.
1780b57cec5SDimitry Andric   SmallVector<DbgValueLoc, 1> Values;
1790b57cec5SDimitry Andric 
1800b57cec5SDimitry Andric public:
1810b57cec5SDimitry Andric   /// Create a location list entry for the range [\p Begin, \p End).
1820b57cec5SDimitry Andric   ///
1830b57cec5SDimitry Andric   /// \param Vals One or more values describing (parts of) the variable.
1840b57cec5SDimitry Andric   DebugLocEntry(const MCSymbol *Begin, const MCSymbol *End,
1850b57cec5SDimitry Andric                 ArrayRef<DbgValueLoc> Vals)
1860b57cec5SDimitry Andric       : Begin(Begin), End(End) {
1870b57cec5SDimitry Andric     addValues(Vals);
1880b57cec5SDimitry Andric   }
1890b57cec5SDimitry Andric 
1900b57cec5SDimitry Andric   /// Attempt to merge this DebugLocEntry with Next and return
1910b57cec5SDimitry Andric   /// true if the merge was successful. Entries can be merged if they
1920b57cec5SDimitry Andric   /// share the same Loc/Constant and if Next immediately follows this
1930b57cec5SDimitry Andric   /// Entry.
1940b57cec5SDimitry Andric   bool MergeRanges(const DebugLocEntry &Next) {
1950b57cec5SDimitry Andric     // If this and Next are describing the same variable, merge them.
1960b57cec5SDimitry Andric     if ((End == Next.Begin && Values == Next.Values)) {
1970b57cec5SDimitry Andric       End = Next.End;
1980b57cec5SDimitry Andric       return true;
1990b57cec5SDimitry Andric     }
2000b57cec5SDimitry Andric     return false;
2010b57cec5SDimitry Andric   }
2020b57cec5SDimitry Andric 
2030b57cec5SDimitry Andric   const MCSymbol *getBeginSym() const { return Begin; }
2040b57cec5SDimitry Andric   const MCSymbol *getEndSym() const { return End; }
2050b57cec5SDimitry Andric   ArrayRef<DbgValueLoc> getValues() const { return Values; }
2060b57cec5SDimitry Andric   void addValues(ArrayRef<DbgValueLoc> Vals) {
2070b57cec5SDimitry Andric     Values.append(Vals.begin(), Vals.end());
2080b57cec5SDimitry Andric     sortUniqueValues();
2090b57cec5SDimitry Andric     assert((Values.size() == 1 || all_of(Values, [](DbgValueLoc V) {
2100b57cec5SDimitry Andric               return V.isFragment();
2110b57cec5SDimitry Andric             })) && "must either have a single value or multiple pieces");
2120b57cec5SDimitry Andric   }
2130b57cec5SDimitry Andric 
2140b57cec5SDimitry Andric   // Sort the pieces by offset.
2150b57cec5SDimitry Andric   // Remove any duplicate entries by dropping all but the first.
2160b57cec5SDimitry Andric   void sortUniqueValues() {
2170b57cec5SDimitry Andric     llvm::sort(Values);
2180b57cec5SDimitry Andric     Values.erase(std::unique(Values.begin(), Values.end(),
2190b57cec5SDimitry Andric                              [](const DbgValueLoc &A, const DbgValueLoc &B) {
2200b57cec5SDimitry Andric                                return A.getExpression() == B.getExpression();
2210b57cec5SDimitry Andric                              }),
2220b57cec5SDimitry Andric                  Values.end());
2230b57cec5SDimitry Andric   }
2240b57cec5SDimitry Andric 
2250b57cec5SDimitry Andric   /// Lower this entry into a DWARF expression.
2260b57cec5SDimitry Andric   void finalize(const AsmPrinter &AP,
2270b57cec5SDimitry Andric                 DebugLocStream::ListBuilder &List,
2280b57cec5SDimitry Andric                 const DIBasicType *BT,
2290b57cec5SDimitry Andric                 DwarfCompileUnit &TheCU);
2300b57cec5SDimitry Andric };
2310b57cec5SDimitry Andric 
232fe6060f1SDimitry Andric /// Compare two DbgValueLocEntries for equality.
233fe6060f1SDimitry Andric inline bool operator==(const DbgValueLocEntry &A, const DbgValueLocEntry &B) {
2340b57cec5SDimitry Andric   if (A.EntryKind != B.EntryKind)
2350b57cec5SDimitry Andric     return false;
2360b57cec5SDimitry Andric 
2370b57cec5SDimitry Andric   switch (A.EntryKind) {
238fe6060f1SDimitry Andric   case DbgValueLocEntry::E_Location:
2390b57cec5SDimitry Andric     return A.Loc == B.Loc;
240fe6060f1SDimitry Andric   case DbgValueLocEntry::E_TargetIndexLocation:
241480093f4SDimitry Andric     return A.TIL == B.TIL;
242fe6060f1SDimitry Andric   case DbgValueLocEntry::E_Integer:
2430b57cec5SDimitry Andric     return A.Constant.Int == B.Constant.Int;
244fe6060f1SDimitry Andric   case DbgValueLocEntry::E_ConstantFP:
2450b57cec5SDimitry Andric     return A.Constant.CFP == B.Constant.CFP;
246fe6060f1SDimitry Andric   case DbgValueLocEntry::E_ConstantInt:
2470b57cec5SDimitry Andric     return A.Constant.CIP == B.Constant.CIP;
2480b57cec5SDimitry Andric   }
2490b57cec5SDimitry Andric   llvm_unreachable("unhandled EntryKind");
2500b57cec5SDimitry Andric }
2510b57cec5SDimitry Andric 
252fe6060f1SDimitry Andric /// Compare two DbgValueLocs for equality.
253fe6060f1SDimitry Andric inline bool operator==(const DbgValueLoc &A, const DbgValueLoc &B) {
254fe6060f1SDimitry Andric   return A.ValueLocEntries == B.ValueLocEntries &&
255fe6060f1SDimitry Andric          A.Expression == B.Expression && A.IsVariadic == B.IsVariadic;
256fe6060f1SDimitry Andric }
257fe6060f1SDimitry Andric 
2580b57cec5SDimitry Andric /// Compare two fragments based on their offset.
2590b57cec5SDimitry Andric inline bool operator<(const DbgValueLoc &A,
2600b57cec5SDimitry Andric                       const DbgValueLoc &B) {
2610b57cec5SDimitry Andric   return A.getExpression()->getFragmentInfo()->OffsetInBits <
2620b57cec5SDimitry Andric          B.getExpression()->getFragmentInfo()->OffsetInBits;
2630b57cec5SDimitry Andric }
2640b57cec5SDimitry Andric 
2650b57cec5SDimitry Andric }
2660b57cec5SDimitry Andric 
2670b57cec5SDimitry Andric #endif
268