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