Coverage Report

Created: 2024-01-17 10:31

/src/llvm-project/llvm/lib/CodeGen/AsmPrinter/DebugLocEntry.h
Line
Count
Source (jump to first uncovered line)
1
//===-- llvm/CodeGen/DebugLocEntry.h - Entry in debug_loc list -*- C++ -*--===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
9
#ifndef LLVM_LIB_CODEGEN_ASMPRINTER_DEBUGLOCENTRY_H
10
#define LLVM_LIB_CODEGEN_ASMPRINTER_DEBUGLOCENTRY_H
11
12
#include "DebugLocStream.h"
13
#include "llvm/Config/llvm-config.h"
14
#include "llvm/IR/Constants.h"
15
#include "llvm/IR/DebugInfo.h"
16
#include "llvm/MC/MCSymbol.h"
17
#include "llvm/MC/MachineLocation.h"
18
#include "llvm/Support/Debug.h"
19
20
namespace llvm {
21
class AsmPrinter;
22
23
/// This struct describes target specific location.
24
struct TargetIndexLocation {
25
  int Index;
26
  int Offset;
27
28
  TargetIndexLocation() = default;
29
  TargetIndexLocation(unsigned Idx, int64_t Offset)
30
9
      : Index(Idx), Offset(Offset) {}
31
32
3
  bool operator==(const TargetIndexLocation &Other) const {
33
3
    return Index == Other.Index && Offset == Other.Offset;
34
3
  }
35
};
36
37
/// A single location or constant within a variable location description, with
38
/// either a single entry (with an optional DIExpression) used for a DBG_VALUE,
39
/// or a list of entries used for a DBG_VALUE_LIST.
40
class DbgValueLocEntry {
41
42
  /// Type of entry that this represents.
43
  enum EntryType {
44
    E_Location,
45
    E_Integer,
46
    E_ConstantFP,
47
    E_ConstantInt,
48
    E_TargetIndexLocation
49
  };
50
  enum EntryType EntryKind;
51
52
  /// Either a constant,
53
  union {
54
    int64_t Int;
55
    const ConstantFP *CFP;
56
    const ConstantInt *CIP;
57
  } Constant;
58
59
  union {
60
    /// Or a location in the machine frame.
61
    MachineLocation Loc;
62
    /// Or a location from target specific location.
63
    TargetIndexLocation TIL;
64
  };
65
66
public:
67
799
  DbgValueLocEntry(int64_t i) : EntryKind(E_Integer) { Constant.Int = i; }
68
0
  DbgValueLocEntry(const ConstantFP *CFP) : EntryKind(E_ConstantFP) {
69
0
    Constant.CFP = CFP;
70
0
  }
71
0
  DbgValueLocEntry(const ConstantInt *CIP) : EntryKind(E_ConstantInt) {
72
0
    Constant.CIP = CIP;
73
0
  }
74
2.44k
  DbgValueLocEntry(MachineLocation Loc) : EntryKind(E_Location), Loc(Loc) {}
75
  DbgValueLocEntry(TargetIndexLocation Loc)
76
9
      : EntryKind(E_TargetIndexLocation), TIL(Loc) {}
77
78
1.39k
  bool isLocation() const { return EntryKind == E_Location; }
79
4.25k
  bool isIndirectLocation() const {
80
4.25k
    return EntryKind == E_Location && Loc.isIndirect();
81
4.25k
  }
82
9
  bool isTargetIndexLocation() const {
83
9
    return EntryKind == E_TargetIndexLocation;
84
9
  }
85
1.39k
  bool isInt() const { return EntryKind == E_Integer; }
86
0
  bool isConstantFP() const { return EntryKind == E_ConstantFP; }
87
0
  bool isConstantInt() const { return EntryKind == E_ConstantInt; }
88
376
  int64_t getInt() const { return Constant.Int; }
89
0
  const ConstantFP *getConstantFP() const { return Constant.CFP; }
90
0
  const ConstantInt *getConstantInt() const { return Constant.CIP; }
91
1.29k
  MachineLocation getLoc() const { return Loc; }
92
9
  TargetIndexLocation getTargetIndexLocation() const { return TIL; }
93
  friend bool operator==(const DbgValueLocEntry &, const DbgValueLocEntry &);
94
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
95
0
  LLVM_DUMP_METHOD void dump() const {
96
0
    if (isLocation()) {
97
0
      llvm::dbgs() << "Loc = { reg=" << Loc.getReg() << " ";
98
0
      if (Loc.isIndirect())
99
0
        llvm::dbgs() << "+0";
100
0
      llvm::dbgs() << "} ";
101
0
    } else if (isConstantInt())
102
0
      Constant.CIP->dump();
103
0
    else if (isConstantFP())
104
0
      Constant.CFP->dump();
105
0
  }
106
#endif
107
};
108
109
/// The location of a single variable, composed of an expression and 0 or more
110
/// DbgValueLocEntries.
111
class DbgValueLoc {
112
  /// Any complex address location expression for this DbgValueLoc.
113
  const DIExpression *Expression;
114
115
  SmallVector<DbgValueLocEntry, 2> ValueLocEntries;
116
117
  bool IsVariadic;
118
119
public:
120
  DbgValueLoc(const DIExpression *Expr, ArrayRef<DbgValueLocEntry> Locs)
121
      : Expression(Expr), ValueLocEntries(Locs.begin(), Locs.end()),
122
0
        IsVariadic(true) {}
123
124
  DbgValueLoc(const DIExpression *Expr, ArrayRef<DbgValueLocEntry> Locs,
125
              bool IsVariadic)
126
      : Expression(Expr), ValueLocEntries(Locs.begin(), Locs.end()),
127
3.25k
        IsVariadic(IsVariadic) {
128
3.25k
#ifndef NDEBUG
129
3.25k
    assert(Expr->isValid() ||
130
3.25k
           !any_of(Locs, [](auto LE) { return LE.isLocation(); }));
131
3.25k
    if (!IsVariadic) {
132
3.24k
      assert(ValueLocEntries.size() == 1);
133
3.24k
    }
134
3.25k
#endif
135
3.25k
  }
136
137
  DbgValueLoc(const DIExpression *Expr, DbgValueLocEntry Loc)
138
0
      : Expression(Expr), ValueLocEntries(1, Loc), IsVariadic(false) {
139
0
    assert(((Expr && Expr->isValid()) || !Loc.isLocation()) &&
140
0
           "DBG_VALUE with a machine location must have a valid expression.");
141
0
  }
142
143
1.43k
  bool isFragment() const { return getExpression()->isFragment(); }
144
0
  bool isEntryVal() const { return getExpression()->isEntryValue(); }
145
1.44k
  bool isVariadic() const { return IsVariadic; }
146
2.12k
  bool isEquivalent(const DbgValueLoc &Other) const {
147
    // Cannot be equivalent with different numbers of entries.
148
2.12k
    if (ValueLocEntries.size() != Other.ValueLocEntries.size())
149
0
      return false;
150
2.12k
    bool ThisIsIndirect =
151
2.12k
        !IsVariadic && ValueLocEntries[0].isIndirectLocation();
152
2.12k
    bool OtherIsIndirect =
153
2.12k
        !Other.IsVariadic && Other.ValueLocEntries[0].isIndirectLocation();
154
    // Check equivalence of DIExpressions + Directness together.
155
2.12k
    if (!DIExpression::isEqualExpression(Expression, ThisIsIndirect,
156
2.12k
                                         Other.Expression, OtherIsIndirect))
157
107
      return false;
158
    // Indirectness should have been accounted for in the above check, so just
159
    // compare register values directly here.
160
2.02k
    if (ThisIsIndirect || OtherIsIndirect) {
161
48
      DbgValueLocEntry ThisOp = ValueLocEntries[0];
162
48
      DbgValueLocEntry OtherOp = Other.ValueLocEntries[0];
163
48
      return ThisOp.isLocation() && OtherOp.isLocation() &&
164
48
             ThisOp.getLoc().getReg() == OtherOp.getLoc().getReg();
165
48
    }
166
    // If neither are indirect, then just compare the loc entries directly.
167
1.97k
    return ValueLocEntries == Other.ValueLocEntries;
168
2.02k
  }
169
2.99k
  const DIExpression *getExpression() const { return Expression; }
170
1.82k
  ArrayRef<DbgValueLocEntry> getLocEntries() const { return ValueLocEntries; }
171
  friend bool operator==(const DbgValueLoc &, const DbgValueLoc &);
172
  friend bool operator<(const DbgValueLoc &, const DbgValueLoc &);
173
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
174
0
  LLVM_DUMP_METHOD void dump() const {
175
0
    for (const DbgValueLocEntry &DV : ValueLocEntries)
176
0
      DV.dump();
177
0
    if (Expression)
178
0
      Expression->dump();
179
0
  }
180
#endif
181
};
182
183
/// This struct describes location entries emitted in the .debug_loc
184
/// section.
185
class DebugLocEntry {
186
  /// Begin and end symbols for the address range that this location is valid.
187
  const MCSymbol *Begin;
188
  const MCSymbol *End;
189
190
  /// A nonempty list of locations/constants belonging to this entry,
191
  /// sorted by offset.
192
  SmallVector<DbgValueLoc, 1> Values;
193
194
public:
195
  /// Create a location list entry for the range [\p Begin, \p End).
196
  ///
197
  /// \param Vals One or more values describing (parts of) the variable.
198
  DebugLocEntry(const MCSymbol *Begin, const MCSymbol *End,
199
                ArrayRef<DbgValueLoc> Vals)
200
3.18k
      : Begin(Begin), End(End) {
201
3.18k
    addValues(Vals);
202
3.18k
  }
203
204
  /// Attempt to merge this DebugLocEntry with Next and return
205
  /// true if the merge was successful. Entries can be merged if they
206
  /// share the same Loc/Constant and if Next immediately follows this
207
  /// Entry.
208
2.33k
  bool MergeRanges(const DebugLocEntry &Next) {
209
    // If this and Next are describing the same variable, merge them.
210
2.33k
    if (End != Next.Begin)
211
203
      return false;
212
2.12k
    if (Values.size() != Next.Values.size())
213
0
      return false;
214
3.79k
    for (unsigned EntryIdx = 0; EntryIdx < Values.size(); ++EntryIdx)
215
2.12k
      if (!Values[EntryIdx].isEquivalent(Next.Values[EntryIdx]))
216
467
        return false;
217
1.66k
    End = Next.End;
218
1.66k
    return true;
219
2.12k
  }
220
221
0
  const MCSymbol *getBeginSym() const { return Begin; }
222
0
  const MCSymbol *getEndSym() const { return End; }
223
89
  ArrayRef<DbgValueLoc> getValues() const { return Values; }
224
3.18k
  void addValues(ArrayRef<DbgValueLoc> Vals) {
225
3.18k
    Values.append(Vals.begin(), Vals.end());
226
3.18k
    sortUniqueValues();
227
3.18k
    assert((Values.size() == 1 || all_of(Values, [](DbgValueLoc V) {
228
3.18k
              return V.isFragment();
229
3.18k
            })) && "must either have a single value or multiple pieces");
230
3.18k
  }
231
232
  // Sort the pieces by offset.
233
  // Remove any duplicate entries by dropping all but the first.
234
3.18k
  void sortUniqueValues() {
235
    // Values is either 1 item that does not have a fragment, or many items
236
    // that all do. No need to sort if the former and also prevents operator<
237
    // being called on a non fragment item when _GLIBCXX_DEBUG is defined.
238
3.18k
    if (Values.size() == 1)
239
3.18k
      return;
240
0
    llvm::sort(Values);
241
0
    Values.erase(std::unique(Values.begin(), Values.end(),
242
0
                             [](const DbgValueLoc &A, const DbgValueLoc &B) {
243
0
                               return A.getExpression() == B.getExpression();
244
0
                             }),
245
0
                 Values.end());
246
0
  }
247
248
  /// Lower this entry into a DWARF expression.
249
  void finalize(const AsmPrinter &AP,
250
                DebugLocStream::ListBuilder &List,
251
                const DIBasicType *BT,
252
                DwarfCompileUnit &TheCU);
253
};
254
255
/// Compare two DbgValueLocEntries for equality.
256
1.97k
inline bool operator==(const DbgValueLocEntry &A, const DbgValueLocEntry &B) {
257
1.97k
  if (A.EntryKind != B.EntryKind)
258
233
    return false;
259
260
1.74k
  switch (A.EntryKind) {
261
1.30k
  case DbgValueLocEntry::E_Location:
262
1.30k
    return A.Loc == B.Loc;
263
3
  case DbgValueLocEntry::E_TargetIndexLocation:
264
3
    return A.TIL == B.TIL;
265
431
  case DbgValueLocEntry::E_Integer:
266
431
    return A.Constant.Int == B.Constant.Int;
267
0
  case DbgValueLocEntry::E_ConstantFP:
268
0
    return A.Constant.CFP == B.Constant.CFP;
269
0
  case DbgValueLocEntry::E_ConstantInt:
270
0
    return A.Constant.CIP == B.Constant.CIP;
271
1.74k
  }
272
0
  llvm_unreachable("unhandled EntryKind");
273
0
}
274
275
/// Compare two DbgValueLocs for equality.
276
0
inline bool operator==(const DbgValueLoc &A, const DbgValueLoc &B) {
277
0
  return A.ValueLocEntries == B.ValueLocEntries &&
278
0
         A.Expression == B.Expression && A.IsVariadic == B.IsVariadic;
279
0
}
280
281
/// Compare two fragments based on their offset.
282
inline bool operator<(const DbgValueLoc &A,
283
0
                      const DbgValueLoc &B) {
284
0
  return A.getExpression()->getFragmentInfo()->OffsetInBits <
285
0
         B.getExpression()->getFragmentInfo()->OffsetInBits;
286
0
}
287
288
}
289
290
#endif