11275e4f0SDavid Blaikie //===-- llvm/CodeGen/DebugLocEntry.h - Entry in debug_loc list -*- C++ -*--===// 21275e4f0SDavid Blaikie // 32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information. 52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 61275e4f0SDavid Blaikie // 71275e4f0SDavid Blaikie //===----------------------------------------------------------------------===// 81275e4f0SDavid Blaikie 9a7c40ef0SBenjamin Kramer #ifndef LLVM_LIB_CODEGEN_ASMPRINTER_DEBUGLOCENTRY_H 10a7c40ef0SBenjamin Kramer #define LLVM_LIB_CODEGEN_ASMPRINTER_DEBUGLOCENTRY_H 1196b1551dSAdrian Prantl 1296b1551dSAdrian Prantl #include "DebugLocStream.h" 13432a3883SNico Weber #include "llvm/Config/llvm-config.h" 141275e4f0SDavid Blaikie #include "llvm/IR/Constants.h" 15b1416837SAdrian Prantl #include "llvm/IR/DebugInfo.h" 161275e4f0SDavid Blaikie #include "llvm/MC/MCSymbol.h" 17d9903888SChandler Carruth #include "llvm/MC/MachineLocation.h" 184dbf3371SBenjamin Kramer #include "llvm/Support/Debug.h" 191275e4f0SDavid Blaikie 201275e4f0SDavid Blaikie namespace llvm { 2192da14b2SAdrian Prantl class AsmPrinter; 22c0f7dd72SDuncan P. N. Exon Smith 23adf7a0a5SYury Delendik /// This struct describes target specific location. 24adf7a0a5SYury Delendik struct TargetIndexLocation { 25adf7a0a5SYury Delendik int Index; 26adf7a0a5SYury Delendik int Offset; 27adf7a0a5SYury Delendik 28adf7a0a5SYury Delendik TargetIndexLocation() = default; TargetIndexLocationTargetIndexLocation29adf7a0a5SYury Delendik TargetIndexLocation(unsigned Idx, int64_t Offset) 30adf7a0a5SYury Delendik : Index(Idx), Offset(Offset) {} 31adf7a0a5SYury Delendik 32adf7a0a5SYury Delendik bool operator==(const TargetIndexLocation &Other) const { 33adf7a0a5SYury Delendik return Index == Other.Index && Offset == Other.Offset; 34adf7a0a5SYury Delendik } 35adf7a0a5SYury Delendik }; 36adf7a0a5SYury Delendik 37e64f3cccSStephen Tozer /// A single location or constant within a variable location description, with 38e64f3cccSStephen Tozer /// either a single entry (with an optional DIExpression) used for a DBG_VALUE, 39e64f3cccSStephen Tozer /// or a list of entries used for a DBG_VALUE_LIST. 40e64f3cccSStephen Tozer class DbgValueLocEntry { 4187b7eb9dSAdrian Prantl 4292da14b2SAdrian Prantl /// Type of entry that this represents. 43adf7a0a5SYury Delendik enum EntryType { 44adf7a0a5SYury Delendik E_Location, 45adf7a0a5SYury Delendik E_Integer, 46adf7a0a5SYury Delendik E_ConstantFP, 47adf7a0a5SYury Delendik E_ConstantInt, 48adf7a0a5SYury Delendik E_TargetIndexLocation 49adf7a0a5SYury Delendik }; 50e19e5efeSAdrian Prantl enum EntryType EntryKind; 511275e4f0SDavid Blaikie 5292da14b2SAdrian Prantl /// Either a constant, 53e19e5efeSAdrian Prantl union { 54e19e5efeSAdrian Prantl int64_t Int; 55e19e5efeSAdrian Prantl const ConstantFP *CFP; 56e19e5efeSAdrian Prantl const ConstantInt *CIP; 57e19e5efeSAdrian Prantl } Constant; 58e19e5efeSAdrian Prantl 59adf7a0a5SYury Delendik union { 60076ae0d2SNikola Prica /// Or a location in the machine frame. 61e19e5efeSAdrian Prantl MachineLocation Loc; 62adf7a0a5SYury Delendik /// Or a location from target specific location. 63adf7a0a5SYury Delendik TargetIndexLocation TIL; 64adf7a0a5SYury Delendik }; 65e19e5efeSAdrian Prantl 66076ae0d2SNikola Prica public: DbgValueLocEntry(int64_t i)67e64f3cccSStephen Tozer DbgValueLocEntry(int64_t i) : EntryKind(E_Integer) { Constant.Int = i; } DbgValueLocEntry(const ConstantFP * CFP)68e64f3cccSStephen Tozer DbgValueLocEntry(const ConstantFP *CFP) : EntryKind(E_ConstantFP) { 69076ae0d2SNikola Prica Constant.CFP = CFP; 70076ae0d2SNikola Prica } DbgValueLocEntry(const ConstantInt * CIP)71e64f3cccSStephen Tozer DbgValueLocEntry(const ConstantInt *CIP) : EntryKind(E_ConstantInt) { 72076ae0d2SNikola Prica Constant.CIP = CIP; 73076ae0d2SNikola Prica } DbgValueLocEntry(MachineLocation Loc)74e64f3cccSStephen Tozer DbgValueLocEntry(MachineLocation Loc) : EntryKind(E_Location), Loc(Loc) {} DbgValueLocEntry(TargetIndexLocation Loc)75e64f3cccSStephen Tozer DbgValueLocEntry(TargetIndexLocation Loc) 76e64f3cccSStephen Tozer : EntryKind(E_TargetIndexLocation), TIL(Loc) {} 77076ae0d2SNikola Prica isLocation()78e19e5efeSAdrian Prantl bool isLocation() const { return EntryKind == E_Location; } isTargetIndexLocation()79adf7a0a5SYury Delendik bool isTargetIndexLocation() const { 80adf7a0a5SYury Delendik return EntryKind == E_TargetIndexLocation; 81adf7a0a5SYury Delendik } isInt()82e19e5efeSAdrian Prantl bool isInt() const { return EntryKind == E_Integer; } isConstantFP()83e19e5efeSAdrian Prantl bool isConstantFP() const { return EntryKind == E_ConstantFP; } isConstantInt()84e19e5efeSAdrian Prantl bool isConstantInt() const { return EntryKind == E_ConstantInt; } getInt()85e19e5efeSAdrian Prantl int64_t getInt() const { return Constant.Int; } getConstantFP()86e19e5efeSAdrian Prantl const ConstantFP *getConstantFP() const { return Constant.CFP; } getConstantInt()87e19e5efeSAdrian Prantl const ConstantInt *getConstantInt() const { return Constant.CIP; } getLoc()88e19e5efeSAdrian Prantl MachineLocation getLoc() const { return Loc; } getTargetIndexLocation()89adf7a0a5SYury Delendik TargetIndexLocation getTargetIndexLocation() const { return TIL; } 90e64f3cccSStephen Tozer friend bool operator==(const DbgValueLocEntry &, const DbgValueLocEntry &); 91615eb470SAaron Ballman #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) dump()92194ded55SMatthias Braun LLVM_DUMP_METHOD void dump() const { 93dba58fbdSAdrian Prantl if (isLocation()) { 94dba58fbdSAdrian Prantl llvm::dbgs() << "Loc = { reg=" << Loc.getReg() << " "; 95dba58fbdSAdrian Prantl if (Loc.isIndirect()) 962049c0d7SAdrian Prantl llvm::dbgs() << "+0"; 97dba58fbdSAdrian Prantl llvm::dbgs() << "} "; 98076ae0d2SNikola Prica } else if (isConstantInt()) 99dba58fbdSAdrian Prantl Constant.CIP->dump(); 100dba58fbdSAdrian Prantl else if (isConstantFP()) 101dba58fbdSAdrian Prantl Constant.CFP->dump(); 102e64f3cccSStephen Tozer } 103e64f3cccSStephen Tozer #endif 104e64f3cccSStephen Tozer }; 105e64f3cccSStephen Tozer 106e64f3cccSStephen Tozer /// The location of a single variable, composed of an expression and 0 or more 107e64f3cccSStephen Tozer /// DbgValueLocEntries. 108e64f3cccSStephen Tozer class DbgValueLoc { 109e64f3cccSStephen Tozer /// Any complex address location expression for this DbgValueLoc. 110e64f3cccSStephen Tozer const DIExpression *Expression; 111e64f3cccSStephen Tozer 112e64f3cccSStephen Tozer SmallVector<DbgValueLocEntry, 2> ValueLocEntries; 113e64f3cccSStephen Tozer 114e64f3cccSStephen Tozer bool IsVariadic; 115e64f3cccSStephen Tozer 116e64f3cccSStephen Tozer public: DbgValueLoc(const DIExpression * Expr,ArrayRef<DbgValueLocEntry> Locs)117e64f3cccSStephen Tozer DbgValueLoc(const DIExpression *Expr, ArrayRef<DbgValueLocEntry> Locs) 118e64f3cccSStephen Tozer : Expression(Expr), ValueLocEntries(Locs.begin(), Locs.end()), 119e64f3cccSStephen Tozer IsVariadic(true) { 120e64f3cccSStephen Tozer #ifndef NDEBUG 121e64f3cccSStephen Tozer // Currently, DBG_VALUE_VAR expressions must use stack_value. 122e64f3cccSStephen Tozer assert(Expr && Expr->isValid() && 123e64f3cccSStephen Tozer is_contained(Locs, dwarf::DW_OP_stack_value)); 124e64f3cccSStephen Tozer #endif 125e64f3cccSStephen Tozer } 126e64f3cccSStephen Tozer DbgValueLoc(const DIExpression * Expr,ArrayRef<DbgValueLocEntry> Locs,bool IsVariadic)127e64f3cccSStephen Tozer DbgValueLoc(const DIExpression *Expr, ArrayRef<DbgValueLocEntry> Locs, 128e64f3cccSStephen Tozer bool IsVariadic) 129e64f3cccSStephen Tozer : Expression(Expr), ValueLocEntries(Locs.begin(), Locs.end()), 130e64f3cccSStephen Tozer IsVariadic(IsVariadic) { 131e64f3cccSStephen Tozer #ifndef NDEBUG 132e64f3cccSStephen Tozer assert(cast<DIExpression>(Expr)->isValid() || 133e64f3cccSStephen Tozer !any_of(Locs, [](auto LE) { return LE.isLocation(); })); 134e64f3cccSStephen Tozer if (!IsVariadic) { 135e64f3cccSStephen Tozer assert(ValueLocEntries.size() == 1); 136e64f3cccSStephen Tozer } else { 137e64f3cccSStephen Tozer // Currently, DBG_VALUE_VAR expressions must use stack_value. 138e64f3cccSStephen Tozer assert(Expr && Expr->isValid() && 139e64f3cccSStephen Tozer is_contained(Expr->getElements(), dwarf::DW_OP_stack_value)); 140e64f3cccSStephen Tozer } 141e64f3cccSStephen Tozer #endif 142e64f3cccSStephen Tozer } 143e64f3cccSStephen Tozer DbgValueLoc(const DIExpression * Expr,DbgValueLocEntry Loc)144e64f3cccSStephen Tozer DbgValueLoc(const DIExpression *Expr, DbgValueLocEntry Loc) 145e64f3cccSStephen Tozer : Expression(Expr), ValueLocEntries(1, Loc), IsVariadic(false) { 146e64f3cccSStephen Tozer assert(((Expr && Expr->isValid()) || !Loc.isLocation()) && 147e64f3cccSStephen Tozer "DBG_VALUE with a machine location must have a valid expression."); 148e64f3cccSStephen Tozer } 149e64f3cccSStephen Tozer isFragment()150e64f3cccSStephen Tozer bool isFragment() const { return getExpression()->isFragment(); } isEntryVal()151e64f3cccSStephen Tozer bool isEntryVal() const { return getExpression()->isEntryValue(); } isVariadic()152e64f3cccSStephen Tozer bool isVariadic() const { return IsVariadic; } getExpression()153e64f3cccSStephen Tozer const DIExpression *getExpression() const { return Expression; } getLocEntries()154e64f3cccSStephen Tozer const ArrayRef<DbgValueLocEntry> getLocEntries() const { 155e64f3cccSStephen Tozer return ValueLocEntries; 156e64f3cccSStephen Tozer } 157e64f3cccSStephen Tozer friend bool operator==(const DbgValueLoc &, const DbgValueLoc &); 158e64f3cccSStephen Tozer friend bool operator<(const DbgValueLoc &, const DbgValueLoc &); 159e64f3cccSStephen Tozer #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) dump()160e64f3cccSStephen Tozer LLVM_DUMP_METHOD void dump() const { 161*9e70d4e5SSimon Pilgrim for (const DbgValueLocEntry &DV : ValueLocEntries) 162e64f3cccSStephen Tozer DV.dump(); 163dba58fbdSAdrian Prantl if (Expression) 164dba58fbdSAdrian Prantl Expression->dump(); 165dba58fbdSAdrian Prantl } 166194ded55SMatthias Braun #endif 167e19e5efeSAdrian Prantl }; 168e8bde9f0SAdrian Prantl 169076ae0d2SNikola Prica /// This struct describes location entries emitted in the .debug_loc 170076ae0d2SNikola Prica /// section. 171076ae0d2SNikola Prica class DebugLocEntry { 172076ae0d2SNikola Prica /// Begin and end symbols for the address range that this location is valid. 173076ae0d2SNikola Prica const MCSymbol *Begin; 174076ae0d2SNikola Prica const MCSymbol *End; 175076ae0d2SNikola Prica 176be4b5171SAdrian Prantl /// A nonempty list of locations/constants belonging to this entry, 177be4b5171SAdrian Prantl /// sorted by offset. 178076ae0d2SNikola Prica SmallVector<DbgValueLoc, 1> Values; 179e19e5efeSAdrian Prantl 1801275e4f0SDavid Blaikie public: 1812028ae97SDavid Stenberg /// Create a location list entry for the range [\p Begin, \p End). 1822028ae97SDavid Stenberg /// 1832028ae97SDavid Stenberg /// \param Vals One or more values describing (parts of) the variable. DebugLocEntry(const MCSymbol * Begin,const MCSymbol * End,ArrayRef<DbgValueLoc> Vals)1842028ae97SDavid Stenberg DebugLocEntry(const MCSymbol *Begin, const MCSymbol *End, 185076ae0d2SNikola Prica ArrayRef<DbgValueLoc> Vals) 1862028ae97SDavid Stenberg : Begin(Begin), End(End) { 1872028ae97SDavid Stenberg addValues(Vals); 1881275e4f0SDavid Blaikie } 1891275e4f0SDavid Blaikie 1905f8f34e4SAdrian Prantl /// Attempt to merge this DebugLocEntry with Next and return 191e09ee3faSAdrian Prantl /// true if the merge was successful. Entries can be merged if they 192e09ee3faSAdrian Prantl /// share the same Loc/Constant and if Next immediately follows this 193e09ee3faSAdrian Prantl /// Entry. MergeRanges(const DebugLocEntry & Next)194e09ee3faSAdrian Prantl bool MergeRanges(const DebugLocEntry &Next) { 195b1416837SAdrian Prantl // If this and Next are describing the same variable, merge them. 196e19e5efeSAdrian Prantl if ((End == Next.Begin && Values == Next.Values)) { 1976fa9966eSDavid Blaikie End = Next.End; 1986fa9966eSDavid Blaikie return true; 1996fa9966eSDavid Blaikie } 2006fa9966eSDavid Blaikie return false; 2011275e4f0SDavid Blaikie } 202b1416837SAdrian Prantl getBeginSym()2031275e4f0SDavid Blaikie const MCSymbol *getBeginSym() const { return Begin; } getEndSym()2041275e4f0SDavid Blaikie const MCSymbol *getEndSym() const { return End; } getValues()205076ae0d2SNikola Prica ArrayRef<DbgValueLoc> getValues() const { return Values; } addValues(ArrayRef<DbgValueLoc> Vals)206076ae0d2SNikola Prica void addValues(ArrayRef<DbgValueLoc> Vals) { 2071c6f2ec1SAdrian Prantl Values.append(Vals.begin(), Vals.end()); 208293dd93fSAdrian Prantl sortUniqueValues(); 209076ae0d2SNikola Prica assert((Values.size() == 1 || all_of(Values, [](DbgValueLoc V) { 210076ae0d2SNikola Prica return V.isFragment(); 211076ae0d2SNikola Prica })) && "must either have a single value or multiple pieces"); 212293dd93fSAdrian Prantl } 213293dd93fSAdrian Prantl 2145f8f34e4SAdrian Prantl // Sort the pieces by offset. 215293dd93fSAdrian Prantl // Remove any duplicate entries by dropping all but the first. sortUniqueValues()216293dd93fSAdrian Prantl void sortUniqueValues() { 2170cac726aSFangrui Song llvm::sort(Values); 218076ae0d2SNikola Prica Values.erase(std::unique(Values.begin(), Values.end(), 219076ae0d2SNikola Prica [](const DbgValueLoc &A, const DbgValueLoc &B) { 220546c8be9SDuncan P. N. Exon Smith return A.getExpression() == B.getExpression(); 22187b7eb9dSAdrian Prantl }), 22287b7eb9dSAdrian Prantl Values.end()); 223b1416837SAdrian Prantl } 22492da14b2SAdrian Prantl 2255f8f34e4SAdrian Prantl /// Lower this entry into a DWARF expression. 226b86ce219SMarkus Lavin void finalize(const AsmPrinter &AP, 227b86ce219SMarkus Lavin DebugLocStream::ListBuilder &List, 228b86ce219SMarkus Lavin const DIBasicType *BT, 229b86ce219SMarkus Lavin DwarfCompileUnit &TheCU); 2301275e4f0SDavid Blaikie }; 2311275e4f0SDavid Blaikie 232e64f3cccSStephen Tozer /// Compare two DbgValueLocEntries for equality. 233e64f3cccSStephen Tozer inline bool operator==(const DbgValueLocEntry &A, const DbgValueLocEntry &B) { 234e8bde9f0SAdrian Prantl if (A.EntryKind != B.EntryKind) 235e8bde9f0SAdrian Prantl return false; 236e8bde9f0SAdrian Prantl 237e8bde9f0SAdrian Prantl switch (A.EntryKind) { 238e64f3cccSStephen Tozer case DbgValueLocEntry::E_Location: 239e8bde9f0SAdrian Prantl return A.Loc == B.Loc; 240e64f3cccSStephen Tozer case DbgValueLocEntry::E_TargetIndexLocation: 241adf7a0a5SYury Delendik return A.TIL == B.TIL; 242e64f3cccSStephen Tozer case DbgValueLocEntry::E_Integer: 243e8bde9f0SAdrian Prantl return A.Constant.Int == B.Constant.Int; 244e64f3cccSStephen Tozer case DbgValueLocEntry::E_ConstantFP: 245e8bde9f0SAdrian Prantl return A.Constant.CFP == B.Constant.CFP; 246e64f3cccSStephen Tozer case DbgValueLocEntry::E_ConstantInt: 247e8bde9f0SAdrian Prantl return A.Constant.CIP == B.Constant.CIP; 2481275e4f0SDavid Blaikie } 249e8bde9f0SAdrian Prantl llvm_unreachable("unhandled EntryKind"); 250e8bde9f0SAdrian Prantl } 251e8bde9f0SAdrian Prantl 252e64f3cccSStephen Tozer /// Compare two DbgValueLocs for equality. 253e64f3cccSStephen Tozer inline bool operator==(const DbgValueLoc &A, const DbgValueLoc &B) { 254e64f3cccSStephen Tozer return A.ValueLocEntries == B.ValueLocEntries && 255e64f3cccSStephen Tozer A.Expression == B.Expression && A.IsVariadic == B.IsVariadic; 256e64f3cccSStephen Tozer } 257e64f3cccSStephen Tozer 258941fa758SAdrian Prantl /// Compare two fragments based on their offset. 259076ae0d2SNikola Prica inline bool operator<(const DbgValueLoc &A, 260076ae0d2SNikola Prica const DbgValueLoc &B) { 26149797ca6SAdrian Prantl return A.getExpression()->getFragmentInfo()->OffsetInBits < 26249797ca6SAdrian Prantl B.getExpression()->getFragmentInfo()->OffsetInBits; 263e8bde9f0SAdrian Prantl } 264e8bde9f0SAdrian Prantl 265f00654e3SAlexander Kornienko } 266e8bde9f0SAdrian Prantl 2671275e4f0SDavid Blaikie #endif 268