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